UNPKG

@jupyterlab/toc

Version:

JupyterLab - Table of Contents widget

177 lines 5.58 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. import { TableOfContents } from '../tokens'; /** * Class used to mark numbering prefix for headings in a document. */ export const NUMBERING_CLASS = 'numbering-entry'; /** * Filter headings for table of contents and compute associated prefix * * @param headings Headings to process * @param options Options * @param initialLevels Initial levels for prefix computation * @returns Extracted headings */ export function filterHeadings(headings, options, initialLevels = []) { const config = { ...TableOfContents.defaultConfig, ...options }; const levels = initialLevels; let previousLevel = levels.length; const filteredHeadings = new Array(); for (const heading of headings) { if (heading.skip) { continue; } const level = heading.level; if (level > 0 && level <= config.maximalDepth) { const prefix = getPrefix(level, previousLevel, levels, config); previousLevel = level; filteredHeadings.push({ ...heading, prefix }); } } return filteredHeadings; } /** * Returns whether a MIME type corresponds to either HTML. * * @param mime - MIME type string * @returns boolean indicating whether a provided MIME type corresponds to either HTML * * @example * const bool = isHTML('text/html'); * // returns true * * @example * const bool = isHTML('text/plain'); * // returns false */ export function isHTML(mime) { return mime === 'text/html'; } /** * Parse a HTML string for headings. * * ### Notes * The html string is not sanitized - use with caution * * @param html HTML string to parse * @param force Whether to ignore HTML headings with class jp-toc-ignore and tocSkip or not * @returns Extracted headings */ export function getHTMLHeadings(html, force = true) { var _a; const container = document.createElement('div'); container.innerHTML = html; const headings = new Array(); const headers = container.querySelectorAll('h1, h2, h3, h4, h5, h6'); for (const h of headers) { const level = parseInt(h.tagName[1], 10); headings.push({ text: (_a = h.textContent) !== null && _a !== void 0 ? _a : '', level, id: h === null || h === void 0 ? void 0 : h.getAttribute('id'), skip: h.classList.contains('jp-toc-ignore') || h.classList.contains('tocSkip') }); } return headings; } /** * Add an heading prefix to a HTML node. * * @param container HTML node containing the heading * @param selector Heading selector * @param prefix Title prefix to add * @returns The modified HTML element */ export function addPrefix(container, selector, prefix) { let element = container.querySelector(selector); if (!element) { return null; } if (!element.querySelector(`span.${NUMBERING_CLASS}`)) { addNumbering(element, prefix); } else { // There are likely multiple elements with the same selector // => use the first one without prefix const allElements = container.querySelectorAll(selector); for (const el of allElements) { if (!el.querySelector(`span.${NUMBERING_CLASS}`)) { element = el; addNumbering(el, prefix); break; } } } return element; } /** * Update the levels and create the numbering prefix * * @param level Current level * @param previousLevel Previous level * @param levels Levels list * @param options Options * @returns The numbering prefix */ export function getPrefix(level, previousLevel, levels, options) { const { baseNumbering, numberingH1, numberHeaders } = options; let prefix = ''; if (numberHeaders) { const highestLevel = numberingH1 ? 1 : 2; if (level > previousLevel) { // Initialize the new levels for (let l = previousLevel; l < level - 1; l++) { levels[l] = 0; } levels[level - 1] = level === highestLevel ? baseNumbering : 1; } else { // Increment the current level levels[level - 1] += 1; // Drop higher levels if (level < previousLevel) { levels.splice(level); } } // If the header list skips some level, replace missing elements by 0 if (numberingH1) { prefix = levels.map(level => level !== null && level !== void 0 ? level : 0).join('.') + '. '; } else { if (levels.length > 1) { prefix = levels .slice(1) .map(level => level !== null && level !== void 0 ? level : 0) .join('.') + '. '; } } } return prefix; } /** * Add a numbering prefix to a HTML element. * * @param el HTML element * @param numbering Numbering prefix to add */ function addNumbering(el, numbering) { el.insertAdjacentHTML('afterbegin', `<span class="${NUMBERING_CLASS}">${numbering}</span>`); } /** * Remove all numbering nodes from element * @param element Node to clear */ export function clearNumbering(element) { element === null || element === void 0 ? void 0 : element.querySelectorAll(`span.${NUMBERING_CLASS}`).forEach(el => { el.remove(); }); } //# sourceMappingURL=common.js.map