123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /* toc.js - Generate and manage the table of content
- Copyright © 2017 Free Software Foundation, Inc.
- This file is part of GNU Texinfo.
- GNU Texinfo is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- GNU Texinfo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Texinfo. If not, see <http://www.gnu.org/licenses/>. */
- import {
- absolute_url_p,
- basename,
- depth_first_walk,
- href_hash
- } from "./utils";
- import config from "./config";
- /** Return a relative URL corresponding to HREF, which refers to an anchor of
- 'config.INDEX_NAME'. URL must be a USVString representing an absolute or
- relative URL.
- For example "foo/bar.html" will return "config.INDEX_NAME#bar". */
- export function
- with_sidebar_query (href)
- {
- if (basename (href) === config.INDEX_NAME)
- return config.INDEX_NAME;
- else
- {
- let url = new window.URL (href, window.location);
- let hash = basename (url.pathname, /[.]x?html/) + url.hash.slice (1);
- return config.INDEX_NAME + "#" + hash;
- }
- }
- /* Keep children but remove grandchildren (Exception: don't remove
- anything on the current page; however, that's not a problem in the
- Kawa manual). */
- function
- hide_grand_child_nodes (ul)
- {
- for (let li = ul.firstElementChild; li; li = li.nextElementSibling)
- {
- let a = li.firstElementChild;
- let li$ = a && a.nextElementSibling;
- /* Never remove Overall-Index. */
- if (li$ && a.getAttribute ("href") !== config.OVERALL_INDEX_NAME)
- li$.setAttribute ("toc-detail", "yes");
- }
- }
- /** Scan ToC entries to see which should be hidden. */
- export function
- scan_toc (node, filename)
- {
- var current = with_sidebar_query (filename);
- var ul = node.querySelector ("ul");
- if (filename === config.INDEX_NAME)
- hide_grand_child_nodes (ul);
- else
- scan_toc1 (ul, current);
- }
- /* Scan ToC entries to see which should be hidden. Return "current" if node
- matches current, "ancestor" if node is ancestor of current, else 'null'. */
- function
- scan_toc1 (node, current)
- {
- if (node.matches ("a"))
- {
- if (current === node.getAttribute ("href"))
- {
- node.setAttribute ("toc-current", "yes");
- var ul = node.nextElementSibling;
- if (ul && ul.matches ("ul"))
- hide_grand_child_nodes (ul);
- return "current";
- }
- }
- var ancestor = null;
- for (var child = node.firstElementChild; child;
- child = child.nextElementSibling)
- {
- if (scan_toc1 (child, current) !== null)
- {
- ancestor = child;
- break;
- }
- }
- if (ancestor && ancestor.parentNode && ancestor.parentNode.parentNode)
- {
- var pparent = ancestor.parentNode.parentNode;
- for (var sib = pparent.firstElementChild; sib;
- sib = sib.nextElementSibling)
- {
- if (sib !== ancestor.parentNode
- && sib.firstElementChild
- && sib.firstElementChild.nextElementSibling)
- {
- sib.firstElementChild
- .nextElementSibling
- .setAttribute ("toc-detail", "yes");
- }
- }
- }
- return ancestor ? "ancestor" : null;
- }
- /** Reset what is done by 'scan_toc' and 'hide_grand_child_nodes'. */
- export function
- clear_toc_styles (node)
- {
- function
- do_clear (node$)
- {
- if (node$.matches ("ul"))
- node$.removeAttribute ("toc-detail");
- else if (node$.matches ("a"))
- node$.removeAttribute ("toc-current");
- }
- depth_first_walk (node, do_clear, Node.ELEMENT_NODE);
- }
- /** Build the global dictionary containing navigation links from NAV. NAV
- must be an 'ul' DOM element containing the table of content of the
- manual. */
- export function
- create_link_dict (nav)
- {
- let prev_id = config.INDEX_ID;
- let links = {};
- function
- add_link (elem)
- {
- if (elem.matches ("a") && elem.hasAttribute ("href"))
- {
- let id = href_hash (elem.getAttribute ("href"));
- links[prev_id] = Object.assign ({}, links[prev_id], { forward: id });
- links[id] = Object.assign ({}, links[id], { backward: prev_id });
- prev_id = id;
- }
- }
- depth_first_walk (nav, add_link, Node.ELEMENT_NODE);
- return links;
- }
- /** Modify LINKS to handle the iframe based navigation properly. Relative
- links will be opened inside the corresponding iframe and absolute links
- will be opened in a new tab. LINKS must be an array or a collection of
- nodes. */
- export function
- fix_links (links)
- {
- for (let i = 0; i < links.length; i += 1)
- {
- let link = links[i];
- let href = link.getAttribute ("href");
- if (href)
- {
- if (absolute_url_p (href))
- link.setAttribute ("target", "_blank");
- else
- link.setAttribute ("href", with_sidebar_query (href));
- }
- }
- }
|