static/app.js
browsing at commit = 118f7b3050759438e47061859b2ee856af44ebfc
// Client-side rendering: syntax highlighting for source files and markdown
// rendering for READMEs and .md files.
(function () {
"use strict";
// Map a filename to an explicit highlight.js language. Resolution order:
// exact full-name match, then filename patterns, then extension. Anything
// that resolves here overrides highlight.js auto-detection.
var FILENAME_LANGUAGES = { "CMakeLists.txt": "cmake" };
// Patterns matched against the whole filename, in order.
var FILENAME_PATTERNS = [
{ test: /^\..*ignore$/i, language: "plaintext" }, // .gitignore, .dockerignore, ...
{ test: /^Dockerfile/i, language: "dockerfile" }, // Dockerfile, Dockerfile.dev, ...
];
var EXTENSION_LANGUAGES = {
cpp: "cpp",
hpp: "cpp",
js: "javascript",
json: "json",
yml: "yaml",
txt: "plaintext",
man: "plaintext", // no troff/man grammar in highlight.js; pin to plain text
py: "python",
tf: "terraform",
sql: "sql",
patch: "diff", // patch files are unified diffs
};
function languageForFilename(filename) {
if (!filename) return null;
if (FILENAME_LANGUAGES[filename]) return FILENAME_LANGUAGES[filename];
for (var i = 0; i < FILENAME_PATTERNS.length; i++) {
if (FILENAME_PATTERNS[i].test.test(filename)) return FILENAME_PATTERNS[i].language;
}
var dot = filename.lastIndexOf(".");
// Extensionless files (LICENSE, README, etc.) are treated as plain text
// rather than letting auto-detection guess a language.
if (dot === -1) return "plaintext";
return EXTENSION_LANGUAGES[filename.slice(dot + 1).toLowerCase()] || null;
}
function highlight() {
if (typeof hljs === "undefined") return;
document.querySelectorAll("pre.code > code.hljs").forEach(function (el) {
var lang = languageForFilename(el.dataset.filename);
if (lang) el.classList.add("language-" + lang);
hljs.highlightElement(el);
var detected = el.result && el.result.language ? el.result.language : "plaintext";
var label = document.createElement("p");
label.className = "lang-detected";
label.textContent = "Detected language: " + detected;
el.parentElement.insertAdjacentElement("afterend", label);
});
}
// Each ".markdown-src" element holds raw markdown and a data-target CSS
// selector pointing at the element to render it into.
function renderMarkdown() {
if (typeof marked === "undefined") return;
document.querySelectorAll(".markdown-src").forEach(function (src) {
var target = document.querySelector(src.dataset.target);
if (target) target.innerHTML = marked.parse(src.textContent);
});
}
// Single toggle above the log that shows or hides every commit body at once.
function setupLogToggle() {
var btn = document.querySelector(".log-toggle");
if (!btn) return;
btn.addEventListener("click", function () {
var on = btn.getAttribute("aria-pressed") !== "true";
btn.setAttribute("aria-pressed", on ? "true" : "false");
btn.textContent = "expand: " + (on ? "on" : "off");
document.querySelectorAll(".commit-body").forEach(function (el) {
el.hidden = !on;
});
});
}
// Toggle between the file list table and a thumbnail grid. The choice is
// remembered in localStorage so it persists while browsing into subfolders.
function setupViewToggle() {
var btn = document.querySelector(".view-toggle");
if (!btn) return;
var table = document.querySelector("table.tree");
var grid = document.querySelector(".tree-grid");
if (!table || !grid) return;
function apply(grid_on) {
btn.setAttribute("aria-pressed", grid_on ? "true" : "false");
btn.textContent = "view: " + (grid_on ? "grid" : "list");
table.hidden = grid_on;
grid.hidden = !grid_on;
}
apply(localStorage.getItem("treeView") === "grid");
btn.addEventListener("click", function () {
var grid_on = btn.getAttribute("aria-pressed") !== "true";
localStorage.setItem("treeView", grid_on ? "grid" : "list");
apply(grid_on);
});
}
document.addEventListener("DOMContentLoaded", function () {
highlight();
renderMarkdown();
setupLogToggle();
setupViewToggle();
});
})();