diff --git a/html2pdf4doc/html2pdf4doc_js/html2pdf4doc.min.js b/html2pdf4doc/html2pdf4doc_js/html2pdf4doc.min.js index 4cf2f30..1821fad 100644 --- a/html2pdf4doc/html2pdf4doc_js/html2pdf4doc.min.js +++ b/html2pdf4doc/html2pdf4doc_js/html2pdf4doc.min.js @@ -1,2 +1,10 @@ /*! Version: 0.2.3 */ -var HTML2PDF4DOC;(()=>{"use strict";var e={d:(t,o)=>{for(var n in o)e.o(o,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:o[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{init:()=>T});const o={init:"[html2pdf]",pageDivider:"html2pdf-page",pageStartMarker:"[html2pdf-page-start]",contentFlowStart:"html2pdf-content-flow-start",contentFlowEnd:"html2pdf-content-flow-end",style:"[html2pdf-style]",footerTemplate:"[html2pdf-footer]",headerTemplate:"[html2pdf-header]",frontpageTemplate:"[html2pdf-frontpage]",frontpageContent:"html2pdf-frontpage",headerContent:"html2pdf-header",footerContent:"html2pdf-footer",pageNumberRoot:"[html2pdf-page-number]",pageNumberCurrent:"[html2pdf-page-number-current]",pageNumberTotal:"[html2pdf-page-number-total]",root:"html2pdf-root",paperFlow:"html2pdf-paper-flow",contentFlow:"html2pdf-content-flow",virtualPaper:"html2pdf-virtual-paper",virtualPaperTopMargin:"html2pdf-virtual-paper-margin-top",virtualPaperBottomMargin:"html2pdf-virtual-paper-margin-bottom",virtualPaperGap:"html2pdf-virtual-paper-gap",paperBody:"html2pdf-paper-body",paperHeader:"html2pdf-paper-header",paperFooter:"html2pdf-paper-footer",runningSafety:"html2pdf-print-running",printPageBreak:"html2pdf-print-page-break",printIgnore:"[html2pdf-print-ignore]",printHide:"[html2pdf-print-hide]",neutral:"html2pdf-neutral",word:"html2pdf-word",textNode:"html2pdf-text-node",textLine:"html2pdf-text-line",textGroup:"html2pdf-text-group",complexTextBlock:"html2pdf-complex-text-block",printForcedPageBreak:"html2pdf-print-forced-page-break",splitted:"[html2pdf-splitted]",processed:"[html2pdf-processed]",flagNoBreak:"[html2pdf-flag-no-break]",flagNoHanging:"[html2pdf-flag-no-hanging]",topCutPart:".html2pdf-top-cut",bottomCutPart:".html2pdf-bottom-cut",tocPageNumber:"html2pdf-toc-page-number"};function n(e){let t={debugMode:!1,consoleAssert:!1,preloader:!1,preloaderTarget:"",preloaderBackground:"",mask:!0,noHangingSelectors:"",forcedPageBreakSelectors:"",pageBreakBeforeSelectors:"",pageBreakAfterSelectors:"",noBreakSelectors:"",tocPageNumberSelector:"html2pdf-toc-page-number",printLeftMargin:"21mm",printRightMargin:"21mm",printTopMargin:"12mm",printBottomMargin:"12mm",printFontSize:"12pt",printWidth:"210mm",printHeight:"297mm",headerMargin:"16px",footerMargin:"16px",virtualPagesGap:"16px"};const n={printWidth:"210mm",printHeight:"297mm"},s={printWidth:"148.5mm",printHeight:"210mm"};switch((e=function(e){const t={...e};for(const e in t){const o=t[e];if("string"==typeof o){const n=o.toLowerCase();"true"===n||"1"===n?t[e]=!0:"false"!==n&&"0"!==n&&""!==n||(t[e]=!1)}}return t}(e)).printPaperSize){case"A5":case"a5":t={...t,...s};break;default:t={...t,...n}}t={...t,initialRoot:o.init,tocPageNumberSelector:o.tocPageNumber,...e},console.info("[HTML2PDF4DOC] Config:",t);const i={printLeftMargin:t.printLeftMargin,printRightMargin:t.printRightMargin,printTopMargin:t.printTopMargin,printBottomMargin:t.printBottomMargin,printFontSize:t.printFontSize,printWidth:t.printWidth,printHeight:t.printHeight,headerMargin:t.headerMargin,footerMargin:t.footerMargin,virtualPagesGap:t.virtualPagesGap},r=document.createElement("div");return r.style="\n position:absolute;\n z-index:1000;\n left: 200%;\n ",document.body.append(r),Object.entries(i).forEach((([e,t])=>{r.style.width=t,i[e]=`${Math.trunc(r.getBoundingClientRect().width)}px`})),r.remove(),t={...t,...i},t.noHangingSelectors=t.noHangingSelectors+" H1 H2 H3 H4 H5 H6",t.forcedPageBreakSelectors=t.forcedPageBreakSelectors+" "+o.printForcedPageBreak,t.debugMode&&console.info("Config with converted units:",t),t}const s={DOM:{_:!1},layout:{_:!0},pages:{_:!0,_parseNode:!1,_parseNodes:!1,_registerPageStart:!1,_getProcessedChildren:!1,_splitPreNode:!1,_splitTableNode:!1,_splitTableLikeNode:!1,_splitTableRow:!1,_splitGridNode:!1,_createSlicesBySplitFlag:!1,_getInternalBlockSplitters:!1},paragraph:{_:!1},node:{_:!1},paper:{_:!1},preview:{_:!1},toc:{_:!1}};class i{constructor({DOM:e,config:t}){this.document=e,this.body=e.body,this._debugMode=t.debugMode,this._debug=t.debugMode?{...t.debugConfig.DOM}:{},this._assert=!!t.consoleAssert}createElement(e){return this.document.createElement(e)}createDocumentFragment(){return this.document.createDocumentFragment()}cloneNode(e){return e?.cloneNode(!0)}cloneNodeWrapper(e){return e?.cloneNode(!1)}insertBefore(e,...t){e.before(...t)}insertAfter(e,...t){e.after(...t)}insertAtEnd(e,...t){e.append(...t)}insertAtStart(e,...t){e.prepend(...t)}insertInsteadOf(e,...t){e.before(...t),e.remove()}moveContent(e,t){for(;e.firstChild;)t.append(e.firstChild);console.assert(""===this.getInnerHTML(e))}removeNode(e){e.remove()}getElement(e,t=this.document){return t.querySelector(e)}getAllElements(e,t=this.document){return t.querySelectorAll(e)}getElementById(e,t=this.document){return t.getElementById(e)}getRightNeighbor(e){return e.nextElementSibling}getLeftNeighbor(e){return e.previousElementSibling}getParentNode(e){return e.parentElement}getNodeValue(e){return e.nodeValue}getLastElementChild(e){return e.lastElementChild}getFirstElementChild(e){return e.firstElementChild}getChildNodes(e){return e.childNodes}getChildren(e){return e.children}getElementOffsetParent(e){return e.offsetParent}getComputedStyle(e){return window.getComputedStyle(e)}getElementBCR(e){return e.getBoundingClientRect()}getElementOffsetLeft(e){return e?.offsetLeft}getElementOffsetHeight(e){return e?.offsetHeight}getElementOffsetWidth(e){return e?.offsetWidth}getElementOffsetTop(e){return e?.offsetTop}getElementOffsetBottom(e){return e?.offsetTop+e?.offsetHeight||void 0}getElementTagName(e){return e.tagName}getDataId(e){return e.dataset.id}getAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("getAttribute() must have 2 params"));const o=t.charAt(0);if("."!==o&&"#"!==o||this._debug._&&console.log(`you're really sure ${t} is attribute selector?`),"["===o){this._assert&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);return e.getAttribute(o)}e.getAttribute(t)}setAttribute(e,t,o){if(!e||!t)return void(this._debug._&&console.warn("setAttribute() must have 2 params"));const n=t.charAt(0);if("."!==n)if("#"!==n)if("["!==n)this._debug._&&console.log(`you're really sure ${t} is a selector?`);else{this._assert&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const n=t.substring(1,t.length-1);e.setAttribute(n,o||"")}else{const o=t.substring(1);e.id=o}else{const o=t.substring(1);e.classList.add(o)}}setStyles(e,t){Object.entries(t).forEach((([t,o])=>e.style[t]=o))}addClasses(e,...t){e.classList.add(...t)}removeAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("removeAttribute() must have 2 params"));const o=t.charAt(0);if(this._assert&&console.assert(o.match(/[a-zA-Z#\[\.]/),`removeAttribute() expects a valid selector, but received ${t}`),"."!==o)if("#"!==o)if("["!==o)e.removeAttribute(attr);else{this._assert&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);e.removeAttribute(o)}else{const o=t.substring(1);e.removeAttribute(o)}else{const o=t.substring(1);e.classList.remove(o)}}removeAllAttributes(e){for(;e.attributes.length>0;)e.removeAttribute(e.attributes[0].name)}removeClasses(e,...t){e.classList.remove(...t)}removeAllClasses(e){e.classList=""}removeAllStyles(e){e.style=""}getInnerHTML(e){if("string"==typeof e){const t=this.document.querySelector(e);return t?t.innerHTML:void 0}return e.innerHTML}setInnerHTML(e,t){if("string"==typeof e){const o=this.document.querySelector(e);o&&(o.innerHTML=t)}e.innerHTML=t}isDocumentBody(e){return"BODY"===e.tagName}isTextNode(e){return e.nodeType===Node.TEXT_NODE}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}hasClass(e,t){return e.classList.contains(t)}hasID(e,t){return e.id===t}hasAttribute(e,t){return e.hasAttribute(t)}}class r{constructor(e){this.config=e,this.charWidth="10px"}create(){return this._baseStyle()+this._testStyle()}_baseStyle(){return`\n\n@page {\n size: A4;\n /* 2 values: width then height */\n size: ${this.config.printWidth} ${this.config.printHeight};\n\n margin-left: ${this.config.printLeftMargin};\n margin-right: ${this.config.printRightMargin};\n margin-top: ${this.config.printTopMargin};\n margin-bottom: 0; /* hack */\n}\n\n${o.root} {\n /* reset user styles */\n display: block;\n\n /* for proper printable flow positioning */\n position: relative;\n\n /* to compensate for possible BG in the parent node */\n z-index: 1;\n\n /* set print styles: affects previews */\n margin: 0 auto;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n font-size: ${this.config.printFontSize};\n\n /* protection against unpredictability of margins */\n padding-top: .1px;\n padding-bottom: calc(2 * ${this.config.virtualPagesGap});\n}\n\n${o.contentFlowStart},\n${o.contentFlowEnd},\n${o.pageDivider} {\n display: block;\n}\n\n${o.virtualPaper} {\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: minmax(min-content, max-content) minmax(min-content, max-content) 1fr minmax(min-content, max-content) minmax(min-content, max-content);\n place-items: stretch stretch;\n place-content: stretch stretch;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n height: ${this.config.printHeight};\n font-size: ${this.config.printFontSize};\n}\n\n${o.virtualPaper}::before {\n position: absolute;\n content: '';\n width: ${this.config.printWidth};\n height: ${this.config.printHeight};\n left: -${this.config.printLeftMargin};\n background-color: #fff;\n box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 12px 0px;\n z-index: -1;\n}\n\n${o.paperFooter},\n${o.paperHeader} {\n display: block;\n position: relative;\n}\n\n${o.headerContent},\n${o.footerContent} {\n display: block;\n font-size: small;\n}\n\n${o.headerContent} p,\n${o.footerContent} p {\n margin: 0;\n}\n\n${o.headerContent} {\n padding-bottom: ${this.config.headerMargin};\n /* padding-top: 1px; */\n /* Page numbers: */\n padding-top: 10px;\n}\n\n${o.footerContent} {\n padding-top: ${this.config.footerMargin};\n /* padding-bottom: 1px; */\n /* Page numbers: */\n min-height: 32px;\n}\n\n${o.tocPageNumber} {\n min-width: 3ch;\n display: flex;\n justify-content: flex-end;\n align-items: baseline;\n}\n\n${o.pageNumberRoot} {\n display: flex;\n column-gap: 2px;\n position: absolute;\n /* left: 100%; */\n right: 0;\n text-align: right;\n line-height: 1;\n}\n\n${o.headerContent} ${o.pageNumberRoot} {\n top: 0;\n}\n\n${o.footerContent} ${o.pageNumberRoot} {\n bottom: 0;\n}\n\n${o.paperFlow} {\n display: block;\n position: absolute;\n width: 100%;\n z-index: -1;\n /* affect only screen */\n padding-bottom: 100px;\n}\n\n${o.contentFlow} {\n display: block;\n}\n\n${o.runningSafety} {\n display: block;\n /* ? should be checked and updated,\n but in the meantime, bring back the common solution:\n firefox ignores 0.1px size, so it's necessary to make a full-size pixel\n and take it into account in the calculations:\n padding-top: 1px;\n */\n padding-top: .1px;\n}\n\n${o.virtualPaperTopMargin} {\n display: block;\n height: ${this.config.printTopMargin};\n}\n\n${o.virtualPaperBottomMargin} {\n display: block;\n height: ${this.config.printBottomMargin};\n}\n\n${o.virtualPaperGap} {\n display: block;\n padding-top: ${this.config.virtualPagesGap};\n}\n\n${o.paperBody} {\n display: block;\n}\n\n${o.frontpageContent} {\n display: block;\n transform-origin: top center;\n padding: .1px;\n height: 100%;\n}\n\n.null {\n display: inline;\n padding: 0;\n margin: 0;\n font: 0;\n color: transparent;\n line-height: 0;\n border: none;\n outline: none;\n background: none;\n background-color: transparent;\n}\n\n${o.word},\n${o.textNode},\n${o.textLine},\n${o.textGroup},\n${o.neutral},\n${o.neutral} span {\n display: inline;\n padding: 0;\n margin: 0;\n font: inherit;\n color: inherit;\n line-height: inherit;\n background: none;\n background-color: transparent;\n}\n\n${o.textGroup} {\n display: block;\n}\n\n/*${o.splitted} ${o.textGroup} {\n display: inline;\n}*/\n\n${o.complexTextBlock} > ${o.textLine} {\n /* Firefox and inconsistent values of offset top for inline element */\n display: inline-block;\n // TODO: it removes spaces between parts of the string, it should leave the text inline after processing.\n}\n\n${o.textGroup} ${o.textLine} {\n display: inline;\n}\n\n${o.complexTextBlock} {\n display: block;\n}\n\n${o.complexTextBlock} ${o.complexTextBlock} {\n display: inline;\n}\n\n${o.printPageBreak} {\n display: block;\n}\n\n${o.printForcedPageBreak} {\n display: block;\n visibility: hidden;\n height: 0;\n overflow: hidden;\n}\n\n@media print {\n ${o.root} {\n /* to prevent a blank last page */\n padding: 0;\n }\n\n ${o.paperFlow} {\n padding-bottom: 0;\n }\n\n ${o.contentFlow} {\n -webkit-mask-image: none !important;\n mask-image: none !important;\n }\n\n ${o.printIgnore} {\n display: contents;\n }\n\n ${o.printHide},\n ${o.virtualPaper}::before,\n ${o.virtualPaperTopMargin},\n ${o.virtualPaperBottomMargin},\n ${o.virtualPaperGap} {\n display: none;\n }\n\n ${o.virtualPaper} {\n break-inside: avoid;\n height: auto;\n }\n\n ${o.paperBody} {\n break-inside: avoid;\n }\n\n ${o.printPageBreak} {\n break-after: page;\n padding: .1px;\n }\n\n ${o.printForcedPageBreak} {\n /* JUST MANUAL! */\n /* break-after: page; */\n }\n\n ${o.flagNoBreak} {\n /*\n TODO: temporary commented!\n When splitting blocks, printPageBreak falls INTO this element,\n and in Firefox it causes a blank page.\n FIX the split of complex blocks and check in Firefox.\n */\n /* break-inside: avoid-page; */\n }\n}\n\n/* arrangement */\n${o.topCutPart} {\n margin-top: 0 !important;\n border-top: none !important;\n}\n${o.bottomCutPart} {\n margin-bottom: 0 !important;\n border-bottom: none !important;\n}\n `}_testStyle(){return this.config.debugMode?`\n/* FOR TEST */\n${o.contentFlow} {\n background:repeating-linear-gradient(\n -45deg,\n rgba(222, 222, 222, .1),\n rgba(222, 222, 222, .1) 10px,\n rgba(222, 222, 222, .2) 10px,\n rgba(222, 222, 222, .2) 20px\n );\n}\n\n${o.virtualPaperGap} {\n background: #ff000020;\n}\n\n${o.paperFooter},\n${o.paperHeader} {\n background: #fa96ff20;\n}\n${o.paperBody} {\n background: #ffee0020;\n}\n${o.runningSafety} {\n background: #f200ff;\n}\n${o.frontpageContent} {\n background: #00fcff20;\n}\n\n${o.neutral} {\n background: #00ffee10;\n}\n\n${o.textNode} {\n background: #00ff0010;\n}\n\n${o.textGroup},\n${o.textLine} {\n background: #0000ff08;\n}\n\n `:""}}class l{constructor({config:e,DOM:t,node:o,selector:n}){this.success=!1,this.root,this.paperFlow,this.contentFlow,this.frontpageTemplate,this.headerTemplate,this.footerTemplate,this._initialRoot,this._contentRoot,this._config=e,this._debug=e.debugMode?{...e.debugConfig.layout}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._selector=n,this._node=o,this._customInitialRootSelector=e.initialRoot,this._defaultInitialRootSelector=n.init}create(){if(this._getTemplates(),this._insertStyle(),this._DOM.getElement(`style${this._selector.style}`)){if(this._createLayout(),this._DOM.getParentNode(this.root)!==this._initialRoot||this._DOM.getElementOffsetParent(this.paperFlow)!==this.root||this._DOM.getElementOffsetParent(this.contentFlow)!==this.root)return this._assert&&console.assert(this._DOM.getParentNode(this.root)===this._initialRoot,"Failed to insert the layout root into the DOM."),this._assert&&console.assert(this._DOM.getElementOffsetParent(this.paperFlow)===this.root,"Failed to insert the paperFlow element into the DOM."),void(this._assert&&console.assert(this._DOM.getElementOffsetParent(this.contentFlow)===this.root,"Failed to insert the contentFlow element into the DOM."));this.success=!0}else console.error("Failed to add print styles into the DOM.")}_getTemplates(){this._assert&&console.assert(this._selector.frontpageTemplate,"frontpageTemplate selector is missing"),this._assert&&console.assert(this._selector.headerTemplate,"headerTemplate selector is missing"),this._assert&&console.assert(this._selector.footerTemplate,"footerTemplate selector is missing"),this.frontpageTemplate=this._DOM.getInnerHTML(this._selector.frontpageTemplate),this.headerTemplate=this._DOM.getInnerHTML(this._selector.headerTemplate),this.footerTemplate=this._DOM.getInnerHTML(this._selector.footerTemplate)}_insertStyle(){const e=this._DOM.getElement("head"),t=this._DOM.body;if(!e&&!t)return void console.error("Check the structure of your document. We didn`t find HEAD and BODY tags. HTML2PDF4DOC expects valid HTML.");const o=this._node.create("style",new r(this._config).create());o?(this._DOM.setAttribute(o,this._selector.style,""),e?this._DOM.insertAtEnd(e,o):t?this._DOM.insertBefore(t,o):this._assert&&console.assert(!1,"We expected to find the HEAD and BODY tags.")):console.error("Failed to create print styles")}_createLayout(){this._getInitialRoot(),this._initialRoot?(this._debug._&&console.log("initial root:",this._initialRoot),this._createRoot(),this._createPaperFlow(),this._createContentFlow(),this._DOM.moveContent(this._initialRoot,this.contentFlow),this._DOM.insertAtEnd(this._initialRoot,this.root),this._DOM.insertAtEnd(this.root,this.paperFlow,this.contentFlow),this._insertContentFlowStartAndEnd(this.contentFlow),this._ignoreUnprintableEnvironment(this.root)):console.error("Failed to initialize the root element.")}_insertContentFlowStartAndEnd(e){const t=this._node.create(this._selector.contentFlowStart),o=this._node.create(this._selector.contentFlowEnd);return this._DOM.insertAtStart(e,t),this._DOM.insertAtEnd(e,o),{contentFlowStart:t,contentFlowEnd:o}}_getInitialRoot(){let e=this._customInitialRootSelector?this._DOM.getElement(this._customInitialRootSelector):this._DOM.getElement(this._defaultInitialRootSelector);if(!e){if(!this._DOM.body)return void console.error("We expected to find the BODY tag.");e=this._DOM.body,console.warn(`The printable area is currently unspecified and encompasses the entire contents of the BODY tag. To restrict the printed content to a specific area, include ${this._defaultInitialRootSelector} in the root element of the desired printing area.`)}return this._initialRoot=e,e}_createRoot(){const e=this._node.create(this._selector.root);return this.root=e,e}_createPaperFlow(){const e=this._node.create(this._selector.paperFlow);return this.paperFlow=e,e}_createContentFlow(){const e=this._node.create(this._selector.contentFlow);return this.contentFlow=e,e}_ignoreUnprintableEnvironment(e){if(e===this._DOM.body)return void(this._assert&&console.assert(!1,"misshapen root"));let t=this._DOM.getParentNode(e);this._DOM.setAttribute(t,this._selector.printIgnore),this._DOM.getChildNodes(t).forEach((t=>{if(t!==e&&this._DOM.isElementNode(t))this._DOM.setAttribute(t,this._selector.printHide);else{if(!this._node.isSignificantTextNode(t))return;this._DOM.setAttribute(this._node.wrapTextNode(t),this._selector.printHide)}})),this._DOM.isDocumentBody(t)||this._ignoreUnprintableEnvironment(t)}}class a{constructor({config:e,DOM:t,selector:o}){this._config=e,this._DOM=t,this._selector=o,this._debug=e.debugMode?{...e.debugConfig.node}:{},this._assert=!!e.consoleAssert,this._markupDebugMode=this._config.markupDebugMode}get(e,t=this._DOM){return this._debug._&&console.assert(e),this._DOM.getElement(e,t)}getAll(e,t=this._DOM){return this._debug._&&console.assert(e),"string"==typeof e&&(e=e.split(",").filter(Boolean)),this._assert&&console.assert(Array.isArray(e),"Selectors must be provided as an array or string (one selector or multiple selectors, separated by commas). Now the selectors are:",e),this._debug._&&console.assert(e.length>0,"getAll(selectors), selectors:",e),1===e.length?[...this._DOM.getAllElements(e[0],t)]:[...e].flatMap((e=>[...this._DOM.getAllElements(e,t)]))}getTableEntries(e){const t=[...e.children].reduce(((e,t)=>{const o=t.tagName;return"TBODY"===o?{...e,rows:[...e.rows,...t.children]}:"CAPTION"===o?(this.setFlagNoBreak(t),{...e,caption:t}):"COLGROUP"===o?(this.setFlagNoBreak(t),{...e,colgroup:t}):"THEAD"===o?(this.setFlagNoBreak(t),{...e,thead:t}):"TFOOT"===o?(this.setFlagNoBreak(t),{...e,tfoot:t}):"TR"===o?{...e,rows:[...e.rows,...t]}:{...e,unexpected:[...e.unexpected,...t]}}),{caption:null,thead:null,tfoot:null,rows:[],unexpected:[]});return t.unexpected.length>0&&this._debug._&&console.warn(`something unexpected is found in the table ${e}`),t}getPreparedChildren(e){if(this.isComplexTextBlock(e))return[...this._DOM.getChildren(e)];{let t=[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this.isSTYLE(t))return e;if(this.isSignificantTextNode(t))return e.push(this.wrapTextNode(t)),e;if(!this._DOM.getElementOffsetParent(t)){const o=this.getPreparedChildren(t);return o.length>0&&e.push(...o),e}return this._DOM.isElementNode(t)?(e.push(t),e):void 0}),[]);return this.isVerticalFlowDisrupted(t)&&(t=this._processInlineChildren(t)),t}}_processInlineChildren(e){let t=null;const o=[];return e.forEach((e=>{this.isInline(this._DOM.getComputedStyle(e))?(t||(t=this.createComplexTextBlock(),this.wrapNode(e,t),o.push(t)),this._DOM.insertAtEnd(t,e)):(t=null,o.push(e))})),o}clearTemplates(e){this.getAll("template",e).forEach((e=>this._DOM.removeNode(e)))}isSelectorMatching(e,t){if(!e||!t)return void(this._debug._&&console.warn("isSelectorMatching() must have 2 params","\n element: ",e,"\n selector: ",t));const o=t.charAt(0);if("."===o){const o=t.substring(1);return this._DOM.hasClass(e,o)}if("#"===o){const o=t.substring(1);return this._DOM.hasID(e,o)}if("["===o){this._debug._&&console.assert("]"===t.at(-1),`the ${t} selector is not OK.`);const o=t.substring(1,t.length-1);return this._DOM.hasAttribute(e,o)}return this._DOM.getElementTagName(e)===t.toUpperCase()}isSignificantTextNode(e){return!!this._DOM.isTextNode(e)&&this._DOM.getNodeValue(e).trim().length>0}isSTYLE(e){return"STYLE"===this._DOM.getElementTagName(e)}isIMG(e){return"IMG"===this._DOM.getElementTagName(e)}isSVG(e){return"svg"===this._DOM.getElementTagName(e)}isOBJECT(e){return"OBJECT"===this._DOM.getElementTagName(e)}isLiNode(e){return"LI"===this._DOM.getElementTagName(e)}isNeutral(e){return this.isSelectorMatching(e,this._selector.neutral)}isWrappedTextNode(e){return this.isSelectorMatching(e,this._selector.textNode)}isWrappedTextLine(e){return this.isSelectorMatching(e,this._selector.textLine)}isWrappedTextGroup(e){return this.isSelectorMatching(e,this._selector.textGroup)}isPageStartElement(e){return this.isSelectorMatching(e,this._selector.pageStartMarker)}isContentFlowStart(e){return this.isSelectorMatching(e,this._selector.contentFlowStart)}isAfterContentFlowStart(e){const t=this._DOM.getLeftNeighbor(e);return this.isSelectorMatching(t,this._selector.contentFlowStart)}isContentFlowEnd(e){return this.isSelectorMatching(e,this._selector.contentFlowEnd)}isComplexTextBlock(e){return this.isSelectorMatching(e,this._selector.complexTextBlock)}isNoBreak(e,t=this._DOM.getComputedStyle(e)){return this.isSelectorMatching(e,this._selector.flagNoBreak)||this.isWrappedTextLine(e)||this.isWrappedTextGroup(e)||this.isInlineBlock(t)||this.notSolved(e)}isNoHanging(e){return this.isSelectorMatching(e,this._selector.flagNoHanging)}isForcedPageBreak(e){return this.isSelectorMatching(e,this._selector.printForcedPageBreak)}isInline(e){const t=e.display;return"inline"===t||"inline-block"===t||"inline-table"===t||"inline-flex"===t||"inline-grid"===t}isInlineBlock(e){const t=e.display;return"inline-block"===t||"inline-table"===t||"inline-flex"===t||"inline-grid"===t}isGrid(e){return"grid"===e.display}isTableLikeNode(e,t=this._DOM.getComputedStyle(e)){return"TABLE"!==this._DOM.getElementTagName(e)&&["table"].includes(t.display)}isTableNode(e,t=this._DOM.getComputedStyle(e)){return"TABLE"===this._DOM.getElementTagName(e)||["table"].includes(t.display)}isPRE(e,t=this._DOM.getComputedStyle(e)){return["block"].includes(t.display)&&["pre","pre-wrap","pre-line","break-spaces","nowrap"].includes(t.whiteSpace)}isGridAutoFlowRow(e){const t=e.display,o=e.gridAutoFlow;return("grid"===t||"inline-grid"===t)&&"row"===o}isFullySPlitted(e){const t=this._DOM.getComputedStyle(e);return this.isPRE(e,t)||this.isTableNode(e,t)||this.isTableLikeNode(e,t)||this.isGridAutoFlowRow(t)}isSlough(e){return this._DOM.hasAttribute(e,"slough-node")}isFirstChildOfFirstChild(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let o=e;for(;this._DOM.getParentNode(o)&&o!==t;){if(this._DOM.getFirstElementChild(this._DOM.getParentNode(o))!==o)return!1;o=this._DOM.getParentNode(o)}return o===t}isLastChildOfLastChild(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let o=e;for(;this._DOM.getParentNode(o)&&o!==t;){if(this._DOM.getParentNode(o)===t){let e=this._DOM.getRightNeighbor(o);for(;!this._DOM.getElementOffsetHeight(e)&&!this._DOM.getElementOffsetWidth(e);)if(e=this._DOM.getRightNeighbor(e),this.isContentFlowEnd(e))return!0;return this.isContentFlowEnd(e)}if(this._DOM.getLastElementChild(this._DOM.getParentNode(o))!==o)return!1;o=this._DOM.getParentNode(o)}return o===t}isLineChanged(e,t){return this._DOM.getElementOffsetTop(t)-this._DOM.getElementOffsetBottom(e)>-2}isLineKept(e,t,o){const n=this._DOM.getElementOffsetBottom(e),s=this._DOM.getElementOffsetTop(t),i=n-s,r=i>=2;return o&&console.group("isLineKept?"),o&&console.log("\n",r,"\n","\n currentBottom",n,[e],"\n nextTop",s,[t],"\n delta",i),o&&console.groupEnd("isLineKept?"),r}findFirstChildParent(e,t){let o=this._DOM.getParentNode(e),n=null;for(;o&&o!==t;){if(e!==this._DOM.getFirstElementChild(o))return n;n=o,e=o,o=this._DOM.getParentNode(e)}return n}findLastChildParent(e,t){let o=this._DOM.getParentNode(e),n=null;for(;o&&o!==t;){if(e!==this._DOM.getLastElementChild(o))return n;n=o,e=o,o=this._DOM.getParentNode(e)}return n}isVerticalFlowDisrupted(e){return e.some(((e,t,o)=>{const n=e,s=o[t+1];if(!s)return!1;return this._DOM.getElementOffsetBottom(n)>this._DOM.getElementOffsetTop(s)}))}findBetterForcedPageStarter(e,t){let o=e;for(;;){const e=this.findFirstChildParent(o,t);if(e&&e!==o){o=e;continue}const n=this._DOM.getLeftNeighbor(o);if(!n||!this.isNoHanging(n))break;o=n}return o}findBetterPageStart(e,t,o){this._debug._&&console.groupCollapsed("➗ findBetterPageStart");let n=!1,s=!1;const i=this.getTop(t,o);this._debug._&&console.log("Start calculations:",{pageStart:e,lastPageStart:t,topLimit:i});let r=this.findFirstChildParentFromPage(e,i,o)||e;this._debug._&&console.log("betterCandidate:",r);let l=r;for(;;){const e=this.findPreviousNonHangingsFromPage(l,i,o);if(void 0===e){this._debug._&&console.warn("🫥 previousCandidate",e),n=!0;break}if(this._debug._&&console.log("• previousCandidate",{previousCandidate:e}),e){l=e;continue}this._debug._&&console.log("• update currentCandidate",{previousCandidate:e});const t=this.findFirstChildParentFromPage(l,i,o);if(void 0===t){this._debug._&&console.warn("🫥 firstChildParent",t),n=!0;break}if(this._debug._&&console.log("• firstChildParent",{firstChildParent:t}),!t){this._debug._&&console.log("• update currentCandidate",{firstChildParent:t});break}l=t}(l==t||this.getTop(l,o)<=i)&&(s=!0,this._debug._&&console.log("☝️ Top page limit has been reached",r));const a=this._DOM.getLeftNeighbor(l);a==t&&(s=!0,this._debug._&&console.log("👈 Left limit has been reached (left neighbor is the last page start)",a,r));let h=n||s?r:l;return this.isAfterContentFlowStart(h)&&(h=e),this._debug._&&console.log({interruptedWithUndefined:n,interruptedWithLimit:s,pageStart:e,betterCandidate:r,currentCandidate:l,result:h}),this._debug._&&console.log("➗ end, return:",h),this._debug._&&console.groupEnd(),h}findAllForcedPageBreakInside(e){return this.getAll(this._selector.printForcedPageBreak,e)}findFirstChildParentFromPage(e,t,o){this._debug._&&console.groupCollapsed("⬆ findFirstChildParentFromPage");let n=null,s=e,i=!1;for(;;){const e=this._DOM.getParentNode(s);if(!e)break;if(!(this._DOM.getFirstElementChild(e)===s)){this._debug._&&console.warn({"!isFirstChild":e});break}if(this.isPageStartElement(e)||this.getTop(e,o)t?n:null}insertForcedPageBreakBefore(e){const t=this.create(this._selector.printForcedPageBreak);return this._DOM.insertBefore(e,t),t}insertForcedPageBreakAfter(e){const t=this.create(this._selector.printForcedPageBreak);return this._DOM.insertAfter(e,t),t}replaceNodeContentsWith(e,...t){this._DOM.setInnerHTML(e,""),this._DOM.insertAtEnd(e,...t)}fitElementWithinBoundaries({element:e,height:t,width:o,vspace:n,hspace:s}){const i=n/t,r=s/o,l=i{this._DOM.setAttribute(e,this._selector.topCutPart),this._DOM.setAttribute(e,this._selector.bottomCutPart)})),this._DOM.removeAttribute(e.at(0),this._selector.topCutPart),this._DOM.removeAttribute(e.at(-1),this._selector.bottomCutPart)}wrapNode(e,t){this._DOM.insertBefore(e,t),this._DOM.insertAtEnd(t,e)}wrapTextNode(e){if(!this.isSignificantTextNode(e))return;const t=this.create(this._selector.textNode);return this._DOM.insertBefore(e,t),this._DOM.insertAtEnd(t,e),t}getTop(e,t=null,o=0){if(!e)return void(this._debug._&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0));if(null===t)return this._DOM.getElementOffsetTop(e);if(!t)return void(this._debug._&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0));const n=this._DOM.getElementOffsetParent(e);if(!n)return void(this._debug._&&console.warn("Element has no offset parent.","\n element:",[e],"\n offsetParent:",n,"\n The function returned:",void 0));const s=this._DOM.getElementOffsetTop(e);return n===t?s+o:this.getTop(n,t,o+s)}getBottom(e,t=null){if(e){if(null===t)return this._DOM.getElementOffsetBottom(e);if(t)return this.getTop(e,t)+this._DOM.getElementOffsetHeight(e);this._debug._&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0)}else this._debug._&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0)}getHeightWithMargin(e){const t=parseInt(this._DOM.getComputedStyle(e).marginTop),o=parseInt(this._DOM.getComputedStyle(e).marginBottom);return this._DOM.getElementOffsetHeight(e)+t+o}getBottomWithMargin(e,t){if(!e)return;const o=this.getBottom(e,t);let n;const s=this.createNeutralBlock();this._DOM.insertAfter(e,s);const i=this.getTop(s,t);this._DOM.removeNode(s);if(i>=o)n=i;else{n=o+this._DOM.getComputedStyle(e).marginBottom}return n}getTopWithMargin(e,t){const o=parseInt(this._DOM.getComputedStyle(e).marginTop);return this.getTop(e,t)-o}getMaxWidth(e){const t=this.create();this._DOM.insertAtEnd(e,t);const o=this._DOM.getElementOffsetWidth(t);return this._DOM.removeNode(t),o}getEmptyNodeHeight(e,t=!0){const o=this.create();t&&this._DOM.setStyles(o,{padding:"0.1px"});const n=this._DOM.cloneNodeWrapper(e);"TABLE"===this._DOM.getElementTagName(e)&&this._DOM.setInnerHTML(n,""),this._DOM.insertAtEnd(o,n),this._DOM.insertBefore(e,o);const s=this._DOM.getElementOffsetHeight(o);return this._DOM.removeNode(o),s}getLineHeight(e){const t=this.createNeutral();this._DOM.setInnerHTML(t,"!"),this._DOM.setStyles(t,{display:"block"}),this._DOM.insertAtEnd(e,t);const o=this._DOM.getElementOffsetHeight(t);return this._DOM.removeNode(t),o}getTableRowHeight(e,t=0){const o=this._DOM.getElementOffsetTop(e),n=this._DOM.cloneNode(e),s="!
".repeat(t);[...n.children].forEach((e=>this._DOM.setInnerHTML(e,s))),this._DOM.insertBefore(e,n);const i=this._DOM.getElementOffsetTop(e);return this._DOM.removeNode(n),i-o}copyNodeWidth(e,t){this._DOM.setStyles(e,{width:`${this._DOM.getElementOffsetWidth(t)}px`,"min-width":`${this._DOM.getElementOffsetWidth(t)}px`})}lockTableWidths(e){this.copyNodeWidth(e,e),this.getAll("td",e).forEach((e=>this.copyNodeWidth(e,e)))}prepareSplittedNode(e){const t=e,o=this.splitByWordsGreedy(e),n=o.map((e=>{const t=this._DOM.createElement("span");return this._DOM.setInnerHTML(t,e+" "),t})),s=this.createTestNodeFrom(e);return this._DOM.insertAtEnd(s,...n),this._DOM.insertAtEnd(e,s),{splittedNode:t,nodeWords:o,nodeWordItems:n}}splitByLinesGreedy(e){return e.split(/(?<=\n)/)}splitByWordsGreedy(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).split(/(?<=\s|-)/)}splitByWordsGreedyWithSpacesFilter(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).trim().split(/(?<=\s|-)/).filter((e=>" "!=e))}notSolved(e){this._DOM.getElementTagName(e);return!1}}function h(e){return e?.length?e?.split(/\s+/).filter(Boolean):[]}class d{constructor({config:e,DOM:t,node:o,selector:n}){this._debug=e.debugMode?{...e.debugConfig.paragraph}:{},this._DOM=t,this._selector=n,this._node=o,this._minParagraphLeftLines=2,this._minParagraphDanglingLines=2,this._minParagraphBreakableLines=this._minParagraphLeftLines+this._minParagraphDanglingLines||2}init(){this._debug._&&console.log("🚨 init Paragraph")}split(e){return this._splitComplexTextBlockIntoLines(e)}_getLines(e){return Math.ceil(this._DOM.getElementOffsetHeight(e)/this._node.getLineHeight(e))}_splitComplexTextBlockIntoLines(e){if(this._debug._&&console.group("_splitComplexTextBlockIntoLines",[e]),this._node.isSelectorMatching(e,this._selector.splitted))return this._end(this._selector.splitted),this._DOM.getChildren(e);const t=this._node.getPreparedChildren(e),o=t.map((e=>{const t=this._node.getLineHeight(e),o=this._DOM.getElementOffsetHeight(e),n=this._DOM.getElementOffsetLeft(e),s=this._DOM.getElementOffsetTop(e);return{element:e,lines:Math.ceil(o/t),left:n,top:s,height:o,lineHeight:t,text:this._DOM.getInnerHTML(e)}}));this._debug._&&console.log("\n🚸 nodeChildren",[...t],"\n🚸 extendedChildrenArray",[...o]);const n=o.flatMap((e=>e.lines>1&&!this._node.isNoBreak(e.element)?this._breakItIntoLines(e.element):e.element));this._debug._&&console.log("\n🚸🚸🚸\n partiallyLinedChildren",[...n]);const s=n.reduce(((e,t,o,n)=>(e||(e=[]),"BR"===this._DOM.getElementTagName(t)?(e.at(-1).push(t),e.push([]),this._debug._&&console.log("br; push:",t),e):!e.length||this._node.isLineChanged(e.at(-1).at(-1),t)?(e.push([t]),this._debug._&&console.log("◼️ start new line:",t),e):0===e.at(-1).length||e.length&&this._node.isLineKept(e.at(-1).at(-1),t)?(this._debug._&&console.log("⬆ add to line:",t),e.at(-1).push(t),e):void(this._debug._&&console.assert(!0,"groupedPartiallyLinedChildren: An unexpected case of splitting a complex paragraph into lines.","\nOn the element:",t)))),[]);if(this._debug._&&console.log("🟡🟡🟡 groupedPartiallyLinedChildren \n",s.length,[...s]),s.length{let o;if(0==e.length)o=e[0],o.setAttribute("role","🚫"),console.assert(0==e.length,"The string cannot be empty (_splitComplexTextBlockIntoLines)");else if(1==e.length)o=e[0];else{o=this._node.createTextGroup(),this._DOM.insertBefore(e[0],o),this._DOM.insertAtEnd(o,...e)}return o.dataset.child=t,o}));return this._end("OK _splitComplexTextBlockIntoLines"),this._DOM.setAttribute(e,this._selector.splitted),l}_breakItIntoLines(e){if(this._debug._&&console.group("_breakItIntoLines",[e]),this._node.isNoBreak(e))return this._end("isNoBreak"),e;if(this._node.isWrappedTextNode(e)){const t=this._breakWrappedTextNodeIntoLines(e);return this._end("TextNode newLines"),t}return this._end("(recursive _breakItIntoLines)"),this._processNestedInlineElements(e)}_processNestedInlineElements(e){this._debug._&&console.group("_processNestedInlineElements",[e]);const t=this._getNestedInlineChildren(e).flatMap((e=>this._getLines(e)>1?this._breakItIntoLines(e):e)),o=this._findNewLineStarts(t),n=o.map(((n,s)=>{const i=t[n],r=t[o[s+1]];return this._cloneAndCleanOutsideRange(e,i,r)}));return this._DOM.insertInsteadOf(e,...n),this._end("Nested Inline parts"),n}_cloneAndCleanOutsideRange(e,t,o){t&&t.setAttribute("split","start"),o&&o.setAttribute("split","end");let n=e.cloneNode(!0);if(t){let t=n.querySelector('[split="start"]'),o=t.previousElementSibling;for(;o;){let e=o;o=o.previousElementSibling,e.remove()}let s=t.parentElement;for(;s&&s!==e;){let e=s.previousElementSibling;for(;e;){let t=e;e=e.previousElementSibling,t.remove()}s=s.parentElement}t.removeAttribute("split")}if(o){let t=n.querySelector('[split="end"]'),o=t.nextElementSibling;for(;o;){let e=o;o=o.nextElementSibling,e.remove()}let s=t.parentElement;for(;s&&s!==e;){let e=s.nextElementSibling;for(;e;){let t=e;e=e.nextElementSibling,t.remove()}s=s.parentElement}t.remove()}return t&&t.removeAttribute("split"),o&&o.removeAttribute("split"),n}_getNestedInlineChildren(e){return[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this._node.isSignificantTextNode(t))return e.push(this._node.wrapTextNode(t)),e;if(!this._DOM.getElementOffsetParent(t)){const o=this._node.getPreparedChildren(t);return o.length>0&&e.push(...o),e}if(this._DOM.isElementNode(t)){return this._getNestedInlineChildren(t).forEach((t=>e.push(t))),e}}),[])}_makeWordsFromTextNode(e){const t=this._node.splitByWordsGreedy(e);this._debug._&&console.log("wordArray",t);const o=t.map(((e,t)=>this._node.createWord(e+"",t)));return this._debug._&&console.log("wrappedWordArray",o),{wordArray:t,wrappedWordArray:o}}_breakWrappedTextNodeIntoLines(e){e.classList.add("🔠_breakItIntoLines");const{wordArray:t,wrappedWordArray:o}=this._makeWordsFromTextNode(e);this._DOM.setInnerHTML(e,""),this._DOM.insertAtEnd(e,...o);const n=this._findNewLineStarts(o),s=n.reduce(((o,s,i)=>{const r=this._node.createTextLine(),l=n[i],a=n[i+1],h=t.slice(l,a).join("")+"";return this._DOM.setInnerHTML(r,h),this._DOM.insertBefore(e,r),o.push(r),o}),[]);return e.remove(),s}_findNewLineStarts(e){return e.reduce(((t,o,n)=>(n>0&&e[n-1].offsetTop+e[n-1].offsetHeight<=o.offsetTop&&t.push(n),t)),[0])}_end(e){this._debug._&&console.log(`%c ▲ ${e} `,"background:#eee;color:#888;padding: 0 1px 0 0;"),this._debug._&&console.groupEnd()}}const g="#66CC00",c=`color: ${g};font-weight:bold`,p=`border:1px solid ${g};background:#EEEEEE;color:${g};`,_="background:#999;color:#FFF;padding: 0 4px;";class u{constructor({config:e,DOM:t,node:o,selector:n,layout:s,referenceWidth:i,referenceHeight:r}){this._debug=e.debugMode?{...e.debugConfig.pages}:{},this._assert=!!e.consoleAssert,this._selector=n,this._node=o,this._noHangingSelectors=h(e.noHangingSelectors),this._pageBreakBeforeSelectors=h(e.pageBreakBeforeSelectors),this._pageBreakAfterSelectors=h(e.pageBreakAfterSelectors),this._forcedPageBreakSelectors=h(e.forcedPageBreakSelectors),this._noBreakSelectors=h(e.noBreakSelectors),this._garbageSelectors=h(e.garbageSelectors),this._DOM=t,this._paragraph=new d({config:e,DOM:t,node:o,selector:n}),this._paragraph.init(),this._root=s.root,this._contentFlow=s.contentFlow,this._referenceWidth=i,this._referenceHeight=r,this._minLeftLines=2,this._minDanglingLines=2,this._minBreakableLines=this._minLeftLines+this._minDanglingLines,this._minLeftRows=1,this._minDanglingRows=1,this._minBreakableRows=this._minLeftRows+this._minDanglingRows,this._minPreFirstBlockLines=3,this._minPreLastBlockLines=3,this._minPreBreakableLines=this._minPreFirstBlockLines+this._minPreLastBlockLines,this._minBreakableGridRows=4,this._imageReductionRatio=.8,this._signpostHeight=24,this._commonLineHeight=this._node.getLineHeight(this._root),this._minimumBreakableHeight=this._commonLineHeight*this._minBreakableLines,this._isFirefox="undefined"!=typeof InstallTrigger,this.pages=[]}calculate(){return this._removeGarbageElements(),this._prepareNoHangingElements(),this._prepareForcedPageBreakElements(),this._prepareNoBreakElements(),this._calculate(),this._debug._&&console.log("%c ✔ Pages.calculate()",p,this.pages),this.pages}_removeGarbageElements(){if(this._garbageSelectors.length){this._node.getAll(this._garbageSelectors,this._contentFlow).forEach((e=>{this._DOM.removeNode(e)}))}}_prepareNoHangingElements(){if(this._noHangingSelectors.length){this._node.getAll(this._noHangingSelectors,this._contentFlow).forEach((e=>{this._node.setFlagNoHanging(e);const t=this._node.findLastChildParent(e,this._contentFlow);t&&this._node.setFlagNoHanging(t,"parent")}))}}_prepareNoBreakElements(){if(this._noBreakSelectors.length){this._node.getAll(this._noBreakSelectors,this._contentFlow).forEach((e=>this._node.setFlagNoBreak(e)))}}_prepareForcedPageBreakElements(){const e=this._pageBreakBeforeSelectors.length?this._node.getAll(this._pageBreakBeforeSelectors,this._contentFlow):[],t=this._pageBreakAfterSelectors.length?this._node.getAll(this._pageBreakAfterSelectors,this._contentFlow):[],o=this._node.getAll(this._forcedPageBreakSelectors,this._contentFlow);if(e.length){const t=e[0],o=this._node.findFirstChildParent(t,this._contentFlow)||t;this._node.isAfterContentFlowStart(o)&&e.shift()}if(t.length){const e=t.at(-1),o=this._node.findLastChildParent(e,this._contentFlow)||e,n=this._DOM.getRightNeighbor(o);this._node.isContentFlowEnd(n)&&t.pop()}e.length&&e.forEach((e=>{const t=this._node.findBetterForcedPageStarter(e,this._contentFlow);t&&this._node.insertForcedPageBreakBefore(t)})),o&&o.forEach((e=>{if(!this._node.isForcedPageBreak(e)){const t=this._node.findBetterForcedPageStarter(e,this._contentFlow);t&&this._node.insertForcedPageBreakBefore(t)}})),t.length&&t.forEach((e=>{const t=this._node.findLastChildParent(e,this._contentFlow);t&&(e=t),this._node.isForcedPageBreak(e.nextElementSibling)||this._node.insertForcedPageBreakAfter(e)}))}_calculate(){this._debug._&&console.groupCollapsed("•• init data ••"),this._debug._&&console.log("this._referenceHeight",this._referenceHeight,"\n","this._noHangingSelectors",this._noHangingSelectors,"\n","this._pageBreakBeforeSelectors",this._pageBreakBeforeSelectors,"\n","this._pageBreakAfterSelectors",this._pageBreakAfterSelectors,"\n","this._forcedPageBreakSelectors",this._forcedPageBreakSelectors,"\n","this._noBreakSelectors",this._noBreakSelectors,"\n","isFirefox",this._isFirefox),this._debug._&&console.groupEnd("•• init data ••"),this._registerPageStart(this._node.get(this._selector.contentFlowStart,this._contentFlow));const e=this._node.getBottomWithMargin(this._contentFlow,this._root);if(ethis._registerPageStart(e)));const t=this._node.getPreparedChildren(this._contentFlow);this._debug._&&console.groupCollapsed("%c🚸 children(contentFlow)",p),this._debug._&&console.log(t),this._debug._&&console.groupEnd("%c🚸 children(contentFlow)",p),this._parseNodes({array:t})}_registerPageStart(e,t=!1){if(this._debug._registerPageStart&&console.log("%c📍","background:yellow;font-weight:bold","\n improveResult:",t,"\n passed pageStart:",e),this._node.isPageStartElement(e))return;t&&(e=this._node.findBetterPageStart(e,this.pages.at(-1)?.pageStart,this._root));const o=this._node.getTopWithMargin(e,this._root),n=o+this._referenceHeight;this.pages.push({pageStart:e,pageBottom:n}),this._node.markPageStartElement(e,this.pages.length),this._debug._registerPageStart&&console.log(`%c📍register page ${this.pages.length}`,"background:yellow;font-weight:bold","\n improved result:",t,"\n pageTop:",o,"\n pageBottom:",n,"\n pageStart:",e)}_parseNodes({array:e,previous:t,next:o,parent:n,parentBottom:s}){this._debug._parseNodes&&console.log("🔵 _parseNodes","\narray:",[...e],"\ntracedParent:",n);for(let i=0;ig+this._referenceHeight;if(i&&p){if(d=void 0,this._debug._parseNode&&console.log("🪁 Tile: We got a tail from the lower shells of the last child. Giving up our “last child” rule here and will try to insert a page break at the end of some parent. ",{parentBottom:i,currentParentBottom:d,currentElementBottom:a,newPageBottom:l},{currentElement:o,parent:s}),a<=l){this._debug._parseNode&&console.log("🪁 Tile: currentElementBottom <= newPageBottom");const e=[];let t=o;for(this._debug._parseNode&&console.log("🪁 Tile: currentElement",o);t&&t!==s;)e.push({element:t,bottom:this._node.getBottomWithMargin(t,this._root)}),t=t.parentElement;if(t!==s)throw new Error("parent not found in the ancestor chain");e.push({element:s,bottom:i}),this._debug._parseNode&&console.log("🪁 Tile: _parents",e);let n=l;this._debug._parseNode&&console.log("🪁 Tile: _currentPageBottom = newPageBottom",n);for(let t=0;tn){this._debug._parseNode&&console.log("🪁 Tile: _parents[i].bottom > _currentPageBottom",e[t].bottom,">",n,e[t].element);const o=this._node.createNeutral();o.classList.add("service"),this._DOM.insertAtEnd(e[t].element,o),this._registerPageStart(o),this._debug._parseNode&&console.log("_registerPageStart",o),this._node.markProcessed(o,"node is ForcedPageBreak");const s=this.pages.at(-1).pageBottom;if(this._debug._parseNode&&console.log(n,s,i),!(i>s))return this._debug._parseNode&&console.log("%c END _parseNode (bottom tile of parents)",_),void(this._debug._parseNode&&console.groupEnd());this._debug._&&console.log("🧧 • parentBottom > justUpdatedPageBottom"),n=s,this._debug._parseNode&&console.log("new _currentPageBottom",n)}return this._debug._parseNode&&console.log("%c END _parseNode (bottom tile of parents)",_),void(this._debug._parseNode&&console.groupEnd())}this._debug._parseNode&&console.log("🪁 Tile: currentElementBottom > newPageBottom","DOING NOTHING")}const u=d||a;if(this.pages.at(-1).pageStart===o&&(this._node.isNoBreak(o)||u<=l))return this._node.markProcessed(o,"node is already registered and fits in the page"),this._debug._parseNode&&console.log("%c END _parseNode (node is already registered and fits in the next page)",_),void(this._debug._parseNode&&console.groupEnd());if(g>=l&&a-g){const e=s?this._node.getTopWithMargin(s,this._root):void 0,t=s&&e&&g-e>=this._referenceHeight;this._debug._parseNode&&console.warn("🪀 currentElementTop >= newPageBottom",g,">=",l,"\n beginningTail:",t,g-e,">=",this._referenceHeight),this._registerPageStart(o,!t)}if(this._node.isForcedPageBreak(o))return this._registerPageStart(o),this._node.markProcessed(o,"node is ForcedPageBreak"),this._debug._parseNode&&console.log("%c END _parseNode (isForcedPageBreak)",_),void(this._debug._parseNode&&console.groupEnd());this._debug._&&console.assert(this._DOM.getElementOffsetParent(o),"it is expected that the element has an offset parent",o);const m=this._node.getTop(n,this._root);if(this._debug._parseNode&&console.log(...r,"• newPageBottom",l,"\n","• nextElementTop",m),m<=l)this._debug._parseNode&&console.log("nextElementTop <= newPageBottom",m,"<=",l),this._node.markProcessed(o,"node fits"),this._node.findAllForcedPageBreakInside(o).forEach((e=>{this._node.markProcessed(e,"node is ForcedPageBreak (inside a node that fits)"),this._registerPageStart(e)}));else{if(this._debug._parseNode&&console.log("nextElementTop > newPageBottom",m,">",l),u<=l)return this._debug._parseNode&&console.log("currentBlockBottom <= newPageBottom",u,"<=",l,"\n register nextElement as pageStart"),this._node.isNoHanging(o)?(this._debug._parseNode&&console.log("currentElement fits / last, and _isNoHanging => move it to the next page"),this._node.markProcessed(o,"it fits & last & _isNoHanging => move it to the next page"),this._registerPageStart(o,!0),this._debug._parseNode&&console.log("%c END _parseNode (isNoHanging)",_),void(this._debug._parseNode&&console.groupEnd())):(this._registerPageStart(n),this._node.markProcessed(o,"fits, its bottom falls exactly on the cut"),this._node.markProcessed(n,"starts new page, its top is exactly on the cut"),this._debug._parseNode&&console.log("%c END _parseNode (currentElement fits, register the next element)",_),void(this._debug._parseNode&&console.groupEnd()));if(this._node.isSVG(o)||this._node.isIMG(o)||this._node.isOBJECT(o)){const e=this._node.isSVG(o)?this._node.createSignpost(o):o;let t=s?l-this._node.getTop(e,this._root):l-this._node.getTop(s,this._root);t-=i?i-this._node.getBottom(e,this._root):0;let r=this._referenceHeight-(s?this._node.getTop(e,this._root)-this._node.getTop(s,this._root):0);const a=this._DOM.getElementOffsetHeight(e),h=this._DOM.getElementOffsetWidth(e);if(this._debug._parseNode&&console.log("🖼️🖼️🖼️🖼️🖼️🖼️\n",`H-space: ${t}, image Height: ${a}, image Width: ${h}`,o,"\n parent",s,"parentBottom",i,"currentParentBottom",d),athis._imageReductionRatio?(this._debug._parseNode&&console.log("Register next elements; 🖼️🖼️🖼️ IMG RESIZE to availableImageNodeSpace:",t,o),this._node.markProcessed(o,`IMG with ratio ${g}, and next starts on next`),this._node.fitElementWithinBoundaries({element:o,height:a,width:h,vspace:t,hspace:this._referenceWidth}),this._registerPageStart(n),this._debug._parseNode&&console.log("%c END _parseNode 🖼️ IMG scaled",_),void(this._debug._parseNode&&console.groupEnd())):(this._node.markProcessed(o,"IMG starts on next"),this._registerPageStart(e,!0),this._debug._parseNode&&console.log("🖼️ register Page Start",o),a>r&&(this._node.fitElementWithinBoundaries({element:o,height:a,width:h,vspace:r,hspace:this._referenceWidth}),this._node.markProcessed(o,"IMG starts on next and resized"),this._debug._parseNode&&console.log("🖼️ ..and fit it to full page",o)),this._debug._parseNode&&console.log("%c END",_),void(this._debug._parseNode&&console.groupEnd()))}if(o.style.height){this._debug._parseNode&&console.log("🥁 currentElement has HEIGHT",o.style.height);const e=l-g,t=m-g,s=e/t,i=this._referenceHeight/t;return this._debug._parseNode&&console.log("\n🥁 currentElementTop",g,"\n🥁 newPageBottom",l,"\n🥁 availableSpace",e,"\n🥁 currentElementContextualHeight",t,"\n🥁 availableSpaceFactor",s,"\n🥁 fullPageFactor",i),this._debug._parseNode&&console.assert(s<1),s>.8?(this._debug._parseNode&&console.log("🥁 availableSpaceFactor > 0.8: ",s),this._DOM.setStyles(o,{transform:`scale(${s})`,"transform-origin":"top center"}),this._registerPageStart(n),this._node.markProcessed(o,"processed as a image, has been scaled down within 20%, the next one starts a new page"),this._node.markProcessed(n,"the previous one was scaled down within 20%, and this one starts a new page."),this._debug._parseNode&&console.log("%c END _parseNode (has height & scale)",_),void(this._debug._parseNode&&console.groupEnd())):(i<1&&(this._debug._parseNode&&console.log("🥁 fullPageFactor < 1: ",i),this._node.markProcessed(o,"processed as a image, has been scaled down, and starts new page"),this._DOM.setStyles(o,{transform:`scale(${i})`,"transform-origin":"top center"})),this._debug._parseNode&&console.log("🥁 _registerPageStart",o),this._registerPageStart(o,!0),this._node.markProcessed(o,"processed as a image, starts new page"),this._debug._parseNode&&console.log("%c END _parseNode (has height & put on next page)",_),void(this._debug._parseNode&&console.groupEnd()))}this._debug._parseNode&&console.log("split or not? \n","currentBlockBottom",u),this._debug._parseNode&&console.log("currentParentBottom || currentElementBottom",{currentParentBottom:d,currentElementBottom:a},"currentBlockBottom > newPageBottom",u,">",l);const c=this._getProcessedChildren(o,l,this._referenceHeight);this._debug._parseNode&&console.log("try to break it and loop the children:",c);const p=c.length;this._debug._parseNode&&console.log(...r,"childrenNumber ",p),this._debug._parseNode&&console.log(...r,"currentElement ",o);const f=(e||i)&&s||o;if(p){const e=this._node.isFullySPlitted(o)||this._node.isSlough(o);this._debug._parseNode&&console.log({isFullySPlittedParent:e,parent:s,tracedParent:f}),this._parseNodes({array:c,previous:t,next:n,parent:e?void 0:f,parentBottom:e?void 0:h}),this._node.markProcessed(o,"getProcessedChildren and _parseNodes")}else this._debug._parseNode&&console.log(...r,"_registerPageStart (from _parseNode): \n",o),this._registerPageStart(o,!0),this._node.markProcessed(o,"doesn't fit, has no children, register it or parents")}this._debug._parseNode&&console.log("%c END _parseNode",_),this._debug._parseNode&&console.groupEnd()}_getProcessedChildren(e,t,o){const n=["%c_getProcessedChildren\n","color:white"];let s=[];if(this._node.isNoBreak(e))return this._debug._getProcessedChildren&&console.info(...n,"🧡 isNoBreak",e),[];if(this._node.isComplexTextBlock(e))return this._debug._getProcessedChildren&&console.info(...n,"💚 ComplexTextBlock",e),this._paragraph.split(e)||[];if(this._node.isWrappedTextNode(e))return this._debug._getProcessedChildren&&console.info(...n,"💚 TextNode",e),this._paragraph.split(e)||[];const i=this._DOM.getComputedStyle(e);return this._node.isTableLikeNode(e,i)?(this._debug._getProcessedChildren&&console.info(...n,"💚 TABLE like",e),s=this._splitTableLikeNode(e,t,o,i)||[]):this._node.isTableNode(e,i)?(this._debug._getProcessedChildren&&console.info(...n,"💚 TABLE",e),s=this._splitTableNode(e,t,o,i)||[]):this._node.isPRE(e,i)?(this._debug._getProcessedChildren&&console.info(...n,"💚 PRE",e),s=this._splitPreNode(e,t,o)||[]):this._node.isGridAutoFlowRow(this._DOM.getComputedStyle(e))?(this._debug._getProcessedChildren&&console.info(...n,"💜 GRID"),s=this._splitGridNode(e,t,o)||[]):(this._debug._getProcessedChildren&&console.info(...n,"💚 some node",e),s=this._node.getPreparedChildren(e),this._debug._getProcessedChildren&&console.info(...n,"🚸 get element children ",s)),s}_splitPreNode(e,t,o,n){const s=n||this._DOM.getComputedStyle(e),i=["%c_splitPreNode\n","color:white"];this._debug._splitPreNode&&console.group("%c_splitPreNode","background:cyan"),this._debug._splitPreNode&&console.log(...i,"node",e);const r=this._node.getTop(e,this._root),l=this._DOM.getElementOffsetHeight(e),a=this._node.getLineHeight(e),h=this._node.getEmptyNodeHeight(e,!1);if(l1)return this._debug._splitPreNode&&console.log("%c END _splitPreNode TODO!",_),[];{if(this._DOM.isElementNode(d[0])){const e=d[0];return this._debug._splitPreNode&&console.warn("is Element Node",e),this._debug._splitPreNode&&console.log("%c END _splitPreNode ???????",_),[]}this._node.isWrappedTextNode(d[0])&&this._debug._splitPreNode&&console.warn(`is TEXT Node: ${d[0]}`);const n=d[0].wholeText,l=this._node.splitByLinesGreedy(n);if(l.length{const t=this._node.createWithFlagNoBreak();return this._DOM.setInnerHTML(t,e),t}));this._debug._splitPreNode&&console.log("linesFromNode",c),this._node.replaceNodeContentsWith(e,...c);const p=o-h;let u=0,m=[],f=t-r-h;const b=s.position;"relative"!=b&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;tf&&(t&&m.push(t),t&&(u+=1),f=t?this._node.getTop(o,e)+p:p)}if(this._DOM.setStyles(e,{position:b}),!m.length)return this._debug._splitPreNode&&console.log("%c END _splitPreNode NO SPLIITERS",_),[];m.push(null),this._debug._splitPreNode&&console.log(...i,"splitters",m);const M=m.map(((t,o,n)=>{const s=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(s);const i=n[o-1]||0,r=t||n[n.length];return this._DOM.insertAtEnd(s,...c.slice(i,r)),s}));return this._node.markPartNodesWithClass(M),this._debug._splitPreNode&&console.log(...i,"newPreElementsArray",M),this._node.replaceNodeContentsWith(e,...M),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),this._DOM.removeAllClasses(e),this._debug._splitPreNode&&console.log("%c END _splitPreNode",_),this._debug._splitPreNode&&console.groupEnd(),M}}_insertTableSplit({startId:e,endId:t,table:o,tableEntries:n}){const s=this._DOM.cloneNodeWrapper(o),i=n.rows.slice(e,t),r=this._node.createWithFlagNoBreak();return o.before(r),e&&this._DOM.insertAtEnd(r,this._node.createSignpost("(table continued)",this._signpostHeight)),this._DOM.insertAtEnd(r,this._node.createTable({wrapper:s,colgroup:this._DOM.cloneNode(n.colgroup),caption:this._DOM.cloneNode(n.caption),thead:this._DOM.cloneNode(n.thead),tbody:i}),this._node.createSignpost("(table continues on the next page)",this._signpostHeight)),r}_splitTableLikeNode(e,t,o,n){const s=n||this._DOM.getComputedStyle(e),i=this._node.getPreparedChildren(e),r=this._node.getTop(e,this._root),l=this._node.getEmptyNodeHeight(e),a=o-l;let h=i,d=0,g=[],c=t-r-l;const p=s.position;"relative"!=p&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;tc&&(t&&g.push(t),t&&(d+=1),c=t?this._node.getTop(o,e)+a:a)}if(this._DOM.setStyles(e,{position:p}),!g.length)return this._debug._splitTableLikeNode&&console.log("splitters.length",g.length),[];g.push(null);const _=g.map(((t,o,n)=>{const s=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(s),this._node.unmarkPageStartElement(s);const i=n[o-1]||0,r=t||n[n.length];return this._DOM.insertAtEnd(s,...h.slice(i,r)),s}));return this._node.markPartNodesWithClass(_),this._node.replaceNodeContentsWith(e,..._),this._DOM.removeAllClasses(e),this._DOM.removeAllStyles(e),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),_}_splitTableNode(e,t,o){const n=["%c_splitTableNode\n","color:white"];this._debug._splitTableNode&&console.time("_splitTableNode"),this._debug._splitTableNode&&console.group("%c_splitTableNode","background:cyan"),this._node.lockTableWidths(e);const s=this._node.getEmptyNodeHeight(e),i=this._node.getTableEntries(e);this._debug._splitTableNode&&console.log(...n,e,"\ntableEntries",i);const r=this._node.getTopWithMargin(e,this._root),l=this._DOM.getElementOffsetHeight(i.caption)||0,a=this._DOM.getElementOffsetHeight(i.thead)||0,h=this._DOM.getElementOffsetHeight(i.tfoot)||0,d=(l??0)*(this._isFirefox??0),g=t-r-s-this._signpostHeight,c=o-l-a-h-s-2*this._signpostHeight;this._debug._splitTableNode&&console.log(...n,"\n • tableFirstPartBottom",g,"\n","\n pageBottom",t,"\n - tableTop",r,"\n - tableCaptionHeight",l,"\n - tableTheadHeight",a,"\n - tableWrapperHeight",s,"\n - this._signpostHeight",this._signpostHeight,"\n","\n fullPageHeight",o,"\n - tableCaptionHeight",l,"\n - tableTheadHeight",a,"\n - tableTfootHeight",h,"\n - 2 * this._signpostHeight",2*this._signpostHeight,"\n - tableWrapperHeight",s,"\n = tableFullPartContentHeight",c);const p=e=>[...e.rows,...e.tfoot?[e.tfoot]:[]];let u=p(i),m=[],f=g;this._debug._splitTableNode&&console.log(this._node.getTop(u[1],e)-this._node.getBottom(u[0],e),"(row[1].top - row[0].bottom)"),this._node.getTop(u[0],e)>f&&(f=c,this._debug._splitTableNode&&console.log("The Row 0 goes to the 2nd page"));for(let o=0;of){const s=o,l=n,a=this._DOM.getElementOffsetHeight(l),h=this._node.getTableRowHeight(l,this._minBreakableLines),g=this._node.getTableRowHeight(l),b=r,M=this._node.isNoBreak(l),P=a>=h&&!M;if(this._debug._splitTableNode&&console.log(`%c • Row # ${o}: try to split`,"color:blueviolet"),P){this._debug._splitTableRow&&console.groupCollapsed(`Split The ROW.${s}`);const e=f-b-g,n=c-g,r=this._DOM.getChildren(l);let a;a=[...r].map(((o,i)=>{const r=this._node.getPreparedChildren(o);this._debug._splitTableRow&&console.groupCollapsed(`Split TD.${i} in ROW.${s}`);const l=this._getInternalBlockSplitters({rootNode:o,children:r,pageBottom:t,firstPartHeight:e,fullPageHeight:n});return this._debug._splitTableRow&&console.groupEnd(`Split TD.${i} in ROW.${s}`),l})),this._debug._splitTableRow&&console.log("🟣 \ntheRowContentSlicesByTD",a);const h=a.some((e=>(this._debug._splitTableRow&&console.log("🟣","\nobj.result.length",e.result.length,"\nobj.result[0]",e.result[0]),e.result.length&&null===e.result[0])));this._debug._splitTableRow&&console.log("🟣","\nshouldFirstPartBeSkipped",h),h&&(a=[...r].map((e=>{const o=this._node.getPreparedChildren(e);return this._getInternalBlockSplitters({rootNode:e,children:o,pageBottom:t,firstPartHeight:n,fullPageHeight:n})}))),this._debug._splitTableRow&&console.log("🟣","\n theRowContentSlicesByTD",a);const d=a.some((e=>e.result.length));if(this._debug._splitTableRow&&console.log("🟣 ifThereIsSplit",d),d){const e=a.map((e=>{if(e.result.length)return this._createSlicesBySplitFlag(e.trail);{const t=this._node.createWithFlagNoBreak();t.classList.add("🟣"),this._DOM.setStyles(t,{display:"contents"});const o=e.trail.map((e=>e.element));return this._DOM.insertAtEnd(t,...o),[t]}}));this._debug._splitTableRow&&console.log("🟣 theTdContentElements",e);const t=Math.max(...e.map((e=>e.length)));this._debug._splitTableRow&&console.log("🟣 theNewTrCount",t);const n=[];for(let o=0;o{const i=this._DOM.cloneNodeWrapper(n);e[s][o]&&this._DOM.insertAtEnd(i,e[s][o]),this._DOM.insertAtEnd(t,i)})),n.push(t)}this._debug._splitTableRow&&console.log("🟣","\n theNewRows",n),this._DOM.setAttribute(l,".🚫_must_be_removed"),this._debug._splitTableRow&&console.log("🟣 splittingRow",l),this._DOM.insertInsteadOf(l,...n),i.rows.splice(s,1,...n),u=p(i),o-=1}this._debug._splitTableRow&&console.log(`%c END 🟪 Split The ROW.${s}`,_),this._debug._splitTableRow&&console.groupEnd("END OF 'if makesSenseToSplitTheRow'")}else this._debug._splitTableNode&&console.log(`%c • Row # ${o}: small or noBreak`,"color:blueviolet"),o>=this._minLeftRows&&(m.push(o),this._debug._splitTableNode&&console.log(`%c • Row # ${o}: REGISTER as start, index >= ${this._minLeftRows} (_minLeftRows) `,"color:blueviolet")),f=this._node.getTop(u[o],e)+d+c}else this._debug._splitTableNode&&console.log(`%c • Row # ${o}: PASS ...`,"color:blueviolet")}if(this._debug._splitTableNode&&console.log(...n,"splitsIds",m),!m.length)return this._debug._splitTableNode&&console.log("%c END _splitTableNode !splitsIds.length",_),this._debug._splitTableNode&&console.groupEnd(),[];const b=u.length-1-this._minDanglingRows;m[m.length-1]>b&&(m[m.length-1]=b);const M=m.map(((t,o,n)=>this._insertTableSplit({startId:n[o-1]||0,endId:t,table:e,tableEntries:i})));this._debug._splitTableNode&&console.log(...n,"splits",M);const P=this._node.createWithFlagNoBreak();return e.before(P),this._DOM.insertAtEnd(P,this._node.createSignpost("(table continued)",this._signpostHeight),e),this._debug._splitTableNode&&console.timeEnd("_splitTableNode"),this._debug._splitTableNode&&console.log("%c END _splitTableNode",_),this._debug._splitTableNode&&console.groupEnd(),[...M,P]}_createSlicesBySplitFlag(e){this._debug._createSlicesBySplitFlag&&console.group("_createSlicesBySplitFlag");const t=this._node.createWithFlagNoBreak();this._DOM.setStyles(t,{display:"contents"}),t.classList.add("🧰");const o=[t];let n=[t],s=t;const i=e=>{if(0===e.length)return null;const t=e[0];let o=t;for(let t=1;t{this._debug._createSlicesBySplitFlag&&console.group("processChildren"),this._debug._createSlicesBySplitFlag&&console.log("*start* children",e);for(let t=0;t{const t=e.children?.length>0,l=e.split,a=e.element,h=e.id;if(this._debug._createSlicesBySplitFlag&&console.group(`processObj # ${h}`),this._debug._createSlicesBySplitFlag&&console.log("currentElement",a),a&&this._DOM.removeNode(a),l){this._debug._createSlicesBySplitFlag&&console.log("••• hasSplitFlag"),n=n.map((e=>{const t=this._DOM.cloneNodeWrapper(e);return t.classList.add("🚩"),t})),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: NEW wrappers.map:",[...n]);const e=i(n);o.push(e),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: slices.push(nextWrapper):",[...o]),s=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("• hasSplitFlag: currentTargetInSlice:",s)}if(t){this._debug._createSlicesBySplitFlag&&console.log("••• hasChildren");const t=this._DOM.cloneNodeWrapper(a);n.push(t),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: wrappers.push(cloneCurrentElementWrapper)",t,[...n]),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice (check):",s),s?(this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice","TRUE, add to existing",t),this._DOM.insertAtEnd(s,t)):(this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice","FALSE, init the first",t),t.classList.add("🏁first"),this._DOM.setStyles(t,{background:"yellow"}),o.push(t),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: slices.push(cloneCurrentElementWrapper)",t,[...o])),s=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("• hasChildren: currentTargetInSlice (=):",s),r(e.children,a)}else s=n.at(-1),this._debug._createSlicesBySplitFlag&&console.log("insert currentElement",a,"to target",s),this._DOM.insertAtEnd(s,a);this._debug._createSlicesBySplitFlag&&console.log(`%c END processObj # ${h}`,_),this._debug._createSlicesBySplitFlag&&console.groupEnd()};return this._debug._createSlicesBySplitFlag&&console.log("####### currentTargetInSlice (=):",s),r(e),this._debug._createSlicesBySplitFlag&&console.log("slices:",o),this._debug._createSlicesBySplitFlag&&o.forEach((e=>console.log("slice:",e))),this._debug._createSlicesBySplitFlag&&console.log("%c END _createSlicesBySplitFlag",_),this._debug._createSlicesBySplitFlag&&console.groupEnd(),o}_getInternalBlockSplitters({rootNode:e,rootComputedStyle:t,children:o,pageBottom:n,firstPartHeight:s,fullPageHeight:i,result:r=[],trail:l=[],indexTracker:a=[],stack:h=[]}){const d=t||this._DOM.getComputedStyle(e),g=d.position;"relative"!=g&&this._DOM.setStyles(e,{position:"relative"}),this._debug._getInternalBlockSplitters&&console.group("💟 _getInternalBlockSplitters");const c=e=>{e>=0?a.push(e):a.pop()},p=(e,t)=>{this._debug._getInternalBlockSplitters&&console.assert(t>=0,"registerResult: ID mast be provided",e);let o,n=l[t];if(this._debug._getInternalBlockSplitters&&console.groupCollapsed("💜💜💜 registerResult(element, id)"),this._debug._getInternalBlockSplitters&&console.log("\n element",e,"\n id",t,"\n theElementObject (trail[id])",n,"\n theElementIndexInStack",o),0==t){const e=(e=>{let t,o=null;for(let n=e.length-1;n>=0;n--){if(0!==e[n].id)return{item:o,index:t};o=e[n],t=n}return{item:o,index:t}})(h);this._debug._getInternalBlockSplitters&&console.log("💜💜 id == 0","\n💜 [...stack]",[...h],"\n💜 topParentElementFromStack",e),e.item&&(n=e.item,o=e.index)}this._debug._getInternalBlockSplitters&&console.log("💜","\n theElementObject",n,"\n theElementIndexInStack",o,"\n [...indexTracker]",[...a]),0===o?(r.push(null),this._debug._getInternalBlockSplitters&&console.log("result.push(null)","\n\n💜💜💜")):(r.push(n.element),n&&(n.split=!0),this._debug._getInternalBlockSplitters&&console.log("\n theElementObject",n,"\n theElementObject.element",n.element,"\n result.push(theElementObject.element)","\n\n💜💜💜 ")),this._debug._getInternalBlockSplitters&&console.log("%c END _getInternalBlockSplitters registerResult",_),this._debug._getInternalBlockSplitters&&console.groupEnd()};this._debug._getInternalBlockSplitters&&console.log("💟 result 💟",r,"\n\n","\n rootNode:",e,"\n children:",o,"\n pageBottom:",n,"\n firstPartHeight:",s,"\n fullPageHeight:",i,"\n\n\n","💟 stack",[...h]);for(let t=0;t floater \n ${m} > ${M} `),(this._node.isSVG(_)||this._node.isIMG(_))&&this._debug._getInternalBlockSplitters&&console.log("%cIMAGE 💟💟","color:red;text-weight:bold");const o=this._node.getBottomWithMargin(_,e);if(this._debug._getInternalBlockSplitters&&console.log("💟💟 current ???","\n currentElement",_,"\n currentElementBottom",o,"\n floater",M),o<=M)this._debug._getInternalBlockSplitters&&console.log("💟💟💟 currentElementBottom <= floater"),u&&(this._debug._getInternalBlockSplitters&&console.log("💟💟💟💟 register nextElement"),l.push(b),p(u,t+1));else{this._debug._getInternalBlockSplitters&&console.log("💟💟💟 currentElementBottom > floater,\ntry to split",_);const o=this._getProcessedChildren(_,n,i);if(o.length)c(t),h.push(f),this._getInternalBlockSplitters({rootNode:e,rootComputedStyle:d,children:o,pageBottom:n,firstPartHeight:s,fullPageHeight:i,result:r,trail:l[t].children=[],indexTracker:a,stack:h}),h.pop(),this._debug._getInternalBlockSplitters&&console.log("🟪 back from _getInternalBlockSplitters;\n trail[i]",l[t]);else if(g&&this._node.isNoHanging(g)){console.warn("tst improveResult",g);let e=g;e=this._node.findFirstChildParent(e,this._contentFlow)||e;e=this._node.findPreviousNonHangingsFromPage(e,this.pages.at(-2)?.pageBottom,this._root)||e,this._debug._getInternalBlockSplitters&&console.log("previousElement _isNoHanging"),p(e,t-1)}else this._debug._getInternalBlockSplitters&&console.log(_,"currentElement has no children"),p(_,t)}}}return c(),this._DOM.setStyles(e,{position:g}),this._debug._getInternalBlockSplitters&&console.log("%c END _getInternalBlockSplitters",_),this._debug._getInternalBlockSplitters&&console.groupEnd(),{result:r,trail:l}}_splitGridNode(e,t,o){this._debug._splitGridNode&&console.group("%c_splitGridNode","background:#00FFFF");const n=this._node.getPreparedChildren(e);this._debug._splitGridNode&&console.log("💠 children",n),this._debug._splitGridNode&&console.groupCollapsed("make childrenGroups");const s=n.reduce(((e,t,o,n)=>{const s=this._DOM.getComputedStyle(t),i=s.getPropertyValue("grid-column-start"),r=s.getPropertyValue("grid-column-end"),l={element:t,start:"auto"===i?"auto":parseInt(s.getPropertyValue("grid-column-start")),end:"auto"===r?"auto":parseInt(s.getPropertyValue("grid-column-end")),top:this._DOM.getElementOffsetTop(t)};return!e.length||e.at(-1).at(-1).start>=l.start||"auto"===e.at(-1).at(-1).start||"auto"===l.start?(e.at(-1)&&this._node.isNoHanging(e.at(-1).at(-1).element)?(e.at(-1).push(l),this._debug._splitGridNode&&console.log("Add to group (after no-hang.)",l)):(e.push([l]),this._debug._splitGridNode&&console.log("Start new group:",l)),this._debug._splitGridNode&&console.log("result:",[...e]),e):e.length&&e.at(-1).at(-1).starte.map((e=>e.top)).sort())).map((e=>e[0])),r];this._debug._splitGridNode&&console.log("gridPseudoRowsTopPoints",l);const a=this._node.getTop(e,this._root),h=this._node.getEmptyNodeHeight(e),d=t-a-h,g=o-h;this._debug._splitGridNode&&console.log("\n • firstPartHeight",d,"\n • fullPagePartHeight",g);const c=l;let p=[],u=d;for(let e=0;eu&&(e>this._minLeftRows&&p.push(e-1),u=c[e-1]+g);this._debug._splitGridNode&&console.log("splitsIds",p);const m=(t,o)=>{this._debug._splitGridNode&&console.log(`=> insertGridSplit(${t}, ${o})`);const n=s.slice(t,o).flat().map((e=>e.element));this._debug._splitGridNode&&console.log("partEntries",n);const i=this._DOM.cloneNodeWrapper(e);return this._node.copyNodeWidth(i,e),this._node.setFlagNoBreak(i),e.before(i),this._DOM.insertAtEnd(i,...n),i},f=[...p.map(((e,t,o)=>m(o[t-1]||0,e))),e];return this._debug._splitGridNode&&console.log("splits",f),f.forEach(((e,t)=>this._DOM.setAttribute(e,"[part]",`${t}`))),this._node.setFlagNoBreak(e),this._debug._splitGridNode&&console.log("%c END _splitGridNode",_),this._debug._splitGridNode&&console.groupEnd(),f}}class m{constructor({config:e,DOM:t,node:o,selector:n,layout:s}){this._DOM=t,this._selector=n,this._node=o,this._frontpageTemplate=s.frontpageTemplate,this._headerTemplate=s.headerTemplate,this._footerTemplate=s.footerTemplate,this._paperBodySelector=n?.paperBody||".paperBody",this._paperHeaderSelector=n?.paperHeader||".paperHeader",this._paperFooterSelector=n?.paperFooter||".paperFooter",this._headerContentSelector=n?.headerContent||".headerContent",this._footerContentSelector=n?.footerContent||".footerContent",this._frontpageContentSelector=n?.frontpageContent||".frontpageContent",this._virtualPaperSelector=n?.virtualPaper||".virtualPaper",this._virtualPaperTopMarginSelector=n?.virtualPaperTopMargin||".virtualPaperTopMargin",this._virtualPaperBottomMarginSelector=n?.virtualPaperBottomMargin||".virtualPaperBottomMargin",this._pageNumberRootSelector=n?.pageNumberRoot||void 0,this._pageNumberCurrentSelector=n?.pageNumberCurrent||void 0,this._pageNumberTotalSelector=n?.pageNumberTotal||void 0,this._paperHeight,this._frontpageFactor,this.headerHeight,this.footerHeight,this.bodyHeight,this.bodyWidth,this._calculatePaperParams()}create({currentPage:e,totalPages:t}){const o=this._createPaperBody(this.bodyHeight),n=this._createPaperHeader(this._headerTemplate),s=this._createPaperFooter(this._footerTemplate);return this._createPaper({header:n,body:o,footer:s,currentPage:e,totalPages:t})}createFrontpage({currentPage:e,totalPages:t}){const o=this._createFrontpageContent(this._frontpageTemplate,this._frontpageFactor),n=this._createPaperBody(this.bodyHeight,o),s=this._createPaperHeader(this._headerTemplate),i=this._createPaperFooter(this._footerTemplate);return this._createPaper({header:s,body:n,footer:i,currentPage:e,totalPages:t})}createVirtualTopMargin(){return this._node.create(this._virtualPaperTopMarginSelector)}createVirtualBottomMargin(){return this._node.create(this._virtualPaperBottomMarginSelector)}_createPaper({header:e,body:t,footer:o,currentPage:n,totalPages:s}){const i=this._node.create(this._virtualPaperSelector);return this._DOM.insertAtEnd(i,this.createVirtualTopMargin(),e,t,o,this.createVirtualBottomMargin()),n&&s&&(this._setPageNumber(e,n,s),this._setPageNumber(o,n,s)),i}_createFrontpageContent(e,t){const o=this._node.create(this._frontpageContentSelector);return e&&this._DOM.setInnerHTML(o,e),t&&this._DOM.setStyles(o,{transform:`scale(${t})`}),o}_createPaperBody(e,t){const o=this._node.create(this._paperBodySelector);return this._DOM.setStyles(o,{height:e+"px"}),t&&this._DOM.insertAtEnd(o,t),o}_createPaperHeader(e){const t=this._node.create(this._paperHeaderSelector);if(e){const o=this._node.create(this._headerContentSelector);this._DOM.setInnerHTML(o,e),this._DOM.insertAtEnd(t,o)}return t}_createPaperFooter(e){const t=this._node.create(this._paperFooterSelector);if(e){const o=this._node.create(this._footerContentSelector);this._DOM.setInnerHTML(o,e),this._DOM.insertAtEnd(t,o)}return t}_setPageNumber(e,t,o){const n=this._pageNumberRootSelector?this._DOM.getElement(this._pageNumberRootSelector,e):this._pageNumberRootSelector;if(n){const e=this._DOM.getElement(this._pageNumberCurrentSelector,n),s=this._DOM.getElement(this._pageNumberTotalSelector,n);this._DOM.setInnerHTML(e,t),this._DOM.setInnerHTML(s,o)}}_calculatePaperParams(){const e=this._createPaperBody(),t=this._createFrontpageContent(this._frontpageTemplate),o=this._createPaperHeader(this._headerTemplate),n=this._createPaperFooter(this._footerTemplate),s=this._createPaper({header:o,body:e,footer:n}),i=this._node.create("#workbench");this._DOM.setStyles(i,{position:"absolute",left:"-3000px"}),this._DOM.insertAtEnd(i,s),this._DOM.insertAtStart(this._DOM.body,i);const r=this._DOM.getElementBCR(s).height,l=this._DOM.getElementOffsetHeight(o)||0,a=this._DOM.getElementOffsetHeight(n)||0,h=this._DOM.getElementOffsetHeight(e),d=this._DOM.getElementOffsetWidth(e);this._DOM.insertAtStart(e,t);const g=this._DOM.getElementOffsetHeight(e),c=g>h?h/g:1;this._DOM.removeNode(i),l>.2*r&&console.warn("It seems that your custom header is too high"),a>.15*r&&console.warn("It seems that your custom footer is too high"),c<1&&console.warn("It seems that your frontpage content is too large. We made it smaller to fit on the page. Check out how it looks! It might make sense to fix this with styles or reduce the text amount."),this._paperHeight=r,this.headerHeight=l,this.footerHeight=a,this.bodyHeight=h,this.bodyWidth=d,this._frontpageFactor=c}}class f{constructor({config:e,DOM:t,selector:o,node:n,pages:s,layout:i,paper:r}){this._config=e,this._debug=e.debugMode?{...e.debugConfig.preview}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._selector=o,this._node=n,this._virtualPaperGapSelector=o.virtualPaperGap,this._runningSafetySelector=o.runningSafety,this._printPageBreakSelector=o.printPageBreak,this._pageDivider=o.pageDivider,this._virtualPaper=o.virtualPaper,this._virtualPaperTopMargin=o.virtualPaperTopMargin,this._paperBody=o.paperBody,this._pages=s,this._root=i.root,this._contentFlow=i.contentFlow,this._paperFlow=i.paperFlow,this._paper=r,this._hasFrontPage=!!i.frontpageTemplate}create(){this._processFirstPage(),this._processOtherPages(),(!0===this._config.mask||"true"===this._config.mask)&&this._addMask()}_addMask(){const e=parseInt(this._config.virtualPagesGap),t=parseInt(this._config.printHeight),o=parseInt(this._config.printTopMargin),n=parseInt(this._config.printBottomMargin),s=parseInt(this._config.headerMargin),i=parseInt(this._config.footerMargin),r=this._paper.headerHeight,l=this._paper.footerHeight,a=this._paper.bodyHeight,h=r?Math.ceil(s/2):0,d=l?Math.ceil(i/2):0,g=r-h,c=l-d,p=a+h+d,_=o+g,u=t+e;this._assert&&console.assert(t===p+g+o+c+n,"Paper size calculation params do not match"),function({targetElement:e,maskStep:t,maskWindow:o,maskFirstShift:n}){e.style=`\n -webkit-mask-image: linear-gradient(\n black 0,\n black ${o}px,\n transparent ${o}px,\n transparent ${t}px\n );\n mask-image: linear-gradient(\n black 0,\n black ${o}px,\n transparent ${o}px,\n transparent ${t}px\n );\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-size: 100% ${t}px;\n mask-size: 100% ${t}px;\n -webkit-mask-position: 100% ${n}px;\n mask-position: 100% ${n}px;\n -webkit-mask-repeat: repeat-y;\n mask-repeat: repeat-y;\n -webkit-mask-origin: border-box;\n mask-origin: border-box;\n `}({targetElement:this._contentFlow,maskStep:u,maskWindow:p,maskFirstShift:_})}_processFirstPage(){let e;if(this._hasFrontPage){const t=this._insertFrontpageSpacer(this._contentFlow,this._paper.bodyHeight);this._pages.unshift({pageStart:t}),e=this._paper.createFrontpage({currentPage:1,totalPages:this._pages.length})}else e=this._paper.create({currentPage:1,totalPages:this._pages.length});this._insertIntoPaperFlow(e),this._insertIntoContentFlow(0)}_processOtherPages(){for(let e=1;e=0,`balancer is negative: ${n} < 0`,t)}}class b{constructor({config:e,DOM:t,selector:o,node:n,layout:s}){this._debugMode=e.debugMode,this._debug=e.debugMode?{...e.debugConfig.toc}:{},this._DOM=t,this._node=n,this._tocPageNumberSelector=e.tocPageNumberSelector,this._root=s.root,this._contentFlow=s.contentFlow,this._pageDividerSelector=o.pageDivider}render(){this._debugMode&&console.time("Processing TOC"),this._debug._&&console.log(`\n📑 TOC: I am here!\n\ntocPageNumberSelector:\n • ${this._tocPageNumberSelector}\n pageDividerSelector:\n • ${this._pageDividerSelector}\n `);const e=this._node.getAll(this._tocPageNumberSelector,this._contentFlow);if(this._debug._&&console.log("📑 tocPageNumberBoxes",e.length),!e.length)return void(this._debug._&&console.log("📑 no valid toc"));const t=this._node.getAll(this._pageDividerSelector,this._contentFlow).reduce(((e,t,o)=>{const n=this._node.getTop(t,this._root)-1,s=this._DOM.getAttribute(t,"[page]");return e[n]=s,e}),{});this._debug._&&console.log("📑 dataFromPagesMarkers",t);const o=e.reduce(((e,t)=>{const o=this._DOM.getDataId(t),n=this._DOM.getElementById(o),s=this._node.getTop(n,this._root);return e[s]={box:t,id:o,targetTop:s},e}),{});this._debug._&&console.log("📑 dataFromTOC",o);const n={...t,...o};let s=0;this._debug._&&console.groupCollapsed("Processing obj");for(const e in n){const t=n[e];this._debug._&&console.log(`Processing ${e}: ${t}`),"string"==typeof t?s=t:(t.page=s,this._DOM.setInnerHTML(t.box,s))}this._debug._&&console.groupEnd("Processing obj"),this._debug._&&console.log("📑 tocObject",n),this._debugMode&&console.timeEnd("Processing TOC")}}class M{constructor({config:e,DOM:t,selector:o,node:n,layout:s}){this._config=e,this._selector=o,this._DOM=t,this._node=n,this._layout=s,this._root=s.root,this._assert=!!e.consoleAssert}init(){this._config.debugMode&&console.log("🐙 i am Validator!");const e=`${this._selector.paperFlow} ${this._selector.virtualPaperGap}`,t=`${this._selector.contentFlow} ${this._selector.virtualPaperGap}`,o=[...this._DOM.getAllElements(e)],n=[...this._DOM.getAllElements(t)],s=o.map((e=>this._node.getTop(e))),i=n.map((e=>this._node.getTop(e,this._root))),r=s.reduce(((e,t,o)=>(t!==i[o]&&e.push(o+1),e)),[]);this._assert&&console.assert(!r.length,"Problems with preview generation on the following pages: ",r)}}const P="border:1px dashed #cccccc;background:#ffffff;color:#cccccc;";class O{constructor(e){this._debugMode=e.debugMode,this._preloader,this._preloaderTarget=document.querySelector(e.preloaderTarget)||document.body,this._preloaderBackground=e.preloaderBackground||"white"}create(){this._debugMode&&console.groupCollapsed("%c Preloader ",P),this._insertStyle(),this._preloader=document.createElement("div"),this._preloader.classList.add("lds-dual-ring"),this._preloaderTarget.append(this._preloader),this._debugMode&&console.groupEnd("%c Preloader ",P)}remove(){if(!this._preloader)return;let e=1;const t=setInterval((()=>{e<=.1&&(clearInterval(t),this._preloader.remove()),this._preloader.style.opacity=e,e-=.1*e}),50);this._debugMode&&console.log("%c Preloader removed ",P)}_insertStyle(){const e=document.querySelector("head"),t=document.createElement("style");t.append(document.createTextNode(this._css())),t.setAttribute("data-preloader-style",""),e.append(t)}_css(){return`\n /* PRELOADER */\n .lds-dual-ring {\n position: absolute;\n z-index: 99999;\n top: 0; left: 0; bottom: 0; right: 0;\n background: ${this._preloaderBackground};\n display: flex;\n justify-content: center;\n align-items: center;\n }\n /*\n .lds-dual-ring:after {\n content: " ";\n display: block;\n width: 64px;\n height: 64px;\n margin: 8px;\n border-radius: 50%;\n border: 6px solid #eee;\n border-color: #eee transparent #eee transparent;\n animation: lds-dual-ring 1.2s linear infinite;\n }\n @keyframes lds-dual-ring {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n */\n `}}class N{constructor(e){this._debugMode=e.debugMode}run(){let e=[...document.querySelectorAll("object")];this._debugMode&&console.log(e);let t=[];return e.forEach((e=>{const o=new Promise((t=>{e.addEventListener("load",(o=>{this._debugMode&&console.log("⏰ EVENT: object load",e.clientHeight,e.clientWidth,e),t()}))}));t.push(o)})),Promise.all(t)}}const S="color:Gray;border:1px solid;";console.info("[HTML2PDF4DOC] Version:","0.2.3");const D=document.currentScript.dataset,E=new class{constructor(e){this.params=e,this.debugMode=e.debugMode,this.preloader=e.preloader,this.selector=o,this.config}async render(){console.time("[HTML2PDF4DOC] Total time"),this.debugMode&&console.log("🏁 document.readyState",document.readyState),document.addEventListener("readystatechange",(e=>{this.debugMode&&console.log("🏁 readystatechange",document.readyState)})),this.debugMode&&console.time("⏱️ await DOMContentLoaded time"),await new Promise((e=>{window.addEventListener("DOMContentLoaded",(t=>{this.debugMode&&console.log("⏰ EVENT: DOMContentLoaded"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await DOMContentLoaded time"),this.debugMode&&console.time("⏱️ create Preloader time");const e=new O(this.params);"true"===this.preloader&&e.create(),this.debugMode&&console.timeEnd("⏱️ create Preloader time"),this.debugMode&&console.time("⏱️ Config time"),this.debugMode&&console.groupCollapsed("%c config ",S+"color:LightGray"),this.config={...n(this.params),debugConfig:s},this.debugMode&&console.groupEnd(),this.debugMode&&console.info("⚙️ Current config with debugConfig:",this.config),this.debugMode&&console.timeEnd("⏱️ Config time"),this.config.consoleAssert&&console.info("🧧 Assertions enabled."),this.debugMode&&console.time("⏱️ DOM helpers init time");const t=new i({DOM:window.document,config:this.config});this.debugMode&&console.timeEnd("⏱️ DOM helpers init time"),this.debugMode&&console.time("⏱️ node helpers init time");const o=new a({config:this.config,DOM:t,selector:this.selector});this.debugMode&&console.timeEnd("⏱️ node helpers init time"),this.debugMode&&console.time("⏱️ await window load time"),await new Promise((e=>{window.addEventListener("load",(t=>{this.debugMode&&console.log("⏰ EVENT: window load"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await window load time"),this.debugMode&&console.time("⏱️ Layout time"),this.debugMode&&console.groupCollapsed("%c Layout ",S);const r=new l({config:this.config,DOM:t,selector:this.selector,node:o});if(r.create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Layout time"),!r.success)return void(this.debugMode&&console.error("Failed to create layout.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.info("%c calculate Paper params ",S),this.debugMode&&console.time("⏱️ Paper time");const h=new m({config:this.config,DOM:t,selector:this.selector,node:o,layout:r});if(this.debugMode&&console.timeEnd("⏱️ Paper time"),!h||!h.bodyHeight||!h.bodyWidth)return void(this.debugMode&&console.error("Failed to create paper calculations.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.time("⏱️ Preprocess time"),this.debugMode&&console.groupCollapsed("%c Preprocess ",S),await new N(this.config).run(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preprocess time"),this.debugMode&&console.time("⏱️ Pages time"),this.debugMode&&console.groupCollapsed("%c Pages ",S);const d=new u({config:this.config,DOM:t,selector:this.selector,node:o,layout:r,referenceHeight:h.bodyHeight,referenceWidth:h.bodyWidth}).calculate();this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Pages time"),this.debugMode&&console.time("⏱️ Preview time"),this.debugMode&&console.groupCollapsed("%c Preview ",S),new f({config:this.config,DOM:t,selector:this.selector,node:o,layout:r,paper:h,pages:d}).create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preview time"),this.debugMode&&console.time("⏱️ Toc time"),new b({config:this.config,DOM:t,selector:this.selector,node:o,layout:r}).render(),this.debugMode&&console.timeEnd("⏱️ Toc time"),this.debugMode&&console.time("⏱️ Validator time"),new M({config:this.config,DOM:t,selector:this.selector,node:o,layout:r}).init(),this.debugMode&&console.timeEnd("⏱️ Validator time"),t.setAttribute(r.root,"[success]"),t.setAttribute(r.root,"[pages]",d.length),e.remove(),console.info("[HTML2PDF4DOC] Page count:",d.length),console.timeEnd("[HTML2PDF4DOC] Total time")}}(D),B="manual"===D.init;function T(){B&&E.render()}B&&console.info("HTML2PDF4DOC in manual initialization mode"),!B&&E.render(),HTML2PDF4DOC=t})(); \ No newline at end of file +var HTML2PDF4DOC;(()=>{"use strict";var e={d:(t,i)=>{for(var n in i)e.o(i,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:i[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{init:()=>Tn});var i={};e.r(i),e.d(i,{log:()=>x,logGroup:()=>R,logGroupEnd:()=>k,strictAssert:()=>F});var n={};e.r(n),e.d(n,{isAfterContentFlowStart:()=>X,isComplexTextBlock:()=>ee,isContentFlowEnd:()=>Q,isContentFlowStart:()=>J,isFlexRow:()=>ue,isForcedPageBreak:()=>re,isFullySPlitted:()=>pe,isGrid:()=>ae,isGridAutoFlowRow:()=>ge,isIMG:()=>W,isInline:()=>se,isInlineBlock:()=>le,isLiNode:()=>V,isNeutral:()=>U,isNoBreak:()=>ie,isNoHanging:()=>ne,isOBJECT:()=>z,isPRE:()=>de,isPageStartElement:()=>Z,isSTYLE:()=>G,isSVG:()=>j,isSelectorMatching:()=>L,isSignificantTextNode:()=>$,isSlice:()=>oe,isSlough:()=>_e,isSyntheticTextWrapper:()=>te,isTableLikeNode:()=>he,isTableNode:()=>ce,isWrappedTextGroup:()=>Y,isWrappedTextLine:()=>K,isWrappedTextNode:()=>q});var o={};e.r(o),e.d(o,{insertStyle:()=>fe});var r={};e.r(r),e.d(r,{isFirstChildOfFirstChild:()=>be,isLastChildOfLastChild:()=>we,isLineChanged:()=>Se,isLineKept:()=>Me,resolveFlowElement:()=>Ce,setInitStyle:()=>Pe});var s={};e.r(s),e.d(s,{getBottom:()=>ve,getBottomWithMargin:()=>Re,getContentHeightByProbe:()=>$e,getEmptyNodeHeightByProbe:()=>Ne,getHeightWithMargin:()=>ke,getLineHeight:()=>Be,getMaxWidth:()=>Fe,getNormalizedBottomWithMargin:()=>Ee,getNormalizedTop:()=>ye,getTableEmptyRowHeight:()=>Ae,getTableEntries:()=>Le,getTableRowHeight:()=>He,getTableRowShellHeightByTD:()=>Ie,getTop:()=>De,getTopForPageStartCandidate:()=>Te,getTopWithMargin:()=>xe});var l={};e.r(l),e.d(l,{create:()=>Ge,createComplexTextBlock:()=>Ye,createForcedPageBreak:()=>Xe,createNeutral:()=>We,createNeutralBlock:()=>je,createPrintPageBreak:()=>Ke,createSignpost:()=>Qe,createTable:()=>et,createTestNodeFrom:()=>Ze,createTextGroup:()=>Ue,createTextLine:()=>Ve,createTextNodeWrapper:()=>ze,createWithFlagNoBreak:()=>qe,createWord:()=>Je});var a={};e.r(a),e.d(a,{prepareSplittedNode:()=>ot,splitByWordsGreedyWithSpacesFilter:()=>nt,splitTextByLinesGreedy:()=>tt,splitTextByWordsGreedy:()=>it});var h={};e.r(h),e.d(h,{markBottomCut:()=>ft,markCleanBottomCut:()=>pt,markCleanTopCut:()=>ut,markPageEndElement:()=>gt,markPageStartElement:()=>ct,markProcessed:()=>st,markSliceCuts:()=>mt,markSliceCutsInRows:()=>bt,markTopCut:()=>_t,setFlagNoBreak:()=>lt,setFlagNoHanging:()=>at,setFlagSlice:()=>ht,unmarkPageStartElement:()=>dt});var c={};e.r(c),e.d(c,{wrapNodeChildrenWithNeutralBlock:()=>wt});var d={};e.r(d),e.d(d,{copyNodeWidth:()=>Ot,estimateInlineImgGapBelow:()=>Et,fitElementWithinBoundaries:()=>Mt,fitElementWithinHeight:()=>Pt,lockNodesWidths:()=>yt,lockTableWidths:()=>Tt,scaleCellsToHeight:()=>Ct});var g={};e.r(g),e.d(g,{findAllForcedPageBreakInside:()=>Ht,findBetterForcedPageStarter:()=>vt,findBetterPageStart:()=>Rt,findFirstChildParent:()=>Ft,findFirstChildParentFromPage:()=>kt,findLastChildParent:()=>Nt,findPreviousNonHangingsFromPage:()=>xt,findSuitableNonHangingPageStart:()=>Bt});var u={};e.r(u),e.d(u,{getFirstChildrenChain:()=>zt,getLastChildrenChain:()=>Vt,getPreparedChildren:()=>Wt,getSplitChildren:()=>jt});var p={};e.r(p),e.d(p,{isReplacedElement:()=>Qt,resolveReplacedElement:()=>ei});var _={};e.r(_),e.d(_,{cloneAndCleanOutsideRange:()=>ai,getSplitPoints:()=>ii,getSplitPointsPerCells:()=>ni,isFirstSliceEmpty:()=>li,normalizeContentCuts:()=>ri,sliceNodeBySplitPoints:()=>oi,sliceNodeContentBySplitPoints:()=>si});var f={};e.r(f),e.d(f,{shouldSkipFlowElement:()=>ui});var m={};e.r(m),e.d(m,{buildRowSlices:()=>_i,evaluateRowSplitPlacement:()=>mi,paginationBuildBalancedRowSlices:()=>fi,replaceCurrentRowsAfterRowSplit:()=>bi,sliceCellsBySplitPoints:()=>pi});var b={};e.r(b),e.d(b,{paginationApplyFullPageScaling:()=>Pi,paginationScaleCellsToHeight:()=>Si,paginationShouldScaleFullPage:()=>Mi});var w={};e.r(w),e.d(w,{applyRowSlicesToEntriesAfterRowSplit:()=>Ci,computeRowFlags:()=>Oi});var S={};e.r(S),e.d(S,{paginationRefreshRowsAfterSplit:()=>yi,validateSplitterAdapter:()=>Ti});var M={};e.r(M),e.d(M,{paginationComputeCellShellHeights:()=>Ei});var P={};e.r(P),e.d(P,{handleRowOverflow:()=>Ri,handleRowSplitFailure:()=>ki,scaleRowCellsToHeight:()=>vi});var C={};e.r(C),e.d(C,{absorbShortTrailingSliceIfFits:()=>Fi,calculateFinalPartReclaimedHeight:()=>xi});var O={};e.r(O),e.d(O,{paginationBuildRowEvaluationContext:()=>Bi,paginationCanAbsorbLastRow:()=>Hi});var T={};e.r(T),e.d(T,{paginationCalculateRowSplitBudget:()=>Gi,paginationHandleRowSlicesPlacement:()=>Ui,paginationProcessRowSplitResult:()=>zi,paginationResolveAlreadySlicedRow:()=>$i,paginationResolveOverflowingRow:()=>Ii,paginationResolveRowWithRowspan:()=>Li,paginationResolveSplittableRow:()=>Vi,paginationSplitRow:()=>Wi});const y={init:"[html2pdf]",pageDivider:"html2pdf-page",pageStartMarker:"[html2pdf-page-start]",pageEndMarker:"[html2pdf-page-end]",contentFlowStart:"html2pdf-content-flow-start",contentFlowEnd:"html2pdf-content-flow-end",style:"[html2pdf-style]",footerTemplate:"[html2pdf-footer]",headerTemplate:"[html2pdf-header]",frontpageTemplate:"[html2pdf-frontpage]",frontpageContent:"html2pdf-frontpage",headerContent:"html2pdf-header",footerContent:"html2pdf-footer",pageNumberRoot:"[html2pdf-page-number]",pageNumberCurrent:"[html2pdf-page-number-current]",pageNumberTotal:"[html2pdf-page-number-total]",root:"html2pdf-root",paperFlow:"html2pdf-paper-flow",contentFlow:"html2pdf-content-flow",virtualPaper:"html2pdf-virtual-paper",virtualPaperTopMargin:"html2pdf-virtual-paper-margin-top",virtualPaperBottomMargin:"html2pdf-virtual-paper-margin-bottom",virtualPaperGap:"html2pdf-virtual-paper-gap",paperBody:"html2pdf-paper-body",paperHeader:"html2pdf-paper-header",paperFooter:"html2pdf-paper-footer",runningSafety:"html2pdf-print-running",printPageBreak:"html2pdf-print-page-break",printIgnore:"[html2pdf-print-ignore]",printHide:"[html2pdf-print-hide]",neutral:"html2pdf-neutral",word:"html2pdf-word",textNode:"html2pdf-text-node",textLine:"html2pdf-text-line",textGroup:"html2pdf-text-group",complexTextBlock:"html2pdf-complex-text-block",printForcedPageBreak:"html2pdf-print-forced-page-break",split:"[html2pdf-split]",processed:"[html2pdf-processed]",flagNoBreak:"[html2pdf-flag-no-break]",flagNoHanging:"[html2pdf-flag-no-hanging]",flagSlice:"[html2pdf-flag-slice]",topCutPart:".html2pdf-top-cut",bottomCutPart:".html2pdf-bottom-cut",cleanTopCut:".html2pdf-clean-top-cut",cleanBottomCut:".html2pdf-clean-bottom-cut",tocPageNumber:"html2pdf-toc-page-number"};function E(e){let t={debugMode:!1,consoleAssert:!1,markupDebugMode:!1,preloader:!1,preloaderTarget:"",preloaderBackground:"",mask:!0,noHangingSelectors:"",forcedPageBreakSelectors:"",pageBreakBeforeSelectors:"",pageBreakAfterSelectors:"",noBreakSelectors:"",tocPageNumberSelector:"html2pdf-toc-page-number",printLeftMargin:"21mm",printRightMargin:"21mm",printTopMargin:"12mm",printBottomMargin:"12mm",printFontSize:"12pt",paperColor:"white",printWidth:"210mm",printHeight:"297mm",headerMargin:"16px",footerMargin:"16px",virtualPagesGap:"16px",splitLabelHeight:"24px"};const i={printWidth:"210mm",printHeight:"297mm"},n={printWidth:"148.5mm",printHeight:"210mm"};switch((e=function(e){const t={...e};for(const e in t){const i=t[e];if("string"==typeof i){const n=i.toLowerCase();"true"===n||"1"===n?t[e]=!0:"false"!==n&&"0"!==n&&""!==n||(t[e]=!1)}}return t}(e)).printPaperSize){case"A5":case"a5":t={...t,...n};break;default:t={...t,...i}}t={...t,initialRoot:y.init,tocPageNumberSelector:y.tocPageNumber,...e},console.info("[HTML2PDF4DOC] Config:",t);const o={printLeftMargin:t.printLeftMargin,printRightMargin:t.printRightMargin,printTopMargin:t.printTopMargin,printBottomMargin:t.printBottomMargin,printFontSize:t.printFontSize,printWidth:t.printWidth,printHeight:t.printHeight,headerMargin:t.headerMargin,footerMargin:t.footerMargin,virtualPagesGap:t.virtualPagesGap},r=document.createElement("div");return r.style="\n position:absolute;\n z-index:1000;\n left: 200%;\n ",document.body.append(r),Object.entries(o).forEach((([e,t])=>{r.style.width=t,o[e]=`${Math.trunc(r.getBoundingClientRect().width)}px`})),r.remove(),t={...t,...o},t.noHangingSelectors=t.noHangingSelectors+" H1 H2 H3 H4 H5 H6",t.forcedPageBreakSelectors=t.forcedPageBreakSelectors+" "+y.printForcedPageBreak,t.debugMode&&console.info("Config with converted units:",t),t}const D={DOM:{_:!1},layout:{_:!1},pages:{_:!1,_parseNode:!1,_parseNodes:!1,_registerPageStart:!1},paper:{_:!1},preview:{_:!1},toc:{_:!1},node:{_:!1,children:!1,creators:!1,flowFilters:!1,fitters:!1,getters:!1,markers:!1,pageBreaks:!1,positioning:!1,selectors:!1,slicers:!1,splitters:!1,wrappers:!1,pagination:!1},paragraph:{_:!1},grid:{_:!1},pre:{_:!1},table:{_:!1},tableLike:{_:!1}},v="background:#eee;color:#888;padding: 0 1px 0 0;";function R(e,t="",i=!1){"boolean"==typeof t&&(i=t,t=""),!0===i?this._debug._&&console.groupCollapsed(`%c${e}`,t):this._debug._&&console.group(`%c${e}`,t)}function k(e){this._debug._&&console.log(`%c ▲ ${e} `,v),this._debug._&&console.groupEnd()}function x(e,...t){this._debug._&&console.log(`[${e}]`,...t)}function F(e,...t){this._assert&&console.assert(e,"⛔",...t)}class N{constructor({DOM:e,config:t}){this.document=e,this.body=e.body,this._debug=t.debugMode?{...t.debugConfig.DOM}:{},this._assert=!!t.consoleAssert,Object.assign(this,i)}createElement(e){return this.document.createElement(e)}createDocumentFragment(){return this.document.createDocumentFragment()}cloneNode(e){return e?.cloneNode(!0)}cloneNodeWrapper(e){return e?.cloneNode(!1)}insertBefore(e,...t){const i=t.filter((e=>null!=e));e.before(...i)}insertAfter(e,...t){const i=t.filter((e=>null!=e));e.after(...i)}insertAtEnd(e,...t){const i=t.filter((e=>null!=e));e.append(...i)}insertAtStart(e,...t){const i=t.filter((e=>null!=e));e.prepend(...i)}insertInsteadOf(e,...t){this.insertBefore(e,...t),e.remove()}wrap(e,t){return e.before(t),t.append(e),t}moveContent(e,t){for(;e.firstChild;)t.append(e.firstChild);this.strictAssert(""===this.getInnerHTML(e))}moveRowContent(e,t){if(!e||!t)return void(this._debug._&&console.warn("moveRowContent(): sourceTR or targetTR is missing"));const i=this.getElementTagName(e),n=this.getElementTagName(t);this.strictAssert("TR"===i,`moveRowContent(): source is not TR, got ${i}`),this.strictAssert("TR"===n,`moveRowContent(): target is not TR, got ${n}`);const o=[...this.getChildren(e)],r=[...this.getChildren(t)];o.length!==r.length&&this._debug._&&console.warn(`moveRowContent(): cells count mismatch: ${o.length} (source) vs ${r.length} (target)`);const s=Math.min(o.length,r.length);for(let e=0;e0,"getAll(selectors), selectors:",e),1===e.length?[...this.getAllElements(e[0],t)]:[...e].flatMap((e=>[...this.getAllElements(e,t)]))}getElement(e,t=this.document){return this.strictAssert(e),t.querySelector(e)}getAllElements(e,t=this.document){return this.strictAssert(e),t.querySelectorAll(e)}getElementById(e,t=this.document){return t.getElementById(e)}getRightNeighbor(e){return e.nextElementSibling}getLeftNeighbor(e){return e.previousElementSibling}getParentNode(e){return e.parentElement}getNodeValue(e){return e.nodeValue}getLastElementChild(e){return e.lastElementChild}getFirstElementChild(e){return e.firstElementChild}getChildNodes(e){return e.childNodes}getChildren(e){return e.children}getElementOffsetParent(e){return e.offsetParent}getComputedStyle(e){return window.getComputedStyle(e)}getElementBCR(e){return e.getBoundingClientRect()}getElementOffsetLeft(e){return e?.offsetLeft}getElementOffsetHeight(e){return e?.offsetHeight}getElementOffsetWidth(e){return e?.offsetWidth}getElementOffsetTop(e){return e?.offsetTop}getElementOffsetBottom(e){return e?.offsetTop+e?.offsetHeight||void 0}getElementTagName(e){return e.tagName}getDataId(e){return e.dataset.id}getAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("getAttribute() must have 2 params"));const i=t.charAt(0);if("."!==i&&"#"!==i||this.log("getAttribute",`you're really sure ${t} is attribute selector?`),"["===i){this.strictAssert("]"===t.at(-1),`the ${t} selector is not OK.`);const i=t.substring(1,t.length-1);return e.getAttribute(i)}e.getAttribute(t)}setAttribute(e,t,i){if(!e||!t)return void(this._debug._&&console.warn("setAttribute() must have 2 params"));const n=t.charAt(0);if("."!==n)if("#"!==n)if("["!==n)this.log("setAttribute",`you're really sure ${t} is a selector?`);else{this.strictAssert("]"===t.at(-1),`the ${t} selector is not OK.`);const n=t.substring(1,t.length-1);e.setAttribute(n,i||"")}else{const i=t.substring(1);e.id=i}else{const i=t.substring(1);e.classList.add(i)}}setStyles(e,t){Object.entries(t).forEach((([t,i])=>{Array.isArray(i)?this.setStyle(e,t,i[0],i[1]||""):this.setStyle(e,t,i)}))}setStyle(e,t,i,n=""){const o=this._toKebab(t);null==i||""===i?e.style.removeProperty(o):e.style.setProperty(o,String(i),n)}_toKebab=e=>{if(e.includes("-"))return e;const t=e.match(/^(webkit|moz|ms|o)(?=[A-Z])/);return t&&(e="-"+t[1]+"-"+e.slice(t[1].length)),e.replace(/[A-Z]/g,(e=>"-"+e.toLowerCase()))};addClasses(e,...t){e.classList.add(...t)}removeAttribute(e,t){if(!e||!t)return void(this._debug._&&console.warn("removeAttribute() must have 2 params"));const i=t.charAt(0);if(this.strictAssert(i.match(/[a-zA-Z#\[\.]/),`removeAttribute() expects a valid selector, but received ${t}`),"."!==i)if("#"!==i)if("["!==i)e.removeAttribute(attr);else{this.strictAssert("]"===t.at(-1),`the ${t} selector is not OK.`);const i=t.substring(1,t.length-1);e.removeAttribute(i)}else{const i=t.substring(1);e.removeAttribute(i)}else{const i=t.substring(1);e.classList.remove(i)}}removeAllAttributes(e){for(;e.attributes.length>0;)e.removeAttribute(e.attributes[0].name)}removeClasses(e,...t){e.classList.remove(...t)}removeAllClasses(e){e.classList=""}removeAllStyles(e){e.style=""}getInnerHTML(e){if("string"==typeof e){const t=this.document.querySelector(e);return t?t.innerHTML:void 0}return e.innerHTML}setInnerHTML(e,t){if("string"==typeof e){const i=this.document.querySelector(e);i&&(i.innerHTML=t)}e.innerHTML=t}isDocumentBody(e){return"BODY"===e.tagName}isTextNode(e){return e.nodeType===Node.TEXT_NODE}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}hasClass(e,t){return e.classList.contains(t)}hasID(e,t){return e.id===t}hasAttribute(e,t){return e.hasAttribute(t)}}class B{constructor(e){this.config=e,this.charWidth="10px"}create(){return this._baseStyle()+this._testStyle()}_baseStyle(){return`\n\n@page {\n size: A4;\n /* 2 values: width then height */\n size: ${this.config.printWidth} ${this.config.printHeight};\n\n margin-left: ${this.config.printLeftMargin};\n margin-right: ${this.config.printRightMargin};\n margin-top: ${this.config.printTopMargin};\n /* margin-bottom: ${this.config.printBottomMargin}; */\n margin-bottom: 0; /* hack */\n}\n\n${y.root} {\n /* reset user styles */\n display: block;\n\n /* for proper printable flow positioning */\n position: relative;\n\n /* to compensate for possible BG in the parent node */\n z-index: 1;\n\n /* set print styles: affects previews */\n margin: 0 auto;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n font-size: ${this.config.printFontSize};\n\n /* protection against unpredictability of margins */\n padding-top: .1px;\n padding-bottom: calc(2 * ${this.config.virtualPagesGap});\n}\n\n${y.contentFlowStart},\n${y.contentFlowEnd},\n${y.pageDivider} {\n display: block;\n /* to avoid the effect of margins of neighboring elements on the positioning of this marker: */\n overflow: auto;\n}\n\n${y.virtualPaper} {\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: minmax(min-content, max-content) minmax(min-content, max-content) 1fr minmax(min-content, max-content) minmax(min-content, max-content);\n place-items: stretch stretch;\n place-content: stretch stretch;\n width: calc(${this.config.printWidth} - ${this.config.printLeftMargin} - ${this.config.printRightMargin});\n height: ${this.config.printHeight};\n font-size: ${this.config.printFontSize};\n}\n\n${y.virtualPaper}::before {\n position: absolute;\n content: '';\n width: ${this.config.printWidth};\n height: ${this.config.printHeight};\n left: -${this.config.printLeftMargin};\n background-color: #fff;\n box-shadow: rgba(0, 0, 0, 0.1) 2px 2px 12px 0px;\n z-index: -1;\n}\n\n${y.paperFooter},\n${y.paperHeader} {\n display: block;\n position: relative;\n}\n\n${y.headerContent},\n${y.footerContent} {\n display: block;\n font-size: small;\n}\n\n${y.headerContent} p,\n${y.footerContent} p {\n margin: 0;\n}\n\n${y.headerContent} {\n padding-bottom: ${this.config.headerMargin};\n /* padding-top: 1px; */\n /* Page numbers: */\n padding-top: 10px;\n}\n\n${y.footerContent} {\n padding-top: ${this.config.footerMargin};\n /* padding-bottom: 1px; */\n /* Page numbers: */\n min-height: 32px;\n}\n\n${y.tocPageNumber} {\n min-width: 3ch;\n display: flex;\n justify-content: flex-end;\n align-items: baseline;\n}\n\n${y.pageNumberRoot} {\n display: flex;\n column-gap: 2px;\n position: absolute;\n /* left: 100%; */\n right: 0;\n text-align: right;\n line-height: 1;\n}\n\n${y.headerContent} ${y.pageNumberRoot} {\n top: 0;\n}\n\n${y.footerContent} ${y.pageNumberRoot} {\n bottom: 0;\n}\n\n${y.paperFlow} {\n display: block;\n position: absolute;\n width: 100%;\n z-index: -1;\n /* affect only screen */\n padding-bottom: 100px;\n}\n\n${y.contentFlow} {\n display: block;\n}\n\n${y.runningSafety} {\n display: block;\n overflow: auto;\n}\n\n${y.virtualPaperTopMargin} {\n display: block;\n height: ${this.config.printTopMargin};\n}\n\n${y.virtualPaperBottomMargin} {\n display: block;\n height: ${this.config.printBottomMargin};\n}\n\n${y.virtualPaperGap} {\n display: block;\n padding-top: ${this.config.virtualPagesGap};\n}\n\n${y.paperBody} {\n display: block;\n}\n\n${y.frontpageContent} {\n display: block;\n transform-origin: top center;\n padding: .1px;\n height: 100%;\n}\n\n.null {\n display: inline;\n padding: 0;\n margin: 0;\n font: 0;\n color: transparent;\n line-height: 0;\n border: none;\n outline: none;\n background: none;\n background-color: transparent;\n}\n\n${y.word},\n${y.textNode},\n${y.textLine},\n${y.textGroup},\n${y.neutral},\n${y.neutral} span {\n display: inline;\n padding: 0;\n margin: 0;\n font: inherit;\n color: inherit;\n line-height: inherit;\n background: none;\n background-color: transparent;\n}\n\n${y.textGroup} {\n display: block;\n}\n\n/*${y.split} ${y.textGroup} {\n display: inline;\n}*/\n\n${y.complexTextBlock} > ${y.textLine} {\n /* Firefox and inconsistent values of offset top for inline element */\n display: inline-block;\n // TODO: it removes spaces between parts of the string, it should leave the text inline after processing.\n}\n\n${y.textGroup} ${y.textLine} {\n display: inline;\n}\n\n${y.complexTextBlock} {\n display: block;\n}\n\n${y.complexTextBlock} ${y.complexTextBlock} {\n display: inline;\n}\n\n${y.printPageBreak} {\n display: block;\n}\n\n${y.printForcedPageBreak} {\n display: block;\n visibility: hidden;\n height: 0;\n overflow: hidden;\n}\n\n@media print {\n ${y.root} {\n /* to prevent a blank last page */\n padding: 0;\n }\n\n ${y.root}::after {\n /* Safety placeholder for the bottom margin of the paper */\n --paper-color: ${this.config.paperColor};\n content: '';\n position: fixed;\n pointer-events: none;\n z-index: 2147483647;\n background: var(--paper-color, white);\n inset: 0;\n top: unset;\n height: ${this.config.printBottomMargin};\n }\n\n ${y.paperFlow} {\n padding-bottom: 0;\n }\n\n ${y.contentFlow} {\n /*\n -webkit-mask-image: none !important;\n mask-image: none !important;\n */\n }\n\n ${y.printIgnore} {\n display: contents;\n }\n\n ${y.printHide},\n ${y.virtualPaper}::before,\n ${y.virtualPaperTopMargin},\n ${y.virtualPaperBottomMargin},\n ${y.virtualPaperGap} {\n display: none;\n }\n\n ${y.virtualPaper} {\n break-inside: avoid;\n height: auto;\n }\n\n ${y.paperBody} {\n break-inside: avoid;\n }\n\n ${y.printPageBreak} {\n break-after: page;\n /* padding: .1px; */\n overflow: auto;\n }\n\n ${y.printForcedPageBreak} {\n /* JUST MANUAL! */\n /* break-after: page; */\n }\n\n ${y.flagNoBreak} {\n /*\n TODO: temporary commented!\n When splitting blocks, printPageBreak falls INTO this element,\n and in Firefox it causes a blank page.\n FIX the split of complex blocks and check in Firefox.\n */\n /* break-inside: avoid-page; */\n }\n}\n\n/* arrangement */\n${y.topCutPart} {\n margin-top: 0 !important;\n}\n${y.bottomCutPart} {\n margin-bottom: 0 !important;\n}\n${y.cleanTopCut} {\n margin-top: 0 !important;\n padding-top: 0 !important;\n border-top: none !important;\n}\n${y.cleanBottomCut} {\n margin-bottom: 0 !important;\n padding-bottom: 0 !important;\n border-bottom: none !important;\n}\n `}_testStyle(){return this.config.debugMode?`\n/* FOR TEST */\n${y.contentFlow} {\n background:repeating-linear-gradient(\n -45deg,\n rgba(222, 222, 222, .1),\n rgba(222, 222, 222, .1) 10px,\n rgba(222, 222, 222, .2) 10px,\n rgba(222, 222, 222, .2) 20px\n );\n}\n\n${y.virtualPaperGap} {\n background: #ff000020;\n}\n\n${y.paperFooter},\n${y.paperHeader} {\n background: #fa96ff20;\n}\n${y.paperBody} {\n background: #ffee0020;\n}\n${y.runningSafety} {\n background: #f200ff;\n outline: 0.1px dashed #f200ff88;\n}\n${y.frontpageContent} {\n background: #00fcff20;\n}\n\n${y.neutral} {\n background: #00ffee10;\n}\n\n${y.textNode} {\n background: #00ff0010;\n}\n\n${y.textGroup},\n${y.textLine} {\n background: #0000ff08;\n}\n\n `:""}}class H{constructor({config:e,DOM:t,node:n,selector:o}){this.success=!1,this._assert=!!e.consoleAssert,Object.assign(this,i),this.root,this.paperFlow,this.contentFlow,this.frontpageTemplate,this.headerTemplate,this.footerTemplate,this._initialRoot,this._contentRoot,this._config=e,this._debug=e.debugMode?{...e.debugConfig.layout}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._selector=o,this._node=n,this._customInitialRootSelector=e.initialRoot,this._defaultInitialRootSelector=o.init}create(){if(this._getTemplates(),this._insertStyle(),this._DOM.getElement(`style${this._selector.style}`)){if(this._createLayout(),this._DOM.getParentNode(this.root)!==this._initialRoot||this._DOM.getElementOffsetParent(this.paperFlow)!==this.root||this._DOM.getElementOffsetParent(this.contentFlow)!==this.root)return this.strictAssert(this._DOM.getParentNode(this.root)===this._initialRoot,"Failed to insert the layout root into the DOM."),this.strictAssert(this._DOM.getElementOffsetParent(this.paperFlow)===this.root,"Failed to insert the paperFlow element into the DOM."),void this.strictAssert(this._DOM.getElementOffsetParent(this.contentFlow)===this.root,"Failed to insert the contentFlow element into the DOM.");this.success=!0}else console.error("Failed to add print styles into the DOM.")}_getTemplates(){this.strictAssert(this._selector.frontpageTemplate,"frontpageTemplate selector is missing"),this.strictAssert(this._selector.headerTemplate,"headerTemplate selector is missing"),this.strictAssert(this._selector.footerTemplate,"footerTemplate selector is missing"),this.frontpageTemplate=this._DOM.getInnerHTML(this._selector.frontpageTemplate),this.headerTemplate=this._DOM.getInnerHTML(this._selector.headerTemplate),this.footerTemplate=this._DOM.getInnerHTML(this._selector.footerTemplate)}_insertStyle(){this._node.insertStyle(new B(this._config).create())}_createLayout(){this._getInitialRoot(),this._initialRoot?(this.log("create Layout","initial root:",this._initialRoot),this._createRoot(),this._createPaperFlow(),this._createContentFlow(),this._DOM.moveContent(this._initialRoot,this.contentFlow),this._DOM.insertAtEnd(this._initialRoot,this.root),this._DOM.insertAtEnd(this.root,this.paperFlow,this.contentFlow),this._insertContentFlowStartAndEnd(this.contentFlow),this._ignoreUnprintableEnvironment(this.root)):console.error("Failed to initialize the root element.")}_insertContentFlowStartAndEnd(e){const t=this._node.create(this._selector.contentFlowStart),i=this._node.create(this._selector.contentFlowEnd);return this._DOM.insertAtStart(e,t),this._DOM.insertAtEnd(e,i),{contentFlowStart:t,contentFlowEnd:i}}_getInitialRoot(){let e=this._customInitialRootSelector?this._DOM.getElement(this._customInitialRootSelector):this._DOM.getElement(this._defaultInitialRootSelector);if(!e){if(!this._DOM.body)return void console.error("We expected to find the BODY tag.");e=this._DOM.body,console.warn(`The printable area is currently unspecified and encompasses the entire contents of the BODY tag. To restrict the printed content to a specific area, include ${this._defaultInitialRootSelector} in the root element of the desired printing area.`)}return this._initialRoot=e,e}_createRoot(){const e=this._node.create(this._selector.root);return this._DOM.setStyles(e,{visibility:"hidden"}),this.root=e,e}_createPaperFlow(){const e=this._node.create(this._selector.paperFlow);return this.paperFlow=e,e}_createContentFlow(){const e=this._node.create(this._selector.contentFlow);return this.contentFlow=e,e}_ignoreUnprintableEnvironment(e){if(e===this._DOM.body)return void this.strictAssert(!1,"misshapen root");let t=this._DOM.getParentNode(e);this._DOM.setAttribute(t,this._selector.printIgnore),this._DOM.getChildNodes(t).forEach((t=>{if(t!==e&&this._DOM.isElementNode(t))this._DOM.setAttribute(t,this._selector.printHide);else{if(!this._node.isSignificantTextNode(t))return;{const e=this._node.createTextNodeWrapper();this._DOM.wrap(t,e),this._DOM.setAttribute(e,this._selector.printHide)}}})),this._DOM.isDocumentBody(t)||this._ignoreUnprintableEnvironment(t)}}function A(e){return function(t){return t._config.debugMode&&t._debug[e]}}const I=A("selectors");function L(e,t){if(!e||!t)return void(I(this)&&console.warn("isSelectorMatching() must have 2 params","\n element: ",e,"\n selector: ",t));const i=t.charAt(0);if("."===i){const i=t.substring(1);return this._DOM.hasClass(e,i)}if("#"===i){const i=t.substring(1);return this._DOM.hasID(e,i)}if("["===i){this.strictAssert("]"===t.at(-1),`the ${t} selector is not OK.`);const i=t.substring(1,t.length-1);return this._DOM.hasAttribute(e,i)}return this._DOM.getElementTagName(e)===t.toUpperCase()}function $(e){return!!this._DOM.isTextNode(e)&&this._DOM.getNodeValue(e).trim().length>0}function G(e){return"STYLE"===this._DOM.getElementTagName(e)}function W(e){return"IMG"===this._DOM.getElementTagName(e)}function j(e){return"svg"===this._DOM.getElementTagName(e)}function z(e){return"OBJECT"===this._DOM.getElementTagName(e)}function V(e){return"LI"===this._DOM.getElementTagName(e)}function U(e){return this.isSelectorMatching(e,this._selector.neutral)}function q(e){return this.isSelectorMatching(e,this._selector.textNode)}function K(e){return this.isSelectorMatching(e,this._selector.textLine)}function Y(e){return this.isSelectorMatching(e,this._selector.textGroup)}function Z(e){return this.isSelectorMatching(e,this._selector.pageStartMarker)}function J(e){return this.isSelectorMatching(e,this._selector.contentFlowStart)}function X(e){const t=this._DOM.getLeftNeighbor(e);return this.isSelectorMatching(t,this._selector.contentFlowStart)}function Q(e){return this.isSelectorMatching(e,this._selector.contentFlowEnd)}function ee(e){return this.isSelectorMatching(e,this._selector.complexTextBlock)}function te(e){return this.isComplexTextBlock(e)||this.isWrappedTextNode(e)||this.isWrappedTextLine(e)||this.isWrappedTextGroup(e)}function ie(e,t){return this.isSelectorMatching(e,this._selector.flagNoBreak)||this.isWrappedTextLine(e)||this.isWrappedTextGroup(e)||this.isInlineBlock(e,t)||this.notSolved(e)}function ne(e){return this.isSelectorMatching(e,this._selector.flagNoHanging)}function oe(e){return this.isSelectorMatching(e,this._selector.flagSlice)}function re(e){return this.isSelectorMatching(e,this._selector.printForcedPageBreak)}function se(e,t){if(!(e instanceof HTMLElement))return;const i=(t||this._DOM.getComputedStyle(e)).display;return"inline"===i||"inline-block"===i||"inline-table"===i||"inline-flex"===i||"inline-grid"===i}function le(e,t){if(!(e instanceof HTMLElement))return;const i=(t||this._DOM.getComputedStyle(e)).display;return"inline-block"===i||"inline-table"===i||"inline-flex"===i||"inline-grid"===i}function ae(e,t){if(!(e instanceof HTMLElement))return;return"grid"===(t||this._DOM.getComputedStyle(e)).display}function he(e,t){if(!(e instanceof HTMLElement))return;const i=t||this._DOM.getComputedStyle(e);return"TABLE"!==this._DOM.getElementTagName(e)&&["table"].includes(i.display)}function ce(e,t){if(!(e instanceof HTMLElement))return;const i=t||this._DOM.getComputedStyle(e);return"TABLE"===this._DOM.getElementTagName(e)||["table"].includes(i.display)}function de(e,t){if(!(e instanceof HTMLElement))return;const i=t||this._DOM.getComputedStyle(e);return["block"].includes(i.display)&&["pre","pre-wrap","pre-line","break-spaces","nowrap"].includes(i.whiteSpace)}function ge(e,t){if(!(e instanceof HTMLElement))return;const i=t||this._DOM.getComputedStyle(e),n=i.display,o=i.gridAutoFlow;return("grid"===n||"inline-grid"===n)&&"row"===o}function ue(e,t){if(!(e instanceof HTMLElement))return;const i=t||this._DOM.getComputedStyle(e),n=i.display;if("flex"!==n&&"inline-flex"!==n)return!1;return(i.flexDirection||"").startsWith("row")}function pe(e,t){const i=t||this._DOM.getComputedStyle(e);return this.isPRE(e,i)||this.isTableNode(e,i)||this.isTableLikeNode(e,i)||this.isGridAutoFlowRow(e,i)}function _e(e){return this._DOM.hasAttribute(e,"slough-node")}function fe(e,t=""){const i=this._DOM.getElement("head"),n=this._DOM.body;if(!i&&!n)return void console.error("Check the structure of your document. We didn`t find HEAD and BODY tags. HTML2PDF4DOC expects valid HTML.");const o=this.create("style",e);o?(this._DOM.setAttribute(o,this._selector.style,t),i?this._DOM.insertAtEnd(i,o):n?this._DOM.insertBefore(n,o):this.strictAssert(!1,"We expected to find the HEAD and BODY tags.")):console.error("Failed to create print styles")}const me=A("positioning");function be(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let i=e;for(;this._DOM.getParentNode(i)&&i!==t;){if(this._DOM.getFirstElementChild(this._DOM.getParentNode(i))!==i)return!1;i=this._DOM.getParentNode(i)}return i===t}function we(e,t){if(!e||!this._DOM.getParentNode(e))return!1;let i=e;for(;this._DOM.getParentNode(i)&&i!==t;){if(this._DOM.getParentNode(i)===t){let e=this._DOM.getRightNeighbor(i);for(;!this._DOM.getElementOffsetHeight(e)&&!this._DOM.getElementOffsetWidth(e);)if(e=this._DOM.getRightNeighbor(e),this.isContentFlowEnd(e))return!0;return this.isContentFlowEnd(e)}if(this._DOM.getLastElementChild(this._DOM.getParentNode(i))!==i)return!1;i=this._DOM.getParentNode(i)}return i===t}function Se(e,t){return this._DOM.getElementOffsetTop(t)-this._DOM.getElementOffsetBottom(e)>-2}function Me(e,t){const i=this._DOM.getElementOffsetBottom(e),n=this._DOM.getElementOffsetTop(t),o=i-n,r=o>=2;return me(this)&&console.group("isLineKept?"),me(this)&&console.log("\n",r,"\n","\n currentBottom",i,[e],"\n nextTop",n,[t],"\n delta",o),me(this)&&console.groupEnd("isLineKept?"),r}function Pe(e,t,i){const n="[init-position]",o="[init-vertical-align]",r="relative",s=i||this._DOM.getComputedStyle(t),l=s.position,a=s.verticalAlign;if(e)l!=r&&(this._DOM.setStyles(t,{position:r}),this._DOM.setAttribute(t,n,l)),"top"!=a&&(this._DOM.setStyles(t,{"vertical-align":"top"}),this._DOM.setAttribute(t,o,a));else{const e=this._DOM.getAttribute(t,n),i=this._DOM.getAttribute(t,o);e&&(this._DOM.setStyles(t,{position:e}),this._DOM.removeAttribute(t,n)),i&&(this._DOM.setStyles(t,{"vertical-align":i}),this._DOM.removeAttribute(t,o))}}function Ce(e,{prefer:t="self"}={}){if(!e)return null;const i=e=>"last"===t?this._DOM.getLastElementChild(e):"first"===t||"self"===t?this._DOM.getFirstElementChild(e):null,n=new Set;let o=e;for(;o&&!n.has(o);){n.add(o);if(this._DOM.getElementOffsetParent(o))return o;const e=this._DOM.getComputedStyle(o);if(!e)return null;const t=e.display,r=e.visibility,s=e.position;if("none"===t||"collapse"===r||"fixed"===s)return null;if("contents"!==t)return null;{const e=i.call(this,o);if(!e)return null;o=e}}return null}const Oe=A("getters");function Te(e,t){return this.getTop(e,t)}function ye(e,t,i){const n=i||this._DOM.getComputedStyle(t),o=parseFloat(n.paddingTop)||0;return this.getTop(e,t)-o}function Ee(e,t,i){const n=i||this._DOM.getComputedStyle(t),o=parseFloat(n.paddingTop)||0;return this.getBottomWithMargin(e,t)-o}function De(e,t=null,i=0){if(!e)return void(Oe(this)&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0));if(null===t)return this._DOM.getElementOffsetTop(e);if(!t)return void(Oe(this)&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0));const n=this._DOM.getElementOffsetParent(e);if(!n)return void(Oe(this)&&console.warn("Element has no offset parent.","\n element:",[e],"\n offsetParent:",n,"\n The function returned:",void 0));const o=this._DOM.getElementOffsetTop(e);return n===t?o+i:this.getTop(n,t,i+o)}function ve(e,t=null){if(e){if(null===t)return this._DOM.getElementOffsetBottom(e);if(t)return this.getTop(e,t)+this._DOM.getElementOffsetHeight(e);Oe(this)&&console.warn("root must be provided, but was received:",t,"\nThe function returned:",void 0)}else Oe(this)&&console.warn("element must be provided, but was received:",e,"\nThe function returned:",void 0)}function Re(e,t){if(!e)return;const i=this.getBottom(e,t);let n;const o=this.createNeutralBlock();this._DOM.insertAfter(e,o);const r=this.getTop(o,t);this._DOM.removeNode(o);if(r>=i)n=r;else{n=i+parseInt(this._DOM.getComputedStyle(e).marginBottom)}return n}function ke(e){const t=parseInt(this._DOM.getComputedStyle(e).marginTop),i=parseInt(this._DOM.getComputedStyle(e).marginBottom);return this._DOM.getElementOffsetHeight(e)+t+i}function xe(e,t){const i=parseInt(this._DOM.getComputedStyle(e).marginTop);return this.getTop(e,t)-i}function Fe(e){const t=this.create();this._DOM.insertAtEnd(e,t);const i=this._DOM.getElementOffsetWidth(t);return this._DOM.removeNode(t),i}function Ne(e,t="",i=!0){const n=this.create();i&&this._DOM.setStyles(n,{overflow:"auto"});const o=this._DOM.cloneNodeWrapper(e);this._DOM.setInnerHTML(o,t),this._DOM.insertAtEnd(n,o),this._DOM.insertBefore(e,n);const r=this._DOM.getElementOffsetHeight(n);return this._DOM.removeNode(n),r}function Be(e){const t=this.createNeutral();this._DOM.setInnerHTML(t,"!"),this._DOM.setStyles(t,{display:"block"}),this._DOM.insertAtEnd(e,t);const i=this._DOM.getElementOffsetHeight(t);return this._DOM.removeNode(t),i}function He(e,t=0){const i=this._DOM.getElementOffsetTop(e),n=this._DOM.cloneNode(e),o="!
".repeat(t);[...n.children].forEach((e=>this._DOM.setInnerHTML(e,o))),this._DOM.insertBefore(e,n);const r=this._DOM.getElementOffsetTop(e);return this._DOM.removeNode(n),r-i}function Ae(e){const t=this._DOM.getElementOffsetTop(e),i=this._DOM.cloneNodeWrapper(e);this._DOM.insertBefore(e,i);const n=this._DOM.getElementOffsetTop(e);return this._DOM.removeNode(i),n-t}function Ie(e){const t=this._DOM.getElementOffsetTop(e),i=this._DOM.cloneNodeWrapper(e),n=e.children.length,o=[...e.children];this._DOM.insertBefore(e,i);const r=[];for(let s=0;sthis._DOM.removeNode(e)))}return this._DOM.removeNode(i),r}function Le(e){if(!(e instanceof HTMLElement)||"TABLE"!==e.tagName)throw new Error("Expected a element.");const t=[...e.children].reduce(((e,t)=>{const i=t.tagName;return"TBODY"===i?{...e,rows:[...e.rows,...t.children]}:"CAPTION"===i?(this.setFlagNoBreak(t),{...e,caption:t}):"COLGROUP"===i?(this.setFlagNoBreak(t),{...e,colgroup:t}):"THEAD"===i?(this.setFlagNoBreak(t),{...e,thead:t}):"TFOOT"===i?(this.setFlagNoBreak(t),{...e,tfoot:t}):"TR"===i?{...e,rows:[...e.rows,...t]}:(Oe(this)&&t&&console.warn("unexpected:",t),{...e,unexpected:[...e.unexpected,...t]})}),{caption:null,thead:null,tfoot:null,rows:[],unexpected:[]});return t.unexpected.length>0&&Oe(this)&&console.warn(`something unexpected is found in the table ${e}`),t}function $e(e,t){const i=t||this._DOM.getComputedStyle(e),n=this.createNeutralBlock();this._DOM.setStyles(n,{display:"block",padding:"0",margin:"0",border:"0",height:"0",clear:"both",visibility:"hidden",contain:"layout"}),this._DOM.insertAtEnd(e,n);const o=this.getNormalizedTop(n,e,i);return this._DOM.removeNode(n),o}A("creators");function Ge(e,t){let i;if(e){const t=e.charAt(0);if(t.match(/[#\[\.]/))i=this._DOM.createElement("div"),this._DOM.setAttribute(i,e);else{if(!t.match(/[a-zA-Z]/))return void this.strictAssert(!1,"Expected valid html selector ot tag name, but received:",e);i=this._DOM.createElement(e)}}else i=this._DOM.createElement("div");return t&&this._DOM.setInnerHTML(i,t),i}function We(){return this.create(this._selector.neutral)}function je(){const e=this.createNeutral();return e.style.display="block",e.style.clear="both",e}function ze(){return this.create(this._selector.textNode)}function Ve(){return this.create(this._selector.textLine)}function Ue(){return this.create(this._selector.textGroup)}function qe(e){const t=this.create(this._selector.flagNoBreak);return e&&this._DOM.setStyles(t,e),t}function Ke(){return this.create(this._selector.printPageBreak)}function Ye(){return this.create(this._selector.complexTextBlock)}function Ze(e){const t=this._DOM.cloneNodeWrapper(e);return this._DOM.setAttribute(t,".test-node"),this._DOM.setStyles(t,{position:"absolute",background:"rgb(255 239 177)",width:this.getMaxWidth(e)+"px"}),t}function Je(e,t){const i=this.create(this._selector.word);return this._DOM.setInnerHTML(i,e),i.dataset.index=t,i}function Xe(){return this.create(this._selector.printForcedPageBreak)}function Qe(e,t){if(!t)return null;const i=this.create();return this._DOM.setStyles(i,{display:"flex",flexWrap:"nowrap",alignItems:"center",justifyContent:"center",textAlign:"center",fontSize:"8px",fontFamily:"sans-serif",letterSpacing:"1px",textTransform:"uppercase",height:t+"px"}),e&&this._DOM.setInnerHTML(i,e),i}function et({wrapper:e,caption:t,colgroup:i,thead:n,tfoot:o,tbody:r}){const s=e||this.create("table"),l=this.create("TBODY");return t&&this._DOM.insertAtEnd(s,t),i&&this._DOM.insertAtEnd(s,i),n&&this._DOM.insertAtEnd(s,n),r&&this._DOM.insertAtEnd(l,...r),this._DOM.insertAtEnd(s,l),o&&this._DOM.insertAtEnd(s,o),s}A("splitters");function tt(e){return e.split(/(?<=\n)/)}function it(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).split(/(?<=\s|-)/)}function nt(e){return(this._DOM.getNodeValue(e)||this._DOM.getInnerHTML(e)).trim().split(/(?<=\s|-)/).filter((e=>" "!=e))}function ot(e){const t=e,i=this.splitTextByWordsGreedy(e),n=i.map((e=>{const t=this._DOM.createElement("span");return this._DOM.setInnerHTML(t,e+" "),t})),o=this.createTestNodeFrom(e);return this._DOM.insertAtEnd(o,...n),this._DOM.insertAtEnd(e,o),{splittedNode:t,nodeWords:i,nodeWordItems:n}}const rt=A("markers");function st(e,t){this._markupDebugMode&&this._DOM.setAttribute(e,this._selector.processed,"🏷️ "+t)}function lt(e){this._DOM.setAttribute(e,this._selector.flagNoBreak)}function at(e,t){this._DOM.setAttribute(e,this._selector.flagNoHanging,t)}function ht(e){this._DOM.setAttribute(e,this._selector.flagSlice)}function ct(e,t){this._DOM.setAttribute(e,this._selector.pageStartMarker,t)}function dt(e){this._DOM.removeAttribute(e,this._selector.pageStartMarker)}function gt(e,t){this._DOM.setAttribute(e,this._selector.pageEndMarker,t)}function ut(e){rt(this)&&console.log("[mark ⊤ cut]",e),e&&this._DOM.setAttribute(e,this._selector.cleanTopCut)}function pt(e){rt(this)&&console.log("[mark ⊥ cut]",e),e&&this._DOM.setAttribute(e,this._selector.cleanBottomCut)}function _t(e){rt(this)&&console.log("[mark ⊤ cut]",e),e&&this._DOM.setAttribute(e,this._selector.topCutPart)}function ft(e){rt(this)&&console.log("[mark ⊥ cut]",e),e&&this._DOM.setAttribute(e,this._selector.bottomCutPart)}function mt(e){if(e&&e.length)if(1!==e.length)for(let t=0;t0,n=t0,o=t","color:blue",i),r=i,s=[...this._DOM.getChildren(i)]):Array.isArray(i)?(rt(this)&&console.log("%c[markSliceCutsInRows] It is an Array","color:blue",i),r=void 0,s=i):this.strictAssert(0,"we expected TR or an array of elements!"),!r&&!s.length){rt(this)&&console.log("%c[markSliceCutsInRows] There was no split","color:red",{rowWrapper:r,cellWrappers:s});break}n&&(r&&console.log("[markSliceCutsInRows] rowWrapper ⊥",r),r&&this.markTopCut(r),s.forEach((e=>{rt(this)&&console.log("[markSliceCutsInRows] cell 🖍️ ⊥",e),this.markTopCut(e)}))),o&&(r&&console.log("[markSliceCutsInRows] rowWrapper ⊤",r),r&&this.markBottomCut(r),s.forEach((e=>{rt(this)&&console.log("[markSliceCutsInRows] cell 🖍️ ⊤",e),this.markBottomCut(e)})))}else rt(this)&&console.log("%c[markSliceCutsInRows] The rows were not passed. Doing nothing.","color:red")}A("wrappers");function wt(e){const t=this._DOM.getChildren(e),i=this.createNeutralBlock();return this._DOM.insertAtStart(i,...t),this._DOM.insertAtStart(e,i),i}const St=A("fitters");function Mt({element:e,height:t,width:i,vspace:n,hspace:o}){const r=n/t,s=o/i,l=ra&&(g||(g=this.wrapNodeChildrenWithNeutralBlock(s),d=this._DOM.getElementOffsetHeight(g)||d),this.fitElementWithinHeight(g,a),o=!0,St(this)&&console.warn("💢 scaleCellsToHeight: resized cell content",{cell:s,target:a}))}return o}function Ot(e,t){this._DOM.setStyles(e,{"box-sizing":"border-box",width:`${this._DOM.getElementOffsetWidth(t)}px`,"min-width":`${this._DOM.getElementOffsetWidth(t)}px`})}function Tt(e){this.copyNodeWidth(e,e),this._DOM.getAll("td",e).forEach((e=>this.copyNodeWidth(e,e)))}function yt(e){Array.isArray(e)&&e.forEach((e=>{e&&this.copyNodeWidth(e,e)}))}function Et(e,t={}){const{descentRatio:i=.22,normalLH:n=1.2,safety:o=1}=t,r=getComputedStyle(e),s=parseFloat(r.fontSize)||0;let l;if("normal"!==r.lineHeight&&r.lineHeight){const e=parseFloat(r.lineHeight);l=Number.isFinite(e)?e:n*s}else l=n*s;const a=(Math.max(0,(l-s)/2)+i*s)*o;return Math.ceil(a)}const Dt=A("pageBreaks");function vt(e,t){let i=e;for(;;){const e=this.findFirstChildParent(i,t);if(e&&e!==i){i=e;continue}const n=$t.call(this,i,"findBetterForcedPageStarter:left");if(!n||!this.isNoHanging(n))break;i=n}return i}function Rt(e,t,i){Dt(this)&&console.group("➗ findBetterPageStart");let n=!1,o=!1,r=!1;const s=this.getTop(t,i);Dt(this)&&console.log("Start calculations:",{pageStart:e,lastPageStart:t,root:i,topLimit:s});const l=this.findFirstChildParentFromPage(e,s,i);let a;if(l)a=l;else{a=this.getTop(e,i)t?n:null}function Ht(e){return this._DOM.getAll(this._selector.printForcedPageBreak,e)}function At(e,t){let i=this._DOM.getParentNode(e);for(;i&&this.shouldSkipFlowElement(i,{context:t});)i=this._DOM.getParentNode(i);return i}function It(e,t){let i=this._DOM.getFirstElementChild(e);for(;i&&this.shouldSkipFlowElement(i,{context:t});)i=this._DOM.getRightNeighbor(i);return i}function Lt(e,t){let i=this._DOM.getLastElementChild(e);for(;i&&this.shouldSkipFlowElement(i,{context:t});)i=this._DOM.getLeftNeighbor(i);return i}function $t(e,t){let i=this._DOM.getLeftNeighbor(e);for(;i&&this.shouldSkipFlowElement(i,{context:t});)i=this._DOM.getLeftNeighbor(i);return i}const Gt=A("children");function Wt(e){Gt(this)&&console.groupCollapsed("getPreparedChildren of",e);let t=[];if(this.isComplexTextBlock(e))t=[...this._DOM.getChildren(e)],Gt(this)&&console.info("🚸 getPreparedChildren: return children for complexTextBlock",t);else{if(!Yt.call(this,e))return Gt(this)&&console.info("🪲 getPreparedChildren: empty node, skip & return []",e),[];t=[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this.isSTYLE(t))return Gt(this)&&console.info("🚸 (getPreparedChildren) ignore STYLE",[t]),e;if(this.isSignificantTextNode(t)){const i=this.createTextNodeWrapper();return this._DOM.wrap(t,i),e.push(i),Gt(this)&&console.info("🚸 (getPreparedChildren) wrap and return TEXT NODE",[t]),e}if(this._DOM.isElementNode(t)){if(this.shouldSkipFlowElement(t,{context:"getPreparedChildren"}))return e;if(!this._DOM.getElementOffsetParent(t)){const i=this.getPreparedChildren(t);return i.length>0&&e.push(...i),Gt(this)&&console.info("%c🚸 (getPreparedChildren) * no offset parent — unwrapped","color:green",i,[t]),e}return e.push(t),Gt(this)&&console.info("🚸 (getPreparedChildren) * normal node",[t]),e}return Gt(this)&&console.info("%c🚸 (getPreparedChildren) IGNORE whitespace / comment ...","color:red",[t]),e}),[]),Kt.call(this,t)&&(Gt(this)&&console.info("🚸 (getPreparedChildren) isVerticalFlowDisrupted in children of",[e]),t=Ut.call(this,t))}return Gt(this)&&console.groupEnd("getPreparedChildren"),Gt(this)&&console.info("🚸 getPreparedChildren:",t),t}function jt(e,t,i,n){let o=[];if(this.isNoBreak(e))return Gt(this)&&console.info("🧡 isNoBreak",e),[];if(this.isComplexTextBlock(e))return Gt(this)&&console.info("💚 ComplexTextBlock",e),this._paragraph.split(e)||[];if(this.isWrappedTextNode(e))return Gt(this)&&console.info("💚 TextNode",e),this._paragraph.split(e)||[];if(!Yt.call(this,e))return Gt(this)&&console.info("🪲 getSplitChildren: empty node, return []",e),[];const r=this._DOM.getComputedStyle(e);if(this.isTableLikeNode(e,r))Gt(this)&&console.info("💚 TABLE like",e),o=this._tableLike.split(e,t,i,n,r)||[];else if(this.isTableNode(e,r))Gt(this)&&console.info("💚 TABLE",e),o=this._table.split(e,t,i,n)||[];else if(this.isPRE(e,r))Gt(this)&&console.info("💚 PRE",e),o=this._pre.split(e,t,i,n,r)||[];else if(this.isFlexRow(e,r)){Gt(this)&&console.info("🩷 Flex ROW",e);let t=this.getPreparedChildren(e);o=qt.call(this,t)}else this.isGridAutoFlowRow(e,r)?(Gt(this)&&console.info("💜 GRID"),o=this._grid.split(e,t,i,n)||[]):(Gt(this)&&console.info("💚 found some node - use main this.getPreparedChildren() for:",e),o=this.getPreparedChildren(e));return o}function zt(e){const t=[];if(!e||!this||!this._DOM)return t;let i=e;for(;i;){let e=this._DOM.getFirstElementChild(i);for(;e&&this.shouldSkipFlowElement(e,{context:"getFirstChildren:firstChild"});)e=this._DOM.getRightNeighbor(e);if(!e)break;if(this.isSyntheticTextWrapper(e))break;t.push(e),i=e}return t}function Vt(e){const t=[];if(!e||!this||!this._DOM)return t;let i=e;for(;i;){let e=this._DOM.getLastElementChild(i);for(;e&&this.shouldSkipFlowElement(e,{context:"getLastChildren:lastChild"});)e=this._DOM.getLeftNeighbor(e);if(!e)break;if(this.isSyntheticTextWrapper(e))break;t.push(e),i=e}return t}function Ut(e){let t=null;const i=[];return e.forEach((e=>{this.isInline(e)?(t||(t=this.createComplexTextBlock(),this._DOM.wrap(e,t),i.push(t)),this._DOM.insertAtEnd(t,e)):(t=null,i.push(e))})),i}function qt(e){const t=e.filter((e=>this._DOM.getElementOffsetHeight(e)>0));return t.length>0?t:e}function Kt(e){return e.some(((e,t,i)=>{const n=e,o=i[t+1];if(!o)return!1;return this._DOM.getElementOffsetBottom(n)>this._DOM.getElementOffsetTop(o)}))}function Yt(e){let t=e.firstChild;for(;t;){if(this._DOM.isElementNode(t)){if(!this.shouldSkipFlowElement(t,{context:"hasRenderableChild"}))return!0}else if(this.isSignificantTextNode(t))return!0;t=t.nextSibling}return!1}const Zt=A("media"),Jt=new Set(["IMG","SVG","OBJECT","EMBED","IFRAME","VIDEO","AUDIO","CANVAS"]);function Xt(e,t="self"){return"last"===t?this._DOM.getLastElementChild(e):this._DOM.getFirstElementChild(e)}function Qt(e){if(!e)return!1;const t=this._DOM.getElementTagName(e);if(!t)return!1;if("INPUT"===t){return"image"===(this._DOM.getAttribute(e,"type")||"").toLowerCase()}return Jt.has(t)}function ei(e,{prefer:t="self"}={}){if(!e)return null;const i=new Set;let n=e;for(;n&&!i.has(n);){if(i.add(n),this.isReplacedElement(n))return n;if("function"==typeof this.resolveFlowElement){const e=this.resolveFlowElement(n,{prefer:t});if(e&&e!==n){if(this.isReplacedElement(e))return e;n=e;continue}}const e=[...this._DOM.getChildren(n)].filter((e=>{const t=this._DOM.getComputedStyle(e)?.display;return"none"!==t}));if(1!==e.length)return Zt(this)&&console.info("🧭 resolveReplacedElement: branching or empty wrapper",n,e),null;n=Xt.call(this,n,t)||e[0]}return null}const ti=A("slicers");function ii({rootNode:e,rootComputedStyle:t,children:i,firstPartHeight:n,fullPageHeight:o,firstChild:r,points:s=[]}){if(!i.length)return ti(this)&&console.log("🧶 [getSplitPoints] %c has no children, early returns []","font-weight:bold",{rootNode:e}),[];const l=t=>{const i=this.findBetterPageStart(t,s.at(-1),e,e);return s.length||i!==r?(ti(this)&&console.log("%c 🧼🧼🧼🧼 push(point) in registerPoint()","color:violet",{point:i,points:s,firstChild:r},s.length),s.push(i),!1):(ti(this)&&console.log("%c !points.length && point === children[0] && children[1]","color:red"),ti(this)&&console.log("%c 🅾️ push(null) in registerPoint()","color:red"),s.push(null),!0)};ti(this)&&console.group("🧶 getSplitPoints"),ti(this)&&console.log("points.length",s.length);const a=t||this._DOM.getComputedStyle(e),h=new WeakMap,c=e=>{let t=h.get(e);return t||(t=Object.create(null),h.set(e,t)),t},d=t=>{if(!t)return NaN;const i=c(t);return"top"in i||(i.top=this.getNormalizedTop(t,e,a)),i.top},g=t=>{if(!t)return NaN;const i=c(t);return"bottomWithMargin"in i||(i.bottomWithMargin=this.getNormalizedBottomWithMargin(t,e,a)),i.bottomWithMargin},u=e=>{if(!e)return 0;const t=c(e);return"offsetHeight"in t||(t.offsetHeight=this._DOM.getElementOffsetHeight(e)),t.offsetHeight};this.setInitStyle(!0,e,a);let p=!1;const _=()=>(p||(p=!0,ti(this)&&console.groupEnd(`walking through ${i.length} children`),this.setInitStyle(!1,e,t),ti(this)&&console.groupEnd("getSplitPoints")),s);ti(this)&&console.group(`walking through ${i.length} children`,i);for(let t=0;th))if(ti(this)&&console.log("[getSplitPoints]",`next overtook the floater : (nextElementTop) ${b} > ${h}`,{currentElement:p},"does current overflow? let's check.",{isNextElementTopFinite:w}),(this.isSVG(p)||this.isIMG(p))&&ti(this)&&console.log("%cIMAGE","color:red;text-weight:bold"),S=g(p),S<=h){if(w){ti(this)&&console.log("[getSplitPoints]",`current fits: (currentElementBottom) ${S} <= ${h}, 🍎 register nextElement as Point.`,{currentElement:p,nextElement:m});if(l(m))return ti(this)&&console.log("%cNULL CASE, return","color:red;text-weight:bold"),_();continue}ti(this)&&console.log("[getSplitPoints] nextElementTop not finite and current fits tail window",{currentElementBottom:S,floater:h,nextElement:m})}else ti(this)&&console.log(`🔪🥒 try to split overflowing current: (currentElementBottom > ) ${S} > ${h}`,{currentElement:p}),M=!0;if(!m){ti(this)&&console.log("%c[getSplitPoints] !nextElement","color:red"),ti(this)&&console.log("%c[getSplitPoints] * Try to split it. 🔪🥒","color:blue"),S=S??g(p);let t=p;if(p.parentElement&&e.contains(p.parentElement)){let i=p.parentElement;for(;i&&e.contains(i)&&i!==e&&!this._DOM.getRightNeighbor(i);)t=i,i=i.parentElement}const i=t===p?S:g(t);if(i<=h){ti(this)&&console.log("%c 🍕 [getSplitPoints] !nextElement branch fits with container shell","color:violet",{currentElementBottom:S,containerBottom:i,floater:h,containerElement:t});continue}M=!0}if(!M)continue;let P=[];const C=this.getSplitChildren(p,n,o,e);if(C.length){if(P=ii.call(this,{rootNode:e,rootComputedStyle:a,children:C,firstPartHeight:n,fullPageHeight:o,firstChild:r,points:s}),0===P.length){const e=Math.max(n,o),t=u(p),i=t>e&&(!P.length||1===P.length&&null===P[0]);if(ti(this)&&console.log("room (Math.max)",e),i){if(ti(this)&&console.warn("%c⚠️ UNSPLITTABLE OVERSIZED ELEMENT — SCALE IT","color:white; background:red; font-weight:bold;",p,`height: ${t}`),!s.length&&p===r)return ti(this)&&console.warn("🅾️ (1) points.push(null) in isUnbreakableOversized"),s.push(null),_();if(m){if(l(m))return _()}}else if(l(p))return _()}}else{ti(this)&&console.log("🍎 currentElementChildren.length == 0");const e=u(p);if(e>c&&(!P.length||1===P.length&&null===P[0])){if(ti(this)&&console.warn("%c⚠️ UNSPLITTABLE OVERSIZED ELEMENT — SCALE IT","color:white; background:red; font-weight:bold;",p,`height: ${e}`),ti(this)&&console.warn("🅾️ (2) points.push(null) in isUnbreakableOversized"),!s.length&&p===r)return s.push(null),_();if(m){ti(this)&&console.warn("🅾️🅾️🅾️🅾️🅾️🅾️🅾️🅾️ registerPoint(nextElement)");if(l(m))return _()}}else{if(l(p))return _()}}}return _()}function ni(e,t,i,n,o){ti(this)&&console.group("[✖️] getSplitPointsPerCells");const r=e.map(((e,r)=>{ti(this)&&console.group(`(•) Split CELL.${r} in:`,o);let s=[];const l=i-(t[r]||0),a=n-(t[r]||0);let h=this.getSplitChildren(e,l,a,o);if(h.length){const t=h[0];ti(this)&&console.log("firstChild",t),s=this.getSplitPoints({rootNode:e,children:h,firstPartHeight:l,fullPageHeight:a,firstChild:t})}else ti(this)&&console.log(`(•) empty cell #${r}`);return ti(this)&&console.log(`(•) return splitPoints for CELL#${r}`,s),ti(this)&&console.groupEnd(),s})),s=r.some(li);ti(this)&&console.log("🧽🧽🧽🧽🧽🧽🧽 isFirstPartEmptyInAnyCell",s);let l=r,a=!1;if(s){l=e.map(((e,r)=>{ti(this)&&console.group(`(••) Split CELL.${r} in:`,o);const s=i-(t[r]||0),l=n-(t[r]||0),a=this.getSplitChildren(e,s,l,o),h=a[0];ti(this)&&console.log("firstChild",h);let c=[];return a.length&&(c=this.getSplitPoints({rootNode:e,children:a,firstPartHeight:l,fullPageHeight:l,firstChild:h})),ti(this)&&console.log(`(••) return splitPoints for CELL#${r}`,c),ti(this)&&console.groupEnd(),c})),ti(this)&&console.log("[••] splitPointsPerCell",l);for(let e=0;e0&&this.strictAssert(i.every((e=>null!==e)),"sliceNodeBySplitPoints: splitPoints contains null — sanitize upstream before slicing"),this.strictAssert(i.every((e=>!e||e.nodeType===Node.ELEMENT_NODE&&(t===e||t.contains(e)))),"sliceNodeBySplitPoints: split point is not an Element within rootNode");for(let e=0;e<=i.length;e++){const o=i[e-1]??null,r=i[e]??null,s=this.cloneAndCleanOutsideRange(t,o,r);this.normalizeContentCuts({slice:s,top:null!==o,bottom:null!==r}),this._DOM.getChildNodes(s).length>0&&n.push(s)}return ti(this)&&console.log(n),ti(this)&&console.groupEnd(`🔪 (${e}) sliceNodeBySplitPoints`),n}function ri({slice:e,top:t=!1,bottom:i=!1}){if(e){if(t){const t=[...this.getFirstChildrenChain(e)];t.forEach((e=>this.markCleanTopCut(e))),ti(this)&&console.log("[normalizeContentCuts] topChain 👗",t)}if(i){const t=[...this.getLastChildrenChain(e)];t.forEach((e=>this.markCleanBottomCut(e))),ti(this)&&console.log("[normalizeContentCuts] bottomChain 👗",t)}}else ti(this)&&console.log("[normalizeContentCuts] no slice has been passed; return")}function si({index:e,rootNode:t,splitPoints:i}){ti(this)&&console.group(`🔪 (${e}) sliceNodeContentBySplitPoints`);const n=[];for(let e=0;e<=i.length;e++){const o=i[e-1]??null,r=i[e]??null,s=this.cloneAndCleanOutsideRange(t,o,r);ti(this)&&console.log({slice:s});const l=this.createNeutralBlock();for(;s.firstChild;)l.appendChild(s.firstChild);l.childNodes.length>0&&n.push(l)}return ti(this)&&console.log(n),ti(this)&&console.groupEnd(`🔪 (${e}) sliceNodeContentBySplitPoints`),n}function li(e){return!!Array.isArray(e)&&(e.length>0&&null===e[0])}function ai(e,t,i){t&&t.setAttribute("split","start"),i&&i.setAttribute("split","end");let n=e.cloneNode(!0);if(t){let t=n.querySelector('[split="start"]'),i=t.previousElementSibling;for(;i;){let e=i;i=i.previousElementSibling,e.remove()}let o=t.parentElement;for(;o&&o!==e;){let e=o.previousElementSibling;for(;e;){let t=e;e=e.previousElementSibling,t.remove()}o=o.parentElement}t.removeAttribute("split")}if(i){let t=n.querySelector('[split="end"]'),i=t.nextElementSibling;for(;i;){let e=i;i=i.nextElementSibling,e.remove()}let o=t.parentElement;for(;o&&o!==e;){let e=o.nextElementSibling;for(;e;){let t=e;e=e.nextElementSibling,t.remove()}o=o.parentElement}t.remove()}return t&&t.removeAttribute("split"),i&&i.removeAttribute("split"),n}const hi=A("flowfilters"),ci="__html2pdfFlowFilter",di=[{test:e=>"none"===e.display,cache:{reason:"display:none",message:"* display:none — skipped"}},{test:e=>"absolute"===e.position,cache:{reason:"position:absolute",message:"* position:absolute — skipped"}},{test:e=>"fixed"===e.position,cache:{reason:"position:fixed",message:"* position:fixed — skipped"}},{test:e=>"collapse"===e.visibility,cache:{reason:"visibility:collapse",message:"* visibility:collapse — skipped"}}];function gi(e,t,i,n,{cached:o}={cached:!1}){if(!hi(e))return;const r=t?`(${t}) `:"",s=o?" (cached)":"";console.info(`🚸 ${r}${i.message}${s}`,[n])}function ui(e,{context:t="",computedStyle:i}={}){if(!(e&&this&&this._DOM&&this._DOM.isElementNode(e)))return!1;const n=e[ci];if(n)return gi(this,t,n,e,{cached:!0}),!0;const o=i??this._DOM.getComputedStyle(e);if(!o)return!1;for(const i of di)if(i.test(o))return e[ci]=i.cache,gi(this,t,i.cache,e),!0;return!1}A("pagination");function pi({cells:e,splitPointsPerCell:t,sliceCell:i}){return t.map(((t,n)=>{const o=e[n];return i({cell:o,index:n,splitPoints:t})}))}function _i({originalRow:e,originalCells:t,slicedCellsPerOriginal:i,beginRow:n,cloneCellFallback:o,handleCell:r,finalizeRow:s}){const l=Math.max(...i.map((e=>e.length))),a=[];for(let h=0;h{const n=i[t][h]||o(e);r({context:l,cellClone:n,originalCell:e,cellIndex:t})})),a.push(s({context:l}))}return a}function fi({originalRow:e,originalCells:t,splitPointsPerCell:i,sliceCell:n,beginRow:o,cloneCellFallback:r,handleCell:s,finalizeRow:l}){if(!Array.isArray(i)||!i.length)return[];const a=this.sliceCellsBySplitPoints({cells:t,splitPointsPerCell:i,sliceCell:n});return this.buildRowSlices({originalRow:e,originalCells:t,slicedCellsPerOriginal:a,beginRow:o,cloneCellFallback:r,handleCell:s,finalizeRow:l})}function mi({usedRemainingWindow:e,isFirstPartEmpty:t,firstSliceTop:i,firstSliceBottom:n,pageBottom:o,epsilon:r=.5}){return{placeOnCurrentPage:e&&!t,remainingWindowSpace:Math.max(0,o-i),exceedsWindow:n>o+r}}function bi({currentRows:e,index:t,rowSlices:i}){return Array.isArray(e)?(e.splice(t,1,...i),e):[]}const wi=A("pagination");function Si({cells:e,targetHeight:t,shells:i}){return!!(Array.isArray(e)&&e.length&&t>0)&&this.scaleCellsToHeight(e,t,i)}function Mi({needsScalingInFullPage:e,cells:t}){return Boolean(e&&Array.isArray(t)&&t.length)}function Pi({needsScalingInFullPage:e,scaleCallback:t,payload:i}){if(!e)return!1;if("function"!=typeof t)return!1;const n=t(i||{});return!n&&this&&this._debug&&this._debug._&&wi(this)&&console.warn("[pagination.scaling] requested full-page scaling but callback reported no change",i),Boolean(n)}A("pagination");function Ci(e,t,i){e&&Array.isArray(e.rows)&&e.rows.splice(t,1,...i)}function Oi({rows:e,DOM:t,cellTagFilter:i,guardCallback:n}){if(!Array.isArray(e))return{};let o=!1,r=!1,s=!1,l=null;e.forEach((e=>{const n=Array.isArray(e)?e:Array.from(t.getChildren(e)||[]);null==l&&(l=n.length),n.length!==l&&(s=!0),n.forEach((e=>{const n=t.getElementTagName(e);if(!i||i(n,e)){const t=parseInt(e.getAttribute?.("rowspan"));Number.isFinite(t)&&t>1&&(o=!0);const i=parseInt(e.getAttribute?.("colspan"));Number.isFinite(i)&&i>1&&(r=!0)}}))}));const a={hasRowspan:o,hasColspan:r,inconsistentCells:s};return n?.(a),a}A("pagination");function Ti(e){if(!e||"object"!=typeof e)throw new Error("splitter kernel adapter must be an object.");if(!e.rows||"object"!=typeof e.rows)throw new Error("splitter kernel adapter must expose a rows provider.");if("function"!=typeof e.rows.replaceRow)throw new Error("splitter kernel adapter rows.replaceRow must be a function.")}function yi(e,{rowIndex:t,rowSlices:i}){Ti(e);const n=Number.isFinite(t)?t:0,o=Array.isArray(i)?i:[],r=e.rows;r.replaceRow({rowIndex:n,rowSlices:o}),r.syncEntries?.({rowIndex:n,rowSlices:o});const s=e.guards?.getConfig?.({rowIndex:n,rowSlices:o})??r.getGuardConfig?.({rowIndex:n,rowSlices:o})??null;let l=null;if(s){const t={rows:s.rows,DOM:s.DOM||this._DOM,cellTagFilter:s.cellTagFilter,guardCallback:s.guardCallback};Array.isArray(t.rows)&&t.DOM&&(l=this.computeRowFlags(t),e.guards?.onFlags?.({flags:l,rowIndex:n,rowSlices:o}))}return e.metrics?.refresh?.({rowIndex:n,rowSlices:o,flags:l}),r.onRowsChanged?.({rowIndex:n,rowSlices:o,flags:l}),{flags:l}}A("pagination");function Ei({cells:e}){return Array.isArray(e)&&e.length?e.map((e=>{if(!e)return 0;const t=this._DOM.getComputedStyle(e),i=(parseFloat(t?.paddingTop)||0)+(parseFloat(t?.paddingBottom)||0)+(parseFloat(t?.borderTopWidth)||0)+(parseFloat(t?.borderBottomWidth)||0);return Number.isFinite(i)?Math.max(0,i):0})):[]}const Di=A("pagination");function vi({ownerLabel:e,DOM:t,row:i,targetHeight:n,cachedShells:o,getRowShellHeightsCallback:r,scaleCellsToHeightCallback:s}){if(e||Di(this)&&console.warn("[scaleRowCellsToHeight] 👤 Owner wanted!",{owner:e}),!i)return Di(this)&&console.warn("[pagination.overflow] Missing row for scaling.",{owner:e}),!1;if("function"!=typeof s)return Di(this)&&console.warn("[pagination.overflow] scaleCellsToHeight callback is required.",{owner:e}),!1;const l=t,a=l&&"function"==typeof l.getChildren?l.getChildren(i):null;return s(a?[...a]:[],n,Array.isArray(o)?o:"function"==typeof r?r(i):[])}function Ri({ownerLabel:e,rowIndex:t,row:i,availableRowHeight:n,fullPageHeight:o,splitStartRowIndexes:r,reasonTail:s,reasonFull:l,registerPageStartCallback:a,scaleProblematicCellsCallback:h,debugLogger:c}){return e||Di(this)&&console.warn("[handleRowOverflow] 👤 Owner wanted!",{owner:e}),Array.isArray(r)?"function"!=typeof a?(Di(this)&&console.warn("[pagination.overflow] registerPageStart callback is required.",{owner:e}),t):n!1),isSlice:o=(()=>!1)}=t,{handleRowWithRowspan:r=(()=>e.rowIndex),handleSplittableRow:s=(()=>e.rowIndex),handleAlreadySlicedRow:l=(()=>e.rowIndex)}=i,{row:a}=e;return n(a,e)?r({evaluation:e}):o(a,e)?l({evaluation:e}):s({evaluation:e})}function Li({evaluation:e,splitStartRowIndexes:t,fullPageHeight:i,resolveOverflow:n,debug:o,afterResolve:r}){const{rowIndex:s,tailWindowHeight:l}=e;Ai(this)&&console.log("%c ⚠️ Row has ROWSPAN; use conservative fallback (no slicing)","color:DarkOrange; font-weight:bold");const a=n({rowIndex:s,evaluation:e,availableRowHeight:l,splitStartRowIndexes:t,fullPageHeight:i});return r?.({evaluation:e,tailWindowHeight:l,fullPageHeight:i,result:a}),a}function $i({evaluation:e,splitStartRowIndexes:t,resolveSplitFailure:i,fullPageHeight:n,debug:o}){const{rowIndex:r,row:s,tailWindowHeight:l,delta:a}=e;return Ai(this)&&console.log(`%c Row # ${r} is slice! but don't fit`,"color:DarkOrange; font-weight:bold",s),Ai(this)&&console.warn("%c SUPER BIG","background:red;color:white",a,{part:n}),i({evaluation:e,splitStartRowIndexes:t,availableRowHeight:l,fullPageHeight:n})}function Gi({tailWindowHeight:e,minMeaningfulRowSpace:t,fullPartHeight:i,debug:n}){return ethis.sliceNodeBySplitPoints({index:t,rootNode:e,splitPoints:i})),f=l.beginRow||(({originalRow:t,sliceIndex:i})=>{const n=this._DOM.cloneNodeWrapper(t);return r?.({rowWrapper:n,rowIndex:e,sliceIndex:i,originalRow:t}),{rowWrapper:n}}),m=l.cloneCellFallback||(e=>this._DOM.cloneNodeWrapper(e)),b=l.handleCell||(({context:e,cellClone:t})=>{this._DOM.insertAtEnd(e.rowWrapper,t)}),w=l.finalizeRow||(({context:e})=>e.rowWrapper),S=[];if(g.some((e=>Array.isArray(e)&&e.length))){const e=this.paginationBuildBalancedRowSlices({originalRow:t,originalCells:h,splitPointsPerCell:g,sliceCell:_,beginRow:f,cloneCellFallback:m,handleCell:b,finalizeRow:w});S.push(...e)}else Ai(this)&&console.log("🔴 There is no Split");return S.length&&this.markSliceCutsInRows(S),o&&o._&&console.log("%c newRows \n","color:magenta; font-weight:bold",S),{newRows:S,isFirstPartEmptyInAnyTD:u,needsScalingInFullPage:p}}function ji({row:e,rowIndex:t,decorateRowSlice:i}){const n=Array.isArray(e),o=this;return{getParentContainer:()=>n?null:e,getOriginalCells:()=>n?[...e]:[...o._DOM.getChildren(e)],getShellHeights:({cells:t})=>n?[]:o.getTableRowShellHeightByTD(e),markOriginalRow:({cells:t})=>{n||o.setFlagSlice(e)},beginRow:({originalRow:e,sliceIndex:r})=>{if(n)return{cells:[]};const s=o._DOM.cloneNodeWrapper(e);return i?.({rowWrapper:s,rowIndex:t,sliceIndex:r,originalRow:e}),{rowWrapper:s}},cloneCellFallback:e=>o._DOM.cloneNodeWrapper(e),handleCell:({context:e,cellClone:t})=>{n?(o.setFlagSlice(t),e.cells.push(t)):o._DOM.insertAtEnd(e.rowWrapper,t)},finalizeRow:({context:e})=>n?e.cells:e.rowWrapper}}function zi({evaluation:e,splitResult:t,splitStartRowIndexes:i,insufficientRemainingWindow:n,extraCapacity:o,fullPageHeight:r,debug:s,handlers:l={}}){const{newRows:a,isFirstPartEmptyInAnyTD:h,needsScalingInFullPage:c}=t||{},{rowIndex:d,row:g,isLastRow:u,tailWindowHeight:p}=e,{onReplaceRow:_,onAbsorbTail:f,onRefreshRows:m,onPlacement:b,onSplitFailure:w}=l;return Array.isArray(a)&&a.length?(_?.({evaluation:e,newRows:a}),u&&f?.({evaluation:e,newRows:a,extraCapacity:o}),m?.({evaluation:e,newRows:a,splitStartRowIndexes:i}),b?.({evaluation:e,newRows:a,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:h,needsScalingInFullPage:c,splitStartRowIndexes:i})??e.rowIndex):(Ai(this)&&console.log(`%c The row is not split. (ROW.${d})`,"color:orange",g),w?.({evaluation:e,splitStartRowIndexes:i,availableRowHeight:p,fullPageHeight:r})??e.rowIndex)}function Vi({evaluation:e,splitStartRowIndexes:t,extraCapacity:i,fullPageHeight:n,minPartLines:o,debug:r,decorateRowSlice:s,onBudgetInfo:l,handlers:a={}}){if(!e||!e.row)return e?.rowIndex??0;const{row:h}=e,c=this.getTableRowHeight(h,o),d=this.paginationCalculateRowSplitBudget({tailWindowHeight:e.tailWindowHeight,minMeaningfulRowSpace:c,fullPartHeight:n,debug:r});l?.({evaluation:e,firstPartHeight:d.firstPartHeight,fullPartHeight:n});const g=a.getRowSliceAdapter,u=g?.({evaluation:e,row:h,rowIndex:e.rowIndex,decorateRowSlice:s}),p=this.paginationSplitRow({rowIndex:e.rowIndex,row:h,firstPartHeight:d.firstPartHeight,fullPageHeight:n,debug:r,decorateRowSlice:s,rowAdapter:u});return this.paginationProcessRowSplitResult({evaluation:e,splitResult:p,splitStartRowIndexes:t,insufficientRemainingWindow:d.insufficientRemainingWindow,extraCapacity:i,fullPageHeight:n,debug:r,handlers:a})}function Ui({evaluation:e,table:t,newRows:i,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:o,needsScalingInFullPage:r,splitStartRowIndexes:s,pageBottom:l,fullPageHeight:a,debug:h,registerPageStartCallback:c,scaleProblematicSliceCallback:d,applyFullPageScalingCallback:g}){const{rowIndex:u}=e,p=Array.isArray(i)?i[0]:null;if(!p)return c?.({targetIndex:u,reason:"Row split produced empty first slice"}),u-1;const _=this.getTop(p,t),f=this.getBottom(p,t),m=this.evaluateRowSplitPlacement({usedRemainingWindow:!n,isFirstPartEmpty:o,firstSliceTop:_,firstSliceBottom:f,pageBottom:l,epsilon:0});return m.placeOnCurrentPage?(m.remainingWindowSpace>0&&d?.(p,m.remainingWindowSpace),c?.({targetIndex:u+1,reason:"Row split — next slice starts new page"})):(g?.({row:p,needsScalingInFullPage:r,fullPageHeight:a}),c?.({targetIndex:u,reason:"Empty first part — move row to next page"})),u-1}class qi{constructor({config:e,DOM:t,node:n,selector:o}){this._debug=e.debugMode?{...e.debugConfig.paragraph}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._selector=o,this._node=n,this._minParagraphLeftLines=2,this._minParagraphDanglingLines=2,this._minParagraphBreakableLines=this._minParagraphLeftLines+this._minParagraphDanglingLines||2,Object.assign(this,i)}split(e){return this._splitComplexTextBlockIntoLines(e)}_estimateLineCount(e){return Math.ceil(this._DOM.getElementOffsetHeight(e)/this._node.getLineHeight(e))}_splitComplexTextBlockIntoLines(e){if(this._debug._&&console.group("_splitComplexTextBlockIntoLines",[e]),this._estimateLineCount(e){const t=this._node.getLineHeight(e),i=this._DOM.getElementOffsetHeight(e),n=this._DOM.getElementOffsetLeft(e),o=this._DOM.getElementOffsetTop(e);return{element:e,lines:Math.ceil(i/t),left:n,top:o,height:i,lineHeight:t,text:this._DOM.getInnerHTML(e)}}));this._debug._&&console.log("\n🚸 nodeChildren",[...t],"\n🚸 extendedChildrenArray",[...i]);const n=i.flatMap((e=>e.lines>1&&!this._node.isNoBreak(e.element)?this._breakItIntoLines(e.element):e.element));this._debug._&&console.log("\n🚸🚸🚸\n partiallyLinedChildren",[...n]);const o=n.reduce(((e,t,i,n)=>(e||(e=[]),"BR"===this._DOM.getElementTagName(t)?(e.at(-1).push(t),e.push([]),this._debug._&&console.log("br; push:",t),e):!e.length||this._node.isLineChanged(e.at(-1).at(-1),t)?(e.push([t]),this._debug._&&console.log("◼️ start new line:",t),e):0===e.at(-1).length||e.length&&this._node.isLineKept(e.at(-1).at(-1),t)?(this._debug._&&console.log("⬆ add to line:",t),e.at(-1).push(t),e):void this.strictAssert(!0,"groupedPartiallyLinedChildren: An unexpected case of splitting a complex paragraph into lines.","\nOn the element:",t))),[]);if(this._debug._&&console.log("🟡🟡🟡 groupedPartiallyLinedChildren \n",o.length,[...o]),o.length{let i;if(0==e.length)i=e[0],i.setAttribute("role","🚫"),this.strictAssert(0==e.length,"The string cannot be empty (_splitComplexTextBlockIntoLines)");else if(1==e.length)i=e[0];else{i=this._node.createTextGroup(),this._DOM.insertBefore(e[0],i),this._DOM.insertAtEnd(i,...e)}return i.dataset.child=t,i}));return this.logGroupEnd("OK _splitComplexTextBlockIntoLines"),this._DOM.setAttribute(e,this._selector.split),l}_breakItIntoLines(e){if(this._debug._&&console.group("_breakItIntoLines",[e]),this._node.isNoBreak(e))return this.logGroupEnd("isNoBreak"),e;if(this._node.isWrappedTextNode(e)){const t=this._breakWrappedTextNodeIntoLines(e);return this.logGroupEnd("TextNode newLines"),t}return this.logGroupEnd("(recursive _breakItIntoLines)"),this._processNestedInlineElements(e)}_processNestedInlineElements(e){this._debug._&&console.group("_processNestedInlineElements",[e]);const t=this._getNestedInlineChildren(e).flatMap((e=>this._estimateLineCount(e)>1?this._breakItIntoLines(e):e)),i=this._findNewLineStarts(t,e),n=i.map(((n,o)=>{const r=t[n],s=t[i[o+1]];return this._node.cloneAndCleanOutsideRange(e,r,s)}));return this._DOM.insertInsteadOf(e,...n),this.logGroupEnd("Nested Inline parts"),n}_getNestedInlineChildren(e){return[...this._DOM.getChildNodes(e)].reduce(((e,t)=>{if(this._node.isSignificantTextNode(t)){const i=this._node.createTextNodeWrapper();return this._DOM.wrap(t,i),e.push(i),e}if(!this._DOM.getElementOffsetParent(t)){const i=this._node.getPreparedChildren(t);return i.length>0&&e.push(...i),e}if(this._DOM.isElementNode(t)){return this._getNestedInlineChildren(t).forEach((t=>e.push(t))),e}}),[])}_makeWordsFromTextNode(e){const t=this._node.splitTextByWordsGreedy(e);this._debug._&&console.log("wordArray",t);const i=t.map(((e,t)=>this._node.createWord(e+"",t)));return this._debug._&&console.log("wrappedWordArray",i),{wordArray:t,wrappedWordArray:i}}_breakWrappedTextNodeIntoLines(e){e.classList.add("🔠_breakItIntoLines");const{wordArray:t,wrappedWordArray:i}=this._makeWordsFromTextNode(e);this._DOM.setInnerHTML(e,""),this._DOM.insertAtEnd(e,...i);const n=this._findNewLineStarts(i,e),o=n.reduce(((i,o,r)=>{const s=this._node.createTextLine(),l=n[r],a=n[r+1],h=t.slice(l,a).join("")+"";return this._DOM.setInnerHTML(s,h),this._DOM.insertBefore(e,s),i.push(s),i}),[]);return e.remove(),o}_findNewLineStarts(e,t){const i=t.style.lineHeight;t.style.lineHeight=2;const n=e.reduce(((t,i,n)=>{const o=n>0?e[n-1].offsetTop:void 0,r=n>0?e[n-1].offsetHeight:void 0,s=i.offsetTop;return n>0&&o+r<=s&&t.push(n),t}),[0]);return t.style.lineHeight=i,n}}function Ki(e){if(e)return"function"==typeof e.getDebug?e.getDebug():e.debug}function Yi(e,t,i="unknown case"){if(!e||"function"!=typeof e.getSplitBottom||"function"!=typeof e.setSplitBottom)throw new Error("updateSplitBottom: adapter must expose getSplitBottom() and setSplitBottom().");const n=e.getSplitBottom();let o;if("number"==typeof t)o=t;else{if(!(t instanceof HTMLElement))throw new Error("updateSplitBottom: unexpected value type: "+typeof t);if("function"!=typeof e.computeSplitBottomForElement)throw new Error("updateSplitBottom: adapter must implement computeSplitBottomForElement(element).");o=e.computeSplitBottomForElement(t)}e.setSplitBottom(o);const r=function(e){return e?"function"==typeof e.getSplitBottomLog?e.getSplitBottomLog():e.splitBottomLog||null:null}(e);Array.isArray(r)&&r.push(o);const s=Ki(e);s&&s._&&console.log(`%c♻️ [${function(e){return e?.label||"👤 [paginator.label] element"}(e)}] update splitBottom (with ${t}) \n • ${i}`,"color: green; font-weight: bold","\n",n||"•••","->",o,r?`\n log: ${r}`:"")}function Zi(e,t,i,n="register page start"){const o=function(e){return e?"function"==typeof e.getRows?e.getRows()||[]:e.rows||[]:[]}(e),r=o.length,s=function(e){return!!e&&("function"==typeof e.shouldAssert?e.shouldAssert():Boolean(e.assert))}(e),l=Ki(e),a=Number.isInteger(t);if(s&&console.assert(a,`registerPageStartAt: index must be an integer, got: ${t}`),!a)return;if(s&&console.assert(r>0,"registerPageStartAt: no rows to register"),0===r)return;if(0===t)return l&&l._&&console.log("%c 📍 Row #0 forced to next page (no short first fragment)","color:green; font-weight:bold"),void((o[0]instanceof HTMLElement||"number"==typeof o[0])&&Yi(e,o[0],`${n} (index=0)`));let h=Math.max(1,Math.min(t,r-1));const c=i.at(-1);if(null!=c&&h<=c&&(h=c+1),h>=r)return void(l&&l._&&console.warn(`registerPageStartAt return: computed index (${h}) >= rowsLen (${r})`,"Last split index should not equal rows.length, or the original table will be empty."));i.push(h),l&&l._&&console.log(`%c 📍 Row # ${h} registered as page start`,"color:green; font-weight:bold");const d=o[h];(d instanceof HTMLElement||"number"==typeof d)&&Yi(e,d,n)}function Ji(e){return e._node.createSignpost("(table continued)",e._signpostHeight)}function Xi({owner:e=null,currentRows:t=[]}={}){return{owner:e,currentRows:Array.isArray(t)?t:[],parts:[]}}function Qi({entries:e,part:t,startIndex:i=null,endIndex:n=null,type:o="unknown",rows:r=[],meta:s}){if(!e||!t)return null;const l=function(e){if(e)return Array.isArray(e.parts)||(e.parts=[]),e.parts}(e);if(!l)return null;const a={part:t,type:o,startIndex:i,endIndex:n,rows:Array.isArray(r)?[...r]:[]};return s&&"object"==typeof s&&Object.keys(s).length&&(a.meta={...s}),l.push(a),a}class en{constructor({config:e,DOM:t,node:n,selector:o}){this._debug=e.debugMode?{...e.debugConfig.table}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._selector=o,this._node=n,this._splitLabelHeightFromConfig=e.splitLabelHeight,this._initConstants(),Object.assign(this,i),this._resetCurrent()}split(e,t,i,n){this._setCurrent(e,t,i,n);const o=this._splitCurrentTable();return this._resetCurrent(),o}_initConstants(){this._signpostHeight=parseFloat(this._splitLabelHeightFromConfig)||0,this._minPartLines=2}_resetCurrent(){this._currentTable=void 0,this._currentFirstPageBottom=void 0,this._currentFullPageHeight=void 0,this._currentRoot=void 0,this._currentTableEntries=void 0,this._currentTableRecordedParts=void 0,this._currentTableDistributedRows=void 0,this._currentTableFirstPartContentBottom=void 0,this._currentTableFullPartContentHeight=void 0,this._currentTableTfootHeight=void 0,this._currentTableSplitBottom=void 0,this._logSplitBottom_=[],this._currentRowShellCache=void 0,this._currentOverflowHelpers=void 0,this._currentTableHasRowspan=void 0,this._currentTableHasColspan=void 0,this._currentTableInconsistentCells=void 0,this._currentTableHasUnexpectedChildren=void 0}_setCurrent(e,t,i,n){this._currentTable=e,this._currentFirstPageBottom=t,this._currentFullPageHeight=i,this._currentRoot=n,this._currentRowShellCache=new WeakMap,this._currentOverflowHelpers=this._composeOverflowHelpers()}_prepareCurrentTableForSplitting(){this._lockCurrentTableWidths(),this._collectCurrentTableEntries(),this._updateCurrentTableDistributedRows(),this._currentTableRecordedParts=Xi({owner:this._currentTable,currentRows:this._currentTableDistributedRows}),this._currentTableEntries&&(this._currentTableEntries.recordedParts=this._currentTableRecordedParts),this._currentTable.__html2pdfRecordedParts=this._currentTableRecordedParts,this._analyzeCurrentTableStructure(),this._collectCurrentTableMetrics()}_lockCurrentTableWidths(){this._node.lockTableWidths(this._currentTable)}_splitCurrentTable(){this._prepareCurrentTableForSplitting(),this._setCurrentTableFirstSplitBottom(),this._debug._&&console.group("%c📊 _splitCurrentTable()","color:green; background:#eee; padding:3px","\n•",this._currentTableFirstPartContentBottom,"(1st bottom)","\n•",this._currentTableFullPartContentHeight,"(full part height)",{table:this._currentTable,rows:this._currentTableDistributedRows,entries:this._currentTableEntries,root:this._currentRoot});let e=[];for(let t=0;tNumber.isInteger(e)&&e>0&&e<=this._currentTableDistributedRows.length)),"splitStartRowIndexes contains invalid indexes"),this.strictAssert(e.every(((e,t,i)=>0===t||e>i[t-1])),"splitStartRowIndexes must be strictly ascending and without duplicates"),this.strictAssert(e.at(-1)!==this._currentTableDistributedRows.length,"Last split index should not equal rows.length, or the original table will be empty."),!e.length)return this.logGroupEnd("_splitCurrentTable !splitStartRowIndexes.length"),[];const t=e.map(((e,t,i)=>{const n=t>0?i[t-1]:0;return this._createAndInsertTableSlice({startId:n,endId:e,table:this._currentTable,tableEntries:this._currentTableEntries})})),i=e.length?e[e.length-1]:0,n=this._createAndInsertTableFinalSlice({table:this._currentTable,startId:i});return this._debug._&&console.log("splits",t),this._debug._&&console.log("lastPart",n),this._debug._&&console.log("[table.split] recordedParts",this._currentTableRecordedParts?.parts),this.logGroupEnd("_splitCurrentTable"),[...t,n]}_evaluateAndResolveRow(e,t){const i=e,n=this._currentTableDistributedRows.length;this._debug._&&console.group(`🔲 %c Check the Row # ${i} (from ${n})`,"");const o=this._node.paginationBuildRowEvaluationContext({rows:this._currentTableDistributedRows,rowIndex:e,table:this._currentTable,splitBottom:this._currentTableSplitBottom});if(!o?.row)return console.warn("[table.split] Missing row during evaluation.",{rowIndex:e}),this.logGroupEnd(`Row # ${i} (from ${n}) is checked`),e;if(this._debug._){const e=o.fitsCurrentWindow,t=e?"green":"orange",i=e?"<=":">";console.log(`%c📐 does row fit? %c ${e} %c :: ${o.nextMarker} ${i} ${this._currentTableSplitBottom} %c(Δ=${o.delta})`,"",`font-weight:bold;color:${t};`,"",`color:${t};`)}if(this._debug._&&console.info({row:o.row,rows:[...this._currentTableDistributedRows]}),o.fitsCurrentWindow)return this._debug._&&console.log(`%c ✓ Row # ${e}: PASS`,"color:green"),this.logGroupEnd(`Row # ${i} (from ${n}) is checked`),e;const r=this._node.calculateFinalPartReclaimedHeight({signpostHeight:this._signpostHeight,tfootHeight:this._currentTableTfootHeight});if(this._node.paginationCanAbsorbLastRow({evaluation:o,extraCapacity:r,splitBottom:this._currentTableSplitBottom,debug:this._debug}))return this._debug._&&console.log("🫟 last-row-fits-without-bottom-signpost: skip split"),this.logGroupEnd(`Row # ${i} (from ${n}) is checked`),e;const s=this._resolveOverflowingRow({evaluation:o,splitStartRowIndexes:t,extraCapacity:r});return this.logGroupEnd(`Row # ${i} (from ${n}) is checked`),s}_resolveOverflowingRow({evaluation:e,splitStartRowIndexes:t,extraCapacity:i}){return this._node.paginationResolveOverflowingRow({evaluation:e,utils:{rowHasSpan:e=>this._rowHasSpan(e),isSlice:e=>this._node.isSlice(e)},handlers:{handleRowWithRowspan:()=>this._node.paginationResolveRowWithRowspan({evaluation:e,splitStartRowIndexes:t,fullPageHeight:this._currentTableFullPartContentHeight,resolveOverflow:({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n})=>this._forwardOverflowFallback({rowIndex:e.rowIndex,row:e.row,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:t,reasonTail:"Row with ROWSPAN — move to next page",reasonFull:"Row with ROWSPAN — scaled TDs to full page",branch:"rowspan"}),debug:this._debug,afterResolve:({tailWindowHeight:e,fullPageHeight:t})=>{this._debug._&&e>=t&&console.warn("[table.fallback] ROWSPAN row required full-page scaling to fit.")}}),handleSplittableRow:()=>this._resolveSplittableRow({evaluation:e,splitStartRowIndexes:t,extraCapacity:i}),handleAlreadySlicedRow:()=>this._node.paginationResolveAlreadySlicedRow({evaluation:e,splitStartRowIndexes:t,fullPageHeight:this._currentTableFullPartContentHeight,debug:this._debug,resolveSplitFailure:({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n})=>this._forwardOverflowFallback({rowIndex:e.rowIndex,row:e.row,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:t,reasonTail:"Slice doesn't fit tail — move to next page",reasonFull:"Scaled TD content to fit full page",branch:"alreadySliced"})})}})}_resolveSplittableRow({evaluation:e,splitStartRowIndexes:t,extraCapacity:i}){const{rowIndex:n}=e;this._debug._&&console.group(`%c 🔳 Try to split the ROW ${n} %c (from ${this._currentTableDistributedRows.length})`,"color:magenta;","");const o=this._node.paginationResolveSplittableRow({evaluation:e,splitStartRowIndexes:t,extraCapacity:i,fullPageHeight:this._currentTableFullPartContentHeight,minPartLines:this._minPartLines,debug:this._debug,decorateRowSlice:({rowWrapper:e,rowIndex:t,sliceIndex:i})=>{this._DOM.setAttribute(e,`.splitted_row_${t}_part_${i}`)},onBudgetInfo:({evaluation:e,firstPartHeight:t,fullPartHeight:i})=>{this._debug._&&console.info({currRowTop:e.rowTop,"• splitBottom":this._currentTableSplitBottom,"• is row sliced?":!1,"remaining page space":e.tailWindowHeight,"first part height":t,"full part height":i})},handlers:{onReplaceRow:({evaluation:e,newRows:t})=>{this._replaceRowInDOM(e.row,t)},onAbsorbTail:({newRows:e,extraCapacity:t})=>{this._node.absorbShortTrailingSliceIfFits({slices:e,extraCapacity:t,ownerLabel:"table",debug:this._debug})},onRefreshRows:({evaluation:e,newRows:t})=>{this._node.paginationRefreshRowsAfterSplit(this._getSplitterAdapter(),{rowIndex:e.rowIndex,rowSlices:t})},onPlacement:({evaluation:e,newRows:i,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:o,needsScalingInFullPage:r})=>this._node.paginationHandleRowSlicesPlacement({evaluation:e,table:this._currentTable,newRows:i,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:o,needsScalingInFullPage:r,splitStartRowIndexes:t,pageBottom:this._currentTableSplitBottom,fullPageHeight:this._currentTableFullPartContentHeight,debug:this._debug,registerPageStartCallback:({targetIndex:e,reason:i})=>this._registerPageStartAt(e,t,i),scaleProblematicSliceCallback:(e,t)=>{t>0&&(this._debug._&&console.log("⚖️ scaleProblematicCellsToHeight"),this._scaleProblematicCellsToHeight(e,t,this._getRowShellHeights(e)))},applyFullPageScalingCallback:({row:e,needsScalingInFullPage:t,fullPageHeight:i})=>{this._node.paginationApplyFullPageScaling({needsScalingInFullPage:t&&Boolean(e),payload:{row:e,targetHeight:i},scaleCallback:({row:e,targetHeight:t})=>(this._debug._&&console.log("⚖️ scaleProblematicCellsToHeight"),this._scaleProblematicCellsToHeight(e,t,this._getRowShellHeights(e)))})}}),onSplitFailure:({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n})=>this._forwardOverflowFallback({rowIndex:e.rowIndex,row:e.row,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:t,reasonTail:"Split failed — move row to next page",reasonFull:"Scaled TDs to fit full-page",branch:"splitFailure"})}});return this.logGroupEnd(`🔳 Try to split the ROW ${n} (from ${this._currentTableDistributedRows.length})`),o}_collectCurrentTableEntries(){this._currentTableEntries=this._node.getTableEntries(this._currentTable)}_rowHasSpan(e){const t=[...this._DOM.getChildren(e)];for(const e of t){const t=this._DOM.getElementTagName(e);if("TD"!==t&&"TH"!==t)continue;const i=parseInt(e.getAttribute("rowspan"));if(Number.isFinite(i)&&i>1)return!0}return!1}_collectCurrentTableMetrics(){const e=this._node.getEmptyNodeHeightByProbe(this._currentTable,'',!1),t=this._node.getTopForPageStartCandidate(this._currentTable,this._currentRoot),i=(this._node.getTopWithMargin(this._currentTable,this._currentRoot),this._DOM.getElementOffsetHeight(this._currentTableEntries.caption)||0),n=this._DOM.getElementOffsetTop(this._currentTableDistributedRows[0],this._currentTable)-i||0;this._currentTableTfootHeight=this._DOM.getElementOffsetHeight(this._currentTableEntries.tfoot)||0,this._currentTableFirstPartContentBottom=this._currentFirstPageBottom-t-e-this._signpostHeight,this._currentTableFullPartContentHeight=this._currentFullPageHeight-i-n-this._currentTableTfootHeight-e-2*this._signpostHeight}_getDistributedRows(e){return[...e.rows,...e.tfoot?[e.tfoot]:[]]}_updateCurrentTableDistributedRows(){this._currentTableDistributedRows=this._getDistributedRows(this._currentTableEntries)}_analyzeCurrentTableStructure(){this._currentTableEntries;const e=this._currentTableDistributedRows||[],t=this._node.computeRowFlags({rows:e,DOM:this._DOM,cellTagFilter:(e,t)=>"TFOOT"!==this._DOM.getElementTagName(t.parentNode)&&("TD"===e||"TH"===e)});this._currentTableHasRowspan=t.hasRowspan,this._currentTableHasColspan=t.hasColspan,this._currentTableInconsistentCells=t.inconsistentCells,this._debug._&&(t.hasRowspan&&console.warn("[table.guard] ROWSPAN detected — slicing not implemented; applying conservative fallback.",{table:this._currentTable}),t.hasColspan&&console.warn("[table.guard] COLSPAN present — handled within-row slicing; monitor results.",{table:this._currentTable}),t.inconsistentCells&&console.warn("[table.guard] Inconsistent cell counts across rows — results may vary.",{table:this._currentTable}))}_updateCurrentTableEntriesAfterSplit(e,t){this._currentTableEntries.rows.splice(e,1,...t)}_setCurrentTableFirstSplitBottom(){this._node.getTop(this._currentTableDistributedRows[0],this._currentTable)>this._currentTableSplitBottom?(this._updateCurrentTableSplitBottom(this._currentTableFullPartContentHeight,"SPECIAL CASE: start immediately from the full height of the page"),this._debug._&&console.log("The Row 0 goes to the 2nd page")):this._updateCurrentTableSplitBottom(this._currentTableFirstPartContentBottom,"start with a short first part")}_getPaginatorAdapter(){return{label:"table",getSplitBottom:()=>this._currentTableSplitBottom,setSplitBottom:e=>{this._currentTableSplitBottom=e},computeSplitBottomForElement:e=>this._node.getTop(e,this._currentTable)+this._currentTableFullPartContentHeight,getRows:()=>this._currentTableDistributedRows,shouldAssert:()=>this._assert,getDebug:()=>this._debug,getSplitBottomLog:()=>this._logSplitBottom_}}_getSplitterAdapter(){const e=()=>({rows:this._currentTableDistributedRows||[],DOM:this._DOM,cellTagFilter:(e,t)=>{const i=t?.parentNode;return"TFOOT"!==(i?this._DOM.getElementTagName(i):void 0)&&("TD"===e||"TH"===e)}});return{label:"table",rows:{getCurrentRows:()=>this._currentTableDistributedRows||[],replaceRow:({rowIndex:e,rowSlices:t})=>{this._node.applyRowSlicesToEntriesAfterRowSplit(this._currentTableEntries,e,t)},syncEntries:()=>{this._updateCurrentTableDistributedRows(),this._currentTableRecordedParts&&(this._currentTableRecordedParts.currentRows=this._currentTableDistributedRows)},getGuardConfig:e,onRowsChanged:()=>{this._currentTableRecordedParts&&(this._currentTableRecordedParts.currentRows=this._currentTableDistributedRows)}},guards:{getConfig:e,onFlags:({flags:e})=>{e&&(this._currentTableHasRowspan=Boolean(e.hasRowspan),this._currentTableHasColspan=Boolean(e.hasColspan),this._currentTableInconsistentCells=Boolean(e.inconsistentCells))}}}}_updateCurrentTableSplitBottom(e,t="unknown case"){Yi(this._getPaginatorAdapter(),e,t)}_registerPageStartAt(e,t,i="register page start"){Zi(this._getPaginatorAdapter(),e,t,i)}_composeOverflowHelpers(){const e=this._node.scaleCellsToHeight.bind(this._node),t=this._getRowShellHeights.bind(this),i={ownerLabel:"table",registerPageStartCallback:this._registerPageStartAt.bind(this),debugLogger:this._debug&&this._debug._?(e,t)=>console.log(e,t):void 0,scaleProblematicCellsCallback:(i,n,o)=>this._node.scaleRowCellsToHeight({ownerLabel:"table",DOM:this._DOM,row:i,targetHeight:n,cachedShells:o,getRowShellHeightsCallback:t,scaleCellsToHeightCallback:e})};return this._currentOverflowHelpers=i,i}_scaleProblematicCellsToHeight(e,t,i){return(this._currentOverflowHelpers||this._composeOverflowHelpers()).scaleProblematicCellsCallback(e,t,i)}_forwardOverflowFallback({rowIndex:e,row:t,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:o,reasonTail:r,reasonFull:s,branch:l}){const a=this._currentOverflowHelpers||this._composeOverflowHelpers(),h={ownerLabel:`table:${l}`,rowIndex:e,row:t,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:o,reasonTail:r,reasonFull:s,registerPageStartCallback:a.registerPageStartCallback,scaleProblematicCellsCallback:a.scaleProblematicCellsCallback,debugLogger:a.debugLogger};return this._debug._&&console.log(`%c[table.overflow] branch=${l} rowIndex=${e} tail=${i} full=${n}`,"color:orange; font-weight:bold",{reasonTail:r,reasonFull:s}),"splitFailure"===l?this._node.handleRowSplitFailure(h):this._node.handleRowOverflow(h)}_getRowShellHeights(e){if(!this._currentRowShellCache)return this._node.getTableRowShellHeightByTD(e);if(this._currentRowShellCache.has(e))return this._currentRowShellCache.get(e);const t=this._node.getTableRowShellHeightByTD(e);return this._currentRowShellCache.set(e,t),t}_createTopSignpost(){return this._node.createSignpost("(table continued)",this._signpostHeight)}_createBottomSignpost(){return this._node.createSignpost("(table continues on the next page)",this._signpostHeight)}_replaceRowInDOM(e,t){this._debug._&&this._DOM.setAttribute(e,".🚫_must_be_removed"),this._DOM.insertInsteadOf(e,...t)}_createAndInsertTableSlice({startId:e,endId:t,table:i,tableEntries:n}){const o=function(e,{startId:t,endId:i,table:n,tableEntries:o}){e.strictAssert(Number.isInteger(t)&&Number.isInteger(i),`createAndInsertTableSlice: non-integer bounds: startId=${t}, endId=${i}`);const r=o&&o.rows?o.rows.length:0;e.strictAssert(r>=0,`createAndInsertTableSlice: invalid rows length: ${r}`),e.strictAssert(t>=0&&i>=0&&t({rowIndex:e+i,row:t,cells:Array.from(this._DOM.getChildren(t)||[])}))):[];return this._recordTablePart(o,{startId:e,endId:t,type:"slice",rows:r}),o}_createAndInsertTableFinalSlice({table:e,startId:t=0}){const i=function(e,{table:t}){const i=e._node.createWithFlagNoBreak();return e._node.markTopCut(t),e._DOM.insertBefore(t,i),e._DOM.insertAtEnd(i,Ji(e),t),i}(this,{table:e}),n=Array.isArray(this._currentTableDistributedRows)?this._currentTableDistributedRows.length:0,o=Array.isArray(this._currentTableDistributedRows)?this._currentTableDistributedRows.slice(t).map(((e,i)=>({rowIndex:t+i,row:e,cells:Array.from(this._DOM.getChildren(e)||[])}))):[];return this._recordTablePart(i,{startId:t,endId:n,type:"final",rows:o}),i}_recordTablePart(e,t={}){const i=this._currentTableRecordedParts;if(!i||!e)return null;const{startId:n=null,endId:o=null,type:r="unknown",rows:s=[],meta:l}=t||{};return Qi({entries:i,part:e,startIndex:n,endIndex:o,type:r,rows:s,meta:l})}}class tn{constructor({config:e,DOM:t,node:i,selector:n}){this._debug=e.debugMode?{...e.debugConfig.tableLike}:{},this._DOM=t,this._selector=n,this._node=i,this._minLeftLines=2,this._minDanglingLines=2,this._minBreakableLines=this._minLeftLines+this._minDanglingLines,this._minLeftRows=1,this._minDanglingRows=1,this._minBreakableRows=1,this._minPreFirstBlockLines=3,this._minPreLastBlockLines=3,this._minPreBreakableLines=this._minPreFirstBlockLines+this._minPreLastBlockLines,this._minBreakableGridRows=4,this._imageReductionRatio=.8,this._signpostHeight=parseFloat(e.splitLabelHeight)||0}split(e,t,i,n,o){const r=o||this._DOM.getComputedStyle(e);this._debug._&&console.log("root",n);const s=this._node.getPreparedChildren(e),l=this._node.getTop(e,n),a=this._node.getEmptyNodeHeightByProbe(e),h=i-a;let c=s,d=0,g=[],u=t-l-a;const p=r.position;"relative"!=p&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;tu&&(t&&g.push(t),t&&(d+=1),u=t?this._node.getTop(i,e)+h:h)}if(this._DOM.setStyles(e,{position:p}),!g.length)return this._debug._&&console.log("splitters.length",g.length),[];g.push(null);const _=g.map(((t,i,n)=>{const o=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(o),this._node.unmarkPageStartElement(o);const r=n[i-1]||0,s=t||n[n.length];return this._DOM.insertAtEnd(o,...c.slice(r,s)),o}));return this._node.markSliceCuts(_),this._DOM.replaceNodeContentsWith(e,..._),this._DOM.removeAllClasses(e),this._DOM.removeAllStyles(e),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),_}}class nn{constructor({config:e,DOM:t,node:n,selector:o}){this._debug=e.debugMode?{...e.debugConfig.grid}:{},this._assert=!!e.consoleAssert,Object.assign(this,i),this._DOM=t,this._selector=o,this._node=n,this._resetCurrent(),this._minBreakableGridRows=1,this._minGridRowContentLines=2,this._gridCellLineHeightCache=new WeakMap,this._gridComputedStyleCache=new WeakMap,this._signpostHeight=parseFloat(e.splitLabelHeight)||0}split(e,t,i,n,o){this._resetCurrent(),this._debug._&&console.group("%c split Grid Node","background:#00FFFF",e);const r=this._node.getPreparedChildren(e);this._node.lockNodesWidths(r);const s=o||this._getComputedStyleCached(e);if(!r.length)return this._node.setInitStyle(!1,e,s),this._debug._&&console.groupEnd(),[];this._node.setInitStyle(!0,e,s);const l=this._scanGridLayout(e,s);if(!l.safe)return this._debug._&&console.warn("[grid.split] skip unsafe layout",l),this._debug._&&console.warn("[grid.split] Unsupported grid layout detected; keeping original grid intact.",l),this._node.setInitStyle(!1,e,s),this._debug._&&console.groupEnd(),[];const a=[];let h=!1,c=!1;const d=new Set;let g=null,u=null,p=null;r.forEach((t=>{const i=this._getComputedStyleCached(t),n=parseInt(i.gridRowStart,10),o=Number.isFinite(n),r=this._node.getTop(t,e),s=this._node.getBottom(t,e);let l=!1;l=!a.length||(o&&null!=g?n!==g:null!=p?r>=p-.5:null==u||Math.abs(r-u)>.5),l?(a.push([t]),g=o?n:null,u=r,p=s):(a[a.length-1].push(t),o&&null==g&&(g=n),(null==u||rp)&&(p=s));const _=i.gridRowEnd||"",f=i.gridColumnEnd||"";h=h||_.includes("span"),c=c||f.includes("span"),o&&d.add(n)}));const _=d.size>0&&Math.max(...d)>a.length;if(_)return this._debug._&&console.warn("[grid.split]","Unsupported implicit row gap detected; keeping grid unsplit.",{hasImplicitRowGaps:_}),this._node.setInitStyle(!1,e,s),this._debug._&&console.groupEnd(),[];if(h||c)return this._debug._&&console.warn("[grid.split]","Grid contains row/column spans; using fallback (move row to next page).",{hasRowSpan:h,hasColumnSpan:c}),this._debug._&&console.groupEnd(),this._fallbackMoveGridToNextPage({gridNode:e,nodeComputedStyle:s});this.log("grid.split","currentRows:",a);const f=this._node.getTop(e,n),m=this._node.getEmptyNodeHeightByProbe(e),b=t-f-m,w=i-m;if(this.log("grid.split",{firstPartHeight:b,fullPagePartHeight:w}),this._currentGridNode=e,this._currentGridRows=a,this._currentGridFullPartHeight=w,this._currentGridSplitLog=[],this._currentGridEntries=Xi({owner:e,currentRows:a}),this._currentGridRecordedParts=this._currentGridEntries,this._currentGridNode.__html2pdfRecordedParts=this._currentGridRecordedParts,this._currentGridShellCache=new WeakMap,a.length0?Math.floor(t):1;let o=0;return()=>{if(o+=1,o<=n)return;const t={label:e,iterations:o,limit:n};throw i&&console.assert(!1,`\n\n ⛔ [${e}] ♾️ loop guard triggered`,t),new Error(`\n ⛔ [${e}] ♾️ loop guard triggered`)}}({label:"grid.split",limit:Math.max(1,6*(a.length||1)),assert:this._assert});this._updateCurrentGridSplitBottom(b,"start with initial window");for(let t=0;tthis._buildGridSplit({startId:n[i-1]||0,endId:t,node:e,entries:M}))).filter(Boolean).map((e=>e.part)),this._createAndInsertGridFinalSlice({node:e,entries:M,startId:C})];return this.log("grid.split",{splitStartRowIndexes:S,splits:O,recordedParts:this._currentGridRecordedParts?.parts}),this._node.setInitStyle(!1,e,s),this._resetCurrent(),this.logGroupEnd("split Grid Node"),O}_fallbackMoveGridToNextPage({gridNode:e,nodeComputedStyle:t}){return this._node.setInitStyle(!1,e,t),this._resetCurrent(),[]}_resetCurrent(){this._currentGridNode=void 0,this._currentGridRows=void 0,this._currentGridEntries=void 0,this._currentGridRecordedParts=void 0,this._currentGridSplitBottom=void 0,this._currentGridFullPartHeight=void 0,this._currentGridSplitLog=void 0,this._currentGridRowFlags=void 0,this._currentGridShellCache=void 0,this._gridCellLineHeightCache=new WeakMap,this._gridComputedStyleCache=new WeakMap}_getGridSplittableHandlers({evaluation:e,splitStartRowIndexes:t}){return{getRowSliceAdapter:({row:t})=>this._createGridRowSliceAdapter({row:t,rowIndex:e.rowIndex}),onReplaceRow:({newRows:t})=>{this._removeOriginalGridRowCells(e.row),this._node.paginationRefreshRowsAfterSplit(this._getSplitterAdapter(),{rowIndex:e.rowIndex,rowSlices:t})},onAbsorbTail:()=>{},onRefreshRows:({newRows:t})=>{this._node.paginationRefreshRowsAfterSplit(this._getSplitterAdapter(),{rowIndex:e.rowIndex,rowSlices:t})},onPlacement:({evaluation:e,newRows:i,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:o,needsScalingInFullPage:r})=>this._node.paginationHandleRowSlicesPlacement({evaluation:e,table:this._currentGridNode,newRows:i,insufficientRemainingWindow:n,isFirstPartEmptyInAnyTD:o,needsScalingInFullPage:r,splitStartRowIndexes:t,pageBottom:this._currentGridSplitBottom,fullPageHeight:this._currentGridFullPartHeight,debug:this._debug,registerPageStartCallback:({targetIndex:e,reason:i})=>this._registerPageStartAt(e,t,i),scaleProblematicSliceCallback:(e,t)=>this._scaleGridCellsToHeight(e,t),applyFullPageScalingCallback:({row:e,needsScalingInFullPage:t,fullPageHeight:i})=>{this._node.paginationApplyFullPageScaling({needsScalingInFullPage:t&&Boolean(e),payload:{cells:e,targetHeight:i},scaleCallback:({cells:e,targetHeight:t})=>this._scaleGridCellsToHeight(e,t)})}}),onSplitFailure:({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n})=>this._forwardGridOverflowFallback({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n,branch:"splitFailure"})}}_forwardGridOverflowFallback({evaluation:e,splitStartRowIndexes:t,availableRowHeight:i,fullPageHeight:n=this._currentGridFullPartHeight,branch:o,reasonTail:r,reasonFull:s}){const l=this._composeGridOverflowHelpers(),a={ownerLabel:`grid:${o}`,gridNode:this._currentGridNode,evaluation:e,rowIndex:e.rowIndex,row:e.row,availableRowHeight:i,fullPageHeight:n,splitStartRowIndexes:t,reasonTail:r||("splitFailure"===o?"Grid split failed — move row to next page":"Grid slice overflow — move row to next page"),reasonFull:s||("splitFailure"===o?"Grid split failed — scaled cells to full page":"Grid slice overflow — scaled cells to full page"),registerPageStartCallback:l.registerPageStartCallback,scaleProblematicCellsCallback:l.scaleProblematicCellsCallback,debugLogger:l.debugLogger};return this._debug._&&console.log("[grid.overflow]",o,a),"splitFailure"===o?this._node.handleRowSplitFailure(a):this._node.handleRowOverflow(a)}_buildGridRowEvaluation({rows:e,rowIndex:t,gridNode:i,splitBottom:n}){if(!Array.isArray(e))return null;const o=e[t];if(!o)return null;const r=Array.isArray(o)?new Array(o.length):null,s=this._getRowTop(o,i,r),l=this._getRowBottom(o,i,r),a=e[t+1],h=a?this._getRowTop(a,i):l,c=h-n;return{rowIndex:t,row:o,rowTop:s,rowBottom:l,nextMarker:h,delta:c,tailWindowHeight:n-s,isLastRow:!a,fitsCurrentWindow:c<=0,cellStyles:r}}_composeGridOverflowHelpers(){const e=this._registerPageStartAt.bind(this);this._scaleGridCellsToHeight.bind(this);return{registerPageStartCallback:e,scaleProblematicCellsCallback:(e,t)=>!!Array.isArray(e)&&this._scaleGridCellsToHeight(e,t),debugLogger:this._debug&&this._debug._?(e,t)=>console.log(e,t):void 0}}_resolveGridOverflowingRow({evaluation:e,splitStartRowIndexes:t}){return this._node.paginationResolveOverflowingRow({evaluation:e,utils:{rowHasSpan:()=>!1,isSlice:e=>this._isGridRowSlice(e)},handlers:{handleRowWithRowspan:()=>(this._debug._&&console.warn("[grid.split] ROWSPAN guard triggered unexpectedly.",{evaluation:e}),this._registerPageStartAt(e.rowIndex,t,"Grid ROWSPAN fallback — move row to next page"),e.rowIndex-1),handleSplittableRow:()=>this._resolveGridSplittableRow({evaluation:e,splitStartRowIndexes:t}),handleAlreadySlicedRow:()=>this._forwardGridOverflowFallback({evaluation:e,splitStartRowIndexes:t,branch:"alreadySliced"})}})}_resolveGridSplittableRow({evaluation:e,splitStartRowIndexes:t}){const{rowIndex:i}=e;this._debug._&&console.group("%c[grid.split] Stage5 — splittable row","color:#0080ff",{rowIndex:i,row:e.row,tailWindowHeight:e.tailWindowHeight});const n=this._estimateGridRowMeaningfulSpace({row:e.row,cellStyles:e.cellStyles,minContentLines:this._minGridRowContentLines});if(!(n>0))return console.warn("[grid.metrics] Meaningful row space is unavailable; falling back to overflow handler."),this._forwardGridOverflowFallback({evaluation:e,splitStartRowIndexes:t,availableRowHeight:e.tailWindowHeight,fullPageHeight:this._currentGridFullPartHeight,branch:"metricsMissing",reasonTail:"Grid row metrics missing — move row to next page",reasonFull:"Grid row metrics missing — scaled cells to full page"});const o=this._node.paginationCalculateRowSplitBudget({tailWindowHeight:e.tailWindowHeight,minMeaningfulRowSpace:n,fullPartHeight:this._currentGridFullPartHeight,debug:this._debug}),r=this._node.paginationSplitRow({rowIndex:i,row:e.row,firstPartHeight:o.firstPartHeight,fullPageHeight:this._currentGridFullPartHeight,debug:this._debug,decorateRowSlice:({rowWrapper:e,rowIndex:t,sliceIndex:i})=>{e instanceof HTMLElement&&this._DOM.setAttribute(e,`.grid_row_${t}_part_${i}`)},rowAdapter:this._createGridRowSliceAdapter({row:e.row,rowIndex:i,cellStyles:e.cellStyles})}),s=this._node.paginationProcessRowSplitResult({evaluation:e,splitResult:r,splitStartRowIndexes:t,insufficientRemainingWindow:o.insufficientRemainingWindow,extraCapacity:0,fullPageHeight:this._currentGridFullPartHeight,debug:this._debug,handlers:this._getGridSplittableHandlers({evaluation:e,splitStartRowIndexes:t})});return this.logGroupEnd("[grid.split] Stage5 — splittable row"),s}_createGridRowSliceAdapter({row:e,rowIndex:t,cellStyles:i}){if(!Array.isArray(e))return null;const n=this._currentGridNode,o=e[0]||null,r=this;return{getParentContainer:()=>n,getOriginalCells:()=>[...e],getShellHeights:()=>r._getGridShellHeights(e,i),markOriginalRow:({cells:e})=>{e.forEach((e=>r._node.setFlagSlice(e)))},beginRow:()=>({fragment:r._DOM.createDocumentFragment(),cells:[]}),cloneCellFallback:e=>r._DOM.cloneNodeWrapper(e),handleCell:({context:e,cellClone:t})=>{r._node.setFlagSlice(t),e.fragment.append(t),e.cells.push(t)},finalizeRow:({context:e})=>(o&&r._DOM.insertBefore(o,e.fragment),e.cells)}}_removeOriginalGridRowCells(e){Array.isArray(e)&&e.forEach((e=>{e instanceof HTMLElement&&this._DOM.removeNode(e)}))}_isGridRowSlice(e){if(Array.isArray(e)){const t=e.find((e=>e instanceof HTMLElement));return!!t&&this._node.isSlice(t)}return!!e&&this._node.isSlice(e)}_getPaginatorAdapter(){return{label:"grid",getSplitBottom:()=>this._currentGridSplitBottom,setSplitBottom:e=>{this._currentGridSplitBottom=e},computeSplitBottomForElement:e=>e&&this._currentGridNode?this._node.getTop(e,this._currentGridNode)+(this._currentGridFullPartHeight||0):this._currentGridSplitBottom||0,getRows:()=>Array.isArray(this._currentGridRows)?this._currentGridRows.map((e=>{if(!e)return null;if(e instanceof HTMLElement)return e;if(Array.isArray(e)){const t=e.find((e=>e instanceof HTMLElement));if(t)return t;const i=this._getRowTop(e,this._currentGridNode);return Number.isFinite(i)?i:null}const t=this._getRowTop(e,this._currentGridNode);return Number.isFinite(t)?t:null})):[],shouldAssert:()=>this._assert,getDebug:()=>this._debug,getSplitBottomLog:()=>this._currentGridSplitLog}}_getSplitterAdapter(){return{label:"grid",rows:{getCurrentRows:()=>this._currentGridRows||[],replaceRow:({rowIndex:e,rowSlices:t})=>{Array.isArray(this._currentGridRows)&&this._node.replaceCurrentRowsAfterRowSplit({currentRows:this._currentGridRows,index:e,rowSlices:t})},syncEntries:()=>{this._currentGridEntries&&(this._currentGridEntries.currentRows=this._currentGridRows),this._currentGridRecordedParts&&(this._currentGridRecordedParts.currentRows=this._currentGridRows)},getGuardConfig:()=>({rows:this._currentGridRows||[],DOM:this._DOM})},guards:{onFlags:({flags:e})=>{this._currentGridRowFlags=e}}}}_updateCurrentGridSplitBottom(e,t="unknown case"){Yi(this._getPaginatorAdapter(),e,t)}_registerPageStartAt(e,t,i="register page start"){Zi(this._getPaginatorAdapter(),e,t,i)}_scaleGridCellsToHeight(e,t){if(!(Array.isArray(e)&&e.length&&t>0))return!1;const i=this._getGridShellHeights(e),n=this._debug._?e.map((e=>this._DOM.getElementOffsetHeight(e))):null,o=this._node.paginationScaleCellsToHeight({cells:e,targetHeight:t,shells:i});if(this._debug._){const r=e.map((e=>this._DOM.getElementOffsetHeight(e)));console.log("[grid.scaleCells] target:",t,"shells:",i,"before:",n,"after:",r,"scaled:",o)}return o}_buildGridSplit({startId:e,endId:t,node:i,entries:n}){const o=n?.currentRows||this._currentGridRows||[];if(e===t)return this._debug._&&console.warn("[grid.split] _buildGridSplit: skip empty slice request",e,t),this.strictAssert(!1,"[grid.split] _buildGridSplit: empty slice encountered"),null;if(this._debug._){const i=o.slice(e,t);console.log(`=> [grid.split] _buildGridSplit: slice rows [${e}, ${t})`,i)}const r=this._createAndInsertGridSlice({startId:e,endId:t,node:i,entries:n}),s=this._collectGridTelemetryRows(o,e,t);return this._recordGridPart(r,{startId:e,endId:t,type:"slice",rows:s}),{part:r,telemetryRows:s}}_createAndInsertGridSlice({startId:e,endId:t,node:i,entries:n}){return function(e,{startId:t,endId:i,node:n,entries:o,fallbackCurrentRows:r}){const s=e._DOM.cloneNodeWrapper(n);e._node.copyNodeWidth(s,n),e._node.setFlagNoBreak(s),t&&e._node.markTopCut(s),e._node.markBottomCut(s),n.before(s);const l=o?.currentRows||r||[],a=e&&e._DOM&&"function"==typeof e._DOM.isElementNode?e._DOM.isElementNode.bind(e._DOM):null,h=l.slice(t,i).flat().map((e=>{if(!e)return null;if(a&&a(e))return e;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return e;const t=e.element;if(t){if(a&&a(t))return t;if("undefined"!=typeof HTMLElement&&t instanceof HTMLElement)return t}return null})).filter(Boolean);return e._DOM.insertAtEnd(s,...h),s}(this,{startId:e,endId:t,node:i,entries:n})}_createAndInsertGridFinalSlice({node:e,entries:t,startId:i}){const n=function(e,{node:t,entries:i}){return e._node.markTopCut(t),e._node.setFlagNoBreak(t),t}(this,{node:e,entries:t}),o=t?.currentRows||this._currentGridRows||[],r=this._collectGridTelemetryRows(o,i);return this._recordGridPart(n,{startId:i,endId:o.length,type:"final",rows:r}),n}_collectGridTelemetryRows(e,t,i){if(!Array.isArray(e))return[];return e.slice(t,"number"==typeof i?i:void 0).map(((e,i)=>{const n=Array.isArray(e)?[...e]:[e];return{rowIndex:t+i,row:e,cells:n}}))}_recordGridPart(e,t={}){const i=this._currentGridRecordedParts;if(!i||!e)return null;const{startId:n=null,endId:o=null,type:r="unknown",rows:s=[],meta:l}=t||{};return Qi({entries:i,part:e,startIndex:n,endIndex:o,type:r,rows:s,meta:l})}_estimateGridRowMeaningfulSpace({row:e,cellStyles:t=null,minContentLines:i=this._minGridRowContentLines}){if(!Array.isArray(e)||0===e.length)return console.warn("[grid.metrics] Row payload missing while estimating split budget."),null;const n=this._getGridShellHeights(e,t),o=Array.isArray(t)?t:null,r=Math.max(1,i);let s=0;return e.forEach(((e,t)=>{if(!(e instanceof HTMLElement))return void console.warn("[grid.metrics] Unexpected non-element cell in row; ignoring during split budget calculation.",{cell:e,index:t});let i=o?o[t]:null;i||(i=this._getComputedStyleCached(e),o&&(o[t]=i));const l=this._resolveGridCellLineHeight({cell:e,style:i}),a=(n?.[t]||0)+l*r;s=Math.max(s,a)})),s>0?s:(console.warn("[grid.metrics] Failed to measure meaningful row space."),null)}_resolveGridCellLineHeight({cell:e,style:t}){const i=this._gridCellLineHeightCache,n=i?.get(e);if(n>0)return n;t||(console.warn("[grid.metrics] style not passed for _resolveGridCellLineHeight",{cell:e}),t=this._getComputedStyleCached(e));let o=parseFloat(t?.lineHeight);if(o>0)return i?.set(e,o),o;const r=parseFloat(t?.fontSize);if(Number.isFinite(r)&&r>0){const t=1.2*r;return i?.set(e,t),t}if(o=this._node.getLineHeight(e),o>0)return i?.set(e,o),o;return i?.set(e,16),16}_getGridShellHeights(e,t=null){if(this._currentGridShellCache||(this._currentGridShellCache=new WeakMap),this._currentGridShellCache.has(e))return this._currentGridShellCache.get(e);const i=Array.isArray(e)?e:[e].filter(Boolean),n=this._computeGridCellShellHeights(i,t);return this._currentGridShellCache.set(e,n),n}_getComputedStyleCached(e){if(!e)return console.warn("[grid.split] the element was not passed to _getComputedStyleCached"),null;const t=this._gridComputedStyleCache;if(!t)return this._DOM.getComputedStyle(e);const i=t.get(e);if(i)return i;const n=this._DOM.getComputedStyle(e);return t.set(e,n),n}_computeGridCellShellHeights(e,t=null){return Array.isArray(e)&&e.length?e.map(((e,i)=>{if(!e)return 0;let n=null;t?(n=t[i],n||(n=this._getComputedStyleCached(e),t[i]=n)):n=this._getComputedStyleCached(e);const o=parseFloat(n?.paddingTop)||0,r=parseFloat(n?.paddingBottom)||0,s=parseFloat(n?.borderTopWidth)||0,l=parseFloat(n?.borderBottomWidth)||0,a=parseFloat(n?.marginTop)||0,h=parseFloat(n?.marginBottom)||0,c=o+r+s+l,d=Math.max(0,a)+Math.max(0,h),g=this._DOM.getElementOffsetHeight(e)||0;let u=0;if("function"==typeof this._node.getContentHeightByProbe)try{const t=this._node.getContentHeightByProbe(e,n);Number.isFinite(t)&&t>=0&&(u=t)}catch(e){}u>0&&!(u>g)||(u=Math.max(0,g-c));let p=g-u;return Number.isFinite(p)||(p=c),p=Math.max(p,c),Math.max(0,p+d)})):[]}_getRowTop(e,t,i=null){if(Array.isArray(e)){let i=1/0;return e.forEach((e=>{const n=this._node.getTop(e,t);Number.isFinite(n)&&(i=Math.min(i,n))})),i===1/0?0:i}return e&&this._node.getTop(e,t)||0}_getRowBottom(e,t,i=null){if(Array.isArray(e)){let n=-1/0;return e.forEach(((e,o)=>{const r=this._node.getBottom(e,t);let s=null;i?(s=i[o],!s&&e&&(s=this._getComputedStyleCached(e),i[o]=s)):e&&(s=this._getComputedStyleCached(e));const l=r+(s&&parseFloat(s.marginBottom)||0);Number.isFinite(l)&&(n=Math.max(n,l))})),n===-1/0?0:n}if(e){const i=this._node.getBottom(e,t)||0,n=this._getComputedStyleCached(e);return i+(parseFloat(n?.marginBottom)||0)}return 0}_scanGridLayout(e,t){const i=t.gridAutoFlow||"";if(!i.startsWith("row"))return{safe:!1,reason:`grid-auto-flow=${i}`};if(i.includes("dense"))return{safe:!1,reason:"grid-auto-flow dense not supported yet"};if("none"!==(t.gridTemplateAreas||"none"))return{safe:!1,reason:"grid-template-areas present"};const n=t.gridTemplateColumns||"",o=t.gridTemplateRows||"",r=e=>e.includes("subgrid")||e.includes("auto-fit")||e.includes("auto-fill")||e.includes("fit-content");if(r(n)||r(o))return{safe:!1,reason:"complex track sizing (subgrid/auto-fit/fit-content)"};return/\[.*?\]/.test(n)||/\[.*?\]/.test(o)?{safe:!1,reason:"named grid lines detected"}:{safe:!0}}}const on="background:#999;color:#FFF;padding: 0 4px;";class rn{constructor({config:e,DOM:t,node:i,selector:n}){this._debug=e.debugMode?{...e.debugConfig.pre}:{},this._DOM=t,this._selector=n,this._node=i,this._minPreFirstBlockLines=3,this._minPreLastBlockLines=3,this._minPreBreakableLines=this._minPreFirstBlockLines+this._minPreLastBlockLines,this._imageReductionRatio=.8,this._signpostHeight=parseFloat(e.splitLabelHeight)||0}split(e,t,i,n,o){const r=o||this._DOM.getComputedStyle(e),s=["%c_splitPreNode\n","color:white"];this._debug._&&console.group("%c_splitPreNode","background:cyan"),this._debug._&&console.log(...s,"node",e,{pageBottom:t,fullPageHeight:i});const l=this._node.getTop(e,n),a=this._DOM.getElementOffsetHeight(e),h=this._node.getLineHeight(e),c=this._node.getEmptyNodeHeightByProbe(e,"",!1);if(a1)return this._debug._&&console.log("%c END _splitPreNode TODO!",on),[];{if(this._DOM.isElementNode(d[0])){const e=d[0];return this._debug._&&console.warn("is Element Node",e),this._debug._&&console.log("%c END _splitPreNode ???????",on),[]}this._node.isWrappedTextNode(d[0])&&this._debug._&&console.warn(`is TEXT Node: ${d[0]}`);const n=d[0].wholeText,o=this._node.splitTextByLinesGreedy(n);if(o.length{const t=this._node.createWithFlagNoBreak();return this._DOM.setInnerHTML(t,e),t}));this._debug._&&console.log("linesFromNode",g),this._DOM.replaceNodeContentsWith(e,...g);const u=e=>isNaN(parseFloat(e))?0:parseFloat(e),p=u(r.borderTopWidth),_=u(r.borderBottomWidth),f=u(r.marginTop),m=u(r.marginBottom),b=(u(r.paddingTop),u(r.paddingBottom),0),w=-p-f+b,S=-_-m+b;let M=t-l-c+S; +//! For firstPartSpace we need all margins & preWrapperHeight. +//! For firstPartSpaceForSPlitting we only need selected amendments. +const P=i-c+w;this._debug._&&console.log({pageBottom:t,nodeTop:l,preWrapperHeight:c,topCutLineAmend:w,bottomCutLineAmend:S,fullPageHeight:i},{firstPartSpace:M,fullPageSpace:P});let C=0,O=[],T=M;const y=r.position;"relative"!=y&&this._DOM.setStyles(e,{position:"relative"});for(let t=0;tT&&(this._debug._&&console.log(`start a new page: ${n} > ${T}`,i),t&&O.push(t),t&&(C+=1),T=t?this._node.getTop(i,e)+P:P)}if(this._DOM.setStyles(e,{position:y}),!O.length)return this._debug._&&console.log("%c END _splitPreNode NO SPLIITERS",on),[];O.push(null),this._debug._&&console.log(...s,"splitters",O);const E=O.map(((t,i,n)=>{const o=this._DOM.cloneNodeWrapper(e);this._node.setFlagNoBreak(o);const r=n[i-1]||0,s=t||n[n.length];return this._DOM.insertAtEnd(o,...g.slice(r,s)),o}));return this._node.markSliceCuts(E),this._debug._&&console.log(...s,"newPreElementsArray",E),this._DOM.replaceNodeContentsWith(e,...E),this._DOM.setStyles(e,{display:"contents"}),this._DOM.setAttribute(e,"[slough-node]",""),this._DOM.removeAllClasses(e),this._debug._&&console.log("%c END _splitPreNode",on),this._debug._&&console.groupEnd(),E}}}class sn{constructor({config:e,DOM:t,selector:y}){this._config=e,this._DOM=t,this._selector=y,this._debug=e.debugMode?{...e.debugConfig.node}:{},this._assert=!!e.consoleAssert,this._markupDebugMode=this._config.markupDebugMode,Object.assign(this,i),Object.assign(this,n),Object.assign(this,o),Object.assign(this,r),Object.assign(this,s),Object.assign(this,l),Object.assign(this,a),Object.assign(this,h),Object.assign(this,c),Object.assign(this,d),Object.assign(this,g),Object.assign(this,u),Object.assign(this,p),Object.assign(this,_),Object.assign(this,f),Object.assign(this,m),Object.assign(this,b),Object.assign(this,w),Object.assign(this,S),Object.assign(this,M),Object.assign(this,P),Object.assign(this,C),Object.assign(this,O),Object.assign(this,T),this._paragraph=new qi({config:this._config,DOM:this._DOM,selector:this._selector,node:this}),this._pre=new rn({config:this._config,DOM:this._DOM,selector:this._selector,node:this}),this._table=new en({config:this._config,DOM:this._DOM,selector:this._selector,node:this}),this._grid=new nn({config:this._config,DOM:this._DOM,selector:this._selector,node:this}),this._tableLike=new tn({config:this._config,DOM:this._DOM,selector:this._selector,node:this})}clearTemplates(e){this._DOM.getAll("template",e).forEach((e=>this._DOM.removeNode(e)))}notSolved(e){this._DOM.getElementTagName(e);return!1}}function ln(e){return e?.length?e?.split(/\s+/).filter(Boolean):[]}const an="#66CC00",hn=`color: ${an};font-weight:bold`,cn=`border:1px solid ${an};background:#EEEEEE;color:${an};`,dn="background:#999;color:#FFF;padding: 0 4px;";class gn{constructor({config:e,DOM:t,node:n,selector:o,layout:r,referenceWidth:s,referenceHeight:l}){Object.assign(this,i),this._debug=e.debugMode?{...e.debugConfig.pages}:{},this._assert=!!e.consoleAssert,this._selector=o,this._node=n,this._noHangingSelectors=ln(e.noHangingSelectors),this._pageBreakBeforeSelectors=ln(e.pageBreakBeforeSelectors),this._pageBreakAfterSelectors=ln(e.pageBreakAfterSelectors),this._forcedPageBreakSelectors=ln(e.forcedPageBreakSelectors),this._noBreakSelectors=ln(e.noBreakSelectors),this._garbageSelectors=ln(e.garbageSelectors),this._DOM=t,this._root=r.root,this._contentFlow=r.contentFlow,this._referenceWidth=s,this._referenceHeight=l,this._minLeftLines=2,this._minDanglingLines=2,this._minBreakableLines=this._minLeftLines+this._minDanglingLines,this._minLeftRows=1,this._minDanglingRows=1,this._minBreakableRows=1,this._minPreFirstBlockLines=3,this._minPreLastBlockLines=3,this._minPreBreakableLines=this._minPreFirstBlockLines+this._minPreLastBlockLines,this._minBreakableGridRows=4,this._imageReductionRatio=.8,this._signpostHeight=parseFloat(e.splitLabelHeight)||0,this._commonLineHeight=this._node.getLineHeight(this._root),this._minimumBreakableHeight=this._commonLineHeight*this._minBreakableLines,this.pages=[]}calculate(){return this._removeGarbageElements(),this._prepareNoHangingElements(),this._prepareForcedPageBreakElements(),this._prepareNoBreakElements(),this._calculate(),this._debug._&&console.log("%c ✔ Pages.calculate()",cn,this.pages),this.pages}_removeGarbageElements(){if(this._garbageSelectors.length){this._DOM.getAll(this._garbageSelectors,this._contentFlow).forEach((e=>{this._DOM.removeNode(e)}))}}_prepareNoHangingElements(){if(this._noHangingSelectors.length){this._DOM.getAll(this._noHangingSelectors,this._contentFlow).forEach((e=>{this._node.setFlagNoHanging(e);const t=this._node.findLastChildParent(e,this._contentFlow);t&&this._node.setFlagNoHanging(t,"parent")}))}}_prepareNoBreakElements(){if(this._noBreakSelectors.length){this._DOM.getAll(this._noBreakSelectors,this._contentFlow).forEach((e=>this._node.setFlagNoBreak(e)))}}_prepareForcedPageBreakElements(){const e=this._pageBreakBeforeSelectors.length?this._DOM.getAll(this._pageBreakBeforeSelectors,this._contentFlow):[],t=this._pageBreakAfterSelectors.length?this._DOM.getAll(this._pageBreakAfterSelectors,this._contentFlow):[],i=this._DOM.getAll(this._forcedPageBreakSelectors,this._contentFlow);if(e.length){const t=e[0],i=this._node.findFirstChildParent(t,this._contentFlow)||t;this._node.isAfterContentFlowStart(i)&&e.shift()}if(t.length){const e=t.at(-1),i=this._node.findLastChildParent(e,this._contentFlow)||e,n=this._DOM.getRightNeighbor(i);this._node.isContentFlowEnd(n)&&t.pop()}e.length&&e.forEach((e=>{const t=this._node.findBetterForcedPageStarter(e,this._contentFlow);t&&this._DOM.insertBefore(t,this._node.createForcedPageBreak())})),i&&i.forEach((e=>{if(!this._node.isForcedPageBreak(e)){const t=this._node.findBetterForcedPageStarter(e,this._contentFlow);t&&this._DOM.insertBefore(t,this._node.createForcedPageBreak())}})),t.length&&t.forEach((e=>{const t=this._node.findLastChildParent(e,this._contentFlow);t&&(e=t),this._node.isForcedPageBreak(e.nextElementSibling)||this._DOM.insertAfter(e,this._node.createForcedPageBreak())}))}_registerFirstPage(){this._registerPageStart(this._DOM.getElement(this._selector.contentFlowStart,this._contentFlow))}_isContentFlowShort(){const e=this._DOM.getElement(this._selector.contentFlowEnd,this._contentFlow),t=this._node.getBottom(e,this._root),i=tthis._registerPageStart(e)))}_calculate(){if(this._debug._&&console.groupCollapsed("•• init data ••"),this._debug._&&console.log("this._referenceHeight",this._referenceHeight,"\n","this._noHangingSelectors",this._noHangingSelectors,"\n","this._pageBreakBeforeSelectors",this._pageBreakBeforeSelectors,"\n","this._pageBreakAfterSelectors",this._pageBreakAfterSelectors,"\n","this._forcedPageBreakSelectors",this._forcedPageBreakSelectors,"\n","this._noBreakSelectors",this._noBreakSelectors),this._debug._&&console.groupEnd("•• init data ••"),this._registerFirstPage(),this._isContentFlowShort())return void this._resolveForcedPBInsideContentFlow();const e=this._node.getPreparedChildren(this._contentFlow);this._debug._&&console.groupCollapsed("%c🚸 children(contentFlow)",cn),this._debug._&&console.log(e),this._debug._&&console.groupEnd("%c🚸 children(contentFlow)",cn),this._parseNodes({array:e})}_registerPageStart(e,t=!1){if(this._debug._registerPageStart&&console.log("%c📍","background:yellow;font-weight:bold","\n improveResult:",t,"\n passed pageStart:",e),this._node.isPageStartElement(e))return;t&&(e=this._node.findBetterPageStart(e,this.pages.at(-1)?.pageStart,this._root)),this._DOM.getElementOffsetParent(e)||this._debug._registerPageStart&&console.warn("🚨 pageStart has no offsetParent. Check the caller.",e);const i=this._node.getTopForPageStartCandidate(e,this._root),n=i+this._referenceHeight,o=this._DOM.getLeftNeighbor(e);this.pages.push({pageStart:e,pageBottom:n,pageTop:i,prevPageEnd:o}),this._node.markPageStartElement(e,this.pages.length),this._debug._registerPageStart&&console.log(`%c📍register page ${this.pages.length}`,"background:yellow;font-weight:bold","\n improved result:",t,"\n pageTop:",i,"\n pageBottom:",n,"\n pageStart:",e)}_parseNodes({array:e,previous:t,next:i,parent:n,parentBottom:o}){this._debug._parseNodes&&console.log("🔵 _parseNodes",{array:e,parent:n});for(let r=0;r"),"📄",this.pages.length,{currentElement:n}),this._debug._parseNode&&console.log({previousElement:i,currentElement:n,nextElement:o,isFirstChild:e,isLastChild:t,parent:r,tracedParent:s,parentBottom:l}),!o)return this._node.markProcessed(n,"content-flow-end"),this._debug._parseNode&&console.log("%c END _parseNode (!nextElement)",dn),void(this._debug._parseNode&&console.groupEnd());let h=this.pages.at(-1).pageBottom;const c=()=>{h!==this.pages.at(-1).pageBottom&&this._debug._parseNode&&console.log(`🔄 refreshPageBottom to ${this.pages.at(-1).pageBottom}`),h=this.pages.at(-1).pageBottom},d=(e,t=!1)=>{this._registerPageStart(e,t),c()},g=this._node.getBottomWithMargin(n,this._root);let u=l;if(r&&void 0!==l){const e=this._node.getBottomWithMargin(r,this._root);void 0!==e&&(u=e)}const p=(l=u)??g;let _=l;const f=this._node.getTop(n,this._root);if(void 0!==l&&l-g>=this._referenceHeight){if(_=void 0,this._debug._parseNode&&console.log("🪁 Tail: We got a tail from the lower shells of the last child. Giving up our “last child” rule here and will try to insert a page break at the end of some parent. ",{parentBottom:l,currentParentBottom:_,currentElementBottom:g,newPageBottom:h},{currentElement:n,parent:r}),g<=h){this._debug._parseNode&&console.log("🪁 Tail: currentElementBottom <= newPageBottom");const e=[];let t=n;for(this._debug._parseNode&&console.log("🪁 Tail: currentElement",n);t&&t!==r;)e.push({element:t,bottom:this._node.getBottomWithMargin(t,this._root)}),t=t.parentElement;if(t!==r)throw new Error("parent not found in the ancestor chain");e.push({element:r,bottom:l}),this._debug._parseNode&&console.log("🪁 Tail: _parents",e);let i=h;this._debug._parseNode&&console.log("🪁 Tail: _currentPageBottom = newPageBottom",i);for(let t=0;ti){this._debug._parseNode&&console.log("🪁 Tail: _parents[i].bottom > _currentPageBottom",e[t].bottom,">",i,e[t].element);const n=this._node.createNeutral();n.classList.add("service"),this._DOM.insertAtEnd(e[t].element,n),d(n),this._debug._parseNode&&console.log("_registerPageStart",n),this._node.markProcessed(n,"node is ForcedPageBreak");const o=this.pages.at(-1).pageBottom;if(this._debug._parseNode&&console.log(i,o,l),!(l>o))return this._debug._parseNode&&console.log("%c END _parseNode (bottom Tail of parents)",dn),void(this._debug._parseNode&&console.groupEnd());this._debug._&&console.log("🧧 • parentBottom > justUpdatedPageBottom"),i=o,this._debug._parseNode&&console.log("new _currentPageBottom",i)}return this._debug._parseNode&&console.log("%c END _parseNode (bottom Tail of parents)",dn),void(this._debug._parseNode&&console.groupEnd())}this._debug._parseNode&&console.log("🪁 Tail: currentElementBottom > newPageBottom","DOING NOTHING")} +//! currentParentBottom is refreshed right before, so descendants see live parent boundaries. +//! Using ?? avoids treating 0 as falsy, unlike the previous || variant. +const m=_??g;if(this._debug._parseNode&&console.log("[_parseNode]",{currentBlockBottom:m,currentParentBottom:_,currentElementBottom:g}),this.pages.at(-1).pageStart===n&&(this._node.isNoBreak(n)||m<=h))return this._node.markProcessed(n,"node is already registered and fits in the page"),this._debug._parseNode&&console.log("%c END _parseNode (node is already registered and fits in the next page)",dn),void(this._debug._parseNode&&console.groupEnd());if(f>=h&&g-f){const t=e&&Boolean(r)?this._node.getTopForPageStartCandidate(r,this._root):void 0,i=Boolean(t)&&f-t>=this._referenceHeight;if(i)this._debug._parseNode&&console.log("🪁 beginning Tail",{parentTop:t,currentParentBottom:_,currentElementTop:f,newPageBottom:h},{currentElement:n,parent:r});else{const e=this._DOM.getComputedStyle(n)?.display||"";if(e.includes("inline")||"contents"===e)return this._debug._parseNode&&console.log("🧅 current in thin wrapper"),d(n,!0),this._debug._parseNode&&console.log("%c END _parseNode (registered new page start)",dn),void(this._debug._parseNode&&console.groupEnd())}d(n,!i)}if(this._node.isForcedPageBreak(n))return d(n),this._node.markProcessed(n,"node is ForcedPageBreak"),this._debug._parseNode&&console.log("%c END _parseNode (isForcedPageBreak)",dn),void(this._debug._parseNode&&console.groupEnd());this.strictAssert(this._DOM.getElementOffsetParent(n),"it is expected that the element has an offset parent",n);const b=this._node.getTop(o,this._root);if(this._debug._parseNode&&console.log(...a,"• newPageBottom",h,"\n","• nextElementTop",b),b<=h)return this._debug._parseNode&&console.log("nextElementTop <= newPageBottom",b,"<=",h),this._node.markProcessed(n,"node fits"),this._node.findAllForcedPageBreakInside(n).forEach((e=>{this._node.markProcessed(e,"node is ForcedPageBreak (inside a node that fits)"),d(e)})),this._debug._parseNode&&console.log("%c END _parseNode (node pass)",dn),void(this._debug._parseNode&&console.groupEnd());{if(this._debug._parseNode&&console.log("nextElementTop > newPageBottom",b,">",h),m<=h)return this._debug._parseNode&&console.log("currentBlockBottom <= newPageBottom",m,"<=",h,"\n register nextElement as pageStart"),this._node.isNoHanging(n)?(this._debug._parseNode&&console.log("currentElement fits / last, and _isNoHanging => move it to the next page"),this._node.markProcessed(n,"it fits & last & _isNoHanging => move it to the next page"),d(n,!0),this._debug._parseNode&&console.log("%c END _parseNode (isNoHanging)",dn),void(this._debug._parseNode&&console.groupEnd())):(d(o),this._node.markProcessed(n,"fits, its bottom falls exactly on the cut"),this._node.markProcessed(o,"starts new page, its top is exactly on the cut"),this._debug._parseNode&&console.log("%c END _parseNode (currentElement fits, register the next element)",dn),void(this._debug._parseNode&&console.groupEnd()));const t=this._node.resolveReplacedElement(n,{prefer:"first"});if(t){const i=this._node.isSVG(t),s=i?this._node.createSignpost(t):t,a=this._node.getTop(s,this._root),c=e&&r?this._node.getTop(r,this._root):void 0,g=this._node.estimateInlineImgGapBelow(r); +//! let availableImageNodeSpace = newPageBottom - (parentTopForImage ?? currentImageTop); +let u=h-a-g;u-=l?l-this._node.getBottom(s,this._root):0;let p=this._referenceHeight-g-(void 0!==c?a-c:0);const f=this._DOM.getElementOffsetHeight(s),m=this._DOM.getElementOffsetWidth(s);if(this._debug._parseNode&&console.log("🖼️🖼️🖼️🖼️🖼️🖼️\n",`H-space: ${u}, image Height: ${f}, image Width: ${m}`,n,"\n parent",r,"parentBottom",l,"currentParentBottom",_),m>this._referenceWidth&&this._debug._parseNode&&console.warn("%c IMAGE is too wide","color: red"),fthis._imageReductionRatio)return this._debug._parseNode&&console.log("Register next elements; 🖼️🖼️🖼️ IMG RESIZE to availableImageNodeSpace:",u,n),this._node.markProcessed(n,`IMG with ratio ${b}, and next starts on next`),this._node.fitElementWithinBoundaries({element:t,height:f,width:m,vspace:u,hspace:this._referenceWidth}),!this._node.isContentFlowEnd(o)&&d(o),this._debug._parseNode&&console.log("%c END _parseNode 🖼️ IMG scaled",dn),void(this._debug._parseNode&&console.groupEnd());this._node.markProcessed(n,"IMG starts on next");return d(i?s:t,!0),this._debug._parseNode&&console.log("🖼️ register Page Start",n),f>p&&(this._node.fitElementWithinBoundaries({element:t,height:f,width:m,vspace:p,hspace:this._referenceWidth}),this._node.markProcessed(n,"IMG starts on next and resized"),this._debug._parseNode&&console.log("🖼️ ..and fit it to full page",n)),this._debug._parseNode&&console.log("%c END",dn),void(this._debug._parseNode&&console.groupEnd())}if(n.style.height){this._debug._parseNode&&console.log("🥁 currentElement has HEIGHT",n.style.height);const e=h-f,t=b-f,i=e/t,r=this._referenceHeight/t;return this._debug._parseNode&&console.log("\n🥁 currentElementTop",f,"\n🥁 newPageBottom",h,"\n🥁 availableSpace",e,"\n🥁 currentElementContextualHeight",t,"\n🥁 availableSpaceFactor",i,"\n🥁 fullPageFactor",r),this.strictAssert(i<1),i>.8?(this._debug._parseNode&&console.log("🥁 availableSpaceFactor > 0.8: ",i),this._DOM.setStyles(n,{transform:`scale(${i})`,"transform-origin":"top center"}),d(o),this._node.markProcessed(n,"processed as a image, has been scaled down within 20%, the next one starts a new page"),this._node.markProcessed(o,"the previous one was scaled down within 20%, and this one starts a new page."),this._debug._parseNode&&console.log("%c END _parseNode (has height & scale)",dn),void(this._debug._parseNode&&console.groupEnd())):(r<1&&(this._debug._parseNode&&console.log("🥁 fullPageFactor < 1: ",r),this._node.markProcessed(n,"processed as a image, has been scaled down, and starts new page"),this._DOM.setStyles(n,{transform:`scale(${r})`,"transform-origin":"top center"})),this._debug._parseNode&&console.log("🥁 _registerPageStart",n),d(n,!0),this._node.markProcessed(n,"processed as a image, starts new page"),this._debug._parseNode&&console.log("%c END _parseNode (has height & put on next page)",dn),void(this._debug._parseNode&&console.groupEnd()))}if(this._debug._parseNode&&console.log("split or not? \n","currentBlockBottom",m),this._debug._parseNode&&console.log("currentParentBottom || currentElementBottom",{currentParentBottom:_,currentElementBottom:g},"currentBlockBottom > newPageBottom",m,">",h),this._DOM.getElementOffsetHeight(n)h?h/d:1;this._DOM.removeNode(r),l>.2*s&&console.warn("It seems that your custom header is too high"),a>.15*s&&console.warn("It seems that your custom footer is too high"),g<1&&console.warn("It seems that your frontpage content is too large. We made it smaller to fit on the page. Check out how it looks! It might make sense to fix this with styles or reduce the text amount."),this._paperHeight=s,this.headerHeight=l,this.footerHeight=a,this.bodyHeight=h,this.bodyWidth=c,this._frontpageFactor=g}}function pn({maskStep:e,maskWindow:t,maskFirstShift:i}){return`\n -webkit-mask-image: linear-gradient(\n black 0,\n black ${t}px,\n transparent ${t}px,\n transparent ${e}px\n );\n mask-image: linear-gradient(\n black 0,\n black ${t}px,\n transparent ${t}px,\n transparent ${e}px\n );\n -webkit-mask-repeat: no-repeat;\n mask-repeat: no-repeat;\n -webkit-mask-size: 100% ${e}px;\n mask-size: 100% ${e}px;\n -webkit-mask-position: 100% ${i}px;\n mask-position: 100% ${i}px;\n -webkit-mask-repeat: repeat-y;\n mask-repeat: repeat-y;\n -webkit-mask-origin: border-box;\n mask-origin: border-box;\n `}class _n{constructor({config:e,DOM:t,selector:n,node:o,pages:r,layout:s,paper:l}){this._config=e,this._debug=e.debugMode?{...e.debugConfig.preview}:{},this._assert=!!e.consoleAssert,Object.assign(this,i),this._DOM=t,this._selector=n,this._node=o,this._virtualPaperGapSelector=n.virtualPaperGap,this._runningSafetySelector=n.runningSafety,this._printPageBreakSelector=n.printPageBreak,this._pageDivider=n.pageDivider,this._virtualPaper=n.virtualPaper,this._virtualPaperTopMargin=n.virtualPaperTopMargin,this._paperBody=n.paperBody,this._pages=r,this._root=s.root,this._contentFlow=s.contentFlow,this._paperFlow=s.paperFlow,this._paper=l,this._hasFrontPage=!!s.frontpageTemplate}create(){this._processFirstPage(),this._processOtherPages(),(!0===this._config.mask||"true"===this._config.mask)&&this._addMask(),this._makeRootVisible()}_addMask(){const e=parseInt(this._config.virtualPagesGap),t=parseInt(this._config.printHeight),i=parseInt(this._config.printTopMargin),n=parseInt(this._config.printBottomMargin),o=parseInt(this._config.headerMargin),r=parseInt(this._config.footerMargin),s=this._paper.headerHeight,l=this._paper.footerHeight,a=this._paper.bodyHeight,h=s?Math.ceil(o/2):0,c=l?Math.ceil(r/2):0,d=s-h,g=l-c,u=a+h+c;this.strictAssert(t===u+d+i+g+n,"Paper size calculation params do not match");const p=pn({maskFirstShift:i+d,maskStep:t+e,maskWindow:u}),_=pn({maskFirstShift:d,maskStep:t-i-n,maskWindow:u}),f=`\n ${this._selector.contentFlow} {\n ${p}\n }\n @media print{\n ${this._selector.contentFlow} {\n ${_}\n }\n }`;this._node.insertStyle(f,"mask")}_makeRootVisible(){this._DOM.setStyles(this._root,{visibility:"visible"})}_processFirstPage(){let e;if(this._hasFrontPage){const t=this._insertFrontpageSpacer(this._contentFlow,this._paper.bodyHeight);this._pages.unshift({pageStart:t}),e=this._paper.createFrontpage({currentPage:1,totalPages:this._pages.length})}else e=this._paper.create({currentPage:1,totalPages:this._pages.length});this._insertIntoPaperFlow(e),this._insertIntoContentFlow(0)}_processOtherPages(){for(let e=1;e0,`[preview] There is no page end element before ${e}. Perhaps it's a 'beginningTail'.`),t?this._DOM.setStyles(t,{"margin-top":["0","important"]}):this.strictAssert(0,"[preview] [_preventPageOverflow] current page First Element do not pass! page:",e)}_createPageBreaker(e,t){const i=this._node.create(this._pageDivider);return this._DOM.setAttribute(i,"[page]",`${e+1}`),t&&this._paper.footerHeight&&this._DOM.setStyles(i,{marginTop:this._paper.footerHeight-1+"px"}),this._paper.headerHeight&&this._DOM.setStyles(i,{paddingBottom:this._paper.headerHeight-1+"px"}),i}_updatePageStartElementAttrValue(e,t){this._hasFrontPage&&this._node.markPageStartElement(e,`${t+1}`)}_insertPaper(e,t,i){i?this._DOM.insertAtEnd(e,i,t):this._DOM.insertAtEnd(e,t)}_createVirtualPaperGap(){return this._node.create(this._virtualPaperGapSelector)}_createVirtualPaperTopMargin(){return this._paper.createVirtualTopMargin()}_createVirtualPaperBottomMargin(){return this._paper.createVirtualBottomMargin()}_insertFrontpageSpacer(e,t){const i=this._node.create();return this._DOM.setStyles(i,{paddingBottom:t+"px"}),this._DOM.setAttribute(i,".printFrontpageSpacer"),this._DOM.insertAtStart(e,i),i}_insertHeaderSpacer(e,t){const i=this._DOM.createDocumentFragment(),n=this._node.create(this._runningSafetySelector);this._DOM.insertAtEnd(i,this._createVirtualPaperTopMargin(),n),this._DOM.insertAtEnd(e,i)}_insertFooterSpacer(e,t,i){const n=this._DOM.createDocumentFragment(),o=this._createVirtualPaperGap(),r=this._node.create(this._runningSafetySelector);this._DOM.insertAtEnd(n,r,this._createVirtualPaperBottomMargin(),this._node.create(this._printPageBreakSelector),o),this._DOM.insertAtStart(e,n),this._balanceFooter(r,o,i)}_balanceFooter(e,t,i){const n=this._node.getTop(i,this._root)-this._node.getTop(t,this._root);this._DOM.setStyles(e,{"margin-bottom":n+"px"}),this.strictAssert(n>=0,`balancer is negative: ${n} < 0`,t)}}class fn{constructor({config:e,DOM:t,selector:i,node:n,layout:o}){this._globalDebugMode=e.debugMode,this._debug=e.debugMode?{...e.debugConfig.toc}:{},this._assert=!!e.consoleAssert,this._DOM=t,this._node=n,this._tocPageNumberSelector=e.tocPageNumberSelector,this._root=o.root,this._contentFlow=o.contentFlow,this._pageDividerSelector=i.pageDivider}render(){this._globalDebugMode&&console.time("Processing TOC"),this._debug._&&console.log(`\n📑 TOC: I am here!\n\ntocPageNumberSelector:\n • ${this._tocPageNumberSelector}\n pageDividerSelector:\n • ${this._pageDividerSelector}\n `);const e=this._DOM.getAll(this._tocPageNumberSelector,this._contentFlow);if(this._debug._&&console.log("📑 tocPageNumberBoxes",e.length),!e.length)return void(this._debug._&&console.log("📑 no valid toc"));const t=this._DOM.getAll(this._pageDividerSelector,this._contentFlow).reduce(((e,t,i)=>{const n=this._node.getTop(t,this._root)-1,o=this._DOM.getAttribute(t,"[page]");return e[n]=o,e}),{});this._debug._&&console.log("📑 dataFromPagesMarkers",t);const i=e.reduce(((e,t)=>{const i=this._DOM.getDataId(t),n=this._DOM.getElementById(i),o=this._node.getTop(n,this._root);return e[o]={box:t,id:i,targetTop:o},e}),{});this._debug._&&console.log("📑 dataFromTOC",i);const n={...t,...i};let o=0;this._debug._&&console.groupCollapsed("Processing obj");for(const e in n){const t=n[e];this._debug._&&console.log(`Processing ${e}: ${t}`),"string"==typeof t?o=t:(t.page=o,this._DOM.setInnerHTML(t.box,o))}this._debug._&&console.groupEnd("Processing obj"),this._debug._&&console.log("📑 tocObject",n),this._globalDebugMode&&console.timeEnd("Processing TOC")}}class mn{constructor({config:e,DOM:t,selector:n,node:o,layout:r}){this._config=e,this._selector=n,this._DOM=t,this._node=o,this._layout=r,this._root=r.root,this._assert=!!e.consoleAssert,Object.assign(this,i)}init(){this._config.debugMode&&console.log("🐙 i am Validator!");const e=`${this._selector.paperFlow} ${this._selector.virtualPaperGap}`,t=`${this._selector.contentFlow} ${this._selector.virtualPaperGap}`,i=[...this._DOM.getAllElements(e)],n=[...this._DOM.getAllElements(t)],o=i.map((e=>this._node.getTop(e))),r=n.map((e=>this._node.getTop(e,this._root))),s=o.reduce(((e,t,i)=>(t!==r[i]&&e.push(i+1),e)),[]);this.strictAssert(!s.length,"Problems with preview generation on the following pages: ",s)}}const bn="border:1px dashed #cccccc;background:#ffffff;color:#cccccc;";class wn{constructor(e){this._debugMode=e.debugMode,this._preloader,this._preloaderTarget=document.querySelector(e.preloaderTarget)||document.body,this._preloaderBackground=e.preloaderBackground||"white"}create(){this._debugMode&&console.groupCollapsed("%c Preloader ",bn),this._insertStyle(),this._preloader=document.createElement("div"),this._preloader.classList.add("lds-dual-ring"),this._preloaderTarget.append(this._preloader),this._debugMode&&console.groupEnd("%c Preloader ",bn)}remove(){if(!this._preloader)return;let e=1;const t=setInterval((()=>{e<=.1&&(clearInterval(t),this._preloader.remove()),this._preloader.style.opacity=e,e-=.1*e}),50);this._debugMode&&console.log("%c Preloader removed ",bn)}_insertStyle(){const e=document.querySelector("head"),t=document.createElement("style");t.append(document.createTextNode(this._css())),t.setAttribute("data-preloader-style",""),e.append(t)}_css(){return`\n /* PRELOADER */\n .lds-dual-ring {\n position: absolute;\n z-index: 99999;\n top: 0; left: 0; bottom: 0; right: 0;\n background: ${this._preloaderBackground};\n display: flex;\n justify-content: center;\n align-items: center;\n }\n /*\n .lds-dual-ring:after {\n content: " ";\n display: block;\n width: 64px;\n height: 64px;\n margin: 8px;\n border-radius: 50%;\n border: 6px solid #eee;\n border-color: #eee transparent #eee transparent;\n animation: lds-dual-ring 1.2s linear infinite;\n }\n @keyframes lds-dual-ring {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n */\n `}}class Sn{constructor(e){this._debugMode=e.debugMode}run(){let e=[...document.querySelectorAll("object")];this._debugMode&&console.log(e);let t=[];return e.forEach((e=>{const i=new Promise((t=>{e.addEventListener("load",(i=>{this._debugMode&&console.log("⏰ EVENT: object load",e.clientHeight,e.clientWidth,e),t()}))}));t.push(i)})),Promise.all(t)}}const Mn="color:Gray;border:1px solid;";console.info("[HTML2PDF4DOC] Version:","0.2.3");const Pn=document.currentScript.dataset,Cn=new class{constructor(e){this.params=e,this.debugMode=e.debugMode,this.preloader=e.preloader,this.selector=y,this.config}async render(){console.time("[HTML2PDF4DOC] Total time"),this.debugMode&&console.log("🏁 document.readyState",document.readyState),document.addEventListener("readystatechange",(e=>{this.debugMode&&console.log("🏁 readystatechange",document.readyState)})),this.debugMode&&console.time("⏱️ await DOMContentLoaded time"),await new Promise((e=>{window.addEventListener("DOMContentLoaded",(t=>{this.debugMode&&console.log("⏰ EVENT: DOMContentLoaded"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await DOMContentLoaded time"),this.debugMode&&console.time("⏱️ create Preloader time");const e=new wn(this.params);"true"===this.preloader&&e.create(),this.debugMode&&console.timeEnd("⏱️ create Preloader time"),this.debugMode&&console.time("⏱️ Config time"),this.debugMode&&console.groupCollapsed("%c config ",Mn+"color:LightGray"),this.config={...E(this.params),debugConfig:D},this.debugMode&&console.groupEnd(),this.debugMode&&console.info("⚙️ Current config with debugConfig:",this.config),this.debugMode&&console.timeEnd("⏱️ Config time"),this.config.consoleAssert&&console.info("🧧 Assertions enabled."),this.debugMode&&console.time("⏱️ DOM helpers init time");const t=new N({DOM:window.document,config:this.config});this.debugMode&&console.timeEnd("⏱️ DOM helpers init time"),this.debugMode&&console.time("⏱️ node helpers init time");const i=new sn({config:this.config,DOM:t,selector:this.selector});this.debugMode&&console.timeEnd("⏱️ node helpers init time"),this.debugMode&&console.time("⏱️ await window load time"),await new Promise((e=>{window.addEventListener("load",(t=>{this.debugMode&&console.log("⏰ EVENT: window load"),e()}))})),this.debugMode&&console.timeEnd("⏱️ await window load time"),this.debugMode&&console.time("⏱️ Layout time"),this.debugMode&&console.groupCollapsed("%c Layout ",Mn);const n=new H({config:this.config,DOM:t,selector:this.selector,node:i});if(n.create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Layout time"),!n.success)return void(this.debugMode&&console.error("Failed to create layout.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.info("%c calculate Paper params ",Mn),this.debugMode&&console.time("⏱️ Paper time");const o=new un({config:this.config,DOM:t,selector:this.selector,node:i,layout:n});if(this.debugMode&&console.timeEnd("⏱️ Paper time"),!o||!o.bodyHeight||!o.bodyWidth)return void(this.debugMode&&console.error("Failed to create paper calculations.\n\nWe have to interrupt the process of creating PDF preview."));this.debugMode&&console.time("⏱️ Preprocess time"),this.debugMode&&console.groupCollapsed("%c Preprocess ",Mn),await new Sn(this.config).run(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preprocess time"),this.debugMode&&console.time("⏱️ Pages time"),this.debugMode&&console.group("%c Pages ",Mn);const r=new gn({config:this.config,DOM:t,selector:this.selector,node:i,layout:n,referenceHeight:o.bodyHeight,referenceWidth:o.bodyWidth}).calculate();this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Pages time"),this.debugMode&&console.time("⏱️ Preview time"),this.debugMode&&console.groupCollapsed("%c Preview ",Mn),new _n({config:this.config,DOM:t,selector:this.selector,node:i,layout:n,paper:o,pages:r}).create(),this.debugMode&&console.groupEnd(),this.debugMode&&console.timeEnd("⏱️ Preview time"),this.debugMode&&console.time("⏱️ Toc time"),new fn({config:this.config,DOM:t,selector:this.selector,node:i,layout:n}).render(),this.debugMode&&console.timeEnd("⏱️ Toc time"),this.debugMode&&console.time("⏱️ Validator time"),new mn({config:this.config,DOM:t,selector:this.selector,node:i,layout:n}).init(),this.debugMode&&console.timeEnd("⏱️ Validator time"),t.setAttribute(n.root,"[success]"),t.setAttribute(n.root,"[pages]",r.length),e.remove(),console.info("[HTML2PDF4DOC] Page count:",r.length),console.timeEnd("[HTML2PDF4DOC] Total time")}}(Pn),On="manual"===Pn.init;function Tn(){On&&Cn.render()}On&&console.info("HTML2PDF4DOC in manual initialization mode"),!On&&Cn.render(),HTML2PDF4DOC=t})(); \ No newline at end of file diff --git a/submodules/html2pdf b/submodules/html2pdf index ac37635..1c718cb 160000 --- a/submodules/html2pdf +++ b/submodules/html2pdf @@ -1 +1 @@ -Subproject commit ac3763504fea6e6cbf91d85f91d8cbe27289a206 +Subproject commit 1c718cb0d746712ce9f18a2b658e9e6082aecefe diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/autogen.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/autogen.css new file mode 100644 index 0000000..3224e74 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/autogen.css @@ -0,0 +1,257 @@ +/* A wrapper for styling the markup generated by MarkupRenderer. */ + +sdoc-autogen { + /* + TODO: 'display: contents;' + Turn this back on when the bug is fixed: + Selenium cannot detect text inside a container + with the 'display: contents;' directive + */ + /* display: contents; */ + + /* hyphens: auto; */ + + --autogen-v-rhythm: calc(var(--base-rhythm, 8px) * 2); +} + +sdoc-autogen a, +sdoc-autogen a:link, +sdoc-autogen a:visited { + text-decoration: underline; +} + +/* Table */ + +sdoc-autogen table { + border-collapse: collapse; + margin: var(--base-padding) 0; + font-size: 1rem; + + /*** add scroll for wide tables */ + /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + /* border: 1px solid #ccc; */ + border: none; + display: block; + overflow-x: auto; + white-space: nowrap; +} + +sdoc-autogen table caption { + font-weight: bold; + padding-bottom: 1rem; +} + +sdoc-autogen table th { + background-color: var(--color-bg-main); +} + +sdoc-autogen table th, +sdoc-autogen table td { + padding: var(--base-rhythm) calc(var(--base-rhythm) * 1.5); + vertical-align: top; + text-align: left; + border: 1px solid #ccc; + + /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + /*** add scroll for wide tables (unset) */ + white-space: initial; +} + +/* Typography */ + +sdoc-autogen p { + margin: var(--autogen-v-rhythm) 0; +} + +/* blockquote */ + +sdoc-autogen blockquote { + color: #666; + padding: .25em 0 0.25em 1rem; + border-left: 4px solid #ccc; + margin: var(--autogen-v-rhythm) 0; +} + +/* pre.code */ + +sdoc-autogen pre.code { + font-family: var(--code-font-family); + + font-size: var(--code-font-size); + line-height: 2; + margin: var(--code-font-size) 0; + padding: calc(var(--code-font-size)*1) + calc(var(--code-font-size)*1) + calc(var(--code-font-size)*1) + calc(var(--code-font-size)*2); + + overflow: auto; + background-color: var(--color-bg-main); + border: 1px solid var(--color-border); +} + +/* We have to override this for the print version because the printer + interprets scroll-bars differently in different environments, + which breaks HTML2PDF. + Also, we need to show the whole code in its entirety. + */ +[html2pdf] sdoc-autogen pre.code { + overflow: unset; + white-space: pre-wrap; + overflow-wrap: break-word; +} + +/* ``some text`` is generated into: by docutils. */ +sdoc-autogen tt.literal { + position: relative; + padding: 0 4px; + font-style: normal; + font-family: var(--code-font-family); + font-size: var(--code-font-size); + background-color: var(--color-bg-main); + border: 1px solid var(--color-border); + border-radius: 4px; + + overflow-wrap: break-word; + word-wrap: break-word; + -webkit-box-decoration-break: clone; + box-decoration-break: clone; +} + +/* ul */ + +sdoc-autogen ul, +sdoc-autogen ol { + padding-left: 1.6em; + margin: var(--autogen-v-rhythm) 0; +} + +/* list in table */ +sdoc-autogen td ul, +sdoc-autogen dt ol { + margin: 0; + padding-left: 1em; +} + +/* object */ + +sdoc-autogen img, +sdoc-autogen object { + max-width: 100%; + height: auto; + padding: 1em; + background: var(--color-bg-contrast); +} + +/* + ************************** + automatically added by RST + ************************** +*/ + +div.document { + /* alarm style for detecting unwrapped blocks */ + border: 1px dashed red; +} + +sdoc-autogen div.document { + display: contents; + border: none; +} + +/* block margins */ + +sdoc-autogen .document > *:first-child, /* RST */ +sdoc-autogen > *:first-child { + margin-top: 0 !important; +} + +sdoc-autogen .document > *:last-child, /* RST */ +sdoc-autogen > *:last-child { + margin-bottom: 0 !important; +} + +/* admonition by RST */ +/* "attention", "caution", "danger", "error", "hint", "important", "note", "tip", "warning" */ + +sdoc-autogen .admonition { + display: block; + overflow: hidden; + padding: 0 var(--autogen-v-rhythm); + border: var(--requirement-border-width, 1px) solid; + border-radius: var(--requirement-border-radius); + margin: var(--autogen-v-rhythm) 0; + color: var(--color-fg-main); +} + +sdoc-autogen .admonition .admonition-title { + margin: 0; + padding-top: calc(0.5 * var(--base-rhythm)); + padding-bottom: calc(0.5 * var(--base-rhythm)); + color: currentColor; + font-weight: 600; + position: relative; +} + +sdoc-autogen .admonition .admonition-title::after { + content: ''; + position: absolute; + top: 0; bottom: 0; + left: calc(-1 * var(--autogen-v-rhythm)); + right: calc(-1 * var(--autogen-v-rhythm)); + /* background:repeating-linear-gradient( + -45deg, + rgba(255, 255, 255, .25), + rgba(255, 255, 255, .25) 10px, + rgba(255, 255, 255, .0) 10px, + rgba(255, 255, 255, .0) 20px + ); */ + background-color: currentColor; + opacity: 0.1; +} + +sdoc-autogen .admonition > *:not(.admonition-title) { + color: var(--color-fg-main); +} + +sdoc-autogen .admonition.attention { + color: Crimson; +} + +sdoc-autogen .admonition.caution { + color: Crimson; +} + +sdoc-autogen .admonition.important { + color: OrangeRed; +} + +sdoc-autogen .admonition.danger { + color: red; +} + +sdoc-autogen .admonition.error { + color: Red; +} + +sdoc-autogen .admonition.warning { + color: DarkOrange; +} + +sdoc-autogen .admonition.warning .admonition-title::before { + /* content: '⚠️'; */ + margin-right: var(--base-rhythm); +} + +sdoc-autogen .admonition.note { + /* color: CornflowerBlue; */ + color: SteelBlue; +} + +sdoc-autogen .admonition.hint { + color: DarkSlateBlue; +} + +sdoc-autogen .admonition.tip { + color: MediumSlateBlue; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/base.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/base.css new file mode 100644 index 0000000..6471e25 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/base.css @@ -0,0 +1,154 @@ +/* @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@400;500;600;700&family=Noto+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap'); */ + +/* .test-content {} */ + +:root { + + --color-bg-main: #F2F5F9; + --color-fg-main: #444; + + --color-bg-contrast: #fff; + --color-fg-contrast: #000; + + --color-fg-accent: rgb(242, 100, 42); + --color-bg-accent: rgb(242 100 42 / 10%); + + --color-accent: #274466; + --color-highlight: rgb(255, 255, 200); + --color-highlight-secondary: rgb(230, 236, 242); + + --color-fg-secondary: rgba(0, 0, 0, .5); + --color-bg-secondary: rgba(0, 0, 0, .025); + + --color-fg-secondary-invert: rgb(255 255 255 / 50%); + --color-bg-secondary-invert: rgb(0 0 0 / 10%); + + --color-bg-ui: #282c42; + + --color-red: rgb(200, 0, 0); + --color-blue: rgb(50, 100, 200); + --color-green: rgb(0, 100, 100); + + --color-danger: var(--color-red); + --color-cancel: var(--color-fg-secondary); + --color-submit: var(--color-action); + + --color-link: var(--color-fg-secondary); + --color-action: var(--color-fg-accent); + --color-hover: var(--color-fg-contrast); + + --color-border: rgba(0,0,0,.1); + --color-placeholder: rgba(0,0,0,.25); + + --base-border: 1px solid var(--color-border); + --code-border-color: var(--color-border); + + --scrollbarBG: transparent; + --thumbBG: rgba(0,0,0,.05); + + --base-rhythm: 8px; + + --base-font-size: calc(var(--base-rhythm)*2); + --base-line-height: 1.6; + + --font-size: var(--base-font-size); + + --font-size-l: 1.25rem; + --font-size-sm: 0.8125rem; + --font-size-xsm: 0.75rem; + --font-size-xxsm: 11px; + --code-font-size: .85em; + + --base-font-family: 'Noto Sans', sans-serif; + --code-font-family: 'Noto Sans Mono', consolas, monaco, monospace; + /* + DEV NOTE: To use system fonts, + uncomment the following two variables, replacing the previous two: + */ + /* --base-font-family: ui-sans-serif, system-ui, -apple-system, "system-ui", "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; */ + /* --code-font-family: monospace; */ + + --base-gap: calc(var(--base-rhythm)*6); + --tree-gap: calc(var(--base-rhythm)*4); + --base-padding: calc(var(--base-rhythm)*2); + + --base-elevation-0: 0 0 0 rgba(0,0,0,0); + --base-elevation-node: 0 0 16px rgba(0,0,0,.1); + --base-elevation-modal: 0 0 32px rgba(0,0,0,.32); + + --main-elevation-shadow: inset 8px 8px 16px rgba(0,0,0,.2); + --base-elevation: 0 0 16px rgba(0,0,0,.2); + + --traceability-arrow: 1.25rem; + + --card-width: 300px; +} + +body { + margin: 0; + padding: 0; + + font-family: var(--base-font-family); + font-size: var(--base-font-size); + line-height: var(--base-line-height); + color: var(--color-fg-main); + background-color: var(--color-bg-main); +} + +@font-face { + font-family: 'Noto Sans'; + font-style: normal; + font-weight: 100 900; + /* font-stretch: 100%; */ + font-display: swap; + src: url('./fonts/NotoSans-VariableFont_wdth,wght.ttf') format('truetype-variations'); +} + +@font-face { + font-family: 'Noto Sans'; + font-style: italic; + font-weight: 100 900; + /* font-stretch: 100%; */ + font-display: swap; + src: url('./fonts/NotoSans-Italic-VariableFont_wdth,wght.ttf') format('truetype-variations'); +} + +@font-face { + font-family: 'Noto Sans Mono'; + font-style: normal; + font-weight: 100 900; + /* font-stretch: 100%; */ + font-display: swap; + src: url('./fonts/NotoSansMono-VariableFont_wdth,wght.ttf') format('truetype-variations'); +} + +* { box-sizing: border-box; } + +sdoc-scope { + display: contents; +} + +/* scrollbar */ + +* { + scrollbar-color: var(--thumbBG) var(--scrollbarBG); +} +::-webkit-scrollbar:horizontal, +::-webkit-scrollbar:vertical, +::-webkit-scrollbar, +::-webkit-scrollbar-track:horizontal, +::-webkit-scrollbar-track:vertical, +::-webkit-scrollbar-track, +::-webkit-scrollbar-corner { + background-color: var(--scrollbarBG); +} +::-webkit-scrollbar-thumb:horizontal, +::-webkit-scrollbar-thumb:vertical, +::-webkit-scrollbar-thumb { + background-color: var(--thumbBG) + /* + background-color: var(--scrollbarBG); + border: 3px solid var(--thumbBG); + border-radius: 6px; + */ +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_list.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_list.js new file mode 100644 index 0000000..6ff3dab --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_list.js @@ -0,0 +1,263 @@ +// To collapse and expand TOC branches + +const ROOT_SELECTOR = 'js-collapsible_list'; + +const BRANCH_SELECTOR = `collapsible_list__branch`; +const LIST_DEFAULT = 'open'; +const SYMBOL_MINUS = '-'; +const SYMBOL_PLUS = '+'; +const SYMBOL_SIZE = 16; + +const STYLE = ` +[data-${BRANCH_SELECTOR}] { + display: flex; + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + background-clip: padding-box; + cursor: pointer; + user-select: none; + transition: .3s; + width: ${SYMBOL_SIZE}px; + height: ${SYMBOL_SIZE}px; + font-size: ${SYMBOL_SIZE * 0.875}px; + font-weight: bold; + line-height: 0; + border-radius: 50%; + color: rgba(0,0,0,0.5); + box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; + position: absolute; + top: ${SYMBOL_SIZE * 0.5}px; + left: -${SYMBOL_SIZE * 0.75}px; +} + +[data-${BRANCH_SELECTOR}]:hover { + border: 1px solid rgba(0, 0, 0, 0.15); + box-shadow: rgb(0 0 0 / 15%) 0px 2px 8px 0px; + color: rgba(0,0,0,1); +} + +[data-${BRANCH_SELECTOR}='closed']::before { + content: '${SYMBOL_PLUS}'; +} + +[data-${BRANCH_SELECTOR}='open']::before { + content: '${SYMBOL_MINUS}'; +} + +[data-${BRANCH_SELECTOR}='closed'] ~ ul { /* Subsequent-sibling */ + display: none; +} + +[data-${BRANCH_SELECTOR}='open'] ~ ul { /* Subsequent-sibling */ + display: unset; +} + +[${ROOT_SELECTOR}-bulk] { + display: flex; + gap: 8px; + z-index: 2; + position: fixed; + margin-left: ${SYMBOL_SIZE * 0.5}px; + pointer-events: none; + padding: 8px; + background: #F2F5F9; + box-shadow: #F2F5F9 0px 8px 8px 0px; +} + +[${ROOT_SELECTOR}-bulk] > div { + cursor: pointer; + user-select: none; + transition: .3s; + width: ${SYMBOL_SIZE}px; + height: ${SYMBOL_SIZE}px; + position: relative; + pointer-events: auto; +} + +[${ROOT_SELECTOR}-bulk] > div::before { + content: attr(data-action); + display: flex; + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + background-clip: padding-box; + width: ${SYMBOL_SIZE}px; + height: ${SYMBOL_SIZE}px; + font-size: ${SYMBOL_SIZE * 0.875}px; + font-weight: bold; + line-height: 0; + border-radius: 50%; + background: #F2F5F9; + box-shadow: rgb(0 0 0 / 10%) 0 0px 0px 1px, rgb(0 0 0 / 10%) 2px 1px 1px 0px; + position: absolute; + top: 0; + left: 0; + z-index: 2; +} + +[${ROOT_SELECTOR}-bulk] > div:hover::before { + background: #FFF; +} + +[${ROOT_SELECTOR}-bulk] > div::after { + content: ''; + width: ${SYMBOL_SIZE}px; + height: ${SYMBOL_SIZE}px; + border-radius: 50%; + position: absolute; + box-shadow: rgb(0 0 0 / 15%) 0px 0px 0px 1px; + top: -${SYMBOL_SIZE * 0.25}px; + left: ${SYMBOL_SIZE * 0.25}px; + z-index: 1; +} + +[${ROOT_SELECTOR}-has-bulk] { + margin-top: 32px; +} +`; + +function addStyleElement(target, styleTextContent, attr = 'style') { + const style = document.createElement('style'); + style.setAttribute(`${ROOT_SELECTOR}-${attr}`, ''); + style.textContent = styleTextContent; + target.before(style); +} + +function prepareList(target) { + const ulList = [...target.querySelectorAll('ul')]; + const ulHandlerList = ulList.map( + ul => { + const parent = ul.parentNode; + const ulHandler = document.createElement('div'); + + // parent.insertBefore(ulHandler, ul); + // * I need the button to come before the link as well + parent.prepend(ulHandler); + // Required: + parent.style = "position:relative"; + return ulHandler; + } + ) + return ulHandlerList; +} + +function addBulkHandler(target, handler) { + target.before(handler); + target.setAttribute(`${ROOT_SELECTOR}-has-bulk`, ''); +} + +function createBulkHandler(list) { + const bulk = document.createElement('div'); + bulk.setAttribute(`${ROOT_SELECTOR}-bulk`, ''); + + const bulkPlus = document.createElement('div'); + bulkPlus.dataset.action = SYMBOL_PLUS; + const bulkMinus = document.createElement('div'); + bulkMinus.dataset.action = SYMBOL_MINUS; + + // add event listeners + bulkPlus.addEventListener('click', () => { + bulkToggle(list, 'closed'); + }); + bulkMinus.addEventListener('click', () => { + bulkToggle(list, 'open'); + }); + + bulk.append(bulkPlus, bulkMinus); + return bulk; +} + +function processList(list) { + // This defines how a document is opened: + // with a collapsed or expanded TOC. + const storage = sessionStorage.getItem('collapsibleToc'); + + // If there is no information in the storage, we set the default list state. + const initState = storage || LIST_DEFAULT; + + list.forEach(item => { + item.dataset[BRANCH_SELECTOR] = initState; + + // add event listeners + item.addEventListener('click', () => { + toggle(item); + }); + item.addEventListener('dblclick', () => { + bulkToggle(list, item.dataset[BRANCH_SELECTOR]); + }); + }) +} + +function toggle(item) { + const oldState = item.dataset[BRANCH_SELECTOR]; + const nextState = (oldState === 'closed') ? 'open' : 'closed'; + item.dataset[BRANCH_SELECTOR] = nextState; +} + +function bulkToggle(list, oldState) { + const nextState = (oldState === 'closed') ? 'open' : 'closed'; + // Add last bulk to local storage: + sessionStorage.setItem('collapsibleToc', nextState); + // Update list: + list.forEach(el => el.dataset[BRANCH_SELECTOR] = nextState); +} + +// ****** + +function run() { + const toc = document.querySelector(`[${ROOT_SELECTOR}]`); + + // Processes the list and makes it collapse, if that makes sense + // (if the expanded list was long and would cause scrolling). + // Returns the processed list. + const branchList = prepareList(toc); + + // Do it if that makes sense (if there are branches + // in the list that could in principle be collapsible): + if (branchList.length > 0) { + processList(branchList); + addStyleElement(toc, STYLE); + + // Uncomment to add buttons for bulk operations: + // addBulkHandler(listElement, createBulkHandler(branchList)); + } +} + +function isCollapsibleList(node) { + return node.nodeType === 1 && node.hasAttribute(ROOT_SELECTOR) +} + +window.addEventListener("load",function(){ + + let mutatingFrame = document.querySelector('#frame-toc'); + if (!mutatingFrame) { + console.error("#frame-toc not found"); + return; + } + + new MutationObserver(function (mutationsList, observer) { + + for (let mutation of mutationsList) { + if (mutation.type === 'childList') { + let addedToc = Array.from(mutation.addedNodes).find(node => isCollapsibleList(node)); + if (addedToc) { + run() + } + } + } + + }).observe( + mutatingFrame, + { + childList: true, + // subtree: true + } + ); + + // * Call for the first time. + run() + +},false); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_toc.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_toc.js new file mode 100644 index 0000000..a3c37e4 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_toc.js @@ -0,0 +1,200 @@ +// To collapse and expand TOC branches + +const ROOT_ID = 'toc'; +const SS_ITEM = 'collapsibleTOC'; // sessionStorageItem +const BRANCH_DATA_ATTR = `branch`; // li with a branch inside +const HANDLER_DATA_ATTR = `handler`; // handler +const NODE_ID_DATA_ATTR = `nodeid`; // from sdoc markup +const _TRUE = 'collapsed'; +const _FALSE = 'expanded'; + +const ROOT_SELECTOR = 'js-collapsible_list'; // is used in tests + +const SYMBOL_FALSE = '-'; +const SYMBOL_TRUE = '+'; +const SYMBOL_SIZE = 16; + +const STYLE = ` +[data-${HANDLER_DATA_ATTR}] { + display: flex; + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + background-clip: padding-box; + cursor: pointer; + user-select: none; + transition: .3s; + width: ${SYMBOL_SIZE}px; + height: ${SYMBOL_SIZE}px; + font-size: ${SYMBOL_SIZE * 0.875}px; + font-weight: bold; + line-height: 0; + border-radius: 50%; + color: rgba(0,0,0,0.5); + box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; + position: absolute; + top: ${SYMBOL_SIZE * 0.5}px; + left: -${SYMBOL_SIZE * 0.75}px; +} + +[data-${HANDLER_DATA_ATTR}]:hover { + border: 1px solid rgba(0, 0, 0, 0.15); + box-shadow: rgb(0 0 0 / 15%) 0px 2px 8px 0px; + color: rgba(0,0,0,1); +} + +[data-${HANDLER_DATA_ATTR}='${_TRUE}']::before { + content: '${SYMBOL_TRUE}'; +} + +[data-${HANDLER_DATA_ATTR}='${_FALSE}']::before { + content: '${SYMBOL_FALSE}'; +} + +[data-${BRANCH_DATA_ATTR}='${_TRUE}'] > ul { + display: none; +} + +[data-${BRANCH_DATA_ATTR}='${_FALSE}'] > ul { + display: unset; +} + +`; + +function sessionStorageGet() { + const item = sessionStorage.getItem(SS_ITEM); + const res = item ? JSON.parse(item) : {}; + return res +} + +function sessionStorageSet(obj) { + const string = JSON.stringify(obj); + sessionStorage.setItem(SS_ITEM, string) +} + +function updateSessionStorage() { + const obj = {}; + document.querySelector(`[${ROOT_SELECTOR}]`) + .querySelectorAll(`[data-${BRANCH_DATA_ATTR}]`) + .forEach( + branch => obj[branch.dataset[NODE_ID_DATA_ATTR]] = branch.dataset[BRANCH_DATA_ATTR] + ); + sessionStorageSet(obj); +} + +function addStyleElement(target, styleTextContent, attr = 'style') { + const style = document.createElement('style'); + style.setAttribute(`collapsible-toc-${attr}`, ''); + style.textContent = styleTextContent; + target.before(style); +} + +function setBranchState(handler, state) { + handler.dataset[HANDLER_DATA_ATTR] = state; + handler.parentNode.dataset[BRANCH_DATA_ATTR] = state; +} + +function createHandler(state) { + const div = document.createElement('div'); + state && setBranchState(item, state); + return div +} + +function processToc(toc) { + const storage = sessionStorageGet(); + + const branchList = toc.querySelectorAll('ul'); + + // Do it if that makes sense (if there are branches + // in the list that could in principle be collapsible): + if (branchList.length > 0) { + addStyleElement(toc, STYLE); + + branchList.forEach( + ul => { + const handler = createHandler(); + + const parentNode = ul.parentNode; + const nodeID = parentNode.dataset[NODE_ID_DATA_ATTR]; + const currentState = storage[nodeID] || _FALSE; + + // parent.insertBefore(handler, ul); + // * I need the button to come before the link as well + parentNode.prepend(handler); + // Required: + parentNode.style = "position:relative"; + + // * run after the items have been added to the DOM + setBranchState(handler, currentState); + + // * add event listeners + handler.addEventListener('click', () => { + toggle(handler); + }); + handler.addEventListener('dblclick', () => { + bulkToggleChildBrunches(handler); + }); + } + ); + + updateSessionStorage(); + } +} + +function toggle(handler) { + const newState = (handler.dataset[HANDLER_DATA_ATTR] === _FALSE) ? _TRUE : _FALSE; + setBranchState(handler, newState); + updateSessionStorage(); +} + +function bulkToggleChildBrunches(handler) { + const newState = (handler.dataset[HANDLER_DATA_ATTR] === _FALSE) ? _TRUE : _FALSE; + const list = handler.parentNode.querySelectorAll(`[data-${HANDLER_DATA_ATTR}]`); + list.forEach(handler => { + setBranchState(handler, newState); + }); + updateSessionStorage(); +} + +// ****** + +function run() { + processToc(document.querySelector(`[${ROOT_SELECTOR}]`)); +} + +function isCollapsibleList(node) { + return node.nodeType === 1 && node.id === ROOT_ID +} + +window.addEventListener("load", function() { + + let mutatingFrame = document.querySelector('#frame-toc'); + if (!mutatingFrame) { + console.error("#frame-toc not found"); + return; + } + + new MutationObserver(function (mutationsList, observer) { + + for (let mutation of mutationsList) { + if (mutation.type === 'childList') { + let addedToc = Array.from(mutation.addedNodes).find(node => isCollapsibleList(node)); + if (addedToc) { + run() + } + } + } + + }).observe( + mutatingFrame, + { + childList: true, + // subtree: true + } + ); + + // * Call for the first time. + run() + +},false); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_tree.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_tree.js new file mode 100644 index 0000000..3af9dde --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/collapsible_tree.js @@ -0,0 +1,32 @@ +const ROOT_SELECTOR = 'js-collapsible_tree'; + +window.addEventListener("DOMContentLoaded", function(){ + + const tree = document.querySelector(`[${ROOT_SELECTOR}]`); + if (!tree) { return } + + const summaries = tree.querySelectorAll('summary'); + + summaries.forEach(summary => { + summary.addEventListener('dblclick', () => { + const details = summary.parentElement; + if (details.nodeName !== 'DETAILS') { + console.warn('The DETAILS tag has an unexpected structure.'); + return + } + const open = details.hasAttribute("open"); + + const innerSummaries = details.querySelectorAll('summary'); + + innerSummaries.forEach(summary => { + const details = summary.parentElement; + if (open) { + details.removeAttribute("open") + } else ( + details.setAttribute("open", "") + ) + }) + }); + }) + +},false); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/content.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/content.css new file mode 100644 index 0000000..596cf49 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/content.css @@ -0,0 +1,203 @@ +/* .main */ + +.main { + position: relative; + overflow: auto; + scroll-behavior: smooth; + scrollbar-gutter: stable both-edges; + padding: var(--base-gap) /* == calc(var(--base-rhythm)*6) */ + calc(var(--base-rhythm)*6); /* compensate both-edges scrollbar-gutter */ + + height: 100%; + background-color: var(--color-bg-main); + + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: stretch; + gap: var(--base-rhythm); +} + +/* redefine main layout grid */ + +[data-viewtype="diff"] .main { + padding-bottom: 0; +} + +[data-viewtype="source-file"] .main { + padding: 0; + scrollbar-gutter: unset; +} + +.main_sticky_header { + position: sticky; + top: 0; + left: 0; + z-index: 11; + + display: flex; + flex-direction: column; + gap: var(--base-rhythm); + + /* margin-bottom: calc(var(--base-rhythm)*4); */ + background-color: var(--color-bg-main); + border: none; +} + +.main_sticky_header > * { + position: relative; +} + +.main_sticky_header::before { + content: ''; + position: absolute; + bottom: 0; + top: -60px; + left: calc(-1 * var(--base-gap)); + right: calc(-1 * var(--base-gap)); + background-color: var(--color-bg-main); + z-index: 0; +} + +/* .content */ + +.content { + width: 100%; + min-width: calc(var(--card-width) + calc(var(--base-padding)*4)); +} + +[data-viewtype="document"] .content { + display: block; + max-width: 900px; + margin-bottom: 300px; + margin-left: auto; + margin-right: auto; +} + +[data-viewtype="traceability"] .content { + display: grid; + place-items: stretch stretch; + grid-template-columns: minmax(min-content, max-content) + minmax(var(--card-width), calc(2*var(--card-width))) + minmax(min-content, max-content); + gap: var(--requirement-tree-margin) 0; + width: -moz-fit-content; + width: fit-content; + /* overflow: hidden; */ +} + +[data-viewtype="requirements-coverage"] .content, +[data-viewtype="deep_traceability"] .content { + display: grid; + place-items: stretch stretch; + grid-template-columns: minmax(min-content, max-content) + max-content + minmax(min-content, max-content); + gap: var(--requirement-tree-margin) 0; + width: -moz-fit-content; + width: fit-content; + + /* fon node-controls: */ + /* overflow: hidden; */ +} + +[data-viewtype="table"] .content { + background-color: var(--color-bg-contrast); + display: block; + /* aligns the width of the white box of the content and the table: */ + width: fit-content; +} + +[data-viewtype="table"] sdoc-node .free_text{ + max-width: 900px; +} + +[data-viewtype="search"] .content { + display: grid; + place-items: stretch stretch; + grid-template-columns: 1fr; + gap: var(--tree-gap) 0; + width: -moz-fit-content; + width: fit-content; +} + +/* TODO */ +/* used in TR, DTR, requirements_coverage: */ +.content_section { + display: contents; +} +/* TODO */ +.content_item { + position: relative; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + align-content: stretch; + align-items: stretch; +} + +/* traceability */ + +.content_item[data-role="parents"] { + grid-column: 1 / 2; +} + +.content_item[data-role="current"] { + grid-column: 2 / 3; +} + +[data-viewtype="deep_traceability"] .content_item[data-role="current"] { + /* central column */ + width: var(--card-width); +} + +[data-viewtype="requirements-coverage"] .content_item[data-role="current"] { + /* central column */ + width: calc(var(--card-width)*0.75); +} + +.content_item[data-role="children"] { + grid-column: 3 / 4; +} + +[data-viewtype="deep_traceability"] .content_item[data-role="current"]::before, +[data-viewtype="traceability"] .content_item[data-role="current"]::before { + /* for vertical line in 'current' column */ + content: ''; + position: absolute; + top: 0; + bottom: calc(var(--requirement-tree-margin)*(-1)); + left: 50%; + border-left: 1px dotted #000; +} + +[data-viewtype="deep_traceability"] section:last-child .content_item[data-role="current"]::before, +[data-viewtype="traceability"] section:last-child .content_item[data-role="current"]::before { + /* the last section doesn't need a vertical connector under the middle node */ + content: none; +} + +/* placeholder */ + +sdoc-main-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: var(--color-placeholder); + font-weight: 700; + font-family: var(--code-font-family); + width: 100%; + height: 100%; +} + +sdoc-main-legend { + display: block; + color: var(--color-placeholder); + font-weight: 700; + font-family: var(--code-font-family); + max-width: 1024px; + padding: var(--base-gap); + font-weight: 500; + margin-bottom: auto; /* To align the element at the top of the container that uses 'display:flex' */ +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/anchor_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/anchor_controller.js new file mode 100644 index 0000000..58bf9af --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/anchor_controller.js @@ -0,0 +1,88 @@ +(() => { + + const ANCHOR_SELECTOR = 'sdoc-anchor[data-anchor]'; + const ANCHOR_BLOCK_SELECTOR = '.anchor_block'; + const ANCHOR_BUTTON_SELECTOR = '.anchor_button'; + const ANCHOR_BASE_ICON_SELECTOR = '.anchor_base_icon'; + const ANCHOR_CHECK_ICON_SELECTOR = '.anchor_check_icon'; + const ANCHOR_BACK_LINKS_SELECTOR = '.anchor_back_links'; + const ANCHOR_BACK_LINKS_NUMBER_SELECTOR = '.anchor_back_links_number'; + + class AnchorController extends Stimulus.Controller { + initialize() { + // this.element == sdoc-node + // Processing node anchors and inline anchors in the text: + const anchors = [...this.element.querySelectorAll(ANCHOR_SELECTOR)]; + anchors.forEach(anchor => { + + // Note: template already applies conditions whether an anchorBlock is rendered. + // JS assumes that if anchorBlock exists, it is valid to process. + const anchorBlock = anchor.querySelector(ANCHOR_BLOCK_SELECTOR); + + if (anchorBlock) { + const anchorText = anchor.dataset.anchor; + const anchorButton = anchor.querySelector(ANCHOR_BUTTON_SELECTOR); + const anchorIcon = anchor.querySelector(ANCHOR_BASE_ICON_SELECTOR); + const checkIcon = anchor.querySelector(ANCHOR_CHECK_ICON_SELECTOR); + + anchorButton.addEventListener("click", function (event) { + event.preventDefault(); + updateClipboard(anchorText, confirmMessage(anchorButton, anchorIcon, checkIcon)) + }); + } + }) + } + } + + Stimulus.application.register("anchor_controller", AnchorController); + + function updateClipboard(newClip, callback) { + navigator.clipboard.writeText(newClip).then(() => { + /* clipboard successfully set */ + () => callback(); + console.info('clipboard successfully set: ', newClip); + }, () => { + /* clipboard write failed */ + console.warn('clipboard write failed'); + }); + } + + function confirmMessage(anchorButton, anchorIcon, checkIcon) { + const element = document.createElement('div'); + element.style.position = 'absolute'; + element.style.zIndex = 10; + element.style.width = '100%'; + element.style.height = '100%'; + element.style.paddingLeft = '32px'; + element.style.left = 0; + element.style.background = 'black'; + element.style.color = 'white'; + element.style.fontWeight = 'bold'; + element.style.display = 'flex'; + element.style.alignItems = 'center'; + element.style.justifyContent = 'flex-start'; + // element.innerHTML = '✔️ copied!'; + + // initial opacity + let op = 1; + element.style.opacity = op; + anchorButton.style.opacity = 1; + + anchorIcon.style.display = 'none'; + checkIcon.style.display = 'inline'; + const fadeTimer = setInterval(() => { + if (op <= 0.1) { + clearInterval(fadeTimer); + element.remove(); + anchorIcon.style.display = 'inline'; + checkIcon.style.display = 'none'; + anchorButton.style.opacity = ''; + } + element.style.opacity = op; + op -= op * 0.1; + }, 30); + + // return element; + anchorButton.append(element); + } +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/autocompletable_field_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/autocompletable_field_controller.js new file mode 100644 index 0000000..7439708 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/autocompletable_field_controller.js @@ -0,0 +1,372 @@ +// MIT License +// +// based on https://github.com/afcapel/stimulus-autocomplete/ +// Copyright (c) 2021 Alberto Fernández-Capel + +(() => { + + const optionSelector = "[role='option']:not([aria-disabled])" + const activeSelector = "[aria-selected='true']" + + class AutoCompletable extends Stimulus.Controller { + static targets = ["name"] + static classes = ["selected"] + static values = { + ready: Boolean, + url: String, + minLength: Number, + delay: { type: Number, default: 10 }, + queryParam: { type: String, default: "q" }, + multipleChoice: Boolean, + } + static uniqOptionId = 0 + + connect() { + // this.element is the DOM element to which the controller is connected to. + const autocompletable = this.element + this.autocompletable = autocompletable + this.hidden = autocompletable.nextElementSibling + this.results = this.hidden.nextElementSibling + this.abortController = null; + + this.close() + + if (!autocompletable.hasAttribute("autocompletable")) autocompletable.setAttribute("autocompletable", "off") + autocompletable.setAttribute("spellcheck", "false") + + this.mouseDown = false + + this.onInputChange = debounce(this.onInputChange, this.delayValue) + + this.autocompletable.addEventListener("input", this.onInputChange) + + autocompletable.addEventListener("keydown", (event) => { + const handler = this[`on${event.key}Keydown`] + if (handler) handler(event) + }); + + autocompletable.addEventListener("blur", (event) => { + if (this.mouseDown) return + this.close() + }); + + autocompletable.addEventListener("click", (event) => { + /* Toggle between showing / hiding results. */ + if (this.resultsShown) { + this.hideAndRemoveOptions(); + } else { + /* If minLengthValue is 0, we want to get all possible options (i.e. for SingleChoice). + Otherwise, we want narrow-down-as-you-type behavior, and filter on remainig options. + */ + const query = this.minLengthValue == 0 ? "" : this.autocompletable.innerText.trim(); + this.fetchResults(query); + } + }); + + this.results.addEventListener("mousedown", this.onResultsMouseDown) + this.results.addEventListener("click", this.onResultsClick) + + if (autocompletable.hasAttribute("autofocus")) { + autocompletable.focus() + } + + this.readyValue = true + } + + disconnect() { + this.autocompletable.removeEventListener("keydown", this.onKeydown) + this.autocompletable.removeEventListener("blur", this.onInputBlur) + this.autocompletable.removeEventListener("input", this.onInputChange) + + this.results.removeEventListener("mousedown", this.onResultsMouseDown) + this.results.removeEventListener("click", this.onResultsClick) + } + + sibling(next) { + const options = this.options + const selected = this.selectedOption + const index = options.indexOf(selected) + const sibling = next ? options[index + 1] : options[index - 1] + const def = next ? options[0] : options[options.length - 1] + return sibling || def + } + + select(target) { + const previouslySelected = this.selectedOption + if (previouslySelected) { + previouslySelected.removeAttribute("aria-selected") + previouslySelected.classList.remove(...this.selectedClassesOrDefault) + } + + target.setAttribute("aria-selected", "true") + target.classList.add(...this.selectedClassesOrDefault) + this.autocompletable.setAttribute("aria-activedescendant", target.id) + target.scrollIntoView({ behavior: "auto", block: "nearest" }) + } + + selectText(text) { + const normalizedText = text.trim().toLowerCase(); + const match = this.options.find(option => { + const label = option.getAttribute("data-autocompletable-label") || option.textContent; + return label.trim().toLowerCase() === normalizedText; + }); + + if (match) { + this.select(match); + } + } + + onEscapeKeydown = (event) => { + if (!this.resultsShown) return + + this.hideAndRemoveOptions() + event.stopPropagation() + event.preventDefault() + } + + onArrowDownKeydown = (event) => { + if (!this.resultsShown) return + + const item = this.sibling(true) + if (item) this.select(item) + event.preventDefault() + } + + onArrowUpKeydown = (event) => { + if (!this.resultsShown) return + + const item = this.sibling(false) + if (item) this.select(item) + event.preventDefault() + } + + onTabKeydown = (event) => { + if (!this.resultsShown) return + + /* Either use the selected options, or else select the first result. */ + const selected = this.selectedOption || this.sibling(true) + this.commit(selected) + event.preventDefault(); + } + + onEnterKeydown = (event) => { + const selected = this.selectedOption + if (selected && this.resultsShown) { + this.commit(selected) + } + /* single line, dont allow enter */ + event.preventDefault() + } + + commit(selected) { + if (selected.getAttribute("aria-disabled") === "true") return + + if (selected instanceof HTMLAnchorElement) { + selected.click() + this.close() + return + } + + const textValue = selected.getAttribute("data-autocompletable-label") || selected.textContent.trim() + let suggestion = selected.getAttribute("data-autocompletable-value") || textValue + + if (this.multipleChoiceValue) { + // Get the current text content + const text = this.autocompletable.innerText || ""; + const parts = text.split(","); + + // Replace the last incomplete token with the suggestion. + parts[parts.length - 1] = " " + suggestion; + suggestion = parts.map(p => p.trim()).join(", ") + } + + this.autocompletable.innerText = suggestion + this.hidden.value = suggestion + + // Move the cursor to the end of the input. + this.autocompletable.focus(); + const range = document.createRange(); + range.selectNodeContents(this.autocompletable); + range.collapse(false); + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + + this.hidden.dispatchEvent(new Event("input")) + this.hidden.dispatchEvent(new Event("change")) + + this.autocompletable.focus() + this.hideAndRemoveOptions() + + this.element.dispatchEvent( + new CustomEvent("autocompletable.change", { + bubbles: true, + detail: { value: suggestion, textValue: textValue, selected: selected } + }) + ) + } + + clear() { + this.autocompletable.innerText = "" + this.hidden.value = "" + } + + onResultsClick = (event) => { + if (!(event.target instanceof Element)) return + const selected = event.target.closest(optionSelector) + if (selected) this.commit(selected) + } + + onResultsMouseDown = () => { + this.mouseDown = true + this.results.addEventListener("mouseup", () => { + this.mouseDown = false + }, { once: true }) + } + + onInputChange = () => { + const query = this.autocompletable.innerText.trim() + if (query && query.length >= this.minLengthValue) { + this.fetchResults(query) + } else { + this.hideAndRemoveOptions() + } + + const text = filterSingleLine(this.autocompletable.innerText) + this.hidden.value = text + } + + identifyOptions() { + const prefix = this.results.id || "autocompletable" + const optionsWithoutId = this.results.querySelectorAll(`${optionSelector}:not([id])`) + optionsWithoutId.forEach(el => el.id = `${prefix}-option-${this.constructor.uniqOptionId++}`) + } + + hideAndRemoveOptions() { + this.close() + this.results.innerHTML = null + } + + fetchResults = async (query) => { + if (!this.hasUrlValue) return + + /* Abort the previous request as we are about to send a new one. */ + if (this.abortController) { + this.abortController.abort(); + } + this.abortController = new AbortController(); + const signal = this.abortController.signal; + + const url = this.buildURL(query) + try { + this.element.dispatchEvent(new CustomEvent("loadstart")) + const html = await this.doFetch(url, signal) + this.replaceResults(html) + /* Check if an entry matches the current text and select it. */ + this.selectText(this.autocompletable.innerText.trim()); + this.element.dispatchEvent(new CustomEvent("load")) + this.element.dispatchEvent(new CustomEvent("loadend")) + } catch (error) { + if (error.name === 'AbortError') { + return; + } + this.element.dispatchEvent(new CustomEvent("error")) + this.element.dispatchEvent(new CustomEvent("loadend")) + throw error + } + } + + buildURL(query) { + const url = new URL(this.urlValue, window.location.href) + const params = new URLSearchParams(url.search.slice(1)) + params.append(this.queryParamValue, query) + url.search = params.toString() + + return url.toString() + } + + doFetch = async (url, signal) => { + const response = await fetch(url, {signal}) + + if (!response.ok) { + throw new Error(`Server responded with status ${response.status}`) + } + + const html = await response.text() + return html + } + + replaceResults(html) { + this.results.innerHTML = html + this.identifyOptions() + if (!!this.options) { + this.open() + } else { + this.close() + } + } + + open() { + if (this.resultsShown) return + + this.resultsShown = true + this.element.setAttribute("aria-expanded", "true") + this.element.dispatchEvent( + new CustomEvent("toggle", { + detail: { action: "open", autocompletable: this.autocompletable, results: this.results } + }) + ) + } + + close() { + if (!this.resultsShown) return + + this.resultsShown = false + this.autocompletable.removeAttribute("aria-activedescendant") + this.element.setAttribute("aria-expanded", "false") + this.element.dispatchEvent( + new CustomEvent("toggle", { + detail: { action: "close", autocompletable: this.autocompletable, results: this.results } + }) + ) + } + + get resultsShown() { + return !this.results.hidden + } + + set resultsShown(value) { + this.results.hidden = !value + } + + get options() { + return Array.from(this.results.querySelectorAll(optionSelector)) + } + + get selectedOption() { + return this.results.querySelector(activeSelector) + } + + get selectedClassesOrDefault() { + return this.hasSelectedClass ? this.selectedClasses : ["autocomplete-active"] + } + + } + + Stimulus.application.register("autocompletable", AutoCompletable); + + function filterSingleLine(text) { + return text.replace(/\s/g, ' ').replace(/\s\s+/g, ' ') + } + + const debounce = (fn, delay = 10) => { + let timeoutId = null + + return (...args) => { + clearTimeout(timeoutId) + timeoutId = setTimeout(fn, delay) + } + } + +})(); + diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_stable_link_button_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_stable_link_button_controller.js new file mode 100644 index 0000000..6307b5c --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_stable_link_button_controller.js @@ -0,0 +1,82 @@ +(() => { + + class CopyStableLinkController extends Stimulus.Controller { + connect() { + const button = this.element; + + button.addEventListener("click", (event) => { + event.preventDefault(); + + const link = button.dataset.path; + + const copyIcon = this.element.querySelector(".copy_to_clipboard-copy_icon"); + const doneIcon = this.element.querySelector(".copy_to_clipboard-done_icon"); + + // Resolve any relative URLs with respect to current URL. + const resolved = ( + this._isAbsoluteURL(link) + ? link + : new URL(link, window.location.href).href + ); + + // Expand folder to index if we run from the local file system. + const expanded = ( + (window.location.protocol === 'file:') + ? resolved.replace(/#/, 'index.html?a=') + : resolved.replace(/#/, '?a=') + ); + + this._updateClipboard(expanded, this._confirmCopy(button, copyIcon, doneIcon)); + }); + } + + _isAbsoluteURL(url) { + try { + new URL(url); // throws if it's relative + return true; + } catch { + return false; + } + } + + _updateClipboard(newClip, callback) { + navigator.clipboard.writeText(newClip).then(() => { + /* clipboard successfully set */ + () => callback(); + console.info('Clipboard successfully set: ', newClip); + }, () => { + /* clipboard write failed */ + console.warn('Clipboard write failed'); + }); + } + + _confirmCopy(button, copyIcon, doneIcon) { + // initial opacity + let op = 1; + + // make button visible + button.style.opacity = 1; + + // make DONE icon visible (instead of default COPY) + copyIcon.style.display = 'none'; + doneIcon.style.display = 'contents'; + + const fadeTimer = setInterval(() => { + if (op <= 0.1) { + clearInterval(fadeTimer); + + // make button invisible + button.style.opacity = ''; + + // make COPY icon visible back + copyIcon.style.display = 'contents'; + doneIcon.style.display = 'none'; + } + op -= op * 0.1; + }, 30); + } + } + + Stimulus.application.register("copy_stable_link_button", CopyStableLinkController); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_to_clipboard_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_to_clipboard_controller.js new file mode 100644 index 0000000..e7e6976 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/copy_to_clipboard_controller.js @@ -0,0 +1,70 @@ +(() => { + + class CopyToClipboard extends Stimulus.Controller { + connect() { + const button = this.element.querySelector(".copy_to_clipboard-button"); + + // Add event listener + button.addEventListener("click", (event) => { + event.preventDefault(); + + const clip = this.element.querySelector("sdoc-field-content").innerText.trim(); + const copyIcon = this.element.querySelector(".copy_to_clipboard-copy_icon"); + const doneIcon = this.element.querySelector(".copy_to_clipboard-done_icon"); + const cover = this.element.querySelector(".copy_to_clipboard-cover"); + _updateClipboard( + clip, + _confirm(button, copyIcon, doneIcon, cover) + ) + }); + } + } + + Stimulus.application.register("copy_to_clipboard", CopyToClipboard); + + function _updateClipboard(newClip, callback) { + navigator.clipboard.writeText(newClip).then(() => { + /* clipboard successfully set */ + () => callback(); + console.info('clipboard successfully set: ', newClip); + }, () => { + /* clipboard write failed */ + console.warn('clipboard write failed'); + }); + } + + function _confirm(button, copyIcon, doneIcon, cover) { + // initial opacity + let op = 1; + + // make button visible + button.style.opacity = 1; + + // initial cover + cover.style.background = `rgba(242, 100, 42, ${op})`; + + // make DONE icon visible (instead of default COPY) + copyIcon.style.display = 'none'; + doneIcon.style.display = 'contents'; + + const fadeTimer = setInterval(() => { + // update cover + cover.style.background = `rgba(242, 100, 42, ${op})`; + if (op <= 0.1) { + clearInterval(fadeTimer); + + // make button invisible + button.style.opacity = ''; + + // reset cover + cover.style.background = `rgba(242, 100, 42, 0)`; + + // make COPY icon visible back + copyIcon.style.display = 'contents'; + doneIcon.style.display = 'none'; + } + op -= op * 0.1; + }, 30); + } + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/deletable_field_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/deletable_field_controller.js new file mode 100644 index 0000000..db60193 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/deletable_field_controller.js @@ -0,0 +1,19 @@ +(() => { + + class DeletableField extends Stimulus.Controller { + connect() { + // this.element is the DOM element to which the controller is connected to. + const thisElement = this.element; + const commentLinks = thisElement.querySelectorAll("[data-js-delete-field-action]"); + commentLinks.forEach(link => { + link.addEventListener("click", function (event) { + event.preventDefault(); + thisElement.remove(); + }); + }); + } + } + + Stimulus.application.register("deletable_field", DeletableField); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/draggable_list_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/draggable_list_controller.js new file mode 100644 index 0000000..b73331b --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/draggable_list_controller.js @@ -0,0 +1,334 @@ +(() => { + + const DL_SELECTOR = 'js-draggable_list'; + const DL_ITEM_SELECTOR = 'li'; + const DL_ZONE_CHILD = 32; + + const CSS = ` +${DL_ITEM_SELECTOR}[draggable="true"] { +} +${DL_ITEM_SELECTOR}[draggable="true"]:hover { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: -o-grab; + cursor: -ms-grab; + cursor: grab; +} +${DL_ITEM_SELECTOR}[draggable="true"]:active { + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: -o-grabbing; + cursor: -ms-grabbing; + cursor: grabbing; +} +.dropIndicator { + display: block; + position: absolute; + left: 0; right: 0; + z-index: 2; +} +.dropIndicator::before { + position: absolute; + content: ''; + top: -2px; + left: 0; right: 0; + height: 4px; + background: rgb(242,100,42); + opacity: 0.3; + pointer-events: none; +} +.dropIndicator::after { + position: absolute; + content: ''; + top: -2px; + height: 4px; + width: 100%; + background: rgb(242,100,42); + pointer-events: none; +} +.dragIndicator { + position: absolute; + top: 0; right: 0; + transition: 0.3s; +} +${DL_ITEM_SELECTOR}[draggable="true"] .dragIndicator::before { + position: absolute; + width: 8px; + height: 24px; + top: 0; left: 100%; + content: "⋮⋮"; +} +[data-last_moved="true"] { + position: relative; +} +[data-last_moved="true"]::after { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; bottom: 0; + pointer-events: none; + animation-name: last_moved; + animation-duration: 1s; +} +@keyframes last_moved { + from { + background: rgba(255,255,255,0.5); + } + to { + background: rgba(255,255,255,0); + } +} +[data-dragging="true"] { + background: rgba(255,255,255,0.5) !important; +} + +`; + + const dragState = { + item: null, + reference: null, + option: null, + } + + function resetDragState() { + dragState.item = null; + dragState.reference = null; + dragState.option = null; + } + + function setDragItem(item) { + dragState.item = item; + } + function setDropReference(reference) { + dragState.reference = reference; + } + function setDropOption(option) { + dragState.option = option; + } + + const dropIndicator = createDropIndicator(); + const dragIndicator = createDragIndicator(); + + class DraggableList extends Stimulus.Controller { + static targets = ["name"]; + + initialize() { + // this.element.style.paddingRight = '10px'; + + const last_moved_node_id = this.element.dataset.last_moved_node_id; + + addStyle(this.element, CSS, 'style'); + + // Add event listeners. + const draggableList = [...this.element.querySelectorAll(DL_ITEM_SELECTOR)]; + draggableList.forEach((item) => { + item.addEventListener('dragstart', dragStart); + item.addEventListener('dragend', dragEnd); + item.addEventListener('dragover', dragOver); + item.addEventListener('dragenter', dragEnter); + item.addEventListener('dragleave', dragLeave); + item.addEventListener('drop', dragDrop); + + item.addEventListener("mouseover", mouseOver); + item.addEventListener("mouseleave", mouseLeave); + + last_moved_node_id + && (item.dataset.nodeid === last_moved_node_id) + && (item.dataset.last_moved = 'true'); + + item.setAttribute('draggable', true); + }); + + // Prevent drag for links inside the list. + [...this.element.querySelectorAll('a')].forEach((item) => { + item.setAttribute('draggable', false); + }) + } + } + + Stimulus.application.register("draggable_list", DraggableList); + + function addStyle(target, css, attr = 'style') { + const style = document.createElement('style'); + style.setAttribute(`${DL_SELECTOR}-${attr}`, ''); + style.textContent = css; + target.parentNode.insertBefore(style, target); + } + + function createDropIndicator() { + const dropIndicator = document.createElement('div'); + dropIndicator.className = 'dropIndicator'; + return dropIndicator + } + + function createDragIndicator() { + const dragIndicator = document.createElement('div'); + dragIndicator.className = 'dragIndicator'; + return dragIndicator + } + + function dragStart(event) { + event.stopImmediatePropagation(); + event.dataTransfer.dropEffect = "move"; + event.dataTransfer.effectAllowed = 'move'; + + setDragItem(this); + + setTimeout(() => { + this.dataset.dragging = true; + }, 0); + } + + function dragEnd(event) { + updateDropIndication(); + resetDragState(); + this.dataset.dragging = false; + } + + function updateDropIndication(target, option) { + setDropOption(option); + switch (option) { + case 'child': + target.append(dropIndicator); + dropIndicator.style.paddingLeft = `${DL_ZONE_CHILD}px`; + dropIndicator.style.top = ''; + dropIndicator.style.bottom = 0; + break; + case 'after': + target.append(dropIndicator); + dropIndicator.style.paddingLeft = ''; + dropIndicator.style.top = ''; + dropIndicator.style.bottom = 0; + break; + case 'before': + target.append(dropIndicator); + dropIndicator.style.paddingLeft = ''; + dropIndicator.style.top = 0; + dropIndicator.style.bottom = ''; + break; + default: + // dropIndicator is declared in the global scope, + // so this case works if there are no parameters: + dropIndicator.remove(); + } + } + + function isDropMatter() { + return + } + + function dragOver(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + event.dataTransfer.dropEffect = "move"; + + setDropReference(this); + + // https://developer.mozilla.org/en-US/docs/Web/API/Node/contains + // A node is contained inside itself, + // so (dragState.item !== dragState.reference) + // is the same as (dragState.item.contains(dragState.reference)). + + if (dragState.item.contains(dragState.reference)) { + // We do not process the case when the item does not actually displace. + updateDropIndication(); + } else { + + const bounding = this.getBoundingClientRect(); + + // We do not process the case when the item + // does not actually displace. + + if (event.clientY < bounding.top + (bounding.bottom - bounding.top) * 0.5) { + // * BEFORE + // The mouse is in the top half of the Reference. + + if (dragState.item.nextElementSibling === dragState.reference) { + // We do not process the case when the item + // does not actually displace. + updateDropIndication(); + } else { + updateDropIndication(this, 'before'); + } + + } else { + // * AFTER + // The mouse is in the bottom half of the Reference. + // The dragged element can become a child or just the next one. + + if (event.clientX > bounding.left + DL_ZONE_CHILD) { + // * AFTER / child + // The mouse is shifted to the right of the boundary, + // which indicates the intention to insert the item as a child. + + updateDropIndication(this, 'child'); + + } else { + // * AFTER / just the next item + // The mouse is to the left of the DL_ZONE_CHILD boundary, which points + // to the intention to insert just the next one in the list. + + if (dragState.item.previousElementSibling === dragState.reference) { + // We do not process the case when the item + // does not actually displace. + updateDropIndication(); + } else { + updateDropIndication(this, 'after'); + } + } + } + } + } + + function dragEnter() { } + function dragLeave() { } + + function dragDrop(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + dragState.option && fetchDroppedItemData(dragState.item, dragState.reference, dragState.option); + } + + function mouseOver(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + if (event.target === this) { + event.target.append(dragIndicator); + } + } + function mouseLeave(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + if (event.target === this) { + dragIndicator.remove(); + } + } + + function fetchDroppedItemData(dragItem, dropReference, whereto) { + console.assert(['before', 'after', 'child'].includes(whereto), 'whereto is', whereto) + if (dragItem !== dropReference) { + // Build formData object. + let formData = new FormData(); + formData.append('moved_node_mid', dragItem.dataset.nodeid); + formData.append('target_mid', dropReference.dataset.nodeid); + formData.append('whereto', whereto); + + fetch("/actions/document/move_node", + { + body: formData, + method: "post", + headers: { + "Accept": "text/vnd.turbo-stream.html", + }, + }).then(r => r.text()) + .then(html => Turbo.renderStreamMessage(html)); + } + } + + function moveNodeBefore(dragItem, dropReference) { + // The real insertion of the moved node is done by the server, + // so this functionality is not implemented. + //// dropReference.parentNode.insertBefore(dragItem, dropReference); + //// dragItem.dataset.last_moved = 'true'; + } + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/dropdown_menu_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/dropdown_menu_controller.js new file mode 100644 index 0000000..56398a0 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/dropdown_menu_controller.js @@ -0,0 +1,46 @@ +(() => { + + const HANDLER_SELECTOR = '[js-dropdown-menu-handler]'; + const LIST_SELECTOR = '[js-dropdown-menu-list]'; + + class DropdownMenu extends Stimulus.Controller { + static targets = ["name"]; + + connect() { + this.registerListEvents(); + } + + registerListEvents(params) { + const toggle = this.element.querySelector(HANDLER_SELECTOR); + const content = this.element.querySelector(LIST_SELECTOR); + + const show = () => { + toggle.setAttribute('aria-expanded', true); + content.setAttribute('aria-hidden', false); + } + + const hide = () => { + toggle.setAttribute('aria-expanded', false); + content.setAttribute('aria-hidden', true); + } + + toggle.addEventListener('click', event => { + event.stopPropagation(); + JSON.parse(toggle.getAttribute('aria-expanded')) ? hide() : show(); + }) + + const buttonList = [...content.querySelectorAll('a')]; + buttonList.forEach(button => { + button.addEventListener('click', event => hide()); + }) + + const handleClosure = event => !content.contains(event.target) && hide(); + + window.addEventListener('click', handleClosure); + window.addEventListener('focusin', handleClosure); + } + } + + Stimulus.application.register("dropdown_menu", DropdownMenu); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/editable_field_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/editable_field_controller.js new file mode 100644 index 0000000..46bd281 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/editable_field_controller.js @@ -0,0 +1,52 @@ +(() => { + + class EditableField extends Stimulus.Controller { + static targets = ["name"]; + + connect() { + // this.element is the DOM element to which the controller is connected to. + const editable = this.element; + + const isSingle = (editable.dataset.editable == 'single') ? true : false; + const hidden = editable.nextElementSibling; + + editable.addEventListener('paste', (event) => { + event.preventDefault(); + + const clipboardText = (event.clipboardData || window.clipboardData).getData('text'); + const text = isSingle ? filterSingleLine(clipboardText) : clipboardText; + + const selection = window.getSelection(); + + if (selection.rangeCount) { + selection.deleteFromDocument(); + selection.getRangeAt(0).insertNode(document.createTextNode(text)); + } + + hidden.value = editable.innerText; + }); + + editable.addEventListener('input', (event) => { + const editedText = editable.innerText; + const text = isSingle ? filterSingleLine(editedText) : editedText; + + hidden.value = text; + }); + + if (isSingle) { + editable.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + } + }); + } + } + } + + Stimulus.application.register("editablefield", EditableField); + + function filterSingleLine(text) { + return text.replace(/\s/g, ' ').replace(/\s\s+/g, ' ') + } + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/modal_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/modal_controller.js new file mode 100644 index 0000000..a33ca93 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/modal_controller.js @@ -0,0 +1,47 @@ +(() => { + + class ModalController extends Stimulus.Controller { + initialize() { + // this.element is the DOM element to which the controller is connected to. + const thisElement = this.element; + + // Cancel button selector: [stimulus-modal-cancel-button] + const cancelButton = thisElement.querySelector('[stimulus-modal-cancel-button]'); + + // Clicking on the backdrop in this implementation + // does not close the modal window: + // const backdrop = thisElement.querySelector('sdoc-backdrop'); + + // Removing a modal window code added using Turbo: + const removeModal = () => { + thisElement.remove() + } + + // Removing the Escape listener: + const removeEscapeListener = () => { + document.removeEventListener("keydown", listenEscape); + } + + // Listening to Escape: + const listenEscape = (event) => { + if (event.key === 'Escape') { + removeModal(); + removeEscapeListener(); + } + }; + + // Add Listeners: + + document.addEventListener("keydown", listenEscape); + + cancelButton.addEventListener("click", function (event) { + event.preventDefault(); + removeModal(); + }); + + } + } + + Stimulus.application.register("modal_controller", ModalController); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/scroll_into_view_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/scroll_into_view_controller.js new file mode 100644 index 0000000..1617734 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/scroll_into_view_controller.js @@ -0,0 +1,11 @@ +(() => { + + class ScrollIntoView extends Stimulus.Controller { + connect() { + this.element.scrollIntoView() + } + } + + Stimulus.application.register("scroll_into_view", ScrollIntoView); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/tabs_controller.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/tabs_controller.js new file mode 100644 index 0000000..d5ead3f --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/controllers/tabs_controller.js @@ -0,0 +1,71 @@ +(() => { + + class Tabs extends Stimulus.Controller { + initialize() { + + // ** Tab buttons like this: + // + // Id1 + // Id2 + // + const sdocTabs = document.createElement('sdoc-tabs'); + const sdocTabContent = [...this.element.querySelectorAll('sdoc-tab-content')]; + const tabsData = sdocTabContent.reduce( + (accumulator, currentSdocTabContentElement, currentIndex) => { + // get data from the contents of the tab element in the DOM: + const key = currentSdocTabContentElement.id; + const state = currentSdocTabContentElement.hasAttribute('active'); + + const errors = [...currentSdocTabContentElement.querySelectorAll('sdoc-form-error')]; + + // create and prepare tab element: + const sdocTab = document.createElement('sdoc-tab'); + sdocTab.style.order = currentIndex; + sdocTab.innerHTML = key; + sdocTab.addEventListener("mouseup", () => { + this._activateTab(tabsData.tabs, key) + }); + sdocTabs.append(sdocTab); + sdocTab.setAttribute('data-testid', `form-tab-${key}`); + state && sdocTab.setAttribute('active', ''); + + if (errors.length) { + sdocTab.setAttribute('data-errors', errors.length); + accumulator.errors.push(key); + } + + // update accumulator (form state): + accumulator.tabs[key] = {}; + accumulator.tabs[key].element = currentSdocTabContentElement; + accumulator.tabs[key].order = currentIndex; + accumulator.tabs[key].state = state; + accumulator.tabs[key].handler = sdocTab; + accumulator.tabs[key].errors = errors.length; + + return accumulator; + }, { + tabs: {}, + errors: [] + }); + + // put tab handlers to the DOM + sdocTabContent.length && this.element.prepend(sdocTabs); + + // activate first tab with errors + tabsData.errors.length && this._activateTab(tabsData.tabs, tabsData.errors[0]); + } + + _activateTab(tabs, tabName) { + for (const { element, handler } of Object.values(tabs)) { + element.removeAttribute('active'); + handler.removeAttribute('active'); + } + // activate the tab: + tabs[tabName].element.setAttribute('active', ''); + tabs[tabName].handler.setAttribute('active', ''); + } + } + + Stimulus.application.register("tabs", Tabs); + +})(); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.css new file mode 100644 index 0000000..35ab06f --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.css @@ -0,0 +1,531 @@ +/* diff */ +:root { + --pre-stripe: 20px; + --pre-stripe-color: rgba(0,0,0,0.02); + --pre-block-bg-color: rgba(0,0,0,0.01); + + --diff-block-color-left: rgba(255, 55, 55, .05); + --diff-word-color-left: rgba(255, 55, 55, .2); + --diff-icon-color-left: rgba(255, 55, 55, .75); + --diff-document-color-left: rgba(255, 55, 55, 1); + + --diff-block-color-right: rgba(20, 120, 20, .05); + --diff-word-color-right: rgba(20, 120, 20, .2); + --diff-icon-color-right: rgba(20, 120, 20, .75); + --diff-document-color-right: rgba(20, 120, 20, 1); +} + +/* + *** diff *** + */ + +.diff { + scroll-behavior: smooth; + background-color: var(--color-bg-main); + + display: grid; + place-items: stretch stretch; + place-content: stretch stretch; + grid-template-columns: minmax(0, 1fr) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + minmax(0, 1fr); + grid-template-rows: minmax(0, max-content) + minmax(0, 1fr); + + gap: var(--base-rhythm); + + min-height: 0; /* to prevent from overflowing the parent flex container */ +} + +/* controls */ + +.diff_controls { + display: flex; + justify-content: flex-end; + gap: calc(var(--base-rhythm)/2); +} + +#diff_left_open { + color: var(--diff-document-color-left); +} + +#diff_right_open { + color: var(--diff-document-color-right); +} + +#diff_left_close, +#diff_right_close { + color: var(--color-link); +} + +#diff_left_open:hover, +#diff_right_open:hover { + color: var(--color-hover); +} + +/* columns */ +.diff_column { + overflow: auto; + overflow-y: scroll; + + overflow-wrap: break-word; + + border-radius: 4px; + border: 1px solid var(--color-border); + + position: relative; /* for position:sticky */ +} + +.diff_column[left] { + direction:rtl; +} + +.diff_column[right] { + direction:ltr; +} + +.diff_inner { + direction: initial; + padding-bottom: 100%; /* to balance the scrolling freely */ +} + +.diff_content { + display: flex; + flex-direction: column; + gap: var(--base-rhythm); + padding: var(--base-rhythm); +} + +/* details with summary */ + +.diff details { + width: 100%; +} + +.diff summary { + list-style: none; + display: flex; + gap: var(--base-rhythm); + cursor: pointer; + color: var(--color-link); +} + +.diff details[modified] > summary { + color: var(--color-fg-accent); +} + +.diff details[modified="left"] > summary { + color: var(--diff-document-color-left); +} + +.diff details[modified="right"] > summary { + color: var(--diff-document-color-right); +} + +.diff summary:hover, +.diff details[modified] > summary:hover { + color: var(--color-hover); +} + +.diff summary::-webkit-details-marker { + display: none; +} + +.diff details > summary::before { + content:"+"; +} + +.diff details[open] > summary::before { + content:"–"; +} + +/* document / details */ + +.diff_document { + background-color: var(--color-bg-contrast); + border: 1px solid transparent; + border-radius: 4px; + padding: 0 var(--base-rhythm); +} + +.diff_document[modified] { + border-color: var(--color-fg-accent); +} + +.diff_document[modified="left"] { + border-color: var(--diff-document-color-left, rgba(255, 55, 55, 1)); +} + +.diff_document[modified="right"] { + border-color: var(--diff-document-color-right, rgba(20, 120, 20, 1)); +} + +.diff_document > summary { + line-height: 1.2; + padding: var(--base-rhythm) 0; + font-size: var(--font-size-sm); + font-weight: 700; + justify-content: space-between; /* '+' to right */ +} + +.diff_document[open] > summary { + /* + When the details are closed up, the summary sometimes covers the bottom border. + That's why we only add the background for cases where the card is open + and sticking makes sense. + */ + background: var(--color-bg-contrast); + position: sticky; + top: 0; +} + +.diff_document > summary .document_title { + flex-grow: 1; +} + +.diff_document[open] > summary { + border-bottom: 1px dotted; +} + +.diff_document > summary::before, +.diff_document[open] > summary::before { + content: none !important; +} + +.diff_document > summary::after { + content:"+"; +} + +.diff_document[open] > summary::after { + content:"–"; +} + +/* folder */ + +.diff_folder { + display: flex; + align-items: center; + justify-content: flex-start; + column-gap: calc(var(--base-rhythm)/2); + font-size: var(--font-size-sm); + min-width: 0; + line-height: 1.5; + padding-top: var(--base-rhythm); +} + +/* node content */ + +.diff_node { + margin: var(--base-rhythm) 0; +} + +.diff_node_fields { + display: flex; + flex-direction: column; + margin: var(--base-rhythm) 0; + row-gap: calc(var(--base-rhythm) / 2); +} + +.diff_node > .diff_node_fields { + padding-left: calc(var(--base-rhythm)*2); +} + +.diff_node_field { + display: flex; + flex-wrap: wrap; + align-items: baseline; + column-gap: calc(var(--base-rhythm) / 2); +} + +.diff_node_field > .badge { + line-height: var(--pre-stripe); +} + +/* + *** changelog *** + */ + +.changelog { + display: flex; + flex-direction: column; +} + +.changelog .sdoc-table_key_value { + width: auto; +} + +.changelog .diff_column { + margin-right: -16px; + border-radius: 0; + border: none; + border-right: 1px solid var(--color-border); +} + +.changelog_summary { + padding: calc(2 * var(--base-rhythm)); +} + +.changelog_content { + display: flex; + flex-direction: column; + gap: var(--base-rhythm); + margin-bottom: calc(4 * var(--base-rhythm)); +} + +.changelog_changes { + display: flex; + flex-direction: column; + gap: var(--base-rhythm); +} + +.changelog_change { + background-color: var(--color-bg-contrast); + border: 1px solid var(--color-border); + border-radius: 4px; + display: flex; + flex-direction: row; + flex-wrap: wrap; +} + +.changelog_change_meta { + background-color: var(--color-bg-main); + width: 100%; + font-size: var(--font-size-xsm); + font-weight: 700; + display: flex; + gap: var(--base-rhythm); + padding: var(--base-rhythm); +} + +.changelog_change_type { + font-size: var(--font-size-xsm); +} + +.changelog_change_type.removed { + color: red; +} + +.changelog_change_type.modified { + color: orange; +} + +.changelog_change_type.added { + color: green; +} + +.changelog_change_node { + width: 100%; + padding: var(--base-rhythm); +} + +@media (min-width: 768px) { + .changelog_change_node { + /* width: calc(50% - var(--base-rhythm)); */ + width: 50%; + } +} + +.changelog_node_null { + display: flex; + justify-content: center; + align-items: center; + color: var(--color-placeholder); + + height: 100%; + min-height: 32px; + background:repeating-linear-gradient( + -45deg, + rgba(234, 234, 234, 0.1), + rgba(234, 234, 234, .1) 10px, + rgba(234, 234, 234, .15) 10px, + rgba(234, 234, 234, .15) 20px + ); + +} + +/* + *** MISC *** + */ + +/* badge */ + +.badge { + white-space: nowrap; +} + +.badge::before { + content: attr(text); + padding: 0 calc(var(--base-rhythm)/2); + border: 1px solid; + border-radius: calc(var(--base-rhythm)/2); + font-size: var(--font-size-xxsm); + font-weight: 600; + text-transform: uppercase; +} + +/* in summary: */ +[modified="left"] > summary .badge::before, +/* in field: */ +[modified="left"] > .badge::before { + color: white; + background-color: var(--diff-icon-color-left); + border-color: var(--diff-icon-color-left); +} + +/* in summary: */ +[modified="right"] > summary .badge::before, +/* in field: */ +[modified="right"] > .badge::before { + color: white; + background-color: var(--diff-icon-color-right); + border-color: var(--diff-icon-color-right); +} + +/* pre */ + +.sdoc_pre_content { + flex-grow: 1; + white-space: pre-wrap; + overflow-x: clip; + font-family: monospace; + font-size: 0.85em; + line-height: var(--pre-stripe); + background-image: repeating-linear-gradient( + to bottom, + var(--pre-stripe-color), + var(--pre-stripe-color) var(--pre-stripe), + transparent var(--pre-stripe), + transparent calc(var(--pre-stripe)*2) + ); + background-color: var(--pre-block-bg-color); +} + +[multiline] .sdoc_pre_content { + flex-basis: 100%; +} + +[modified="left"] > .sdoc_pre_content { + background-color: var(--diff-block-color-left); +} +.lambda_red {background-color: var(--diff-word-color-left);} + +[modified="right"] > .sdoc_pre_content { + background-color: var(--diff-block-color-right); +} +.lambda_green {background-color: var(--diff-word-color-right);} + +/* preloaded */ +/* + The element has been pre-loaded + and a smooth appearance effect is added to it. + The element will retain the computed values set by the last keyframe. + */ +.preloaded { + position: relative; + animation: fadeInPreloaded 1s ease-in-out; + animation-fill-mode: forwards; +} + +@keyframes fadeInPreloaded { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +/* skeleton */ + +.skeleton_spinner_container { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + min-height: 333px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + grid-column: 1/3; + grid-row: 2/3; + z-index: 11; +} + +@keyframes change-color { + from {background-color: rgba(255,255,255,0.8);} + to {background-color: rgba(255,255,255,0.3);} +} + +@keyframes pulse { + 0%, 100% { + opacity: .5; + } + 50% { + opacity: 1; + } +} + +.skeleton_spinner { + position: relative; + text-indent: -9999em; + animation: mulShdSpin 1.3s infinite linear; + transform: translateZ(0); + /* size */ + font-size: 8px; + margin: 36px; + /* dot */ + color: var(--color-fg-accent); + width: 1em; + height: 1em; + border-radius: 50%; +} + +@keyframes mulShdSpin { + 0%, + 100% { + box-shadow: 0 -3em 0 0.2em, + 2em -2em 0 0em, 3em 0 0 -1em, + 2em 2em 0 -1em, 0 3em 0 -1em, + -2em 2em 0 -1em, -3em 0 0 -1em, + -2em -2em 0 0; + } + 12.5% { + box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, + 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em, + -2em 2em 0 -1em, -3em 0 0 -1em, + -2em -2em 0 -1em; + } + 25% { + box-shadow: 0 -3em 0 -0.5em, + 2em -2em 0 0, 3em 0 0 0.2em, + 2em 2em 0 0, 0 3em 0 -1em, + -2em 2em 0 -1em, -3em 0 0 -1em, + -2em -2em 0 -1em; + } + 37.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, + 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em, + -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em; + } + 50% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, + 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em, + -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em; + } + 62.5% { + box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, + 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0, + -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em; + } + 75% { + box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, + 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, + -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0; + } + 87.5% { + box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, + 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em, + -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em; + } +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.js new file mode 100644 index 0000000..3d77bbc --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/diff.js @@ -0,0 +1,153 @@ +window.addEventListener("load",function(){ + + const mutatingFrame = document.querySelector('#diff_result'); + + var observer = new MutationObserver(function (mutationsList, observer) { + + const diffTabRoot = mutatingFrame.querySelector('.diff'); + if (diffTabRoot) { + // triggers on the diff tab + prepareBulkButtons(diffTabRoot); + syncDiff(diffTabRoot); + } + + // Disable the observer after the first trigger + // because the functions modify the elements inside the #diff_result. + observer.disconnect(); + }); + + observer.observe( + mutatingFrame, + { + childList: true, + subtree: true + } + ); + +},false); + +function prepareBulkButtons(root) { + + const leftColumn = root.querySelector('.diff_column[left]'); + const rightColumn = root.querySelector('.diff_column[right]'); + + const leftOpenBtn = root.querySelector('#diff_left_open'); + const leftCloseBtn = root.querySelector('#diff_left_close'); + const rightOpenBtn = root.querySelector('#diff_right_open'); + const rightCloseBtn = root.querySelector('#diff_right_close'); + + const detailsLeftAll = [...leftColumn.querySelectorAll('details')]; + const detailsRightAll = [...rightColumn.querySelectorAll('details')]; + const detailsLeft = [...leftColumn.querySelectorAll('details[modified]')]; + const detailsRight = [...rightColumn.querySelectorAll('details[modified]')]; + + leftOpenBtn.addEventListener("click", (event) => { + event.preventDefault(); + _openAll(detailsLeft); + }); + leftCloseBtn.addEventListener("click", (event) => { + event.preventDefault(); + _closeAll(detailsLeftAll); + leftColumn.scrollTo(0, 0); + }); + rightOpenBtn.addEventListener("click", (event) => { + event.preventDefault(); + _openAll(detailsRight); + }); + rightCloseBtn.addEventListener("click", (event) => { + event.preventDefault(); + _closeAll(detailsRightAll); + rightColumn.scrollTo(0, 0); + }); +} + +function syncDiff(root) { + + const sync = [...root.querySelectorAll('button[uid]')] + .reduce((acc, curr) => { + const uid = curr.getAttribute('uid'); + const side = curr.getAttribute('side'); + acc[uid] = { + [side]: curr, + ...acc[uid] + } + return acc + },{}); + + Object.entries(sync).forEach(([uid, obj]) => { + if (!obj.left) { + obj.right.remove() + return + }; + + if (!obj.right) { + obj.left.remove() + return + }; + + obj.left.addEventListener("click", (event) => { + event.preventDefault(); + + // _openAll(detailsLeftAll); + _openAncestors(obj.left, root); + _scrollTo(obj.left); + + setTimeout(() => { + // _openAll(detailsRightAll); + _openAncestors(obj.right, root); + _scrollTo(obj.right); + }, 900); + }); + + obj.right.addEventListener("click", (event) => { + event.preventDefault(); + + // _openAll(detailsRightAll); + _openAncestors(obj.right, root); + _scrollTo(obj.right); + + setTimeout(() => { + // _openAll(detailsLeftAll); + _openAncestors(obj.left, root); + _scrollTo(obj.left); + }, 900); + }); + }) +}; + +function _openAncestors(element, root) { + + let currentElement = element; + + while (currentElement && currentElement !== root) { + currentElement = currentElement.parentElement; + + if (currentElement && currentElement.tagName === 'DETAILS') { + currentElement.setAttribute('open', ''); + } + } +}; + +function _scrollTo(target) { + // We insert a special element into the button ('button[uid]') + // that compensates by 40 pixels + // for the height of the sticky header + // at the top of the scroll container: + // *** + // + + const a = target.querySelector('a-a') || target; + a.scrollIntoView({ behavior: "smooth" }); +}; + +function _closeAll(details) { + details.forEach(detail => { + detail.removeAttribute("open") + }); +}; + +function _openAll(details) { + details.forEach(detail => { + detail.setAttribute("open", "") + }); +}; diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/element.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/element.css new file mode 100644 index 0000000..fc5c6af --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/element.css @@ -0,0 +1,1822 @@ + + +[data-viewtype="source-file"] .requirement__link:hover { + text-decoration: none; +} + +svg { + /* Disable shrinking of icons in flex strings */ + flex-shrink: 0; +} + +/* typography */ + +h1 { font-size: 2em; } +h2 { font-size: 1.6em; } +h3 { font-size: 1.4em; } +h4 { font-size: 1.2em; } +h5 { font-size: 1em; } +h6 { font-size: 1em; } + +h1:first-child, +h2:first-child, +h3:first-child, +h4:first-child, +h5:first-child, +h6:first-child { + margin-top: 0; +} + +/* a */ + +a { + /* Disabled link styles */ + text-decoration: none; + color: gray; + transition: color .2s ease; +} + +a:link, +a:visited, +a[href] { /* or a[href] */ + /* Enabled link styles */ + text-decoration: none; + color: var(--color-link); +} + +a:hover { + /* color: blueviolet; */ + color: var(--color-hover); +} + +a[aria-disabled="true"] { + /* color: currentColor; */ + cursor: not-allowed; + opacity: 0.5; + text-decoration: none; + pointer-events: none; +} + +/* misc */ + +code { + position: relative; + padding: 0 4px; + font-style: normal; + font-family: var(--code-font-family); + font-size: var(--code-font-size); + background-color: var(--color-bg-main); + border: 1px solid var(--color-border); + border-radius: 4px; + + overflow-wrap: break-word; + word-wrap: break-word; + -webkit-box-decoration-break: clone; + box-decoration-break: clone; +} + +/* action_button */ + +.actions_group { + display: flex; + /* header context: */ + column-gap: calc(var(--base-rhythm)/2); + margin-left: auto; +} + +.action_button, +a.action_button, +a.action_button:link, +a.action_button:visited { + font-size:var(--font-size-xsm); + font-weight: 600; + text-align: left; + text-decoration: none; + white-space: nowrap; + position: relative; + display: inline-flex; + + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + border-radius: 6px; + border: 1px solid transparent; + backface-visibility: hidden; + user-select: none; + cursor: pointer; + appearance: none; + + /* 1.5 column-gap is compensated by SVG negative margin */ + column-gap: calc(var(--base-rhythm)*1.5); + padding-left: calc(var(--base-rhythm)*1.5); + padding-right: calc(var(--base-rhythm)*1.5); + min-height: calc(var(--base-rhythm)*4); + max-width: 100%; + + /* box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; */ + color: var(--color-action); + background-color: rgb(255, 255, 255); + border-color: rgba(0, 0, 0, 0.05); + background-clip: padding-box; + + transition: 0.2s; +} + +.action_button:hover, +a.action_button:hover { + box-shadow: rgb(0 0 0 / 10%) 0px 2px var(--base-rhythm) 0px; + color: var(--color-hover); + z-index: 6; +} + +.action_button:disabled, +.action_button:disabled:hover, +.action_button[aria-disabled="true"], +.action_button[aria-disabled="true"]:hover { + color: var(--color-action); + opacity: .4; + cursor: default; +} + +.action_button svg { + /* + action_button 1.5 column-gap + is compensated by SVG negative margin + */ + margin-left: calc(var(--base-rhythm)*(-.5)); + margin-right: calc(var(--base-rhythm)*(-.5)); +} + +[data-action-type="submit"], +.action_button[type=submit] { + color: var(--color-submit); +} + +[data-action-type="action"], +[data-action-type="confirm_delete"] { + color: var(--color-action) !important; + border-color: var(--color-action) !important; +} + +[data-action-type="delete"], +[data-action-type="confirm_delete"] { + color: var(--color-danger) !important; + border-color: var(--color-danger) !important; +} + +[data-action-type="confirm_delete"]:hover { + color: var(--color-bg-contrast) !important; + background: var(--color-danger) !important; +} + +[data-action-type="cancel"], +.action_button[href*="cancel"] { + color: var(--color-cancel) !important; +} + +.action_icon, +a.action_icon, +a.action_icon:link, +a.action_icon:visited { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + backface-visibility: hidden; + user-select: none; + cursor: pointer; + appearance: none; + border: none; + border-color: transparent; + background-color: rgba(0,0,0,0); + background: rgba(0,0,0,0); + box-shadow: none; + background-clip: padding-box; + + color: var(--color-action); + transition: 0.2s; + padding: calc(var(--base-rhythm)*.5); + z-index: 2; +} + +.action_icon.secondary, +a.action_icon.secondary, +a.action_icon.secondary:link, +a.action_icon.secondary:visited { + color: var(--color-link); +} + +.action_icon.secondary:hover, +a.action_icon.secondary:hover, +.action_icon:hover, +a.action_icon:hover { + color: var(--color-hover); + z-index: 6; +} + +.action_button.compact { + column-gap: 0; + padding-left: calc(var(--base-rhythm)* 0.75); + padding-right: calc(var(--base-rhythm)* 0.75); + min-height: calc(var(--base-rhythm)*3); +} + +.action_button.compact .action_button_compact__arising { + overflow: hidden; + + max-width: 0; + margin-left: 0; + + transition-property: max-width, margin; + transition-duration: .5s; + transition-timing-function: ease-in-out; + transition-delay: 1s; +} + +.action_button.compact:hover > .action_button_compact__arising { + max-width: 200px; + margin-left: var(--base-rhythm); + + transition-property: max-width, margin; + transition-duration: .5s; + transition-timing-function: ease-in-out; + transition-delay: 0; +} + +/* TODO */ +sdoc-node-controls .action_button { + /* depends on sdoc-node-controls: */ + /* + width: calc(var(--base-rhythm)*4); + height: calc(var(--base-rhythm)*4); + */ + padding: 0 !important; + width: unset; + height: unset; + min-height: calc(var(--base-rhythm)*3) !important; + max-width: 100%; + max-height: 100%; + aspect-ratio: 1; + border-radius: 20% !important; + + vertical-align: top; +} + +/* field_action */ +/* TODO: optimize code with .action_icon & .action_button */ + +.field_action { /* button */ + font-size:var(--font-size-xsm); + font-weight: 600; + text-align: left; + text-decoration: none; + white-space: nowrap; + + position: static; + display: inline-flex; + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + backface-visibility: hidden; + user-select: none; + cursor: pointer; + appearance: none; + border: none; + border-color: transparent; + background-color: rgba(0,0,0,0); + background: rgba(0,0,0,0); + box-shadow: none; + background-clip: padding-box; + + color: var(--color-action); + transition: 0.2s; + padding: calc(var(--base-rhythm)*.5); + z-index: 2; +} + +.field_action:hover, +a.field_action:hover { + color: var(--color-hover); + z-index: 6; +} + +.field_action::before { + content: ''; + position: absolute; + /* The element is expected to be placed in a context + that defines the top and bottom boundaries. + + The width of the element must be enough + to cover the entire available context, + and will be cut off by the parent element via overflow. + */ + top: calc(var(--base-rhythm)*(-3)); /* -2 */ + bottom: calc(var(--base-rhythm)*(-1)); /* -2 */ + left: -100vw; + right: -100vw; + z-index: 0; + pointer-events: none; + /* Determines the shade of the color through the opacity of the element. + The color is passed from the parent. + */ + transition: background-color 0.3s; + background-color: transparent; + opacity: .1; /* Defines the color shade. */ +} + +.field_action:hover::before { + background: currentcolor; +} + +/* *** + USED BY copy_to_clipboard controller + */ + +sdoc-field { + display: flex; + /* it is assumed that it will automatically stretch, as a block element, + to the entire field space, and the elements in the service area will be + positioned relative to it: + */ + position: relative; + flex-grow: 1; + width: 100%; /* holds within the width of the parent */ +} + +sdoc-field-content { + flex-grow: 1; + width: 100%; /* holds within the width of the parent */ +} + +.copy_to_clipboard-cover { + position: absolute; + z-index: 98; + top: 0; + bottom: 0; + left: 0; + right: 0; + pointer-events: none; + + border-top-right-radius: 6px; /* TODO 4 + in button*/ + background-color: rgba(242, 100, 42, 0); + transition: .5s ease-out; +} + +.copy_to_clipboard-cover:hover { + background-color: rgba(242, 100, 42, 0.05); + transition: .5s ease-out; +} + +/* Fix: Prevent .copy_to_clipboard-button from receiving hover when covered by dropdown menu */ +sdoc-field > sdoc-field-service .copy_to_clipboard-button { + visibility: hidden; +} + +sdoc-field:hover > sdoc-field-service .copy_to_clipboard-button { + visibility: visible; +} + +/* button overrides */ +.copy_to_clipboard-button.action_button { + height: calc(var(--base-rhythm)*3); + width: calc(var(--base-rhythm)*3); + min-height: unset; + padding: var(--base-rhythm); + position: absolute; + right: 0; + pointer-events: auto; + + max-height: 100%; /* for meta row: to keep the copy button from expanding out of the content line */ +} + +/* button behavior */ +sdoc-field .copy_to_clipboard-button { + transition: .5s ease-out; + opacity: 0; +} + +sdoc-field:hover .copy_to_clipboard-button { + opacity: 1; +} + +/* *** + USED BY copy_stable_link controller + inside sdoc-node + */ + +.copy_stable_link-button { + display: inline-flex; + align-items: center; + justify-content: center; + padding: var(--base-rhythm); + + position: absolute; + left: 0; + top: 0; + + cursor: pointer; + transition: .5s ease-out; + opacity: 0; +} + +.copy_stable_link-button:hover { + color: var(--color-action); +} + +sdoc-node:hover .copy_stable_link-button { + opacity: 1; +} + +/* ANCHOR */ + +sdoc-anchor { + /* for Fixed Headers + Section Anchors */ + /* calc(var(--base-gap) + var(--base-padding)); */ + scroll-snap-margin-top: var(--base-gap); + scroll-margin-top: var(--base-gap); +} + +sdoc-node > sdoc-anchor { + scroll-snap-margin-top: unset; /** top: 0; */ + scroll-margin-top: unset; /** top: 0; */ + + display: block; + position: absolute; + top: 0; + bottom: 0; + z-index: 0; +} + +sdoc-anchor.anchor_in_rst { + top:unset; + /* + For anchors generated within the text, + we shift them to the left, beyond the node + (by the sdoc-node padding-inline). + */ + transform: translateX(calc(-4 * var(--base-rhythm))); +} + +sdoc-anchor:target + sdoc-node-content sdoc-node-title, +sdoc-anchor:target + sdoc-section sdoc-section-title, +sdoc-anchor:target + .requirement__title { + background-color: var(--color-highlight); +} + +sdoc-anchor .anchor_block { + display: none; +} + +/* + This styles should only be triggered if + export/html/_static/controllers/anchor_controller.js + processes the parent sdoc-node. +*/ +sdoc-node[data-controller="anchor_controller"] sdoc-anchor { + position: absolute; + z-index: 2; + left: 0; + transition: opacity 0.5s; + opacity: 0; +} + +sdoc-node[data-controller="anchor_controller"]:hover sdoc-anchor { + opacity: 1; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor.anchor_has_back_links { + opacity: 1; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor:hover { + z-index: 10; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_block { + display: block; + position: absolute; + top: 0; + left: calc(-4 * var(--base-rhythm) - 3px); + + border-radius: 6px; + transition: opacity 0.2s; + opacity: .6; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor:hover .anchor_block { + background-color: rgb(255, 255, 255); + border-color: rgba(0, 0, 0, 0.05); + box-shadow: rgb(0 0 0 / 10%) 0px 2px var(--base-rhythm) 0px; + opacity: 1; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_button { + cursor: pointer; + font-size:var(--font-size-sm); + font-weight: 600; + text-align: left; + white-space: nowrap; + position: relative; + display: inline-flex; + align-items: center; + justify-content: flex-start; + + border-radius: 6px; + border: 1px solid transparent; + background-clip: padding-box; + + /* 1.5 column-gap is compensated by SVG negative margin */ + column-gap: calc(var(--base-rhythm)*1.5); + padding-left: calc(var(--base-rhythm)*1.5); + padding-right: calc(var(--base-rhythm)*1.5); + min-height: calc(var(--base-rhythm)*4); + min-width: calc(var(--base-rhythm)*4); + + /* box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; */ + /* color: var(--color-action); */ + + overflow: hidden; + + transition: opacity 0.2s; + opacity: .6; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_button:hover { + color: var(--color-hover); + z-index: 6; + + opacity: 1; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_button svg { + color: var(--color-fg-secondary); + margin-left: calc(var(--base-rhythm)*(-.5)); + margin-right: calc(var(--base-rhythm)*(-.5)); +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor.anchor_has_back_links .anchor_button svg { + color: black; + opacity: 1; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_button:hover svg { + color: var(--color-action) !important; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_button_text { + font-size: var(--font-size-sm); + font-weight: bolder; + + display: none; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor:hover .anchor_button_text { + display: block; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_back_links { + min-width: 300px; + padding-left: calc(var(--base-rhythm)*4); + padding-right: var(--base-rhythm); + padding-top: var(--base-rhythm); + padding-bottom: calc(var(--base-rhythm)*1); + + display: none; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor:hover .anchor_back_links { + display: block; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_back_links a { + display: list-item; +} +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_back_links a::marker { + content: '⇠ '; + width: calc(var(--base-rhythm)*4); +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor .anchor_back_links_number { + color: var(--color-fg-accent); + position: absolute; + width: calc(var(--base-rhythm)*4); + text-align: center; + top: calc(var(--base-rhythm)*3); + left: 0; + font-weight: bold; +} + +sdoc-node[data-controller="anchor_controller"] sdoc-anchor:hover .anchor_back_links_number { + top: calc(var(--base-rhythm)*5); +} + +/* nav */ + +.nav { + list-style: none; + padding: 0; + margin: 0; + + display: flex; + flex-flow: column nowrap; + background-color: var(--color-bg-ui); + width: var(--base-gap); + height: 100%; +} + +.nav_list { + list-style: none; + padding: 0; + margin: 0; +} + +.nav_list li { + margin-bottom: var(--base-rhythm); +} + +.nav_list__link { + display: flex; + column-gap: var(--base-rhythm); +} + +/* nav_button */ + +.nav_button { + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + + text-decoration: none; + + height: var(--base-gap); + width: var(--base-gap); + transition: 0.3s; + + color: var(--color-fg-secondary); +} + +.nav_button:hover { + color: var(--color-fg-contrast); +} + +.nav .nav_button { + color: var(--color-fg-secondary-invert); + background-color: transparent; + border-left: 2px solid transparent; +} + +.nav .nav_button:hover { + color: var(--color-bg-contrast); + border-color: var(--color-bg-contrast); +} + +/* should be like .nav .nav_button:hover */ +[data-viewtype="document-tree"] [data-link="index"], +[data-viewtype="search"] [data-link="search"], +[data-viewtype="diff"] [data-link="diff"], +[data-viewtype="requirements-coverage"] [data-link="requirements_coverage"], +[data-viewtype="traceability-matrix"] [data-link="traceability-matrix"], +[data-viewtype="coverage-tree"] [data-link="source_coverage"] { + color: var(--color-bg-contrast); + border-color: var(--color-bg-contrast); + cursor: default; +} + +/* sdoc tabs (page nav) */ + +.sdoc-tabs { + border-bottom: 1px solid var(--color-border); +} + +.sdoc-tab-list { + display: flex; + overflow: auto; + margin-bottom: -1px; +} + +.sdoc-tab { + padding: var(--base-rhythm) calc(2 * var(--base-rhythm)); + font-size: var(--font-size-xsm); + font-weight: 600; + line-height: 1; + color: var(--color-link); + text-decoration: none; + background-color: transparent; + border-width: 1px 1px 0px; + border-top-style: solid; + border-right-style: solid; + border-left-style: solid; + border-top-color: transparent; + border-right-color: transparent; + border-left-color: transparent; + border-image: initial; + border-bottom-style: initial; + border-bottom-color: initial; + + color: var(--color-fg-contrast); +} + +.sdoc-tab:hover { + color: var(--color-hover); +} + +.sdoc-tab[active] { + color: var(--color-fg-contrast); + border-color: var(--color-border); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + background-color: var(--color-bg-main); +} + +/* tags */ + +.tags { + padding-bottom: var(--base-gap); +} + +.tag { + display: inline-flex; + align-items: center; + background-color: rgba(0,0,0,0.1); + border: 2px solid rgba(0,0,0,0.05); + font-size: 12px; + line-height: 1; + vertical-align: middle; + margin: 2px 0px; + padding-left: 8px; + border-radius: 2em; +} + +.tag_badge { + display: inline-flex; + justify-content: center; + align-items: center; + font-size: var(--font-size-xxsm); + background-color: rgba(255, 255, 255, 0.75); + border: 4px solid transparent; + min-width: 18px; + height: 18px; + border-radius: 2em; + margin-left: 4px; +} + +/* coverage */ + +.value-bar { + display: flex; + height: 1rem; + align-items: center; + gap: 4px; +} + +.value-bar_bar { + width: 3rem; + border-radius: .5rem; + + /* box-shadow: inset 0px 2px 2px 0px #ccc; */ + border: 1px solid rgba(0,0,0,0.1); + position: relative; + overflow: hidden; + + height: 0.75rem; + + background-color: rgba(255, 255, 255, 0.2); +} + +.value-bar_bar[data-value] { + border: 1px solid rgb(80, 240, 40); + background-color: rgba(255, 255, 255, 1); +} + +.value-bar_filler { + position: absolute; + top: 0; + bottom: 0; + left: 0; + background: rgb(80, 240, 40); +} + +.value-bar_text { + width: 2.5rem; + text-align: right; + font-size: 0.75rem; + line-height: 1; + font-weight: 600; +} + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +/* svg icon */ + +svg.svg_icon polyline, +svg.svg_icon line, +svg.svg_icon circle, +svg.svg_icon rect, +svg.svg_icon path { + fill: none; + fill-rule: evenodd; + stroke-width: 1.5; + /* stroke: #000; */ + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + /* transition: 0.2s; */ +} + +svg.svg_icon { + width: calc(var(--base-rhythm)*2); + height: calc(var(--base-rhythm)*2); + flex: 0 0 auto; + background: transparent; + /* color: rgb(246, 153, 13); */ +} + +.svg_icon_hover_visible { + display: none; +} +.anchor_button:hover .svg_icon_hover_visible, +svg:hover .svg_icon_hover_visible { + display: inline; +} +.svg_icon_not_hover_visible { + display: inline; +} +.anchor_button:hover .svg_icon_not_hover_visible, +svg:hover .svg_icon_not_hover_visible { + display: none; +} + +/* .header */ + +.header { + height: calc(var(--base-rhythm)*6); + display: flex; + align-items: center; + justify-content: flex-start; + column-gap: calc(var(--base-rhythm)/2); + padding-left: calc(var(--base-rhythm)*2); + padding-right: var(--base-rhythm); + border-bottom: var(--base-border); + min-width: 0; +} + +.header__document_title { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: var(--font-size-sm); + font-weight: 700; + + flex-shrink: 0.1; +} + +.header__project_name { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: var(--font-size-sm); + font-weight: 400; + min-width: calc(var(--base-rhythm)*2.5); + + flex-shrink: 100; +} + +/* .footer */ + +.footer { + display: flex; + align-items: center; + justify-content: flex-end; + height: 100%; + padding: var(--base-rhythm) calc(var(--base-rhythm)*2); + column-gap: calc(var(--base-rhythm)/2); + background-color: var(--color-bg-ui); + color: var(--color-fg-secondary-invert); + font-size: .85rem; +} + +a.strictdoc__link { + color: var(--color-fg-accent); + fill: var(--color-fg-accent); +} + +a.strictdoc__version { + color: var(--color-fg-secondary-invert); + fill: var(--color-fg-secondary-invert); + display: flex; + column-gap: calc(var(--base-rhythm)/2); + align-items: center; +} + +a.strictdoc__link:hover, +a.strictdoc__version:hover { + color: var(--color-bg-main); + fill: var(--color-bg-main); +} + +/* --md-source-version-icon: url(data:image/svg+xml;charset=utf-8,); */ + + +/* pagetype */ + +.pagetype { + font-size: var(--font-size-xxsm); + font-weight: 700; + text-transform: uppercase; + color: var(--color-fg-secondary); + display: flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +/* viewtype */ + +.viewtype { + position: relative; + font-size: var(--font-size-xsm); +} + +.viewtype__handler { + font-weight: 500; + color: var(--color-fg-accent); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + column-gap: calc(var(--base-rhythm)/2); + user-select: none; +} + +.viewtype__menu { + position: absolute; + z-index: 99; + left: calc(var(--base-rhythm)*(-2)); + top: calc(var(--base-rhythm)*3); + margin: 0; + list-style: none; + padding: var(--base-rhythm); + background: var(--color-bg-contrast); + box-shadow: 0 2px 8px rgb(0 0 0 / 20%); + border-radius: var(--base-rhythm); + font-weight: 500; + display: flex; + flex-direction: column; + row-gap: calc(var(--base-rhythm)/2); +} + +.viewtype__menu[aria-hidden="true"] { + display: none; +} + +.viewtype__menu[aria-hidden="false"] { + display: flex; +} + +.viewtype__menu_header { + padding: var(--base-rhythm); + text-transform: uppercase; + color: var(--color-fg-secondary); + font-weight: 700; + font-size: var(--font-size-xxsm); +} + +.viewtype__menu_item { + padding: 0; + margin: 0; + list-style: none; + white-space: nowrap; + display: block; + padding: var(--base-rhythm); + border-radius: calc(var(--base-rhythm)/2); +} + +.viewtype__menu_item, +.viewtype__menu_item:link, +.viewtype__menu_item:visited { + text-decoration: none; + color: var(--color-fg-main); +} + +.viewtype__menu_item:hover { + background-color: var(--color-bg-secondary); + color: var(--color-fg-accent); +} + +[data-viewtype="document"] [data-viewtype_link="document"], +[data-viewtype="table"] [data-viewtype_link="table"], +[data-viewtype="traceability"] [data-viewtype_link="traceability"], +[data-viewtype="deep_traceability"] [data-viewtype_link="deep_traceability"], +[data-viewtype="standalone_document"] [data-viewtype_link="standalone_document"], +[data-viewtype="html2pdf"] [data-viewtype_link="html2pdf"], +.viewtype__menu_item.active { + background-color: var(--color-bg-accent); + color: var(--color-fg-accent); + cursor: default; +} + +/* sdoc-menu */ + +sdoc-menu menu { + position: absolute; + z-index: 99; + right: 100%; + top: 0; + margin: 0; + list-style: none; + padding: var(--base-rhythm); + background: var(--color-bg-contrast); + box-shadow: 0 2px 8px rgb(0 0 0 / 20%); + border-radius: var(--base-rhythm); + font-weight: 500; + + display: flex; + flex-direction: column; + row-gap: calc(var(--base-rhythm)/2); + +} + +sdoc-menu.add_node menu { + display: grid; + grid-template-columns: minmax(min-content, max-content) + minmax(min-content, max-content) + minmax(min-content, max-content) + minmax(min-content, max-content); +} + +sdoc-menu menu[aria-hidden="true"] { + display: none; +} + +sdoc-menu menu[aria-hidden="false"] { + display: flex; +} +sdoc-menu.add_node menu[aria-hidden="false"] { + display: grid; +} + +sdoc-menu header:first-child { + /* "Add node" */ + grid-column: 1 / -1; + border-bottom: var(--base-border); +} + +sdoc-menu menu a { + padding: 0; + margin: 0; + list-style: none; + white-space: nowrap; + display: flex; /* affects the 'add node' buttons */ + padding: var(--base-rhythm); + border-radius: calc(var(--base-rhythm)/2); + font-size: var(--font-size-xsm); +} + +sdoc-menu menu a, +sdoc-menu menu a:link, +sdoc-menu menu a:visited { + text-decoration: none; + color: var(--color-fg-main); +} + +sdoc-menu menu a:hover { + background-color: var(--color-bg-secondary); + color: var(--color-fg-accent); +} + +sdoc-menu menu header { + padding: var(--base-rhythm); + text-transform: uppercase; + color: var(--color-fg-secondary); + font-weight: 700; + font-size: var(--font-size-xxsm); +} + +/* plus to close */ +sdoc-menu-handler[aria-expanded="true"] svg { + transform: rotate(45deg); + color: black; +} + +/* affects other menus: */ +[aria-expanded="true"] svg { + color: black; +} + +/* tree */ + +.tree { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: var(--base-rhythm); + margin-top: calc(var(--base-rhythm) * 2); + margin-bottom: calc(var(--base-rhythm) * 8); + padding-left: calc(var(--base-rhythm) * 2); + padding-right: calc(var(--base-rhythm) * 2); +} + +.tree_fragments { /* ul */ + margin-top: 0; + margin-bottom: 0; + padding-left: calc(var(--base-rhythm) * 2); + padding-right: 0; + list-style: none; + width: 100%; +} + +.tree_fragments li { + list-style: none; + width: 100%; +} + +.tree_fragments, +.tree_fragments li { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: var(--base-rhythm); +} + +.tree_folder { + display: flex; + align-items: flex-start; + justify-content: flex-start; + column-gap: var(--base-rhythm); + min-width: 0; + line-height: 1.5; + width: 99%; + padding-top: 8px; + margin-top: 8px; + opacity: 0.6; + position: relative; + border-top: var(--base-border); +} + +.tree_folder:first-child { + border-top: none; +} + +.tree_folder_path { + font-size: var(--font-size-xsm); + font-weight: 400; +} + +a.tree_item, +.tree_item { + display: flex; + align-items: flex-start; + justify-content: flex-start; + column-gap: var(--base-rhythm); + font-size: var(--font-size-sm); + min-width: 0; + line-height: 1.5; + width: 99%; /* To calculate cite overflow */ +} + +.tree_item[active] { + color: var(--color-fg-contrast); +} + +.document_title { + font-size: var(--font-size-sm); + font-weight: 700; + width: 99%; /* To calculate cite overflow */ +} + +.document_title[data-file_name]::after { + content: attr(data-file_name); + display: block; + text-overflow: ellipsis; + overflow: hidden; + width: 99%; /* To calculate cite overflow */ + font-weight:400; + opacity:0.6; +} + +/** TOC **/ + +.toc, +.toc ul, +.toc li { + list-style: none; + padding: 0; + margin: 0; +} + +.toc { + margin-top: calc(var(--base-rhythm) * 2); + padding-left: calc(var(--base-rhythm) * 2); + font-size: var(--font-size-sm); + line-height: 1.2; + padding-bottom: var(--base-gap); +} + +.toc li { + margin: 0; + padding-left: var(--base-rhythm); + position: relative; +} + +.toc a { + display: block; + position: relative; + padding-top: var(--base-rhythm); + padding-bottom: var(--base-rhythm); + padding-right: var(--base-rhythm); +} + +.toc a, +.toc a:link, +.toc a:visited { + text-decoration: none; + color: var(--color-fg-secondary); +} +.toc a:hover { + color: var(--color-fg-contrast); +} + +.toc a:focus, +.toc a:active { + background: transparent; +} + +.toc-title-no-link { + color: var(--color-fg-secondary); + opacity: .6; + display: block; + padding-top: var(--base-rhythm); + padding-bottom: var(--base-rhythm); + padding-right: var(--base-rhythm); +} + +/* TOC targeted */ +.toc a[targeted]::before { + position: absolute; + z-index: -1; + content: ''; + top: 0; + bottom: 0; + right: 0; + left: -200px; /* parent has overflow */ + background-color: var(--color-highlight); +} + +/* TOC intersected */ +.toc a::after { + position: absolute; + z-index: -1; + content: ''; + top: 0; + right: 0; + bottom: 0; + width: 8px; + background-color: var(--color-bg-main); +} + +.toc a[intersected]::after { + position: absolute; + z-index: -1; + content: ''; + top: 0; + right: 0; + bottom: 0; + width: 8px; + background-color: var(--color-highlight); +} + +/* TOC parented */ +/* behavior depends on collapsible_list.js */ +.toc [data-collapsible_list__branch="closed"] ~ a[parented]::after { + background-color: var(--color-highlight); +} + +/* pdf-toc */ + +.pdf-toc { + display: table; + width: 100%; +} +.pdf-toc-row { + display: table-row; +} +.pdf-toc-cell { + display: table-cell; + padding-top: var(--base-rhythm); + padding-right: var(--base-rhythm); + font-size: 1em; + line-height: 1.5; +} +.pdf-toc-cell[dotted] { + position: relative; + width: 100%; /* to get max */ +} +.pdf-toc-cell[dotted] > * { + background-color: white; + display: inline; + padding-right: 8px; + position: relative; +} +.pdf-toc-cell[dotted]::before { + content: ''; + position: absolute; + border-bottom: dotted 2px rgba(0,0,0,.4); + bottom: .4em; + left: .8em; + right: .8em; +} +.pdf-toc-cell:last-child { /* page number */ + vertical-align: bottom; + padding-right: 0; + text-align: right; +} + +/* table_key_value component */ + +.sdoc-table_key_value { + display: grid; + grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr); + place-items: stretch stretch; + place-content: stretch stretch; + position: relative; + border: var(--base-border); + border-radius: calc(var(--base-rhythm)*0.5); + + margin: var(--base-padding) 0; + padding: calc(var(--base-rhythm)*0.5); + gap: 2px; + + width: fit-content; + max-width: 100%; + /* overflow-x: auto; */ +} + +.sdoc-table_key_value-section, +.sdoc-table_key_value-key, +.sdoc-table_key_value-value { + padding: var(--base-rhythm) calc(var(--base-rhythm)*2); + background-color: var(--color-bg-secondary); +} + +.sdoc-table_key_value-key { + grid-column: 1 / 2; + color: var(--color-fg-main); + + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: flex-start; + + position: relative; + transition: 0.3s all; +} + +a.sdoc-table_key_value-key { + background-color: rgba(255,255,255,0.5); + color: var(--color-fg-contrast); + padding-right: calc(var(--base-rhythm)*5); + align-items: center; +} + +a.sdoc-table_key_value-key:hover { + background-color: rgba(255,255,255,1); + color: var(--color-fg-accent); +} + +a.sdoc-table_key_value-key::after { + content: "▸"; + position: absolute; + right: calc(var(--base-rhythm)*2); + color: var(--color-fg-accent); + font-size: var(--font-size-sm); +} + +.sdoc-table_key_value-value { + grid-column: 2 / 3; +} + +.sdoc-table_key_value-section { + grid-column: 1 / -1; + + padding: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*4); + padding-bottom: calc(var(--base-rhythm)*1); + font-family: var(--code-font-family); + + font-size: 0.85em; + font-weight: 500; + text-transform: uppercase; + color: var(--color-fg-secondary); + background-color: var(--color-bg-main); +} + +/* badge */ + +.badge { + white-space: nowrap; +} + +.badge::before { + content: attr(text); + padding: 0 calc(var(--base-rhythm)/2); + border: 1px solid; + border-radius: calc(var(--base-rhythm)/2); + font-size: var(--font-size-xxsm); + font-weight: 600; + text-transform: uppercase; +} + +.error { + color: var(--color-danger); +} + +/* tabs */ + +sdoc-tab-content { + display: none; +} +sdoc-tab-content[active] { + display: contents; +} + +sdoc-tabs { + grid-column: 1 / -1; + + /* compensate top padding for sdoc-form-grid: */ + /* margin-top: calc(var(--base-rhythm)*(-4)); */ + padding: calc(var(--base-rhythm)*(1)) calc(var(--base-rhythm)*(2)) 0; + + background-color: var(--color-bg-main); + border-radius: 4px; + + display: flex; +} + +sdoc-tab { + font-size: var(--font-size-xsm); + font-weight: 600; + text-align: left; + text-decoration: none; + white-space: nowrap; + position: relative; + display: inline-flex; + + align-items: center; + justify-content: center; + -webkit-box-align: center; + -webkit-box-pack: center; + + border: 1px solid transparent; + border-bottom: none; + border-radius: 4px 4px 0 0; + + user-select: none; + cursor: pointer; + appearance: none; + + /* 1.5 column-gap is compensated by SVG negative margin */ + /* column-gap: calc(var(--base-rhythm)*1.5); */ + + min-height: calc(var(--base-rhythm)*4); + padding-left: calc(var(--base-rhythm)*1.5); + padding-right: calc(var(--base-rhythm)*1.5); + + color: rgba(0, 0, 0, 0.5); + background-color: rgba(255, 255, 255, 0); + background-clip: padding-box; + + transition: 0.2s; +} + +sdoc-tab:hover { + background-color: rgba(255, 255, 255, 0.5); +} + +sdoc-tab[active] { + color: var(--color-hover); + background-color: rgba(255, 255, 255, 1); + cursor: default; +} + +sdoc-tab[data-errors] { + color: var(--color-danger); + border-color: var(--color-danger); +} + +sdoc-tab[data-errors]::after { + content: attr(data-errors); + display: flex; + justify-content: center; + align-items: center; + background-color: var(--color-danger); + color: var(--color-bg-contrast); + font-size: var(--font-size-xsm); + height: calc(var(--font-size-xsm)*1.75); + width: calc(var(--font-size-xsm)*1.75); + aspect-ratio: 1; + border-radius: 50%; + + /* parent column-gap == 0 */ + position: relative; + right: calc(var(--base-rhythm)*(-1)); +} + +sdoc-tabs.in_aside_panel { + background-color: var(--color-highlight-secondary); + border-bottom: 4px solid var(--color-bg-main); +} + +sdoc-tabs.in_aside_panel sdoc-tab:hover { + background-color: rgba(255, 255, 255, 0.25); +} + +sdoc-tabs.in_aside_panel sdoc-tab[active] { + background-color: var(--color-bg-main); +} + +/* document_issues */ + +.document_issues-banner { + display: flex; + flex-direction: column; + position: relative; + margin-bottom: var(--base-gap); + font-size: var(--font-size-sm); +} + +.document_issues-toggler { + text-align: right; +} + +.document_issues-banner_details { + display: block; + overflow: hidden; + color: var(--color-danger); + border: 1px solid; + border-radius: var(--requirement-border-radius); +} + +.document_issues-banner_summary { + font-weight: 600; + position: relative; + color: var(--color-danger); + padding-inline: calc(2 * var(--base-rhythm)); + padding-block: var(--base-rhythm); + cursor: pointer; + user-select: none; + display: flex; +} + +.document_issues-banner_summary::before { + content: '▸'; + margin-right: var(--base-rhythm); +} + +[open] > .document_issues-banner_summary::before { + content: '▾'; +} + +.document_issues-banner_summary::after { + content: ''; + position: absolute; + inset: 0; + background-color: currentColor; + opacity: 0.1; +} + +.document_issues-banner_content { + position: relative; + color: var(--color-fg-contrast); + padding-inline: calc(2 * var(--base-rhythm)); + padding-block: calc(1 * var(--base-rhythm)); +} + +.document_issues-banner ul { + margin: 0; + padding-inline-start: 20px; +} + +.field_issue { + grid-column: 1 / -1; + position: relative; + color: var(--color-danger); + padding: var(--base-rhythm); + font-size: var(--font-size-sm); + line-height: 1.5; +} + +.field_issue-ribbon { + position: relative; + padding: calc(.5 * var(--base-rhythm)) var(--base-rhythm); + border-radius: calc(.5 * var(--base-rhythm)); + border: 2px solid; +} + +.field_issue-ribbon::before { + position: absolute; + content: ''; + bottom: 100%; + left: var(--base-rhythm); + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid currentColor; +} + +.field_issue-ribbon::after { + content: ''; + position: absolute; + inset: 0; +} + +/* + ** SEARCH bar and result area + */ + +.search-box { + /* DEV: to push to the right in the header flex box */ + margin-left: auto; +} + +.actions_group + .search-box { + /* DEV: if on the server to the right of the action buttons */ + margin-left: unset; +} + +.search-input { + z-index: 101; + position: relative; + min-height: calc(var(--base-rhythm) * 6); /* = .header height */ + display: flex; + align-items: center; + justify-content: flex-end; +} + +.search-input input { + width: 145px; + transition: all .3s ease-out; +} + +.search-box[active] .search-input { + width: 100%; + border-bottom: var(--base-border); + padding-inline: var(--base-rhythm); +} + +.search-box[active] .search-input input { + width: 100%; +} + +.search-box[active] { + z-index: 100; + position: fixed; + width: 50%; + min-width: 300px; + right: 0; + top: 0; + bottom: 0; + background-color: white; + box-shadow: var(--base-elevation); + + display: flex; + flex-direction: column; + min-height: 0; +} + +.search-results { + display: none; +} + +.search-box[active] .search-results { + display: flex; + flex-direction: column; + flex: 1 1 auto; + min-height: 0; +} + +.search-results-navigation { + display: flex; + align-items: center; + justify-content: space-between; + flex: 0 0 auto; + + padding-inline: var(--base-rhythm); + padding-block: calc(var(--base-rhythm) / 2); + border-bottom: var(--base-border); +} + +.search-results-count { + font-size: var(--font-size-sm); + color: var(--color-fg-secondary); +} + +.search-results-count b { + color: var(--color-action); +} + +.search-results-navigation-buttons { + display: flex; + gap: 2px; +} + +.search-results-navigation-button { + display: inline-flex; + align-items: center; + justify-content: center; + + block-size: 1rem; + font-size: 1rem; + line-height: 0; + font-family: monospace; + + aspect-ratio: 1 / 1; + + border: 1px solid; + border-radius: 4px; + background-color: white; + cursor: pointer; +} + +.search-results-navigation-button:hover { + color: var(--color-action); +} + +.search-results-navigation-button#previous, +.search-results-navigation-button#next { + aspect-ratio: 1.75 / 1; +} + +.search-results-navigation-button#start::after { + content: '«'; +} +.search-results-navigation-button#previous::after { + content: '‹'; +} +.search-results-navigation-button#next::after { + content: '›'; +} +.search-results-navigation-button#end::after { + content: '»'; +} + +.search-results-navigation-button[disabled] { + color: #ccc; + cursor: default; +} + +.search-suggestions { + flex: 1 1 auto; + min-height: 0; + overflow: auto; +} + +.static_search-result-node { + padding: calc(var(--base-rhythm)*2); + border-bottom: var(--base-border); +} + +.static_search-result-node-field { + margin-bottom: var(--base-rhythm); +} + +.static_search-result-node-field-key { + font-size: var(--font-size-sm); + font-family: var(--code-font-family); + font-weight: 500; + color: var(--requirement-label-color); +} + +.static_search-result-node-link, +.static_search-result-node-link a { + color: var(--color-action); +} + +.static_search-result-node-link a:hover { + color: var(--color-hover); +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/favicon.ico b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/favicon.ico new file mode 100644 index 0000000..a1cd1eb Binary files /dev/null and b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/favicon.ico differ diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-Italic-VariableFont_wdth,wght.ttf b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-Italic-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..4e962ee Binary files /dev/null and b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-Italic-VariableFont_wdth,wght.ttf differ diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-VariableFont_wdth,wght.ttf b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..f7d0d78 Binary files /dev/null and b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSans-VariableFont_wdth,wght.ttf differ diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSansMono-VariableFont_wdth,wght.ttf b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSansMono-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..122ef75 Binary files /dev/null and b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/fonts/NotoSansMono-VariableFont_wdth,wght.ttf differ diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/form.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/form.css new file mode 100644 index 0000000..be530b8 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/form.css @@ -0,0 +1,595 @@ +/* form */ + +sdoc-backdrop { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + justify-content: center; + align-items: center; + background: rgba(0,0,0,.5); + z-index: 99999; +} + +sdoc-modal { + display: grid; + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + grid-template-rows: min-content minmax(0, 1fr) min-content; + grid-template-areas: + "modal-header" + "modal-content" + "modal-footer"; + place-items: stretch stretch; + place-content: stretch stretch; + + background-color: var(--color-bg-contrast); + border-radius: 8px; + + width: 600px; + max-width: 90vw; + min-width: 375px; + max-height: 90vh; + + box-shadow: var(--base-elevation-modal); + overflow: hidden; + overflow-y: auto; +} + +sdoc-modal[context="confirm"] { + width: 600px; +} + +sdoc-modal[context="form"] { + width: 90vw; + height: 90vh; + max-width: 600px; + max-height: 90vh; +} + +sdoc-modal-container { + padding: calc(var(--base-rhythm)*4); +} + +sdoc-modal-header { + grid-area: modal-header; + padding-top: calc(var(--base-rhythm)*2); + padding-bottom: calc(var(--base-rhythm)*2); + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*4); + font-size: 1.25rem; + font-weight: 600; +} + +.sdoc-modal-header-back-button { + position: relative; + left: calc(var(--base-rhythm) * (-1)); + display: inline-flex; + padding-right: var(--base-rhythm); +} + +.sdoc-modal-header-back-button:hover { + color: var(--color-action); +} + +sdoc-modal-content { + grid-area: modal-content; + border-top: var(--base-border); + border-bottom: var(--base-border); + /* padding-top: calc(var(--base-rhythm)*2); */ + /* padding-bottom: calc(var(--base-rhythm)*2); */ + overflow: auto; + scroll-behavior: smooth; +} + +sdoc-modal-message { + display: block; + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*4); + margin-top: calc(var(--base-rhythm)*2); + margin-bottom: calc(var(--base-rhythm)*2); +} + +sdoc-modal-footer { + grid-area: modal-footer; + display: flex; + justify-content: flex-end; /* buttons to right */ + padding-top: calc(var(--base-rhythm)*2); + padding-bottom: calc(var(--base-rhythm)*2); + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*3); /* buttons to right */ + column-gap: var(--base-rhythm); +} + +/* sdoc-form */ + +sdoc-form { + display: block; + position: relative; + background-color: var(--color-bg-contrast); + border-radius: 4px; + z-index: 11; + border: 1px solid var(--color-fg-accent); +} + +sdoc-form-header { + display: block; + padding-top: 0; + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*4); + font-size: 1.25rem; + font-weight: 600; +} + +sdoc-form-descr { + display: block; + padding-top: 0; + padding-bottom: 0; + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*4); + margin-top: calc(var(--base-rhythm)*2); + margin-bottom: calc(var(--base-rhythm)*2); +} + +sdoc-form-footer { + display: flex; + justify-content: flex-start; /* buttons to left */ + padding-top: 0; + padding-bottom: 0; + padding-left: calc(var(--base-rhythm)*3); /* buttons to left */ + padding-right: calc(var(--base-rhythm)*4); + margin-top: calc(var(--base-rhythm)*2); + margin-bottom: calc(var(--base-rhythm)*2); + column-gap: var(--base-rhythm); +} + +sdoc-form-field { + /* + Flex can not be used, it is necessary exactly "display: block" because of + the effect on the display of the contenteditable element contained inside. + Extra spaces are formed there and it breaks the Selenium end2end tests. + */ + display: block; + position: relative; + padding-top: 0; + padding-bottom: 0; + padding-left: calc(var(--base-rhythm)*4); + padding-right: calc(var(--base-rhythm)*4); + margin-top: calc(var(--base-rhythm)*4); + margin-bottom: calc(var(--base-rhythm)*4); + min-width: 200px; +} + +sdoc-form-row-main { + display: flex; + flex-direction: column; + position: relative; +} + +sdoc-form-row-aside { + display: flex; + flex-wrap: nowrap; + align-items: flex-start; + justify-content: flex-end; + position: relative; +} + +sdoc-form-row-aside [data-action-type="delete"]:hover, +sdoc-form-row-aside [data-action-type="delete"] { + color: var(--color-danger); +} + +sdoc-form-row-aside [data-action-type="action"]:hover, +sdoc-form-row-aside [data-action-type="action"] { + color: var(--color-action); +} + +sdoc-form-row-aside [data-action-type="move_up"]:hover, +sdoc-form-row-aside [data-action-type="move_up"] { + color: var(--color-green); +} + +sdoc-form-row-aside [data-action-type="move_down"]:hover, +sdoc-form-row-aside [data-action-type="move_down"] { + color: var(--color-blue); +} + +sdoc-form-row [data-action-type="add_field"]:only-child { + /* + It is expected to be a button (.action_button) + to add fields like "comment" or "link" + to the requirement edit form. + */ + justify-content: flex-start; + /* color: rgba(0,0,0,0.5) !important; */ + border: none; + top: -40%; +} + +/* + fields grid: + inside sdoc-form-grid +*/ + +sdoc-form-grid { + display: grid; + place-items: stretch stretch; + place-content: stretch stretch; + grid-template-columns: minmax(0, min-content) + minmax(0, 1fr) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + minmax(0, min-content); + gap: + calc(var(--base-rhythm)*4) + var(--base-rhythm); + + padding: + calc(var(--base-rhythm)*4) + calc(var(--base-rhythm)*3); /* (4-1) related to column gap */ + + overflow-x: clip; /* Prevents overflow issues affecting: + - field_action::before (highlight visibility on delete) and + - autocompletable (dropdown visibility) */ + + /* content container has no padding-block */ + margin-top: calc(var(--base-rhythm)*2); + margin-bottom: calc(var(--base-rhythm)*2); +} + +sdoc-form-grid + sdoc-form-field { + padding: 0; + margin: 0; + } + +sdoc-form-grid + sdoc-form-row { + display: contents; + } + +sdoc-form-grid + sdoc-form-row-aside:first-of-type { + grid-column: 1 / 2; /* left */ + } + +sdoc-form-grid + sdoc-form-row-main { + grid-column: 2 / 3; /* center */ + } + +sdoc-form-grid + sdoc-form-row-aside:last-of-type { + grid-column: 3 / 4; /* right */ + } + +/* sdoc-form-field-group */ + +sdoc-form-field-group { + /* display: grid; + place-items: stretch stretch; + place-content: stretch stretch; */ + + display: flex; + flex-direction: row; + flex-wrap: wrap; + + padding: var(--base-rhythm); + border: var(--base-border); + border-radius: var(--base-rhythm); + + gap: calc(var(--base-rhythm)*3); /* label (2) + 1 */ + padding-top: calc(var(--base-rhythm)*3); /* related to column gap */ + padding-bottom: calc(var(--base-rhythm)*1); + + position: relative; +} + +sdoc-form-field-group::before { + /* TODO move to other label */ + content: attr(data-field-label); + position: absolute; + font-family: var(--code-font-family); + font-size: var(--font-size-xsm); + font-weight: 500; + color: var(--color-placeholder); + text-transform: uppercase; + top: calc(var(--base-rhythm)*(-1.25)); + right: var(--base-rhythm); + padding: 0 var(--base-rhythm); + background: var(--color-bg-contrast); + transition: color .2s ease; +} + +sdoc-form-field-group:focus-within::before { + color: var(--color-fg-accent); +} + +/** + * sdoc-contenteditable + */ + +sdoc-contenteditable, +sdoc-autocompletable { + display: block; + position: relative; +} + +sdoc-contenteditable[contenteditable="false"], +sdoc-autocompletable[contenteditable="false"] { + color: var(--color-fg-secondary); +} + +.autocomplete-items { + position: absolute; + border: 1px solid var(--color-action); + background-color: var(--color-bg-contrast); + top: 100%; + left: 0; + right: 0; + width: 33vw; + max-height: 60vh; + overflow-y: auto; + z-index: 999; +} + +.autocomplete-active { + /*when navigating through the items using the arrow keys:*/ + background-color: var(--color-highlight) !important; +} + +.autocompletable-result-item { + position:relative; + display:block; + padding:.25rem 0.25rem; + margin-bottom:-1px; + border:1px solid rgba(0,0,0,.125) +} + +.monospace { + font-family: var(--code-font-family); +} + +.form__requirement_title { + font-size: 1.125em; + font-weight: 700; +} + +/* field name // before */ + +/* todo: Join sdoc-contenteditable with sdoc-form-field */ + +sdoc-form-field label, +sdoc-contenteditable::before, +sdoc-autocompletable::before { + /* for contenteditable */ + content: attr(data-field-label); + /* for all */ + position: absolute; + font-family: var(--code-font-family); + font-size: var(--font-size-xsm); + font-weight: 500; + color: var(--color-placeholder); + text-transform: uppercase; + top: calc(var(--base-rhythm)*(-2.25)); + transition: color .2s ease; + + white-space: nowrap; +} + +sdoc-form-field:focus-within label, +sdoc-contenteditable:focus::before, +sdoc-autocompletable:focus::before { + color: var(--color-fg-accent); +} + +/* sdoc-form-field select */ +sdoc-form-field select { + /* A reset of styles, including removing the default dropdown arrow */ + /* appearance: none; */ + background-color: transparent; + /* border: none; */ + border: 1px solid var(--color-placeholder); + border-radius: 6px; + + padding: 0 1em 0 .5em; + margin: 0; + width: 100%; + font-family: inherit; + font-size: inherit; + cursor: inherit; + line-height: inherit; + /* Stack above custom arrow */ + z-index: 1; + /* Remove focus outline, will add on alternate element */ + outline: none; +} + +sdoc-form-field select:focus { + border: 1px solid var(--color-fg-accent); +} + +/* Remove dropdown arrow in IE10 & IE11 + @link https://www.filamentgroup.com/lab/select-css.html +*/ +sdoc-form-field select::-ms-expand { + display: none; +} + +/* placeholder // after */ + +[placeholder]:empty::after { + content: attr(placeholder); + pointer-events: none; + color: var(--color-placeholder); + /* For Firefox: */ + display: block; +} + +[placeholder]:empty:focus::after { + color: rgba(242, 100, 42,.2); +} + +sdoc-contenteditable[data-field-suffix]:not(:empty)::after, +sdoc-autocompletable[data-field-suffix]:not(:empty)::after { + content: attr(data-field-suffix); + color: var(--color-fg-accent); + margin-left: 4px; +} + +/* data-field-suffix */ + +[contenteditable=true] { + white-space: pre-wrap; + word-break: break-word; + overflow-wrap: anywhere; + outline: none; + /* Without this hack ( display: inline-block ) + Chrome generates duplicated new lines when Enter pressed. + Add style "display:inline-block;" to contenteditable, + it will not generate div, p, span automatic in chrome */ + /* https://stackoverflow.com/a/24689390/598057 */ + /* Also, the parent element should not be allowed to have a flex display. + In order to isolate the 'contenteditable, + the structure "sdoc-form-row-main > sdoc-form-field > contenteditable" + is implemented. + */ + display: inline-block; + /* This is to prevent the field from shifting when the second line appears while typing: */ + vertical-align: top; + width: 100%; +} + +[contenteditable=true][data-field-type="multiline"] { + font-family: var(--code-font-family); +} + + + +form[data-controller~="scroll_into_view"] { + /* fix on 1px border and smth unruly */ + scroll-snap-margin-top: calc(var(--base-padding) + 1px); + scroll-margin-top: calc(var(--base-padding) + 1px); +} + +/* input */ + +sdoc-form input[type="text"] { + padding: var(--base-rhythm); + font-size: var(--font-size); + border: 1px solid var(--color-border); + border-radius: 3px; + outline: transparent; + width: 100%; + transition: border-color calc(var(--transition, 0.2) * 1s) ease; +} + +sdoc-form input[type="text"]:focus { + border-color: var(--color-action); + color: var(--color-action); +} + +/* diff */ + +sdoc-form[diff] { + grid-column: 1 / -1; + + margin: 0; + background-color: transparent; + border: none; +} + +sdoc-form[diff] form { + display: flex; + gap: var(--base-rhythm); + position: relative; + padding: var(--base-rhythm); + background-color: var(--color-bg-contrast); + border: 1px solid var(--color-border); + border-radius: 4px; +} + +/* search */ + +sdoc-form[search] { + display: block; + background-color: transparent; + border: none; + border-radius: 0; +} + +sdoc-form[search] form { + display: flex; + gap: var(--base-rhythm); + position: relative; + padding: var(--base-rhythm); + background-color: var(--color-bg-contrast); + border: 1px solid var(--color-border); + border-radius: 4px; +} + +sdoc-form[search][success] { + border-bottom: 1px solid var(--color-border); +} + +sdoc-form-error { + display: block; + color: var(--color-danger); + font-size: 12px; + /* + set 'order' to be displayed after any other items, + in the context of using flex: + */ + order: 11; + /* + FOR: + components/grammar_form_element/index.jinja + "Relations_Row" + id="document__editable_grammar_relations" + */ + grid-column: 2 / -1; +} + +sdoc-form-error + sdoc-form-error { + margin-top: var(--base-rhythm); +} + +sdoc-form-error + sdoc-form-field-group { + border-color: var(--color-danger); +} + + +sdoc-form-field-group[errors]::before, /* Grammar -> label for group of fields */ +sdoc-contenteditable[errors]::before, /* inside contenteditable errors block does not affected */ +sdoc-autocompletable[errors]::before, +sdoc-form-error + sdoc-form-field > label, /* Grammar -> relation field ; File filed */ +sdoc-form-error + sdoc-form-field > sdoc-contenteditable::before, +sdoc-form-error + sdoc-form-field > sdoc-autocompletable::before { + color: var(--color-danger); +} + +.sdoc-form-error, +.sdoc-form-success, +.sdoc-form-reset { + display: block; + padding: var(--base-rhythm) calc(var(--base-rhythm)*2); + position: relative; +} + +.sdoc-form-error { + color: var(--color-danger); +} + +.sdoc-form-success { + color: var(--color-action); +} + +.sdoc-form-reset { + position: absolute; + right: 0; + bottom: 0; +} + +.sdoc-form-error, +.sdoc-form-success { + padding-right: 120px; /* == sdoc-form-reset width */ +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/html2pdf4doc.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/html2pdf4doc.css new file mode 100644 index 0000000..f7ead23 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/html2pdf4doc.css @@ -0,0 +1,4 @@ +html2pdf-print-forced-page-break + sdoc-node-content[node-view="narrative"], +html2pdf-page + sdoc-node-content[node-view="narrative"] { + border-top: none; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/layout.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/layout.css new file mode 100644 index 0000000..8ecd6df --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/layout.css @@ -0,0 +1,116 @@ +.layout { + height: 100vh; + width: 100%; + display: grid; + + grid-template-columns: + fit-content(var(--base-gap)) + fit-content(20%) + fit-content(20%) + minmax( 0, 1fr ) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + fit-content(20%) + auto; + grid-template-rows: + var(--base-gap) + minmax( 0, 1fr ) /* https://github.com/w3c/csswg-drafts/issues/1777 */ + calc(var(--base-rhythm)*4); + grid-template-areas: + "nav header header header header aside" + "nav tree bar_left main bar_right aside" + "nav footer footer footer footer aside"; + + place-items: stretch stretch; + place-content: stretch stretch; + + overflow: hidden; /* Prevents scrolling before children's styles are triggered */ +} + +.layout_nav { + grid-area: nav; + position: relative; + z-index: 10; +} + +.layout_tree { + grid-area: tree; + min-width: 0; +} + +.layout_toc, +.layout_toc[data-position='left'] { + grid-area: bar_left; +} +.layout_toc[data-position='right'] { + grid-area: bar_right; +} + +.layout_footer { + grid-area: footer; +} + +.layout_header { + grid-area: header; + min-width: 0; +} + +.layout_aside { + grid-area: aside; + min-width: 0; +} + +.layout_main { + grid-area: main; + min-width: 0; +} + +/* */ + +.section-number { + margin-right: .5rem; + font-size: 0.85em; + font-weight: bold; +} + +/* messages */ + +.mars { + position: fixed; + z-index: 1111; + top: 0; + bottom: 0; + left: 0; + right: 0; + pointer-events: none; + + display: flex; + justify-content: center; + /* align-items: flex-end */ + align-items: center; + + padding: calc(var(--base-rhythm)*10); +} + +/* */ + +sdoc-toast { + pointer-events: initial; + text-align: center; + border-radius: var(--base-rhythm); + box-shadow: 0 8px 32px rgba(0,0,0,.3); + background: var(--color-bg-ui); + color: var(--color-fg-secondary-invert); +} + +sdoc-toast:not(:empty) { + padding: .75rem 2rem; +} + +sdoc-toast a, +sdoc-toast a:link, +sdoc-toast a:visited { + color: var(--color-bg-contrast); +} + +sdoc-toast a:hover { + color: var(--color-fg-accent); +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node.css new file mode 100644 index 0000000..cf45ed3 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node.css @@ -0,0 +1,246 @@ +turbo-frame { + display: contents; +} + +sdoc-node { + display: block; + position: relative; +} + +/* sdoc-node[show-node-type-name] sdoc-node-content { + margin-top: calc(2 * var(--base-rhythm)); +} */ + +sdoc-node[show-node-type-name]::before { + content: attr(show-node-type-name); + position: absolute; + top: calc(1 * var(--base-rhythm)); + right: calc(4 * var(--base-rhythm)); + + font-size: 10px; + font-family: var(--code-font-family); + font-weight: 600; + line-height: 1; + text-transform: uppercase; + + padding-top: calc(0.25 * var(--base-rhythm)); + padding-bottom: calc(0.5 * var(--base-rhythm)); + padding-left: calc(0.75 * var(--base-rhythm)); + padding-right: calc(0.75 * var(--base-rhythm)); + border-radius: 3px; + border: var(--requirement-border-width, 1px) solid var(--requirement-border-color, #bfbfbf); + + color: var(--requirement-label-color); + background-color: var(--color-bg-contrast); +} + +/* sdoc-node */ + +sdoc-node { + background-color: var(--color-bg-contrast); + border-radius: 3px; + + /* padding: calc(3 * var(--base-rhythm)) calc(4 * var(--base-rhythm)); */ + padding-inline: calc(4 * var(--base-rhythm)); + padding-block: calc(3 * var(--base-rhythm)); +} + +sdoc-node[node-role="root"] { + padding-top: calc(3 * var(--base-rhythm)); +} + +sdoc-node[node-style="readonly"][node-role="requirement"] { + background: none; + background-color: transparent; + outline: none; + padding-left: 0; + padding-right: 0; + padding-bottom: 0; + margin: 0; +} + +sdoc-node[show-node-type-name][node-style="readonly"]::before { + right: 0; +} + +sdoc-node[show-node-type-name][node-view="plain"]::before { + content: none; +} + +/* editable_node */ + +sdoc-node[node-style="card"][node-role="requirement"], +[data-editable_node="on"] { + box-shadow: var(--base-elevation-0); + transition: box-shadow .5s; +} + +sdoc-node[node-style="card"][node-role="requirement"]:hover, +[data-editable_node="on"]:hover { + box-shadow: var(--base-elevation-node); + z-index: 10; +} + +/* sdoc-node[node-style="card"] */ + +sdoc-node[node-style="card"] { + background-color: var(--color-bg-contrast); + border-radius: 3px; + padding: 0; +} + +sdoc-node[node-style="card"][node-role="text"], +sdoc-node[node-style="card"][node-role="section"] { + background-color: var(--color-bg-contrast); + padding: calc(var(--base-rhythm)) calc(var(--base-rhythm)*2); +} + +[data-role='current'] sdoc-node[node-style="card"] { + background-color: var(--color-bg-contrast); +} + +[data-role='current'] [node-role="requirement"] { + +} + +[data-role='parents'] sdoc-node[node-style="card"], +[data-role='children'] sdoc-node[node-style="card"] { + background-color: var(--color-bg-secondary); + width: var(--card-width); +} + +sdoc-node[node-style="card"].highlighted { + background-color: var(--color-highlight); +} + +[data-viewtype="traceability"] sdoc-node[node-style="card"] + sdoc-node[node-style="card"] { + margin-top: var(--base-padding); +} + +[data-viewtype="deep_traceability"] sdoc-node[node-style="card"] { + /* width: var(--card-width); */ + /* flex-grow: 1; */ +} + +[data-viewtype="requirements-coverage"] sdoc-node[node-style="card"] { + width: calc(var(--card-width)*0.75); + /* width: auto; */ + font-size: .85em; + line-height: 1.4; +} + +/* nouid */ + +sdoc-node.nouid { + /* background-color: rgb(240, 220, 220); */ +} + +.nouid sdoc-node-title, +.nouid .requirement__title { + color: #502222; +} + +/* sdoc-node-controls */ + +sdoc-node-controls[data-direction~="column"], +sdoc-node-controls { + position: absolute; + + display: flex; + justify-content: flex-start; + + transition: .5s ease-out; + opacity: 0; + + /* HACK: [sdoc-node outline hack] */ + left: calc(100% + 1px); + top: -2px; + + /* default: column to right */ + bottom: 0; + right: unset; + width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */ + height: unset; + + justify-content: flex-start; + flex-direction: column; +} + +sdoc-node-controls[data-direction~="column"] { + flex-direction: column; + justify-content: flex-start; + + left: 100%; + top: 0; + bottom: 0; + right: unset; + width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */ + height: unset; +} + +sdoc-node-controls[data-direction~="row"] { + flex-direction: row; + justify-content: flex-end; + + top: calc(100% - 4px); + left: 0; + right: 0; + bottom: unset; + height: calc(var(--base-rhythm)*4); /* determines the size of the buttons */ + width: unset; +} + +sdoc-main-placeholder + sdoc-node-controls { + opacity: 1; +} + +sdoc-node-controls:hover, +sdoc-node:hover sdoc-node-controls { + opacity: 1; +} + +sdoc-node:hover sdoc-node-controls:hover { + opacity: 1; +} + +sdoc-menu { + display: flex; + align-items: stretch; + /* default: */ + flex-direction: column; +} + +sdoc-menu-handler { + display: flex; + align-items: stretch; + /* default: */ + flex-direction: column; +} + +sdoc-menu, /* default: */ +sdoc-menu-handler, /* default: */ +sdoc-node-controls[data-direction~="column"] sdoc-menu, +sdoc-node-controls[data-direction~="column"] sdoc-menu-handler { + flex-direction: column; +} + +sdoc-node-controls[data-direction~="row"] sdoc-menu, +sdoc-node-controls[data-direction~="row"] sdoc-menu-handler { + flex-direction: row; +} + +/* math equation numbering support */ +div.math { + position: relative; + text-align: center; + padding-right: 3em; /* reserve space for eqno */ + overflow: hidden; /* prevents scrollbars */ +} + +.math .eqno { + position: absolute; + right: 0; + top: 0; + font-size: 90%; + white-space: nowrap; +} \ No newline at end of file diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node_content.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node_content.css new file mode 100644 index 0000000..f1c4845 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/node_content.css @@ -0,0 +1,495 @@ +:root { + --requirement-container-limit: 500px; + --requirement-border-color: rgb(230, 230, 230); /* = var(--color-border) on white without opacity */ + --requirement-border-width: 1px; + --requirement-border-radius: 4px; + --requirement-inner-borders-width: 1px; + --requirement-label-color: var(--color-fg-secondary, #808080); + --requirement-bg-dark-color: var(--color-bg-main, #F2F5F9); + --requirement-bg-light-color: var(--color-bg-contrast, #FFFFFF); +} + +/* sdoc-node-content */ + +sdoc-node-content { + display: grid; + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + place-items: stretch stretch; + place-content: stretch stretch; + gap: var(--requirement-inner-borders-width); + + position: relative; + background-color: var(--color-bg-contrast); /* affects the color of the space between cells */ + border: + var(--requirement-border-width, 1px) + solid + var(--requirement-border-color); + + border-radius: var(--requirement-border-radius); + + + min-width: 300px; + + /* and use overflow-wrap: break-word; in the field */ + max-width: 100%; + + /* + DEV: to show anchors (in the context) to the left of the node, + need to remove this: + overflow-x: auto; + */ +} + +/* Workaround for html2pdf4doc print bug: + (https://github.com/strictdoc-project/strictdoc/issues/2450#issuecomment-3299134769) + Disable background for elements that trigger header/footer overlap. + This hides the background of problematic split (not sliced) sections + to prevent them from covering header/footer areas during printing. + Real fix will be applied in html2pdf4doc in a future release. */ +@media print { + sdoc-node-content { + background: none; + background-color: transparent; + } +} + +sdoc-node-title { + display: block; + + font-size: 1.125em; + font-weight: 700; +} + +sdoc-node-title:last-child { + margin-bottom: 0; +} + +sdoc-node-title * { + /* affect H inside title, if applicable */ + margin: 0; +} + +[node-style="card"] sdoc-node-title { + font-size: 1em; +} + +/* synonym to [node-view="inline"] */ +sdoc-node-content[node-view="simple"] sdoc-node-title { + padding-left: calc(var(--base-rhythm)*2); + padding-right: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*1); + padding-bottom: calc(var(--base-rhythm)*1); + + word-break: break-word; + overflow-wrap: break-word; +} + +/* sdoc-node-content[node-view="simple"] sdoc-node-title, */ +sdoc-node-content[node-view="table"] sdoc-node-title, +sdoc-node-content[node-view="zebra"] sdoc-node-title { + padding-left: calc(var(--base-rhythm)*2); + padding-right: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*1); + padding-bottom: calc(var(--base-rhythm)*1); + + border-top-right-radius: var(--requirement-border-radius); + border-top-left-radius: var(--requirement-border-radius); + + background-color: var(--requirement-bg-dark-color); + /* border-bottom: */ + outline: 1px solid var(--requirement-border-color); + + word-break: break-word; + overflow-wrap: break-word; +} + +sdoc-node-uid { + display: block; + padding-left: calc(var(--base-rhythm)*2); + padding-right: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*1); + padding-bottom: calc(var(--base-rhythm)*1); + font-size: var(--font-size-sm); + font-family: var(--code-font-family); + font-weight: 700; + + text-transform: uppercase; + color: var(--requirement-label-color); + + word-break: break-word; + overflow-wrap: break-word; +} + +sdoc-node-field-label { + display: flex; + align-items:flex-start; + + padding-left: calc(var(--base-rhythm)*2); + padding-right: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*1.75); + padding-bottom: calc(var(--base-rhythm)*1); + + font-size: var(--font-size-sm); + font-family: var(--code-font-family); + font-weight: 500; + line-height: 1; + color: var(--requirement-label-color); + + /* @mettta and @stanislaw are commenting this out because REQUIREMENT's field names + were split apart, even though there was enough screen width + word-break: break-word; + */ + overflow-wrap: break-word; +} + +sdoc-node-field { + display: block; + position: relative; + + padding-left: calc(var(--base-rhythm)*2); + padding-right: calc(var(--base-rhythm)*2); + padding-top: calc(var(--base-rhythm)*1); + padding-bottom: calc(var(--base-rhythm)*1); + + word-break: break-word; + overflow-wrap: break-word; +} + +[data-viewtype="html2pdf"] sdoc-node-field-label { + word-break: normal; +} + +/* for relations in requirement */ +sdoc-node-field > ol:first-child, +sdoc-node-field > ul:first-child { + margin-top: 0; +} +sdoc-node-field > ol:last-child, +sdoc-node-field > ul:last-child { + margin-bottom: 0; +} + +/* node-view="plain" */ + +sdoc-node-content[node-view="plain"] { + border: 0; + display: flex; + flex-direction: column; + gap: var(--base-padding); +} + +sdoc-node-content[node-view="plain"] sdoc-node-field-label { + display: none; +} + +sdoc-node-content[node-view="plain"] sdoc-node-field { + padding: 0; +} + +/* node-view="table" */ + +sdoc-node-content[node-view="table"] { + /* grid: */ + grid-template-columns: minmax(80px, min-content) minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + /* border: */ + background-color: var(--requirement-border-color); +} + +sdoc-node-content[node-view="table"] + sdoc-node-title { + grid-column: 1 / 3; + } + +sdoc-node-content[node-view="table"] + sdoc-node-field-label { + grid-column: 1 / 2; + background-color: var(--requirement-bg-dark-color); + } + +sdoc-node-content[node-view="table"] + sdoc-node-field { + grid-column: 2 / 3; + background-color: var(--requirement-bg-light-color); + } + +sdoc-node:not([node-style="card"]) { + /* Making the node a container for the requirement: */ + container: node / inline-size; + /* + HACK: [sdoc-node outline hack] + Buggy behavior for @container CSS feature: + after window resize, the 1px vertically space + appears randomly between nodes. + */ + outline: 1px solid #fff; + margin: 1px 0; +} + +/* calc(var(--card-width) + calc(var(--base-padding)*4)) */ +/* 300 + 16*4 = 364 */ +@container node (width < 400px) { + sdoc-node-content[node-view="table"] { + /* removes columns: */ + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + /* removes inner border: */ + background-color: var(--requirement-bg-light-color); + } + + sdoc-node-content[node-view="table"] + sdoc-node-title, + sdoc-node-content[node-view="table"] + sdoc-node-field-label, + sdoc-node-content[node-view="table"] + sdoc-node-field { + /* removes columns: */ + grid-column: unset; + } +} + +@supports not (container-type: inline-size) { + /* TODO test 888px */ + @media (max-width: 888px) { + /* Do the same as if there was a container support */ + + sdoc-node-content[node-view="table"] { + /* removes columns: */ + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + /* removes inner border: */ + background-color: var(--requirement-bg-light-color); + } + + sdoc-node-content[node-view="table"] + sdoc-node-title, + sdoc-node-content[node-view="table"] + sdoc-node-field-label, + sdoc-node-content[node-view="table"] + sdoc-node-field { + /* removes columns: */ + grid-column: unset; + } + } +} + +/* node-view="zebra" */ + +sdoc-node-content[node-view="zebra"] { + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ +} + +sdoc-node-content[node-view="zebra"] + sdoc-node-field-label { + background-color: var(--requirement-bg-dark-color); + } + +sdoc-node-content[node-view="zebra"] + sdoc-node-field { + background-color: var(--requirement-bg-light-color); + } + +/* node-view="simple" */ +/* synonym to "inline" */ + +sdoc-node-content[node-view="simple"] { + grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ +} + +sdoc-node-content[node-view="simple"] +sdoc-node-field-label { + background-color: #fff; + padding-bottom: 0; +} + +/* node-view="narrative" */ + +sdoc-node-content[node-view="narrative"] { + display: flex; + flex-direction: column; + padding-top: var(--base-rhythm); + border-radius: 0; + border-left: none; + border-right: none; + border-bottom: none; +} + +sdoc-node-content[node-view="narrative"] sdoc-node-title { + border: none; + outline: none; + background: none; + background-color: transparent; + padding: 0; + margin-bottom: var(--base-padding); + grid-column: 1 / -1; +} + +sdoc-node-content[node-view="narrative"] sdoc-node-field { + padding: 0; +} + +sdoc-node-content[node-view="narrative"] sdoc-node-field-label { + opacity: 0.8; + font-size: var(--font-size-sm); + line-height: calc(var(--font-size-sm) * 1.5); + padding: 0; +} + +sdoc-node-content[node-view="narrative"] .node_fields_group-primary { + display: flex; + flex-direction: column; + padding-top: var(--base-padding); +} + +sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field { + margin-bottom: var(--base-padding); + color: var(--color-fg-contrast); +} + +sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field:last-child { + margin-bottom: 0; +} + +sdoc-node-content[node-view="narrative"] .node_fields_group-secondary { + display: grid; + grid-template-columns: max-content 1fr; + gap: calc(.5 * var(--base-rhythm)); +} + +sdoc-node-content[node-view="narrative"] .node_fields_group-secondary sdoc-node-field { + font-size: var(--font-size-sm); + line-height: calc(var(--font-size-sm) * 1.5); + opacity: 0.6; +} + +sdoc-node-content[node-view="narrative"] .requirement__parent-uid, +sdoc-node-content[node-view="narrative"] .requirement__child-uid { + /* + affects UID in links; + make them lighter: + */ + font-weight: normal; +} + +/* section */ + +sdoc-section, +sdoc-section-title { + display: block; + margin: 0; +} + +sdoc-section-title { + font-weight: 700; +} + +sdoc-section-title { + margin-bottom: var(--base-padding); +} + +sdoc-section-title:last-child { + margin-bottom: 0; +} + +sdoc-section-title * { + margin: 0; + + /* This rule, when the element starts the page when printed, + creates illegal margins, + which breaks the rhythm of HTML2PDF4DOC + and generates blank pages: + */ + /* display: inline; */ +} + +/* TEXT node */ + +sdoc-text, +sdoc-section-text { + display: block; + margin: 0; +} + +[node-style="card"] sdoc-text { + padding: var(--base-padding); +} + +sdoc-section-text { + margin-top: var(--base-padding); +} + +sdoc-section-text:first-child { + margin-top: 0; +} + +/* meta */ + +sdoc-meta { + display: grid; + grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr); + place-items: stretch stretch; + place-content: stretch stretch; + position: relative; + border: + var(--requirement-border-width, 1px) + solid + var(--requirement-border-color); + border-radius: var(--requirement-border-radius); + + font-size: var(--font-size-sm); + line-height: 24px; /* to keep the copy button from expanding out of the content line */ + /* margin: var(--base-padding) 0; */ + margin: 0; + padding: calc(var(--base-rhythm)*0.5); + row-gap: 2px; + + width: fit-content; + max-width: 100%; + overflow-x: auto; +} + +sdoc-meta-section, +sdoc-meta-label, +sdoc-meta-field { + display: flex; + align-items: flex-start; + padding: calc(var(--base-rhythm)*0.25) var(--base-rhythm); + background-color: var(--color-bg-contrast); +} + +sdoc-meta-label { + grid-column: 1 / 2; + font-family: var(--code-font-family); + font-weight: 700; + text-transform: uppercase; + color: var(--requirement-label-color); + background-color: var(--color-bg-secondary); +} + +sdoc-meta-field { + grid-column: 2 / 3; +} + +sdoc-meta-section { + grid-column: 1 / -1; +} + +/* PDF */ +/* There is no sdoc-node wrapper, so such neighbours and nesting is possible. */ +sdoc-text + sdoc-text, +sdoc-text + sdoc-section, +sdoc-text + sdoc-section-title, +sdoc-section + sdoc-text, +sdoc-section + sdoc-section, +sdoc-section + sdoc-section sdoc-section-title { + margin-top: calc(var(--base-rhythm)*4); +} + +/* requirement type tag */ + +.requirement__type-tag { + /* font-size: var(--font-size-sm); + font-family: var(--code-font-family); + font-weight: 500; + line-height: 1; + text-transform: uppercase; */ + color: var(--requirement-label-color); + white-space: nowrap; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/pan_with_space.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/pan_with_space.js new file mode 100644 index 0000000..2a04d2d --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/pan_with_space.js @@ -0,0 +1,151 @@ +// This code in this file is a simplified version of the StackOverflow answer +// taken from: https://stackoverflow.com/a/33948409/598057. + +const MOUSEMOVE_SPEED_FACTOR = 1; +const KEYDOWN_SPEED_FACTOR = 20; +const PWS_SELECTOR = "[js-pan_with_space]"; + +function getPanElement() { + const element = document.querySelector(PWS_SELECTOR); + return element; +} + +window.addEventListener('load', function () { + var state = { + spacePressed: false, + isDown: false, + startX: 0, + startY: 0 + } + + const element = getPanElement(); + if (element) { + console.assert(!!element, "Expected a valid element."); + + document.addEventListener("keydown", function (e) { + if (e.key === ' ' || e.key === 'Spacebar') { + // ' ' is standard, 'Spacebar' was used by IE9 and Firefox < 37 + + e.preventDefault(); + e.stopPropagation(); + state.spacePressed = true; + element.style.cursor = 'move'; + element.style.scrollBehavior = 'auto'; + return; + } + + var moveFactor = KEYDOWN_SPEED_FACTOR; + if (e.altKey) { + moveFactor = KEYDOWN_SPEED_FACTOR * 10; + } + + if (e.key === 'ArrowDown') { + e.preventDefault(); + e.stopPropagation(); + element.scrollTop = element.scrollTop + moveFactor; + } + else if (e.key === 'ArrowUp') { + e.preventDefault(); + e.stopPropagation(); + element.scrollTop = element.scrollTop - moveFactor; + } + else if (e.key === 'ArrowLeft') { + e.preventDefault(); + e.stopPropagation(); + element.scrollLeft = element.scrollLeft - moveFactor; + } + else if (e.key === 'ArrowRight') { + e.preventDefault(); + e.stopPropagation(); + element.scrollLeft = element.scrollLeft + moveFactor; + } + }) + + document.addEventListener("keyup", function (e) { + if (e.key === ' ' || e.key === 'Spacebar') { + // ' ' is standard, 'Spacebar' was used by IE9 and Firefox < 37 + e.preventDefault(); + e.stopPropagation(); + state.spacePressed = false; + element.style.cursor = 'default'; + element.style.scrollBehavior = ''; + } + }); + + element.addEventListener("mousedown", function (e) { + if (!state.spacePressed) { + return; + } + + // Tell the browser we're handling this event. + e.preventDefault(); + e.stopPropagation(); + + // Calc the starting mouse X,Y for the drag. + state.startX = parseInt(e.clientX); + state.startY = parseInt(e.clientY); + + var mouseX = parseInt(e.clientX); + var mouseY = parseInt(e.clientY); + + state.isDown = true; + }); + + element.addEventListener("mouseup", function (e) { + if (!state.spacePressed) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + + state.isDown = false; + }); + + element.addEventListener("mousemove", function (e) { + if (!state.isDown) { + return; + } + + if (!state.spacePressed) { + return; + } + + e.preventDefault(); + e.stopPropagation(); + + var mouseX = parseInt(e.clientX); + var mouseY = parseInt(e.clientY); + + var dx = mouseX - state.startX; + var dy = mouseY - state.startY; + + state.startX = mouseX; + state.startY = mouseY; + + var speedupFactor = MOUSEMOVE_SPEED_FACTOR; + element.scrollTo( + element.scrollLeft - dx * speedupFactor, element.scrollTop - dy * speedupFactor + ); + }); + + element.addEventListener("mouseleave", function (e) { + // Tell the browser we're handling this event. + e.preventDefault(); + e.stopPropagation(); + + state.isDown = false; + }); + } +}); + +// When a window is loaded, scroll to the central column of the DTR tree. +// The central column is the one where the current document's requirements are +// listed top-to-bottom. +document.addEventListener("DOMContentLoaded", function(event) { + const element = getPanElement(); + if (element) { + const firstNode = element.querySelector('.content_item[data-role="current"]'); + firstNode && firstNode.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); + } +}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_map.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_map.js new file mode 100644 index 0000000..b6f8946 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_map.js @@ -0,0 +1,1851 @@ +// map of the project for the stable_uri forwarder +const projectMap = { + "strictdoc/docs/strictdoc_01_user_guide.html": [ + + + {"MID":"c2d4542d5f1741c88dfcb4f68ad7dcbd","UID":"SDOC_UG","_LINK":"SDOC_UG" }, + + {"MID":"75a595ff028741d0bf9067bba8fb787a","_LINK":"1-Introduction" }, + + {"MID":"27023bf63c414fd998437961c77a0e2e","_LINK":"27023bf63c414fd998437961c77a0e2e" }, + + {"MID":"bcd0cf7c13cf4cf2ab176455aedc0c90","UID":"SDOC_UG_CONTACT","_LINK":"SDOC_UG_CONTACT" }, + + {"MID":"3ae6491057674be1abf057b7e0d9bf21","_LINK":"3ae6491057674be1abf057b7e0d9bf21" }, + + {"MID":"8e4ede8cdc70402b91a59026d31a7020","_LINK":"1.1.1-StrictDoc-office-hours" }, + + {"MID":"c46def916b6f4df692c95f47414feebb","_LINK":"c46def916b6f4df692c95f47414feebb" }, + + {"MID":"e0a00ca3085f444187050ce9576aa31b","_LINK":"2-Examples" }, + + {"MID":"2122186075e8455181178b01331101fa","UID":"SDOC_UG_HELLO_WORLD","_LINK":"SDOC_UG_HELLO_WORLD" }, + + {"MID":"ffbdb80fb21d48adbaeffb782d7994a2","_LINK":"ffbdb80fb21d48adbaeffb782d7994a2" }, + + {"MID":"83369fc77d584407b530b179a449479b","_LINK":"2.2-StrictDoc-Examples-repository" }, + + {"MID":"d6bde8e4055b42138d216b48692c8f26","_LINK":"d6bde8e4055b42138d216b48692c8f26" }, + + {"MID":"0a736f05ab154b2599988b63201d4f10","_LINK":"2.3-StrictDoc-Templates-repository" }, + + {"MID":"47c2088447d7452ba28962ee220ba63a","_LINK":"47c2088447d7452ba28962ee220ba63a" }, + + {"MID":"2b2e39c48cc740e5b8452d76881f667d","_LINK":"2.4-Other-examples" }, + + {"MID":"2eaa8bfe5a354fcbb704ea7fd94f3a0a","_LINK":"2eaa8bfe5a354fcbb704ea7fd94f3a0a" }, + + {"MID":"821b818006a14ed7aeb025d9ac8fe8b6","UID":"SDOC_UG_GETTING_STARTED","_LINK":"SDOC_UG_GETTING_STARTED" }, + + {"MID":"4e9f094a7b2949edb23c817c5e2276e4","_LINK":"3.1-Requirements" }, + + {"MID":"e7e4c2982d8e49deaa9b7413a09a4efa","_LINK":"e7e4c2982d8e49deaa9b7413a09a4efa" }, + + {"MID":"914da2bf10364a6fbd9fc7f48b96c6e5","_LINK":"3.2-Installing-StrictDoc-as-a-Pip-package-recommended-way" }, + + {"MID":"872a60c673854cfd909787f2379d88c7","_LINK":"872a60c673854cfd909787f2379d88c7" }, + + {"MID":"b3e2c50e2d7e46acbce7ea0c646776ca","_LINK":"3.3-Installing-nightly-StrictDoc-as-a-Pip-package" }, + + {"MID":"867f22a2767a434586d1ee4f7ee161fb","_LINK":"867f22a2767a434586d1ee4f7ee161fb" }, + + {"MID":"9e95ac9422f44aae92c0615176153815","_LINK":"3.4-Installing-StrictDoc-into-a-Docker-container" }, + + {"MID":"32e04944c2a14ead93248ff1ea37a68d","_LINK":"32e04944c2a14ead93248ff1ea37a68d" }, + + {"MID":"e441594df15841d38f717194b722f3de","_LINK":"3.5-Installing-StrictDoc-as-a-Snap-package-not-maintained" }, + + {"MID":"2adfe1bc6be542c3885ca4ea80b8d6e1","_LINK":"2adfe1bc6be542c3885ca4ea80b8d6e1" }, + + {"MID":"4af1193170a7416d81a799344dfc8ed6","_LINK":"3.6-Installing-StrictDoc-with-Nix" }, + + {"MID":"2045b5e37fc34a83b7457c43d816bf2c","_LINK":"2045b5e37fc34a83b7457c43d816bf2c" }, + + {"MID":"6cc72bf1a2a94999954e148a6bef374c","_LINK":"4-Running-StrictDoc" }, + + {"MID":"1685e4d63d9746b784b4a55f17b0de30","UID":"SECTION-UG-Static-HTML-export","_LINK":"SECTION-UG-Static-HTML-export" }, + + {"MID":"c092847abfa04295b63f943c951f24c8","_LINK":"c092847abfa04295b63f943c951f24c8" }, + + {"MID":"1a059d3ae7da45f8b53f3d74f3580980","UID":"SECTION-UG-Web-server","_LINK":"SECTION-UG-Web-server" }, + + {"MID":"1fc9f6f4f84d47439bf6aa3404227ca4","_LINK":"1fc9f6f4f84d47439bf6aa3404227ca4" }, + + {"MID":"9f7fcbdd8e564af8986349deb09745a5","_LINK":"4.3-Security-considerations" }, + + {"MID":"4fa89608f70e4a84a0e4b2930da28bbe","_LINK":"4fa89608f70e4a84a0e4b2930da28bbe" }, + + {"MID":"6d489d82b2e24bfeb2919be24262468f","UID":"SDOC_UG_IDE_SUPPORT","_LINK":"SDOC_UG_IDE_SUPPORT" }, + + {"MID":"aad57726976f4882982458de90d168c7","_LINK":"aad57726976f4882982458de90d168c7" }, + + {"MID":"24fb3436fa8c4b36929183eaac269376","UID":"SECTION-UG-SDoc-syntax","_LINK":"SECTION-UG-SDoc-syntax" }, + + {"MID":"556a4f61a4884f3088a743a0717f397f","_LINK":"556a4f61a4884f3088a743a0717f397f" }, + + {"MID":"43c9624d3c97433a97f8e8f39e2dd784","_LINK":"6.1-Document-structure" }, + + {"MID":"5419c0c9bfcc4922ac5aa79ddb333188","_LINK":"5419c0c9bfcc4922ac5aa79ddb333188" }, + + {"MID":"b4ceeb12bdf1448cb97b7974d4980189","UID":"SECTION-UG-DOCUMENT-ELEMENTS","_LINK":"SECTION-UG-DOCUMENT-ELEMENTS" }, + + {"MID":"db088d5977934056a851a24988e9266c","UID":"SECTION-UG-Document","_LINK":"SECTION-UG-Document" }, + + {"MID":"4b5c6f6fd70e44be8e5be10a38427e77","_LINK":"4b5c6f6fd70e44be8e5be10a38427e77" }, + + {"MID":"c75dc4ddd0c349e489817076877394a7","UID":"DOCUMENT_FIELD_OPTIONS","_LINK":"DOCUMENT_FIELD_OPTIONS" }, + + {"MID":"45f3cb9a3da54852a83670af72a4d21b","_LINK":"45f3cb9a3da54852a83670af72a4d21b" }, + + {"MID":"0f566e0d07bf4194adabc4fba2fdf919","_LINK":"6.2.1.1.1-ENABLE_MID" }, + + {"MID":"196b9e9d857548bebecc698903a593de","_LINK":"196b9e9d857548bebecc698903a593de" }, + + {"MID":"8cef59608d3942c88dc554f5531e2d8a","_LINK":"6.2.1.1.2-MARKUP" }, + + {"MID":"19f65eabcd1c4f28a0091133979b5b6e","_LINK":"19f65eabcd1c4f28a0091133979b5b6e" }, + + {"MID":"48c614864015426b8cb98d423201ad43","_LINK":"6.2.1.1.3-AUTO_LEVELS" }, + + {"MID":"915b35a9193348108e60968f9b60c1d0","_LINK":"915b35a9193348108e60968f9b60c1d0" }, + + {"MID":"8cde71c0f4d448c2a8939f9a81af7ac7","UID":"SECTION-UG-VIEW_STYLE","_LINK":"SECTION-UG-VIEW_STYLE" }, + + {"MID":"538a721c42824ad6b94a2f54780887ea","_LINK":"538a721c42824ad6b94a2f54780887ea" }, + + {"MID":"bdf01de0fc414b70a6a07118396b23b0","_LINK":"6.2.1.1.5-NODE_IN_TOC" }, + + {"MID":"e9e7522f3a094f5ea809f7bae93384d7","_LINK":"e9e7522f3a094f5ea809f7bae93384d7" }, + + {"MID":"726b6a1a2f854e82a7670cb8480b887e","_LINK":"6.2.1.2-Additional-Metadata" }, + + {"MID":"f86d45b7ad1a48ec919b43a695ca9126","_LINK":"f86d45b7ad1a48ec919b43a695ca9126" }, + + {"MID":"93085eee6a214a0a85aa94472f0a0a6c","UID":"SECTION-UG-Leaf-nodes","_LINK":"SECTION-UG-Leaf-nodes" }, + + {"MID":"23cbc84e92294aa0aeb0bb279d914480","_LINK":"6.2.2.1-TEXT" }, + + {"MID":"4474709783b74b1ca31fa754c712344e","_LINK":"4474709783b74b1ca31fa754c712344e" }, + + {"MID":"6426b56116ba428fbba395c79dc2eacc","_LINK":"6.2.2.2-REQUIREMENT" }, + + {"MID":"f221cd0c72f846b385ec2f0a9ddd15d5","_LINK":"f221cd0c72f846b385ec2f0a9ddd15d5" }, + + {"MID":"a1ad4861e5bc442baf38383b29c901a1","UID":"UG_COMPOSITE_NODE","_LINK":"UG_COMPOSITE_NODE" }, + + {"MID":"ce69fe89236a4bcfa104a640def4b64a","_LINK":"ce69fe89236a4bcfa104a640def4b64a" }, + + {"MID":"c8c15acf52a24c99922bdae6711f5120","UID":"ELEMENT_SECTION","_LINK":"ELEMENT_SECTION" }, + + {"MID":"14e5fea31b1c41bf8c743f18e51053e0","_LINK":"14e5fea31b1c41bf8c743f18e51053e0" }, + + {"MID":"9a571c9363ee4dc4a3cdc56abd2c57a7","_LINK":"6.2.3.1.1-Nesting-sections" }, + + {"MID":"fa700a9b975f493ba7ec2fd0a7b44bbe","_LINK":"fa700a9b975f493ba7ec2fd0a7b44bbe" }, + + {"MID":"0f52cfb294af480e806f0434d0a07757","_LINK":"6.2.3.1.2-Section-grammar-definition" }, + + {"MID":"7f2967ea1a41426ba15c0bdde2664920","_LINK":"7f2967ea1a41426ba15c0bdde2664920" }, + + {"MID":"324938c23b864864b4e8ff6a67b589a5","_LINK":"6.2.4-Reserved-fields" }, + + {"MID":"4d69fa95bd974d859973dbb34679a7c4","_LINK":"4d69fa95bd974d859973dbb34679a7c4" }, + + {"MID":"79b128720cd74a548d291e223b61c4bc","UID":"SECTION-UG-Machine-identifiers-MID","_LINK":"SECTION-UG-Machine-identifiers-MID" }, + + {"MID":"7fe2832d60014259a8d67a09f1db102a","_LINK":"7fe2832d60014259a8d67a09f1db102a" }, + + {"MID":"4afebe421fe341b8b609b1c24f47b708","_LINK":"6.2.4.1.1-Unique-vs-machine-identifiers-MID-vs-UID" }, + + {"MID":"a5a3d62d90f646aa8fac43795aa8fcbb","_LINK":"a5a3d62d90f646aa8fac43795aa8fcbb" }, + + {"MID":"6a7c6a10b0fc4db7a5b32abedc3bb31c","_LINK":"6.2.4.2-UID" }, + + {"MID":"2c3b050a2cd0444fb8948bb6adcb7085","_LINK":"2c3b050a2cd0444fb8948bb6adcb7085" }, + + {"MID":"f01eced244e842e28c0729d8458ac935","UID":"UG_NODE_WITHOUT_A_LEVEL","_LINK":"UG_NODE_WITHOUT_A_LEVEL" }, + + {"MID":"094425a33e8941d9a0016b4ed714c664","_LINK":"094425a33e8941d9a0016b4ed714c664" }, + + {"MID":"05c39a0bc4d9482ca4199c84b1981948","_LINK":"6.2.4.4-STATUS" }, + + {"MID":"448aa949724e4361a5b2f317c40c7492","_LINK":"6.2.4.5-TAGS" }, + + {"MID":"d7c2d72f849b413cb312d44813d25d5a","_LINK":"d7c2d72f849b413cb312d44813d25d5a" }, + + {"MID":"62480ac9dbdf4e4fb5c533abefa19997","_LINK":"6.2.4.6-TITLE" }, + + {"MID":"f5f9008f417e40aa8acd9da18ccd89d1","_LINK":"f5f9008f417e40aa8acd9da18ccd89d1" }, + + {"MID":"fb3b2d0bbf4c43abaa09b29b106346d4","_LINK":"6.2.4.7-STATEMENT" }, + + {"MID":"cea069906c2e4329bea0d97744984ba8","_LINK":"cea069906c2e4329bea0d97744984ba8" }, + + {"MID":"bf35d37584b34aabb5bf3b2e144beecb","_LINK":"6.2.4.8-RATIONALE" }, + + {"MID":"7e63bdbce418401da8eb5aa607fd8fc2","_LINK":"7e63bdbce418401da8eb5aa607fd8fc2" }, + + {"MID":"165b33aa61474a1db0ca0bd1f1279ba4","_LINK":"6.2.4.9-COMMENT" }, + + {"MID":"3928acde165b4505943154199ecd739a","_LINK":"3928acde165b4505943154199ecd739a" }, + + {"MID":"f10fd08172054423be7c00fcd16e61e9","UID":"SDOC_UG_REQUIREMENT_RELATIONS","_LINK":"SDOC_UG_REQUIREMENT_RELATIONS" }, + + {"MID":"c0c9c15d57e742ed80f12b8895f01de0","_LINK":"c0c9c15d57e742ed80f12b8895f01de0" }, + + {"MID":"c357b57be45a4871a6dfb877483de702","_LINK":"6.2.4.10.1-Relation-roles" }, + + {"MID":"a54f41576b2d40df92041862bef13600","_LINK":"a54f41576b2d40df92041862bef13600" }, + + {"MID":"57df0956302f4c728f6b35606320b660","UID":"UG_COMPOSABLE_DOCUMENTS","_LINK":"UG_COMPOSABLE_DOCUMENTS" }, + + {"MID":"6ed881a7cb8949cab3d1a1836846b716","_LINK":"6ed881a7cb8949cab3d1a1836846b716" }, + + {"MID":"952dd638d61c45ab950f271d53e56b2f","_LINK":"952dd638d61c45ab950f271d53e56b2f" }, + + {"MID":"0d29071c7f924ecdb11fc32da4ecc5e3","UID":"SECTION-UG-DOCUMENT-GRAMMAR","_LINK":"SECTION-UG-DOCUMENT-GRAMMAR" }, + + {"MID":"4c2244d6affb4653844f730e1de88266","_LINK":"4c2244d6affb4653844f730e1de88266" }, + + {"MID":"269600f411374fce975c3d7110ae74b6","_LINK":"6.3.1-Supported-field-types" }, + + {"MID":"a437c871dc3d46dba80460d5c8c22cf6","_LINK":"a437c871dc3d46dba80460d5c8c22cf6" }, + + {"MID":"3b9af7a4f6444664aa9e76343b477236","_LINK":"6.3.2-Grammar-element-properties" }, + + {"MID":"e1e5bda619f549188d8d7ae158aeaa44","_LINK":"6.3.2.1-IS_COMPOSITE" }, + + {"MID":"5396d4571b4c4204b093a44980a489ed","_LINK":"5396d4571b4c4204b093a44980a489ed" }, + + {"MID":"f2c8342dd6f5432c95ef6f80cf5e87ba","_LINK":"6.3.2.2-PREFIX" }, + + {"MID":"19d4dcbf0cd24f84996bcddb778e348c","_LINK":"19d4dcbf0cd24f84996bcddb778e348c" }, + + {"MID":"61df1b83c27e43909ad5640cf0d78962","UID":"SECTION-UG-VIEW_STYLE-2","_LINK":"SECTION-UG-VIEW_STYLE-2" }, + + {"MID":"4678706b4c864f459d1b478cd703fcc1","_LINK":"4678706b4c864f459d1b478cd703fcc1" }, + + {"MID":"04828fd96e2e42f3810af276d06859c1","UID":"SDOC_UG_GRAMMAR_RELATIONS","_LINK":"SDOC_UG_GRAMMAR_RELATIONS" }, + + {"MID":"012b0350547a48fc9ab3fbd6d9b5d502","_LINK":"012b0350547a48fc9ab3fbd6d9b5d502" }, + + {"MID":"16ce47f32874421986a5a843c5aeb2bf","UID":"SECTION-UG-Relation-roles","_LINK":"SECTION-UG-Relation-roles" }, + + {"MID":"01b8aa59963b42518d98c4e6b5e3259b","_LINK":"01b8aa59963b42518d98c4e6b5e3259b" }, + + {"MID":"ed4e4d30b3eb46ca976295aa27ede9e3","UID":"SDOC_UG_GRAMMAR_RELATIONS_PARENT_VS_CHILD","_LINK":"SDOC_UG_GRAMMAR_RELATIONS_PARENT_VS_CHILD" }, + + {"MID":"b119e614781044eab641e20eaec872e5","_LINK":"b119e614781044eab641e20eaec872e5" }, + + {"MID":"cd7d9c9b0efe443895d1b6eb44a3799b","_LINK":"6.3.4-IMPORT_FROM_FILE-Importing-grammar-from-file" }, + + {"MID":"df106206da0e446e87021fbf711fdb65","_LINK":"df106206da0e446e87021fbf711fdb65" }, + + {"MID":"d4292ad751ca407b8147e7204a934c4e","UID":"SDOC_UG_LINKS_AND_ANCHORS","_LINK":"SDOC_UG_LINKS_AND_ANCHORS" }, + + {"MID":"6ce1010a003146ec9e3e8d77ee89a082","_LINK":"6ce1010a003146ec9e3e8d77ee89a082" }, + + {"MID":"ac7ccc30e5bf489cb4929302c8ec21cf","_LINK":"6.4.1-Links" }, + + {"MID":"8b07c82f462348a58c3ab81be4db753d","_LINK":"8b07c82f462348a58c3ab81be4db753d" }, + + {"MID":"a1d9bb6b7df84b5eb6bf355542a5288a","_LINK":"6.4.2-Anchors" }, + + {"MID":"294d6a0e96424dc8a93d6502c43e8501","_LINK":"294d6a0e96424dc8a93d6502c43e8501" }, + + {"MID":"26b105a45eda470497148a7903ca731b","_LINK":"6.4.2.1-Anchor-example" }, + + {"MID":"ba71ef8f24b342178b28e87b7609b8d7","_LINK":"ba71ef8f24b342178b28e87b7609b8d7" }, + + {"MID":"ec9dcd4ad28a4852bc47723e667006df","_LINK":"6.5-Syntax-rules" }, + + {"MID":"926894ac8efc4e99943741691b3d4efe","UID":"SECTION-UG-Strict-rule-1","_LINK":"SECTION-UG-Strict-rule-1" }, + + {"MID":"2ebd1f2d3c8746a383d71232756c3bd3","_LINK":"2ebd1f2d3c8746a383d71232756c3bd3" }, + + {"MID":"1e465597f02842de92852be3a57f84cb","UID":"SECTION-UG-Strict-rule-2","_LINK":"SECTION-UG-Strict-rule-2" }, + + {"MID":"686eb01cf7db44c4bd1edd72ccb02ed0","_LINK":"686eb01cf7db44c4bd1edd72ccb02ed0" }, + + {"MID":"c741dd299b044fc9b72510256d48589e","UID":"SECTION-UG-Strict-rule-3","_LINK":"SECTION-UG-Strict-rule-3" }, + + {"MID":"c01ab5711463497498c91a968179d63c","_LINK":"c01ab5711463497498c91a968179d63c" }, + + {"MID":"31eb939aa5684f74b86be93ea7f14f7b","_LINK":"7-Markup" }, + + {"MID":"a3d675f38a1341548722239e994e55e1","_LINK":"a3d675f38a1341548722239e994e55e1" }, + + {"MID":"64d48546374e4bfd881733b0174fbebe","_LINK":"7.1-Images" }, + + {"MID":"e87ffdf6195c481cb39bc3d1ec29eca6","_LINK":"e87ffdf6195c481cb39bc3d1ec29eca6" }, + + {"MID":"83066d011cef4e8694aac5fbe90a357e","_LINK":"7.2-Mathjax-support" }, + + {"MID":"abdf406fe10847929dd7cb12a030456f","_LINK":"abdf406fe10847929dd7cb12a030456f" }, + + {"MID":"3e761d05262f44d29f48476c89ce3ca2","_LINK":"8-Export-formats" }, + + {"MID":"110260c57dbb47da87662686bc73d6e7","_LINK":"8.1-HTML-documentation-tree-by-StrictDoc" }, + + {"MID":"a6bfffddf89045a1a7ecf55c9681fe14","_LINK":"a6bfffddf89045a1a7ecf55c9681fe14" }, + + {"MID":"dcc6a2bc11424cf2b114b25a7f65530d","UID":"SECTION-UG-Inbound-Links","_LINK":"SECTION-UG-Inbound-Links" }, + + {"MID":"742831d32ca54791b53c1dbbbd070b55","_LINK":"742831d32ca54791b53c1dbbbd070b55" }, + + {"MID":"1b41e7c036cf4e3282fa3d4e687bf95d","_LINK":"8.1.2-Standalone-HTML-pages" }, + + {"MID":"5674bfd50f31420baf56625d79d1ebff","_LINK":"5674bfd50f31420baf56625d79d1ebff" }, + + {"MID":"f6091bab49714c1fa72c2fbca12c970b","UID":"SECTION-UG-HTML-export-via-Sphinx","_LINK":"SECTION-UG-HTML-export-via-Sphinx" }, + + {"MID":"bf8160f43703418db306785c48463123","_LINK":"bf8160f43703418db306785c48463123" }, + + {"MID":"c95a2b4c4fbd40fcbd92fe7f24c2cd91","UID":"SECTION-UG-PDF-export-via-Sphinx-LaTeX","_LINK":"SECTION-UG-PDF-export-via-Sphinx-LaTeX" }, + + {"MID":"58595abe6ff148afbb45e2b6adc25110","_LINK":"58595abe6ff148afbb45e2b6adc25110" }, + + {"MID":"e33a21323e2b48d692ed85cc56fd06e6","_LINK":"8.4-JSON" }, + + {"MID":"4d956edcd00846a98f59778dd7de9257","_LINK":"4d956edcd00846a98f59778dd7de9257" }, + + {"MID":"40050f96b9a64f57bbb0ad01f4d37264","_LINK":"9-Manage-project-tree" }, + + {"MID":"7f4b56d2a1104f539489bf7ddcdb1469","UID":"SECTION-UG-Automatic-assignment-of-requirements-UID","_LINK":"SECTION-UG-Automatic-assignment-of-requirements-UID" }, + + {"MID":"ed367ed0bc284d4d9318bf6c844c3e3e","_LINK":"ed367ed0bc284d4d9318bf6c844c3e3e" }, + + {"MID":"fa1cc31842144440a8ca310c7c0dedb2","UID":"SECTION-TRACEABILITY-REQS-TO-SOURCE-CODE","_LINK":"SECTION-TRACEABILITY-REQS-TO-SOURCE-CODE" }, + + {"MID":"4398b17f61ad4dd290e72d7888597f48","_LINK":"4398b17f61ad4dd290e72d7888597f48" }, + + {"MID":"845ff817ad9d483796b9dc6016bfc3c7","UID":"SECTION-UG-Language-aware-parsing-of-source-code","_LINK":"SECTION-UG-Language-aware-parsing-of-source-code" }, + + {"MID":"07bfe045a4934dd29d97fdb8ac567b7c","_LINK":"07bfe045a4934dd29d97fdb8ac567b7c" }, + + {"MID":"2cde4b7a4d42450c84c93989aeb4d53d","_LINK":"10.2-Linking-source-code-to-requirements" }, + + {"MID":"c787c538cc0a422fb2898b525ec1006d","_LINK":"c787c538cc0a422fb2898b525ec1006d" }, + + {"MID":"a72c5eceff5c446c968c0e23bda3d933","_LINK":"10.3-Linking-requirements-to-source-code" }, + + {"MID":"1c06fb7b90114633801d177459f482b5","_LINK":"1c06fb7b90114633801d177459f482b5" }, + + {"MID":"38599400293a4b31a7cb6cb748f3dfe5","UID":"SECTION-UG-File-relations-roles","_LINK":"SECTION-UG-File-relations-roles" }, + + {"MID":"4f477cb2e0ca42aaac814042f795b982","_LINK":"4f477cb2e0ca42aaac814042f795b982" }, + + {"MID":"c9da7df725564208971e7ee058ad8d73","UID":"SECTION-UG-Parsing-SDoc-source-nodes","_LINK":"SECTION-UG-Parsing-SDoc-source-nodes" }, + + {"MID":"72fe8c3f618042578850cfdf01868b6c","_LINK":"72fe8c3f618042578850cfdf01868b6c" }, + + {"MID":"31411ccbe80144868da8961ea2dd38bc","UID":"SECTION-UG-ReqIF-support","_LINK":"SECTION-UG-ReqIF-support" }, + + {"MID":"b510d9337e604bfda366f2ec605f4c88","_LINK":"b510d9337e604bfda366f2ec605f4c88" }, + + {"MID":"81f3e7ff2e584f789e0076d0ab560d45","_LINK":"11.1-Import-flow-ReqIF-SDoc" }, + + {"MID":"079ed6d7ec3f4040b59efce7ccd37267","_LINK":"079ed6d7ec3f4040b59efce7ccd37267" }, + + {"MID":"7d1678af20a84f5d8263061f36332773","_LINK":"11.2-Export-flow-SDoc-ReqIF" }, + + {"MID":"94641cac6b9748bfa2de8648ff197584","_LINK":"94641cac6b9748bfa2de8648ff197584" }, + + {"MID":"c87ecf181d564e44ad1981558bf2cab0","UID":"SECTION-UG-ReqIF-options","_LINK":"SECTION-UG-ReqIF-options" }, + + {"MID":"57dd1fb10ba64e2f8e0b75baf772b634","_LINK":"57dd1fb10ba64e2f8e0b75baf772b634" }, + + {"MID":"95643ee2edb84ad8b86f9cf2bb74aaae","UID":"SECTION-REQIF-DETAILS","_LINK":"SECTION-REQIF-DETAILS" }, + + {"MID":"edd5c3bf902e48deaee3248d12087a75","_LINK":"edd5c3bf902e48deaee3248d12087a75" }, + + {"MID":"5ad8e72bdcfb4ac1b942468af9180657","_LINK":"12-Excel-support" }, + + {"MID":"65c1657a8fb04179960fca4ece265b18","_LINK":"65c1657a8fb04179960fca4ece265b18" }, + + {"MID":"4a34ea5da82b4e469cf5a87178f69536","_LINK":"12.1-Import-flow-Excel-XLS-XLSX-SDoc" }, + + {"MID":"b01355b5a6d54409a0c7a684376a5278","_LINK":"b01355b5a6d54409a0c7a684376a5278" }, + + {"MID":"1cbdef9ee67b4392a3bdb64276e90e36","_LINK":"12.2-Export-flow-SDoc-Excel-XLSX" }, + + {"MID":"14161a9fa81d427f8a5a21367359339e","_LINK":"14161a9fa81d427f8a5a21367359339e" }, + + {"MID":"17a8adb92c8d4e7992e869355e73912d","_LINK":"13-Options" }, + + {"MID":"05f82bdf26f141738d2f511133633a2d","UID":"SDOC_UG_OPTIONS_PROJECT_LEVEL","_LINK":"SDOC_UG_OPTIONS_PROJECT_LEVEL" }, + + {"MID":"6449098df878484fbe8aed8a8b0e9a97","_LINK":"6449098df878484fbe8aed8a8b0e9a97" }, + + {"MID":"3671119d6a304d0b80c63f7e31faee88","_LINK":"13.1.1-Project-title" }, + + {"MID":"12501275599f4d7a954892e1a56778b9","_LINK":"12501275599f4d7a954892e1a56778b9" }, + + {"MID":"22741629bf054d6784faf541393e90d0","_LINK":"13.1.2-Path-to-assets" }, + + {"MID":"7d1102cda98c4ea18c6e646b73511097","_LINK":"7d1102cda98c4ea18c6e646b73511097" }, + + {"MID":"9fbabb0a6d0e46648f58ba7245776bd9","UID":"SECTION-UG-Path-to-cache-dir","_LINK":"SECTION-UG-Path-to-cache-dir" }, + + {"MID":"e94e9762cc0e4e1eafe57d0d9e03eb5b","_LINK":"e94e9762cc0e4e1eafe57d0d9e03eb5b" }, + + {"MID":"2c54380e174e42b6ba8eff74173ceb0f","_LINK":"13.1.4-Path-to-source-root" }, + + {"MID":"be42ecf5c8a84fc3bca0b73ea50647de","_LINK":"be42ecf5c8a84fc3bca0b73ea50647de" }, + + {"MID":"499fa0144cbd48c687ba0d5f9f7cb846","_LINK":"13.1.5-Path-to-custom-HTML2PDF-template" }, + + {"MID":"225dc4d22c084a67ae049fca1098bc1a","_LINK":"225dc4d22c084a67ae049fca1098bc1a" }, + + {"MID":"593a2abbdaa5470988103c70e87c4cfc","_LINK":"13.1.6-Include-exclude-document-paths" }, + + {"MID":"27e5981c451d4ad4938ab622e3cf0be2","_LINK":"27e5981c451d4ad4938ab622e3cf0be2" }, + + {"MID":"7284798d60a340c2a6369c651d1ee6be","_LINK":"13.1.7-Include-exclude-source-files-paths" }, + + {"MID":"3908f98fab5c47668ba752d0e93033ab","_LINK":"3908f98fab5c47668ba752d0e93033ab" }, + + {"MID":"b355fc6730d14eb1892ac6a25e47bf59","UID":"SDOC_UG_CONFIG_FEATURES","_LINK":"SDOC_UG_CONFIG_FEATURES" }, + + {"MID":"f43d8170c44b4d70ada2816fe71caf07","_LINK":"f43d8170c44b4d70ada2816fe71caf07" }, + + {"MID":"39f7752d17c848e4ae9acd53eaf8048b","_LINK":"13.1.8.1-Enable-all-features" }, + + {"MID":"d33880e1740d4d0892852cc8c425f66f","_LINK":"d33880e1740d4d0892852cc8c425f66f" }, + + {"MID":"35173b0d735a4d4f8c06256d1d4e1f89","_LINK":"13.1.8.2-Disable-all-features" }, + + {"MID":"9cf2ac683b7a4e939286146ef00631c1","_LINK":"9cf2ac683b7a4e939286146ef00631c1" }, + + {"MID":"fc0da01a4a114ddd888a90fd6a29e456","_LINK":"13.1.9-Server-configuration" }, + + {"MID":"c520cefdfe3e47ccb1a0ada95ee5c4f0","UID":"SECTION-UG-Host-and-port","_LINK":"SECTION-UG-Host-and-port" }, + + {"MID":"9943131c688c400b99e2db9ec4854480","_LINK":"9943131c688c400b99e2db9ec4854480" }, + + {"MID":"cc720b525adf46849f6117c18c97905e","_LINK":"13.2-Command-line-interface-options" }, + + {"MID":"d69f1fe42c754a34a5f360f47d4b4a5b","_LINK":"13.2.1-Project-title" }, + + {"MID":"81d8e1beb5904cb78dfde2712ff3f311","_LINK":"81d8e1beb5904cb78dfde2712ff3f311" }, + + {"MID":"6ea7b264c142461398e9c8711cfec8d3","_LINK":"13.2.2-Parallelization" }, + + {"MID":"f8ff07833ff942dfabdad2412350cd0c","_LINK":"f8ff07833ff942dfabdad2412350cd0c" }, + + {"MID":"8030a2ceb5014b9881529ef39d3c1fb7","_LINK":"14-Python-API" }, + + {"MID":"4504bffd6ced4aa78848ee9e03fdd4b7","_LINK":"4504bffd6ced4aa78848ee9e03fdd4b7" }, + + {"MID":"cb5115ac9a6d47a198ceac81c9d49b60","UID":"UG_PORTABILITY_CONSIDERATIONS","_LINK":"UG_PORTABILITY_CONSIDERATIONS" }, + + {"MID":"e15260727be84ce394386a4f95c627ae","_LINK":"e15260727be84ce394386a4f95c627ae" }, + + {"MID":"d49d64a25f654d0c9b39023e87e5fa19","_LINK":"16-Interoperability-with-other-tools" }, + + {"MID":"dc83f93c820944b6b04c0923a7ad7e69","UID":"SECTION-UG-Doxygen","_LINK":"SECTION-UG-Doxygen" }, + + {"MID":"a8664547ac7e41399d7d8d263869abc6","_LINK":"a8664547ac7e41399d7d8d263869abc6" }, + + {"MID":"1296f265cdd948d8a5c02fbfc1cc4065","_LINK":"16.2-Valispace" }, + + {"MID":"5fe39dedfa4640d2bd7127ff23b0e3de","_LINK":"5fe39dedfa4640d2bd7127ff23b0e3de" }, + + {"MID":"e3596b4fb0804ac28a8bb3d06bd81953","UID":"SDOC_UG_EXPERIMENTAL_FEATURES","_LINK":"SDOC_UG_EXPERIMENTAL_FEATURES" }, + + {"MID":"5b400736aec54789b2ed3ebcffcf961e","_LINK":"5b400736aec54789b2ed3ebcffcf961e" }, + + {"MID":"72fdb23051184714ab32e22859504a77","UID":"SECTION-UG-Search-and-filtering","_LINK":"SECTION-UG-Search-and-filtering" }, + + {"MID":"de584af947a445e5bcc782bab6a93baf","_LINK":"de584af947a445e5bcc782bab6a93baf" }, + + {"MID":"f2d766a310ef41959b0c6d581d042420","_LINK":"17.1.1-Query-engine" }, + + {"MID":"29ffc3e91d8045589b0837f647286128","_LINK":"29ffc3e91d8045589b0837f647286128" }, + + {"MID":"2da071ad45054d168a5ae2982266fb77","_LINK":"17.1.2-Filtering-content" }, + + {"MID":"d52d86750ad54ce1b3263ebb092451c0","_LINK":"d52d86750ad54ce1b3263ebb092451c0" }, + + {"MID":"241afbf6b7af40189eec8054d0d0201c","UID":"SECTION-UG-Project-statistics-screen","_LINK":"SECTION-UG-Project-statistics-screen" }, + + {"MID":"2fefc893de83432fa852886cc3a05fea","_LINK":"2fefc893de83432fa852886cc3a05fea" }, + + {"MID":"aa84a8c59a904c9dbb1052b1bff169bf","_LINK":"17.2.1-User-provided-custom-statistics-generator-experimental" }, + + {"MID":"7cf15de69efc46a5abe6b6fc786e4b71","_LINK":"7cf15de69efc46a5abe6b6fc786e4b71" }, + + {"MID":"aa7ebc36cd2947ac9aa293d6c76d8848","UID":"SECTION-UG-Diff-changelog-screen","_LINK":"SECTION-UG-Diff-changelog-screen" }, + + {"MID":"131a7392a33f4225a62539dd173a920b","_LINK":"131a7392a33f4225a62539dd173a920b" }, + + {"MID":"0a4573d025f14e61b84aad14349d42f4","UID":"SECTION-UG-HTML2PDF-document-generator","_LINK":"SECTION-UG-HTML2PDF-document-generator" }, + + {"MID":"6e610b9a381f4b5d9d26004dd286e001","_LINK":"6e610b9a381f4b5d9d26004dd286e001" }, + + {"MID":"61b3fa2fc31140ae95ae1a651cb18355","_LINK":"17.5-Mermaid-diagramming-and-charting-tool" }, + + {"MID":"6a4e4467a5c0451ea8291fd94309d525","_LINK":"6a4e4467a5c0451ea8291fd94309d525" }, + + {"MID":"74291dc6cfae47d2bae33066024f3807","_LINK":"17.6-Test-report-integration" }, + + {"MID":"07e78a4847554fbd87c44d7b11133f68","_LINK":"07e78a4847554fbd87c44d7b11133f68" }, + + {"MID":"e9c94abacb12425980aec8ed7ee752cb","_LINK":"17.6.1-JUnit-XML" }, + + {"MID":"eba63ebd45624139a8773cf42fe7d670","_LINK":"eba63ebd45624139a8773cf42fe7d670" }, + + {"MID":"06d9dbbeca204f5e8d0042e142b615bd","_LINK":"17.6.2-LLVM-Integrated-Tester-JUnit-XML-specifics" }, + + {"MID":"fab24f53f02f46e7a4cb49e333dfdc54","_LINK":"fab24f53f02f46e7a4cb49e333dfdc54" }, + + {"MID":"c7f5451905bf4fdb9a3a7dc97bb0e853","_LINK":"17.6.3-Robot-Framework-XML" }, + + {"MID":"6c3d98ca65cc40d585953237693ff2c6","_LINK":"6c3d98ca65cc40d585953237693ff2c6" }, + + {"MID":"66e608bfa6b8448598c0a732a27ddaad","_LINK":"17.7-Shadow-features" }, + + {"MID":"38fa0af0d01e479ba7f5be046bae02eb","_LINK":"38fa0af0d01e479ba7f5be046bae02eb" }, + + {"MID":"c3c6d6fe6e8140ca905d26dbbaae22b3","UID":"SDOC_UG_LIMIT","_LINK":"SDOC_UG_LIMIT" }, + + {"MID":"4fb2645146eb42c1be2152d480b61cfc","UID":"SDOC_UG_LIMIT_RST","_LINK":"SDOC_UG_LIMIT_RST" }, + + {"MID":"f7b039831f4e4c1ea19b45efe71c5365","_LINK":"f7b039831f4e4c1ea19b45efe71c5365" }, + + {"MID":"076c2ae8d627491a85ddcacc132a4bc5","UID":"SDOC_UG_LIMIT_WEB","_LINK":"SDOC_UG_LIMIT_WEB" }, + + {"MID":"911c454331634018b8de24186ae8e742","_LINK":"911c454331634018b8de24186ae8e742" }, + + {"MID":"2a49392c11d246ea8c69375764fc5362","_LINK":"18.2.1-Concurrent-use-of-web-user-interface" }, + + {"MID":"bdee3bde500a40878b70be44f113cf2c","_LINK":"bdee3bde500a40878b70be44f113cf2c" }, + + {"MID":"c5cfb2c7892f4137a3bc0c3136a55a89","_LINK":"19-Known-issues" }, + + {"MID":"9282f2d7218a4f2e967b6df45b0347ab","_LINK":"9282f2d7218a4f2e967b6df45b0347ab" }, + + {"MID":"7e4c91401d244149a1aa502d990f0052","UID":"SDOC_IMPL_2","_LINK":"SDOC_IMPL_2" }, + + {"MID":"ec83d51626ee4e0cbb75c500ee306b06","_LINK":"ec83d51626ee4e0cbb75c500ee306b06" }, + + {"MID":"b55c23b113d54802b5717f7a82a45bd2","_LINK":"20-Appendices" }, + + {"MID":"a72ae310493a42ba8ecdc7de2c42d4f2","UID":"SECTION-UG-FREETEXT-TEXT","_LINK":"SECTION-UG-FREETEXT-TEXT" }, + + {"MID":"2509cce7ee634c7a8878c5e1094b83f2","_LINK":"2509cce7ee634c7a8878c5e1094b83f2" }, + + {"MID":"bbe50de9a4d845a7aa91e32dd9335abe","_LINK":"20.1.1-How-to-migrate-from-FREETEXT-to-TEXT" }, + + {"MID":"5d2f033604824264b1cc05840997c6b8","_LINK":"5d2f033604824264b1cc05840997c6b8" }, + + {"MID":"2ed20461aeb4462b812432c08aa006be","UID":"SECTION-UG-NODE-MIGRATION","_LINK":"SECTION-UG-NODE-MIGRATION" }, + + {"MID":"9d55b69bf789487e814210da06fc4164","_LINK":"9d55b69bf789487e814210da06fc4164" }, + + {"MID":"6f15ef6876ba48598d5560aaf4664ec9","_LINK":"20.2.1-How-to-migrate-from-SECTION-to-SECTION" }, + + {"MID":"19fe5099aa034eddb960cc88953ace0e","_LINK":"19fe5099aa034eddb960cc88953ace0e" }, ], + "strictdoc/docs/strictdoc_02_feature_map.html": [ + + + {"MID":"1696d73230f046d589d2d87dd29d48a9","UID":"SDOC_FEATURE_MAP","_LINK":"SDOC_FEATURE_MAP" }, + + {"MID":"f405431dc66e4d6786be020a62a4e5a3","_LINK":"f405431dc66e4d6786be020a62a4e5a3" }, + + {"MID":"01c07ca347a24181a92a5be6c8431094","UID":"SECTION-FM-SDoc-text-markup","_LINK":"SECTION-FM-SDoc-text-markup" }, + + {"MID":"dfd4d2d77c7247819e476f360ffff639","_LINK":"1.1-Definition" }, + + {"MID":"4c40803dd0f04af88fd722ba6b732270","UID":"SDOC-FEAT-1","_LINK":"SDOC-FEAT-1" }, + + {"MID":"3f422abd9abe4717a995ae4150df12e3","_LINK":"1.2-Use-case" }, + + {"MID":"8ea5b080819e47afa78bc346d671cf30","_LINK":"8ea5b080819e47afa78bc346d671cf30" }, + + {"MID":"fa7b37153def4eb4a6e9dcee079cba2a","_LINK":"1.3-Inspirations" }, + + {"MID":"104b6ff4623f4ac9a965aa789c4cf001","_LINK":"104b6ff4623f4ac9a965aa789c4cf001" }, + + {"MID":"87b1538be72a4ff7945b5bb95f856471","_LINK":"1.4-Screenshots" }, + + {"MID":"f48ae881c5134f77885202b019e124d4","_LINK":"f48ae881c5134f77885202b019e124d4" }, + + {"MID":"27bb9f0875d84d79bb882f6ca98ee1fa","_LINK":"2-HTML-export" }, + + {"MID":"4a0844b5938a488a89ac4b379fc7d956","_LINK":"2.1-Definition" }, + + {"MID":"8e6604c8b27b450cbd21c12dc8572291","UID":"SDOC-FEAT-2","_LINK":"SDOC-FEAT-2" }, + + {"MID":"4e46063e2031418298b55a1861179900","_LINK":"2.2-Screenshots" }, + + {"MID":"586f8745588b483b8e027021d90931ac","_LINK":"586f8745588b483b8e027021d90931ac" }, + + {"MID":"3ef4254efd8547a8adaf37e100f22724","_LINK":"3-Web-based-graphical-user-interface" }, + + {"MID":"bd3e1273cb244616956bddfc22c05638","_LINK":"3.1-Definition" }, + + {"MID":"2c1cde585d5944b5b7b5a0d5f72a98ed","UID":"SDOC-FEAT-3","_LINK":"SDOC-FEAT-3" }, + + {"MID":"6b5989db0e984c42b12440993c885987","_LINK":"3.2-Screenshots" }, + + {"MID":"28ce32fe182c45ce882b65c835620339","_LINK":"28ce32fe182c45ce882b65c835620339" }, + + {"MID":"5ac3e3c690494371bd9de04be5eae0b0","_LINK":"4-Traceability-between-requirements-and-source-code" }, + + {"MID":"538d26fae4644debbc8f244709b8be7b","_LINK":"4.1-Definition" }, + + {"MID":"e14eee106ea443e598378e55401914dc","UID":"SDOC-FEAT-4","_LINK":"SDOC-FEAT-4" }, + + {"MID":"ceec313d9ec040b9bcaaf64967ed6af8","_LINK":"4.2-Screenshots" }, + + {"MID":"363aae23cbb44f30aff42ef6a430ffdf","_LINK":"363aae23cbb44f30aff42ef6a430ffdf" }, + + {"MID":"a436d31c5f324eb0bb6b35f0a6ce598d","_LINK":"5-Document-grammar" }, + + {"MID":"f20223cddcb14e40b45f99045e2d3a3a","_LINK":"5.1-Definition" }, + + {"MID":"0bfcb6144dde487791d4f01164dd7e7c","UID":"SDOC-FEAT-5","_LINK":"SDOC-FEAT-5" }, + + {"MID":"f4763b00f9624cfd8b44f8e571f2aec6","_LINK":"5.2-Screenshots" }, + + {"MID":"3d3d3e2c1c974ed4a2382770225212d7","_LINK":"3d3d3e2c1c974ed4a2382770225212d7" }, + + {"MID":"5b511eac439c4e0a8aa2c60499be88d0","_LINK":"6-Composable-documents" }, + + {"MID":"ab4bc7b948154dbfbd4956d41cda8b75","_LINK":"6.1-Definition" }, + + {"MID":"e7b2d61545eb414f97345ecac25c52cc","UID":"SDOC-FEAT-6","_LINK":"SDOC-FEAT-6" }, + + {"MID":"dd4d9c0d593b46f8a0abfb3fd91356ae","_LINK":"7-Export-to-RST" }, + + {"MID":"ab0e4d27b6334b44bd4b46425842cdbe","_LINK":"7.1-Definition" }, + + {"MID":"dd686a557c3e4e50ba89538a74d39383","UID":"SDOC-FEAT-8","_LINK":"SDOC-FEAT-8" }, + + {"MID":"f0a7041347444f3a822129120faf0fcd","_LINK":"7.2-Screenshots" }, + + {"MID":"45be72764a73440b8abf313bb84420aa","_LINK":"45be72764a73440b8abf313bb84420aa" }, + + {"MID":"2e8e39a2198e4f8aa18a470a892e4d25","_LINK":"8-Export-to-PDF" }, + + {"MID":"381ebcd10ee241aaaa9fe3654870961c","_LINK":"8.1-Definition" }, + + {"MID":"5be4f35be2eb49faae7c33b5a2d83251","UID":"SDOC-FEAT-10","_LINK":"SDOC-FEAT-10" }, + + {"MID":"2d8b04efe57d4c0aa543ed974ace868e","_LINK":"8.2-Screenshots" }, + + {"MID":"15d6e791674c4c0ab54afb6a781f35c9","_LINK":"9-Query-engine-and-search-screen" }, + + {"MID":"91177d3444d9437e87032875ac8fcd7d","_LINK":"9.1-Definition" }, + + {"MID":"9c1e6cb601294891bcaae2b8c9042c59","UID":"SDOC-FEAT-7","_LINK":"SDOC-FEAT-7" }, + + {"MID":"631f1620053342c8a398a1a5d458f873","_LINK":"9.2-Screenshots" }, + + {"MID":"64afc2abdab847439c0c18420db7ba47","_LINK":"64afc2abdab847439c0c18420db7ba47" }, + + {"MID":"3475f60f31b5488aab981fd2b7b12d4c","_LINK":"10-Project-statistics" }, + + {"MID":"9bbcc02a46194852b9616ea4437ce976","_LINK":"10.1-Definition" }, + + {"MID":"2dd0b514a24f43a287a4096d0be0af58","UID":"SDOC-FEAT-11","_LINK":"SDOC-FEAT-11" }, + + {"MID":"7d215ba517fc4aee9dfb381279297cc7","_LINK":"10.2-Screenshots" }, + + {"MID":"bd5a4763e2ca4df497dbaeeff9ffbd71","_LINK":"bd5a4763e2ca4df497dbaeeff9ffbd71" }, + + {"MID":"0b3d7fad0ee643ef83617745c51e8e72","_LINK":"11-Documentation-diff-changelog" }, + + {"MID":"9cdf4d3af1014aea923f77b112e6b1e3","_LINK":"11.1-Definition" }, + + {"MID":"e9da42f8e39b438a8e8eada16b280706","UID":"SDOC-FEAT-12","_LINK":"SDOC-FEAT-12" }, + + {"MID":"c60c6fab5740469aa251bfa3a805f21f","_LINK":"11.2-Screenshots" }, + + {"MID":"1fad67b63724450bb63738cf7e29d051","_LINK":"1fad67b63724450bb63738cf7e29d051" }, + + {"MID":"f655f9a2bde044489233fa03d2891de1","_LINK":"12-ReqIF-support" }, + + {"MID":"1627a126e1184c5e9050206f2f1ab725","_LINK":"12.1-Definition" }, + + {"MID":"2845463f977d4b51ac788c2fc9cbd894","UID":"SDOC-FEAT-13","_LINK":"SDOC-FEAT-13" }, + + {"MID":"e1109c5b3b1c4068a0eace811684f0c0","_LINK":"13-Project-configuration" }, + + {"MID":"3c2a1a37e11c425184042d6dab3f050a","_LINK":"13.1-Definition" }, + + {"MID":"8fc72d79bfe940aba2cf041e263b92df","UID":"SDOC-FEAT-9","_LINK":"SDOC-FEAT-9" }, + + {"MID":"275658296e5342acab72102589096f15","_LINK":"13.2-Screenshots" }, + + {"MID":"100daefc4121415989324de1978d1f59","_LINK":"100daefc4121415989324de1978d1f59" }, ], + "strictdoc/docs/strictdoc_03_faq.html": [ + + + {"MID":"a434bc71a7324efaaed7f5a58e56e544","UID":"SDOC_FAQ","_LINK":"SDOC_FAQ" }, + + {"MID":"5acdfccd5771492f95b70328bd599cf7","_LINK":"5acdfccd5771492f95b70328bd599cf7" }, + + {"MID":"e972c79015524961863e095280a81aab","_LINK":"1-What-is-StrictDoc" }, + + {"MID":"d8d92e4eb8254cbda8dcb37709a9df45","_LINK":"d8d92e4eb8254cbda8dcb37709a9df45" }, + + {"MID":"86827c92ec3a493d8a2382b75b5277a8","_LINK":"2-Resources-about-StrictDoc" }, + + {"MID":"f7083cf6a84e4b858b5e551f8c8a555a","_LINK":"2.1-Presentations" }, + + {"MID":"52342105083e4f80884959d4ca7f4dba","_LINK":"52342105083e4f80884959d4ca7f4dba" }, + + {"MID":"d22b63a405264a6a80d4ab3f9b2bf9c5","_LINK":"2.2-Blog-posts" }, + + {"MID":"b2f5aea77e504ee1b64a67be24bd3c58","_LINK":"b2f5aea77e504ee1b64a67be24bd3c58" }, + + {"MID":"d75bd4d35b4b425b90ec8667ffffe191","_LINK":"2.3-Screencasts-tutorials" }, + + {"MID":"9d23e77aa7f848cb8efca49f5cf41f77","_LINK":"9d23e77aa7f848cb8efca49f5cf41f77" }, + + {"MID":"74235945ec4a4116aecbc883ffba54b7","_LINK":"3-Which-web-server-is-recommended-for-StrictDoc-documentation" }, + + {"MID":"966a5c3babf84fc7a1454b2799d13470","_LINK":"966a5c3babf84fc7a1454b2799d13470" }, + + {"MID":"2e911dedb13348bf827f078bbbca44f4","_LINK":"4-Is-StrictDoc-compatible-with-Sphinx" }, + + {"MID":"ac35a712b4a84f4ab2b61feb15c1550d","_LINK":"ac35a712b4a84f4ab2b61feb15c1550d" }, + + {"MID":"235122d2c10748918c7c6ff736e39d18","UID":"SECTION-FAQ-How-did-the-SDoc-text-language-become-what-it-is","_LINK":"SECTION-FAQ-How-did-the-SDoc-text-language-become-what-it-is" }, + + {"MID":"b3561dd4f8e64f11a251c3471022aece","_LINK":"b3561dd4f8e64f11a251c3471022aece" }, + + {"MID":"1d4220cc9a5444a5bdbaee91c8c50670","_LINK":"6-How-StrictDoc-compares-to-other-tools" }, + + {"MID":"45093addf6ec4772a0289fd958ae61dc","_LINK":"45093addf6ec4772a0289fd958ae61dc" }, + + {"MID":"a4533ae81bfe446295242add9156198e","_LINK":"6.1-Doorstop" }, + + {"MID":"d0c305180d8747a1b70254eaf2c4f201","_LINK":"d0c305180d8747a1b70254eaf2c4f201" }, + + {"MID":"5012af516d18447caa3a2dbce97d3e4a","_LINK":"6.2-Sphinx" }, + + {"MID":"74b6be0dc2bb485987d8731348cdf5ce","_LINK":"74b6be0dc2bb485987d8731348cdf5ce" }, + + {"MID":"515bcae39d1f48eda0b72562871ab15a","_LINK":"6.3-Sphinx-Needs" }, + + {"MID":"602327a9b8654e1eab4bc265e172a63d","_LINK":"602327a9b8654e1eab4bc265e172a63d" }, + + {"MID":"4a77366154d74cf7ab34044bed1cd542","_LINK":"6.4-FRET" }, + + {"MID":"e3eb1be604c6499292339ecbe7620c60","_LINK":"e3eb1be604c6499292339ecbe7620c60" }, + + {"MID":"723731c256fc43dfb315a300f6429945","_LINK":"6.5-Other-tools" }, + + {"MID":"ad24dca8ed9c449ab76c1798f38eb37c","_LINK":"ad24dca8ed9c449ab76c1798f38eb37c" }, + + {"MID":"ff143a18e98144bd86e10e29616c187b","_LINK":"7-How-long-has-the-StrictDoc-project-been-around" }, + + {"MID":"47d60404cf574aebb8c83795589c4137","_LINK":"47d60404cf574aebb8c83795589c4137" }, + + {"MID":"6e5ed6bb36634220a0c583d21c96295f","_LINK":"8-Which-StrictDoc-statistics-are-available" }, + + {"MID":"730bfedff6b24c34a6d6331051fd76d3","_LINK":"730bfedff6b24c34a6d6331051fd76d3" }, ], + "strictdoc/docs/strictdoc_04_release_notes.html": [ + + + {"MID":"4277890572a94f49bda9f32a80e43c06","_LINK":"None-Release-Notes" }, + + {"MID":"0dd2649ec4784c9480eac6f4aef3158b","_LINK":"0dd2649ec4784c9480eac6f4aef3158b" }, + + {"MID":"27d526d90cda48dfa5cbf17df88299ba","_LINK":"1-0-12-1-2025-09-18" }, + + {"MID":"7433a733b3794983b5e17169897c3732","_LINK":"7433a733b3794983b5e17169897c3732" }, + + {"MID":"f2a70deaf8164240951fca48510d7aa4","_LINK":"2-0-12-0-2025-09-17" }, + + {"MID":"a7e0cee58f054a50818f07a02bab7230","_LINK":"a7e0cee58f054a50818f07a02bab7230" }, + + {"MID":"721b576103a748c8a63d3147ec771b95","_LINK":"3-0-11-3-2025-09-07" }, + + {"MID":"e60129ab582946319616595111296e76","_LINK":"e60129ab582946319616595111296e76" }, + + {"MID":"4bd05b9073254db38322102f4bbc5096","_LINK":"4-0-11-2-2025-09-02" }, + + {"MID":"7776a30d522b4b5f9a6e405d20241566","_LINK":"7776a30d522b4b5f9a6e405d20241566" }, + + {"MID":"3e3043021e034cb69dfd9b62eecadbb3","_LINK":"5-0-11-1-2025-09-01" }, + + {"MID":"9a4bbed442b94d72859d70d31282efc1","_LINK":"9a4bbed442b94d72859d70d31282efc1" }, + + {"MID":"f53df5a2e9674373a8f52f1a01b5010d","_LINK":"6-0-11-0-2025-08-26" }, + + {"MID":"177963dca83748d89bfaeb01b3d663a8","_LINK":"177963dca83748d89bfaeb01b3d663a8" }, + + {"MID":"a5ab8dd5bc4045e99299eff729e430e6","_LINK":"7-0-10-1-2025-07-25" }, + + {"MID":"6d0bb97e7ef74fc1ae93cf2a91480e6a","_LINK":"6d0bb97e7ef74fc1ae93cf2a91480e6a" }, + + {"MID":"447ab1fa1d38453ab46e0002e6eb852d","_LINK":"8-0-10-0-2025-07-20" }, + + {"MID":"c536381cea6842f0b77c1aa5ac942ce0","_LINK":"c536381cea6842f0b77c1aa5ac942ce0" }, + + {"MID":"aa45a90bad3f4273ab46dade039ef4c6","_LINK":"9-0-9-4-2025-07-12" }, + + {"MID":"a25dd134646e462ca09e850481bccb2b","_LINK":"a25dd134646e462ca09e850481bccb2b" }, + + {"MID":"eca2ad204c8246a8b0f29a5eb8d7f799","_LINK":"10-0-9-3-2025-07-03" }, + + {"MID":"64706a3d4d9c4beda3597ffa9d92921a","_LINK":"64706a3d4d9c4beda3597ffa9d92921a" }, + + {"MID":"6665c867a01f49f59968ae83d2e928fe","_LINK":"11-0-9-2-2025-06-28" }, + + {"MID":"d56dfede85b84e07bd5ecddc82a576fc","_LINK":"d56dfede85b84e07bd5ecddc82a576fc" }, + + {"MID":"a5ab3ca7210f4c18a465e7686e71c15f","_LINK":"12-0-9-1-2025-06-14" }, + + {"MID":"fbf2c4dcf8154779b3ac914d9ff335c4","_LINK":"fbf2c4dcf8154779b3ac914d9ff335c4" }, + + {"MID":"71b0ec45b5644c5083085c83ef6be95e","_LINK":"13-0-9-0-2025-06-10" }, + + {"MID":"72d1a7e4b54d44e38778d87c74075dc8","_LINK":"72d1a7e4b54d44e38778d87c74075dc8" }, + + {"MID":"d64fb5003399496bbb18ffb6e05efaf4","_LINK":"14-0-8-0-2025-04-13" }, + + {"MID":"a7bd074d2dcd40a6af106e91720d90d3","_LINK":"a7bd074d2dcd40a6af106e91720d90d3" }, + + {"MID":"58b99c15df8445ce9832e24a17588e2c","_LINK":"15-0-7-0-2025-03-03" }, + + {"MID":"c5725f24fcd24d54929e155f6ad47b44","_LINK":"c5725f24fcd24d54929e155f6ad47b44" }, + + {"MID":"ff59e375101145b3bf12465ce2b5fc14","_LINK":"16-0-6-0-2025-02-16" }, + + {"MID":"3ddfc6462bec45b2ac69a1799293c7da","_LINK":"3ddfc6462bec45b2ac69a1799293c7da" }, + + {"MID":"d9e164994bb941ada8aecc73000bd51d","_LINK":"17-0-5-0-2025-01-06" }, + + {"MID":"d0d93f5eb37247079cc182e924dabd14","_LINK":"d0d93f5eb37247079cc182e924dabd14" }, + + {"MID":"e7df8274f42c4e01b02ad840e6b2569c","_LINK":"18-0-4-0-2024-12-25" }, + + {"MID":"f4e63483a11b442993c47b5d0574e89b","_LINK":"f4e63483a11b442993c47b5d0574e89b" }, + + {"MID":"591c1b85c6fb4453aee08e23cb9f257a","_LINK":"19-0-3-0-2024-11-21" }, + + {"MID":"b39a3b3d9f8640e380dad5a2fdb75d79","_LINK":"b39a3b3d9f8640e380dad5a2fdb75d79" }, + + {"MID":"f4cd860f07b1479ba1845bce3c749d68","_LINK":"20-0-2-1-2024-11-10" }, + + {"MID":"26043bba142a4e739dd206e229829202","_LINK":"26043bba142a4e739dd206e229829202" }, + + {"MID":"f76d863243b5410788e457b9c3bf1d2b","_LINK":"21-0-2-0-2024-11-04" }, + + {"MID":"611e8df13d464fd1b22e5026cf3ce531","_LINK":"611e8df13d464fd1b22e5026cf3ce531" }, + + {"MID":"83878b68483f4da2930bfb3712c08aa3","_LINK":"22-0-1-0-2024-11-01" }, + + {"MID":"e37e230c932448798bd9978d4f27f32c","_LINK":"e37e230c932448798bd9978d4f27f32c" }, + + {"MID":"771fb5350bf840e4b30485fe9e8d9452","_LINK":"23-0-0-60-2024-10-26" }, + + {"MID":"65daf4400b464021ba3cb7a06061e651","_LINK":"65daf4400b464021ba3cb7a06061e651" }, + + {"MID":"4538fe1994bc4730b7febe3dc624f704","_LINK":"24-0-0-59-2024-10-13" }, + + {"MID":"e9d5e3f8f6b04647afb95bae6b2f503a","_LINK":"e9d5e3f8f6b04647afb95bae6b2f503a" }, + + {"MID":"306a619f550f4be18db6dbb987df3248","_LINK":"25-0-0-58-2024-06-25" }, + + {"MID":"fd7f4d5b58e54f64aa43349684a675c4","_LINK":"fd7f4d5b58e54f64aa43349684a675c4" }, + + {"MID":"0795627e25e343f3b1b476b673a543ab","_LINK":"26-0-0-57-2024-06-23" }, + + {"MID":"f99185cb69cf47d4bc6e1bd404b67467","_LINK":"f99185cb69cf47d4bc6e1bd404b67467" }, + + {"MID":"cd994052a0354410a550858a1f25d426","_LINK":"27-0-0-56-2024-06-02" }, + + {"MID":"61f17be85ac442a0b70003825d671ced","_LINK":"61f17be85ac442a0b70003825d671ced" }, + + {"MID":"938f1a0fdcc94c5aaa87ddb18b880afe","_LINK":"28-0-0-55-2024-04-28" }, + + {"MID":"00abb07e55534a75a8cfd50d8cfc5732","_LINK":"00abb07e55534a75a8cfd50d8cfc5732" }, + + {"MID":"055ee004b28647629eead8165f198579","_LINK":"29-0-0-54-2024-04-17" }, + + {"MID":"e5bf489ac0684ea4b626574b5439c7dd","_LINK":"e5bf489ac0684ea4b626574b5439c7dd" }, + + {"MID":"87b7b54fa4024959bdcb42ded18f77f2","_LINK":"30-0-0-53-2024-04-01" }, + + {"MID":"2ac296f6326b4481beb7d67b95dbb23c","_LINK":"2ac296f6326b4481beb7d67b95dbb23c" }, + + {"MID":"36a70af62b3e4a5d8bf08d9345fda095","_LINK":"31-0-0-52-2024-03-25" }, + + {"MID":"72d6e38e89cc471b8d3f46ae5654e0e6","_LINK":"72d6e38e89cc471b8d3f46ae5654e0e6" }, + + {"MID":"6c72f8654ea1401ea2a6e4ab82cf76e4","_LINK":"32-0-0-51-2024-03-20" }, + + {"MID":"e81c4206bcb148979762ee3f2aa5c9ba","_LINK":"e81c4206bcb148979762ee3f2aa5c9ba" }, + + {"MID":"413952c14412434fb237c3e909101707","_LINK":"33-0-0-50-2024-03-19" }, + + {"MID":"a9d7c449d1a7400496504926c744e500","_LINK":"a9d7c449d1a7400496504926c744e500" }, + + {"MID":"3a03dd169ffb4fe0b64f48b365a77d2e","_LINK":"34-0-0-49-2024-03-11" }, + + {"MID":"0b8c8f40923744b089845afeb44223e9","_LINK":"0b8c8f40923744b089845afeb44223e9" }, + + {"MID":"a7ed1eaf155d4f588b27ba31ecc88d4d","_LINK":"35-0-0-48-2024-01-24" }, + + {"MID":"6cff333594d6430886053b59b265e806","_LINK":"6cff333594d6430886053b59b265e806" }, + + {"MID":"7a3620eecd1b4bd1a8eba7a373f14723","_LINK":"36-0-0-47-2023-11-20" }, + + {"MID":"c422af340d5b45c48bfe89130e1bba52","_LINK":"c422af340d5b45c48bfe89130e1bba52" }, ], + "strictdoc/docs/strictdoc_05_troubleshooting.html": [ + + + {"MID":"5680165c90f44903b3b1dc1013b8cb59","UID":"SDOC_TROUBLESHOOTING","_LINK":"SDOC_TROUBLESHOOTING" }, + + {"MID":"7e3481d51ad14767b5c97132cad2e0a6","_LINK":"7e3481d51ad14767b5c97132cad2e0a6" }, + + {"MID":"17152ac7de9f4c138b85e2956091206f","_LINK":"1-Caching-issues" }, + + {"MID":"9a32ac13510d401cbc1a608259652c78","_LINK":"9a32ac13510d401cbc1a608259652c78" }, ], + "strictdoc/docs/strictdoc_10_contributing.html": [ + + + {"MID":"1739e662499648d38c210a8aafbb3361","_LINK":"None-Contributing-to-StrictDoc" }, + + {"MID":"13fe652f160d4af69e869c28a155437d","_LINK":"13fe652f160d4af69e869c28a155437d" }, + + {"MID":"ec078ab0d7564738acd2961f72abb2c9","_LINK":"1-Contributor-checklist" }, + + {"MID":"ae0fc6d87b114137ab6da7c9b5647b62","_LINK":"ae0fc6d87b114137ab6da7c9b5647b62" }, + + {"MID":"8b40cc35f3524bc7b4e444321c080837","_LINK":"2-How-can-I-help" }, + + {"MID":"8e346888911649f2a3aaf49763aaef24","_LINK":"2.1-Spread-the-word" }, + + {"MID":"07462b02027a423a85ab68525b78ac67","_LINK":"07462b02027a423a85ab68525b78ac67" }, + + {"MID":"2696c7fda6d440f3a290f202bee08fe6","_LINK":"2.2-ReqIF-users" }, + + {"MID":"9cfbb025525f41c5a195be0e637dffee","_LINK":"9cfbb025525f41c5a195be0e637dffee" }, + + {"MID":"4e1edb97346c43af952c4e74f9defbe8","_LINK":"2.3-TeX-LaTeX-Sphinx-experts" }, + + {"MID":"75ed9362d86748269f62f5920514b7c2","_LINK":"75ed9362d86748269f62f5920514b7c2" }, ], + "strictdoc/docs/strictdoc_11_developer_guide.html": [ + + + {"MID":"4f05169346ab4001b6ff19e8349e8fa7","_LINK":"None-Developer-Guide" }, + + {"MID":"f174b0cdec6b482daa2878c8cc0d02c3","_LINK":"f174b0cdec6b482daa2878c8cc0d02c3" }, + + {"MID":"c069e4c7b4d04dd09eb73f940e947bfd","UID":"DEVGUIDE_GETTING_STARTED","_LINK":"DEVGUIDE_GETTING_STARTED" }, + + {"MID":"7477d397d0ca493f8e47532455d44965","_LINK":"1.1-System-dependencies" }, + + {"MID":"df2e1de12c6b456898c48a36650813d4","_LINK":"df2e1de12c6b456898c48a36650813d4" }, + + {"MID":"b7a21564c30043acbf1733d9b47bd0bc","_LINK":"1.1.1-Windows-specific-Long-Path-support" }, + + {"MID":"8591cf6dece04244824c3ac2a8666ba3","_LINK":"8591cf6dece04244824c3ac2a8666ba3" }, + + {"MID":"89ec30b9f67c489da635be391b0b0e15","_LINK":"1.2-Installing-StrictDoc-from-GitHub-developer-mode" }, + + {"MID":"2407bb186b274a58b97b54b99ba6e86f","_LINK":"2407bb186b274a58b97b54b99ba6e86f" }, + + {"MID":"1814a8c25afc40cba6dca1696cae119b","_LINK":"1.2.1-Development-within-a-virtual-environment" }, + + {"MID":"a3e14b05452b48e2a0d8726fa00a7f00","_LINK":"a3e14b05452b48e2a0d8726fa00a7f00" }, + + {"MID":"90d5d79146e64660a71cd74ac23f6811","_LINK":"2-Invoke-for-development-tasks" }, + + {"MID":"452b3c24463446a497ed6b8fcdb31fef","_LINK":"452b3c24463446a497ed6b8fcdb31fef" }, + + {"MID":"e7ce6a2f13614974b43aba56f6ae7253","_LINK":"3-Main-Check-task" }, + + {"MID":"09258e99cabb4455904b0e2c6687d492","_LINK":"09258e99cabb4455904b0e2c6687d492" }, + + {"MID":"07d9a3c17be8475089844f5eb2cd8299","UID":"DEVGUIDE_PYTHON_CODE","_LINK":"DEVGUIDE_PYTHON_CODE" }, + + {"MID":"3012a69ef5d244d49fcb90c088d4523b","_LINK":"3012a69ef5d244d49fcb90c088d4523b" }, + + {"MID":"6e9707c99199464583f091056d1ae458","UID":"DEVGUIDE_GIT_WORKFLOW","_LINK":"DEVGUIDE_GIT_WORKFLOW" }, + + {"MID":"0e916453596b460b84a89f722354a825","_LINK":"0e916453596b460b84a89f722354a825" }, + + {"MID":"2420b2d7a4624bd99b0f8088dfa9abff","_LINK":"6-Frontend-development" }, + + {"MID":"d818aad87db54985b8933f98528808ab","_LINK":"d818aad87db54985b8933f98528808ab" }, + + {"MID":"73c717608cce4abca2c768f1dbfb705d","_LINK":"7-Running-End-to-End-Web-tests" }, + + {"MID":"da3cbcd69b0545988daeb0f42098830d","_LINK":"da3cbcd69b0545988daeb0f42098830d" }, + + {"MID":"240dc1426d994397ac1401834b4f0ef0","_LINK":"8-Running-integration-tests" }, + + {"MID":"4e307b3b950840bbbe455c1ae3238a6e","_LINK":"4e307b3b950840bbbe455c1ae3238a6e" }, + + {"MID":"7b4bf839b1c44b0d82001060596d8cbf","_LINK":"9-Documentation" }, + + {"MID":"d1f5fde86ebc4103bc4eb0334b1ec919","_LINK":"d1f5fde86ebc4103bc4eb0334b1ec919" }, + + {"MID":"a44e3b99323b4ac291f4b4d3948c3cc0","_LINK":"10-Conventions" }, + + {"MID":"49b7349a3bee478cbe81d8ef25f6245c","_LINK":"49b7349a3bee478cbe81d8ef25f6245c" }, ], + "strictdoc/docs/strictdoc_20_L1_Open_Requirements_Tool.html": [ + + + {"MID":"b7bcca934cd148c3855beb4c85723bc5","_LINK":"None-Requirements-Tool-Specification-L1" }, + + {"MID":"c455f0297eb648c6aa9c6d239f043e0d","_LINK":"c455f0297eb648c6aa9c6d239f043e0d" }, + + {"MID":"668d18a7489043b38dd435933319e8e7","_LINK":"1-Summary-of-user-needs" }, + + {"MID":"7a94c3f55e32498187603400923bfae4","_LINK":"7a94c3f55e32498187603400923bfae4" }, + + {"MID":"1cbe275272994922a942fd088fa969d8","_LINK":"1.1-Free-and-open-source-tool" }, + + {"MID":"3ca29d12a7804f089f5b2aa955e4da59","_LINK":"3ca29d12a7804f089f5b2aa955e4da59" }, + + {"MID":"18136bcb9a5b4226a7a95d27dae49805","_LINK":"1.2-Document-types" }, + + {"MID":"14383453f84747d3abdce6b5dce50c7f","_LINK":"14383453f84747d3abdce6b5dce50c7f" }, + + {"MID":"973b586b8a89411ab4f083fd4c262cf5","UID":"SECTION-RTC-Appendix-A-Document-archetypes","_LINK":"SECTION-RTC-Appendix-A-Document-archetypes" }, + + {"MID":"4a847b9a58444e4a9be056db1f23272c","_LINK":"4a847b9a58444e4a9be056db1f23272c" }, + + {"MID":"52b6175f03d7495a9fa8dbffa36aeff4","UID":"SECTION-LRTS-Workflows","_LINK":"SECTION-LRTS-Workflows" }, + + {"MID":"c537b8fa5b54417eb9dff6478553f6d7","_LINK":"c537b8fa5b54417eb9dff6478553f6d7" }, + + {"MID":"08d547a3b04d485ca1f5a3a94a664ee1","_LINK":"1.4-Target-audience" }, + + {"MID":"847eaab505124e7797bd25c865f9d868","_LINK":"847eaab505124e7797bd25c865f9d868" }, + + {"MID":"f1ffdc7f78134d4b98f3c90e9be40cc7","UID":"SECTION-RTS-Documentation-management","_LINK":"SECTION-RTS-Documentation-management" }, + + {"MID":"0cacb010f5164118adce5dd8512c3e27","_LINK":"0cacb010f5164118adce5dd8512c3e27" }, + + {"MID":"72d0dd23dedd4907b4a8924debe7343b","UID":"SDOC-SSS-3","_LINK":"SDOC-SSS-3" }, + + {"MID":"9841bc9a56d740dd9e7988e52339618c","UID":"SDOC-SSS-91","_LINK":"SDOC-SSS-91" }, + + {"MID":"c4de5f1f46f343b6b4e8dc2a6121b0a2","UID":"SDOC-SSS-51","_LINK":"SDOC-SSS-51" }, + + {"MID":"5236f36f278140539e347bacea921118","UID":"SDOC-SSS-52","_LINK":"SDOC-SSS-52" }, + + {"MID":"8aeecdfa139341588d6ab8c0c3606a9b","UID":"SDOC-SSS-53","_LINK":"SDOC-SSS-53" }, + + {"MID":"d1883b65e17442c0a22987d4ad415cb6","UID":"SDOC-SSS-75","_LINK":"SDOC-SSS-75" }, + + {"MID":"b8d7b22fd8a6478a9a21ecaa60cf0028","UID":"SDOC-SSS-63","_LINK":"SDOC-SSS-63" }, + + {"MID":"3bb5252d75bc486b98e7606fb642bac0","UID":"SDOC-SSS-95","_LINK":"SDOC-SSS-95" }, + + {"MID":"fd227b9cfdc54d7db3134cdb925bde87","UID":"SECTION-RTS-Requirements-management","_LINK":"SECTION-RTS-Requirements-management" }, + + {"MID":"c1e2431cdf2141ca86931f29b9912ff7","_LINK":"c1e2431cdf2141ca86931f29b9912ff7" }, + + {"MID":"6e6f1464c47f4ced8e14c4153f40618b","UID":"SDOC-SSS-4","_LINK":"SDOC-SSS-4" }, + + {"MID":"db42ad4b504e48e0bf51b4d82529a888","UID":"SDOC-SSS-61","_LINK":"SDOC-SSS-61" }, + + {"MID":"a69bae43b3224dfc8439a88451a98395","UID":"SDOC-SSS-62","_LINK":"SDOC-SSS-62" }, + + {"MID":"5f89bdaa6cb74e2a8b9b030b6237b7ef","UID":"SDOC-SSS-64","_LINK":"SDOC-SSS-64" }, + + {"MID":"65575cc8a87e4d4480ccdf89d1fb6d67","UID":"SDOC-SSS-5","_LINK":"SDOC-SSS-5" }, + + {"MID":"06ab121d3c0f4d8c94652323b8f735c6","UID":"SDOC-SSS-70","_LINK":"SDOC-SSS-70" }, + + {"MID":"637c129a91804d8cbe2280c1af14836d","UID":"SDOC-SSS-6","_LINK":"SDOC-SSS-6" }, + + {"MID":"1ce495a5194044d4a7a3dd030f766c9f","UID":"SDOC-SSS-7","_LINK":"SDOC-SSS-7" }, + + {"MID":"44b9d75e50c84d6c8424cfb8a42a0771","UID":"SDOC-SSS-8","_LINK":"SDOC-SSS-8" }, + + {"MID":"387bd5ff0e4a4a97962661e9d7451f19","UID":"SDOC-SSS-71","_LINK":"SDOC-SSS-71" }, + + {"MID":"3348caaed8d44be0928cc6f3c7414094","UID":"SDOC-SSS-89","_LINK":"SDOC-SSS-89" }, + + {"MID":"3850f0b8c8294455bf7be9e2acddbd40","UID":"SDOC-SSS-47","_LINK":"SDOC-SSS-47" }, + + {"MID":"1216cb617c0f495a9c96471ef72bf80f","UID":"SDOC-SSS-57","_LINK":"SDOC-SSS-57" }, + + {"MID":"7c112f3a5885477084396fd26387a864","_LINK":"4-Tool-configurability" }, + + {"MID":"4550038552894ef69b85b281cff60c60","UID":"SDOC-SSS-92","_LINK":"SDOC-SSS-92" }, + + {"MID":"4550b38552894ef69b85b281cff60360","UID":"SDOC-SSS-93","_LINK":"SDOC-SSS-93" }, + + {"MID":"56dabce670be4691b35434bda6d6bb36","UID":"SECTION-SSSS-Performance","_LINK":"SECTION-SSSS-Performance" }, + + {"MID":"68e4b4b1ba78485f8620575ef9e1eaa2","_LINK":"68e4b4b1ba78485f8620575ef9e1eaa2" }, + + {"MID":"a0a95079e3c0438bb3ea9e5af7ddddc9","UID":"SDOC-SSS-13","_LINK":"SDOC-SSS-13" }, + + {"MID":"64b982c9299a4c8eb7031495e940a3f8","UID":"SDOC-SSS-14","_LINK":"SDOC-SSS-14" }, + + {"MID":"d1a483f3e321414b83bb4a39b1283293","_LINK":"6-Data-integrity" }, + + {"MID":"d1323d222a0040b2b6122c59b3c00f06","UID":"SDOC-SSS-94","_LINK":"SDOC-SSS-94" }, + + {"MID":"ec52fa5cc1714b07863eb7da9432be1d","UID":"SECTION-SSSS-Existing-workflows","_LINK":"SECTION-SSSS-Existing-workflows" }, + + {"MID":"33769a5f0ca94b99a4802adc81841037","_LINK":"33769a5f0ca94b99a4802adc81841037" }, + + {"MID":"831debedfa0e4e4c8434021569f96bad","UID":"SDOC-SSS-73","_LINK":"SDOC-SSS-73" }, + + {"MID":"5d412989005e4bc3b5dcfd94675615dc","UID":"SDOC-SSS-56","_LINK":"SDOC-SSS-56" }, + + {"MID":"5eb553abd3944bffbd003e37b3d1c5a5","UID":"SDOC-SSS-28","_LINK":"SDOC-SSS-28" }, + + {"MID":"06f0bb40f76142f4ba59d037aaedc9de","UID":"SDOC-SSS-48","_LINK":"SDOC-SSS-48" }, + + {"MID":"74ffae6279bc4e4095c03d6a247c3599","UID":"SDOC-SSS-29","_LINK":"SDOC-SSS-29" }, + + {"MID":"e0e6d1f883764719919238e4974dccef","UID":"SDOC-SSS-49","_LINK":"SDOC-SSS-49" }, + + {"MID":"ed4bd232bed84eda977263fa03e75b80","UID":"SDOC-SSS-74","_LINK":"SDOC-SSS-74" }, + + {"MID":"85d2f75b2f074f98ace5ceb5288c09b9","UID":"SECTION-RTC-Usability-installation-and-usage","_LINK":"SECTION-RTC-Usability-installation-and-usage" }, + + {"MID":"7e33387f373d427d9e1af522f1e5bbc5","UID":"SDOC-SSS-79","_LINK":"SDOC-SSS-79" }, + + {"MID":"57b01915e4624634909dbb40f5d56697","UID":"SDOC-SSS-80","_LINK":"SDOC-SSS-80" }, + + {"MID":"d3e66072363d4e7ea2e2f9691c094bb2","UID":"SDOC-SSS-81","_LINK":"SDOC-SSS-81" }, + + {"MID":"db495bc2f11f4f96ace60cdb0bef4d66","UID":"SDOC-SSS-82","_LINK":"SDOC-SSS-82" }, + + {"MID":"90562d92b9a7468ba42567bc72cb6ebf","UID":"SDOC-SSS-83","_LINK":"SDOC-SSS-83" }, + + {"MID":"4312ed066d19487eba18ec677430e60f","UID":"SDOC-SSS-84","_LINK":"SDOC-SSS-84" }, + + {"MID":"81858dda65844dcd9640fdd74badecee","UID":"SDOC-SSS-85","_LINK":"SDOC-SSS-85" }, + + {"MID":"ee96cc5f18e14f6894e2775c546240d8","UID":"SDOC-SSS-86","_LINK":"SDOC-SSS-86" }, + + {"MID":"f4b122c5081f4b218aa93a119e372a34","UID":"SDOC-SSS-87","_LINK":"SDOC-SSS-87" }, + + {"MID":"29fa83c59e714d0da8b36a9dc65b0c72","UID":"SECTION-SSSS-Implementation-suggestions","_LINK":"SECTION-SSSS-Implementation-suggestions" }, + + {"MID":"3db06eb066b4441290e06b08405da0a9","UID":"SDOC-SSS-30","_LINK":"SDOC-SSS-30" }, + + {"MID":"e718af582b0345c2b0ddb6e405cb6d9a","UID":"SDOC-SSS-31","_LINK":"SDOC-SSS-31" }, + + {"MID":"cd20e9613a65441a8862143ba6407f61","UID":"SDOC-SSS-32","_LINK":"SDOC-SSS-32" }, + + {"MID":"4475857729e5476cbbb409cc844048fd","UID":"SDOC-SSS-68","_LINK":"SDOC-SSS-68" }, + + {"MID":"5ac2f3010db84466bff854fc323e944c","UID":"SDOC-SSS-33","_LINK":"SDOC-SSS-33" }, + + {"MID":"b76fb774542849a182e2cdd89fdaab3c","UID":"SDOC-SSS-67","_LINK":"SDOC-SSS-67" }, + + {"MID":"871a7a66eb50436997fde692e90e93eb","UID":"SDOC-SSS-69","_LINK":"SDOC-SSS-69" }, + + {"MID":"0556a0b2773d4ee0b44b22773455a600","UID":"SDOC-SSS-90","_LINK":"SDOC-SSS-90" }, + + {"MID":"7bdea1a7cb9e4f6fbcf8497670f87278","UID":"SECTION-RTS-Text-based-requirements-language","_LINK":"SECTION-RTS-Text-based-requirements-language" }, + + {"MID":"dfe5a61ed10149bebcf69d9c5c3b1316","_LINK":"dfe5a61ed10149bebcf69d9c5c3b1316" }, + + {"MID":"f472e85f3398413795234a9298d4af3c","UID":"SDOC-SSS-88","_LINK":"SDOC-SSS-88" }, + + {"MID":"b13bc3dfa7324f238bc06a88baf5edb6","UID":"SDOC-SSS-55","_LINK":"SDOC-SSS-55" }, + + {"MID":"0b47da74f9ec45e6a77573185b95f327","UID":"SDOC-SSS-54","_LINK":"SDOC-SSS-54" }, + + {"MID":"13f3e7765b494237893c1585a7c9dfd0","UID":"SDOC-SSS-34","_LINK":"SDOC-SSS-34" }, + + {"MID":"8b1da9907bc847c989dc807b7dff2a05","UID":"SECTION-RTS-Requirements-and-source-code","_LINK":"SECTION-RTS-Requirements-and-source-code" }, + + {"MID":"4692362c77974fb8bcbeefdc248d0e89","UID":"SDOC-SSS-72","_LINK":"SDOC-SSS-72" }, + + {"MID":"cd9e353e07ae4d50b1aa08999854aa02","UID":"SECTION-RTS-Requirements-exchange-formats-export-import","_LINK":"SECTION-RTS-Requirements-exchange-formats-export-import" }, + + {"MID":"ecc76e0991e44d6282776365496193e6","_LINK":"ecc76e0991e44d6282776365496193e6" }, + + {"MID":"73e70548c2cf415f94adbf1066d5fe4b","UID":"SDOC-SSS-58","_LINK":"SDOC-SSS-58" }, + + {"MID":"c94de32c2c2e454d81c77724a4f29283","UID":"SDOC-SSS-59","_LINK":"SDOC-SSS-59" }, + + {"MID":"f7a600a238e34075ac6b65852492cc2f","UID":"SDOC-SSS-60","_LINK":"SDOC-SSS-60" }, + + {"MID":"efaa3e91045c4d49a70232f09a85ad35","UID":"SECTION-RTS-Requirements-collaboration","_LINK":"SECTION-RTS-Requirements-collaboration" }, + + {"MID":"f9d65df46ff24b0da6cb2bf011f0fc70","UID":"SDOC-SSS-65","_LINK":"SDOC-SSS-65" }, + + {"MID":"29d0374556494f38977ec3c928aa894d","UID":"SDOC-SSS-66","_LINK":"SDOC-SSS-66" }, + + {"MID":"f80a4b7ff03042849c3814c6cd5e5ca4","UID":"SECTION-SSSS-Development-process","_LINK":"SECTION-SSSS-Development-process" }, + + {"MID":"f16ea50f686e412f9c21d8096055bb47","UID":"SDOC-SSS-76","_LINK":"SDOC-SSS-76" }, + + {"MID":"0bebdf77108a499c87e5c0838204c39c","UID":"SDOC-SSS-50","_LINK":"SDOC-SSS-50" }, + + {"MID":"1a39a758930040029db320d8466806c1","UID":"SDOC-SSS-77","_LINK":"SDOC-SSS-77" }, + + {"MID":"8cb5ac6812924f4c8f4afd156b2f021c","UID":"SDOC-SSS-78","_LINK":"SDOC-SSS-78" }, + + {"MID":"e4cd429e9ec04deabfd1fb1381c39e38","UID":"SECTION-SSSS-Licensing-and-distribution","_LINK":"SECTION-SSSS-Licensing-and-distribution" }, + + {"MID":"92bf658bcddb4d2899b78c526fbddf38","_LINK":"92bf658bcddb4d2899b78c526fbddf38" }, + + {"MID":"2f30b94fdc074c8fa5858dfccc6202e8","UID":"SDOC-SSS-38","_LINK":"SDOC-SSS-38" }, + + {"MID":"27b640de8cae44a680b23429c981bee9","UID":"SDOC-SSS-39","_LINK":"SDOC-SSS-39" }, + + {"MID":"1338faad11204073a97212fa0fd11317","UID":"SDOC-SSS-40","_LINK":"SDOC-SSS-40" }, ], + "strictdoc/docs/strictdoc_21_L2_StrictDoc_Requirements.html": [ + + + {"MID":"8a87daf19a7c487f89f396406a974509","_LINK":"None-StrictDoc-Requirements-Specification-L2" }, + + {"MID":"bd8a7931c1e04df9bf08d291488c67aa","_LINK":"1-SDoc-data-model" }, + + {"MID":"e8d5b55055254144b96d1ffeb587ec72","UID":"SDOC-SRS-18","_LINK":"SDOC-SRS-18" }, + + {"MID":"3b31cad22529476db01aca41caf39750","UID":"SDOC-SRS-26","_LINK":"SDOC-SRS-26" }, + + {"MID":"8e2ffffd33af4a969d5bb7ca40cb49a4","UID":"SDOC-SRS-100","_LINK":"SDOC-SRS-100" }, + + {"MID":"2d4020ba06d74571aef7aafe8604215b","UID":"SDOC-SRS-132","_LINK":"SDOC-SRS-132" }, + + {"MID":"f94419a390f2403daa3c4cd0e96f6cb6","UID":"SDOC-SRS-98","_LINK":"SDOC-SRS-98" }, + + {"MID":"435f856197d743c1b9b1dcbe91a22863","UID":"SDOC-SRS-110","_LINK":"SDOC-SRS-110" }, + + {"MID":"abcced8724d743c1b9b1dcbe91a22863","UID":"SDOC-SRS-151","_LINK":"SDOC-SRS-151" }, + + {"MID":"63821c507d584cf985f05904710b9779","UID":"SDOC-SRS-99","_LINK":"SDOC-SRS-99" }, + + {"MID":"899d2f68749b4be1a3124fe4d01de1aa","UID":"SDOC-SRS-135","_LINK":"SDOC-SRS-135" }, + + {"MID":"983653fc26214f46977dc792d65ae65f","UID":"SDOC-SRS-109","_LINK":"SDOC-SRS-109" }, + + {"MID":"fad4cf5dcf4d40518c7c9826fd6bd18a","UID":"SDOC-SRS-31","_LINK":"SDOC-SRS-31" }, + + {"MID":"9930894b08c44f5eba996c0a255e9e3f","UID":"SDOC-SRS-101","_LINK":"SDOC-SRS-101" }, + + {"MID":"fa090bc6976c4275aadbf522da6b920b","UID":"SDOC-SRS-149","_LINK":"SDOC-SRS-149" }, + + {"MID":"54132bc6976c4275aadbf522da6b920b","UID":"SDOC-SRS-150","_LINK":"SDOC-SRS-150" }, + + {"MID":"cbc7f72c6e0b4c858817bf17357105a5","_LINK":"2-SDoc-text-markup" }, + + {"MID":"27a6da48c65445539e536ee034921fb5","UID":"SDOC-SRS-20","_LINK":"SDOC-SRS-20" }, + + {"MID":"1f147feed60245378de2e099facd196d","UID":"SDOC-SRS-136","_LINK":"SDOC-SRS-136" }, + + {"MID":"f48a57c0cd764951a667127ce92fdb12","UID":"SDOC-SRS-127","_LINK":"SDOC-SRS-127" }, + + {"MID":"9df34a7ab79842d99ee68303f334d4eb","UID":"SDOC-SRS-104","_LINK":"SDOC-SRS-104" }, + + {"MID":"8dd6dd3979484dadbe71ac91aab50608","UID":"SDOC-SRS-105","_LINK":"SDOC-SRS-105" }, + + {"MID":"e5e3033c13f24fa083423230da7994f7","UID":"SDOC-SRS-19","_LINK":"SDOC-SRS-19" }, + + {"MID":"b97418ceccff438cb0457ed4bdf1be47","UID":"SDOC-SRS-93","_LINK":"SDOC-SRS-93" }, + + {"MID":"8924c29136944f65ac5efc8b6b90a07b","UID":"SDOC-SRS-21","_LINK":"SDOC-SRS-21" }, + + {"MID":"10d23bfbf4504c2e8c995ae89c500be4","UID":"SDOC-SRS-122","_LINK":"SDOC-SRS-122" }, + + {"MID":"5405c74a9eba4e9193007f01ea98bc85","UID":"SDOC-SRS-22","_LINK":"SDOC-SRS-22" }, + + {"MID":"f871dfc381354daf820cc1e2b94fdb05","UID":"SDOC-SRS-24","_LINK":"SDOC-SRS-24" }, + + {"MID":"b1b4f03d4e404a14be481626803fcfc2","UID":"SDOC-SRS-27","_LINK":"SDOC-SRS-27" }, + + {"MID":"39f117b79cfa4a8485c458280b3d36ce","UID":"SDOC-SRS-23","_LINK":"SDOC-SRS-23" }, + + {"MID":"98628e1db3ca4f52b7632674b69dd657","UID":"SDOC-SRS-25","_LINK":"SDOC-SRS-25" }, + + {"MID":"34b4abc6bb4649de9e56af31c229b0d1","UID":"SECTION-SRS-Graph-database","_LINK":"SECTION-SRS-Graph-database" }, + + {"MID":"2c8d7940a23c443f81a7eb373340894e","UID":"SDOC-SRS-28","_LINK":"SDOC-SRS-28" }, + + {"MID":"272b8933276d4cd48a78fcfa11899573","UID":"SDOC-SRS-29","_LINK":"SDOC-SRS-29" }, + + {"MID":"8330d61fd5b1438fa90f127f88903a0d","UID":"SDOC-SRS-30","_LINK":"SDOC-SRS-30" }, + + {"MID":"07a1e7bef11d4fcca86cd31ee5245d8d","UID":"SDOC-SRS-32","_LINK":"SDOC-SRS-32" }, + + {"MID":"2dad5f293bc442eaa98859c4b5eac0d5","UID":"SDOC-SRS-102","_LINK":"SDOC-SRS-102" }, + + {"MID":"4dce611287954289b1c2a6a15c413611","_LINK":"4-Documentation-tree" }, + + {"MID":"50b2d5d6eb1140f0a2b980203468a5f7","UID":"SDOC-SRS-115","_LINK":"SDOC-SRS-115" }, + + {"MID":"fcbf717009ce4cb2a8def7eb7b377654","UID":"SECTION-SRS-Web-HTML-frontend","_LINK":"SECTION-SRS-Web-HTML-frontend" }, + + {"MID":"a3603184d571449792f5cd752c978686","UID":"SECTION-SRS-General-export-requirements-2","_LINK":"SECTION-SRS-General-export-requirements-2" }, + + {"MID":"37f17fdd57ff47e9b7f4147adaeabde1","UID":"SDOC-SRS-49","_LINK":"SDOC-SRS-49" }, + + {"MID":"37399be2a8ac46889e3437209f9dffa9","UID":"SDOC-SRS-50","_LINK":"SDOC-SRS-50" }, + + {"MID":"f2fd90ad8a2946e7b085233a9c7a8a75","UID":"SDOC-SRS-51","_LINK":"SDOC-SRS-51" }, + + {"MID":"8811f0ef33de4365bc66a602a8c184f6","UID":"SDOC-SRS-48","_LINK":"SDOC-SRS-48" }, + + {"MID":"b99ebebdadb94fec968785429cef9002","UID":"SECTION-SRS-Screen-Project-tree","_LINK":"SECTION-SRS-Screen-Project-tree" }, + + {"MID":"100fa410f4b443e69c48738899cfb5bd","UID":"SDOC-SRS-53","_LINK":"SDOC-SRS-53" }, + + {"MID":"eb04abcfd64146f3b7be509afd1693f9","UID":"SDOC-SRS-107","_LINK":"SDOC-SRS-107" }, + + {"MID":"de7cda1156e043d7999933a2df630a30","UID":"SDOC-SRS-108","_LINK":"SDOC-SRS-108" }, + + {"MID":"185cfc2d1ed4429ebaf0689f70a8cb0a","UID":"SECTION-SRS-Screen-Document-DOC","_LINK":"SECTION-SRS-Screen-Document-DOC" }, + + {"MID":"9c962637ef7f45b6af6c83964b0a06d9","UID":"SDOC-SRS-54","_LINK":"SDOC-SRS-54" }, + + {"MID":"201187122be14ea48d69106d396c6790","UID":"SDOC-SRS-106","_LINK":"SDOC-SRS-106" }, + + {"MID":"13968ae160744e10ba8979eaee2f4f54","UID":"SDOC-SRS-55","_LINK":"SDOC-SRS-55" }, + + {"MID":"edc02a3a97704007b70b93102c76b278","UID":"SDOC-SRS-92","_LINK":"SDOC-SRS-92" }, + + {"MID":"197e00dd3b1d42309250c89de23ea51b","UID":"SDOC-SRS-56","_LINK":"SDOC-SRS-56" }, + + {"MID":"2706ac7ccb8148edb7b200a1b78c25d6","UID":"SDOC-SRS-57","_LINK":"SDOC-SRS-57" }, + + {"MID":"d64f7a0f6ba54672a62634304c54e2d4","UID":"SDOC-SRS-96","_LINK":"SDOC-SRS-96" }, + + {"MID":"956371b6a7824d0b91caa5603faeeae2","UID":"SDOC-SRS-120","_LINK":"SDOC-SRS-120" }, + + {"MID":"738b63b7f55b43eb99f5600bd65f5ba7","UID":"SDOC-SRS-59","_LINK":"SDOC-SRS-59" }, + + {"MID":"2b5d74dafd6d43f4bab4c05ed4da6f0d","UID":"SECTION-SRS-Screen-Table-TBL","_LINK":"SECTION-SRS-Screen-Table-TBL" }, + + {"MID":"e12b4c5b4f13444d99279ab445df5bcc","UID":"SDOC-SRS-62","_LINK":"SDOC-SRS-62" }, + + {"MID":"3c589969eb6a41c19b1dd246dabadbc8","UID":"SECTION-SRS-Screen-Traceability-TR","_LINK":"SECTION-SRS-Screen-Traceability-TR" }, + + {"MID":"35d4c1dd30814c2a80918a90081a88b7","UID":"SDOC-SRS-65","_LINK":"SDOC-SRS-65" }, + + {"MID":"9d337068b6a940b7a98d40697ea200a8","UID":"SECTION-SRS-Screen-Deep-traceability-DTR","_LINK":"SECTION-SRS-Screen-Deep-traceability-DTR" }, + + {"MID":"48bc17d898c94605b17d0267480f57ee","UID":"SDOC-SRS-66","_LINK":"SDOC-SRS-66" }, + + {"MID":"ddf15b3113a54107979752ec192e2ded","_LINK":"5.7-Screen-Project-statistics" }, + + {"MID":"19f7c2d35237423e950584a4a7aa95a7","UID":"SDOC-SRS-97","_LINK":"SDOC-SRS-97" }, + + {"MID":"7968fb7612f64504b5a430ccbffe80f1","UID":"SDOC-SRS-154","_LINK":"SDOC-SRS-154" }, + + {"MID":"d84e3a79b3e443cabe96d7c18ea5d322","_LINK":"5.8-Screen-Document-tree-map" }, + + {"MID":"1520fa85ed7a4f1aa80c49ed858f402f","UID":"SDOC-SRS-157","_LINK":"SDOC-SRS-157" }, + + {"MID":"14ad600308434e6baaeef02d3e90b720","_LINK":"5.9-Screen-Traceability-matrix" }, + + {"MID":"167f6fe66d7247a6bf628ed6c1949275","UID":"SDOC-SRS-112","_LINK":"SDOC-SRS-112" }, + + {"MID":"544f8ffed8604e63a269a3f953681163","_LINK":"5.10-Screen-Project-tree-diff" }, + + {"MID":"aef80cc1a3144564bf23bf3c2a1cfd7f","UID":"SDOC-SRS-111","_LINK":"SDOC-SRS-111" }, + + {"MID":"8380fb39beb04d1c9370733bcfafbc01","_LINK":"5.11-Content-search" }, + + {"MID":"3e85dd6bf05a4cecb8e070fd81aa333a","UID":"SDOC-SRS-155","_LINK":"SDOC-SRS-155" }, + + {"MID":"2d4dc6fc901f4b28aaf414fcfbdfabca","UID":"SECTION-SRS-Requirements-to-source-traceability","_LINK":"SECTION-SRS-Requirements-to-source-traceability" }, + + {"MID":"221b544dab2e4b96be124e1caf84a7c2","UID":"SDOC-SRS-33","_LINK":"SDOC-SRS-33" }, + + {"MID":"2f63252320d546d88462849b521f45ba","_LINK":"6.2-Language-aware-parsing-of-source-code" }, + + {"MID":"79a8080f6e41485f9835ccda067b34bc","UID":"SDOC-SRS-142","_LINK":"SDOC-SRS-142" }, + + {"MID":"85a8080f8441485f9111ccda063b34bc","UID":"SDOC-SRS-146","_LINK":"SDOC-SRS-146" }, + + {"MID":"3456080f1358485f9bacdcda063b34bc","UID":"SDOC-SRS-147","_LINK":"SDOC-SRS-147" }, + + {"MID":"9183080f1358485f9bacdcda0635109","UID":"SDOC-SRS-148","_LINK":"SDOC-SRS-148" }, + + {"MID":"bdeda4b89d82446281e2c7c2eae46708","UID":"SDOC-SRS-143","_LINK":"SDOC-SRS-143" }, + + {"MID":"aefeb5b89d82446281e2c7c2eae12345","UID":"SDOC-SRS-144","_LINK":"SDOC-SRS-144" }, + + {"MID":"5fedbaba39d24da79d074501198ff654","_LINK":"6.5-Forward-linking-from-requirements-to-source-code" }, + + {"MID":"21637d9bec434d32bb6b97ba5a4e70e6","UID":"SDOC-SRS-145","_LINK":"SDOC-SRS-145" }, + + {"MID":"9c1dd6cbabd44ac680985c403cf710a7","_LINK":"6.6-Source-code-markup-Relations" }, + + {"MID":"b9144222a7f3454da2989f494cd9647c","UID":"SDOC-SRS-34","_LINK":"SDOC-SRS-34" }, + + {"MID":"61c25cab106e4283b2c6d64bf1db96b2","UID":"SDOC-SRS-124","_LINK":"SDOC-SRS-124" }, + + {"MID":"61c23c1b106e4583b2c6d64bf1d296ba","UID":"SDOC-SRS-137","_LINK":"SDOC-SRS-137" }, + + {"MID":"86e23c1b106e4adeb2c6d64bf1d29aaa","UID":"SDOC-SRS-140","_LINK":"SDOC-SRS-140" }, + + {"MID":"82345cab106e4283b2c7774bf1db96b1","UID":"SDOC-SRS-139","_LINK":"SDOC-SRS-139" }, + + {"MID":"11c23c1b105e4583b2c6d64bf1d296cc","UID":"SDOC-SRS-138","_LINK":"SDOC-SRS-138" }, + + {"MID":"5ce2ea410dd94927807a258f482483a5","_LINK":"6.7-Source-code-markup-Nodes" }, + + {"MID":"f44df3c6a84f4b4e9201a61023446d9c","UID":"SDOC-SRS-141","_LINK":"SDOC-SRS-141" }, + + {"MID":"3aeb1eea0dba4041a9161a1a8d291999","UID":"SDOC-SRS-35","_LINK":"SDOC-SRS-35" }, + + {"MID":"56ecfb19152e45b09c0e55de2d1d5f05","UID":"SDOC-SRS-36","_LINK":"SDOC-SRS-36" }, + + {"MID":"1acdd6ddf9d24dbaa320230402152226","UID":"SECTION-SRS-Export-import-formats","_LINK":"SECTION-SRS-Export-import-formats" }, + + {"MID":"ce1d174a4d794250931a5ba519583be6","UID":"SECTION-SRS-RST","_LINK":"SECTION-SRS-RST" }, + + {"MID":"2aa615b9cf264e7aad826f4ff466e514","UID":"SDOC-SRS-70","_LINK":"SDOC-SRS-70" }, + + {"MID":"6faffbd1d4cc47ea88c08ef38966e5ec","UID":"SDOC-SRS-71","_LINK":"SDOC-SRS-71" }, + + {"MID":"a906dfb776334b8985f778f0fe1b79e4","UID":"SECTION-SRS-ReqIF","_LINK":"SECTION-SRS-ReqIF" }, + + {"MID":"2bf94015818e4770b2b1947b5fdbb969","UID":"SDOC-SRS-72","_LINK":"SDOC-SRS-72" }, + + {"MID":"bb52b698d7a544aca420d606e4e51356","UID":"SDOC-SRS-73","_LINK":"SDOC-SRS-73" }, + + {"MID":"0ffda51372b641f6ba460bf5ac8b3627","UID":"SECTION-SRS-Excel","_LINK":"SECTION-SRS-Excel" }, + + {"MID":"f7b587f66dda402dbd58768e2740742f","UID":"SDOC-SRS-74","_LINK":"SDOC-SRS-74" }, + + {"MID":"97b587f66dda402dbd58768e2740742f","UID":"SDOC-SRS-152","_LINK":"SDOC-SRS-152" }, + + {"MID":"5aa75848972249d5bec8a40812b99d86","UID":"SDOC-SRS-134","_LINK":"SDOC-SRS-134" }, + + {"MID":"53cfa6296eec45479544e6c5165d7fb9","UID":"SECTION-SRS-Command-line-interface","_LINK":"SECTION-SRS-Command-line-interface" }, + + {"MID":"63373c3875404f1c820add84ea057c73","_LINK":"8.1-General-CLI-requirements" }, + + {"MID":"598647eed3a446fe93e2c54b197f830e","UID":"SDOC-SRS-103","_LINK":"SDOC-SRS-103" }, + + {"MID":"7c6a0efe76b84dcd842ef371796e787e","UID":"SECTION-SRS-Command-Manage","_LINK":"SECTION-SRS-Command-Manage" }, + + {"MID":"bea76afe9bf241eaaf5984b54e00ff76","UID":"SECTION-SRS-Command-Auto-UID","_LINK":"SECTION-SRS-Command-Auto-UID" }, + + {"MID":"7daa1310876a421f8e39f8ac25b99c1d","UID":"SDOC-SRS-85","_LINK":"SDOC-SRS-85" }, + + {"MID":"a0ed7cdd06ec4f0ab6d3ba56cced8c7e","_LINK":"9-Python-API" }, + + {"MID":"a20c5b6a021f4dd5a5a5dda2880c1b87","UID":"SDOC-SRS-125","_LINK":"SDOC-SRS-125" }, + + {"MID":"590121ded2074757aa1720b4d8013426","_LINK":"10-Web-server" }, + + {"MID":"409f462f1f4645c8ad24980727a72521","UID":"SDOC-SRS-126","_LINK":"SDOC-SRS-126" }, + + {"MID":"44eb09d0e5b542d5984d234167e6f337","_LINK":"11-User-experience" }, + + {"MID":"821c01118a9643a188a4ecc5b0cec6a5","UID":"SECTION-SSRS-Strict-mode-by-default","_LINK":"SECTION-SSRS-Strict-mode-by-default" }, + + {"MID":"c4e9dce647654deeab8471d04573f8cb","UID":"SDOC-SRS-6","_LINK":"SDOC-SRS-6" }, + + {"MID":"40e7bd8aabdf4cb889e9d7b01b8729e6","UID":"SECTION-SRS-Configurability","_LINK":"SECTION-SRS-Configurability" }, + + {"MID":"da446e6d3c6d4b13badd4a47bdbcc5a3","UID":"SDOC-SRS-37","_LINK":"SDOC-SRS-37" }, + + {"MID":"a6e70c0619204a26b135d1e5fca45dd7","UID":"SDOC-SRS-39","_LINK":"SDOC-SRS-39" }, + + {"MID":"a8a17295d3e24601891c7d19d5ca67d9","UID":"SDOC-SRS-119","_LINK":"SDOC-SRS-119" }, + + {"MID":"bb14fb2c46f34cf1a82b417b57e95853","UID":"SECTION-SSRS-Performance","_LINK":"SECTION-SSRS-Performance" }, + + {"MID":"acd97ca6b9d2451da53168917d96705e","UID":"SDOC-SRS-1","_LINK":"SDOC-SRS-1" }, + + {"MID":"54602f6d120548c8bbd70d1d25113d53","UID":"SDOC-SRS-95","_LINK":"SDOC-SRS-95" }, + + {"MID":"6fec2f8c0baa4ddba95bee05ad03a785","UID":"SDOC-SRS-2","_LINK":"SDOC-SRS-2" }, + + {"MID":"5f2df631605543d18d57e09bc3791003","UID":"SDOC-SRS-3","_LINK":"SDOC-SRS-3" }, + + {"MID":"d0c4828ed8434613aae844481bbef1ca","UID":"SDOC-SRS-4","_LINK":"SDOC-SRS-4" }, + + {"MID":"4e014d3291ce460c993a0ff334eff4a7","UID":"SDOC-SRS-5","_LINK":"SDOC-SRS-5" }, + + {"MID":"de3a4de44f474784bf233ea7610eac6c","UID":"SECTION-SRS-Quality-requirements","_LINK":"SECTION-SRS-Quality-requirements" }, + + {"MID":"cbee3d3e8a9d440abaa58387c342602c","_LINK":"14.1-General-process" }, + + {"MID":"27319e3866b8423099774d8770950acd","UID":"SDOC-SRS-133","_LINK":"SDOC-SRS-133" }, + + {"MID":"47cec130eb3d4583825355f2635e7011","UID":"SECTION-SRS-Requirements-engineering","_LINK":"SECTION-SRS-Requirements-engineering" }, + + {"MID":"d0ab977bbb494cbf818c92a1cab1bef0","UID":"SDOC-SRS-128","_LINK":"SDOC-SRS-128" }, + + {"MID":"b3fff332c2e342ec9dd372ebd49cb64d","UID":"SDOC-SRS-91","_LINK":"SDOC-SRS-91" }, + + {"MID":"dfbaabc0529f4cc987358ae0563910e9","UID":"SECTION-SRS-Implementation-requirements","_LINK":"SECTION-SRS-Implementation-requirements" }, + + {"MID":"5eb734a4b8944531aa75f0b71ef22d52","UID":"SECTION-SRS-Programming-languages","_LINK":"SECTION-SRS-Programming-languages" }, + + {"MID":"4053ea6c8f6c4c29b89fea0e39912861","UID":"SDOC-SRS-8","_LINK":"SDOC-SRS-8" }, + + {"MID":"131af6457a9f43299306e6dc9fce65a7","UID":"SECTION-SRS-Cross-platform-availability","_LINK":"SECTION-SRS-Cross-platform-availability" }, + + {"MID":"ceee07bdc9bd42fc9a4d0e9b4bfc312f","UID":"SDOC-SRS-9","_LINK":"SDOC-SRS-9" }, + + {"MID":"f8c7586e1b324480ac0bd153e068350d","UID":"SDOC-SRS-10","_LINK":"SDOC-SRS-10" }, + + {"MID":"6af3dbb1e05244579622d3d2a26b5413","UID":"SDOC-SRS-11","_LINK":"SDOC-SRS-11" }, + + {"MID":"852396c217184ba98a0d26b92f36fd04","UID":"SECTION-SRS-Implementation-constraints","_LINK":"SECTION-SRS-Implementation-constraints" }, + + {"MID":"83d5c896004948b48c3597d58267dafa","UID":"SDOC-SRS-89","_LINK":"SDOC-SRS-89" }, + + {"MID":"b22bf982e73246a79a5ba4ae653d21e5","UID":"SDOC-SRS-14","_LINK":"SDOC-SRS-14" }, + + {"MID":"309e4108c1fa47e99d4331af642f3b81","UID":"SDOC-SRS-15","_LINK":"SDOC-SRS-15" }, + + {"MID":"b9cacb97a045418385c7f870b23ac063","UID":"SDOC-SRS-16","_LINK":"SDOC-SRS-16" }, + + {"MID":"70f05a744a0546909dc5b69de88ad41f","UID":"SDOC-SRS-87","_LINK":"SDOC-SRS-87" }, + + {"MID":"7d68821750a54cb5833b608cfc278f47","UID":"SDOC-SRS-88","_LINK":"SDOC-SRS-88" }, + + {"MID":"e4e5b9934e074cdb9567fa197db20a4a","UID":"SECTION-SRS-Coding-constraints","_LINK":"SECTION-SRS-Coding-constraints" }, + + {"MID":"61d96cd1d03e40c48187ee67ac0b65f6","UID":"SDOC-SRS-40","_LINK":"SDOC-SRS-40" }, + + {"MID":"72b5b0c925cf4ef49749b7e466675df1","UID":"SDOC-SRS-41","_LINK":"SDOC-SRS-41" }, + + {"MID":"61e87567580045378d970b327d218cac","UID":"SECTION-SRS-Linting","_LINK":"SECTION-SRS-Linting" }, + + {"MID":"6c0163c56ade49faa353ec06cbd676cd","UID":"SDOC-SRS-42","_LINK":"SDOC-SRS-42" }, + + {"MID":"3029f97a1276499dbbd5d7c71691908e","UID":"SECTION-SRS-Static-analysis","_LINK":"SECTION-SRS-Static-analysis" }, + + {"MID":"2cc9b494ca6248058b6bf63b6e2c1cfa","UID":"SDOC-SRS-43","_LINK":"SDOC-SRS-43" }, + + {"MID":"3aba8ca86d404ba9a063ce125489f35b","UID":"SECTION-SRS-Testing","_LINK":"SECTION-SRS-Testing" }, + + {"MID":"2731c64ab32146eeb4b8167df4a34540","UID":"SDOC-SRS-44","_LINK":"SDOC-SRS-44" }, + + {"MID":"70ef3986cfc4437bbb10288d3b55958c","UID":"SDOC-SRS-45","_LINK":"SDOC-SRS-45" }, + + {"MID":"a42c65f1a53b4c9bb50bc2a1ecb855cb","UID":"SDOC-SRS-46","_LINK":"SDOC-SRS-46" }, + + {"MID":"c90f35ab9a7f4c29a418557151878b9f","UID":"SDOC-SRS-47","_LINK":"SDOC-SRS-47" }, + + {"MID":"83bdb9731e78431cb48d584d279443b4","_LINK":"15-Code-hosting-and-distribution" }, + + {"MID":"dbd186fae9624fd6af8aeb55edfaa43b","UID":"SECTION-SRS-Code-hosting","_LINK":"SECTION-SRS-Code-hosting" }, + + {"MID":"b112c60bc2f34114ab1f3361a1a10a00","UID":"SDOC-SRS-12","_LINK":"SDOC-SRS-12" }, + + {"MID":"bd949cbbe07c4cb29492ea0c8e5c1eec","UID":"SDOC-SRS-118","_LINK":"SDOC-SRS-118" }, ], + "strictdoc/docs/strictdoc_24_development_plan.html": [ + + + {"MID":"e776a9eb7ba0455eb589787028aa0529","_LINK":"None-Development-Plan" }, + + {"MID":"2ba509874f1744cf899643b58a6a2095","_LINK":"2ba509874f1744cf899643b58a6a2095" }, + + {"MID":"24b0bc5efe074a419b441900d30b2876","_LINK":"1-Project-goals" }, + + {"MID":"bdbd5aecefdc41bca1c88b9bce71d512","_LINK":"bdbd5aecefdc41bca1c88b9bce71d512" }, + + {"MID":"f1e3c17829fd4eebbd390fceaeb95619","UID":"SECTION-DP-Project-milestones","_LINK":"SECTION-DP-Project-milestones" }, + + {"MID":"fd9294fdd2b546de993f649767371394","_LINK":"fd9294fdd2b546de993f649767371394" }, + + {"MID":"bf9f3f05501140da8d35cde39493c72f","_LINK":"2.1-The-roadmap-diagram" }, + + {"MID":"53e101acb20e44e89de27f0f77c5f0cb","_LINK":"53e101acb20e44e89de27f0f77c5f0cb" }, + + {"MID":"625560c790a3492eaf45466b787602d7","_LINK":"3-Versioning" }, + + {"MID":"ae2a2af6e3f24f65845c6c37ea7da2e2","_LINK":"ae2a2af6e3f24f65845c6c37ea7da2e2" }, + + {"MID":"ef6bde37e1c54f49afdbd3c6785fd01c","_LINK":"4-Quality" }, + + {"MID":"14d0e79fcadc43f1a1cee2d66ae6b763","_LINK":"14d0e79fcadc43f1a1cee2d66ae6b763" }, + + {"MID":"bc49b1e28fff4386b3bf5788a6686a79","_LINK":"4.1-Linting-of-code" }, + + {"MID":"f6de78d4a95b4970ab55563e18472a92","_LINK":"f6de78d4a95b4970ab55563e18472a92" }, + + {"MID":"38ce17138405490b80e06037b40dc49d","_LINK":"4.2-Static-analysis" }, + + {"MID":"ad63541e341d4648ab59b4a0817a7e3c","_LINK":"ad63541e341d4648ab59b4a0817a7e3c" }, + + {"MID":"2834756354a7420499d0deecfe0ee9c4","_LINK":"4.3-Testing" }, + + {"MID":"ee541e7062704b3f919bcaac2bce2723","_LINK":"ee541e7062704b3f919bcaac2bce2723" }, + + {"MID":"2004550abd54486d9aa5f98282eef6e1","_LINK":"4.4-Traceability-between-StrictDoc-requirements-code-and-tests" }, + + {"MID":"f829d28d2e3d4bcaa38f44ffb1ac0373","_LINK":"f829d28d2e3d4bcaa38f44ffb1ac0373" }, + + {"MID":"30b874ab3eac4d429633537e1e89677f","_LINK":"4.5-Continuous-integration-CI" }, + + {"MID":"85e3915270f144c7a76ccfa0e088d93d","_LINK":"85e3915270f144c7a76ccfa0e088d93d" }, + + {"MID":"2ae3a8822a424a9e8ad6976c2476d109","_LINK":"5-Python-baseline" }, + + {"MID":"081ee6266bab4a3a80f290c95e055a25","_LINK":"081ee6266bab4a3a80f290c95e055a25" }, ], + "strictdoc/docs/strictdoc_25_design.html": [ + + + {"MID":"8e68536f7d4047ada15d3a3043580c4a","UID":"SDOC_DD","_LINK":"SDOC_DD" }, + + {"MID":"2c006e9044074d239db4a45328633657","_LINK":"2c006e9044074d239db4a45328633657" }, + + {"MID":"a74f4e7328714765b5e051768ca8383d","_LINK":"1-Overview" }, + + {"MID":"23937f96ac8e437d81686071cc42d6bf","_LINK":"23937f96ac8e437d81686071cc42d6bf" }, + + {"MID":"f296843b2027457f851a159abafc97e3","_LINK":"2-Building-blocks" }, + + {"MID":"bae7db5591fe418a857af4fb02ad4fec","_LINK":"bae7db5591fe418a857af4fb02ad4fec" }, + + {"MID":"5328a6f4c8544f5e92a91279b5b2c0df","UID":"SECTION-DD-High-level-architecture","_LINK":"SECTION-DD-High-level-architecture" }, + + {"MID":"dcb6369b8d0949f0b06c9ee5b2188b12","_LINK":"dcb6369b8d0949f0b06c9ee5b2188b12" }, + + {"MID":"9b81ed50014c412bb617e90552e58879","_LINK":"4-StrictDoc-command-line-application" }, + + {"MID":"0e0fca629004496084dbe5e217874c36","_LINK":"0e0fca629004496084dbe5e217874c36" }, + + {"MID":"dbcfa8a98e4f4928b0b35938d57dd644","_LINK":"5-StrictDoc-web-application" }, + + {"MID":"f84c0efa27954e44a8b5c1dd3517f90f","_LINK":"f84c0efa27954e44a8b5c1dd3517f90f" }, + + {"MID":"dd2bd75fdffe49a1a0299b804538329c","_LINK":"5.1-The-HTML-Over-the-Wire-Hotwire-architecture" }, + + {"MID":"5577da2187294eb986ec84d9fe26bbdf","_LINK":"5577da2187294eb986ec84d9fe26bbdf" }, + + {"MID":"50f1db3236fa426ea5904974ee724939","_LINK":"6-Static-HTML-search" }, + + {"MID":"5fedd9aac1684adc8fe1f3b87557345d","UID":"SDOC-SRS-156","_LINK":"SDOC-SRS-156" }, + + {"MID":"108af17c077c48bea04557c9d325e924","_LINK":"7-Parsing-SDoc-files" }, + + {"MID":"8a926f0a67424a1eb5db73bb5abca0cd","_LINK":"8a926f0a67424a1eb5db73bb5abca0cd" }, + + {"MID":"4db723c7ae2c4350b2f184783cb638e7","UID":"SECTION-DD-Caching-artifacts","_LINK":"SECTION-DD-Caching-artifacts" }, + + {"MID":"d351d1bf6c2a48d88e9b9bdc50e029ff","_LINK":"d351d1bf6c2a48d88e9b9bdc50e029ff" }, + + {"MID":"4b904b71438c47fcac8aba14df2dd7c0","_LINK":"9-HTML-escaping" }, + + {"MID":"e8a03713c7f644698d9a72cc79b2a299","_LINK":"e8a03713c7f644698d9a72cc79b2a299" }, + + {"MID":"92e8709709614f0f9ccdf702799bf56c","_LINK":"10-ReqIF-interface" }, + + {"MID":"abe8709709614f0f9ccdf702799bf511","UID":"SDOC-SRS-153","_LINK":"SDOC-SRS-153" }, ], + "strictdoc/docs/strictdoc_28_Backlog.html": [ + + + {"MID":"cabef7629dda4f2fb34255d01fea8d5f","_LINK":"None-StrictDoc-Backlog" }, + + {"MID":"35bc1e28ec724aefbcff864c89399877","_LINK":"35bc1e28ec724aefbcff864c89399877" }, + + {"MID":"d1e697dea73144c48a4b88d0d784a517","UID":"SECTION-SB-Open-source-requirements-tool-challenges","_LINK":"SECTION-SB-Open-source-requirements-tool-challenges" }, + + {"MID":"d65fe32e8ea444ceb99c174bfc06df7d","_LINK":"d65fe32e8ea444ceb99c174bfc06df7d" }, + + {"MID":"fc76b207c152433888a86a166f58a425","UID":"SDOC-SRS-13","_LINK":"SDOC-SRS-13" }, + + {"MID":"7614a9f4f7bd4b1c9899995ac3d1e6ad","UID":"SECTION-SB-Backlog","_LINK":"SECTION-SB-Backlog" }, + + {"MID":"e61e7224e27d41ceacad9bf6051bd6f0","UID":"SDOC-BACKLOG-6","_LINK":"SDOC-BACKLOG-6" }, + + {"MID":"07a9636655314912a996ecf5692ae3d5","UID":"SDOC-SRS-86","_LINK":"SDOC-SRS-86" }, + + {"MID":"0425151bf3944e0ebc1c5acabcb35905","UID":"SECTION-SRS-Screen-Project-home","_LINK":"SECTION-SRS-Screen-Project-home" }, + + {"MID":"0a158ddac310483489ef08f618ba8741","UID":"SDOC-SRS-52","_LINK":"SDOC-SRS-52" }, + + {"MID":"1d8a2c3cf8c24e1b92fe212ab7efacf2","_LINK":"2.4-Screen-Traceability-navigator" }, + + {"MID":"dbfe92e9ec3b44e9a3e1c9e89a0e9ef5","UID":"SDOC-SRS-113","_LINK":"SDOC-SRS-113" }, + + {"MID":"2654d541d5ce4cb6ad9fcfe2eaa9abb4","UID":"SECTION-SB-Formal-modeling","_LINK":"SECTION-SB-Formal-modeling" }, + + {"MID":"5958a5c0aad8486b84ad31bc014d4ad3","UID":"SDOC-RMC-27","_LINK":"SDOC-RMC-27" }, + + {"MID":"99e84f704c074cf28de51ce6fb183a66","UID":"SDOC-RMC-29","_LINK":"SDOC-RMC-29" }, + + {"MID":"44b30591f6674ede821324fe527babd9","UID":"SDOC-RMC-55","_LINK":"SDOC-RMC-55" }, + + {"MID":"045aee37b0a24b3cb62cabd8b614aaf7","UID":"SDOC-RMC-28","_LINK":"SDOC-RMC-28" }, + + {"MID":"7e0fd5af118b4f5d8ecbf0d8ef3841e6","UID":"SDOC-RMC-30","_LINK":"SDOC-RMC-30" }, + + {"MID":"061392f275b04c93b664faad9ed4f483","UID":"SECTION-SRS-LaTeX-export","_LINK":"SECTION-SRS-LaTeX-export" }, + + {"MID":"9ec7f471ccb243ea9d86cf2756403b8f","UID":"SDOC-SRS-76","_LINK":"SDOC-SRS-76" }, + + {"MID":"5a0304abcd8a44dab5d032dce6625a5d","UID":"SDOC-BACKLOG-1","_LINK":"SDOC-BACKLOG-1" }, + + {"MID":"162a3da4d9d74c15b5078c9859657ce3","UID":"SDOC-BACKLOG-2","_LINK":"SDOC-BACKLOG-2" }, + + {"MID":"06f16ede826749a389c8d7de9828e0eb","UID":"SDOC-BACKLOG-3","_LINK":"SDOC-BACKLOG-3" }, + + {"MID":"0e69828e1d914e20852aef7cfc4e87c4","UID":"SDOC-BACKLOG-9","_LINK":"SDOC-BACKLOG-9" }, + + {"MID":"34246811634c493dbc771ae4c8bc3b14","UID":"SDOC-BACKLOG-4","_LINK":"SDOC-BACKLOG-4" }, + + {"MID":"3f50a97bc70842dbabeea911f653ef90","UID":"SDOC-BACKLOG-7","_LINK":"SDOC-BACKLOG-7" }, + + {"MID":"72285f9b09de48a29fef8f85431e4a94","UID":"SDOC-BACKLOG-8","_LINK":"SDOC-BACKLOG-8" }, + + {"MID":"bdedcdd91c7f4efb8787b5a82cfec49b","UID":"SDOC-SRS-114","_LINK":"SDOC-SRS-114" }, + + {"MID":"478c38d2cca94107b18fe3dc5b8bfefd","_LINK":"2.15-Multi-user-workflow" }, + + {"MID":"f97dc050ddab4a08bf1689200118faaa","UID":"SDOC-SRS-123","_LINK":"SDOC-SRS-123" }, + + {"MID":"e5b2aff0c1db4b11a8c75c278813300b","UID":"SDOC-SRS-130","_LINK":"SDOC-SRS-130" }, + + {"MID":"440f0bc311b84421a7e8bea9dfd2448b","UID":"SDOC-SRS-131","_LINK":"SDOC-SRS-131" }, + + {"MID":"caecd704ed634d718deff07ba0db7fa6","UID":"SDOC-SRS-116","_LINK":"SDOC-SRS-116" }, + + {"MID":"b74a7a3209d247f6b357513b0cce5000","UID":"SDOC-SRS-121","_LINK":"SDOC-SRS-121" }, + + {"MID":"fa7fd8fd3a694d8e93953fd60e19fdde","UID":"SDOC-SRS-61","_LINK":"SDOC-SRS-61" }, + + {"MID":"7a06d1433e4c4b0eaf55ede14507eac9","UID":"SDOC-SRS-94","_LINK":"SDOC-SRS-94" }, + + {"MID":"45b8513623744776899abfbf99c95286","UID":"SDOC-SRS-58","_LINK":"SDOC-SRS-58" }, + + {"MID":"c02a65f2716f4a86b8f83e3a7b4cd31c","UID":"SDOC-SRS-60","_LINK":"SDOC-SRS-60" }, + + {"MID":"7aa5316dd056465e97044e221412290b","UID":"SDOC-SRS-63","_LINK":"SDOC-SRS-63" }, + + {"MID":"229378602d1847cb83c61ab3e97bb22b","UID":"SDOC-SRS-64","_LINK":"SDOC-SRS-64" }, + + {"MID":"b3472533d57145bc9790724efe56075c","_LINK":"2.24-Screen-Impact-analysis" }, + + {"MID":"f5feb38777064d9db939279d32f79130","UID":"SDOC-SRS-117","_LINK":"SDOC-SRS-117" }, + + {"MID":"a7c504087df04cedb5541d83ed988e9b","UID":"SDOC-SRS-75","_LINK":"SDOC-SRS-75" }, + + {"MID":"4a49c79a1bdd4d4aae5f62bc1d2a56d0","UID":"SECTION-SB-Backlog-Web-based-user-interface","_LINK":"SECTION-SB-Backlog-Web-based-user-interface" }, + + {"MID":"d10cddd846de4961bbb0bc8b8c6550d3","_LINK":"d10cddd846de4961bbb0bc8b8c6550d3" }, + + {"MID":"866a55f2e47b477ebcd52ea57da4f037","UID":"SECTION-SB-Backlog-Nice-to-have","_LINK":"SECTION-SB-Backlog-Nice-to-have" }, + + {"MID":"d02e104a518c4627ac918a33ad165c96","_LINK":"d02e104a518c4627ac918a33ad165c96" }, + + {"MID":"eb1fab2bbea541c8b00f70780326c9fc","UID":"SECTION-SB-Backlog-Technical-debt","_LINK":"SECTION-SB-Backlog-Technical-debt" }, + + {"MID":"85e94802132048d29ca73cf2096c6758","_LINK":"85e94802132048d29ca73cf2096c6758" }, + + {"MID":"6ef8c2ad683d46af948674727c7a52b4","UID":"SECTION-SB-Open-questions","_LINK":"SECTION-SB-Open-questions" }, + + {"MID":"717df91623014fb98ba34ab8173b94ab","UID":"SECTION-SB-One-or-many-input-sdoc-trees","_LINK":"SECTION-SB-One-or-many-input-sdoc-trees" }, + + {"MID":"b778a18ede89464c936be2b2af492e24","_LINK":"b778a18ede89464c936be2b2af492e24" }, ], + "strictdoc/docs/strictdoc_30_credits.html": [ + + + {"MID":"d92baa6b8cf745a2ab6be86616b06277","_LINK":"None-Credits" }, + + {"MID":"18cf0af34c194590b3eb391c2ef94074","_LINK":"18cf0af34c194590b3eb391c2ef94074" }, + + {"MID":"c89b5ba9c6dc427497647b64048a2c98","_LINK":"1-Contributions-to-StrictDoc" }, + + {"MID":"e6de83e242bc4aea96622a2e7585f135","_LINK":"e6de83e242bc4aea96622a2e7585f135" }, + + {"MID":"4d59a5df65d547e685cb491937793f69","_LINK":"2-Open-source-software" }, + + {"MID":"4428ac9ec3504dda9f1e1e845ffb3c75","_LINK":"4428ac9ec3504dda9f1e1e845ffb3c75" }, + + {"MID":"2da7450f8b804a7a8494921486bd4d8e","_LINK":"3-Hosting-and-Continuous-Integration" }, + + {"MID":"5b702e6f9b714e458b059912ca8e196a","_LINK":"5b702e6f9b714e458b059912ca8e196a" }, + + {"MID":"43ccb6448b9d4b65a2c40df54d1707aa","_LINK":"4-Free-and-commercial-IDEs-by-JetBrains" }, + + {"MID":"b4729e592d104fe3818c8949615ffef9","_LINK":"b4729e592d104fe3818c8949615ffef9" }, ], + "strictdoc/docs_extra/DO178_requirements.html": [ + + + {"MID":"b3727ea826c24d42a84e88983e7c1e24","_LINK":"None-Technical-Note-DO-178C-requirements-tool-requirements" }, + + {"MID":"fc77215d50134f17aa242b4df7310099","_LINK":"fc77215d50134f17aa242b4df7310099" }, + + {"MID":"6be4dbe02b4346df9849eaa6fe077e0e","UID":"SECTION-DR-Already-implemented-features","_LINK":"SECTION-DR-Already-implemented-features" }, + + {"MID":"af14393406e64ab6b2911eefa4358f33","UID":"DO178-1","_LINK":"DO178-1" }, + + {"MID":"0a19cae3756a4d2f9f0be9e57c44a8fa","UID":"DO178-2","_LINK":"DO178-2" }, + + {"MID":"dd075d6cd4fb4ad2b731a9b8068efade","UID":"DO178-14","_LINK":"DO178-14" }, + + {"MID":"03346e43cd0b43529cc3b958a00d8d35","UID":"DO178-3","_LINK":"DO178-3" }, + + {"MID":"4f0809d49292413eb621a47a8b405bc7","UID":"DO178-4","_LINK":"DO178-4" }, + + {"MID":"c74bba92cec34bf7b1046689c2dfc54c","UID":"DO178-5","_LINK":"DO178-5" }, + + {"MID":"8b73ce9efcc840b2be272d5aaef08e70","UID":"DO178-6","_LINK":"DO178-6" }, + + {"MID":"8c654ff659a94cceb0c7a52bc8ae4073","UID":"DO178-8","_LINK":"DO178-8" }, + + {"MID":"cfdb3867a4a64b3eb9405e998c11ae72","UID":"DO178-7","_LINK":"DO178-7" }, + + {"MID":"40d4a56263d0420691dbde5d7889895a","UID":"DO178-13","_LINK":"DO178-13" }, + + {"MID":"8bd26640450f448c8228464223c21373","UID":"DO178-9","_LINK":"DO178-9" }, + + {"MID":"09f3e3faa1b84aafb19f26e22ab06c95","UID":"SECTION-DR-Needs-discussion","_LINK":"SECTION-DR-Needs-discussion" }, + + {"MID":"db4336a8f119443cae6a70d74a0601da","UID":"DO178-19","_LINK":"DO178-19" }, + + {"MID":"7d18b7674050495c935dc4669dfb260e","UID":"DO178-15","_LINK":"DO178-15" }, + + {"MID":"b0c13e71074242ab91d6344514b82657","UID":"DO178-10","_LINK":"DO178-10" }, + + {"MID":"7e8a475859084e9d95eda3f2c1381ae7","UID":"DO178-11","_LINK":"DO178-11" }, + + {"MID":"23c11790799c4457804bcb9d6288931e","UID":"DO178-12","_LINK":"DO178-12" }, + + {"MID":"a1fb2f7cd7cd4c8eb33c3407a791fd88","UID":"DO178-16","_LINK":"DO178-16" }, + + {"MID":"756503f4934a4aed81dfe090b2538e2a","UID":"DO178-17","_LINK":"DO178-17" }, + + {"MID":"8120b4f6be4e4ecd83c0b69a3424e0be","UID":"DO178-18","_LINK":"DO178-18" }, ], + "strictdoc/docs_extra/Zephyr_requirements.html": [ + + + {"MID":"2e7deb9808bb42879e7463b1d7ac9bba","_LINK":"None-Technical-Note-Zephyr-requirements-tool-requirements" }, + + {"MID":"68e87901205c4b0dbb6a0071479330b5","UID":"ZEP-1","_LINK":"ZEP-1" }, + + {"MID":"36415af620f645388af4dc51c2a19b97","UID":"ZEP-2","_LINK":"ZEP-2" }, + + {"MID":"7a9e26240f5c4fe29143cf3348ac3d3b","UID":"ZEP-3","_LINK":"ZEP-3" }, + + {"MID":"a5928d6204a84d02a3c367d6dbc54092","UID":"ZEP-4","_LINK":"ZEP-4" }, + + {"MID":"55bbe693d12d4e00956d41a837ef15ef","UID":"ZEP-5","_LINK":"ZEP-5" }, + + {"MID":"b58c387f3a2d4cf6a540e279dbe49e47","UID":"ZEP-6","_LINK":"ZEP-6" }, + + {"MID":"17a141add32f4d7696b5a74b6507b9aa","UID":"ZEP-7","_LINK":"ZEP-7" }, + + {"MID":"d0d258d8640443578c7ec508c014b50d","UID":"ZEP-8","_LINK":"ZEP-8" }, + + {"MID":"611546bf2409417e8844f93854d54268","UID":"ZEP-9","_LINK":"ZEP-9" }, + + {"MID":"f1f6da87da5c49d1b8c3441b14863975","UID":"ZEP-10","_LINK":"ZEP-10" }, + + {"MID":"55cbd9b658164414adb0c13b0446e3f7","UID":"ZEP-11","_LINK":"ZEP-11" }, + + {"MID":"a2930225168147808e6554a4da49aeb4","UID":"ZEP-12","_LINK":"ZEP-12" }, + + {"MID":"2614d6673a594da995df672e8943839e","UID":"ZEP-13","_LINK":"ZEP-13" }, + + {"MID":"a92a28ce3bcb4b3590f36e778a604ccb","UID":"ZEP-14","_LINK":"ZEP-14" }, + + {"MID":"b74919612283422a9e139418a20926c6","UID":"ZEP-15","_LINK":"ZEP-15" }, ], +}; diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.css new file mode 100644 index 0000000..940d06b --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.css @@ -0,0 +1,218 @@ + +/* tree */ +.project_tree { + position: relative; + /* width: -moz-fit-content; + width: fit-content; */ + /* margin: 0 auto; */ +} + +.project_tree details>summary { + list-style: none; +} + +.project_tree summary::-webkit-details-marker { + display: none +} + +/* folder */ + +.project_tree-folder { + border: var(--base-border); + border-radius: calc(0.5 * var(--base-rhythm)); + overflow: hidden; + position: relative; + padding-left: var(--base-rhythm); + padding-right: var(--base-rhythm); + background: var(--color-bg-secondary); +} + +.project_tree-folder[open] { + background: transparent; +} + +.project_tree-folder.source { + padding-right: 0; + border-right: none; + border-bottom: none; +} + +.project_tree-folder summary { + position: relative; + cursor: pointer; + user-select: none; +} + +.project_tree-folder-title { + font-weight: bold; + display: flex; + column-gap: calc(0.5 * var(--base-rhythm)); + font-size: 0.85rem; + line-height: 1.2; + color: #666; + padding: calc(0.5 * var(--base-rhythm)); + position: relative; +} + +.project_tree-folder-title::before, +.project_tree-folder-title::after { + content: ''; + position: absolute; + top: 0; + right: -20px; + left: -20px; + bottom: 0; +} + +.project_tree-folder-title::after { + background: var(--color-bg-secondary); +} + +.project_tree-folder summary:hover > .project_tree-folder-title::before { + background: var(--color-bg-secondary); +} + +.project_tree-folder summary:hover > .project_tree-folder-title, +.project_tree-folder summary:hover::after { + color: var(--color-fg-accent); +} + +/* .icon_collapse_expand is class inside SVG */ +.project_tree-folder-title .icon_collapse_expand { + margin-left: auto; +} +/* .collapsed and .expanded are classes inside SVG .icon_collapse */ +.project_tree-folder > summary .icon_collapse_expand .collapsed { + display: initial; +} +.project_tree-folder > summary .icon_collapse_expand .expanded { + display: none; +} +.project_tree-folder[open] > summary .icon_collapse_expand .expanded { + display: initial; +} +.project_tree-folder[open] > summary .icon_collapse_expand .collapsed { + display: none; +} + +.project_tree-folder-content { + display: flex; + flex-direction: column; + justify-content: space-between; + gap: var(--base-rhythm); + padding-top: var(--base-rhythm); + padding-bottom: var(--base-rhythm); +} + +/* file */ + +.project_tree-file { + display: flex; + column-gap: var(--base-rhythm); + padding: calc(0.5 * var(--base-rhythm)); + border-radius: calc(0.5 * var(--base-rhythm)); + transition: background .3s; + border: 1px solid rgba(255,255,255,0); +} + +.project_tree-file:not([href]):hover { + border: 1px solid rgba(255,255,255,0.75); + background: rgba(0,0,0,0.01); +} + +.project_tree-file[href]:hover { + background: rgba(255,255,255,0.5); +} + +.project_tree-file[href]:hover .project_tree-file-icon, +.project_tree-file[href]:hover .project_tree-file-title { + color: var(--color-fg-accent); +} + +.project_tree-file-details { + display: block; +} + +.project_tree-file-icon { + line-height: 0; +} + +.project_tree-file-title { + font-size: 1em; + font-weight: 500; + line-height: 1.2; + transition: color .2s; +} + +.project_tree-file-icon, +.project_tree-file-title { + color: var(--color-fg-secondary); +} + +.project_tree-file[href] .project_tree-file-icon, +.project_tree-file[href] .project_tree-file-title { + color: var(--color-fg-main); +} + +.project_tree-file-name { + font-size: 0.85rem; + line-height: 1.2; + color: var(--color-fg-secondary); + margin-top: 0.25rem; +} + +.project_tree-file-aside { + margin-left: auto; +} + +/* dashboard */ + +.dashboard { + display: flex; + align-items: flex-start; + gap: var(--base-rhythm); +} + +.dashboard-main { + flex-grow: 1; +} + +.dashboard-aside { + width: 30%; + /* max-width: 300px; */ + font-size: 0.75rem; + display: flex; + gap: var(--base-rhythm); + flex-direction: column; +} + +.dashboard-block:empty { + display: none; +} + +.dashboard-block { + border: var(--base-border); + border-radius: calc(0.5 * var(--base-rhythm)); + overflow: hidden; + position: relative; + padding: var(--base-rhythm); +} + +.dashboard-block-title { + font-weight: 600; + position: relative; + top: calc(-1 * var(--base-rhythm)); + color: var(--color-fg-secondary); + padding: calc(0.5 * var(--base-rhythm)) 0; +} + +.dashboard-block-title::after { + content: ''; + position: absolute; + top: -20px; + left: -20px; + right: -20px; + bottom: 0; + background-color: rgba(0,0,0,0.025); + border-bottom: var(--base-border); +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.js new file mode 100644 index 0000000..79a48c9 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/project_tree.js @@ -0,0 +1,373 @@ +const FRAME_SELECTOR = '#frame_project_tree'; +const SWITCH_SELECTOR = '#project_tree_controls'; +const FRAGMENT_ATTR = 'included-document'; +const FRAGMENT_SELECTOR = `.project_tree-file[${FRAGMENT_ATTR}]`; +const FILE_SELECTOR = `.project_tree-file`; +const FOLDER_SELECTOR = `.project_tree-folder`; + +// This class Switch was taken +// from strictdoc/export/html/_static/source-code-coverage.js +// and improved a bit: +class Switch { + constructor({ + callback, + labelText, + checked, + componentClass, + colorOn, + colorOff, + size, + stroke, + units, + position, + topPosition, + leftPosition, + rightPosition, + bottomPosition, + dataTestID, + }) { + this.colorOn = colorOn || 'rgb(242, 100, 42)'; + this.colorOff = colorOff || 'rgb(200, 200, 200)'; + this.labelInitialText = labelText || ''; + this.checked = (checked === false) ? false : true; + + this.dataTestID = dataTestID || 'std-switch'; + this.componentClass = componentClass || 'std-switch-scc'; + this.size = size || 0.75; + this.stroke = stroke || 0.25; + this.units = units || 'rem'; + + this.topPosition = topPosition || 'unset', + this.leftPosition = leftPosition || 'unset', + this.rightPosition = rightPosition || 'unset', + this.bottomPosition = bottomPosition || 'unset', + this.position = position || 'static', + + this.controlLabelTextSpan = document.createElement('span'); + this.callback = callback; + } + + create() { + const block = document.createElement('div'); + block.classList.add(this.componentClass); + const label = document.createElement('label'); + label.classList.add(`${this.componentClass}__label`); + const input = document.createElement('input'); + input.classList.add(`${this.componentClass}__input`); + input.type = 'checkbox'; + input.checked = this.checked; + const slider = document.createElement('span'); + slider.classList.add(`${this.componentClass}__slider`); + + label.append(input, slider, this.controlLabelTextSpan); + block.append(label); + + this.insertStyle(); + this.updateLabelText(this.labelInitialText); + input.addEventListener('change', () => this.callback(input.checked)); + + label.setAttribute('data-testid', this.dataTestID); + + return block; + } + + updateLabelText(text) { + this.controlLabelTextSpan.innerHTML = text; + } + + insertStyle() { + + const css = ` + .${this.componentClass} { + display: inline-block; + line-height: 0; + position: ${this.position}; + top: ${this.topPosition}; + left: ${this.leftPosition}; + right: ${this.rightPosition}; + bottom: ${this.bottomPosition}; + } + .${this.componentClass}__label { + display: inline-flex; + column-gap: 8px; + line-height: ${this.size * 1.6}${this.units}; + line-height: 1.25; + align-items: flex-start; + justify-content: flex-start; + user-select: none; + cursor: pointer; + font-size: small; + } + .${this.componentClass}__input { + opacity: 0; + width: 0; + height: 0; + position: absolute; + } + .${this.componentClass}__slider { + position: relative; + cursor: pointer; + background-color: ${this.colorOff}; + -webkit-transition: .4s; + transition: .4s; + display: inline-block; + width: ${this.size * 2 + this.stroke * 2}${this.units}; + min-width: ${this.size * 2 + this.stroke * 2}${this.units}; + height: ${this.size + this.stroke * 2}${this.units}; + margin-right: ${this.size * 0.5}${this.units}; + border-radius: ${this.size * 0.5 + this.stroke}${this.units}; + } + .${this.componentClass}__slider::before { + position: absolute; + content: ""; + height: ${this.size}${this.units}; + width: ${this.size}${this.units}; + left: ${this.stroke}${this.units}; + bottom: ${this.stroke}${this.units}; + background-color: white; + -webkit-transition: .4s; + transition: .4s; + border-radius: 50%; + } + input:checked + .${this.componentClass}__slider { + background-color: ${this.colorOn}; + } + input:focus + .${this.componentClass}__slider { + box-shadow: 0 0 1px ${this.colorOn}; + } + input:checked + .${this.componentClass}__slider::before { + -webkit-transform: translateX(${this.size}${this.units}); + -ms-transform: translateX(${this.size}${this.units}); + transform: translateX(${this.size}${this.units}); + } + `; + + const head = document.querySelector('head'); + const style = document.createElement('style'); + style.append(document.createTextNode(css)); + style.setAttribute("data-slider-styles", ''); + head.append(style); + } + +} + +class ProjectTree { + constructor({ + mutatingFrame, + controlTarget + }) { + this.mutatingFrame = mutatingFrame; + this.controlTarget = controlTarget; + this.fragments = []; + + this.control; + this.controlElement; + + this.state = { + fragmentVisibility: { + _sessionStorageItemName: 'projectTreeFragmentVisibility', + initial: 'hide', + current: null, + } + }; + } + + init() { + // console.log('First time call.'); + + console.assert(this.mutatingFrame, `mutatingFrame not found on the page`); + this._addMutationObserver(); + + this._initStateAndStorage(); + + // * this.controlTarget may not be present on the page, for example, in the case of static export. + // console.assert(this.controlTarget, `controlTarget not found on the page`); + + this._createControl(); + this._addControl(); + + this.updateFragmentsAndControl(); + } + + getCurrentFragmentVisibilityBool() { + return (this.state.fragmentVisibility.current === 'show') ? true : false; + } + + updateFragmentsAndControl() { + // Update list of fragment elements (files + folders) and toggle visibility + const fileFragments = this._getFileFragments(); + const folderFragments = this._getFoldersWithOnlyFragments(); + + // Store both individual file fragments and folders that contain only fragments + this.fragments = [...fileFragments, ...folderFragments]; + + // Only show number of file fragments (folders are excluded from count) + this._updateControl(fileFragments.length); + this._updateFragmentsVisibility(this.getCurrentFragmentVisibilityBool()); + } + + _getFileFragments() { + // Find all file elements that are marked as included fragments + return [...this.mutatingFrame.querySelectorAll(FRAGMENT_SELECTOR)]; + } + + _getFoldersWithOnlyFragments() { + // Find folders that contain only fragment files and no other files + const folders = [...this.mutatingFrame.querySelectorAll(FOLDER_SELECTOR)]; + return folders.filter(folder => { + // Consider only those folders if it contains only fragment files + const fragCount = folder.querySelectorAll(FRAGMENT_SELECTOR).length; + const fileCount = folder.querySelectorAll(FILE_SELECTOR).length; + return fragCount > 0 && fragCount === fileCount; + }); + } + + _getFragments() { + let fragments = [...this.mutatingFrame.querySelectorAll(FRAGMENT_SELECTOR)]; + const folders = this._prepareFragmentsFolders(fragments); + return fragments.concat(folders); + } + + _prepareFragmentsFolders(fragments) { + // Temporary solution. + // It is possible to optimize the search to reduce the number of runs. + + const result = []; + // .project_tree-folder > .project_tree-folder-content > .project_tree-file === fragment + const folders = [...this.mutatingFrame.querySelectorAll(FOLDER_SELECTOR)]; + folders.forEach(folder => { + const frag = folder.querySelectorAll(FRAGMENT_SELECTOR); + const file = folder.querySelectorAll(FILE_SELECTOR); + if (frag.length === file.length) { + result.push(folder); + } + }); + return result + } + + _updateFragmentsVisibility(bool) { + const display = bool ? '' : 'none'; + this.fragments.forEach(element => { + element.style.display = display; + }) + } + + _updateControl(num) { + this.control.updateLabelText(`Show ${num} fragment${num > 1 ? 's' : ''} included in other documents in the Project document tree.`) + + if (num) { + this._addControl(); + } else { + this._removeControl(); + } + } + + toggleFragmentsVisibility(checked) { + this._updateFragmentsVisibility(checked); + + if (checked) { + this._updateCurrentState('show', 'fragmentVisibility'); + this._setSessionStorageItem('show', 'fragmentVisibility'); + } else { + this._updateCurrentState('hide', 'fragmentVisibility'); + this._setSessionStorageItem('hide', 'fragmentVisibility'); + } + } + + _initStateAndStorage(option = 'fragmentVisibility') { + const storage = this._getSessionStorageItem(option); + + if (storage) { + this._updateCurrentState(storage); + } else { + this._updateCurrentState(this.state[option].initial); + this._setSessionStorageItem(this.state[option].initial); + } + } + + _updateCurrentState(value, option = 'fragmentVisibility') { + this.state[option].current = value; + } + + _setSessionStorageItem(nextState, option = 'fragmentVisibility') { + sessionStorage.setItem(this.state[option]._sessionStorageItemName, nextState); + } + + _getSessionStorageItem(option = 'fragmentVisibility') { + const storage = sessionStorage.getItem(this.state[option]._sessionStorageItemName); + return storage; + } + + _createControl() { + this.control = new Switch( + { + labelText: `Show fragments`, // * This text will be updated later. + dataTestID: 'show-hide-fragments-toggler', + size: 0.5, + stroke: 0.175, + // position: 'absolute', + // topPosition: '16px', + // leftPosition: 0, + // checked: false, + checked: this.getCurrentFragmentVisibilityBool(), + callback: (checked) => this.toggleFragmentsVisibility(checked), + } + ); + this.controlElement = this.control.create(); + } + + _addControl() { + // * this.controlTarget may not be present on the page, for example, in the case of static export. + this.controlTarget && this.controlTarget.append(this.controlElement); + } + + _removeControl() { + this.controlElement.remove(); + } + + _addMutationObserver() { + // console.log('Mutation observer added for', this.mutatingFrame); + + new MutationObserver((mutationsList, observer) => { + for (let mutation of mutationsList) { + if (mutation.type === 'childList') { + // When re-rendering the frame content, + // the array of tracked elements should be updated + // and their visibility should be set according + // to the current settings available in the State. + this.updateFragmentsAndControl(); + } + } + }).observe( + this.mutatingFrame, + { + childList: true, + // subtree: true + } + ); + } +} + +window.addEventListener("DOMContentLoaded", function(){ + + const controlTarget = document.querySelector(SWITCH_SELECTOR); + // * This element may not be present on the page, for example, in the case of static export. + // if (!controlTarget) { + // console.error(`Selector "${SWITCH_SELECTOR}" not found on the page`); + // return; + // } + + const mutatingFrame = document.querySelector(FRAME_SELECTOR); + if (!mutatingFrame) { + console.error(`Selector "${FRAME_SELECTOR}" not found on the page`); + return; + } + + const projectTree = new ProjectTree({ + mutatingFrame, + controlTarget + }); + + projectTree.init(); + +},false); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement-tree.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement-tree.css new file mode 100644 index 0000000..b0aa443 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement-tree.css @@ -0,0 +1,283 @@ +:root { + --requirement-tree-line-width: 1px; + --requirement-tree-line-color: var(--color-border); + --requirement-tree-margin: var(--tree-gap); + --requirement-tree-downward-margin: calc(var(--requirement-tree-margin)*.5); + --requirement-tree-downward-string-margin: calc(var(--requirement-tree-downward-margin)*0.25); + --requirement-tree-line: var(--requirement-tree-line-width) solid; + --requirement-tree-downward-line: var(--requirement-tree-line-color) var(--requirement-tree-line-width) solid; + --requirement-tree-arrow-size: calc(var(--requirement-tree-margin)/4); + /* var(--color-fg-contrast) */ + /* var(--color-accent) */ +} + +/* requirement-tree */ + +.requirement-tree { + position: relative; + + list-style: none; + padding: 0; + margin: 0; + box-sizing: border-box; + + display: flex; + justify-content: flex-start; + flex-direction: column; + align-content: flex-start; + + /* default aka right direction */ + align-items: flex-start; + margin-left: var(--requirement-tree-margin); +} + +.requirement-tree_right.requirement-tree { + align-items: flex-start; + margin-right: 0; + margin-left: var(--requirement-tree-margin); +} + +.requirement-tree_left.requirement-tree { + align-items: flex-end; + margin-left: 0; + margin-right: var(--requirement-tree-margin); +} + +.requirement-tree_branch { + position: relative; + + display: flex; + justify-content: center; + align-items: flex-start; + align-content: stretch; + margin-bottom: var(--requirement-tree-margin); +} + +.requirement-tree_left .requirement-tree_branch { + flex-direction: row-reverse; +} + +.requirement-tree_branch:last-child { + margin-bottom: 0; +} + +.requirement-tree_node { + display: flex; + flex-direction: column; + align-items: stretch; + + /* for width restrictions in deep trace */ + max-width: var(--card-width); +} + +[data-viewtype="requirements-coverage"] .requirement-tree_node { + width: calc(var(--card-width)*0.75); +} + + /* arrows */ + +.requirement-tree_right.requirement-tree::before { + /* arrow from children, show only in right tree */ + content: ''; + position: absolute; + width: var(--requirement-tree-arrow-size); + height: var(--requirement-tree-arrow-size); + top: var(--requirement-tree-margin); + left: calc(var(--requirement-tree-margin)*(-1) - var(--requirement-tree-line-width)*0.5); + box-sizing: border-box; + border-top: var(--requirement-tree-line); + border-left: var(--requirement-tree-line); + transform-origin: top left; + transform: rotate(-45deg); + z-index: 2; +} + +.requirement-tree_left .requirement-tree_node::before { + /* arrow to parents inside tree */ + content: ''; + position: absolute; + width: var(--requirement-tree-arrow-size); + height: var(--requirement-tree-arrow-size); + top: var(--requirement-tree-margin); + right: calc(var(--requirement-tree-arrow-size)*(-1)); + box-sizing: border-box; + border-top: var(--requirement-tree-line); + border-left: var(--requirement-tree-line); + transform-origin: top left; + transform: rotate(-45deg); + z-index: 2; +} + +/* corner connector to node */ + +.requirement-tree_branch::before { + content: ''; + position: absolute; + width: calc(var(--requirement-tree-margin)*0.5); + height: var(--requirement-tree-margin); + top: 0; + box-sizing: border-box; + /* default aka right direction */ + border-bottom: var(--requirement-tree-line); + border-left: var(--requirement-tree-line); + left: calc(var(--requirement-tree-margin)*(-1)*0.5); +} + +.requirement-tree_right .requirement-tree_branch::before { + right: unset; + left: calc(var(--requirement-tree-margin)*(-1)*0.5); + border: none; + border-bottom: var(--requirement-tree-line); + border-left: var(--requirement-tree-line); +} + +.requirement-tree_left .requirement-tree_branch::before { + left: unset; + right: calc(var(--requirement-tree-margin)*(-1)*0.5); + border: none; + border-bottom: var(--requirement-tree-line); + border-right: var(--requirement-tree-line); +} + +/* horizontal line to top node instead corner */ + +.requirement-tree_branch:first-child::before { + width: var(--requirement-tree-margin); + border: none; + border-bottom: var(--requirement-tree-line); + /* default aka right direction */ + right: unset; + left: calc(var(--requirement-tree-margin)*(-1)); +} + +.requirement-tree_right .requirement-tree_branch:first-child::before { + right: unset; + left: calc(var(--requirement-tree-margin)*(-1)); +} + +.requirement-tree_left .requirement-tree_branch:first-child::before { + left: unset; + right: calc(var(--requirement-tree-margin)*(-1)); +} + +/* vertical line */ + +.requirement-tree_branch::after { + content: ''; + position: absolute; + width: calc(var(--requirement-tree-margin)*0.5); + top: var(--requirement-tree-margin); + bottom: calc(var(--requirement-tree-margin)*(-1)); + box-sizing: border-box; + /* default aka right direction */ + border: none; + border-left: var(--requirement-tree-line); + left: calc(var(--requirement-tree-margin)*(-1)*0.5); +} + +.requirement-tree_right .requirement-tree_branch::after { + border: none; + border-left: var(--requirement-tree-line); + right: unset; + left: calc(var(--requirement-tree-margin)*(-1)*0.5); +} + +.requirement-tree_left .requirement-tree_branch::after { + border: none; + border-right: var(--requirement-tree-line); + left: unset; + right: calc(var(--requirement-tree-margin)*(-1)*0.5); +} + +/* vertical line on last node is not showing */ +.requirement-tree_branch:last-child:after { + content: none; +} + +/* downward */ + +.requirement-tree_downward { + list-style: none; + padding: 0; + margin: 0; + margin-left: var(--requirement-tree-downward-margin); + box-sizing: border-box; + + font-size: .75rem; + line-height: 1.2; +} + +.requirement-tree_downward_node { + position: relative; + border-left: var(--requirement-tree-downward-line); +} + +.requirement-tree_downward .requirement-tree_downward_node { + padding-top: calc(var(--requirement-tree-downward-margin)*0.5); +} + +.requirement-tree_downward .requirement-tree_downward_node:first-child { + padding-top: var(--requirement-tree-downward-margin); +} + +.requirement-tree_downward .requirement-tree_downward_node:last-child { + border-color: transparent; +} + +.requirement-tree_downward .requirement-tree_downward_node::before { + position: absolute; + content: ''; + width: var(--requirement-tree-downward-margin); + border-bottom: var(--requirement-tree-downward-line); + box-sizing: border-box; + top: 0; + left: calc(var(--requirement-tree-line-width)*(-1)); + bottom: calc(100% - var(--requirement-tree-downward-margin)*0.5 - 0.75rem); +} + +.requirement-tree_downward .requirement-tree_downward_node:last-child::before { + border-left: var(--requirement-tree-downward-line); +} + +.requirement-tree_downward .requirement-tree_downward_node:first-child::before { + bottom: calc(100% - var(--requirement-tree-downward-margin)*1 - 0.75rem); +} + +.requirement-tree_downward_node .requirement-tree_downward_item { + position: relative; + /* margin-left: calc(var(--requirement-tree-downward-margin) + var(--requirement-tree-downward-string-margin)); */ + margin-left: calc(var(--requirement-tree-downward-margin) - 0.25rem); + + border-radius: 4px; + overflow: clip; + border: 1px solid var(--requirement-tree-line-color); + background-color: var(--color-bg-main); + + overflow-wrap: break-word; +} + +.requirement-tree_downward_item span, +.requirement-tree_downward_item a { + padding: 4px 6px; + display: inline-block; + width: 100%; + overflow-wrap: break-word; +} + +.requirement-tree_downward_item a { + color: var(--color-accent); + text-decoration: none; +} + +.requirement-tree_downward_item a:hover { + text-decoration: underline; +} + +/* hover */ + +/* .requirement-tree_node:hover + .requirement-tree::before, +.requirement-tree_node:hover + .requirement-tree .requirement-tree::before, +.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::before, +.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::after { + border-width: 2px; +} */ diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement__temporary.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement__temporary.css new file mode 100644 index 0000000..24122fe --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/requirement__temporary.css @@ -0,0 +1,138 @@ +/* TODO: should be revised and then moved to a permanent location or removed */ + +/* requirement__title */ + +.requirement__title { + margin: 0; + line-height: 1.6; + font-weight: bold; +} + +/* requirement: parent / child / file */ + +ul.requirement__link { + font-size: .85rem; + line-height: 1.4; + list-style: none; + padding: 0; +} + +[data-viewtype="source-file"] ul.requirement__link li { + margin-top: 0.5rem; +} + +.requirement__link a, +.requirement__link li > span { + display: inline-block; + position: relative; + margin-left: 1.5rem; + width: calc(100% - 1.5rem); + overflow-wrap: break-word; +} + +.requirement__link a::before, +.requirement__link li > span::before { + color: #808080; + position: absolute; + left: -1.5rem; +} + +.requirement__link a:link, +.requirement__link a:visited { + color: var(--color-fg-contrast); + text-decoration: none; +} + +.requirement__link a:hover { + /* color: var(--color-fg-accent); */ + text-decoration: underline; +} + +/* .requirement__link a::before { + content: '\2014'; +} */ + +a.requirement__link-file::before, +.requirement__link-file::before { + content: ''; +} + +a.requirement__link-parent::before { + content: '\2190'; +} + +a.requirement__link-child::before { + content: '\2192'; +} + +.requirement__link-external::before { + content: '\21D6'; +} + +.requirement__parent-uid, +.requirement__child-uid { + position: relative; + font-weight: bold; +} + +/* switch (injected by JS) */ + +.std-switch { + display: flex; + align-items: center; + justify-content: flex-start; + + user-select: none; + cursor: pointer; +} + +.std-switch input { + opacity: 0; + width: 0; + height: 0; + position: absolute; +} + +.std-switch_slider { + + position: relative; + cursor: pointer; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; + + display: inline-block; + width: 44px; + height: 26px; + margin-right: 10px; + + border-radius: 22px; +} + +.std-switch_slider::before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; + + border-radius: 50%; +} + +input:checked + .std-switch_slider { + background-color: rgb(100, 222, 50); +} + +input:focus + .std-switch_slider { + box-shadow: 0 0 1px rgb(100, 222, 50); +} + +input:checked + .std-switch_slider:before { + -webkit-transform: translateX(18px); + -ms-transform: translateX(18px); + transform: translateX(18px); +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/resizable_bar.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/resizable_bar.js new file mode 100644 index 0000000..098482c --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/resizable_bar.js @@ -0,0 +1,602 @@ +// Expected in element: +// js-resizable_bar="name" +// data-state="open|closed" +// data-position="left|right" + +class ResizableBar { + constructor({ + barAttribute, + barOpenMinWidth, + barOpenMaxWidthRatio, + // styles + barPadding, + barPaddingBottom, + barClosedWidth, + barHandlerWidth, + barColorMain, + barColorBackground, + barColorActive, + barColorBorder, + barColorScrollbarTrack, + barColorScrollbarThumb, + }) { + this.barAttribute = barAttribute || 'js-resizable_bar'; + this.barOpenMaxWidthRatio = barOpenMaxWidthRatio || 0.2; + this.barOpenMinWidth = barOpenMinWidth || 77; + // styles + this.barPadding = barPadding || 'calc(var(--base-rhythm, 8px)*2)'; + this.barPaddingBottom = barPaddingBottom || 'calc(var(--base-rhythm, 8px)*8)'; + this.barClosedWidth = barClosedWidth || 12; + this.barHandlerWidth = barHandlerWidth || 8; + this.barColorMain = barColorMain || 'var(--color-fg-main, Black)'; + this.barColorBackground = barColorBackground || 'var(--color-bg-main, White)'; + this.barColorActive = barColorActive || 'var(--color-fg-accent, currentColor)'; + this.barColorBorder = barColorBorder || 'var(--color-border, rgba(0,0,0,0.1))'; + this.barColorScrollbarTrack = barColorScrollbarTrack || 'var(--scrollbarBG, transparent)'; + this.barColorScrollbarThumb = barColorScrollbarThumb || 'var(--thumbBG, rgba(0,0,0,.05))'; + + // state + this.state = { + current: { + id: null, + direction: null, // 1||-1 + pageX: null + } + }; + + this.initialState = 'open'; + this.initialWidth = `${this.barOpenMaxWidthRatio * 100}vw`; + this.initialStyle = ``; + + // subscribe + const _this = this; + this._mouseDownHandler = (e) => {_this._onMouseDown(e)}; + this._mouseMoveHandler = (e) => {_this._onMouseMove(e)}; + this._mouseUpHandler = (e) => {_this._onMouseUp(e)}; + this._toggleHandler = (e) => {_this._toggle(e)}; + } + + init() { + this._insertInitialBarStyle(); + this._insertInitialPreloaderStyle(); + } + + render() { + this._renderBars(); + this._insertBarStyle(); + this._insertPreloaderStyle(); + } + + // render + + _renderBars() { + [...document.querySelectorAll(`[${this.barAttribute}]`)] + .forEach((bar) => { + const id = bar.getAttribute(this.barAttribute); + const position = bar.dataset.position; + const direction = (bar.dataset.position === 'left') ? 1 : -1;; + const state = this._sessionStorageGetItem(id, 'state') || this.initialState; + const width = this._sessionStorageGetItem(id, 'width'); + + // Read data from element and from Storage + // and set to State: + this._setState({ + id: id, + element: bar, + position: position, + direction: direction, + state: state, + width: width, + }); + + // Update Bar with data from Storage: + this._updateBar(id); + + // Wrap the bar content in the created scrolling element: + const wrapper = this._createScrollableWrapper(id); + [ ...bar.childNodes ].forEach(child => wrapper.appendChild(child)); + bar.appendChild(wrapper); + + // Add control elements: + bar.append(this._createHandler(id)); + + // Add testID: + this._addTestID(bar, id, 'bar'); + }); + } + + _adjustWidth(width) { + let adjustedWidth = width; + const max = window.innerWidth * this.barOpenMaxWidthRatio; + if(width && width < this.barOpenMinWidth) { + adjustedWidth = this.barOpenMinWidth + } + if(width && width > max) { + adjustedWidth = null; + } + return adjustedWidth; + } + + // session storage + + _sessionStorageGet() { + return JSON.parse(sessionStorage.getItem('resizableBarStorage')) + } + + _sessionStorageSet(obj) { + const string = JSON.stringify(obj); + sessionStorage.setItem('resizableBarStorage', string) + } + + _sessionStorageGetItem(id, item) { + const storage = this._sessionStorageGet(); + const value = (storage && storage[id]) ? storage[id][item] : null; + return value; + } + + _sessionStorageSetItem(id, item, value) { + let storage = this._sessionStorageGet() || {}; + storage = { + ...storage, + [id]: { + ...storage[id], + [item]: value, + }, + }; + this._sessionStorageSet(storage); + } + + // state + + _setState({ + id, + element, + state, + position, + direction, + width, + }) { + this.state[id] = { + element: element, + state: state, + position: position, + direction: direction, + width: width, + }; + } + + _updateState({ + id, + element, + state, + position, + direction, + width, + }) { + console.assert(id, '_updateState(): ID must be provided'); + if (!this.state[id]) { this.state[id] = {} } + if (element) { this.state[id].element = element; } + if (state) { this.state[id].state = state; } + if (position) { this.state[id].position = position; } + if (direction) { this.state[id].direction = direction; } + if (width || width===null) { this.state[id].width = width; } + } + + // current + + _updateCurrent(e) { + if (e.type == "mousedown") { + // When we start a new resize, we update the currents: + this.state.current.id = e.target.dataset.content; + this.state.current.pageX = e.pageX; + this.state.current.startWidth = this.state[this.state.current.id].element.offsetWidth; + } else { + // e.type == "mouseup" + // At the end of the resize: + this.state.current.id = null; + this.state.current.pageX = null; + this.state.current.startWidth = null; + } + } + + // elements + + _addTestID(element, id, attr) { + element.dataset.testid = `${id}-${attr}`; + } + + _updateBar(id) { + const barState = this.state[id]; + const bar = this.state[id].element; + bar.dataset.position = barState.position; + bar.dataset.state = barState.state; + this._updateBarWidth(bar, barState.width); + } + + _updateBarWidth(bar, width) { + // If there is no specific width, set the maximum. + // The style tag cannot be left empty to override the preloaded styles + // set for each bar with the width taken from the storage + // before the page is rendered. + bar.style.width = width ? `${width}px` : `${this.barOpenMaxWidthRatio * 100}vw`; + } + + _createHandler(id) { + const handler = document.createElement('div'); + handler.setAttribute(`${this.barAttribute}-handler`, ''); + handler.dataset.content = id; + handler.style[this.state[id].position] = 'unset'; // 'left | right' + + const border = document.createElement('div'); + border.setAttribute(`${this.barAttribute}-border`, ''); + border.dataset.content = id; + border.title = `Resize ${id}`; + border.addEventListener('mousedown', this._mouseDownHandler); + + const button = document.createElement('div'); + button.setAttribute(`${this.barAttribute}-button`, ''); + button.dataset.content = id; + button.title = `Toggle ${id}`; + button.addEventListener('mousedown', this._toggleHandler); + + // Add testIDs: + this._addTestID(border, id, 'handler-border'); + this._addTestID(button, id, 'handler-button'); + + handler.append(border, button); + return handler; + } + + _createScrollableWrapper(id, direction = 'y') { + const wrapper = document.createElement('div'); + wrapper.setAttribute(`${this.barAttribute}-scroll`, direction); + wrapper.dataset.content = id; + return wrapper; + } + + // event listeners + + _onMouseDown(e) { + // Init resizing + if (e.button == 0) { + e.preventDefault(); + this._updateCurrent(e); + window.addEventListener('mousemove', this._mouseMoveHandler); + window.addEventListener('mouseup', this._mouseUpHandler); + } + } + + _onMouseMove(e) { + // Resizing + const currentId = this.state.current.id; + const currentX = this.state.current.pageX; + const currentStartWidth = this.state.current.startWidth; + const currentBar = this.state[currentId].element; + + // todo: _onMouseUp() does not always stop execution of requestAnimationFrame, + // and after the correct width is calculated in _adjustWidth (20vw), + // the extreme width from this function can be set again (for ex.: 789px). + // requestAnimationFrame(() => { + + // currentId exists if a resize has been initiated + if (currentId) { + + // Resize + // * delta: the distance traveled by the mouse, starting from the initial point + const delta = e.pageX - currentX; + // * this.state[currentId].direction = 1 || -1 + // * w: current bar width + this.state.current.width = currentStartWidth + this.state[currentId].direction * delta; + + // Rendering the change in width of the bar: + // currentBar.style.width = w + 'px'; + this._updateBarWidth(currentBar, this.state.current.width); + + // Close/Open + if (this.state.current.width < this.barOpenMinWidth) { + if (this.state[currentId].state == 'open') { + this._close(currentId); + } + } else { + if (this.state[currentId].state == 'closed') { + this._open(currentId); + } + } + } + + // }) + } + + _onMouseUp(e) { + // Clean up after work + window.removeEventListener('mousemove', this._mouseMoveHandler); + window.removeEventListener('mouseup', this._mouseUpHandler); + + const currentWidth = this._adjustWidth(this.state.current.width); + this._updateState({ id: this.state.current.id, width: currentWidth }); + this._sessionStorageSetItem(this.state.current.id, 'width', currentWidth); // WRITE DATA TO STORAGE + this._updateBar(this.state.current.id); + this._updateCurrent(e); + } + + _toggle(e) { + if (e.button == 0) { + const id = e.target.dataset.content; + this.state[id].state = this.state[id].state === 'open' + ? 'closed' + : 'open'; + this._sessionStorageSetItem(id, 'state', this.state[id].state); + this._updateBar(id); + } + } + + _open(id) { + this.state[id].state = 'open'; + this._sessionStorageSetItem(id, 'state', this.state[id].state); + this._updateBar(id); + } + + _close(id) { + this.state[id].state = 'closed'; + this._sessionStorageSetItem(id, 'state', this.state[id].state); + this._updateBar(id); + } + + // styles + + _insertStyle(css, attr) { + const style = document.createElement('style'); + style.setAttribute(`${this.barAttribute}-${attr}`, ''); + style.textContent = css; + document.head.append(style); + } + + _insertInitialBarStyle() { + const storage = this._sessionStorageGet(); + + let initStyle = `[${this.barAttribute}]{width:${this.barOpenMaxWidthRatio * 100}vw}`; + + // Add styles based on data from Storage: + for (let id in storage) { + const w = (storage[id].state == 'closed') ? this.barClosedWidth : storage[id].width; + // If w = null (this is possible if so in the storage), + // the base style will be in effect: + w && (initStyle += `[${this.barAttribute}="${id}"]{width:${w}px}`); + } + + this._insertStyle(initStyle, 'initial-style') + } + + _insertBarStyle() { + let barStyle = ` +[${this.barAttribute}] { + position: relative; + height: 100%; + max-width: ${this.barOpenMaxWidthRatio * 100}vw; +} + +[${this.barAttribute}]:hover { + z-index: 22; +} + +[${this.barAttribute}][data-state="open"] { + min-width: ${this.barOpenMinWidth}px; + pointer-events: auto; +} +[${this.barAttribute}][data-state="closed"] { + max-width: ${this.barClosedWidth}px; + min-width: ${this.barClosedWidth}px; + pointer-events: none; + transition: .5s; +} + +[${this.barAttribute}][data-position="left"] { + border-left: none; +} +[${this.barAttribute}][data-position="right"] { + border-right: none; +} + +[${this.barAttribute}-handler] { + pointer-events: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 10; + width: ${this.barHandlerWidth}px; + color: ${this.barColorActive}; +} + +[${this.barAttribute}-border] { + pointer-events: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: ${this.barHandlerWidth}px; + background: transparent; + transition: .3s; + cursor: col-resize; +} + +[${this.barAttribute}][data-state="closed"] [${this.barAttribute}-border] { + cursor: e-resize; +} + +[${this.barAttribute}-border]::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 1px; + background: ${this.barColorBorder}; + transition: .3s; +} + +[${this.barAttribute}-border]::after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: ${0.5 * this.barHandlerWidth}px; + background: transparent; + transition: .3s; +} + +[${this.barAttribute}][data-position="left"] [${this.barAttribute}-border]::before { + right: 0; + left: unset; +} +[${this.barAttribute}][data-position="left"] [${this.barAttribute}-border]::after { + right: ${-0.25 * this.barHandlerWidth}px; + left: unset; +} + +[${this.barAttribute}][data-position="right"] [${this.barAttribute}-border]::before { + right: unset; + left: 0; +} +[${this.barAttribute}][data-position="right"] [${this.barAttribute}-border]::after { + right: unset; + left: ${-0.25 * this.barHandlerWidth}px; +} + +[${this.barAttribute}-border]:hover::after { + background: ${this.barColorActive}; +} + +[${this.barAttribute}-button] { + cursor: pointer; + position: absolute; + z-index: 2; + left: 0; + right: 0; + top: ${-1 * this.barHandlerWidth}px; + box-sizing: border-box; + width: ${2 * this.barHandlerWidth}px; + height: ${2 * this.barHandlerWidth}px; + font-size: ${1.5 * this.barHandlerWidth}px; + font-weight: bold; + border-radius: 50%; + border-width: 1px; + border-style: solid; + border-color: ${this.barColorBackground}; + background: ${this.barColorBackground}; + color: ${this.barColorActive}; + transition: .3s; +} + +[data-position="right"] [${this.barAttribute}-button] { + right: 0; + left: unset; +} +[data-position="left"] [${this.barAttribute}-button] { + left: 0; + right: unset; +} + +[${this.barAttribute}-button]:hover { + color: ${this.barColorMain}; + border-color: ${this.barColorMain}; +} + +/* ❮❯ */ +[${this.barAttribute}-button]::after { + content: '❮'; + position: absolute; + display: flex; + align-items: center; + justify-content: center; + left: 0; + right: 0; + top: ${-1 * this.barHandlerWidth}px; + bottom: ${-1 * this.barHandlerWidth}px; +} +[${this.barAttribute}][data-state="open"] [${this.barAttribute}-button]::after, +[${this.barAttribute}][data-state="open"][data-position="left"] [${this.barAttribute}-button]::after, +[${this.barAttribute}][data-state="closed"][data-position="right"] [${this.barAttribute}-button]::after { + content: '❮'; +} +[${this.barAttribute}][data-state="closed"] [${this.barAttribute}-button]::after, +[${this.barAttribute}][data-state="closed"][data-position="left"] [${this.barAttribute}-button]::after, +[${this.barAttribute}][data-state="open"][data-position="right"] [${this.barAttribute}-button]::after { + content: '❯'; +} + +[${this.barAttribute}-scroll] { + height: 100%; + overflow-x: hidden; + overflow-y: scroll; + /*padding: ${this.barPadding}; + padding-bottom: ${this.barPaddingBottom};*/ + scrollbar-color: ${this.barColorScrollbarTrack} ${this.barColorScrollbarTrack}; +} +[${this.barAttribute}-scroll='y'] { + overflow-x: hidden; + overflow-y: scroll; +} +[${this.barAttribute}-scroll]:hover { + scrollbar-color: ${this.barColorScrollbarThumb} ${this.barColorScrollbarTrack}; +} +[${this.barAttribute}-scroll]::-webkit-scrollbar-thumb { + background-color: ${this.barColorScrollbarTrack}; +} +[${this.barAttribute}-scroll]:hover::-webkit-scrollbar-thumb { + background-color: ${this.barColorScrollbarThumb} +} + +[data-state="closed"] [${this.barAttribute}-scroll] { + display: none; +} +`; + + this._insertStyle(barStyle, 'style'); + } + + _insertInitialPreloaderStyle() { + let style = ` + aside { + /* for a pseudo preloader [js-resizable_bar]::after, affects: layout_tree,layout_toc */ + position: relative; + } + [${this.barAttribute}]::after { + display: flex; + align-items: center; + justify-content: center; + content: ''; + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 2; + background-color: ${this.barColorBackground}; + } + `; + + this._insertStyle(style, 'initial-preloader-style'); + } + + _insertPreloaderStyle() { + let style = ` + [${this.barAttribute}]::after { + opacity: 0; + transition: .3s; + pointer-events: none; + } + `; + + this._insertStyle(style, 'preloader-style'); + } +} + +const resizableBar = new ResizableBar({}); +resizableBar.init(); + +window.addEventListener("load", function () { + resizableBar.render(); +}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.css new file mode 100644 index 0000000..16df13a --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.css @@ -0,0 +1,283 @@ +.project_coverage { + width: 100%; + /* font-size: 0.875rem; */ +} + +.project_coverage thead { + position: sticky; + z-index: 1; + top: calc(-1 * var(--base-gap)); /* compensate .main top padding when scrolling */ +} + +.project_coverage thead th { + /* adding a background prevents the th-button background from working */ + vertical-align: bottom; + border-bottom: var(--base-border); + font-size: 0.875em; +} + +.project_coverage thead::before { + content: ''; + position: absolute; + z-index: -1; + left: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */ + right: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */ + top: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */ + bottom: 0; + background: var(--color-bg-main); +} + +.project_coverage th, +.project_coverage td { + padding: calc(0.5 * var(--base-rhythm)) var(--base-rhythm); + border-right: var(--base-border); + position: relative; +} + +.project_coverage td { + text-align: right; +} + +.project_coverage th:last-child, +.project_coverage td:last-child { + border-right: none; +} + +.project_coverage tr:first-child th:first-child, /* tr compensate colspan */ +.project_coverage td:first-child { + width: auto; + text-align: left; +} + +.project_coverage td:not(:first-child) { + width: 1px; + white-space: nowrap; +} + +.project_coverage tr.project_coverage-file:hover { + background: rgba(255,255,255,0.3); +} + +.project_coverage tr.project_coverage-folder td { + padding-right: 0; +} + +.project_coverage-folder-title { + /* font-weight: bold; */ + display: flex; + align-items: flex-end; + column-gap: calc(0.5 * var(--base-rhythm)); + /* font-size: 0.75em; */ + line-height: 1; + color: #999; + padding: calc(0.5 * var(--base-rhythm)); + position: relative; + background: var(--color-bg-secondary); +} + +.project_coverage-file-link { + display: flex; + /* column-gap: var(--base-rhythm); */ + padding: calc(0.5 * var(--base-rhythm)); + border-radius: calc(0.5 * var(--base-rhythm)); + transition: background .3s; + border: 1px solid rgba(255,255,255,0); +} + +.project_coverage-file-icon {} + +.project_coverage-file-title { + font-size: 1em; + font-weight: 500; + line-height: 1.2; + transition: color .2s; + display: flex; + column-gap: var(--base-rhythm); +} + +.project_coverage-file-path { + font-size: 0.75em; + color: var(--color-fg-secondary); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + position: absolute; + left: 0; + right: 0; + bottom: 0; + display: none; +} + +.project_coverage-file-details { + position: relative; + flex-grow: 1; +} + +.project_coverage-file-link:not([href]):hover { + /* color: gray; */ + /* all this file have no links -> they are red */ +} + +.project_coverage-file_uncovered .project_coverage-file-link, +.project_coverage-file_uncovered .project_coverage-file-title { + color: var(--color-danger); + font-weight: 400 !important; +} + +.project_coverage-file-link[href]:hover .project_coverage-file-icon, +.project_coverage-file-link[href]:hover .project_coverage-file-title { + color: var(--color-fg-accent); +} + +.project_coverage-file-link[href] .project_coverage-file-icon, +.project_coverage-file-link[href] .project_coverage-file-title { + color: var(--color-fg-main); +} + +/* cols */ + +.project_coverage-col-line { + background-color: rgba(255, 155, 0, 0.05) !important; +} + +.project_coverage-col-func { + background-color: rgba(175, 0, 255, 0.05) !important; +} + +.sorted_col.project_coverage-col-line, +th.project_coverage-col-line { + background-color: rgba(255, 155, 0, 0.15) !important; +} + +.sorted_col.project_coverage-col-func, +th.project_coverage-col-func { + background-color: rgba(175, 0, 255, 0.15) !important; +} + +/* value_extended */ + +.value_extended[data-ext]::after { +content: attr(data-ext); +margin-left: 2px; +font-size: 0.85em; +font-weight: 200; +} + +/* project_coverage-sort_handler */ + +.project_coverage-sort_handler { + cursor: pointer; +} + +.project_coverage-sort_handler::after { + content: '○'; + display: block; +} + +.project_coverage-sort_handler::before { + content: ''; + cursor: pointer; + position: absolute; + inset: 0; + z-index: -1; +} + +.project_coverage-sort_handler:hover { + color: var(--color-blue); +} + +.project_coverage-sort_handler:hover::before { + border: 3px solid white; +} + +.project_coverage-sort_handler[sorted]::before { + border: 3px solid white; +} + +/* ▿ ▵ △ ▽ ▾ ▴ */ + +.project_coverage-sort_handler:hover::after { + /* the first act: desc */ + content: '▽'; +} + +.project_coverage-sort_handler[sorted='asc']::after { + content: '▴'; +} + +.project_coverage-sort_handler[sorted='dsc']::after { + content: '▾'; +} + +.project_coverage-sort_handler[sorted='dsc']:hover::after { + content: '△'; +} + +.project_coverage-sort_handler[sorted='asc']:hover::after { + content: '▽'; +} + +/* sort_reset */ + +.project_coverage-sort_reset { + display: flex; + flex-direction: column; + gap: var(--base-padding); +} + +.project_coverage-sort_reset::after { + content: ' '; + display: block; +} + +/* sorted sort_reset */ + +.project_coverage.sorted .project_coverage-sort_reset { + cursor: pointer; +} + +.project_coverage.sorted .project_coverage-sort_reset::after { + content: 'reset sorting'; + font-weight: 400; + text-align: right; + color: var(--color-fg-accent); +} + +.project_coverage.sorted .project_coverage-sort_reset::before { + content: ''; + cursor: pointer; + position: absolute; + inset: 0; + z-index: -1; +} + +.project_coverage.sorted .project_coverage-sort_reset:hover::before { + background-color: rgb(255 255 255 / 50%); +} + +/* sorted mods */ + +.project_coverage.sorted .project_coverage-folder, +.project_coverage.sorted .project_coverage-file-indent { + display: none; +} + +.project_coverage.sorted .project_coverage-file-path { + display: block; +} + +.project_coverage.sorted .project_coverage-file-details { + position: relative; + flex-grow: 1; + padding: 0 0 var(--base-padding) 0; +} + +/* color */ + +.color-secondary { + color: var(--color-fg-secondary); +} + +.color-uncovered { + color: var(--color-danger); +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.js new file mode 100644 index 0000000..64fbc86 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_coverage_screen.js @@ -0,0 +1,73 @@ +// @relation(SDOC-SRS-35, scope=file) + +document.addEventListener("DOMContentLoaded", () => { + const table = document.querySelector(".project_coverage"); + const tbody = table.querySelector("tbody"); + const originalRows = Array.from(tbody.rows); + let sortState = null; + + const handlers = table.querySelectorAll(".project_coverage-sort_handler"); + const colgroupCols = table.querySelectorAll("colgroup col"); + + handlers.forEach((handler) => { + handler.addEventListener("click", () => { + + const dataId = handler.getAttribute("data-id"); + // We expect: + // - Each .project_coverage-sort_handler has a unique data-id + // - Each contains matching the same data-id + + console.assert(dataId, "Missing data-id on sort handler."); + if (!dataId) return; + + const isSameColumn = sortState && sortState.id === dataId; + const asc = isSameColumn ? !sortState.asc : false; + + const rows = Array.from(tbody.rows); + const validRows = rows.filter(row => + row.classList.contains("project_coverage-file") && + row.querySelector(`td[data-id="${dataId}"]`) + ); + if (validRows.length === 0) return; + + validRows.sort((a, b) => { + const aCell = a.querySelector(`td[data-id="${dataId}"]`); + const bCell = b.querySelector(`td[data-id="${dataId}"]`); + const aVal = parseFloat(aCell?.dataset.value || '0'); + const bVal = parseFloat(bCell?.dataset.value || '0'); + return asc ? aVal - bVal : bVal - aVal; + }); + + tbody.innerHTML = ""; + validRows.forEach(row => tbody.appendChild(row)); + table.classList.add("sorted"); + + handlers.forEach(h => h.removeAttribute("sorted")); + handler.setAttribute("sorted", asc ? "asc" : "dsc"); + + sortState = { id: dataId, asc }; + + // Highlight active + colgroupCols.forEach(col => col.classList.remove("sorted_col")); + const activeCol = table.querySelector(`colgroup col[data-id="${dataId}"]`); + if (activeCol) { + activeCol.classList.add("sorted_col"); + } else { + console.warn(`No found for data-id="${dataId}"`); + } + }); + }); + + const resetter = table.querySelector(".project_coverage-sort_reset"); + if (resetter) { + resetter.addEventListener("click", () => { + tbody.innerHTML = ""; + originalRows.forEach(row => tbody.appendChild(row)); + table.classList.remove("sorted"); + handlers.forEach(h => h.removeAttribute("sorted")); + colgroupCols.forEach(col => col.classList.remove("sorted_col")); + sortState = null; + }); + } +}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.css new file mode 100644 index 0000000..06a393a --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.css @@ -0,0 +1,410 @@ +* { + margin: 0; + padding: 0; +} + +[data-viewtype="source-file"] { + --source-line: 1px solid rgba(0, 0, 0, .05); +} + +[data-viewtype="source-file"] .layout { + grid-template-columns: + fit-content(var(--base-gap)) + minmax(222px, 22%) /* replaced: fit-content(20%) */ + fit-content(20%) + minmax(0, 1fr) + fit-content(20%) + auto; + grid-template-areas: + "nav header header header header aside" + "nav tree bar_left main bar_right aside" + "nav footer footer footer footer aside"; +} + +/* left panel */ + +.source-file__aside { + display: flex; + flex-direction: column; + height: 100%; +} + +/* left scrollable panel */ + +.source-file__refer { /* wrapper */ + position: relative; + height: 100%; + overflow-y: hidden; +} + +.source-file__toc { + position: relative; + height: 100%; + overflow-y: scroll; + padding: calc(var(--base-padding)*2) + calc(var(--base-padding) / 2) + calc(var(--base-padding)*4) + calc(var(--base-padding) / 1); + + font-size: var(--font-size-sm); + + transition: margin-left .5s; + scrollbar-color: transparent var(--scrollbarBG); +} + +.source-file__toc:hover { + scrollbar-color: var(--thumbBG) var(--scrollbarBG); +} + +.source-file__toc::-webkit-scrollbar-thumb { + background-color: transparent; +} + +.source-file__toc:hover::-webkit-scrollbar-thumb { + background-color: var(--thumbBG) +} + +.source-file__toc-range { + background-color: var(--color-highlight-secondary); + border-radius: var(--base-rhythm); + margin-bottom: var(--tree-gap); +} + +.source-file__toc-range-header { + padding: var(--base-rhythm); +} + +.source-file__toc-range-node { + border-top: 2px solid var(--color-bg-main); +} + +.source-file__toc-node { + border-top: 1px solid var(--color-border); + margin-bottom: 2rem; +} + +/* SDOC-NODE in SOURCE */ + +.source-file__requirement { + position: relative; + padding: var(--base-rhythm) 0; + transition: background-color 0.3s ease-in, border-color 0.3s ease-in; + font-size: var(--font-size-xsm); + display: flex; + flex-direction: column; + align-items: stretch; + gap: 0.25rem; +} + +.source-file__requirement-links { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 0.25rem; + margin-top: var(--base-rhythm); +} + +.source-file__requirement-info { + word-break: break-word; +} + +.source-file__requirement-uid { + display: block; + position: relative; + font-weight: bold; + word-break: break-word; +} + +.source-file__requirement details { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 0.25rem; +} + +.source-file__requirement summary { + list-style: none; + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + position: relative; + gap: var(--base-rhythm); + align-items: flex-start; +} + +.source-file__requirement summary::-webkit-details-marker { + display: none; +} + +.source-file__requirement summary::after { + content: "➕"; + user-select: none; + padding: calc(var(--base-rhythm) / 2); + margin-left: auto; + transition: transform 0.2s; + font-size: 8px; + color: var(--color-link); +} + +.source-file__requirement:hover summary::after { + color: var(--color-hover); +} + +.source-file__requirement details[open] summary::after { + content: "➖"; +} + +.source-file__requirement-header { + display: flex; + gap: var(--base-rhythm); + align-items: flex-start; /* to push action icon to top */ +} + +/* requirement_file */ + +[data-viewtype="source-file"] .requirement_file li { + position: relative; +} + +[data-viewtype="source-file"] .requirement_file li > a, +[data-viewtype="source-file"] .requirement_file li > span { + display: inline-block; + padding: .15rem .25rem .15rem 0; + line-height: 1; +} + +[data-viewtype="source-file"] .current_file_pseudolink { + font-weight: bold; + color: #808080; +} + +/* CODE */ + +.source-file__source { + /* position: relative; */ + position: absolute; + inset: 0px; + left: var(--tree-gap); + overflow: auto; + + padding: var(--tree-gap) 0 calc(var(--tree-gap)*10); + transition: box-shadow 0.3s ease-in; +} + +.source-file__source .sdoc-table_key_value { + /* font-size: var(--font-size-sm); */ + font-size: 14px; + min-width: 100%; + margin-bottom: var(--tree-gap); +} + +.source { + display: grid; + grid-template-columns: + minmax(min-content, max-content) + minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */ + gap: 0 0; + place-items: stretch stretch; + transition: transform 0.3s ease-in; + position: relative; + + min-width: 100%; + width: max-content; + + font-size: 14px; + z-index: 1; +} + +.source_highlight { + position: absolute; + left: 0; + right: 0; + background-color: var(--color-highlight); + z-index: -1; + transition: height 0.3s ease-in, top 0.3s ease-in; +} + +/* source__range */ + +.source__range { + grid-column: 1 / -1; + display: contents; +} + +.source__range-closer { + grid-column: 1 / -1; + /* margin-bottom: var(--tree-gap); */ + margin-bottom: var(--base-padding); +} + +.source__range-closer-label { + display: flex; + border-radius: 0 0 6px 6px; + column-gap: calc(var(--base-rhythm)* 1); + background-color: var(--color-highlight-secondary); + padding: var(--base-rhythm); +} + +.source__range-closer-label .source__range-definition::before { + content: 'End of'; + display: inline-block; + margin-right: 6px; +} + +.focus .source__range:not(.active), +.focus .source__range-closer:not(.active) { + display: none; +} + +.source__range-cell { + background-color: var(--color-highlight-secondary); +} + +.source__range-header { + grid-column: 1 / -1; + background-color: var(--color-highlight-secondary); + padding: var(--base-rhythm); + margin-top: var(--tree-gap); + border-top-left-radius: var(--base-rhythm); +} + +.source__range-button { + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + height: 100%; +} + +.source__range-banner { + padding: 0 1rem 1rem 0; +} + +.source__range.collapsed .source__range-banner { + display: none; +} + +ul.source__range-titles-list { + margin: var(--base-rhythm); + list-style-type: none; +} + +.source__range.collapsed .source__range-titles-list { + display: block; +} + +.source__range.expanded .source__range-titles-list { + display: none; +} + +.source__range-title-icon { + cursor: help; +} + +/* sdoc-node-content */ + +.source__range-banner sdoc-node-content[node-view="table"] sdoc-node-field-label { + background-color: var(--requirement-bg-light-color); +} + +/* source__range-handler */ + +.source__range-handler { + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + height: 100%; + color: var(--color-link); +} + +.source__range-handler:hover { + color: var(--color-hover); +} + +.source__range .source__range-handler .expanded, +.source__range.expanded .source__range-handler .collapsed { + display: none; +} + +.source__range .source__range-handler .collapsed, +.source__range.expanded .source__range-handler .expanded { + display: unset; +} + +/* source__line */ + +.source__line { + grid-column: 1 / -1; + display: contents; +} + +.source.coverage .source__line.covered > div { + background: rgba(75, 255, 0, 0.2); +} + +.source__line.highlighted > div { + background: var(--color-highlight) !important; +} + +/* line-number */ + +.source__line-number { + grid-column: 1 / 2; + padding: 0.25rem 1rem 0.25rem 2rem; + text-align: right; + border-bottom: var(--source-line); + color: var(--color-fg-secondary); + background: var(--color-bg-contrast); + user-select: none; + position: relative; +} + +/* line content */ + +.source__line-content { + grid-column: 2 / 3; + padding: 0.25rem 1rem 0.25rem .5rem; + border-bottom: var(--source-line); + border-left: var(--source-line); + background: var(--color-bg-contrast); +} + +/* pointers */ + +.source__range-pointer { + display: inline-block; + padding-left: calc(var(--base-rhythm)* 1); + padding-right: calc(var(--base-rhythm)* 1); + border-radius: 6px; +} + +.source__range-pointer.active { + background-color: var(--color-highlight) !important; + color: var(--color-fg-contrast) !important; +} + +.focus .source__range-pointer.active { + outline: solid 3px yellow; +} + +.source__range-pointer .source__range-pointer_description { + font-weight: normal; + word-break: break-word; +} + +.source__range-definition { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100%; + min-width: 0; + display: inline-block; +} + +/* Pygments */ + +.highlight { + background: transparent !important; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.js new file mode 100644 index 0000000..8e47e20 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/source_file_screen.js @@ -0,0 +1,642 @@ +// @relation(SDOC-SRS-36, scope=file) + +const __log = (topic, ...payload) => { + console.log(`%c ${topic} `, 'background:yellow;color:black', + ...payload + ); +} + +class SimpleTabs { + constructor(tabsContainer, tabContentSelector = "sdoc-tab-content") { + this.tabsContainer = tabsContainer; + this.tabContents = document.querySelectorAll(tabContentSelector); + this.tabs = tabsContainer.querySelectorAll("sdoc-tab"); + this._init(); + } + + _init() { + this.tabs.forEach((tab) => { + tab.addEventListener("click", () => { + this.activateTab(tab.innerText.trim()); + }); + }); + + // Activate the tab marked as active, or the first one + const activeTab = [...this.tabs].find((t) => t.hasAttribute("active")) || this.tabs[0]; + this.activateTab(activeTab.innerText.trim()); + } + + activateTab(tabName) { + this.tabs.forEach((tab) => { + if (tab.innerText.trim() === tabName) { + tab.setAttribute("active", ""); + } else { + tab.removeAttribute("active"); + } + }); + + this.tabContents.forEach((content) => { + if (content.id === tabName) { + content.setAttribute("active", ""); + } else { + content.removeAttribute("active"); + } + }); + } +} + +class Switch { + constructor({ + callback, + labelText, + checked, + componentClass, + colorOn, + colorOff, + size, + stroke, + units, + alignRight, + }) { + this.colorOn = colorOn || 'rgb(100, 200, 50)'; + this.colorOff = colorOff || 'rgb(200, 200, 200)'; + this.labelText = labelText || ''; + this.checked = checked || false; // todo: replace true/false with strings + + this.componentClass = componentClass || 'std-switch-scc'; + this.size = size || 0.75; + this.stroke = stroke || 0.25; + this.units = units || 'rem'; + this.alignRight = alignRight || true; + + this.callback = callback; + } + + create() { + const block = document.createElement('div'); + block.classList.add(this.componentClass); + const label = document.createElement('label'); + label.classList.add(`${this.componentClass}__label`); + const input = document.createElement('input'); + input.classList.add(`${this.componentClass}__input`); + input.type = 'checkbox'; + input.checked = this.checked; + const slider = document.createElement('span'); + slider.classList.add(`${this.componentClass}__slider`); + const text = document.createElement('span'); + text.innerHTML = this.labelText; + + input.addEventListener('change', () => this.callback(input.checked)); + + label.append(input, slider, text); + block.append(label); + this.insertStyle(); + + return block; + } + + insertStyle() { + + const css = ` + .${this.componentClass} { + display: inline-block; + line-height: 0; + } + .${this.componentClass}__label { + display: inline-flex; + gap: ${this.size * 0.5}${this.units}; + font-size: ${this.size * 1.5}${this.units}; /* 0.75rem; */ + line-height: ${this.size}${this.units}; + align-items: center; + justify-content: flex-start; + user-select: none; + cursor: pointer; + flex-direction: ${this.alignRight ? "row-reverse" : "row"}; + text-align: ${this.alignRight ? "right" : "left"}; + } + .${this.componentClass}__input { + opacity: 0; + width: 0; + height: 0; + position: absolute; + } + .${this.componentClass}__slider { + position: relative; + cursor: pointer; + background-color: ${this.colorOff}; + -webkit-transition: .4s; + transition: .4s; + display: inline-block; + width: ${this.size * 2 + this.stroke * 2}${this.units}; + height: ${this.size + this.stroke * 2}${this.units}; + border-radius: ${this.size * 0.5 + this.stroke}${this.units}; + } + .${this.componentClass}__slider::before { + position: absolute; + content: ""; + height: ${this.size}${this.units}; + width: ${this.size}${this.units}; + left: ${this.stroke}${this.units}; + bottom: ${this.stroke}${this.units}; + background-color: white; + -webkit-transition: .4s; + transition: .4s; + border-radius: 50%; + } + input:checked + .${this.componentClass}__slider { + background-color: ${this.colorOn}; + } + input:focus + .${this.componentClass}__slider { + box-shadow: 0 0 1px ${this.colorOn}; + } + input:checked + .${this.componentClass}__slider::before { + -webkit-transform: translateX(${this.size}${this.units}); + -ms-transform: translateX(${this.size}${this.units}); + transform: translateX(${this.size}${this.units}); + } + `; + + const head = document.querySelector('head'); + const style = document.createElement('style'); + style.append(document.createTextNode(css)); + style.setAttribute("data-slider-styles", ''); + head.append(style); + } + +} + +class Dom { + constructor({ + sourceId, + sourceContainerId, + referContainerId, + hashSplitter, + strictdocPointerSelector, + strictdocRequirementSelector, + strictdocRangeBannerSelector, + strictdocRangeBannerHeaderSelector, + strictdocRangeHandlerSelector, + strictdocRangeCloserSelector, + strictdocLineSelector, + strictdocLineNumberSelector, + strictdocLineContentSelector, + strictdocLineRangeSelector, + strictdocSourceFilterClass, + filteredClass, + coveredClass, + activeClass, + collapsedClass, + expandedClass, + coverageClass, + highlightClass, + focusClass, + }) { + + // CONSTANTS + this.sourceId = sourceId || 'source'; + this.sourceContainerId = sourceContainerId || 'sourceContainer'; + this.referContainerId = referContainerId || 'referContainer'; + this.hashSplitter = hashSplitter || '#'; + + // STRICTDOC SPECIFIC + this.strictdocPointerSelector = strictdocPointerSelector || '.source__range-pointer'; + this.strictdocRequirementSelector = strictdocRequirementSelector || '.source-file__requirement'; + this.strictdocRangeBannerSelector = strictdocRangeBannerSelector || '.source__range'; + this.strictdocRangeBannerHeaderSelector = strictdocRangeBannerHeaderSelector || '.source__range-header'; + this.strictdocRangeHandlerSelector = strictdocRangeHandlerSelector || '.source__range-handler'; + this.strictdocRangeCloserSelector = strictdocRangeCloserSelector || '.source__range-closer'; + this.strictdocLineSelector = strictdocLineSelector || '.source__line'; + this.strictdocLineNumberSelector = strictdocLineNumberSelector || '.source__line-number'; + this.strictdocLineContentSelector = strictdocLineContentSelector || '.source__line-content'; + this.strictdocLineRangeSelector = strictdocLineRangeSelector || '.source__line-ranges'; + this.strictdocSourceFilterClass = strictdocSourceFilterClass || 'source__filter'; + this.filteredClass = filteredClass || 'filtered'; + this.activeClass = activeClass || 'active'; + this.coveredClass = coveredClass || 'covered'; + this.coverageClass = coverageClass || 'coverage'; + this.collapsedClass = collapsedClass || 'collapsed'; + this.expandedClass = expandedClass || 'expanded'; + this.highlightClass = highlightClass || 'highlighted'; + this.focusClass = focusClass || 'focus'; + + // elements + this.sourceContainer; + this.referContainer; + this.source; + this.lines = {}; + this.requirements = {}; + this.ranges = {}; + this.closers = {}; + + // state + this.active = { + range: null, + pointers: [], + labels: [], + focus: false, + }; + } + + prepare() { + this._prepareSourceContainer(); + this._prepareReferContainer(); + this._prepareSource(); + + this._prepareLines(); + this._prepareRanges(); + this._updateLinesWithRanges(); + this._updateRangesWithRequirements(); + this._updateRangesWithHandlers(); + this._updateRangesWithBanners(); + this._updateRangesWithClosers(); + + // console.log('this.lines', this.lines); + // console.log('this.ranges', this.ranges); + // console.log('this.closers', this.closers); + // console.log('this.requirements', this.requirements); + // console.log('this.active', this.active); + } + + useLocationHash() { + const [_, reqId, rangeBegin, rangeEnd] = window.location.hash.split(this.hashSplitter); + const rangeAlias = rangeBegin ? this._generateRangeAlias(rangeBegin, rangeEnd) : undefined; + + this.changeActive({ + rangeBegin, + rangeEnd, + rangeAlias, + pointers: rangeAlias ? this.ranges[rangeAlias].pointers : null, + labels: (reqId && rangeAlias) ? this.ranges[rangeAlias][reqId] : null, + }); + + this.highlightRange(); + } + + changeActive = ({ + rangeBegin, + rangeEnd, + rangeAlias, + pointers, + labels, + }) => { + + // remove old 'active' + this.active.pointers?.forEach(pointer => pointer?.classList.remove(this.activeClass)); + this.active.labels?.forEach(label => label?.classList.remove(this.activeClass)); + if (this.active.rangeAlias) { + this.ranges[this.active.rangeAlias].banner.classList.remove(this.activeClass); + + const closer = this.closers?.[this.active.rangeEnd]; + console.assert( + closer, + "Closer must not be null. One known way of getting this error is " + + "when a closing function/range marker is missing and not registered " + + "with the file traceability info." + ); + + closer.classList.remove(this.activeClass); + } + + // make changes to state + this.active.pointers = pointers; + this.active.labels = labels; + this.active.rangeBegin = rangeBegin; + this.active.rangeEnd = rangeEnd; + this.active.rangeAlias = rangeAlias; + + // add new 'active' + this.active.pointers?.forEach(pointer => pointer.classList.add(this.activeClass)); + this.active.labels?.forEach(label => label.classList.add(this.activeClass)); + this.ranges[rangeAlias]?.banner.classList.add(this.activeClass); + this.closers[this.active.rangeEnd]?.classList.add(this.activeClass); + } + + toggleRangeBannerVisibility(handler) { + const banner = handler.closest(this.strictdocRangeBannerSelector); + + if (banner.classList.contains(this.expandedClass)) { + banner.classList.remove(this.expandedClass); + banner.classList.add(this.collapsedClass); + } else { + banner.classList.add(this.expandedClass); + banner.classList.remove(this.collapsedClass); + } + } + + toggleCoverageVisibility(toggler) { + if (toggler) { + this.source.classList.add(this.coverageClass); + } else { + this.source.classList.remove(this.coverageClass); + } + } + + highlightRange() { + this.scrollToActiveRangeIfNeeded(); + + const begin = parseInt(this.active.rangeBegin, 10); + const end = parseInt(this.active.rangeEnd, 10); + + for (var key in this.lines) { + this.lines[key].line.classList.remove(this.highlightClass); + if (key >= begin && key <= end) { + this.lines[key].line.classList.add(this.highlightClass); + } + } + } + + scrollToActiveRangeIfNeeded() { + // scroll to highlighted, do not scroll to top when unset highlighting: + if (this.active.rangeAlias) { + const activeRange = this.ranges[this.active.rangeAlias]?.bannerHeader || 0; + requestAnimationFrame(() => { + this.scrollTo(activeRange); + }); + } + } + + scrollTo(element) { + const top = element.offsetTop || 0; + this.sourceContainer.scrollTo({ + top: top, + behavior: 'smooth', + }); + } + + _prepareSource() { + this.source = document.getElementById(this.sourceId); + this.source.style.position = 'relative'; + this.source.style.zIndex = '1'; + } + + _prepareSourceContainer() { + this.sourceContainer = document.getElementById('sourceContainer'); + } + + _prepareReferContainer() { + this.referContainer = document.getElementById('referContainer'); + } + + _prepareLines() { + this.lines = [...document.querySelectorAll(this.strictdocLineSelector)] + .reduce((acc, line) => { + const lineNumber = line.querySelector(this.strictdocLineNumberSelector); + const lineContent = line.querySelector(this.strictdocLineContentSelector); + acc[line.dataset.line] = { + line: line, + lineNumber: lineNumber, + lineContent: lineContent, + ranges: [] + }; + return acc + }, {}); + } + + _getRangePart(hash) { + const parts = hash.split(this.hashSplitter); + return `${this.hashSplitter}${parts[parts.length - 2]}${this.hashSplitter}${parts[parts.length - 1]}`; + }; + + _prepareRanges() { + [...document.querySelectorAll(this.strictdocPointerSelector)] + .map(pointer => { + const thisFileOrOther = pointer.dataset.traceabilityFileType; + // consider only references to the current file: + if (thisFileOrOther === "other_file") { + return; + } + + const rangeBegin = pointer.dataset.begin; + const rangeEnd = pointer.dataset.end; + const rangeReq = pointer.dataset.reqid; + + const range = this._generateRangeAlias(rangeBegin, rangeEnd); + + if (!this.ranges[range]) { + // add new range + this.ranges[range] = {}; + this.ranges[range].pointers = []; + + this.ranges[range].beginLine = this.lines[rangeBegin].lineNumber; + this.ranges[range].endLine = this.lines[rangeEnd].lineNumber; + this.ranges[range].begin = rangeBegin; + this.ranges[range].end = rangeEnd; + } + + // todo pointers? + if (rangeReq) { + + // add pointer from code + (this.ranges[range][rangeReq] ??= []).push(pointer); + + } else { + + // add pointer from menu + this.ranges[range].pointers.push(pointer); + } + + pointer.addEventListener("click", (event) => { + const targetHash = `#${rangeReq || ""}${this.hashSplitter}${rangeBegin}${this.hashSplitter}${rangeEnd}`; + const currentHash = window.location.hash; + + const isSameHash = currentHash === targetHash; + // Buttons linked to requirements include an ID in the hash, + // while buttons in the source code do not. + // Therefore, only the range part of the hash (e.g., #3#10) + // should be compared to identify the currently active range. + const isSameRange = this._getRangePart(currentHash) === `${this.hashSplitter}${rangeBegin}${this.hashSplitter}${rangeEnd}`; + + const isModifierPressed = event.metaKey || event.ctrlKey; + + const targetBannerHeader = this.ranges[range]?.bannerHeader; + const topBefore = targetBannerHeader?.getBoundingClientRect().top; + + // Modifier click + if (isModifierPressed) { + event.preventDefault(); // cancel opening a new browser tab + + if (isSameRange) { + this._toggleFocus(); + this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore); + } else { + // Sets the URL hash to activate a specific range without reloading the page: + window.location.hash = targetHash; + this.useLocationHash(); + this._activateFocus(); + this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore); + } + return; + } + + // Normal click + if (isSameRange) { + // active → reset + event.preventDefault(); + // Removes hash from URL without reloading or adding history entry: + history.replaceState(null, '', window.location.pathname); + this.useLocationHash(); + this._clearFocus(); + this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore); + } else { + // inactive → just reset the focus, + // the basic functionality via URL will work itself out + this._clearFocus(); + this._compensateSourceContainerScrollPosition(targetBannerHeader, topBefore); + } + }); + + }); + } + + _compensateSourceContainerScrollPosition(element, topBefore) { + // Compensates scroll to keep the given element in the same viewport position. + // Expects the element and its initial .getBoundingClientRect().top value as input. + // Measures element's top offset relative to the viewport before and after DOM changes. + // Uses requestAnimationFrame to wait for DOM/layout updates before measuring again. + // Calculates delta = after - before, i.e. how much the element moved visually. + // Scrolls by that delta to restore the element's original viewport position. + requestAnimationFrame(() => { + const topAfter = element?.getBoundingClientRect().top; + const delta = topAfter - topBefore; + this.sourceContainer.scrollBy({ top: delta }); + }); + } + + _toggleFocus() { + if (this.active.focus) { + this.sourceContainer.classList.remove(this.focusClass); + this.referContainer.classList.remove(this.focusClass); + } else { + this.sourceContainer.classList.add(this.focusClass); + this.referContainer.classList.add(this.focusClass); + } + this.active.focus = !this.active.focus; + } + + _activateFocus() { + if (!this.active.focus) { + this.active.focus = true; + this.sourceContainer.classList.add(this.focusClass); + this.referContainer.classList.add(this.focusClass); + } + } + + _clearFocus() { + if (this.active.focus) { + this.active.focus = false; + this.sourceContainer.classList.remove(this.focusClass); + this.referContainer.classList.remove(this.focusClass); + } + } + + _updateRangesWithRequirements() { + const requirements = [...document.querySelectorAll(this.strictdocRequirementSelector)]; + requirements.forEach(requirement => { + + const rangeBegin = requirement.dataset.begin; + const rangeEnd = requirement.dataset.end; + const rangeReq = requirement.dataset.reqid; + + if (rangeEnd && rangeBegin) { + const range = this._generateRangeAlias(rangeBegin, rangeEnd); + console.assert(this.ranges[range], "The range must be registered:", range); + + (this.ranges[range].requirements ??= {})[rangeReq] = {}; + this.ranges[range].requirements[rangeReq].begin = rangeBegin; + this.ranges[range].requirements[rangeReq].end = rangeEnd; + this.ranges[range].requirements[rangeReq].element = requirement; + } else { + this.requirements[rangeReq] = requirement; + } + + + }) + } + + _updateRangesWithHandlers() { + const handlers = [...document.querySelectorAll(this.strictdocRangeHandlerSelector)]; + handlers.forEach(handler => { + + const rangeBegin = handler.dataset.begin; + const rangeEnd = handler.dataset.end; + const range = this._generateRangeAlias(rangeBegin, rangeEnd); + + console.assert(this.ranges[range], "The range must be registered:", range); + + this.ranges[range].handler = handler; + handler.addEventListener("click", event => this.toggleRangeBannerVisibility(event.currentTarget)); + }) + } + + _updateRangesWithBanners() { + const banners = [...document.querySelectorAll(this.strictdocRangeBannerSelector)]; + banners.forEach(banner => { + + const rangeBegin = banner.dataset.begin; + const rangeEnd = banner.dataset.end; + + if (rangeBegin && rangeEnd) { + const range = this._generateRangeAlias(rangeBegin, rangeEnd); + console.assert(this.ranges[range], "The range must be registered:", range); + this.ranges[range].banner = banner; + this.ranges[range].bannerHeader = banner.querySelector(this.strictdocRangeBannerHeaderSelector); // 'source__range-header' + } + }) + } + + _updateRangesWithClosers() { + const closers = [...document.querySelectorAll(this.strictdocRangeCloserSelector)]; + closers.forEach(closer => { + + const rangeEnd = closer.dataset.end; + + if (rangeEnd) { + this.closers[rangeEnd] = closer; + } + }) + } + + _updateLinesWithRanges() { + Object.entries(this.ranges).forEach(([key, value]) => { + const begin = parseInt(value.begin, 10); + const end = parseInt(value.end, 10); + + for (let i = begin; i <= end; i++) { + (this.lines[i].ranges ??= []).push(key); + (this.lines[i].pointers ??= []).push(...value.pointers); + + console.assert(this.lines[i].lineNumber, `The line ${i} must be registered.`); + this.lines[i].lineNumber.classList.add(this.strictdocSourceFilterClass); + this.lines[i].line.classList.add(this.coveredClass); + } + }); + } + + _generateRangeAlias(begin, end) { return `${begin}${this.hashSplitter}${end}` }; +} + +const dom = new Dom({}); + +window.addEventListener("load", function () { + dom.prepare(); + dom.useLocationHash(); + + const switcher = new Switch( + { + labelText: 'Show coverage', + size: 0.5, + stroke: 0.2, + checked: false, + callback: (checked) => dom.toggleCoverageVisibility(checked), + } + ); + document.getElementById('sourceCodeCoverageSwitch').append(switcher.create()); + + const tabsContainer = document.querySelector("sdoc-tabs"); + if (tabsContainer) { + new SimpleTabs(tabsContainer); + } + +}); + +window.addEventListener("hashchange", () => dom.useLocationHash()); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stable_uri_forwarder.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stable_uri_forwarder.js new file mode 100644 index 0000000..fcabf7f --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stable_uri_forwarder.js @@ -0,0 +1,99 @@ +// stable_uri_forwarder.js +// +// This script is included from the project's index.html page (in static HTML export) +// It checks for a known MID or UID in the #anchor, and then +// redirects to the referenced section or node within the project. +// +// Example: +// http://strictdoc.company.com/#SDOC_UG will redirect to +// http://strictdoc.company.com/strictdoc/docs/strictdoc_01_user_guide.html#SDOC_UG +// +// Thanks to this mechanism, it becomes possible to export stable links to +// nodes/requirements/sections for integration with external tools. +// The external links remain stable, even if the node/requirement/section is moved +// within the project. + + +// Resolve the MID / UID to the correct page / anchor using the projectMap. +function resolveStableUriRedirectUsingProjectMap(anchor) { + for (const [page, nodes] of Object.entries(projectMap)) { + for (const node of nodes) { + if (node['_LINK'].toLowerCase() === anchor.toLowerCase()) { + window.location.replace(page + "#" + node['_LINK']); + return; + } + + const nodeHasUID = 'UID' in node && typeof node['UID'] === 'string'; + if (nodeHasUID && node['UID'].toLowerCase() === anchor.toLowerCase()) { + window.location.replace(page + "#" + node['_LINK']); + return; + } + + const nodeHasMID = 'MID' in node && typeof node['MID'] === 'string'; + if (nodeHasMID && node['MID'].toLowerCase() === anchor.toLowerCase()) { + window.location.replace(page + "#" + node['_LINK']); + return; + } + } + } +} + +// Dynamically load the projectMap an resolve MID / UID. +function loadProjectMapAndResolveStableUriRedirect(anchor) { + + // ProjectMap is loaded, no need to load it again. + if (typeof projectMap !== 'undefined') { + resolveStableUriRedirectUsingProjectMap(anchor); + return; + } + + // Get script URL and derive from it the url of project_map.js + const scriptUrl = new URL(document.getElementById("stable_uri_forwarder").src, window.location + .href) + const projectMapUrl = new URL('project_map.js', scriptUrl).href; + + // Dynamically load project map and resolve + const script = document.createElement("script"); + script.src = projectMapUrl; + script.onload = () => resolveStableUriRedirectUsingProjectMap(anchor); + script.onerror = () => { + console.error(`Failed to load project map from ${projectMapUrl}`); + }; + document.head.appendChild(script); +} + +function processStableUriRedirect(anchor) { + const exportType = document.querySelector('meta[name="strictdoc-export-type"]')?.content; + + if (exportType === 'webserver') { + // For the web server, we let the main_router.py dynamically forward UID to node. + window.location.replace("/UID/" + anchor); + } else if (exportType === 'static') { + // For static exports, we use the project_map.js. + loadProjectMapAndResolveStableUriRedirect(anchor) + } +} + + +// In case an anchor is present at content load time. +document.addEventListener("DOMContentLoaded", () => { + const anchorParam = new URLSearchParams(window.location.search).get("a"); + if (anchorParam) { + processStableUriRedirect(anchorParam) + return + } + + // for legacy link support + const anchorHash = window.location.hash.substring(1); + if (anchorHash) { + processStableUriRedirect(anchorHash) + } +}); + +// In case an anchor is added manually afterwards (eases testing). +window.addEventListener("hashchange", () => { + const anchor = window.location.hash.substring(1); + if (anchor) { + processStableUriRedirect(anchor) + } +}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stimulus_umd.min.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stimulus_umd.min.js new file mode 100644 index 0000000..0df2936 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/stimulus_umd.min.js @@ -0,0 +1,5 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Stimulus={})}(this,function(e){"use strict";class K{constructor(e,t,r){this.eventTarget=e,this.eventName=t,this.eventOptions=r,this.unorderedBindings=new Set}connect(){this.eventTarget.addEventListener(this.eventName,this,this.eventOptions)}disconnect(){this.eventTarget.removeEventListener(this.eventName,this,this.eventOptions)}bindingConnected(e){this.unorderedBindings.add(e)}bindingDisconnected(e){this.unorderedBindings.delete(e)}handleEvent(e){var t=function(t){{if("immediatePropagationStopped"in t)return t;{let e=t.stopImmediatePropagation;return Object.assign(t,{immediatePropagationStopped:!1,stopImmediatePropagation(){this.immediatePropagationStopped=!0,e.call(this)}})}}}(e);for(const r of this.bindings){if(t.immediatePropagationStopped)break;r.handleEvent(t)}}hasBindings(){return 0{e=e.index,t=t.index;return ee.connect()))}stop(){this.started&&(this.started=!1,this.eventListeners.forEach(e=>e.disconnect()))}get eventListeners(){return Array.from(this.eventListenerMaps.values()).reduce((e,t)=>e.concat(Array.from(t.values())),[])}bindingConnected(e){this.fetchEventListenerForBinding(e).bindingConnected(e)}bindingDisconnected(e,t=!1){this.fetchEventListenerForBinding(e).bindingDisconnected(e),t&&this.clearEventListenersForBinding(e)}handleError(e,t,r={}){this.application.handleError(e,"Error "+t,r)}clearEventListenersForBinding(e){var t=this.fetchEventListenerForBinding(e);t.hasBindings()||(t.disconnect(),this.removeMappedEventListenerFor(e))}removeMappedEventListenerFor(e){var{eventTarget:e,eventName:t,eventOptions:r}=e,s=this.fetchEventListenerMapForEventTarget(e),t=this.cacheKey(t,r);s.delete(t),0==s.size&&this.eventListenerMaps.delete(e)}fetchEventListenerForBinding(e){var{eventTarget:e,eventName:t,eventOptions:r}=e;return this.fetchEventListener(e,t,r)}fetchEventListener(e,t,r){var s=this.fetchEventListenerMapForEventTarget(e),i=this.cacheKey(t,r);let n=s.get(i);return n||(n=this.createEventListener(e,t,r),s.set(i,n)),n}createEventListener(e,t,r){e=new K(e,t,r);return this.started&&e.connect(),e}fetchEventListenerMapForEventTarget(e){let t=this.eventListenerMaps.get(e);return t||(t=new Map,this.eventListenerMaps.set(e,t)),t}cacheKey(e,t){const r=[e];return Object.keys(t).sort().forEach(e=>{r.push((t[e]?"":"!")+e)}),r.join(":")}}const j={stop({event:e,value:t}){return t&&e.stopPropagation(),!0},prevent({event:e,value:t}){return t&&e.preventDefault(),!0},self({event:e,value:t,element:r}){return!t||r===e.target}},$=/^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;function U(e){var t,e=e.trim().match($)||[];let r=e[2],s=e[3];return s&&!["keydown","keyup","keypress"].includes(r)&&(r+="."+s,s=""),{eventTarget:"window"==(t=e[4])?window:"document"==t?document:void 0,eventName:r,eventOptions:e[7]?e[7].split(":").reduce((e,t)=>Object.assign(e,{[t.replace(/^!/,"")]:!/^!/.test(t)}),{}):{},identifier:e[5],methodName:e[6],keyFilter:e[1]||s}}function a(e){return e.replace(/(?:[_-])([a-z0-9])/g,(e,t)=>t.toUpperCase())}function s(e){return a(e.replace(/--/g,"-").replace(/__/g,"_"))}function l(e){return e.charAt(0).toUpperCase()+e.slice(1)}function h(e){return e.replace(/([A-Z])/g,(e,t)=>"-"+t.toLowerCase())}function c(e){return null!=e}function u(e,t){return Object.prototype.hasOwnProperty.call(e,t)}const o=["meta","ctrl","alt","shift"];class P{constructor(e,t,r,s){this.element=e,this.index=t,this.eventTarget=r.eventTarget||e,this.eventName=r.eventName||function(e){var t=e.tagName.toLowerCase();if(t in i)return i[t](e)}(e)||n("missing event name"),this.eventOptions=r.eventOptions||{},this.identifier=r.identifier||n("missing identifier"),this.methodName=r.methodName||n("missing method name"),this.keyFilter=r.keyFilter||"",this.schema=s}static forToken(e,t){return new this(e.element,e.index,U(e.content),t)}toString(){var e=this.keyFilter?"."+this.keyFilter:"",t=this.eventTargetName?"@"+this.eventTargetName:"";return this.eventName+e+t+`->${this.identifier}#`+this.methodName}shouldIgnoreKeyboardEvent(e){var t;return!!this.keyFilter&&(t=this.keyFilter.split("+"),!!this.keyFilterDissatisfied(e,t)||!!(t=t.filter(e=>!o.includes(e))[0])&&(u(this.keyMappings,t)||n("contains unknown key filter: "+this.keyFilter),this.keyMappings[t].toLowerCase()!==e.key.toLowerCase()))}shouldIgnoreMouseEvent(e){var t;return!!this.keyFilter&&(t=[this.keyFilter],!!this.keyFilterDissatisfied(e,t))}get params(){var e,t,r={},s=new RegExp(`^data-${this.identifier}-(.+)-param$`,"i");for({name:e,value:t}of Array.from(this.element.attributes)){var i=e.match(s),i=i&&i[1];i&&(r[a(i)]=function(t){try{return JSON.parse(t)}catch(e){return t}}(t))}return r}get eventTargetName(){return(e=this.eventTarget)==window?"window":e==document?"document":void 0;var e}get keyMappings(){return this.schema.keyMappings}keyFilterDissatisfied(e,t){var[r,s,i,n]=o.map(e=>t.includes(e));return e.metaKey!==r||e.ctrlKey!==s||e.altKey!==i||e.shiftKey!==n}}const i={a:()=>"click",button:()=>"click",form:()=>"submit",details:()=>"toggle",input:e=>"submit"==e.getAttribute("type")?"click":"input",select:()=>"change",textarea:()=>"input"};function n(e){throw new Error(e)}class R{constructor(e,t){this.context=e,this.action=t}get index(){return this.action.index}get eventTarget(){return this.action.eventTarget}get eventOptions(){return this.action.eventOptions}get identifier(){return this.context.identifier}handleEvent(e){var t=this.prepareActionEvent(e);this.willBeInvokedByEvent(e)&&this.applyEventModifiers(t)&&this.invokeWithEvent(t)}get eventName(){return this.action.eventName}get method(){var e=this.controller[this.methodName];if("function"==typeof e)return e;throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`)}applyEventModifiers(e){var t,r,s,i=this.action.element,n=this.context.application.actionDescriptorFilters,o=this.context.controller;let a=!0;for([t,r]of Object.entries(this.eventOptions))t in n&&(s=n[t],a=a&&s({name:t,value:r,event:e,element:i,controller:o}));return a}prepareActionEvent(e){return Object.assign(e,{params:this.action.params})}invokeWithEvent(t){var{target:r,currentTarget:s}=t;try{this.method.call(this.controller,t),this.context.logDebugActivity(this.methodName,{event:t,target:r,currentTarget:s,action:this.methodName})}catch(e){var{identifier:r,controller:s,element:i,index:n}=this;this.context.handleError(e,`invoking action "${this.action}"`,{identifier:r,controller:s,element:i,index:n,event:t})}}willBeInvokedByEvent(e){var t=e.target;return!(e instanceof KeyboardEvent&&this.action.shouldIgnoreKeyboardEvent(e)||e instanceof MouseEvent&&this.action.shouldIgnoreMouseEvent(e))&&(this.element===t||(t instanceof Element&&this.element.contains(t)?this.scope.containsElement(t):this.scope.containsElement(this.action.element)))}get controller(){return this.context.controller}get methodName(){return this.action.methodName}get element(){return this.scope.element}get scope(){return this.context.scope}}class d{constructor(e,t){this.mutationObserverInit={attributes:!0,childList:!0,subtree:!0},this.element=e,this.started=!1,this.delegate=t,this.elements=new Set,this.mutationObserver=new MutationObserver(e=>this.processMutations(e))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,this.mutationObserverInit),this.refresh())}pause(e){this.started&&(this.mutationObserver.disconnect(),this.started=!1),e(),this.started||(this.mutationObserver.observe(this.element,this.mutationObserverInit),this.started=!0)}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started){var e=new Set(this.matchElementsInTree());for(const t of Array.from(this.elements))e.has(t)||this.removeElement(t);for(const r of Array.from(e))this.addElement(r)}}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){"attributes"==e.type?this.processAttributeChange(e.target,e.attributeName):"childList"==e.type&&(this.processRemovedNodes(e.removedNodes),this.processAddedNodes(e.addedNodes))}processAttributeChange(e,t){this.elements.has(e)?this.delegate.elementAttributeChanged&&this.matchElement(e)?this.delegate.elementAttributeChanged(e,t):this.removeElement(e):this.matchElement(e)&&this.addElement(e)}processRemovedNodes(e){for(const r of Array.from(e)){var t=this.elementFromNode(r);t&&this.processTree(t,this.removeElement)}}processAddedNodes(e){for(const r of Array.from(e)){var t=this.elementFromNode(r);t&&this.elementIsActive(t)&&this.processTree(t,this.addElement)}}matchElement(e){return this.delegate.matchElement(e)}matchElementsInTree(e=this.element){return this.delegate.matchElementsInTree(e)}processTree(e,t){for(const r of this.matchElementsInTree(e))t.call(this,r)}elementFromNode(e){if(e.nodeType==Node.ELEMENT_NODE)return e}elementIsActive(e){return e.isConnected==this.element.isConnected&&this.element.contains(e)}addElement(e){this.elements.has(e)||this.elementIsActive(e)&&(this.elements.add(e),this.delegate.elementMatched)&&this.delegate.elementMatched(e)}removeElement(e){this.elements.has(e)&&(this.elements.delete(e),this.delegate.elementUnmatched)&&this.delegate.elementUnmatched(e)}}class m{constructor(e,t,r){this.attributeName=t,this.delegate=r,this.elementObserver=new d(e,this)}get element(){return this.elementObserver.element}get selector(){return`[${this.attributeName}]`}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get started(){return this.elementObserver.started}matchElement(e){return e.hasAttribute(this.attributeName)}matchElementsInTree(e){var t=this.matchElement(e)?[e]:[],e=Array.from(e.querySelectorAll(this.selector));return t.concat(e)}elementMatched(e){this.delegate.elementMatchedAttribute&&this.delegate.elementMatchedAttribute(e,this.attributeName)}elementUnmatched(e){this.delegate.elementUnmatchedAttribute&&this.delegate.elementUnmatchedAttribute(e,this.attributeName)}elementAttributeChanged(e,t){this.delegate.elementAttributeValueChanged&&this.attributeName==t&&this.delegate.elementAttributeValueChanged(e,t)}}function r(e,t,r){p(e,t).add(r)}function g(e,t,r){p(e,t).delete(r),f(e,t)}function p(e,t){let r=e.get(t);return r||(r=new Set,e.set(t,r)),r}function f(e,t){var r=e.get(t);null!=r&&0==r.size&&e.delete(t)}class v{constructor(){this.valuesByKey=new Map}get keys(){return Array.from(this.valuesByKey.keys())}get values(){return Array.from(this.valuesByKey.values()).reduce((e,t)=>e.concat(Array.from(t)),[])}get size(){return Array.from(this.valuesByKey.values()).reduce((e,t)=>e+t.size,0)}add(e,t){r(this.valuesByKey,e,t)}delete(e,t){g(this.valuesByKey,e,t)}has(e,t){e=this.valuesByKey.get(e);return null!=e&&e.has(t)}hasKey(e){return this.valuesByKey.has(e)}hasValue(t){return Array.from(this.valuesByKey.values()).some(e=>e.has(t))}getValuesForKey(e){e=this.valuesByKey.get(e);return e?Array.from(e):[]}getKeysForValue(t){return Array.from(this.valuesByKey).filter(([,e])=>e.has(t)).map(([e])=>e)}}class z extends v{constructor(){super(),this.keysByValue=new Map}get values(){return Array.from(this.keysByValue.keys())}add(e,t){super.add(e,t),r(this.keysByValue,t,e)}delete(e,t){super.delete(e,t),g(this.keysByValue,t,e)}hasValue(e){return this.keysByValue.has(e)}getKeysForValue(e){e=this.keysByValue.get(e);return e?Array.from(e):[]}}class b{constructor(e,t,r,s){this._selector=t,this.details=s,this.elementObserver=new d(e,this),this.delegate=r,this.matchesByElement=new v}get started(){return this.elementObserver.started}get selector(){return this._selector}set selector(e){this._selector=e,this.refresh()}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get element(){return this.elementObserver.element}matchElement(e){var t=this.selector;return!!t&&(t=e.matches(t),this.delegate.selectorMatchElement?t&&this.delegate.selectorMatchElement(e,this.details):t)}matchElementsInTree(e){var t,r=this.selector;return r?(t=this.matchElement(e)?[e]:[],e=Array.from(e.querySelectorAll(r)).filter(e=>this.matchElement(e)),t.concat(e)):[]}elementMatched(e){var t=this.selector;t&&this.selectorMatched(e,t)}elementUnmatched(e){for(const t of this.matchesByElement.getKeysForValue(e))this.selectorUnmatched(e,t)}elementAttributeChanged(e,t){var r,s,i=this.selector;i&&(r=this.matchElement(e),s=this.matchesByElement.has(i,e),r&&!s?this.selectorMatched(e,i):!r&&s&&this.selectorUnmatched(e,i))}selectorMatched(e,t){this.delegate.selectorMatched(e,t,this.details),this.matchesByElement.add(t,e)}selectorUnmatched(e,t){this.delegate.selectorUnmatched(e,t,this.details),this.matchesByElement.delete(t,e)}}class y{constructor(e,t){this.element=e,this.delegate=t,this.started=!1,this.stringMap=new Map,this.mutationObserver=new MutationObserver(e=>this.processMutations(e))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,{attributes:!0,attributeOldValue:!0}),this.refresh())}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started)for(const e of this.knownAttributeNames)this.refreshAttribute(e,null)}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){var t=e.attributeName;t&&this.refreshAttribute(t,e.oldValue)}refreshAttribute(e,t){var r=this.delegate.getStringMapKeyForAttribute(e);if(null!=r){this.stringMap.has(e)||this.stringMapKeyAdded(r,e);var s=this.element.getAttribute(e);if(this.stringMap.get(e)!=s&&this.stringMapValueChanged(s,r,t),null==s){const t=this.stringMap.get(e);this.stringMap.delete(e),t&&this.stringMapKeyRemoved(r,e,t)}else this.stringMap.set(e,s)}}stringMapKeyAdded(e,t){this.delegate.stringMapKeyAdded&&this.delegate.stringMapKeyAdded(e,t)}stringMapValueChanged(e,t,r){this.delegate.stringMapValueChanged&&this.delegate.stringMapValueChanged(e,t,r)}stringMapKeyRemoved(e,t,r){this.delegate.stringMapKeyRemoved&&this.delegate.stringMapKeyRemoved(e,t,r)}get knownAttributeNames(){return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)))}get currentAttributeNames(){return Array.from(this.element.attributes).map(e=>e.name)}get recordedAttributeNames(){return Array.from(this.stringMap.keys())}}class O{constructor(e,t,r){this.attributeObserver=new m(e,t,this),this.delegate=r,this.tokensByElement=new v}get started(){return this.attributeObserver.started}start(){this.attributeObserver.start()}pause(e){this.attributeObserver.pause(e)}stop(){this.attributeObserver.stop()}refresh(){this.attributeObserver.refresh()}get element(){return this.attributeObserver.element}get attributeName(){return this.attributeObserver.attributeName}elementMatchedAttribute(e){this.tokensMatched(this.readTokensForElement(e))}elementAttributeValueChanged(e){var[e,t]=this.refreshTokensForElement(e);this.tokensUnmatched(e),this.tokensMatched(t)}elementUnmatchedAttribute(e){this.tokensUnmatched(this.tokensByElement.getValuesForKey(e))}tokensMatched(e){e.forEach(e=>this.tokenMatched(e))}tokensUnmatched(e){e.forEach(e=>this.tokenUnmatched(e))}tokenMatched(e){this.delegate.tokenMatched(e),this.tokensByElement.add(e.element,e)}tokenUnmatched(e){this.delegate.tokenUnmatched(e),this.tokensByElement.delete(e.element,e)}refreshTokensForElement(e){var r,s,t=this.tokensByElement.getValuesForKey(e),e=this.readTokensForElement(e),i=(r=t,s=e,i=Math.max(r.length,s.length),Array.from({length:i},(e,t)=>[r[t],s[t]]).findIndex(([e,t])=>{return t=t,!((e=e)&&t&&e.index==t.index&&e.content==t.content)}));return-1==i?[[],[]]:[t.slice(i),e.slice(i)]}readTokensForElement(e){var r,s,t=this.attributeName,i=e.getAttribute(t)||"";return r=e,s=t,i.trim().split(/\s+/).filter(e=>e.length).map((e,t)=>({element:r,attributeName:s,content:e,index:t}))}}class A{constructor(e,t,r){this.tokenListObserver=new O(e,t,this),this.delegate=r,this.parseResultsByToken=new WeakMap,this.valuesByTokenByElement=new WeakMap}get started(){return this.tokenListObserver.started}start(){this.tokenListObserver.start()}stop(){this.tokenListObserver.stop()}refresh(){this.tokenListObserver.refresh()}get element(){return this.tokenListObserver.element}get attributeName(){return this.tokenListObserver.attributeName}tokenMatched(e){var t=e.element,r=this.fetchParseResultForToken(e).value;r&&(this.fetchValuesByTokenForElement(t).set(e,r),this.delegate.elementMatchedValue(t,r))}tokenUnmatched(e){var t=e.element,r=this.fetchParseResultForToken(e).value;r&&(this.fetchValuesByTokenForElement(t).delete(e),this.delegate.elementUnmatchedValue(t,r))}fetchParseResultForToken(e){let t=this.parseResultsByToken.get(e);return t||(t=this.parseToken(e),this.parseResultsByToken.set(e,t)),t}fetchValuesByTokenForElement(e){let t=this.valuesByTokenByElement.get(e);return t||(t=new Map,this.valuesByTokenByElement.set(e,t)),t}parseToken(e){try{return{value:this.delegate.parseValueForToken(e)}}catch(e){return{error:e}}}}class _{constructor(e,t){this.context=e,this.delegate=t,this.bindingsByAction=new Map}start(){this.valueListObserver||(this.valueListObserver=new A(this.element,this.actionAttribute,this),this.valueListObserver.start())}stop(){this.valueListObserver&&(this.valueListObserver.stop(),delete this.valueListObserver,this.disconnectAllActions())}get element(){return this.context.element}get identifier(){return this.context.identifier}get actionAttribute(){return this.schema.actionAttribute}get schema(){return this.context.schema}get bindings(){return Array.from(this.bindingsByAction.values())}connectAction(e){var t=new R(this.context,e);this.bindingsByAction.set(e,t),this.delegate.bindingConnected(t)}disconnectAction(e){var t=this.bindingsByAction.get(e);t&&(this.bindingsByAction.delete(e),this.delegate.bindingDisconnected(t))}disconnectAllActions(){this.bindings.forEach(e=>this.delegate.bindingDisconnected(e,!0)),this.bindingsByAction.clear()}parseValueForToken(e){e=P.forToken(e,this.schema);if(e.identifier==this.identifier)return e}elementMatchedValue(e,t){this.connectAction(t)}elementUnmatchedValue(e,t){this.disconnectAction(t)}}class q{constructor(e,t){this.context=e,this.receiver=t,this.stringMapObserver=new y(this.element,this),this.valueDescriptorMap=this.controller.valueDescriptorMap}start(){this.stringMapObserver.start(),this.invokeChangedCallbacksForDefaultValues()}stop(){this.stringMapObserver.stop()}get element(){return this.context.element}get controller(){return this.context.controller}getStringMapKeyForAttribute(e){if(e in this.valueDescriptorMap)return this.valueDescriptorMap[e].name}stringMapKeyAdded(e,t){t=this.valueDescriptorMap[t];this.hasValue(e)||this.invokeChangedCallback(e,t.writer(this.receiver[e]),t.writer(t.defaultValue))}stringMapValueChanged(e,t,r){var s=this.valueDescriptorNameMap[t];null!==e&&(null===r&&(r=s.writer(s.defaultValue)),this.invokeChangedCallback(t,e,r))}stringMapKeyRemoved(e,t,r){var s=this.valueDescriptorNameMap[e];this.hasValue(e)?this.invokeChangedCallback(e,s.writer(this.receiver[e]),r):this.invokeChangedCallback(e,s.writer(s.defaultValue),r)}invokeChangedCallbacksForDefaultValues(){for(var{key:e,name:t,defaultValue:r,writer:s}of this.valueDescriptors)null==r||this.controller.data.has(e)||this.invokeChangedCallback(t,s(r),void 0)}invokeChangedCallback(t,r,s){var i=this.receiver[t+"Changed"];if("function"==typeof i){t=this.valueDescriptorNameMap[t];try{var n=t.reader(r);let e=s;s&&(e=t.reader(s)),i.call(this.receiver,n,e)}catch(e){throw e instanceof TypeError&&(e.message=`Stimulus Value "${this.context.identifier}.${t.name}" - `+e.message),e}}}get valueDescriptors(){let t=this.valueDescriptorMap;return Object.keys(t).map(e=>t[e])}get valueDescriptorNameMap(){const t={};return Object.keys(this.valueDescriptorMap).forEach(e=>{e=this.valueDescriptorMap[e];t[e.name]=e}),t}hasValue(e){e="has"+l(this.valueDescriptorNameMap[e].name);return this.receiver[e]}}class W{constructor(e,t){this.context=e,this.delegate=t,this.targetsByName=new v}start(){this.tokenListObserver||(this.tokenListObserver=new O(this.element,this.attributeName,this),this.tokenListObserver.start())}stop(){this.tokenListObserver&&(this.disconnectAllTargets(),this.tokenListObserver.stop(),delete this.tokenListObserver)}tokenMatched({element:e,content:t}){this.scope.containsElement(e)&&this.connectTarget(e,t)}tokenUnmatched({element:e,content:t}){this.disconnectTarget(e,t)}connectTarget(e,t){var r;this.targetsByName.has(t,e)||(this.targetsByName.add(t,e),null!=(r=this.tokenListObserver)&&r.pause(()=>this.delegate.targetConnected(e,t)))}disconnectTarget(e,t){var r;this.targetsByName.has(t,e)&&(this.targetsByName.delete(t,e),null!=(r=this.tokenListObserver))&&r.pause(()=>this.delegate.targetDisconnected(e,t))}disconnectAllTargets(){for(const e of this.targetsByName.keys)for(const t of this.targetsByName.getValuesForKey(e))this.disconnectTarget(t,e)}get attributeName(){return`data-${this.context.identifier}-target`}get element(){return this.context.element}get scope(){return this.context.scope}}function E(e,r){e=t(e);return Array.from(e.reduce((t,e)=>(function(e,t){e=e[t];return Array.isArray(e)?e:[]}(e,r).forEach(e=>t.add(e)),t),new Set))}function J(e,r){return t(e).reduce((e,t)=>(e.push(...function(e,t){const r=e[t];return r?Object.keys(r).map(e=>[e,r[e]]):[]}(t,r)),e),[])}function t(e){for(var t=[];e;)t.push(e),e=Object.getPrototypeOf(e);return t.reverse()}class H{constructor(e,t){this.started=!1,this.context=e,this.delegate=t,this.outletsByName=new v,this.outletElementsByName=new v,this.selectorObserverMap=new Map,this.attributeObserverMap=new Map}start(){this.started||(this.outletDefinitions.forEach(e=>{this.setupSelectorObserverForOutlet(e),this.setupAttributeObserverForOutlet(e)}),this.started=!0,this.dependentContexts.forEach(e=>e.refresh()))}refresh(){this.selectorObserverMap.forEach(e=>e.refresh()),this.attributeObserverMap.forEach(e=>e.refresh())}stop(){this.started&&(this.started=!1,this.disconnectAllOutlets(),this.stopSelectorObservers(),this.stopAttributeObservers())}stopSelectorObservers(){0e.stop()),this.selectorObserverMap.clear())}stopAttributeObservers(){0e.stop()),this.attributeObserverMap.clear())}selectorMatched(e,t,{outletName:r}){var s=this.getOutlet(e,r);s&&this.connectOutlet(s,e,r)}selectorUnmatched(e,t,{outletName:r}){var s=this.getOutletFromMap(e,r);s&&this.disconnectOutlet(s,e,r)}selectorMatchElement(e,{outletName:t}){var r=this.selector(t),s=this.hasOutlet(e,t),t=e.matches(`[${this.schema.controllerAttribute}~=${t}]`);return!!r&&s&&t&&e.matches(r)}elementMatchedAttribute(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}elementAttributeValueChanged(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}elementUnmatchedAttribute(e,t){t=this.getOutletNameFromOutletAttributeName(t);t&&this.updateSelectorObserverForOutlet(t)}connectOutlet(e,t,r){var s;this.outletElementsByName.has(r,t)||(this.outletsByName.add(r,e),this.outletElementsByName.add(r,t),null!=(s=this.selectorObserverMap.get(r))&&s.pause(()=>this.delegate.outletConnected(e,t,r)))}disconnectOutlet(e,t,r){var s;this.outletElementsByName.has(r,t)&&(this.outletsByName.delete(r,e),this.outletElementsByName.delete(r,t),null!=(s=this.selectorObserverMap.get(r)))&&s.pause(()=>this.delegate.outletDisconnected(e,t,r))}disconnectAllOutlets(){for(const e of this.outletElementsByName.keys)for(const t of this.outletElementsByName.getValuesForKey(e))for(const r of this.outletsByName.getValuesForKey(e))this.disconnectOutlet(r,t,e)}updateSelectorObserverForOutlet(e){var t=this.selectorObserverMap.get(e);t&&(t.selector=this.selector(e))}setupSelectorObserverForOutlet(e){var t=this.selector(e),t=new b(document.body,t,this,{outletName:e});this.selectorObserverMap.set(e,t),t.start()}setupAttributeObserverForOutlet(e){var t=this.attributeNameForOutletName(e),t=new m(this.scope.element,t,this);this.attributeObserverMap.set(e,t),t.start()}selector(e){return this.scope.outlets.getSelectorForOutletName(e)}attributeNameForOutletName(e){return this.scope.schema.outletAttributeForScope(this.identifier,e)}getOutletNameFromOutletAttributeName(t){return this.outletDefinitions.find(e=>this.attributeNameForOutletName(e)===t)}get outletDependencies(){const r=new v;return this.router.modules.forEach(t=>{E(t.definition.controllerConstructor,"outlets").forEach(e=>r.add(e,t.identifier))}),r}get outletDefinitions(){return this.outletDependencies.getKeysForValue(this.identifier)}get dependentControllerIdentifiers(){return this.outletDependencies.getValuesForKey(this.identifier)}get dependentContexts(){const t=this.dependentControllerIdentifiers;return this.router.contexts.filter(e=>t.includes(e.identifier))}hasOutlet(e,t){return!!this.getOutlet(e,t)||!!this.getOutletFromMap(e,t)}getOutlet(e,t){return this.application.getControllerForElementAndIdentifier(e,t)}getOutletFromMap(t,e){return this.outletsByName.getValuesForKey(e).find(e=>e.element===t)}get scope(){return this.context.scope}get schema(){return this.context.schema}get identifier(){return this.context.identifier}get application(){return this.context.application}get router(){return this.application.router}}class M{constructor(e,t){this.logDebugActivity=(e,t={})=>{var{identifier:r,controller:s,element:i}=this;t=Object.assign({identifier:r,controller:s,element:i},t),this.application.logDebugActivity(this.identifier,e,t)},this.module=e,this.scope=t,this.controller=new e.controllerConstructor(this),this.bindingObserver=new _(this,this.dispatcher),this.valueObserver=new q(this,this.controller),this.targetObserver=new W(this,this),this.outletObserver=new H(this,this);try{this.controller.initialize(),this.logDebugActivity("initialize")}catch(e){this.handleError(e,"initializing controller")}}connect(){this.bindingObserver.start(),this.valueObserver.start(),this.targetObserver.start(),this.outletObserver.start();try{this.controller.connect(),this.logDebugActivity("connect")}catch(e){this.handleError(e,"connecting controller")}}refresh(){this.outletObserver.refresh()}disconnect(){try{this.controller.disconnect(),this.logDebugActivity("disconnect")}catch(e){this.handleError(e,"disconnecting controller")}this.outletObserver.stop(),this.targetObserver.stop(),this.valueObserver.stop(),this.bindingObserver.stop()}get application(){return this.module.application}get identifier(){return this.module.identifier}get schema(){return this.application.schema}get dispatcher(){return this.application.dispatcher}get element(){return this.scope.element}get parentElement(){return this.element.parentElement}handleError(e,t,r={}){var{identifier:s,controller:i,element:n}=this;r=Object.assign({identifier:s,controller:i,element:n},r),this.application.handleError(e,"Error "+t,r)}targetConnected(e,t){this.invokeControllerMethod(t+"TargetConnected",e)}targetDisconnected(e,t){this.invokeControllerMethod(t+"TargetDisconnected",e)}outletConnected(e,t,r){this.invokeControllerMethod(s(r)+"OutletConnected",e,t)}outletDisconnected(e,t,r){this.invokeControllerMethod(s(r)+"OutletDisconnected",e,t)}invokeControllerMethod(e,...t){var r=this.controller;"function"==typeof r[e]&&r[e](...t)}}function Z(e){return r=E(n=e=e,"blessings"),r=r.reduce((e,t)=>{var r=t(n);for(const i in r){var s=e[i]||{};e[i]=Object.assign(s,r[i])}return e},{}),t=Q(e),e=function(s,i){return G(i).reduce((e,t)=>{var r=function(e,t,r){var e=Object.getOwnPropertyDescriptor(e,r),s=e&&"value"in e;if(!s)return s=Object.getOwnPropertyDescriptor(t,r).value,e&&(s.get=e.get||s.get,s.set=e.set||s.set),s}(s,i,t);return r&&Object.assign(e,{[t]:r}),e},{})}(e.prototype,r),Object.defineProperties(t.prototype,e),t;var t,n,r}const G="function"==typeof Object.getOwnPropertySymbols?e=>[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)]:Object.getOwnPropertyNames,Q=(()=>{function e(e){function t(){return Reflect.construct(e,arguments,new.target)}return t.prototype=Object.create(e.prototype,{constructor:{value:t}}),Reflect.setPrototypeOf(t,e),t}try{return(t=e(function(){this.a.call(this)})).prototype.a=function(){},new t,e}catch(e){return e=>class extends e{}}var t})();class X{constructor(e,t){this.application=e,this.definition={identifier:t.identifier,controllerConstructor:Z(t.controllerConstructor)},this.contextsByScope=new WeakMap,this.connectedContexts=new Set}get identifier(){return this.definition.identifier}get controllerConstructor(){return this.definition.controllerConstructor}get contexts(){return Array.from(this.connectedContexts)}connectContextForScope(e){e=this.fetchContextForScope(e);this.connectedContexts.add(e),e.connect()}disconnectContextForScope(e){e=this.contextsByScope.get(e);e&&(this.connectedContexts.delete(e),e.disconnect())}fetchContextForScope(e){let t=this.contextsByScope.get(e);return t||(t=new M(this,e),this.contextsByScope.set(e,t)),t}}class Y{constructor(e){this.scope=e}has(e){return this.data.has(this.getDataKey(e))}get(e){return this.getAll(e)[0]}getAll(e){return(this.data.get(this.getDataKey(e))||"").match(/[^\s]+/g)||[]}getAttributeName(e){return this.data.getAttributeNameForKey(this.getDataKey(e))}getDataKey(e){return e+"-class"}get data(){return this.scope.data}}class ee{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get(e){e=this.getAttributeNameForKey(e);return this.element.getAttribute(e)}set(e,t){var r=this.getAttributeNameForKey(e);return this.element.setAttribute(r,t),this.get(e)}has(e){e=this.getAttributeNameForKey(e);return this.element.hasAttribute(e)}delete(e){return!!this.has(e)&&(e=this.getAttributeNameForKey(e),this.element.removeAttribute(e),!0)}getAttributeNameForKey(e){return`data-${this.identifier}-`+h(e)}}class te{constructor(e){this.warnedKeysByObject=new WeakMap,this.logger=e}warn(e,t,r){let s=this.warnedKeysByObject.get(e);s||(s=new Set,this.warnedKeysByObject.set(e,s)),s.has(t)||(s.add(t),this.logger.warn(r,e))}}function w(e,t){return`[${e}~="${t}"]`}class re{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce((e,t)=>e||this.findTarget(t)||this.findLegacyTarget(t),void 0)}findAll(...e){return e.reduce((e,t)=>[...e,...this.findAllTargets(t),...this.findAllLegacyTargets(t)],[])}findTarget(e){e=this.getSelectorForTargetName(e);return this.scope.findElement(e)}findAllTargets(e){e=this.getSelectorForTargetName(e);return this.scope.findAllElements(e)}getSelectorForTargetName(e){return w(this.schema.targetAttributeForScope(this.identifier),e)}findLegacyTarget(e){var t=this.getLegacySelectorForTargetName(e);return this.deprecate(this.scope.findElement(t),e)}findAllLegacyTargets(t){var e=this.getLegacySelectorForTargetName(t);return this.scope.findAllElements(e).map(e=>this.deprecate(e,t))}getLegacySelectorForTargetName(e){e=this.identifier+"."+e;return w(this.schema.targetAttribute,e)}deprecate(e,t){var r,s,i;return e&&(r=this.identifier,s=this.schema.targetAttribute,i=this.schema.targetAttributeForScope(r),this.guide.warn(e,"target:"+t,`Please replace ${s}="${r}.${t}" with ${i}="${t}". `+`The ${s} attribute is deprecated and will be removed in a future version of Stimulus.`)),e}get guide(){return this.scope.guide}}class se{constructor(e,t){this.scope=e,this.controllerElement=t}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce((e,t)=>e||this.findOutlet(t),void 0)}findAll(...e){return e.reduce((e,t)=>[...e,...this.findAllOutlets(t)],[])}getSelectorForOutletName(e){e=this.schema.outletAttributeForScope(this.identifier,e);return this.controllerElement.getAttribute(e)}findOutlet(e){var t=this.getSelectorForOutletName(e);if(t)return this.findElement(t,e)}findAllOutlets(e){var t=this.getSelectorForOutletName(e);return t?this.findAllElements(t,e):[]}findElement(t,r){return this.scope.queryElements(t).filter(e=>this.matchesElement(e,t,r))[0]}findAllElements(t,r){return this.scope.queryElements(t).filter(e=>this.matchesElement(e,t,r))}matchesElement(e,t,r){var s=e.getAttribute(this.scope.schema.controllerAttribute)||"";return e.matches(t)&&s.split(" ").includes(r)}}class k{constructor(e,t,r,s){this.targets=new re(this),this.classes=new Y(this),this.data=new ee(this),this.containsElement=e=>e.closest(this.controllerSelector)===this.element,this.schema=e,this.element=t,this.identifier=r,this.guide=new te(s),this.outlets=new se(this.documentScope,t)}findElement(e){return this.element.matches(e)?this.element:this.queryElements(e).find(this.containsElement)}findAllElements(e){return[...this.element.matches(e)?[this.element]:[],...this.queryElements(e).filter(this.containsElement)]}queryElements(e){return Array.from(this.element.querySelectorAll(e))}get controllerSelector(){return w(this.schema.controllerAttribute,this.identifier)}get isDocumentScope(){return this.element===document.documentElement}get documentScope(){return this.isDocumentScope?this:new k(this.schema,document.documentElement,this.identifier,this.guide.logger)}}class ie{constructor(e,t,r){this.element=e,this.schema=t,this.delegate=r,this.valueListObserver=new A(this.element,this.controllerAttribute,this),this.scopesByIdentifierByElement=new WeakMap,this.scopeReferenceCounts=new WeakMap}start(){this.valueListObserver.start()}stop(){this.valueListObserver.stop()}get controllerAttribute(){return this.schema.controllerAttribute}parseValueForToken(e){var{element:e,content:t}=e;return this.parseValueForElementAndIdentifier(e,t)}parseValueForElementAndIdentifier(e,t){var r=this.fetchScopesByIdentifierForElement(e);let s=r.get(t);return s||(s=this.delegate.createScopeForElementAndIdentifier(e,t),r.set(t,s)),s}elementMatchedValue(e,t){var r=(this.scopeReferenceCounts.get(t)||0)+1;this.scopeReferenceCounts.set(t,r),1==r&&this.delegate.scopeConnected(t)}elementUnmatchedValue(e,t){var r=this.scopeReferenceCounts.get(t);r&&(this.scopeReferenceCounts.set(t,r-1),1==r)&&this.delegate.scopeDisconnected(t)}fetchScopesByIdentifierForElement(e){let t=this.scopesByIdentifierByElement.get(e);return t||(t=new Map,this.scopesByIdentifierByElement.set(e,t)),t}}class ne{constructor(e){this.application=e,this.scopeObserver=new ie(this.element,this.schema,this),this.scopesByIdentifier=new v,this.modulesByIdentifier=new Map}get element(){return this.application.element}get schema(){return this.application.schema}get logger(){return this.application.logger}get controllerAttribute(){return this.schema.controllerAttribute}get modules(){return Array.from(this.modulesByIdentifier.values())}get contexts(){return this.modules.reduce((e,t)=>e.concat(t.contexts),[])}start(){this.scopeObserver.start()}stop(){this.scopeObserver.stop()}loadDefinition(e){this.unloadIdentifier(e.identifier);var t=new X(this.application,e),t=(this.connectModule(t),e.controllerConstructor.afterLoad);t&&t.call(e.controllerConstructor,e.identifier,this.application)}unloadIdentifier(e){e=this.modulesByIdentifier.get(e);e&&this.disconnectModule(e)}getContextForElementAndIdentifier(t,e){e=this.modulesByIdentifier.get(e);if(e)return e.contexts.find(e=>e.element==t)}proposeToConnectScopeForElementAndIdentifier(e,t){var r=this.scopeObserver.parseValueForElementAndIdentifier(e,t);r?this.scopeObserver.elementMatchedValue(r.element,r):console.error(`Couldn't find or create scope for identifier: "${t}" and element:`,e)}handleError(e,t,r){this.application.handleError(e,t,r)}createScopeForElementAndIdentifier(e,t){return new k(this.schema,e,t,this.logger)}scopeConnected(e){this.scopesByIdentifier.add(e.identifier,e);var t=this.modulesByIdentifier.get(e.identifier);t&&t.connectContextForScope(e)}scopeDisconnected(e){this.scopesByIdentifier.delete(e.identifier,e);var t=this.modulesByIdentifier.get(e.identifier);t&&t.disconnectContextForScope(e)}connectModule(t){this.modulesByIdentifier.set(t.identifier,t),this.scopesByIdentifier.getValuesForKey(t.identifier).forEach(e=>t.connectContextForScope(e))}disconnectModule(t){this.modulesByIdentifier.delete(t.identifier),this.scopesByIdentifier.getValuesForKey(t.identifier).forEach(e=>t.disconnectContextForScope(e))}}const N={controllerAttribute:"data-controller",actionAttribute:"data-action",targetAttribute:"data-target",targetAttributeForScope:e=>`data-${e}-target`,outletAttributeForScope:(e,t)=>`data-${e}-${t}-outlet`,keyMappings:Object.assign(Object.assign({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"},F("abcdefghijklmnopqrstuvwxyz".split("").map(e=>[e,e]))),F("0123456789".split("").map(e=>[e,e])))};function F(e){return e.reduce((e,[t,r])=>Object.assign(Object.assign({},e),{[t]:r}),{})}class oe{constructor(e=document.documentElement,t=N){this.logger=console,this.debug=!1,this.logDebugActivity=(e,t,r={})=>{this.debug&&this.logFormattedMessage(e,t,r)},this.element=e,this.schema=t,this.dispatcher=new I(this),this.router=new ne(this),this.actionDescriptorFilters=Object.assign({},j)}static start(e,t){e=new this(e,t);return e.start(),e}async start(){await new Promise(e=>{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",()=>e()):e()}),this.logDebugActivity("application","starting"),this.dispatcher.start(),this.router.start(),this.logDebugActivity("application","start")}stop(){this.logDebugActivity("application","stopping"),this.dispatcher.stop(),this.router.stop(),this.logDebugActivity("application","stop")}register(e,t){this.load({identifier:e,controllerConstructor:t})}registerActionOption(e,t){this.actionDescriptorFilters[e]=t}load(e,...t){(Array.isArray(e)?e:[e,...t]).forEach(e=>{e.controllerConstructor.shouldLoad&&this.router.loadDefinition(e)})}unload(e,...t){(Array.isArray(e)?e:[e,...t]).forEach(e=>this.router.unloadIdentifier(e))}get controllers(){return this.router.contexts.map(e=>e.controller)}getControllerForElementAndIdentifier(e,t){e=this.router.getContextForElementAndIdentifier(e,t);return e?e.controller:null}handleError(e,t,r){this.logger.error(`%s + +%o + +%o`,t,e,r),null!=(r=window.onerror)&&r.call(window,t,"",0,0,e)}logFormattedMessage(e,t,r={}){r=Object.assign({application:this},r),this.logger.groupCollapsed(e+" #"+t),this.logger.log("details:",Object.assign({},r)),this.logger.groupEnd()}}function B(e,t,r){return e.application.getControllerForElementAndIdentifier(t,r)}function C(e,t,r){var s=B(e,t,r);return s||(e.application.router.proposeToConnectScopeForElementAndIdentifier(t,r),B(e,t,r))||void 0}function T([s,n],o){{let{token:e,typeDefinition:i}=o={controller:o,token:s,typeDefinition:n},t=h(e)+"-value",r=function(e){var{controller:e,token:t,typeDefinition:r}=e,s={controller:e,token:t,typeObject:r},s=function(e){var{controller:t,token:r,typeObject:s}=e,i=c(s.type),n=c(s.default),o=i&&n,a=i&&!n,i=!i&&n,n=S(s.type),e=x(e.typeObject.default);if(a)return n;if(i)return e;if(n===e)return o?n:void 0;throw new Error(`The specified default value for the Stimulus Value "${t?t+"."+r:r}" must match the defined type "${n}". The provided default value of "${s.default}" is of type "${e}".`)}(s),i=x(r),n=S(r),s=s||i||n;if(s)return s;i=e?e+"."+r:t;throw new Error(`Unknown value type "${i}" for "${t}" value`)}(o);return{type:r,key:t,name:a(t),get defaultValue(){var e=i;if(t=S(e))return D[t];var t=u(e,"default"),r=u(e,"type"),s=e;if(t)return s.default;if(r){t=s.type,r=S(t);if(r)return D[r]}return e},get hasCustomDefaultValue(){return void 0!==x(i)},reader:ae[r],writer:L[r]||L.default}}}function S(e){switch(e){case Array:return"array";case Boolean:return"boolean";case Number:return"number";case Object:return"object";case String:return"string"}}function x(e){switch(typeof e){case"boolean":return"boolean";case"number":return"number";case"string":return"string"}return Array.isArray(e)?"array":"[object Object]"===Object.prototype.toString.call(e)?"object":void 0}const D={get array(){return[]},boolean:!1,number:0,get object(){return{}},string:""},ae={array(e){var t=JSON.parse(e);if(Array.isArray(t))return t;throw new TypeError(`expected value of type "array" but instead got value "${e}" of type "${x(t)}"`)},boolean(e){return!("0"==e||"false"==String(e).toLowerCase())},number(e){return Number(e.replace(/_/g,""))},object(e){var t=JSON.parse(e);if(null===t||"object"!=typeof t||Array.isArray(t))throw new TypeError(`expected value of type "object" but instead got value "${e}" of type "${x(t)}"`);return t},string(e){return e}},L={default:function(e){return""+e},array:le,object:le};function le(e){return JSON.stringify(e)}class V{constructor(e){this.context=e}static get shouldLoad(){return!0}static afterLoad(e,t){}get application(){return this.context.application}get scope(){return this.context.scope}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get targets(){return this.scope.targets}get outlets(){return this.scope.outlets}get classes(){return this.scope.classes}get data(){return this.scope.data}initialize(){}connect(){}disconnect(){}dispatch(e,{target:t=this.element,detail:r={},prefix:s=this.identifier,bubbles:i=!0,cancelable:n=!0}={}){s=new CustomEvent(s?s+":"+e:e,{detail:r,bubbles:i,cancelable:n});return t.dispatchEvent(s),s}}V.blessings=[function(e){return E(e,"classes").reduce((e,t)=>{return Object.assign(e,{[(r=t)+"Class"]:{get(){var e=this.classes;if(e.has(r))return e.get(r);throw e=e.getAttributeName(r),new Error(`Missing attribute "${e}"`)}},[r+"Classes"]:{get(){return this.classes.getAll(r)}},[`has${l(r)}Class`]:{get(){return this.classes.has(r)}}});var r},{})},function(e){return E(e,"targets").reduce((e,t)=>{return Object.assign(e,{[(r=t)+"Target"]:{get(){var e=this.targets.find(r);if(e)return e;throw new Error(`Missing target element "${r}" for "${this.identifier}" controller`)}},[r+"Targets"]:{get(){return this.targets.findAll(r)}},[`has${l(r)}Target`]:{get(){return this.targets.has(r)}}});var r},{})},function(e){const t=J(e,"values");return t.reduce((e,t)=>Object.assign(e,function(e,t){let r=T(e,t),{key:s,name:i,reader:n,writer:o}=r;return{[i]:{get(){var e=this.data.get(s);return null!==e?n(e):r.defaultValue},set(e){void 0===e?this.data.delete(s):this.data.set(s,o(e))}},["has"+l(i)]:{get(){return this.data.has(s)||r.hasCustomDefaultValue}}}}(t)),{valueDescriptorMap:{get(){return t.reduce((e,t)=>{var t=T(t,this.identifier),r=this.data.getAttributeNameForKey(t.key);return Object.assign(e,{[r]:t})},{})}}})},function(e){return E(e,"outlets").reduce((e,t)=>{return Object.assign(e,{[(e=s(r=t))+"Outlet"]:{get(){var e=this.outlets.find(r),t=this.outlets.getSelectorForOutletName(r);if(e){e=C(this,e,r);if(e)return e;throw new Error(`The provided outlet element is missing an outlet controller "${r}" instance for host controller "${this.identifier}"`)}throw new Error(`Missing outlet element "${r}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${t}".`)}},[e+"Outlets"]:{get(){var e=this.outlets.findAll(r);return 0{var t=C(this,e,r);if(t)return t;console.warn(`The provided outlet element is missing an outlet controller "${r}" instance for host controller "${this.identifier}"`,e)}).filter(e=>e):[]}},[e+"OutletElement"]:{get(){var e=this.outlets.find(r),t=this.outlets.getSelectorForOutletName(r);if(e)return e;throw new Error(`Missing outlet element "${r}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${t}".`)}},[e+"OutletElements"]:{get(){return this.outlets.findAll(r)}},[`has${l(e)}Outlet`]:{get(){return this.outlets.has(r)}}});var r},{})}],V.targets=[],V.outlets=[],V.values={},e.Application=oe,e.AttributeObserver=m,e.Context=M,e.Controller=V,e.ElementObserver=d,e.IndexedMultimap=z,e.Multimap=v,e.SelectorObserver=b,e.StringMapObserver=y,e.TokenListObserver=O,e.ValueListObserver=A,e.add=r,e.defaultSchema=N,e.del=g,e.fetch=p,e.prune=f,Object.defineProperty(e,"__esModule",{value:!0})}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/table_vew.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/table_vew.css new file mode 100644 index 0000000..263332e --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/table_vew.css @@ -0,0 +1,79 @@ +/* ultimate table view */ + +.content-view-table { + border-collapse: collapse; + width: 100%; + background-color: var(--color-bg-contrast); +} + +/* .content-view-table td, +.content-view-table th, */ +.content-view-th, +.content-view-td { + padding: .5rem 1rem; + border: 1px solid #666; + vertical-align: top; +} + +.content-view-th { + text-align: left; + text-transform: uppercase; + background-color: var(--color-border); + font-size: .85em; + font-weight: bold; +} + +.content-view-td-type, +.content-view-td-meta { + background-color: var(--color-bg-main); + font-size: .85em; +} + +.content-view-td-type { + background-color: var(--color-bg-main); + text-align: left; + font-weight: normal; + text-transform: uppercase; +} + +.content-view-table div.document { + /* TODO */ + display: block; + max-width: 900px; +} + +.content-view-table p:first-child { + margin-top: 0; +} + +.content-view-table p:last-child { + margin-bottom: 0; +} + +.content-view-td:empty { + width: 1%; +} + +.content-view-td-content:not(:empty) { + min-width: 333px; + width: 30%; +} + +.content-view-td-title:not(:empty) { + font-weight: bold; + min-width: 264px; +} + +.content-view-td-related:not(:empty) { + min-width: 264px; +} + +.content-view-td-related, +.content-view-td-related > ul.requirement__link { + font-size: .85rem; + margin-top: 0; +} + +.content-view-td-related > ul.requirement__link:last-child { + margin-bottom: 0; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/toc_highlighting.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/toc_highlighting.js new file mode 100644 index 0000000..fb96016 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/toc_highlighting.js @@ -0,0 +1,291 @@ +const TOC_HIGHLIGHT_DEBUG = false; + +const TOC_FRAME_SELECTOR = 'turbo-frame#frame-toc'; // updating +const TOC_LIST_SELECTOR = 'ul#toc'; +const TOC_ELEMENT_SELECTOR = 'a'; +const CONTENT_FRAME_SELECTOR = 'turbo-frame#frame_document_content'; // replacing => parentNode is needed +const CONTENT_ELEMENT_SELECTOR = 'sdoc-anchor'; + +let tocHighlightingState = { + data: {}, + links: null, + anchors: null, + contentFrameTop: undefined, + closerForFolder: {}, + folderSet: new Set(), +}; + +function resetState() { + tocHighlightingState.data = {}; + tocHighlightingState.links = null; + tocHighlightingState.anchors = null; + tocHighlightingState.closerForFolder = {}; + tocHighlightingState.folderSet = new Set(); +} + +window.addEventListener("hashchange", handleHashChange); +window.addEventListener("load",function(){ + + // * Frames are stable and we define them once. + const tocFrame = document.querySelector(TOC_FRAME_SELECTOR); + const tocList = tocFrame ? tocFrame.querySelector(TOC_LIST_SELECTOR) : null; + const contentFrame = document.querySelector(CONTENT_FRAME_SELECTOR)?.parentNode; + + if(!tocFrame || !tocList || !contentFrame) { return } + + // ! depends on TOC markup + tocHighlightingState.contentFrameTop = contentFrame.offsetParent + ? contentFrame.offsetTop + : contentFrame.parentNode.offsetTop; + + const anchorObserver = new IntersectionObserver( + handleIntersect, + { + root: null, + rootMargin: "0px", + }); + + // * Then we will refresh when the TOC tree is updated& + // * The content in the tocFrame frame will mutate: + const mutatingFrame = tocFrame; + new MutationObserver(function (mutationsList, observer) { + // * Use requestAnimationFrame to put highlightTOC + // * at the end of the event queue and to ensure + // * the code runs after all DOM changes have been applied. + requestAnimationFrame(() => { + highlightTOC(tocFrame, contentFrame, anchorObserver); + }) + }).observe( + mutatingFrame, + { + // * We're looking at an updatable frame (mutates its contents, + // * and we don't care what mutations were made inside): + childList: true, + // attributes: true, + // characterData: true, + // subtree: true + } + ); + + // * Call for the first time only if the TOC actually contains items. + if (tocList && tocList.querySelector(TOC_ELEMENT_SELECTOR)) { + highlightTOC(tocFrame, contentFrame, anchorObserver); + } + +},false); + +function highlightTOC(tocFrame, contentFrame, anchorObserver) { + + resetState(); + processLinkList(tocFrame); + processAnchorList(contentFrame, anchorObserver); + handleHashChange(); + + TOC_HIGHLIGHT_DEBUG && console.log(tocHighlightingState); +} + +function handleHashChange() { + const hash = window.location.hash; + const match = hash.match(/#(.*)/); + const fragment = match ? match[1] : null; + + // Guard: no links collected yet (e.g., empty TOC or init race) + if (!tocHighlightingState.links || typeof tocHighlightingState.links.forEach !== 'function') { + return; + } + + tocHighlightingState.links.forEach(link => { + targetItem(link, false) + }); + // * When updating the hash + // * and there's a fragment, + fragment + // * and the corresponding link-anchor pair is registered, + && tocHighlightingState.data[fragment] + // * highlight the corresponding link. + && targetItem(tocHighlightingState.data[fragment].link) +} + +function processLinkList(tocFrame) { + // * Collects all links in the TOC + tocHighlightingState.links = tocFrame.querySelectorAll(TOC_ELEMENT_SELECTOR); + if (!tocHighlightingState.links || tocHighlightingState.links.length === 0) { + return; + } + tocHighlightingState.links.length + && tocHighlightingState.links.forEach(link => { + const id = link.getAttribute('anchor'); + tocHighlightingState.data[id] = { + 'link': link, + ...tocHighlightingState.data[id] + } + + // ! depends on TOC markup + // is link in collapsible node and precedes the UL + // ! expected UL or null + const ul = link.nextSibling; + + if (ul && ul.nodeName === 'UL') { + // register folder + tocHighlightingState.folderSet.add(id); + + // register closer + const lastLink = findDeepestLastChild(ul); + const lastAnchor = lastLink.getAttribute('anchor'); + + + if (!tocHighlightingState.closerForFolder[lastAnchor]) { + tocHighlightingState.closerForFolder[lastAnchor] = []; + } + tocHighlightingState.closerForFolder[lastAnchor].push(id); + } + }); +} + +function processAnchorList(contentFrame, anchorObserver) { + anchorObserver.disconnect(); // FIXME don`t work: have to hack at #rootBounds_null + + // * Collects all anchors in the document + tocHighlightingState.anchors = null; + tocHighlightingState.anchors = contentFrame.querySelectorAll(CONTENT_ELEMENT_SELECTOR); + tocHighlightingState.anchors.length + && tocHighlightingState.anchors.forEach(anchor => { + const id = anchor.id; + tocHighlightingState.data[id] = { + 'anchor': anchor, + ...tocHighlightingState.data[id] + }; + // * Adds an observer for the position of the anchor + anchorObserver.observe(anchor); + }); +} + +function handleIntersect(entries, observer) { + + entries.forEach((entry) => { + + // #rootBounds_null + // rootBounds: null + // after frame reload and before init + if(!entry.rootBounds) { + return + } + + const anchor = entry.target.id; + // * For anchors that go into the viewport, + // * finds the corresponding links + const link = tocHighlightingState.data[anchor].link; + + // * if there is no menu item for the section in the TOC + if(!link) { + return + } + + if (entry.isIntersecting) { //! entry.intersectionRatio > 0 -- it happens to be equal to zero at the intersection! + + TOC_HIGHLIGHT_DEBUG && console.group('🔶', entry.isIntersecting, entry.intersectionRatio, anchor, entry.intersectionRect.height); + // * and highlights them in the TOC, + fireItem(link) + + // * semi-highlights folder in the TOC, + if (tocHighlightingState.folderSet.has(anchor)) { + TOC_HIGHLIGHT_DEBUG && console.log('🔴', anchor, '(visible folder)', ); + fireFolder(link) + } + + // * semi-highlights closer`s parent folder in the TOC, + if (tocHighlightingState.closerForFolder[anchor]) { + tocHighlightingState.closerForFolder[anchor].forEach(id => { + TOC_HIGHLIGHT_DEBUG && console.log(`🔴`, id, `(from ${anchor})`); + fireFolder(tocHighlightingState.data[id].link) + }) + } + TOC_HIGHLIGHT_DEBUG && console.groupEnd(); + + } else { + + TOC_HIGHLIGHT_DEBUG && console.group('🔹', entry.isIntersecting, entry.intersectionRatio, anchor); + // * or cancels highlighting for the rest of the links. + fireItem(link, false); + + if( + // * If the node goes down ⬇️ off the screen + entry.boundingClientRect.bottom >= entry.rootBounds.bottom + // * and it's a folder + && tocHighlightingState.folderSet.has(anchor) + ) { + // ** remove highlights from folder in the TOC + TOC_HIGHLIGHT_DEBUG && console.log(`⚫ ⬇️`, anchor); + fireFolder(link, false) + } + + if( + // * If the node goes up ⬆️ off the screen + entry.boundingClientRect.y < tocHighlightingState.contentFrameTop + // * and this is the last child of the section + && tocHighlightingState.closerForFolder[anchor] + ) { + // * When the LAST CHILD of the section disappears + // * over the upper boundary ( < tocHighlightingState.contentFrameTop), + // * strictly speaking, this occurs when the lower bound disappears: + // * entry.boundingClientRect.bottom. + // * But we will use the upper bound, entry.boundingClientRect.y + // * which will be less than or equal to the lower bound. + + // ** remove highlights from closer`s parent folder in the TOC + tocHighlightingState.closerForFolder[anchor].forEach(id => { + TOC_HIGHLIGHT_DEBUG && console.log(`⚫ ⬆️`, id,); + fireFolder(tocHighlightingState.data[id].link, false) + }); + } + + TOC_HIGHLIGHT_DEBUG && console.groupEnd(); + } + }); + +} + +function findDeepestLastChild(element) { + // ! depends on TOC markup + // ul > li > div + a + ul > ... + // ul > li > a + // > li > a <---------------*** + if (element.nodeName === 'A') { + return element; + } + const children = element.children; + if (children && children.length > 0) { + return findDeepestLastChild([...children].at(-1)) + } else { + return element; + } +} + +function targetItem(element, on = true) { + if (!element) { return } // Guard against race conditions: + // hashchange or intersection events may fire + // before the TOC is fully built, resulting in undefined link elements. + if(on) { + element.setAttribute('targeted', ''); + } else { + element.removeAttribute('targeted'); + } +} + +function fireItem(element, on = true) { + if (!element) { return } // Guard against race conditions + if(on) { + element.setAttribute('intersected', ''); + } else { + element.removeAttribute('intersected'); + } +} + +function fireFolder(element, on = true) { + if (!element) { return } // Guard against race conditions + if(on) { + element.setAttribute('parented', ''); + } else { + element.removeAttribute('parented'); + } +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.css new file mode 100644 index 0000000..6c9c279 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.css @@ -0,0 +1,148 @@ +.traceability_matrix { + --traceability_matrix-thead-height: calc(4 * var(--base-rhythm)); + + + display: table; + border-collapse: collapse; +} + +.traceability_matrix__anchor { + /* for Fixed Headers + Section Anchors */ + scroll-snap-margin-top: var(--base-gap); + scroll-margin-top: var(--base-gap); +} + +.traceability_matrix .traceability_matrix__thead { + position: sticky; + top: calc(-1 * var(--traceability_matrix-thead-height)); + z-index: 2; + background-color: var(--color-bg-main); +} + +.traceability_matrix .traceability_matrix__thead::before { + content: ''; + position: absolute; + top: calc(-1 * var(--base-gap)); + left: calc(-1 * var(--base-gap)); + right: calc(-1 * var(--base-gap)); + bottom: 0; + z-index: 0; + background-color: var(--color-bg-main); +} + +.traceability_matrix__thead th { + height: var(--traceability_matrix-thead-height); + text-align: left; + vertical-align: middle; + line-height: 1; + position: relative; + background-color: var(--color-bg-secondary-invert); + padding-left: var(--base-rhythm); + border: 1px solid var(--color-border); +} + +.traceability_matrix td { + border: 1px solid var(--color-border); + background-color: var(--color-bg-contrast); + vertical-align: top; +} + +td.traceability_matrix__document { + position: sticky; + padding: 0; + top: 0; + z-index: 1; +} + +.traceability_matrix__placeholder { + padding: var(--base-rhythm); + text-align: center; + font-size: var(--font-size-sm); +} + +td.traceability_matrix__null { + height: calc(4 * var(--base-rhythm)); + background-color: var(--color-bg-main); + border: none; +} + +.traceability_matrix__document_line { + display: flex; + align-items: center; + justify-content: flex-start; + column-gap: calc(2 * var(--base-rhythm)); + font-size: var(--font-size-l); + font-weight: 600; + line-height: 1.2; + width: 100%; + + padding: var(--base-rhythm); + padding-top: calc(1.5 * var(--base-rhythm)); + + border-bottom: 1px solid var(--color-border); +} + +.traceability_matrix__document_stat { + margin-left: auto; +} + +.traceability_matrix__requirement { + display: block; + position: relative; + font-size: var(--font-size-sm); + line-height: 1.2; + padding: var(--base-rhythm); +} + +.traceability_matrix__file { + position: relative; + font-size: var(--font-size-sm); + line-height: 1.2; + margin-top: var(--base-rhythm); + margin-bottom: var(--base-rhythm); + padding-right: var(--base-rhythm); +} + +.traceability_matrix__file a { + /* overflow-wrap: break-word; */ + overflow-wrap: anywhere; + color: var(--color-link); + text-decoration: none; +} + +.traceability_matrix__file a:hover { + color: var(--color-hover); +} + +[with_relation] { + padding-left: calc(4 * var(--base-rhythm)); +} + +[with_relation]::before { + content: ''; + font-size: var(--font-size); + line-height: 1; + position: absolute; + left: var(--base-rhythm); +} + +.traceability_matrix__requirement[with_relation]::before { + top: var(--base-rhythm); +} + +.traceability_matrix__file[with_relation]::before { + top: 0 +} + +/* ← → */ +[with_relation="parent"]::before { + content: '→'; +} + +[with_relation="child"]::before { + content: '←'; +} + +[with_relation="file"]::before { + content: '→'; +} diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.js new file mode 100644 index 0000000..9be993e --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/traceability_matrix_screen.js @@ -0,0 +1,48 @@ +// @relation(SDOC-SRS-112, scope=file) + +const SELECTOR = '[js-requirements-coverage]'; + +const __log = (topic, ...payload) => { + console.log(`%c ${topic} `, 'background:yellow;color:black', + ...payload + ); +} + +function markSame(newUid, state, arr) { + // __log('state', state.currentUid); + state.currentUid && arr[state.currentUid].forEach(element => element.classList.remove('highlighted')); + state.currentUid = newUid; + arr[newUid].forEach(element => element.classList.add('highlighted')); + +} + +window.addEventListener("load", function () { + // __log( + // 'requirements-coverage', + // 'test' + // ) + + const state = { + currentUid: null + } + + // https://stackoverflow.com/questions/32249997/how-to-check-if-data-attribute-exist-with-plain-javascript/32250073 + const reqs = [...document.querySelectorAll(SELECTOR)] + .reduce((acc, req) => { + if (req.hasAttribute('data-uid')) { + req.addEventListener('click', () => markSame(uid, state, reqs)); + const uid = req.dataset.uid; + acc[uid] = acc[uid] ? [...acc[uid], req] : [req]; + } else { + req.classList.add('nouid') + acc.nouid.push(req); + } + return acc + }, { nouid: [] }); + + // __log( + // '--', + // reqs + // ) + +}); diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/tree(not_in_use).css b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/tree(not_in_use).css new file mode 100644 index 0000000..acd2a13 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/tree(not_in_use).css @@ -0,0 +1,146 @@ +.std-tree { + --tree-font-size: 16px; + --tree-line-height: calc(var(--tree-font-size)*1.25); + --tree-level-padding: calc(var(--tree-font-size)*1.5); + --tree-cell-padding: calc(var(--tree-font-size)*0.5); + + --tree-level-line-width: 1px; + + --tree-color-line: #808080; + --tree-color-fg: var(--color-fg-main, #444444); + --tree-color-bg: var(--color-bg-main, #F2F5F9); + --tree-color-row-hover-bg: var(--color-bg-contrast, #FFFFFF); + --tree-btn-bg-color: var(--color-bg-contrast, #FFFFFF); + + --tree-half-sell-height: calc( var(--tree-line-height)/2 + var(--tree-cell-padding) ); + + --tree-ico-size: var(--tree-font-size, 1rem); + + --tree-max-width: 800px; +} + + +/* tree */ +.std-tree { + font-size: var(--tree-font-size, 1rem); + line-height: var(--tree-line-height, 1.25); + color: var(--tree-color-fg, #444444); + + position: relative; + width: -moz-fit-content; + width: fit-content; + /* margin: 0 auto; */ +} + +.std-tree ul { + list-style: none; + width: 100%; + padding: 0; + margin: 0; +} + +.std-tree li { + position: relative; + padding-left: var(--tree-level-padding); +} + +.std-tree ul ul > li::before { + content: ''; + position: absolute; + left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding)); + top: calc(var(--tree-ico-size)*(-0.5)); + height: 100%; + border-left: 1px solid var(--tree-color-line); +} + +.std-tree ul > li:last-child::before { + height: calc(var(--tree-ico-size) + var(--tree-cell-padding)); +} + +.std-tree_ico { + display: inline-flex; + align-items: center; + + position: absolute; + left: 0; + top: calc(var(--tree-cell-padding)); +} + + ul ul .std-tree_ico::before { + content: ''; + position: absolute; + left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding)); + right: 100%; + border-bottom: 1px solid var(--tree-color-line); + } + + .std-tree_ico svg { + display: inline-block; + width: var(--tree-ico-size); + height: var(--tree-ico-size); + + fill: var(--tree-color-line); + } + + .std-tree_row { + padding-top: var(--tree-cell-padding); + padding-bottom: var(--tree-cell-padding); + padding-left: var(--tree-cell-padding); + + display: flex; + justify-content: space-between; + } + + .std-tree_folder { + font-weight: bold; + display: flex; + } + + .std-tree_file { + order: 1; + flex-grow: 1; + } + + .std-tree_file__title { + font-size: 1.25em; + color: #000; + transition: color .2s ease; + } + + .std-tree_file-link:hover .std-tree_file__title { + color: var(--color-fg-accent); + } + + .std-tree_file__name { + font-size: 0.85rem; + line-height: 1.2; + color: var(--color-fg-secondary); + margin-top: 0.25rem; + } + + .std-tree_desc { + position: relative; + top: -2px; + color: #000; + } + + .std-tree_name { + font-size: 0.85rem; + line-height: 1.2; + color: #666; + } + + .std-tree_aside { + width: -moz-fit-content; + width: fit-content; + padding-left: 20px; + display: flex; + justify-content: space-between; + align-items: flex-start; + order: 3; + } + + .std-tree_file-link { + position: relative; + top: -2px; + } diff --git a/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/turbo.min.js b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/turbo.min.js new file mode 100644 index 0000000..ee8fdf3 --- /dev/null +++ b/tests/integration/_validation/20251011_strictdoc_guide_broken_admonition_page_split/assets/turbo.min.js @@ -0,0 +1,24 @@ +!function(){if(void 0!==window.Reflect&&void 0!==window.customElements&&!window.customElements.polyfillWrapFlushCallback){const e=HTMLElement,t=function(){return Reflect.construct(e,[],this.constructor)};window.HTMLElement=t,HTMLElement.prototype=e.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,e)}}(),function(e){function r(e,t,s){throw new e("Failed to execute 'requestSubmit' on 'HTMLFormElement': "+t+".",s)}"function"!=typeof e.requestSubmit&&(e.requestSubmit=function(e){var t,s;e?(s=this,(t=e)instanceof HTMLElement||r(TypeError,"parameter 1 is not of type 'HTMLElement'"),"submit"!=t.type&&r(TypeError,"The specified element is not a submit button"),t.form!=s&&r(DOMException,"The specified element is not owned by this form element","NotFoundError"),e.click()):((e=document.createElement("input")).type="submit",e.hidden=!0,this.appendChild(e),e.click(),this.removeChild(e))})}(HTMLFormElement.prototype);const submittersByForm=new WeakMap;function findSubmitterFromClickTarget(e){e=e instanceof Element?e:e instanceof Node?e.parentElement:null,e=e?e.closest("input, button"):null;return"submit"==(null==e?void 0:e.type)?e:null}function clickCaptured(e){e=findSubmitterFromClickTarget(e.target);e&&e.form&&submittersByForm.set(e.form,e)}var FrameLoadingStyle,FetchMethod,FormSubmissionState,FormEnctype,TimingMetric,VisitState,SystemStatusCode,PageStage;!function(){if(!("submitter"in Event.prototype)){let e;if("SubmitEvent"in window&&/Apple Computer/.test(navigator.vendor))e=window.SubmitEvent.prototype;else{if("SubmitEvent"in window)return;e=window.Event.prototype}addEventListener("click",clickCaptured,!0),Object.defineProperty(e,"submitter",{get(){if("submit"==this.type&&this.target instanceof HTMLFormElement)return submittersByForm.get(this.target)}})}}(),function(e){e.eager="eager",e.lazy="lazy"}(FrameLoadingStyle=FrameLoadingStyle||{});class FrameElement extends HTMLElement{constructor(){super(),this.loaded=Promise.resolve(),this.delegate=new FrameElement.delegateConstructor(this)}static get observedAttributes(){return["disabled","loading","src"]}connectedCallback(){this.delegate.connect()}disconnectedCallback(){this.delegate.disconnect()}reload(){var e=this["src"];this.src=null,this.src=e}attributeChangedCallback(e){"loading"==e?this.delegate.loadingStyleChanged():"src"==e?this.delegate.sourceURLChanged():this.delegate.disabledChanged()}get src(){return this.getAttribute("src")}set src(e){e?this.setAttribute("src",e):this.removeAttribute("src")}get loading(){return frameLoadingStyleFromString(this.getAttribute("loading")||"")}set loading(e){e?this.setAttribute("loading",e):this.removeAttribute("loading")}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get autoscroll(){return this.hasAttribute("autoscroll")}set autoscroll(e){e?this.setAttribute("autoscroll",""):this.removeAttribute("autoscroll")}get complete(){return!this.delegate.isLoading}get isActive(){return this.ownerDocument===document&&!this.isPreview}get isPreview(){var e;return null==(e=null==(e=this.ownerDocument)?void 0:e.documentElement)?void 0:e.hasAttribute("data-turbo-preview")}}function frameLoadingStyleFromString(e){return"lazy"!==e.toLowerCase()?FrameLoadingStyle.eager:FrameLoadingStyle.lazy}function expandURL(e){return new URL(e.toString(),document.baseURI)}function getAnchor(e){return e.hash?e.hash.slice(1):(e=e.href.match(/#(.*)$/))?e[1]:void 0}function getAction(e,t){return expandURL((null==t?void 0:t.getAttribute("formaction"))||e.getAttribute("action")||e.action)}function getExtension(e){return(getLastPathComponent(e).match(/\.[^.]*$/)||[])[0]||""}function isHTML(e){return!!getExtension(e).match(/^(?:|\.(?:htm|html|xhtml))$/)}function isPrefixedBy(e,t){t=getPrefix(t);return e.href===expandURL(t).href||e.href.startsWith(t)}function locationIsVisitable(e,t){return isPrefixedBy(e,t)&&isHTML(e)}function getRequestURL(e){var t=getAnchor(e);return null!=t?e.href.slice(0,-(t.length+1)):e.href}function toCacheKey(e){return getRequestURL(e)}function urlsAreEqual(e,t){return expandURL(e).href==expandURL(t).href}function getPathComponents(e){return e.pathname.split("/").slice(1)}function getLastPathComponent(e){return getPathComponents(e).slice(-1)[0]}function getPrefix(e){return addTrailingSlash(e.origin+e.pathname)}function addTrailingSlash(e){return e.endsWith("/")?e:e+"/"}class FetchResponse{constructor(e){this.response=e}get succeeded(){return this.response.ok}get failed(){return!this.succeeded}get clientError(){return 400<=this.statusCode&&this.statusCode<=499}get serverError(){return 500<=this.statusCode&&this.statusCode<=599}get redirected(){return this.response.redirected}get location(){return expandURL(this.response.url)}get isHTML(){return this.contentType&&this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/)}get statusCode(){return this.response.status}get contentType(){return this.header("Content-Type")}get responseText(){return this.response.clone().text()}get responseHTML(){return this.isHTML?this.response.clone().text():Promise.resolve(void 0)}header(e){return this.response.headers.get(e)}}function dispatch(e,{target:t,cancelable:s,detail:r}={}){e=new CustomEvent(e,{cancelable:s,bubbles:!0,detail:r});return(t&&t.isConnected?t:document.documentElement).dispatchEvent(e),e}function nextAnimationFrame(){return new Promise(e=>requestAnimationFrame(()=>e()))}function nextEventLoopTick(){return new Promise(e=>setTimeout(()=>e(),0))}function nextMicrotask(){return Promise.resolve()}function parseHTMLDocument(e=""){return(new DOMParser).parseFromString(e,"text/html")}function unindent(e,...t){e=interpolate(e,t).replace(/^\n/,"").split("\n"),t=e[0].match(/^\s+/);const s=t?t[0].length:0;return e.map(e=>e.slice(s)).join("\n")}function interpolate(e,r){return e.reduce((e,t,s)=>{return e+t+(null==r[s]?"":r[s])},"")}function uuid(){return Array.apply(null,{length:36}).map((e,t)=>8==t||13==t||18==t||23==t?"-":14==t?"4":(19==t?Math.floor(4*Math.random())+8:Math.floor(15*Math.random())).toString(16)).join("")}function getAttribute(t,...e){for(const s of e.map(e=>null==e?void 0:e.getAttribute(t)))if("string"==typeof s)return s;return null}function markAsBusy(...e){for(const t of e)"turbo-frame"==t.localName&&t.setAttribute("busy",""),t.setAttribute("aria-busy","true")}function clearBusyState(...e){for(const t of e)"turbo-frame"==t.localName&&t.removeAttribute("busy"),t.removeAttribute("aria-busy")}function fetchMethodFromString(e){switch(e.toLowerCase()){case"get":return FetchMethod.get;case"post":return FetchMethod.post;case"put":return FetchMethod.put;case"patch":return FetchMethod.patch;case"delete":return FetchMethod.delete}}!function(e){e[e.get=0]="get",e[e.post=1]="post",e[e.put=2]="put",e[e.patch=3]="patch",e[e.delete=4]="delete"}(FetchMethod=FetchMethod||{});class FetchRequest{constructor(e,t,s,r=new URLSearchParams,i=null){this.abortController=new AbortController,this.resolveRequestPromise=e=>{},this.delegate=e,this.method=t,this.headers=this.defaultHeaders,this.body=r,this.url=s,this.target=i}get location(){return this.url}get params(){return this.url.searchParams}get entries(){return this.body?Array.from(this.body.entries()):[]}cancel(){this.abortController.abort()}async perform(){var e,t,s=this["fetchOptions"];null!=(t=(e=this.delegate).prepareHeadersForRequest)&&t.call(e,this.headers,this),await this.allowRequestToBeIntercepted(s);try{this.delegate.requestStarted(this);var r=await fetch(this.url.href,s);return await this.receive(r)}catch(e){if("AbortError"!==e.name)throw this.delegate.requestErrored(this,e),e}finally{this.delegate.requestFinished(this)}}async receive(e){e=new FetchResponse(e);return dispatch("turbo:before-fetch-response",{cancelable:!0,detail:{fetchResponse:e},target:this.target}).defaultPrevented?this.delegate.requestPreventedHandlingResponse(this,e):e.succeeded?this.delegate.requestSucceededWithResponse(this,e):this.delegate.requestFailedWithResponse(this,e),e}get fetchOptions(){var e;return{method:FetchMethod[this.method].toUpperCase(),credentials:"same-origin",headers:this.headers,redirect:"follow",body:this.isIdempotent?null:this.body,signal:this.abortSignal,referrer:null==(e=this.delegate.referrer)?void 0:e.href}}get defaultHeaders(){return{Accept:"text/html, application/xhtml+xml"}}get isIdempotent(){return this.method==FetchMethod.get}get abortSignal(){return this.abortController.signal}async allowRequestToBeIntercepted(e){var t=new Promise(e=>this.resolveRequestPromise=e);dispatch("turbo:before-fetch-request",{cancelable:!0,detail:{fetchOptions:e,url:this.url,resume:this.resolveRequestPromise},target:this.target}).defaultPrevented&&await t}}class AppearanceObserver{constructor(e,t){this.started=!1,this.intersect=e=>{e=e.slice(-1)[0];null!=e&&e.isIntersecting&&this.delegate.elementAppearedInViewport(this.element)},this.delegate=e,this.element=t,this.intersectionObserver=new IntersectionObserver(this.intersect)}start(){this.started||(this.started=!0,this.intersectionObserver.observe(this.element))}stop(){this.started&&(this.started=!1,this.intersectionObserver.unobserve(this.element))}}class StreamMessage{constructor(e){this.templateElement=document.createElement("template"),this.templateElement.innerHTML=e}static wrap(e){return"string"==typeof e?new this(e):e}get fragment(){var e=document.createDocumentFragment();for(const t of this.foreignElements)e.appendChild(document.importNode(t,!0));return e}get foreignElements(){return this.templateChildren.reduce((e,t)=>"turbo-stream"==t.tagName.toLowerCase()?[...e,t]:e,[])}get templateChildren(){return Array.from(this.templateElement.content.children)}}function formEnctypeFromString(e){switch(e.toLowerCase()){case FormEnctype.multipart:return FormEnctype.multipart;case FormEnctype.plain:return FormEnctype.plain;default:return FormEnctype.urlEncoded}}StreamMessage.contentType="text/vnd.turbo-stream.html",function(e){e[e.initialized=0]="initialized",e[e.requesting=1]="requesting",e[e.waiting=2]="waiting",e[e.receiving=3]="receiving",e[e.stopping=4]="stopping",e[e.stopped=5]="stopped"}(FormSubmissionState=FormSubmissionState||{}),function(e){e.urlEncoded="application/x-www-form-urlencoded",e.multipart="multipart/form-data",e.plain="text/plain"}(FormEnctype=FormEnctype||{});class FormSubmission{constructor(e,t,s,r=!1){this.state=FormSubmissionState.initialized,this.delegate=e,this.formElement=t,this.submitter=s,this.formData=buildFormData(t,s),this.location=expandURL(this.action),this.method==FetchMethod.get&&mergeFormDataEntries(this.location,[...this.body.entries()]),this.fetchRequest=new FetchRequest(this,this.method,this.location,this.body,this.formElement),this.mustRedirect=r}static confirmMethod(e,t){return confirm(e)}get method(){var e;return fetchMethodFromString(((null==(e=this.submitter)?void 0:e.getAttribute("formmethod"))||this.formElement.getAttribute("method")||"").toLowerCase())||FetchMethod.get}get action(){var e,t="string"==typeof this.formElement.action?this.formElement.action:null;return(null==(e=this.submitter)?void 0:e.getAttribute("formaction"))||this.formElement.getAttribute("action")||t||""}get body(){return this.enctype==FormEnctype.urlEncoded||this.method==FetchMethod.get?new URLSearchParams(this.stringFormData):this.formData}get enctype(){var e;return formEnctypeFromString((null==(e=this.submitter)?void 0:e.getAttribute("formenctype"))||this.formElement.enctype)}get isIdempotent(){return this.fetchRequest.isIdempotent}get stringFormData(){return[...this.formData].reduce((e,[t,s])=>e.concat("string"==typeof s?[[t,s]]:[]),[])}get confirmationMessage(){return this.formElement.getAttribute("data-turbo-confirm")}get needsConfirmation(){return null!==this.confirmationMessage}async start(){var{initialized:e,requesting:t}=FormSubmissionState;if(this.needsConfirmation&&!FormSubmission.confirmMethod(this.confirmationMessage,this.formElement))return;if(this.state==e)return this.state=t,this.fetchRequest.perform()}stop(){var{stopping:e,stopped:t}=FormSubmissionState;if(this.state!=e&&this.state!=t)return this.state=e,this.fetchRequest.cancel(),!0}prepareHeadersForRequest(e,t){t.isIdempotent||((t=getCookieValue(getMetaContent("csrf-param"))||getMetaContent("csrf-token"))&&(e["X-CSRF-Token"]=t),e.Accept=[StreamMessage.contentType,e.Accept].join(", "))}requestStarted(e){var t;this.state=FormSubmissionState.waiting,null!=(t=this.submitter)&&t.setAttribute("disabled",""),dispatch("turbo:submit-start",{target:this.formElement,detail:{formSubmission:this}}),this.delegate.formSubmissionStarted(this)}requestPreventedHandlingResponse(e,t){this.result={success:t.succeeded,fetchResponse:t}}requestSucceededWithResponse(e,t){t.clientError||t.serverError?this.delegate.formSubmissionFailedWithResponse(this,t):this.requestMustRedirect(e)&&responseSucceededWithoutRedirect(t)?(e=new Error("Form responses must redirect to another location"),this.delegate.formSubmissionErrored(this,e)):(this.state=FormSubmissionState.receiving,this.result={success:!0,fetchResponse:t},this.delegate.formSubmissionSucceededWithResponse(this,t))}requestFailedWithResponse(e,t){this.result={success:!1,fetchResponse:t},this.delegate.formSubmissionFailedWithResponse(this,t)}requestErrored(e,t){this.result={success:!1,error:t},this.delegate.formSubmissionErrored(this,t)}requestFinished(e){var t;this.state=FormSubmissionState.stopped,null!=(t=this.submitter)&&t.removeAttribute("disabled"),dispatch("turbo:submit-end",{target:this.formElement,detail:Object.assign({formSubmission:this},this.result)}),this.delegate.formSubmissionFinished(this)}requestMustRedirect(e){return!e.isIdempotent&&this.mustRedirect}}function buildFormData(e,t){var e=new FormData(e),s=null==t?void 0:t.getAttribute("name"),t=null==t?void 0:t.getAttribute("value");return s&&null!=t&&e.get(s)!=t&&e.append(s,t),e}function getCookieValue(t){var e;return null!=t&&(e=(document.cookie?document.cookie.split("; "):[]).find(e=>e.startsWith(t)))&&(e=e.split("=").slice(1).join("="))?decodeURIComponent(e):void 0}function getMetaContent(e){e=document.querySelector(`meta[name="${e}"]`);return e&&e.content}function responseSucceededWithoutRedirect(e){return 200==e.statusCode&&!e.redirected}function mergeFormDataEntries(e,t){var s,r,i=new URLSearchParams;for([s,r]of t)r instanceof File||i.append(s,r);return e.search=i.toString(),e}class Snapshot{constructor(e){this.element=e}get children(){return[...this.element.children]}hasAnchor(e){return null!=this.getElementForAnchor(e)}getElementForAnchor(e){return e?this.element.querySelector(`[id='${e}'], a[name='${e}']`):null}get isConnected(){return this.element.isConnected}get firstAutofocusableElement(){return this.element.querySelector("[autofocus]")}get permanentElements(){return[...this.element.querySelectorAll("[id][data-turbo-permanent]")]}getPermanentElementById(e){return this.element.querySelector(`#${e}[data-turbo-permanent]`)}getPermanentElementMapForSnapshot(e){var t={};for(const i of this.permanentElements){var s=i["id"],r=e.getPermanentElementById(s);r&&(t[s]=[i,r])}return t}}class FormInterceptor{constructor(e,t){this.submitBubbled=e=>{var t,s=e.target;!e.defaultPrevented&&s instanceof HTMLFormElement&&s.closest("turbo-frame, html")==this.element&&"dialog"!=((null==(t=e.submitter||void 0)?void 0:t.getAttribute("formmethod"))||s.method)&&this.delegate.shouldInterceptFormSubmission(s,t)&&(e.preventDefault(),e.stopImmediatePropagation(),this.delegate.formSubmissionIntercepted(s,t))},this.delegate=e,this.element=t}start(){this.element.addEventListener("submit",this.submitBubbled)}stop(){this.element.removeEventListener("submit",this.submitBubbled)}}class View{constructor(e,t){this.resolveRenderPromise=e=>{},this.resolveInterceptionPromise=e=>{},this.delegate=e,this.element=t}scrollToAnchor(e){e=this.snapshot.getElementForAnchor(e);e?(this.scrollToElement(e),this.focusElement(e)):this.scrollToPosition({x:0,y:0})}scrollToAnchorFromLocation(e){this.scrollToAnchor(getAnchor(e))}scrollToElement(e){e.scrollIntoView()}focusElement(e){e instanceof HTMLElement&&(e.hasAttribute("tabindex")?e.focus():(e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")))}scrollToPosition({x:e,y:t}){this.scrollRoot.scrollTo(e,t)}scrollToTop(){this.scrollToPosition({x:0,y:0})}get scrollRoot(){return window}async render(e){var{isPreview:t,shouldRender:s,newSnapshot:r}=e;if(s)try{this.renderPromise=new Promise(e=>this.resolveRenderPromise=e),this.renderer=e,this.prepareToRenderSnapshot(e);var i=new Promise(e=>this.resolveInterceptionPromise=e);this.delegate.allowsImmediateRender(r,this.resolveInterceptionPromise)||await i,await this.renderSnapshot(e),this.delegate.viewRenderedSnapshot(r,t),this.finishRenderingSnapshot(e)}finally{delete this.renderer,this.resolveRenderPromise(void 0),delete this.renderPromise}else this.invalidate()}invalidate(){this.delegate.viewInvalidated()}prepareToRenderSnapshot(e){this.markAsPreview(e.isPreview),e.prepareToRender()}markAsPreview(e){e?this.element.setAttribute("data-turbo-preview",""):this.element.removeAttribute("data-turbo-preview")}async renderSnapshot(e){await e.render()}finishRenderingSnapshot(e){e.finishRendering()}}class FrameView extends View{invalidate(){this.element.innerHTML=""}get snapshot(){return new Snapshot(this.element)}}class LinkInterceptor{constructor(e,t){this.clickBubbled=e=>{this.respondsToEventTarget(e.target)?this.clickEvent=e:delete this.clickEvent},this.linkClicked=e=>{this.clickEvent&&this.respondsToEventTarget(e.target)&&e.target instanceof Element&&this.delegate.shouldInterceptLinkClick(e.target,e.detail.url)&&(this.clickEvent.preventDefault(),e.preventDefault(),this.delegate.linkClickIntercepted(e.target,e.detail.url)),delete this.clickEvent},this.willVisit=()=>{delete this.clickEvent},this.delegate=e,this.element=t}start(){this.element.addEventListener("click",this.clickBubbled),document.addEventListener("turbo:click",this.linkClicked),document.addEventListener("turbo:before-visit",this.willVisit)}stop(){this.element.removeEventListener("click",this.clickBubbled),document.removeEventListener("turbo:click",this.linkClicked),document.removeEventListener("turbo:before-visit",this.willVisit)}respondsToEventTarget(e){e=e instanceof Element?e:e instanceof Node?e.parentElement:null;return e&&e.closest("turbo-frame, html")==this.element}}class Bardo{constructor(e){this.permanentElementMap=e}static preservingPermanentElements(e,t){e=new this(e);e.enter(),t(),e.leave()}enter(){for(const t in this.permanentElementMap){var[,e]=this.permanentElementMap[t];this.replaceNewPermanentElementWithPlaceholder(e)}}leave(){for(const t in this.permanentElementMap){var[e]=this.permanentElementMap[t];this.replaceCurrentPermanentElementWithClone(e),this.replacePlaceholderWithPermanentElement(e)}}replaceNewPermanentElementWithPlaceholder(e){var t=createPlaceholderForPermanentElement(e);e.replaceWith(t)}replaceCurrentPermanentElementWithClone(e){var t=e.cloneNode(!0);e.replaceWith(t)}replacePlaceholderWithPermanentElement(e){var t=this.getPlaceholderById(e.id);null!=t&&t.replaceWith(e)}getPlaceholderById(t){return this.placeholders.find(e=>e.content==t)}get placeholders(){return[...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")]}}function createPlaceholderForPermanentElement(e){var t=document.createElement("meta");return t.setAttribute("name","turbo-permanent-placeholder"),t.setAttribute("content",e.id),t}class Renderer{constructor(e,t,s,r=!0){this.currentSnapshot=e,this.newSnapshot=t,this.isPreview=s,this.willRender=r,this.promise=new Promise((e,t)=>this.resolvingFunctions={resolve:e,reject:t})}get shouldRender(){return!0}prepareToRender(){}finishRendering(){this.resolvingFunctions&&(this.resolvingFunctions.resolve(),delete this.resolvingFunctions)}createScriptElement(e){var t;return"false"==e.getAttribute("data-turbo-eval")?e:(t=document.createElement("script"),this.cspNonce&&(t.nonce=this.cspNonce),t.textContent=e.textContent,t.async=!1,copyElementAttributes(t,e),t)}preservingPermanentElements(e){Bardo.preservingPermanentElements(this.permanentElementMap,e)}focusFirstAutofocusableElement(){var e=this.connectedSnapshot.firstAutofocusableElement;elementIsFocusable(e)&&e.focus()}get connectedSnapshot(){return this.newSnapshot.isConnected?this.newSnapshot:this.currentSnapshot}get currentElement(){return this.currentSnapshot.element}get newElement(){return this.newSnapshot.element}get permanentElementMap(){return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot)}get cspNonce(){var e;return null==(e=document.head.querySelector('meta[name="csp-nonce"]'))?void 0:e.getAttribute("content")}}function copyElementAttributes(e,t){for(var{name:s,value:r}of[...t.attributes])e.setAttribute(s,r)}function elementIsFocusable(e){return e&&"function"==typeof e.focus}class FrameRenderer extends Renderer{get shouldRender(){return!0}async render(){await nextAnimationFrame(),this.preservingPermanentElements(()=>{this.loadFrameElement()}),this.scrollFrameIntoView(),await nextAnimationFrame(),this.focusFirstAutofocusableElement(),await nextAnimationFrame(),this.activateScriptElements()}loadFrameElement(){var e=document.createRange(),e=(e.selectNodeContents(this.currentElement),e.deleteContents(),this.newElement),t=null==(t=e.ownerDocument)?void 0:t.createRange();t&&(t.selectNodeContents(e),this.currentElement.appendChild(t.extractContents()))}scrollFrameIntoView(){if(this.currentElement.autoscroll||this.newElement.autoscroll){var e=this.currentElement.firstElementChild,t=readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"),"end");if(e)return e.scrollIntoView({block:t}),!0}return!1}activateScriptElements(){for(const t of this.newScriptElements){var e=this.createScriptElement(t);t.replaceWith(e)}}get newScriptElements(){return this.currentElement.querySelectorAll("script")}}function readScrollLogicalPosition(e,t){return"end"==e||"start"==e||"center"==e||"nearest"==e?e:t}class ProgressBar{constructor(){this.hiding=!1,this.value=0,this.visible=!1,this.trickle=()=>{this.setValue(this.value+Math.random()/100)},this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement(),this.installStylesheetElement(),this.setValue(0)}static get defaultCSS(){return unindent` + .turbo-progress-bar { + position: fixed; + display: block; + top: 0; + left: 0; + height: 3px; + background: #0076ff; + z-index: 9999; + transition: + width ${ProgressBar.animationDuration}ms ease-out, + opacity ${ProgressBar.animationDuration/2}ms ${ProgressBar.animationDuration/2}ms ease-in; + transform: translate3d(0, 0, 0); + } + `}show(){this.visible||(this.visible=!0,this.installProgressElement(),this.startTrickling())}hide(){this.visible&&!this.hiding&&(this.hiding=!0,this.fadeProgressElement(()=>{this.uninstallProgressElement(),this.stopTrickling(),this.visible=!1,this.hiding=!1}))}setValue(e){this.value=e,this.refresh()}installStylesheetElement(){document.head.insertBefore(this.stylesheetElement,document.head.firstChild)}installProgressElement(){this.progressElement.style.width="0",this.progressElement.style.opacity="1",document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()}fadeProgressElement(e){this.progressElement.style.opacity="0",setTimeout(e,1.5*ProgressBar.animationDuration)}uninstallProgressElement(){this.progressElement.parentNode&&document.documentElement.removeChild(this.progressElement)}startTrickling(){this.trickleInterval||(this.trickleInterval=window.setInterval(this.trickle,ProgressBar.animationDuration))}stopTrickling(){window.clearInterval(this.trickleInterval),delete this.trickleInterval}refresh(){requestAnimationFrame(()=>{this.progressElement.style.width=10+90*this.value+"%"})}createStylesheetElement(){var e=document.createElement("style");return e.type="text/css",e.textContent=ProgressBar.defaultCSS,e}createProgressElement(){var e=document.createElement("div");return e.className="turbo-progress-bar",e}}ProgressBar.animationDuration=300;class HeadSnapshot extends Snapshot{constructor(){super(...arguments),this.detailsByOuterHTML=this.children.filter(e=>!elementIsNoscript(e)).map(e=>elementWithoutNonce(e)).reduce((e,t)=>{var s=t["outerHTML"],r=s in e?e[s]:{type:elementType(t),tracked:elementIsTracked(t),elements:[]};return Object.assign(Object.assign({},e),{[s]:Object.assign(Object.assign({},r),{elements:[...r.elements,t]})})},{})}get trackedElementSignature(){return Object.keys(this.detailsByOuterHTML).filter(e=>this.detailsByOuterHTML[e].tracked).join("")}getScriptElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("script",e)}getStylesheetElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("stylesheet",e)}getElementsMatchingTypeNotInSnapshot(t,s){return Object.keys(this.detailsByOuterHTML).filter(e=>!(e in s.detailsByOuterHTML)).map(e=>this.detailsByOuterHTML[e]).filter(({type:e})=>e==t).map(({elements:[e]})=>e)}get provisionalElements(){return Object.keys(this.detailsByOuterHTML).reduce((e,t)=>{var{type:t,tracked:s,elements:r}=this.detailsByOuterHTML[t];return null!=t||s?1{var[t]=this.detailsByOuterHTML[t]["elements"];return elementIsMetaElementWithName(t,s)?t:e},void 0)}}function elementType(e){return elementIsScript(e)?"script":elementIsStylesheet(e)?"stylesheet":void 0}function elementIsTracked(e){return"reload"==e.getAttribute("data-turbo-track")}function elementIsScript(e){return"script"==e.tagName.toLowerCase()}function elementIsNoscript(e){return"noscript"==e.tagName.toLowerCase()}function elementIsStylesheet(e){var t=e.tagName.toLowerCase();return"style"==t||"link"==t&&"stylesheet"==e.getAttribute("rel")}function elementIsMetaElementWithName(e,t){return"meta"==e.tagName.toLowerCase()&&e.getAttribute("name")==t}function elementWithoutNonce(e){return e.hasAttribute("nonce")&&e.setAttribute("nonce",""),e}class PageSnapshot extends Snapshot{constructor(e,t){super(e),this.headSnapshot=t}static fromHTMLString(e=""){return this.fromDocument(parseHTMLDocument(e))}static fromElement(e){return this.fromDocument(e.ownerDocument)}static fromDocument({head:e,body:t}){return new this(t,new HeadSnapshot(e))}clone(){return new PageSnapshot(this.element.cloneNode(!0),this.headSnapshot)}get headElement(){return this.headSnapshot.element}get rootLocation(){var e;return expandURL(null!=(e=this.getSetting("root"))?e:"/")}get cacheControlValue(){return this.getSetting("cache-control")}get isPreviewable(){return"no-preview"!=this.cacheControlValue}get isCacheable(){return"no-cache"!=this.cacheControlValue}get isVisitable(){return"reload"!=this.getSetting("visit-control")}getSetting(e){return this.headSnapshot.getMetaValue("turbo-"+e)}}!function(e){e.visitStart="visitStart",e.requestStart="requestStart",e.requestEnd="requestEnd",e.visitEnd="visitEnd"}(TimingMetric=TimingMetric||{}),function(e){e.initialized="initialized",e.started="started",e.canceled="canceled",e.failed="failed",e.completed="completed"}(VisitState=VisitState||{});const defaultOptions={action:"advance",historyChanged:!1,visitCachedSnapshot:()=>{},willRender:!0};!function(e){e[e.networkFailure=0]="networkFailure",e[e.timeoutFailure=-1]="timeoutFailure",e[e.contentTypeMismatch=-2]="contentTypeMismatch"}(SystemStatusCode=SystemStatusCode||{});class Visit{constructor(e,t,s,r={}){this.identifier=uuid(),this.timingMetrics={},this.followedRedirect=!1,this.historyChanged=!1,this.scrolled=!1,this.snapshotCached=!1,this.state=VisitState.initialized,this.delegate=e,this.location=t,this.restorationIdentifier=s||uuid();var{action:e,historyChanged:t,referrer:s,snapshotHTML:r,response:i,visitCachedSnapshot:n,willRender:o}=Object.assign(Object.assign({},defaultOptions),r);this.action=e,this.historyChanged=t,this.referrer=s,this.snapshotHTML=r,this.response=i,this.isSamePage=this.delegate.locationWithActionIsSamePage(this.location,this.action),this.visitCachedSnapshot=n,this.willRender=o,this.scrolled=!o}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}get restorationData(){return this.history.getRestorationDataForIdentifier(this.restorationIdentifier)}get silent(){return this.isSamePage}start(){this.state==VisitState.initialized&&(this.recordTimingMetric(TimingMetric.visitStart),this.state=VisitState.started,this.adapter.visitStarted(this),this.delegate.visitStarted(this))}cancel(){this.state==VisitState.started&&(this.request&&this.request.cancel(),this.cancelRender(),this.state=VisitState.canceled)}complete(){this.state==VisitState.started&&(this.recordTimingMetric(TimingMetric.visitEnd),this.state=VisitState.completed,this.adapter.visitCompleted(this),this.delegate.visitCompleted(this),this.followRedirect())}fail(){this.state==VisitState.started&&(this.state=VisitState.failed,this.adapter.visitFailed(this))}changeHistory(){var e;this.historyChanged||(e=this.location.href===(null==(e=this.referrer)?void 0:e.href)?"replace":this.action,e=this.getHistoryMethodForAction(e),this.history.update(e,this.location,this.restorationIdentifier),this.historyChanged=!0)}issueRequest(){this.hasPreloadedResponse()?this.simulateRequest():this.shouldIssueRequest()&&!this.request&&(this.request=new FetchRequest(this,FetchMethod.get,this.location),this.request.perform())}simulateRequest(){this.response&&(this.startRequest(),this.recordResponse(),this.finishRequest())}startRequest(){this.recordTimingMetric(TimingMetric.requestStart),this.adapter.visitRequestStarted(this)}recordResponse(e=this.response){(this.response=e)&&(e=e["statusCode"],isSuccessful(e)?this.adapter.visitRequestCompleted(this):this.adapter.visitRequestFailedWithStatusCode(this,e))}finishRequest(){this.recordTimingMetric(TimingMetric.requestEnd),this.adapter.visitRequestFinished(this)}loadResponse(){if(this.response){const{statusCode:e,responseHTML:t}=this.response;this.render(async()=>{this.cacheSnapshot(),this.view.renderPromise&&await this.view.renderPromise,isSuccessful(e)&&null!=t?(await this.view.renderPage(PageSnapshot.fromHTMLString(t),!1,this.willRender),this.adapter.visitRendered(this),this.complete()):(await this.view.renderError(PageSnapshot.fromHTMLString(t)),this.adapter.visitRendered(this),this.fail())})}}getCachedSnapshot(){var e=this.view.getCachedSnapshotForLocation(this.location)||this.getPreloadedSnapshot();if(e&&(!getAnchor(this.location)||e.hasAnchor(getAnchor(this.location)))&&("restore"==this.action||e.isPreviewable))return e}getPreloadedSnapshot(){if(this.snapshotHTML)return PageSnapshot.fromHTMLString(this.snapshotHTML)}hasCachedSnapshot(){return null!=this.getCachedSnapshot()}loadCachedSnapshot(){const e=this.getCachedSnapshot();if(e){const t=this.shouldIssueRequest();this.render(async()=>{this.cacheSnapshot(),this.isSamePage?this.adapter.visitRendered(this):(this.view.renderPromise&&await this.view.renderPromise,await this.view.renderPage(e,t,this.willRender),this.adapter.visitRendered(this),t||this.complete())})}}followRedirect(){var e;this.redirectedToLocation&&!this.followedRedirect&&null!=(e=this.response)&&e.redirected&&(this.adapter.visitProposedToLocation(this.redirectedToLocation,{action:"replace",response:this.response}),this.followedRedirect=!0)}goToSamePageAnchor(){this.isSamePage&&this.render(async()=>{this.cacheSnapshot(),this.adapter.visitRendered(this)})}requestStarted(){this.startRequest()}requestPreventedHandlingResponse(e,t){}async requestSucceededWithResponse(e,t){var s=await t.responseHTML,{redirected:r,statusCode:i}=t;null==s?this.recordResponse({statusCode:SystemStatusCode.contentTypeMismatch,redirected:r}):(this.redirectedToLocation=t.redirected?t.location:void 0,this.recordResponse({statusCode:i,responseHTML:s,redirected:r}))}async requestFailedWithResponse(e,t){var s=await t.responseHTML,{redirected:t,statusCode:r}=t;null==s?this.recordResponse({statusCode:SystemStatusCode.contentTypeMismatch,redirected:t}):this.recordResponse({statusCode:r,responseHTML:s,redirected:t})}requestErrored(e,t){this.recordResponse({statusCode:SystemStatusCode.networkFailure,redirected:!1})}requestFinished(){this.finishRequest()}performScroll(){this.scrolled||("restore"==this.action?this.scrollToRestoredPosition()||this.scrollToAnchor()||this.view.scrollToTop():this.scrollToAnchor()||this.view.scrollToTop(),this.isSamePage&&this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation,this.location),this.scrolled=!0)}scrollToRestoredPosition(){var e=this.restorationData["scrollPosition"];if(e)return this.view.scrollToPosition(e),!0}scrollToAnchor(){var e=getAnchor(this.location);if(null!=e)return this.view.scrollToAnchor(e),!0}recordTimingMetric(e){this.timingMetrics[e]=(new Date).getTime()}getTimingMetrics(){return Object.assign({},this.timingMetrics)}getHistoryMethodForAction(e){switch(e){case"replace":return history.replaceState;case"advance":case"restore":return history.pushState}}hasPreloadedResponse(){return"object"==typeof this.response}shouldIssueRequest(){return!this.isSamePage&&("restore"==this.action?!this.hasCachedSnapshot():this.willRender)}cacheSnapshot(){this.snapshotCached||(this.view.cacheSnapshot().then(e=>e&&this.visitCachedSnapshot(e)),this.snapshotCached=!0)}async render(e){this.cancelRender(),await new Promise(e=>{this.frame=requestAnimationFrame(()=>e())}),await e(),delete this.frame,this.performScroll()}cancelRender(){this.frame&&(cancelAnimationFrame(this.frame),delete this.frame)}}function isSuccessful(e){return 200<=e&&e<300}class BrowserAdapter{constructor(e){this.progressBar=new ProgressBar,this.showProgressBar=()=>{this.progressBar.show()},this.session=e}visitProposedToLocation(e,t){this.navigator.startVisit(e,uuid(),t)}visitStarted(e){e.loadCachedSnapshot(),e.issueRequest(),e.changeHistory(),e.goToSamePageAnchor()}visitRequestStarted(e){this.progressBar.setValue(0),e.hasCachedSnapshot()||"restore"!=e.action?this.showVisitProgressBarAfterDelay():this.showProgressBar()}visitRequestCompleted(e){e.loadResponse()}visitRequestFailedWithStatusCode(e,t){switch(t){case SystemStatusCode.networkFailure:case SystemStatusCode.timeoutFailure:case SystemStatusCode.contentTypeMismatch:return this.reload();default:return e.loadResponse()}}visitRequestFinished(e){this.progressBar.setValue(1),this.hideVisitProgressBar()}visitCompleted(e){}pageInvalidated(){this.reload()}visitFailed(e){}visitRendered(e){}formSubmissionStarted(e){this.progressBar.setValue(0),this.showFormProgressBarAfterDelay()}formSubmissionFinished(e){this.progressBar.setValue(1),this.hideFormProgressBar()}showVisitProgressBarAfterDelay(){this.visitProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay)}hideVisitProgressBar(){this.progressBar.hide(),null!=this.visitProgressBarTimeout&&(window.clearTimeout(this.visitProgressBarTimeout),delete this.visitProgressBarTimeout)}showFormProgressBarAfterDelay(){null==this.formProgressBarTimeout&&(this.formProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay))}hideFormProgressBar(){this.progressBar.hide(),null!=this.formProgressBarTimeout&&(window.clearTimeout(this.formProgressBarTimeout),delete this.formProgressBarTimeout)}reload(){window.location.reload()}get navigator(){return this.session.navigator}}class CacheObserver{constructor(){this.started=!1}start(){this.started||(this.started=!0,addEventListener("turbo:before-cache",this.removeStaleElements,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-cache",this.removeStaleElements,!1))}removeStaleElements(){for(const e of[...document.querySelectorAll('[data-turbo-cache="false"]')])e.remove()}}class FormSubmitObserver{constructor(e){this.started=!1,this.submitCaptured=()=>{removeEventListener("submit",this.submitBubbled,!1),addEventListener("submit",this.submitBubbled,!1)},this.submitBubbled=e=>{var t,s;e.defaultPrevented||(t=e.target instanceof HTMLFormElement?e.target:void 0,s=e.submitter||void 0,t&&"dialog"!=((null==s?void 0:s.getAttribute("formmethod"))||t.getAttribute("method"))&&this.delegate.willSubmitForm(t,s)&&(e.preventDefault(),this.delegate.formSubmitted(t,s)))},this.delegate=e}start(){this.started||(addEventListener("submit",this.submitCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("submit",this.submitCaptured,!0),this.started=!1)}}class FrameRedirector{constructor(e){this.element=e,this.linkInterceptor=new LinkInterceptor(this,e),this.formInterceptor=new FormInterceptor(this,e)}start(){this.linkInterceptor.start(),this.formInterceptor.start()}stop(){this.linkInterceptor.stop(),this.formInterceptor.stop()}shouldInterceptLinkClick(e,t){return this.shouldRedirect(e)}linkClickIntercepted(e,t){var s=this.findFrameElement(e);s&&s.delegate.linkClickIntercepted(e,t)}shouldInterceptFormSubmission(e,t){return this.shouldSubmit(e,t)}formSubmissionIntercepted(e,t){var s=this.findFrameElement(e,t);s&&(s.removeAttribute("reloadable"),s.delegate.formSubmissionIntercepted(e,t))}shouldSubmit(e,t){var s=getAction(e,t),r=this.element.ownerDocument.querySelector('meta[name="turbo-root"]'),r=expandURL(null!=(r=null==r?void 0:r.content)?r:"/");return this.shouldRedirect(e,t)&&locationIsVisitable(s,r)}shouldRedirect(e,t){t=this.findFrameElement(e,t);return!!t&&t!=e.closest("turbo-frame")}findFrameElement(e,t){t=(null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame");if(t&&"_top"!=t){e=this.element.querySelector(`#${t}:not([disabled])`);if(e instanceof FrameElement)return e}}}class History{constructor(e){this.restorationIdentifier=uuid(),this.restorationData={},this.started=!1,this.pageLoaded=!1,this.onPopState=e=>{this.shouldHandlePopState()&&(e=(e.state||{})["turbo"],e)&&(this.location=new URL(window.location.href),e=e["restorationIdentifier"],this.restorationIdentifier=e,this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location,e))},this.onPageLoad=async e=>{await nextMicrotask(),this.pageLoaded=!0},this.delegate=e}start(){this.started||(addEventListener("popstate",this.onPopState,!1),addEventListener("load",this.onPageLoad,!1),this.started=!0,this.replace(new URL(window.location.href)))}stop(){this.started&&(removeEventListener("popstate",this.onPopState,!1),removeEventListener("load",this.onPageLoad,!1),this.started=!1)}push(e,t){this.update(history.pushState,e,t)}replace(e,t){this.update(history.replaceState,e,t)}update(e,t,s=uuid()){e.call(history,{turbo:{restorationIdentifier:s}},"",t.href),this.location=t,this.restorationIdentifier=s}getRestorationDataForIdentifier(e){return this.restorationData[e]||{}}updateRestorationData(e){var t=this["restorationIdentifier"],s=this.restorationData[t];this.restorationData[t]=Object.assign(Object.assign({},s),e)}assumeControlOfScrollRestoration(){var e;this.previousScrollRestoration||(this.previousScrollRestoration=null!=(e=history.scrollRestoration)?e:"auto",history.scrollRestoration="manual")}relinquishControlOfScrollRestoration(){this.previousScrollRestoration&&(history.scrollRestoration=this.previousScrollRestoration,delete this.previousScrollRestoration)}shouldHandlePopState(){return this.pageIsLoaded()}pageIsLoaded(){return this.pageLoaded||"complete"==document.readyState}}class LinkClickObserver{constructor(e){this.started=!1,this.clickCaptured=()=>{removeEventListener("click",this.clickBubbled,!1),addEventListener("click",this.clickBubbled,!1)},this.clickBubbled=e=>{var t,s;this.clickEventIsSignificant(e)&&(t=e.composedPath&&e.composedPath()[0]||e.target,t=this.findLinkFromClickTarget(t))&&(s=this.getLocationForLink(t),this.delegate.willFollowLinkToLocation(t,s))&&(e.preventDefault(),this.delegate.followedLinkToLocation(t,s))},this.delegate=e}start(){this.started||(addEventListener("click",this.clickCaptured,!0),this.started=!0)}stop(){this.started&&(removeEventListener("click",this.clickCaptured,!0),this.started=!1)}clickEventIsSignificant(e){return!(e.target&&e.target.isContentEditable||e.defaultPrevented||1{var e=this["readyState"];"interactive"==e?this.pageIsInteractive():"complete"==e&&this.pageIsComplete()},this.pageWillUnload=()=>{this.delegate.pageWillUnload()},this.delegate=e}start(){this.started||(this.stage==PageStage.initial&&(this.stage=PageStage.loading),document.addEventListener("readystatechange",this.interpretReadyState,!1),addEventListener("pagehide",this.pageWillUnload,!1),this.started=!0)}stop(){this.started&&(document.removeEventListener("readystatechange",this.interpretReadyState,!1),removeEventListener("pagehide",this.pageWillUnload,!1),this.started=!1)}pageIsInteractive(){this.stage==PageStage.loading&&(this.stage=PageStage.interactive,this.delegate.pageBecameInteractive())}pageIsComplete(){this.pageIsInteractive(),this.stage==PageStage.interactive&&(this.stage=PageStage.complete,this.delegate.pageLoaded())}get readyState(){return document.readyState}}class ScrollObserver{constructor(e){this.started=!1,this.onScroll=()=>{this.updatePosition({x:window.pageXOffset,y:window.pageYOffset})},this.delegate=e}start(){this.started||(addEventListener("scroll",this.onScroll,!1),this.onScroll(),this.started=!0)}stop(){this.started&&(removeEventListener("scroll",this.onScroll,!1),this.started=!1)}updatePosition(e){this.delegate.scrollPositionChanged(e)}}class StreamObserver{constructor(e){this.sources=new Set,this.started=!1,this.inspectFetchResponse=e=>{var t=fetchResponseFromEvent(e);t&&fetchResponseIsStream(t)&&(e.preventDefault(),this.receiveMessageResponse(t))},this.receiveMessageEvent=e=>{this.started&&"string"==typeof e.data&&this.receiveMessageHTML(e.data)},this.delegate=e}start(){this.started||(this.started=!0,addEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}connectStreamSource(e){this.streamSourceIsConnected(e)||(this.sources.add(e),e.addEventListener("message",this.receiveMessageEvent,!1))}disconnectStreamSource(e){this.streamSourceIsConnected(e)&&(this.sources.delete(e),e.removeEventListener("message",this.receiveMessageEvent,!1))}streamSourceIsConnected(e){return this.sources.has(e)}async receiveMessageResponse(e){e=await e.responseHTML;e&&this.receiveMessageHTML(e)}receiveMessageHTML(e){this.delegate.receivedMessageFromStream(new StreamMessage(e))}}function fetchResponseFromEvent(e){e=null==(e=e.detail)?void 0:e.fetchResponse;if(e instanceof FetchResponse)return e}function fetchResponseIsStream(e){return(null!=(e=e.contentType)?e:"").startsWith(StreamMessage.contentType)}class ErrorRenderer extends Renderer{async render(){this.replaceHeadAndBody(),this.activateScriptElements()}replaceHeadAndBody(){var{documentElement:e,head:t,body:s}=document;e.replaceChild(this.newHead,t),e.replaceChild(this.newElement,s)}activateScriptElements(){for(const s of this.scriptElements){var e,t=s.parentNode;t&&(e=this.createScriptElement(s),t.replaceChild(e,s))}}get newHead(){return this.newSnapshot.headSnapshot.element}get scriptElements(){return[...document.documentElement.querySelectorAll("script")]}}class PageRenderer extends Renderer{get shouldRender(){return this.newSnapshot.isVisitable&&this.trackedElementsAreIdentical}prepareToRender(){this.mergeHead()}async render(){this.willRender&&this.replaceBody()}finishRendering(){super.finishRendering(),this.isPreview||this.focusFirstAutofocusableElement()}get currentHeadSnapshot(){return this.currentSnapshot.headSnapshot}get newHeadSnapshot(){return this.newSnapshot.headSnapshot}get newElement(){return this.newSnapshot.element}mergeHead(){this.copyNewHeadStylesheetElements(),this.copyNewHeadScriptElements(),this.removeCurrentHeadProvisionalElements(),this.copyNewHeadProvisionalElements()}replaceBody(){this.preservingPermanentElements(()=>{this.activateNewBody(),this.assignNewBody()})}get trackedElementsAreIdentical(){return this.currentHeadSnapshot.trackedElementSignature==this.newHeadSnapshot.trackedElementSignature}copyNewHeadStylesheetElements(){for(const e of this.newHeadStylesheetElements)document.head.appendChild(e)}copyNewHeadScriptElements(){for(const e of this.newHeadScriptElements)document.head.appendChild(this.createScriptElement(e))}removeCurrentHeadProvisionalElements(){for(const e of this.currentHeadProvisionalElements)document.head.removeChild(e)}copyNewHeadProvisionalElements(){for(const e of this.newHeadProvisionalElements)document.head.appendChild(e)}activateNewBody(){document.adoptNode(this.newElement),this.activateNewBodyScriptElements()}activateNewBodyScriptElements(){for(const t of this.newBodyScriptElements){var e=this.createScriptElement(t);t.replaceWith(e)}}assignNewBody(){document.body&&this.newElement instanceof HTMLBodyElement?document.body.replaceWith(this.newElement):document.documentElement.appendChild(this.newElement)}get newHeadStylesheetElements(){return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot)}get newHeadScriptElements(){return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot)}get currentHeadProvisionalElements(){return this.currentHeadSnapshot.provisionalElements}get newHeadProvisionalElements(){return this.newHeadSnapshot.provisionalElements}get newBodyScriptElements(){return this.newElement.querySelectorAll("script")}}class SnapshotCache{constructor(e){this.keys=[],this.snapshots={},this.size=e}has(e){return toCacheKey(e)in this.snapshots}get(e){var t;if(this.has(e))return t=this.read(e),this.touch(e),t}put(e,t){return this.write(e,t),this.touch(e),t}clear(){this.snapshots={}}read(e){return this.snapshots[toCacheKey(e)]}write(e,t){this.snapshots[toCacheKey(e)]=t}touch(e){var e=toCacheKey(e),t=this.keys.indexOf(e);-1s.remove())):s.addEventListener("submit",()=>s.remove()),document.body.appendChild(s),dispatch("submit",{cancelable:!0,target:s})}return!1}allowsVisitingLocationWithAction(e,t){return this.locationWithActionIsSamePage(e,t)||this.applicationAllowsVisitingLocation(e)}visitProposedToLocation(e,t){extendURLWithDeprecatedProperties(e),this.adapter.visitProposedToLocation(e,t)}visitStarted(e){extendURLWithDeprecatedProperties(e.location),e.silent||this.notifyApplicationAfterVisitingLocation(e.location,e.action)}visitCompleted(e){this.notifyApplicationAfterPageLoad(e.getTimingMetrics())}locationWithActionIsSamePage(e,t){return this.navigator.locationWithActionIsSamePage(e,t)}visitScrolledToSamePageLocation(e,t){this.notifyApplicationAfterVisitingSamePageLocation(e,t)}willSubmitForm(e,t){var s=getAction(e,t);return this.elementDriveEnabled(e)&&(!t||this.elementDriveEnabled(t))&&locationIsVisitable(expandURL(s),this.snapshot.rootLocation)}formSubmitted(e,t){this.navigator.submitForm(e,t)}pageBecameInteractive(){this.view.lastRenderedLocation=this.location,this.notifyApplicationAfterPageLoad()}pageLoaded(){this.history.assumeControlOfScrollRestoration()}pageWillUnload(){this.history.relinquishControlOfScrollRestoration()}receivedMessageFromStream(e){this.renderStreamMessage(e)}viewWillCacheSnapshot(){var e;null!=(e=this.navigator.currentVisit)&&e.silent||this.notifyApplicationBeforeCachingSnapshot()}allowsImmediateRender({element:e},t){return!this.notifyApplicationBeforeRender(e,t).defaultPrevented}viewRenderedSnapshot(e,t){this.view.lastRenderedLocation=this.history.location,this.notifyApplicationAfterRender()}viewInvalidated(){this.adapter.pageInvalidated()}frameLoaded(e){this.notifyApplicationAfterFrameLoad(e)}frameRendered(e,t){this.notifyApplicationAfterFrameRender(e,t)}applicationAllowsFollowingLinkToLocation(e,t){return!this.notifyApplicationAfterClickingLinkToLocation(e,t).defaultPrevented}applicationAllowsVisitingLocation(e){return!this.notifyApplicationBeforeVisitingLocation(e).defaultPrevented}notifyApplicationAfterClickingLinkToLocation(e,t){return dispatch("turbo:click",{target:e,detail:{url:t.href},cancelable:!0})}notifyApplicationBeforeVisitingLocation(e){return dispatch("turbo:before-visit",{detail:{url:e.href},cancelable:!0})}notifyApplicationAfterVisitingLocation(e,t){return markAsBusy(document.documentElement),dispatch("turbo:visit",{detail:{url:e.href,action:t}})}notifyApplicationBeforeCachingSnapshot(){return dispatch("turbo:before-cache")}notifyApplicationBeforeRender(e,t){return dispatch("turbo:before-render",{detail:{newBody:e,resume:t},cancelable:!0})}notifyApplicationAfterRender(){return dispatch("turbo:render")}notifyApplicationAfterPageLoad(e={}){return clearBusyState(document.documentElement),dispatch("turbo:load",{detail:{url:this.location.href,timing:e}})}notifyApplicationAfterVisitingSamePageLocation(e,t){dispatchEvent(new HashChangeEvent("hashchange",{oldURL:e.toString(),newURL:t.toString()}))}notifyApplicationAfterFrameLoad(e){return dispatch("turbo:frame-load",{target:e})}notifyApplicationAfterFrameRender(e,t){return dispatch("turbo:frame-render",{detail:{fetchResponse:e},target:t,cancelable:!0})}elementDriveEnabled(e){e=null==e?void 0:e.closest("[data-turbo]");return this.drive?!e||"false"!=e.getAttribute("data-turbo"):!!e&&"true"==e.getAttribute("data-turbo")}getActionForLink(e){e=e.getAttribute("data-turbo-action");return isAction(e)?e:"advance"}getTargetFrameForLink(e){var t=e.getAttribute("data-turbo-frame");return t||((t=e.closest("turbo-frame"))?t.id:void 0)}get snapshot(){return this.view.snapshot}}function extendURLWithDeprecatedProperties(e){Object.defineProperties(e,deprecatedLocationPropertyDescriptors)}const deprecatedLocationPropertyDescriptors={absoluteURL:{get(){return this.toString()}}},session=new Session,navigator$1=session["navigator"];function start(){session.start()}function registerAdapter(e){session.registerAdapter(e)}function visit(e,t){session.visit(e,t)}function connectStreamSource(e){session.connectStreamSource(e)}function disconnectStreamSource(e){session.disconnectStreamSource(e)}function renderStreamMessage(e){session.renderStreamMessage(e)}function clearCache(){session.clearCache()}function setProgressBarDelay(e){session.setProgressBarDelay(e)}function setConfirmMethod(e){FormSubmission.confirmMethod=e}var Turbo=Object.freeze({__proto__:null,navigator:navigator$1,session:session,PageRenderer:PageRenderer,PageSnapshot:PageSnapshot,start:start,registerAdapter:registerAdapter,visit:visit,connectStreamSource:connectStreamSource,disconnectStreamSource:disconnectStreamSource,renderStreamMessage:renderStreamMessage,clearCache:clearCache,setProgressBarDelay:setProgressBarDelay,setConfirmMethod:setConfirmMethod});class FrameController{constructor(e){this.fetchResponseLoaded=e=>{},this.currentFetchRequest=null,this.resolveVisitPromise=()=>{},this.connected=!1,this.hasBeenLoaded=!1,this.settingSourceURL=!1,this.element=e,this.view=new FrameView(this,this.element),this.appearanceObserver=new AppearanceObserver(this,this.element),this.linkInterceptor=new LinkInterceptor(this,this.element),this.formInterceptor=new FormInterceptor(this,this.element)}connect(){this.connected||(this.connected=!0,this.reloadable=!1,this.loadingStyle==FrameLoadingStyle.lazy&&this.appearanceObserver.start(),this.linkInterceptor.start(),this.formInterceptor.start(),this.sourceURLChanged())}disconnect(){this.connected&&(this.connected=!1,this.appearanceObserver.stop(),this.linkInterceptor.stop(),this.formInterceptor.stop())}disabledChanged(){this.loadingStyle==FrameLoadingStyle.eager&&this.loadSourceURL()}sourceURLChanged(){this.loadingStyle!=FrameLoadingStyle.eager&&!this.hasBeenLoaded||this.loadSourceURL()}loadingStyleChanged(){this.loadingStyle==FrameLoadingStyle.lazy?this.appearanceObserver.start():(this.appearanceObserver.stop(),this.loadSourceURL())}async loadSourceURL(){if(!this.settingSourceURL&&this.enabled&&this.isActive&&(this.reloadable||this.sourceURL!=this.currentURL)){var t=this.currentURL;if(this.currentURL=this.sourceURL,this.sourceURL)try{this.element.loaded=this.visit(expandURL(this.sourceURL)),this.appearanceObserver.stop(),await this.element.loaded,this.hasBeenLoaded=!0}catch(e){throw this.currentURL=t,e}}}async loadResponse(e){(e.redirected||e.succeeded&&e.isHTML)&&(this.sourceURL=e.response.url);try{var t,s,r,i=await e.responseHTML;i&&(t=parseHTMLDocument(i)["body"],s=new Snapshot(await this.extractForeignFrameElement(t)),r=new FrameRenderer(this.view.snapshot,s,!1,!1),this.view.renderPromise&&await this.view.renderPromise,await this.view.render(r),session.frameRendered(e,this.element),session.frameLoaded(this.element),this.fetchResponseLoaded(e))}catch(e){console.error(e),this.view.invalidate()}finally{this.fetchResponseLoaded=()=>{}}}elementAppearedInViewport(e){this.loadSourceURL()}shouldInterceptLinkClick(e,t){return!e.hasAttribute("data-turbo-method")&&this.shouldInterceptNavigation(e)}linkClickIntercepted(e,t){this.reloadable=!0,this.navigateFrame(e,t)}shouldInterceptFormSubmission(e,t){return this.shouldInterceptNavigation(e,t)}formSubmissionIntercepted(e,t){this.formSubmission&&this.formSubmission.stop(),this.reloadable=!1,this.formSubmission=new FormSubmission(this,e,t);e=this.formSubmission.fetchRequest;this.prepareHeadersForRequest(e.headers,e),this.formSubmission.start()}prepareHeadersForRequest(e,t){e["Turbo-Frame"]=this.id}requestStarted(e){markAsBusy(this.element)}requestPreventedHandlingResponse(e,t){this.resolveVisitPromise()}async requestSucceededWithResponse(e,t){await this.loadResponse(t),this.resolveVisitPromise()}requestFailedWithResponse(e,t){console.error(t),this.resolveVisitPromise()}requestErrored(e,t){console.error(t),this.resolveVisitPromise()}requestFinished(e){clearBusyState(this.element)}formSubmissionStarted({formElement:e}){markAsBusy(e,this.findFrameElement(e))}formSubmissionSucceededWithResponse(e,t){var s=this.findFrameElement(e.formElement,e.submitter);this.proposeVisitIfNavigatedWithAction(s,e.formElement,e.submitter),s.delegate.loadResponse(t)}formSubmissionFailedWithResponse(e,t){this.element.delegate.loadResponse(t)}formSubmissionErrored(e,t){console.error(t)}formSubmissionFinished({formElement:e}){clearBusyState(e,this.findFrameElement(e))}allowsImmediateRender(e,t){return!0}viewRenderedSnapshot(e,t){}viewInvalidated(){}async visit(e){const t=new FetchRequest(this,FetchMethod.get,e,new URLSearchParams,this.element);return null!=(e=this.currentFetchRequest)&&e.cancel(),this.currentFetchRequest=t,new Promise(e=>{this.resolveVisitPromise=()=>{this.resolveVisitPromise=()=>{},this.currentFetchRequest=null,e()},t.perform()})}navigateFrame(e,t,s){var r=this.findFrameElement(e,s);this.proposeVisitIfNavigatedWithAction(r,e,s),r.setAttribute("reloadable",""),r.src=t}proposeVisitIfNavigatedWithAction(s,e,t){const r=getAttribute("data-turbo-action",t,e,s);if(isAction(r)){const i=new SnapshotSubstitution(s)["visitCachedSnapshot"];s.delegate.fetchResponseLoaded=e=>{var t;s.src&&({statusCode:e,redirected:t}=e,e={statusCode:e,redirected:t,responseHTML:s.ownerDocument.documentElement.outerHTML},session.visit(s.src,{action:r,response:e,visitCachedSnapshot:i,willRender:!1}))}}}findFrameElement(e,t){return null!=(t=getFrameElementById(getAttribute("data-turbo-frame",t,e)||this.element.getAttribute("target")))?t:this.element}async extractForeignFrameElement(e){var t,s=CSS.escape(this.id);try{if(t=activateElement(e.querySelector("turbo-frame#"+s),this.currentURL))return t;if(t=activateElement(e.querySelector(`turbo-frame[src][recurse~=${s}]`),this.currentURL))return await t.loaded,await this.extractForeignFrameElement(t);console.error(`Response has no matching element`)}catch(e){console.error(e)}return new FrameElement}formActionIsVisitable(e,t){return locationIsVisitable(expandURL(getAction(e,t)),this.rootLocation)}shouldInterceptNavigation(e,t){var s=getAttribute("data-turbo-frame",t,e)||this.element.getAttribute("target");if(e instanceof HTMLFormElement&&!this.formActionIsVisitable(e,t))return!1;if(!this.enabled||"_top"==s)return!1;if(s){s=getFrameElementById(s);if(s)return!s.disabled}return!(!session.elementDriveEnabled(e)||t&&!session.elementDriveEnabled(t))}get id(){return this.element.id}get enabled(){return!this.element.disabled}get sourceURL(){if(this.element.src)return this.element.src}get reloadable(){return this.findFrameElement(this.element).hasAttribute("reloadable")}set reloadable(e){var t=this.findFrameElement(this.element);e?t.setAttribute("reloadable",""):t.removeAttribute("reloadable")}set sourceURL(e){this.settingSourceURL=!0,this.element.src=null!=e?e:null,this.currentURL=this.element.src,this.settingSourceURL=!1}get loadingStyle(){return this.element.loading}get isLoading(){return void 0!==this.formSubmission||void 0!==this.resolveVisitPromise()}get isActive(){return this.element.isActive&&this.connected}get rootLocation(){var e=this.element.ownerDocument.querySelector('meta[name="turbo-root"]');return expandURL(null!=(e=null==e?void 0:e.content)?e:"/")}}class SnapshotSubstitution{constructor(e){this.visitCachedSnapshot=({element:e})=>{var{id:t,clone:s}=this;null!=(e=e.querySelector("#"+t))&&e.replaceWith(s)},this.clone=e.cloneNode(!0),this.id=e.id}}function getFrameElementById(e){if(null!=e){e=document.getElementById(e);if(e instanceof FrameElement)return e}}function activateElement(e,t){if(e){var s=e.getAttribute("src");if(null!=s&&null!=t&&urlsAreEqual(s,t))throw new Error(`Matching element has a source URL which references itself`);if((e=e.ownerDocument!==document?document.importNode(e,!0):e)instanceof FrameElement)return e.connectedCallback(),e.disconnectedCallback(),e}}const StreamActions={after(){this.targetElements.forEach(e=>{var t;return null==(t=e.parentElement)?void 0:t.insertBefore(this.templateContent,e.nextSibling)})},append(){this.removeDuplicateTargetChildren(),this.targetElements.forEach(e=>e.append(this.templateContent))},before(){this.targetElements.forEach(e=>{var t;return null==(t=e.parentElement)?void 0:t.insertBefore(this.templateContent,e)})},prepend(){this.removeDuplicateTargetChildren(),this.targetElements.forEach(e=>e.prepend(this.templateContent))},remove(){this.targetElements.forEach(e=>e.remove())},replace(){this.targetElements.forEach(e=>e.replaceWith(this.templateContent))},update(){this.targetElements.forEach(e=>{e.innerHTML="",e.append(this.templateContent)})}};class StreamElement extends HTMLElement{async connectedCallback(){try{await this.render()}catch(e){console.error(e)}finally{this.disconnect()}}async render(){var e;return null!=(e=this.renderPromise)?e:this.renderPromise=(async()=>{this.dispatchEvent(this.beforeRenderEvent)&&(await nextAnimationFrame(),this.performAction())})()}disconnect(){try{this.remove()}catch(e){}}removeDuplicateTargetChildren(){this.duplicateChildren.forEach(e=>e.remove())}get duplicateChildren(){var e,t=this.targetElements.flatMap(e=>[...e.children]).filter(e=>!!e.id);const s=[...null==(e=this.templateContent)?void 0:e.children].filter(e=>!!e.id).map(e=>e.id);return t.filter(e=>s.includes(e.id))}get performAction(){if(this.action){var e=StreamActions[this.action];if(e)return e;this.raise("unknown action")}this.raise("action attribute is missing")}get targetElements(){return this.target?this.targetElementsById:this.targets?this.targetElementsByQuery:void this.raise("target or targets attribute is missing")}get templateContent(){return this.templateElement.content.cloneNode(!0)}get templateElement(){if(this.firstElementChild instanceof HTMLTemplateElement)return this.firstElementChild;this.raise("first child element must be a
in sortable rows has matching data-id and data-value + // -