/** * Construct recurseData.str as a nested list of headers by recursively going * through all children of elem that has header tags. * * References: * https://stackoverflow.com/questions/187619/is-there-a-javascript-solution-to-generating-a-table-of-contents-for-a-page * @param elem DOM element * @param recurseData Object with fields: { int: level, int: count, str: toc } */ function recurseChild(elem, recurseData) { if (elem !== "undefined") { if(elem.nodeName.match(/^H\d+$/) && elem.textContent) { var headerText = elem.textContent; var prevLevel = recurseData.level; var level = elem.nodeName.substr(1); var anchor = "kiwix-toc-" + recurseData.count; recurseData.count += 1; /* Wrap header content with something we can reference. */ elem.innerHTML = '' + headerText + ''; /* Start or end a list or item based on current and previous level */ if (level > prevLevel) recurseData.toc += ''; else recurseData.toc += ''; recurseData.level = parseInt(level); recurseData.toc += '
  • ' + '' + headerText + '' + headerText + ''; } var c = elem.children; for (var i = 0; i < c.length; i++) recurseChild(c[i], recurseData); } } function tocHTMLStr() { /* level used to track current header level. toc used to store constructed list. count used to uniquely identify each list item in toc. */ var recurseData = { level: 0, toc: "", count: 0,}; recurseChild(document.body, recurseData); /* End list when non-empty */ if (recurseData.level) recurseData.toc += (new Array(recurseData.level + 1)).join(''); return recurseData.toc; } function getPixelWithZoom(pixel) { var zoom = window.outerWidth / window.document.documentElement.clientWidth; return (pixel / zoom.toFixed(1)).toString() + "px"; } function makeTOCVisible(visible) { var tocElem = document.getElementById("kiwix-toc-side"); tocElem.style.display = visible ? "block" : "none"; document.body.style.marginLeft = visible ? getPixelWithZoom(310) : null; document.body.style.maxWidth = visible ? "calc(100vw - " + getPixelWithZoom(310) + ")" : null; } function showToolTip (elem) { var tooltip = elem.getElementsByClassName("kiwix-tool-tip")[0]; /* Check if there is overflow. */ if (tooltip && elem.offsetWidth < elem.scrollWidth) { tooltip.style.display = "block"; var rect = elem.getBoundingClientRect(); tooltip.style.top = (rect.top).toString() + "px"; tooltip.style.left = getPixelWithZoom(306); } } function hideToolTip (elem) { var tooltip = elem.getElementsByClassName("kiwix-tool-tip")[0]; if (tooltip) tooltip.style.display = ""; } function setupTOCItems() { var c = document.getElementsByClassName("kiwix-toc-item-a"); for (var i = 0; i < c.length; i++) { if (c[i] !== "undefined" && c[i].style) { var p = c[i].parentNode; var count = -1; while (p) { if (p.nodeName.match(/^UL$/)) count += 1; p = p.parentNode; } /* We need manual padding to achieve visual effects on hover. */ c[i].style.paddingLeft = ((count == -1 ? 0 : count) * 30).toString() + "px"; c[i].addEventListener("mouseover", (event) => { showToolTip(event.target); }); c[i].addEventListener("mouseout", (event) => { hideToolTip(event.target); }); } } } function setupTOC() { var toc = document.createElement('div'); toc.id = "kiwix-toc"; toc.innerHTML += tocHTMLStr(); var tocTitle = document.createElement('p'); tocTitle.id = "kiwix-toc-title"; var tocHideButton = document.createElement('button'); tocHideButton.id = "kiwix-toc-hide-button" var tocTitleDiv = document.createElement('div'); tocTitleDiv.id = "kiwix-toc-title-div"; tocTitleDiv.append(tocTitle); tocTitleDiv.append(tocHideButton); var tocSideDiv = document.createElement('div'); tocSideDiv.id = "kiwix-toc-side"; tocSideDiv.append(tocTitleDiv); tocSideDiv.append(toc); document.body.prepend(tocSideDiv); } function resize(){ document.getElementById("kiwix-toc-side").style.width = getPixelWithZoom(306); if (document.getElementById("kiwix-toc-side").style.display !== "none") { document.body.style.marginLeft = getPixelWithZoom(310); document.body.style.maxWidth = "calc(100vw - " + getPixelWithZoom(310) + ")"; } } new QWebChannel(qt.webChannelTransport, function(channel) { var kiwixObj = channel.objects.kiwixChannelObj setupTOC(); setupTOCItems(); document.getElementById("kiwix-toc-title").textContent = kiwixObj.tocTitle; var tocHideButton = document.getElementById("kiwix-toc-hide-button"); tocHideButton.textContent = kiwixObj.hideButtontext; tocHideButton.onclick = () => { kiwixObj.tocVisible = false; }; kiwixObj.tocVisibleChanged.connect(function(visible) { makeTOCVisible(visible); }); makeTOCVisible(kiwixObj.tocVisible); window.onresize = resize; resize(); });