mirror of
https://github.com/flame-engine/flame.git
synced 2025-10-29 16:05:47 +08:00
As mentioned in discord, the current build of the docs loses jQuery functionality. This is due to sphinx being upgraded to version 6 in which they removed jQuery and created a stand-alone package for it. Additionally, in the process of doing that, I noticed the previously mentioned fix (in the comments) for the `melos doc-setup` about removing the single quotes to keep it clean didn't make into the final code. I have updated that as it was previously confirmed to work on all platforms in: https://github.com/flame-engine/flame/pull/2401 I noticed that the copyright that was in the `conf.py` was locked at 2021 and so I made it go to 2023 as well. This can be removed if not desired, but thought maybe this had just been overlooked. Finally, there was an error regarding a duplicate instantiation of a constant. This had to do with the fact the basic theme provided with sphinx, the next version after which the docs were based, had a bug fix implemented: https://www.sphinx-doc.org/en/master/changes.html#release-5-1-0-released-jul-24-2022. In their fix, it also broke the way the flames theme works. On a side note, the docs are using a very outdated version of the basic theme and should likely be overhauled, but that is outside the scope of this pr. None the less, after I finally figured out how the basic theme is inherited and where that lived on my machine, I was able to resolve the discrepancies and eliminate the conflicting names between the two themes. In short, all errors have been resolved and I have confirmed that mobile, web, search, highlighting, menus, etc. all work - at least on my machine.
284 lines
8.9 KiB
JavaScript
284 lines
8.9 KiB
JavaScript
/*
|
|
* Originally from:
|
|
* https://github.com/sphinx-doc/sphinx/blob/2b42752219424cb09ba910b6f654145107e0387b/sphinx/themes/basic/static/doctools.js
|
|
* -----------------------------------------------------------------------------
|
|
* doctools.js
|
|
* ~~~~~~~~~~~
|
|
*
|
|
* Base JavaScript utilities for all Sphinx HTML documentation.
|
|
*
|
|
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
|
|
* :license: BSD, see LICENSE for details.
|
|
* -----------------------------------------------------------------------------
|
|
*/
|
|
"use strict";
|
|
|
|
const _ready = (callback) => {
|
|
if (document.readyState !== "loading") {
|
|
callback();
|
|
} else {
|
|
document.addEventListener("DOMContentLoaded", callback);
|
|
}
|
|
};
|
|
|
|
const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
|
|
"TEXTAREA",
|
|
"INPUT",
|
|
"SELECT",
|
|
"BUTTON",
|
|
]);
|
|
|
|
/**
|
|
* highlight a given string on a node by wrapping it in
|
|
* span elements with the given class name.
|
|
*/
|
|
const _highlightFlame = (node, addItems, text, className, index) => {
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
const val = node.nodeValue;
|
|
const parent = node.parentNode;
|
|
const pos = val.toLowerCase().indexOf(text);
|
|
if (
|
|
pos >= 0 &&
|
|
!parent.classList.contains(className) &&
|
|
!parent.classList.contains("nohighlight")
|
|
) {
|
|
let span;
|
|
|
|
const closestNode = parent.closest("body, svg, foreignObject");
|
|
const isInSVG = closestNode && closestNode.matches("svg");
|
|
if (isInSVG) {
|
|
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
|
} else {
|
|
span = document.createElement("span");
|
|
span.classList.add(className);
|
|
span.classList.add('i' + index);
|
|
}
|
|
|
|
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
|
parent.insertBefore(
|
|
span,
|
|
parent.insertBefore(
|
|
document.createTextNode(val.substr(pos + text.length)),
|
|
node.nextSibling
|
|
)
|
|
);
|
|
node.nodeValue = val.substr(0, pos);
|
|
|
|
if (isInSVG) {
|
|
const rect = document.createElementNS(
|
|
"http://www.w3.org/2000/svg",
|
|
"rect"
|
|
);
|
|
const bbox = parent.getBBox();
|
|
rect.x.baseVal.value = bbox.x;
|
|
rect.y.baseVal.value = bbox.y;
|
|
rect.width.baseVal.value = bbox.width;
|
|
rect.height.baseVal.value = bbox.height;
|
|
rect.setAttribute("class", className);
|
|
addItems.push({ parent: parent, target: rect });
|
|
}
|
|
}
|
|
} else if (node.matches && !node.matches("button, select, textarea")) {
|
|
node.childNodes.forEach((el) => _highlightFlame(el, addItems, text, className, index));
|
|
}
|
|
};
|
|
const _highlightTextFlame = (thisNode, text, className, index) => {
|
|
let addItems = [];
|
|
_highlightFlame(thisNode, addItems, text, className, index);
|
|
addItems.forEach((obj) =>
|
|
obj.parent.insertAdjacentElement("beforebegin", obj.target)
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Small JavaScript module for the documentation.
|
|
*/
|
|
const DocumentationFlame = {
|
|
init: () => {
|
|
DocumentationFlame.highlightSearchWords();
|
|
DocumentationFlame.initDomainIndexTable();
|
|
DocumentationFlame.initOnKeyListeners();
|
|
},
|
|
|
|
/**
|
|
* i18n support
|
|
*/
|
|
TRANSLATIONS: {},
|
|
PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
|
|
LOCALE: "unknown",
|
|
|
|
// gettext and ngettext don't access this so that the functions
|
|
// can safely bound to a different name (_ = DocumentationFlame.gettext)
|
|
gettext: (string) => {
|
|
const translated = DocumentationFlame.TRANSLATIONS[string];
|
|
switch (typeof translated) {
|
|
case "undefined":
|
|
return string; // no translation
|
|
case "string":
|
|
return translated; // translation exists
|
|
default:
|
|
return translated[0]; // (singular, plural) translation tuple exists
|
|
}
|
|
},
|
|
|
|
ngettext: (singular, plural, n) => {
|
|
const translated = DocumentationFlame.TRANSLATIONS[singular];
|
|
if (typeof translated !== "undefined")
|
|
return translated[DocumentationFlame.PLURAL_EXPR(n)];
|
|
return n === 1 ? singular : plural;
|
|
},
|
|
|
|
addTranslations: (catalog) => {
|
|
Object.assign(DocumentationFlame.TRANSLATIONS, catalog.messages);
|
|
DocumentationFlame.PLURAL_EXPR = new Function(
|
|
"n",
|
|
`return (${catalog.plural_expr})`
|
|
);
|
|
DocumentationFlame.LOCALE = catalog.locale;
|
|
},
|
|
|
|
/**
|
|
* highlight the search words provided in the url in the text
|
|
*/
|
|
highlightSearchWords: () => {
|
|
const highlight =
|
|
new URLSearchParams(window.location.search).get("highlight") || "";
|
|
const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
|
|
if (terms.length === 0) return; // nothing to do
|
|
|
|
// There should never be more than one element matching "div.body"
|
|
const divBody = document.querySelectorAll("div.body");
|
|
const body = divBody.length ? divBody[0] : document.querySelector("body");
|
|
const hbox = $("#highlight-content");
|
|
window.setTimeout(() => {
|
|
terms.forEach((term, index) => {
|
|
_highlightTextFlame(body, term, "highlighted", index);
|
|
hbox.append($('<span>' + term + '</span>').click(function(){
|
|
$(this).toggleClass("off");
|
|
DocumentationFlame.toggleSearchWord(index);
|
|
}));
|
|
});
|
|
}, 10);
|
|
|
|
$("div.highlight-box").show();
|
|
$("div.highlight-box button.close").click(DocumentationFlame.hideSearchWords);
|
|
const searchBox = document.getElementById("searchbox");
|
|
if (searchBox === null) return;
|
|
searchBox.appendChild(
|
|
document
|
|
.createRange()
|
|
.createContextualFragment(
|
|
'<p class="highlight-link">' +
|
|
'<a href="javascript:DocumentationFlame.hideSearchWords()">' +
|
|
DocumentationFlame.gettext("Hide Search Matches") +
|
|
"</a></p>"
|
|
)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* helper function to hide the search marks again
|
|
*/
|
|
hideSearchWords: () => {
|
|
$("div.highlight-box").fadeOut(300);
|
|
document
|
|
.querySelectorAll("#searchbox .highlight-link")
|
|
.forEach((el) => el.remove());
|
|
document
|
|
.querySelectorAll("span.highlighted")
|
|
.forEach((el) => el.classList.remove("highlighted"));
|
|
const url = new URL(window.location);
|
|
url.searchParams.delete("highlight");
|
|
window.history.replaceState({}, "", url);
|
|
},
|
|
|
|
/**
|
|
* helper function to focus on search bar
|
|
*/
|
|
focusSearchBar: () => {
|
|
document.querySelectorAll("input[name=q]")[0]?.focus();
|
|
},
|
|
|
|
toggleSearchWord : function(i) {
|
|
$('span.highlighted.i' + i).toggleClass('off');
|
|
},
|
|
|
|
/**
|
|
* Initialize the domain index toggle buttons
|
|
*/
|
|
initDomainIndexTable: () => {
|
|
const toggler = (el) => {
|
|
const idNumber = el.id.substr(7);
|
|
const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
|
|
if (el.src.substr(-9) === "minus.png") {
|
|
el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
|
|
toggledRows.forEach((el) => (el.style.display = "none"));
|
|
} else {
|
|
el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
|
|
toggledRows.forEach((el) => (el.style.display = ""));
|
|
}
|
|
};
|
|
|
|
const togglerElements = document.querySelectorAll("img.toggler");
|
|
togglerElements.forEach((el) =>
|
|
el.addEventListener("click", (event) => toggler(event.currentTarget))
|
|
);
|
|
togglerElements.forEach((el) => (el.style.display = ""));
|
|
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
|
|
},
|
|
|
|
initOnKeyListeners: () => {
|
|
// only install a listener if it is really needed
|
|
if (
|
|
!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
|
|
!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
|
|
)
|
|
return;
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; // bail for input elements
|
|
if (event.altKey || event.ctrlKey || event.metaKey) return; // bail with special keys
|
|
|
|
if (!event.shiftKey) {
|
|
switch (event.key) {
|
|
case "ArrowLeft":
|
|
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
|
|
|
|
const prevLink = document.querySelector('link[rel="prev"]');
|
|
if (prevLink && prevLink.href) {
|
|
window.location.href = prevLink.href;
|
|
event.preventDefault();
|
|
}
|
|
break;
|
|
case "ArrowRight":
|
|
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
|
|
|
|
const nextLink = document.querySelector('link[rel="next"]');
|
|
if (nextLink && nextLink.href) {
|
|
window.location.href = nextLink.href;
|
|
event.preventDefault();
|
|
}
|
|
break;
|
|
case "Escape":
|
|
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
|
|
DocumentationFlame.hideSearchWords();
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
// some keyboard layouts may need Shift to get /
|
|
switch (event.key) {
|
|
case "/":
|
|
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
|
|
DocumentationFlame.focusSearchBar();
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
},
|
|
};
|
|
|
|
// quick alias for translations
|
|
const _ = DocumentationFlame.gettext;
|
|
|
|
_ready(DocumentationFlame.init);
|