Files
klammertext/sks/document/js/toc.js
Andy Kopra 2ba7ceee7a Initial commit: Klammertext source distribution
Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 19:32:38 +02:00

302 lines
8.7 KiB
JavaScript

function current_page_headers() {
let result = K.getv([1,2,3,4,5].map(function (o) {
return "#text h" + o;
}));
result = [...result];
["kt-part", "kt-chapter"].forEach(function (tag) {
let elt = K.get("#text " + tag);
if (elt) {
result.push(elt);
}
});
return result;
}
function add_navlink_mapping(navlink_map, navlink) {
let target = K.attr(navlink, "data-target");
navlink_map[target] = navlink.children[0];
return navlink_map;
}
function headers_in_text() {
//const headers = [...K.getv("h1,h2,h3,h4")];
const headers = current_page_headers();
//const text_rect = K.get("#text").getBoundingClientRect();
const text_rect = displayed_text().getBoundingClientRect();
const top = text_rect.top;
const bottom = top + text_rect.height;
let visible = [];
let invisible = [];
headers.forEach(function (h) {
const header_rect = h.getBoundingClientRect();
const header_bottom = header_rect.bottom;
if (header_bottom > top && header_bottom < bottom) {
visible.push(h);
} else {
invisible.push(h);
}
});
//console.log("headers_in_text: " + visible.length
// + " " + invisible.length);
return [visible, invisible];
}
function open_highlighted_sections(node) {
//console.log("open_highlighted_sections");
let parent = node.parentNode;
while (parent && parent.id != "toc_items") {
//console.log(parent.id);
//console.dir(parent);
//console.log(parent);
//console.log(parent.children);
let carets = [...parent.children].filter(function (node) {
return K.has_class(node, "caret")
&& !K.has_class(node, "caret-down");
});
carets.forEach(function (c) {
c.click();
});
//console.log("carets: ")
//console.log(carets);
parent = parent.parentNode;
}
}
function open_visible() {
//console.log("open_visible");
let open_sections = visible_toc_sections();
if (open_sections.length === 1 && !open_sections[0]) {
return;
}
//console.log("open_sections:");
//console.log(open_sections);
open_sections.forEach(function (e) {
//console.log("visible: " + e);
let section_id = K.attr(e, "id");
let navlink = K.get(".navlink[data-target=\"" + section_id + "\"]");
if (navlink) {
open_highlighted_sections(navlink);
}
});
}
var last_visible = [];
//function find_visible_element(node) {
// [...node.children].forEach(function (o) {
function highlight_headers_in_toc() {
let navlink_map = {};
[...K.getv(".navlink")].forEach(
function (o) { add_navlink_mapping(navlink_map, o); });
[...K.getv(".highlight")].forEach(function (o) {
K.remove_class(o, "highlight");
});
let [visible, invisible] = headers_in_text();
/*
console.log("-");
console.log("visible: ");
console.log(visible);
console.log("visible length: " + visible.length + " " + visible);
console.log("invisible: ");
console.log(invisible);
console.log("invisible length: " + invisible.length + " " + invisible);
console.log("-");
*/
let max_level = 0;
if (visible.length > 0) {
visible.forEach(function (h) {
if (h.id) {
K.add_class(navlink_map[h.id], "highlight");
//console.log(h);
max_level = Math.max(max_level, parseInt(K.attr(h, "data-level")));
}
});
}
//console.log("max_level: ", max_level);
if (invisible.length > 0) {
invisible.forEach(function (h) {
if (h.id) {
K.remove_class(navlink_map[h.id], "highlight");
}
});
}
//if (toc_count === 0) {
/*
if (visible.length !== 0) {
//console.log("last visible: " + last_visible);
//last_visible = visible[visible.length - 1];
last_visible = visible[0];
} else {
//console.log("None visible; setting:")
//console.log(last_visible);
//visible = [last_visible];
}
console.log("visible");
console.log(visible);
*/
//console.log("last_visible:");
//console.log(last_visible);
if (visible.length === 0 && last_visible.id && navlink_map[last_visible.id]) {
// No headers are visible; use the header of the displayed element
//console.log("setting visiblity of " + last_visible.id);
K.add_class(navlink_map[last_visible.id], "highlight");
/*
last_visible.forEach(function (h) {
K.add_class(navlink_map[h.id], "highlight");
});
*/
}
if (visible.length !== 0) {
//console.log("set last visible: " + last_visible.id);
//last_visible = visible[visible.length - 1];
last_visible = visible[visible.length - 1];
}
open_visible();
}
/*
function update_hash() {
const first_highlighted_navlink = K.get(".section-title.highlight").parentNode;
const basename = K.attr(first_highlighted_navlink, "data-page");
const target = K.attr(first_highlighted_navlink, "data-target");
window.location.hash = "#" + basename + "#" + target;
}
*/
var navigation_interval = null;
function go_to_section(elt, basename_arg, target_arg, force_reload, on_loaded) {
const basename = basename_arg || K.attr(elt, "data-page");
const target = target_arg || (elt ? K.attr(elt, "data-target") : null);
const parts = window.location.toString().split("#");
let hash = "#" + basename;
if (target) {
hash += "#" + target;
}
let basepage = K.get("#_page_" + basename);
if (!basepage) {
return;
}
if (navigation_interval) {
clearInterval(navigation_interval);
navigation_interval = null;
}
var retries = 0;
const max_retries = 100;
navigation_interval = setInterval(function() {
if (!K.get("#text") || parts[1] != basename || force_reload) {
displayed_text().innerHTML = K.get("#_page_" + basename).innerHTML;
resize_images();
if (!force_reload) {
unhighlight_search_targets();
}
}
force_reload = false;
var target_element = document.getElementById(target);
if (!target_element) {
if (++retries > max_retries) {
clearInterval(navigation_interval);
navigation_interval = null;
}
return;
}
clearInterval(navigation_interval);
navigation_interval = null;
if (on_loaded) {
on_loaded();
}
let text_div = displayed_text();
text_div.scrollTop = target_element.offsetTop - text_div.offsetTop;
remove_toc_highlighting();
highlight_headers_in_toc();
set_next_last_button_status();
set_link_listeners();
window.location.hash = hash;
localStorage.setItem("klammertext_location", `${basename}:${target}`);
}, 10);
K.get("#help").textContent = "Help";
}
function toggle_caret(node) {
//console.trace();
node.parentElement.querySelector(".nested").classList.toggle("active");
node.classList.toggle("caret-down");
resize_toc();
}
function add_scrolling_to_text() {
K.get("#text").addEventListener("scroll", function (event) {
//event.preventDefault();
//console.log("scroll " + K.get("#text").scrollTop);
highlight_headers_in_toc();
//show_all_highlighted();
});
}
window.addEventListener("load", function (event) {
var toggler = document.getElementsByClassName("caret");
for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function(event) {
toggle_caret(event.srcElement);
});
}
K.map(".section-number, .section-title-text", function(elt) {
elt.addEventListener("click", function (event) {
event.preventDefault();
buttons_before_search();
const caret = event.srcElement.parentNode.parentNode.parentNode.firstChild;
if (caret.nodeName !== "#text") {
const caret_down = K.has_class(caret, "caret-down");
if (!caret_down) {
toggle_caret(caret);
}
}
go_to_section(elt.parentNode.parentNode);
});
});
add_scrolling_to_text();
/*
K.get("#text").addEventListener("scroll", function (event) {
//event.preventDefault();
console.log("scroll " + K.get("#text").scrollTop);
highlight_headers_in_toc();
//show_all_highlighted();
});
*/
//highlight_headers_in_toc();
//open_visible();
//show_all_highlighted();
});