From e4e6b133a2d82de2e2c8565579e0d3833965ad89 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Wed, 31 May 2023 15:17:47 -0700 Subject: [PATCH] [Dev Deps] update `ecmarkup` --- index.html | 296 ++++++++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 256 insertions(+), 42 deletions(-) diff --git a/index.html b/index.html index 04fa919..74ee93a 100644 --- a/index.html +++ b/index.html @@ -214,7 +214,7 @@ if (/^[\d.]*$/.test(searchString)) { results = this.biblio.clauses .filter(clause => clause.number.substring(0, searchString.length) === searchString) - .map(clause => ({ entry: clause })); + .map(clause => ({ key: getKey(clause), entry: clause })); } else { results = []; @@ -754,6 +754,7 @@ let $spacer = document.createElement('div'); $spacer.setAttribute('id', 'references-pane-spacer'); + $spacer.classList.add('menu-spacer'); this.$pane = document.createElement('div'); this.$pane.setAttribute('id', 'references-pane'); @@ -902,6 +903,7 @@ e.preventDefault(); e.stopPropagation(); menu.togglePinEntry(this.entry.id); + this.$pinLink.textContent = menu._pinnedIds[this.entry.id] ? 'Unpin' : 'Pin'; }); this.$refsLink = document.createElement('a'); @@ -922,6 +924,7 @@ sdoBox.deactivate(); this.active = true; this.entry = entry; + this.$pinLink.textContent = menu._pinnedIds[entry.id] ? 'Unpin' : 'Pin'; this.$outer.classList.add('active'); this.top = el.offsetTop - this.$outer.offsetHeight; this.left = el.offsetLeft - 10; @@ -1117,41 +1120,245 @@ referencePane.init(); }); +// preserve state during navigation + +function getTocPath(li) { + let path = []; + let pointer = li; + while (true) { + let parent = pointer.parentElement; + if (parent == null) { + return null; + } + let index = [].indexOf.call(parent.children, pointer); + if (index == -1) { + return null; + } + path.unshift(index); + pointer = parent.parentElement; + if (pointer == null) { + return null; + } + if (pointer.id === 'menu-toc') { + break; + } + if (pointer.tagName !== 'LI') { + return null; + } + } + return path; +} + +function activateTocPath(path) { + try { + let pointer = document.getElementById('menu-toc'); + for (let index of path) { + pointer = pointer.querySelector('ol').children[index]; + } + pointer.classList.add('active'); + } catch (e) { + // pass + } +} + +function getActiveTocPaths() { + return [...menu.$menu.querySelectorAll('.active')].map(getTocPath).filter(p => p != null); +} + +function loadStateFromSessionStorage() { + if (!window.sessionStorage || typeof menu === 'undefined' || window.navigating) { + return; + } + if (sessionStorage.referencePaneState != null) { + let state = JSON.parse(sessionStorage.referencePaneState); + if (state != null) { + if (state.type === 'ref') { + let entry = menu.search.biblio.byId[state.id]; + if (entry != null) { + referencePane.showReferencesFor(entry); + } + } else if (state.type === 'sdo') { + let sdos = sdoMap[state.id]; + if (sdos != null) { + referencePane.$headerText.innerHTML = state.html; + referencePane.showSDOsBody(sdos, state.id); + } + } + delete sessionStorage.referencePaneState; + } + } + + if (sessionStorage.activeTocPaths != null) { + document + .getElementById('menu-toc') + .querySelectorAll('.active') + .forEach(e => { + e.classList.remove('active'); + }); + let active = JSON.parse(sessionStorage.activeTocPaths); + active.forEach(activateTocPath); + delete sessionStorage.activeTocPaths; + } + + if (sessionStorage.searchValue != null) { + let value = JSON.parse(sessionStorage.searchValue); + menu.search.$searchBox.value = value; + menu.search.search(value); + delete sessionStorage.searchValue; + } + + if (sessionStorage.tocScroll != null) { + let tocScroll = JSON.parse(sessionStorage.tocScroll); + menu.$toc.scrollTop = tocScroll; + delete sessionStorage.tocScroll; + } +} + +document.addEventListener('DOMContentLoaded', loadStateFromSessionStorage); + +window.addEventListener('pageshow', loadStateFromSessionStorage); + +window.addEventListener('beforeunload', () => { + if (!window.sessionStorage || typeof menu === 'undefined') { + return; + } + sessionStorage.referencePaneState = JSON.stringify(referencePane.state || null); + sessionStorage.activeTocPaths = JSON.stringify(getActiveTocPaths()); + sessionStorage.searchValue = JSON.stringify(menu.search.$searchBox.value); + sessionStorage.tocScroll = JSON.stringify(menu.$toc.scrollTop); +}); + 'use strict'; -let decimalBullet = Array.from({ length: 100 }, (a, i) => '' + (i + 1)); -let alphaBullet = Array.from({ length: 26 }, (a, i) => String.fromCharCode('a'.charCodeAt(0) + i)); - -// prettier-ignore -let romanBullet = ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix', 'x', 'xi', 'xii', 'xiii', 'xiv', 'xv', 'xvi', 'xvii', 'xviii', 'xix', 'xx', 'xxi', 'xxii', 'xxiii', 'xxiv', 'xxv']; -// prettier-ignore -let bullets = [decimalBullet, alphaBullet, romanBullet, decimalBullet, alphaBullet, romanBullet]; - -function addStepNumberText(ol, parentIndex) { - for (let i = 0; i < ol.children.length; ++i) { - let child = ol.children[i]; - let index = parentIndex.concat([i]); - let applicable = bullets[Math.min(index.length - 1, 5)]; - let span = document.createElement('span'); - span.textContent = (applicable[i] || '?') + '. '; - span.style.fontSize = '0'; - span.setAttribute('aria-hidden', 'true'); - child.prepend(span); - let sublist = child.querySelector('ol'); - if (sublist != null) { - addStepNumberText(sublist, index); + +// Manually prefix algorithm step list items with hidden counter representations +// corresponding with their markers so they get selected and copied with content. +// We read list-style-type to avoid divergence with the style sheet, but +// for efficiency assume that all lists at the same nesting depth use the same +// style (except for those associated with replacement steps). +// We also precompute some initial items for each supported style type. +// https://w3c.github.io/csswg-drafts/css-counter-styles/ + +const lowerLetters = Array.from({ length: 26 }, (_, i) => + String.fromCharCode('a'.charCodeAt(0) + i) +); +// Implement the lower-alpha 'alphabetic' algorithm, +// adjusting for indexing from 0 rather than 1. +// https://w3c.github.io/csswg-drafts/css-counter-styles/#simple-alphabetic +// https://w3c.github.io/csswg-drafts/css-counter-styles/#alphabetic-system +const lowerAlphaTextForIndex = i => { + let S = ''; + for (const N = lowerLetters.length; i >= 0; i--) { + S = lowerLetters[i % N] + S; + i = Math.floor(i / N); + } + return S; +}; + +const weightedLowerRomanSymbols = Object.entries({ + m: 1000, + cm: 900, + d: 500, + cd: 400, + c: 100, + xc: 90, + l: 50, + xl: 40, + x: 10, + ix: 9, + v: 5, + iv: 4, + i: 1, +}); +// Implement the lower-roman 'additive' algorithm, +// adjusting for indexing from 0 rather than 1. +// https://w3c.github.io/csswg-drafts/css-counter-styles/#simple-numeric +// https://w3c.github.io/csswg-drafts/css-counter-styles/#additive-system +const lowerRomanTextForIndex = i => { + let value = i + 1; + let S = ''; + for (const [symbol, weight] of weightedLowerRomanSymbols) { + if (!value) break; + if (weight > value) continue; + const reps = Math.floor(value / weight); + S += symbol.repeat(reps); + value -= weight * reps; + } + return S; +}; + +// Memoize pure index-to-text functions with an exposed cache for fast retrieval. +const makeCounter = (pureGetTextForIndex, precomputeCount = 30) => { + const cache = Array.from({ length: precomputeCount }, (_, i) => pureGetTextForIndex(i)); + const getTextForIndex = i => { + if (i >= cache.length) cache[i] = pureGetTextForIndex(i); + return cache[i]; + }; + return { getTextForIndex, cache }; +}; + +const counterByStyle = { + __proto__: null, + decimal: makeCounter(i => String(i + 1)), + 'lower-alpha': makeCounter(lowerAlphaTextForIndex), + 'upper-alpha': makeCounter(i => lowerAlphaTextForIndex(i).toUpperCase()), + 'lower-roman': makeCounter(lowerRomanTextForIndex), + 'upper-roman': makeCounter(i => lowerRomanTextForIndex(i).toUpperCase()), +}; +const fallbackCounter = makeCounter(() => '?'); +const counterByDepth = []; + +function addStepNumberText( + ol, + depth = 0, + special = [...ol.classList].some(c => c.startsWith('nested-')) +) { + let counter = !special && counterByDepth[depth]; + if (!counter) { + const counterStyle = getComputedStyle(ol)['list-style-type']; + counter = counterByStyle[counterStyle]; + if (!counter) { + console.warn('unsupported list-style-type', { + ol, + counterStyle, + id: ol.closest('[id]')?.getAttribute('id'), + }); + counterByStyle[counterStyle] = fallbackCounter; + counter = fallbackCounter; + } + if (!special) { + counterByDepth[depth] = counter; } } + const { cache, getTextForIndex } = counter; + let i = (Number(ol.getAttribute('start')) || 1) - 1; + for (const li of ol.children) { + const marker = document.createElement('span'); + marker.textContent = `${i < cache.length ? cache[i] : getTextForIndex(i)}. `; + marker.setAttribute('aria-hidden', 'true'); + const attributesContainer = li.querySelector('.attributes-tag'); + if (attributesContainer == null) { + li.prepend(marker); + } else { + attributesContainer.insertAdjacentElement('afterend', marker); + } + for (const sublist of li.querySelectorAll(':scope > ol')) { + addStepNumberText(sublist, depth + 1, special); + } + i++; + } } + document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('emu-alg > ol').forEach(ol => { - addStepNumberText(ol, []); + addStepNumberText(ol); }); }); let sdoMap = JSON.parse(`{}`); -let biblio = JSON.parse(`{"refsByClause":{"sec-object.groupby":["_ref_0","_ref_1","_ref_2"],"sec-map.groupby":["_ref_3","_ref_4","_ref_5"],"sec-group-by":["_ref_6","_ref_7","_ref_8","_ref_9","_ref_10","_ref_11","_ref_12","_ref_13","_ref_14","_ref_15","_ref_16","_ref_17"],"sec-add-value-to-keyed-group":["_ref_18"]},"entries":[{"type":"clause","id":"sec-scope","titleHTML":"Scope","number":"1"},{"type":"clause","id":"sec-object.groupby","title":"Object.groupBy ( items, callbackfn )","titleHTML":"Object.groupBy ( items, callbackfn )","number":"2.1"},{"type":"clause","id":"sec-properties-of-the-object-constructor","titleHTML":"Properties of the Object Constructor (20.1.2)","number":"2"},{"type":"clause","id":"sec-map.groupby","title":"Map.groupBy ( items, callbackfn )","titleHTML":"Map.groupBy ( items, callbackfn )","number":"3.1"},{"type":"clause","id":"sec-properties-of-the-map-constructor","titleHTML":"Properties of the Map Constructor (24.1.2)","number":"3"},{"type":"op","aoid":"GroupBy","refId":"sec-group-by"},{"type":"clause","id":"sec-group-by","title":"GroupBy ( items, callbackfn, coercion )","titleHTML":"GroupBy ( items, callbackfn, coercion )","number":"4.1","referencingIds":["_ref_0","_ref_3"]},{"type":"op","aoid":"AddValueToKeyedGroup","refId":"sec-add-value-to-keyed-group"},{"type":"clause","id":"sec-add-value-to-keyed-group","title":"AddValueToKeyedGroup ( groups, key, value )","titleHTML":"AddValueToKeyedGroup ( groups, key, value )","number":"4.2","referencingIds":["_ref_17"]},{"type":"clause","id":"sec-group-by-helpers","titleHTML":"Group By Helpers","number":"4"},{"type":"clause","id":"sec-copyright-and-software-license","title":"Copyright & Software License","titleHTML":"Copyright & Software License","number":"A"}]}`); +let biblio = JSON.parse(`{"refsByClause":{"sec-object.groupby":["_ref_0"],"sec-map.groupby":["_ref_1"],"sec-group-by":["_ref_2"]},"entries":[{"type":"clause","id":"sec-scope","titleHTML":"Scope","number":"1"},{"type":"clause","id":"sec-object.groupby","title":"Object.groupBy ( items, callbackfn )","titleHTML":"Object.groupBy ( items, callbackfn )","number":"2.1"},{"type":"clause","id":"sec-properties-of-the-object-constructor","titleHTML":"Properties of the Object Constructor (20.1.2)","number":"2"},{"type":"clause","id":"sec-map.groupby","title":"Map.groupBy ( items, callbackfn )","titleHTML":"Map.groupBy ( items, callbackfn )","number":"3.1"},{"type":"clause","id":"sec-properties-of-the-map-constructor","titleHTML":"Properties of the Map Constructor (24.1.2)","number":"3"},{"type":"op","aoid":"GroupBy","refId":"sec-group-by"},{"type":"clause","id":"sec-group-by","title":"GroupBy ( items, callbackfn, coercion )","titleHTML":"GroupBy ( items, callbackfn, coercion )","number":"4.1","referencingIds":["_ref_0","_ref_1"]},{"type":"op","aoid":"AddValueToKeyedGroup","refId":"sec-add-value-to-keyed-group"},{"type":"clause","id":"sec-add-value-to-keyed-group","title":"AddValueToKeyedGroup ( groups, key, value )","titleHTML":"AddValueToKeyedGroup ( groups, key, value )","number":"4.2","referencingIds":["_ref_2"]},{"type":"clause","id":"sec-group-by-helpers","titleHTML":"Group By Helpers","number":"4"},{"type":"clause","id":"sec-copyright-and-software-license","title":"Copyright & Software License","titleHTML":"Copyright & Software License","number":"A"}]}`); ;let usesMultipage = false