diff --git a/index.html b/index.html index 3fca4ae..69998aa 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 = []; @@ -455,25 +455,68 @@ }; function findActiveClause(root, path) { - let clauses = getChildClauses(root); path = path || []; - for (let $clause of clauses) { - let rect = $clause.getBoundingClientRect(); + let visibleClauses = getVisibleClauses(root, path); + let midpoint = Math.floor(window.innerHeight / 2); + + for (let [$clause, path] of visibleClauses) { + let { top: clauseTop, bottom: clauseBottom } = $clause.getBoundingClientRect(); + let isFullyVisibleAboveTheFold = + clauseTop > 0 && clauseTop < midpoint && clauseBottom < window.innerHeight; + if (isFullyVisibleAboveTheFold) { + return path; + } + } + + visibleClauses.sort(([, pathA], [, pathB]) => pathB.length - pathA.length); + for (let [$clause, path] of visibleClauses) { + let { top: clauseTop, bottom: clauseBottom } = $clause.getBoundingClientRect(); let $header = $clause.querySelector('h1'); + let clauseStyles = getComputedStyle($clause); let marginTop = Math.max( - parseInt(getComputedStyle($clause)['margin-top']), + 0, + parseInt(clauseStyles['margin-top']), parseInt(getComputedStyle($header)['margin-top']) ); - - if (rect.top - marginTop <= 1 && rect.bottom > 0) { - return findActiveClause($clause, path.concat($clause)) || path; + let marginBottom = Math.max(0, parseInt(clauseStyles['margin-bottom'])); + let crossesMidpoint = + clauseTop - marginTop <= midpoint && clauseBottom + marginBottom >= midpoint; + if (crossesMidpoint) { + return path; } } return path; } +function getVisibleClauses(root, path) { + let childClauses = getChildClauses(root); + path = path || []; + + let result = []; + + let seenVisibleClause = false; + for (let $clause of childClauses) { + let { top: clauseTop, bottom: clauseBottom } = $clause.getBoundingClientRect(); + let isPartiallyVisible = + (clauseTop > 0 && clauseTop < window.innerHeight) || + (clauseBottom > 0 && clauseBottom < window.innerHeight) || + (clauseTop < 0 && clauseBottom > window.innerHeight); + + if (isPartiallyVisible) { + seenVisibleClause = true; + let innerPath = path.concat($clause); + result.push([$clause, innerPath]); + result.push(...getVisibleClauses($clause, innerPath)); + } else if (seenVisibleClause) { + break; + } + } + + return result; +} + function* getChildClauses(root) { for (let el of root.children) { switch (el.nodeName) { @@ -754,6 +797,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 +946,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 +967,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 +1163,270 @@ 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 initTOCExpansion(visibleItemLimit) { + // Initialize to a reasonable amount of TOC expansion: + // * Expand any full-breadth nesting level up to visibleItemLimit. + // * Expand any *single-item* level while under visibleItemLimit (even if that pushes over it). + + // Limit to initialization by bailing out if any parent item is already expanded. + const tocItems = Array.from(document.querySelectorAll('#menu-toc li')); + if (tocItems.some(li => li.classList.contains('active') && li.querySelector('li'))) { + return; + } + + const selfAndSiblings = maybe => Array.from(maybe?.parentNode.children ?? []); + let currentLevelItems = selfAndSiblings(tocItems[0]); + let availableCount = visibleItemLimit - currentLevelItems.length; + while (availableCount > 0 && currentLevelItems.length) { + const nextLevelItems = currentLevelItems.flatMap(li => selfAndSiblings(li.querySelector('li'))); + availableCount -= nextLevelItems.length; + if (availableCount > 0 || currentLevelItems.length === 1) { + // Expand parent items of the next level down (i.e., current-level items with children). + for (const ol of new Set(nextLevelItems.map(li => li.parentNode))) { + ol.closest('li').classList.add('active'); + } + } + currentLevelItems = nextLevelItems; + } +} + +function initState() { + if (typeof menu === 'undefined' || window.navigating) { + return; + } + const storage = typeof sessionStorage !== 'undefined' ? sessionStorage : Object.create(null); + if (storage.referencePaneState != null) { + let state = JSON.parse(storage.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 storage.referencePaneState; + } + } + + if (storage.activeTocPaths != null) { + document.querySelectorAll('#menu-toc li.active').forEach(li => li.classList.remove('active')); + let active = JSON.parse(storage.activeTocPaths); + active.forEach(activateTocPath); + delete storage.activeTocPaths; + } else { + initTOCExpansion(20); + } + + if (storage.searchValue != null) { + let value = JSON.parse(storage.searchValue); + menu.search.$searchBox.value = value; + menu.search.search(value); + delete storage.searchValue; + } + + if (storage.tocScroll != null) { + let tocScroll = JSON.parse(storage.tocScroll); + menu.$toc.scrollTop = tocScroll; + delete storage.tocScroll; + } +} + +document.addEventListener('DOMContentLoaded', initState); + +window.addEventListener('pageshow', initState); + +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(`{"prod-KCDyML_C":{"Early":{"clause":"1.2.1","ids":["prod-p4aAXPL4"]}}}`); -let biblio = JSON.parse(`{"refsByClause":{"sec-jsx-string-characters":["_ref_0","_ref_60","_ref_61","_ref_62"],"sec-jsx-PrimaryExpression":["_ref_1","_ref_2"],"sec-jsx-elements":["_ref_3","_ref_4","_ref_5","_ref_6","_ref_7","_ref_8","_ref_9","_ref_10","_ref_11","_ref_12","_ref_13","_ref_14","_ref_15","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_23","_ref_24"],"sec-jsx-elements-early-errors":["_ref_25","_ref_26","_ref_27","_ref_28","_ref_29","_ref_30","_ref_31"],"sec-jsx-attributes":["_ref_32","_ref_33","_ref_34","_ref_35","_ref_36","_ref_37","_ref_38","_ref_39","_ref_40","_ref_41","_ref_42","_ref_43","_ref_44","_ref_45","_ref_46","_ref_47","_ref_48","_ref_49","_ref_50"],"sec-jsx-children":["_ref_51","_ref_52","_ref_53","_ref_54","_ref_55","_ref_56","_ref_57","_ref_58","_ref_59"],"sec-HTMLCharacterReference":["_ref_63","_ref_64","_ref_65","_ref_66"],"sec-jsx-JSXString":["_ref_67","_ref_68","_ref_69"],"sec-jsx-JSXString-SV":["_ref_70","_ref_71","_ref_72","_ref_73"]},"entries":[{"type":"clause","id":"sec-rationale","titleHTML":"Rationale","number":""},{"type":"clause","id":"sec-intro","titleHTML":"Introduction","number":""},{"type":"clause","id":"sec-jsx-PrimaryExpression","titleHTML":"Modified Productions","number":"1.1"},{"type":"production","id":"prod-JSXElement","name":"JSXElement","referencingIds":["_ref_1","_ref_43","_ref_54"]},{"type":"production","id":"prod-JSXSelfClosingElement","name":"JSXSelfClosingElement","referencingIds":["_ref_3"]},{"type":"production","id":"prod-JSXOpeningElement","name":"JSXOpeningElement","referencingIds":["_ref_4","_ref_25","_ref_29"]},{"type":"production","id":"prod-JSXClosingElement","name":"JSXClosingElement","referencingIds":["_ref_6","_ref_27","_ref_31"]},{"type":"production","id":"prod-JSXFragment","name":"JSXFragment","referencingIds":["_ref_2","_ref_44","_ref_55"]},{"type":"production","id":"prod-JSXElementName","name":"JSXElementName","referencingIds":["_ref_7","_ref_9","_ref_11","_ref_28","_ref_30"]},{"type":"production","id":"prod-JSXIdentifier","name":"JSXIdentifier","referencingIds":["_ref_13","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_24","_ref_38"]},{"type":"production","id":"prod-JSXNamespacedName","name":"JSXNamespacedName","referencingIds":["_ref_14","_ref_39"]},{"type":"production","id":"prod-JSXMemberExpression","name":"JSXMemberExpression","referencingIds":["_ref_15","_ref_23"]},{"type":"clause","id":"sec-jsx-elements-early-errors","titleHTML":"Static Semantics: Early Errors","number":"1.2.1"},{"type":"clause","id":"sec-jsx-elements","titleHTML":"JSX Elements","number":"1.2"},{"type":"production","id":"prod-JSXAttributes","name":"JSXAttributes","referencingIds":["_ref_8","_ref_10","_ref_33","_ref_35"]},{"type":"production","id":"prod-JSXSpreadAttribute","name":"JSXSpreadAttribute","referencingIds":["_ref_32"]},{"type":"production","id":"prod-JSXAttribute","name":"JSXAttribute","referencingIds":["_ref_34"]},{"type":"production","id":"prod-JSXAttributeName","name":"JSXAttributeName","referencingIds":["_ref_36"]},{"type":"production","id":"prod-JSXAttributeInitializer","name":"JSXAttributeInitializer","referencingIds":["_ref_37"]},{"type":"production","id":"prod-JSXAttributeValue","name":"JSXAttributeValue","referencingIds":["_ref_40","_ref_60"]},{"type":"production","id":"prod-JSXDoubleStringCharacters","name":"JSXDoubleStringCharacters","referencingIds":["_ref_41","_ref_46","_ref_67"]},{"type":"production","id":"prod-JSXDoubleStringCharacter","name":"JSXDoubleStringCharacter","referencingIds":["_ref_45"]},{"type":"production","id":"prod-JSXSingleStringCharacters","name":"JSXSingleStringCharacters","referencingIds":["_ref_42","_ref_49","_ref_68"]},{"type":"production","id":"prod-JSXSingleStringCharacter","name":"JSXSingleStringCharacter","referencingIds":["_ref_48"]},{"type":"clause","id":"sec-jsx-attributes","titleHTML":"JSX Attributes","number":"1.3"},{"type":"production","id":"prod-JSXChildren","name":"JSXChildren","referencingIds":["_ref_5","_ref_12","_ref_26","_ref_52"]},{"type":"production","id":"prod-JSXChild","name":"JSXChild","referencingIds":["_ref_51"]},{"type":"production","id":"prod-JSXText","name":"JSXText","referencingIds":["_ref_53","_ref_58","_ref_61","_ref_69"]},{"type":"production","id":"prod-JSXTextCharacter","name":"JSXTextCharacter","referencingIds":["_ref_57"]},{"type":"production","id":"prod-JSXChildExpression","name":"JSXChildExpression","referencingIds":["_ref_56"]},{"type":"clause","id":"sec-jsx-children","titleHTML":"JSX Children","number":"1.4"},{"type":"production","id":"prod-JSXStringCharacter","name":"JSXStringCharacter","referencingIds":["_ref_47","_ref_50","_ref_59","_ref_71"]},{"type":"clause","id":"sec-jsx-string-characters","titleHTML":"JSX String Characters","number":"1.5.1"},{"type":"production","id":"prod-HTMLCharacterReference","name":"HTMLCharacterReference","referencingIds":["_ref_62"]},{"type":"production","id":"prod-HTMLDecimalCharacterReference","name":"HTMLDecimalCharacterReference","referencingIds":["_ref_63"]},{"type":"production","id":"prod-HTMLHexCharacterReference","name":"HTMLHexCharacterReference","referencingIds":["_ref_64"]},{"type":"production","id":"prod-HTMLNamedCharacterReference","name":"HTMLNamedCharacterReference","referencingIds":["_ref_65"]},{"type":"production","id":"prod-HTMLNamedCharacterReferenceName","name":"HTMLNamedCharacterReferenceName","referencingIds":["_ref_66","_ref_72","_ref_73"]},{"type":"clause","id":"sec-HTMLCharacterReference","titleHTML":"HTML Character References","number":"1.5.2","referencingIds":["_ref_0"]},{"type":"production","id":"prod-JSXString","name":"JSXString","referencingIds":["_ref_70"]},{"type":"clause","id":"sec-jsx-JSXString-SV","titleHTML":"Static Semantics: SV","number":"1.5.3.1"},{"type":"clause","id":"sec-jsx-JSXString","titleHTML":"JSX String Definition","number":"1.5.3"},{"type":"clause","id":"sec-jsx-string","titleHTML":"JSX Strings","number":"1.5"},{"type":"clause","id":"sec-jsx","titleHTML":"JSX Definition","number":"1"},{"type":"clause","id":"sec-why-not-template-literals","titleHTML":"Why not Template Literals?","number":"A"},{"type":"clause","id":"sec-why-not-JXON","titleHTML":"Why not JXON?","number":"B"},{"type":"clause","id":"sec-prior-art","titleHTML":"Prior Art","number":"C"},{"type":"clause","id":"sec-license","titleHTML":"License","number":"D"}]}`); +let biblio = JSON.parse(`{"refsByClause":{"sec-jsx-string-characters":["_ref_0","_ref_62","_ref_63","_ref_64"],"sec-jsx-PrimaryExpression":["_ref_1","_ref_2"],"sec-jsx-elements":["_ref_3","_ref_4","_ref_5","_ref_6","_ref_7","_ref_8","_ref_9","_ref_10","_ref_11","_ref_12","_ref_13","_ref_14","_ref_15","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_23","_ref_24","_ref_32","_ref_33"],"sec-jsx-elements-early-errors":["_ref_25","_ref_26","_ref_27","_ref_28","_ref_29","_ref_30","_ref_31"],"sec-jsx-attributes":["_ref_34","_ref_35","_ref_36","_ref_37","_ref_38","_ref_39","_ref_40","_ref_41","_ref_42","_ref_43","_ref_44","_ref_45","_ref_46","_ref_47","_ref_48","_ref_49","_ref_50","_ref_51","_ref_52"],"sec-jsx-children":["_ref_53","_ref_54","_ref_55","_ref_56","_ref_57","_ref_58","_ref_59","_ref_60","_ref_61"],"sec-HTMLCharacterReference":["_ref_65","_ref_66","_ref_67","_ref_68"],"sec-jsx-JSXString":["_ref_69","_ref_70","_ref_71"],"sec-jsx-JSXString-SV":["_ref_72","_ref_73","_ref_74","_ref_75"]},"entries":[{"type":"clause","id":"sec-rationale","titleHTML":"Rationale","number":""},{"type":"clause","id":"sec-intro","titleHTML":"Introduction","number":""},{"type":"clause","id":"sec-jsx-PrimaryExpression","titleHTML":"Modified Productions","number":"1.1"},{"type":"production","id":"prod-JSXElement","name":"JSXElement","referencingIds":["_ref_1","_ref_45","_ref_56"]},{"type":"production","id":"prod-JSXSelfClosingElement","name":"JSXSelfClosingElement","referencingIds":["_ref_3"]},{"type":"production","id":"prod-JSXOpeningElement","name":"JSXOpeningElement","referencingIds":["_ref_4","_ref_25","_ref_29"]},{"type":"production","id":"prod-JSXClosingElement","name":"JSXClosingElement","referencingIds":["_ref_6","_ref_27","_ref_31"]},{"type":"production","id":"prod-JSXFragment","name":"JSXFragment","referencingIds":["_ref_2","_ref_46","_ref_57"]},{"type":"production","id":"prod-JSXElementName","name":"JSXElementName","referencingIds":["_ref_7","_ref_9","_ref_11","_ref_28","_ref_30"]},{"type":"production","id":"prod-JSXIdentifier","name":"JSXIdentifier","referencingIds":["_ref_13","_ref_16","_ref_17","_ref_18","_ref_19","_ref_20","_ref_21","_ref_22","_ref_24","_ref_32","_ref_33","_ref_40"]},{"type":"production","id":"prod-JSXNamespacedName","name":"JSXNamespacedName","referencingIds":["_ref_14","_ref_41"]},{"type":"production","id":"prod-JSXMemberExpression","name":"JSXMemberExpression","referencingIds":["_ref_15","_ref_23"]},{"type":"clause","id":"sec-jsx-elements-early-errors","titleHTML":"Static Semantics: Early Errors","number":"1.2.1"},{"type":"clause","id":"sec-jsx-elements","titleHTML":"JSX Elements","number":"1.2"},{"type":"production","id":"prod-JSXAttributes","name":"JSXAttributes","referencingIds":["_ref_8","_ref_10","_ref_35","_ref_37"]},{"type":"production","id":"prod-JSXSpreadAttribute","name":"JSXSpreadAttribute","referencingIds":["_ref_34"]},{"type":"production","id":"prod-JSXAttribute","name":"JSXAttribute","referencingIds":["_ref_36"]},{"type":"production","id":"prod-JSXAttributeName","name":"JSXAttributeName","referencingIds":["_ref_38"]},{"type":"production","id":"prod-JSXAttributeInitializer","name":"JSXAttributeInitializer","referencingIds":["_ref_39"]},{"type":"production","id":"prod-JSXAttributeValue","name":"JSXAttributeValue","referencingIds":["_ref_42","_ref_62"]},{"type":"production","id":"prod-JSXDoubleStringCharacters","name":"JSXDoubleStringCharacters","referencingIds":["_ref_43","_ref_48","_ref_69"]},{"type":"production","id":"prod-JSXDoubleStringCharacter","name":"JSXDoubleStringCharacter","referencingIds":["_ref_47"]},{"type":"production","id":"prod-JSXSingleStringCharacters","name":"JSXSingleStringCharacters","referencingIds":["_ref_44","_ref_51","_ref_70"]},{"type":"production","id":"prod-JSXSingleStringCharacter","name":"JSXSingleStringCharacter","referencingIds":["_ref_50"]},{"type":"clause","id":"sec-jsx-attributes","titleHTML":"JSX Attributes","number":"1.3"},{"type":"production","id":"prod-JSXChildren","name":"JSXChildren","referencingIds":["_ref_5","_ref_12","_ref_26","_ref_54"]},{"type":"production","id":"prod-JSXChild","name":"JSXChild","referencingIds":["_ref_53"]},{"type":"production","id":"prod-JSXText","name":"JSXText","referencingIds":["_ref_55","_ref_60","_ref_63","_ref_71"]},{"type":"production","id":"prod-JSXTextCharacter","name":"JSXTextCharacter","referencingIds":["_ref_59"]},{"type":"production","id":"prod-JSXChildExpression","name":"JSXChildExpression","referencingIds":["_ref_58"]},{"type":"clause","id":"sec-jsx-children","titleHTML":"JSX Children","number":"1.4"},{"type":"production","id":"prod-JSXStringCharacter","name":"JSXStringCharacter","referencingIds":["_ref_49","_ref_52","_ref_61","_ref_73"]},{"type":"clause","id":"sec-jsx-string-characters","titleHTML":"JSX String Characters","number":"1.5.1"},{"type":"production","id":"prod-HTMLCharacterReference","name":"HTMLCharacterReference","referencingIds":["_ref_64"]},{"type":"production","id":"prod-HTMLDecimalCharacterReference","name":"HTMLDecimalCharacterReference","referencingIds":["_ref_65"]},{"type":"production","id":"prod-HTMLHexCharacterReference","name":"HTMLHexCharacterReference","referencingIds":["_ref_66"]},{"type":"production","id":"prod-HTMLNamedCharacterReference","name":"HTMLNamedCharacterReference","referencingIds":["_ref_67"]},{"type":"production","id":"prod-HTMLNamedCharacterReferenceName","name":"HTMLNamedCharacterReferenceName","referencingIds":["_ref_68","_ref_74","_ref_75"]},{"type":"clause","id":"sec-HTMLCharacterReference","titleHTML":"HTML Character References","number":"1.5.2","referencingIds":["_ref_0"]},{"type":"production","id":"prod-JSXString","name":"JSXString","referencingIds":["_ref_72"]},{"type":"clause","id":"sec-jsx-JSXString-SV","titleHTML":"Static Semantics: SV","number":"1.5.3.1"},{"type":"clause","id":"sec-jsx-JSXString","titleHTML":"JSX String Definition","number":"1.5.3"},{"type":"clause","id":"sec-jsx-string","titleHTML":"JSX Strings","number":"1.5"},{"type":"clause","id":"sec-jsx","titleHTML":"JSX Definition","number":"1"},{"type":"clause","id":"sec-why-not-template-literals","titleHTML":"Why not Template Literals?","number":"A"},{"type":"clause","id":"sec-why-not-JXON","titleHTML":"Why not JXON?","number":"B"},{"type":"clause","id":"sec-prior-art","titleHTML":"Prior Art","number":"C"},{"type":"clause","id":"sec-license","titleHTML":"License","number":"D"}]}`); ;let usesMultipage = false