bookshelf-doc/static/nav.js

249 lines
6.1 KiB
JavaScript
Raw Normal View History

// Persistent expansion cookie for the file tree
// ---------------------------------------------
let expanded = {};
for (const e of (sessionStorage.getItem('expanded') || '').split(',')) {
if (e !== '') {
expanded[e] = true;
}
}
function saveExpanded() {
sessionStorage.setItem("expanded",
Object.getOwnPropertyNames(expanded).filter((e) => expanded[e]).join(","));
}
for (const elem of document.getElementsByClassName('nav_sect')) {
const id = elem.getAttribute('data-path');
if (!id) continue;
if (expanded[id]) {
elem.open = true;
}
elem.addEventListener('toggle', () => {
expanded[id] = elem.open;
saveExpanded();
});
}
for (const currentFileLink of document.getElementsByClassName('visible')) {
currentFileLink.scrollIntoView({block: 'center'});
}
// Tactic list tag filter
// ----------------------
function filterSelectionClass(tagNames, classname) {
if (tagNames.length == 0) {
for (const elem of document.getElementsByClassName(classname)) {
elem.classList.remove("hide");
}
} else {
// Add the "show" class (display:block) to the filtered elements, and remove the "show" class from the elements that are not selected
for (const elem of document.getElementsByClassName(classname)) {
elem.classList.add("hide");
for (const tagName of tagNames) {
if (elem.classList.contains(tagName)) {
elem.classList.remove("hide");
}
}
}
}
}
function filterSelection(c) {
filterSelectionClass(c, "tactic");
filterSelectionClass(c, "taclink");
}
var filterBoxes = document.getElementsByClassName("tagfilter");
function updateDisplay() {
filterSelection(getSelectValues());
}
function getSelectValues() {
var result = [];
for (const opt of filterBoxes) {
if (opt.checked) {
result.push(opt.value);
}
}
return result;
}
function setSelectVal(val) {
for (const opt of filterBoxes) {
opt.checked = val;
}
}
updateDisplay();
for (const opt of filterBoxes) {
opt.addEventListener('change', updateDisplay);
}
const tse = document.getElementById("tagfilter-selectall")
if (tse != null) {
tse.addEventListener('change', function() {
setSelectVal(this.checked);
updateDisplay();
});
}
// Simple declaration search
// -------------------------
2022-02-13 13:25:37 +00:00
const declURL = new URL(`${siteRoot}searchable_data.bmp`, window.location);
const getDecls = (() => {
let decls;
return () => {
if (!decls) decls = new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.responseType = 'json';
req.addEventListener('load', () => resolve(loadDecls(req.response)));
req.addEventListener('error', () => reject());
req.open('GET', declURL);
req.send();
})
return decls;
}
})()
const declSearch = async (q) => getMatches(await getDecls(), q);
const srId = 'search_results';
document.getElementById('search_form')
.appendChild(document.createElement('div'))
.id = srId;
function handleSearchCursorUpDown(down) {
const sel = document.querySelector(`#${srId} .selected`);
const sr = document.getElementById(srId);
if (sel) {
sel.classList.remove('selected');
const toSelect = down ?
sel.nextSibling || sr.firstChild:
sel.previousSibling || sr.lastChild;
toSelect && toSelect.classList.add('selected');
} else {
const toSelect = down ? sr.firstChild : sr.lastChild;
toSelect && toSelect.classList.add('selected');
}
}
function handleSearchEnter() {
const sel = document.querySelector(`#${srId} .selected`)
|| document.getElementById(srId).firstChild;
sel.click();
}
const searchInput = document.querySelector('#search_form input[name=q]');
searchInput.addEventListener('keydown', (ev) => {
switch (ev.key) {
case 'Down':
case 'ArrowDown':
ev.preventDefault();
handleSearchCursorUpDown(true);
break;
case 'Up':
case 'ArrowUp':
ev.preventDefault();
handleSearchCursorUpDown(false);
break;
case 'Enter':
ev.preventDefault();
handleSearchEnter();
break;
}
});
searchInput.addEventListener('input', async (ev) => {
const text = ev.target.value;
if (!text) {
const sr = document.getElementById(srId);
sr.removeAttribute('state');
sr.replaceWith(sr.cloneNode(false));
return;
}
document.getElementById(srId).setAttribute('state', 'loading');
const result = await declSearch(text);
if (ev.target.value != text) return;
const oldSR = document.getElementById('search_results');
const sr = oldSR.cloneNode(false);
for (const {decl} of result) {
const d = sr.appendChild(document.createElement('a'));
d.innerText = decl;
d.title = decl;
d.href = `${siteRoot}find/${decl}`;
}
sr.setAttribute('state', 'done');
oldSR.replaceWith(sr);
});
// 404 page goodies
// ----------------
const howabout = document.getElementById('howabout');
if (howabout) {
howabout.innerText = "Please wait a second. I'll try to help you.";
howabout.parentNode
.insertBefore(document.createElement('pre'), howabout)
.appendChild(document.createElement('code'))
.innerText = window.location.href.replace(/[/]/g, '/\u200b');
const query = window.location.href.match(/[/]([^/]+)(?:\.html|[/])?$/)[1];
declSearch(query).then((results) => {
howabout.innerText = 'How about one of these instead:';
const ul = howabout.appendChild(document.createElement('ul'));
for (const {decl} of results) {
const li = ul.appendChild(document.createElement('li'));
const a = li.appendChild(document.createElement('a'));
a.href = `${siteRoot}find/${decl}`;
a.appendChild(document.createElement('code')).innerText = decl;
}
});
}
// Rewrite GitHub links
// --------------------
for (const elem of document.getElementsByClassName('gh_link')) {
const a = elem.firstElementChild;
// commit is set in add_commit.js
for (const [prefix, replacement] of commit) {
if (a.href.startsWith(prefix)) {
a.href = a.href.replace(prefix, replacement);
break;
}
}
}