blob: 36249112df79dd53573241f484d4c23572163b14 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
document.addEventListener('DOMContentLoaded', () => dynamicTOC());
function dynamicTOC() {
const content = document.getElementById('content');
// Bind a click listener to all section titles.
const sectionTitles = content.querySelectorAll('a.link');
for (const sectionTitle of sectionTitles) {
sectionTitle.addEventListener('click', event => collapseThenExpand(hash(event.target)));
}
// Bind a click listener to all inline links to documentation sections.
const inlineLinks = content.querySelectorAll('p > a');
for (const inlineLink of inlineLinks) {
const linkHash = inlineLink.hash || '';
if (linkHash.startsWith('#')) {
inlineLink.addEventListener('click', event => collapseThenExpand(hash(event.target)));
}
}
// Bind a click listener to all TOC titles.
const toc = document.getElementById('toc');
const tocTitles = toc.querySelectorAll('a');
for (const tocTitle of tocTitles) {
tocTitle.addEventListener('click', event => collapseThenExpand(hash(event.target)));
}
// Add the icons to TOC nodes.
const nodes = toc.querySelectorAll('li');
for (const node of nodes) {
const span = document.createElement('span');
const css = span.classList;
if (node.querySelector(':scope > ul')) {
css.add('toc-toggle');
// Font-Awesome classes.
css.add('fa');
css.add('fa-caret-right');
span.addEventListener('click', event => toggle(event.target));
} else {
css.add('toc-item');
// The "icon" is the • HTML entity.
span.appendChild(document.createTextNode('•'));
}
node.prepend(span);
}
collapseThenExpand(document.location.hash);
}
function hash(element) {
const a = element.closest('a');
return a ? a.hash : null;
}
function collapseThenExpand(hash) {
const toc = document.getElementById('toc');
if (hash) {
const current = toc.querySelector('a.toc-current');
if (current) {
current.classList.remove('toc-current');
}
const anchor = toc.querySelector('a[href="' + hash + '"');
if (anchor) {
anchor.classList.add('toc-current');
collapse(toc);
expand(anchor.parentNode);
}
} else {
collapse(toc);
}
}
function collapse(node) {
const sections = node.querySelectorAll('ul');
for (const section of sections) {
const css = section.classList;
// Always show first levels TOC titles.
const alwaysShow = css.contains('sectlevel1') || css.contains('sectlevel2');
if (!alwaysShow) {
css.add('hidden');
}
}
// Show the collapsed icon.
const spans = node.querySelectorAll('span.toc-toggle');
for (const span of spans) {
const css = span.classList;
css.remove('fa-caret-down');
css.add('fa-caret-right');
}
}
function expand(node) {
const root = document.getElementById('toc').querySelector('ul');
// Show the current node and its ancestors.
let parent = node;
while (parent !== root) {
// Show the node.
parent.classList.remove('hidden');
// Show the expanded icon.
const span = parent.querySelector(':scope > span.toc-toggle');
if (span) {
const css = span.classList;
css.remove('fa-caret-right');
css.add('fa-caret-down');
}
parent = parent.parentNode;
}
// Show the children.
const children = node.querySelector(':scope > ul');
if (children) {
children.classList.remove('hidden');
}
}
function toggle(span) {
const css = span.classList;
const expanded = css.contains('fa-caret-down');
if (expanded) {
collapse(span.parentNode);
} else {
expand(span.parentNode);
}
}