spec-up-t 1.3.0-beta → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/assets/compiled/body.js +3 -3
  2. package/assets/compiled/head.css +2 -1
  3. package/assets/css/counter.css +92 -0
  4. package/assets/css/{pdf-download.css → download-pdf-docx.css} +9 -5
  5. package/assets/js/addAnchorsToTerms.js +1 -1
  6. package/assets/js/collapse-definitions.js +0 -3
  7. package/assets/js/custom-elements.js +25 -27
  8. package/assets/js/download-pdf-docx.js +68 -0
  9. package/assets/js/highlight-heading-plus-sibling-nodes.test.js +120 -0
  10. package/config/asset-map.json +3 -2
  11. package/index.js +1 -1
  12. package/package.json +3 -2
  13. package/sonar-project.properties +7 -6
  14. package/src/create-docx.js +1 -1
  15. package/src/html-dom-processor.js +15 -15
  16. package/src/install-from-boilerplate/boilerplate/.github/workflows/menu.yml +78 -77
  17. package/src/install-from-boilerplate/boilerplate/spec/spec-head.md +1 -1
  18. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/composability.md +3 -0
  19. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/compost.md +3 -0
  20. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/fertilizer.md +3 -0
  21. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/mulch.md +3 -0
  22. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/pruning.md +3 -0
  23. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/seedling.md +3 -0
  24. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/soil.md +11 -0
  25. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/watering.md +3 -0
  26. package/src/install-from-boilerplate/boilerplate/specs.json +22 -9
  27. package/src/install-from-boilerplate/config-system-files.js +0 -1
  28. package/assets/js/pdf-download.js +0 -46
  29. package/src/install-from-boilerplate/boilerplate/.github/workflows/fetch-and-push-xrefs.yml.old +0 -42
  30. package/src/install-from-boilerplate/boilerplate/.github/workflows/render-specs.yml +0 -47
  31. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-1.md +0 -13
  32. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-2.md +0 -3
  33. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-3.md +0 -3
  34. package/src/install-from-boilerplate/boilerplate/spec/terms-definitions/term-4.md +0 -3
  35. package/test-default-definitions.js +0 -55
  36. package/test-edge-cases.md +0 -20
  37. package/test-fix-markdown.js +0 -11
  38. package/test-no-def.md +0 -22
@@ -102,14 +102,14 @@ function inPageSearch(){const t=document.querySelector(".terms-and-definitions-l
102
102
  function highlightMenuItems(){let e=null;function t(e){document.querySelectorAll("#toc_list a").forEach((e=>{e.classList.remove("highlight-cfib41dyhcd99sm")}));const t=document.querySelector(`#toc_list a[href="#${e.id}"]`);t&&(t.classList.add("highlight-cfib41dyhcd99sm"),t.scrollIntoView({behavior:"smooth",block:"center"}),document.dispatchEvent(new CustomEvent("highlight-menu-item",{detail:{menuItem:t,headingId:e.id}})))}const n=new IntersectionObserver(((n,o)=>{const i=n.filter((e=>e.isIntersecting)).map((e=>e.target));i.length>0?(e=i[0],t(e)):e&&t(e)}),{root:null,rootMargin:"0px",threshold:.1});document.querySelectorAll("h2, h3, h4, h5, h6").forEach((e=>n.observe(e)))}document.addEventListener("DOMContentLoaded",(function(){highlightMenuItems()}));
103
103
  function initCollapsibleMenu(){const e=document.getElementById("toc");if(!e)return void console.warn("TOC container not found");e.querySelectorAll(".collapse-toggle").forEach((e=>e.remove()));e.querySelectorAll("ul li").forEach(((e,t)=>{const l=e.querySelector("ul");if(l){e.classList.add("has-children");const a=document.createElement("button");a.className="collapse-toggle",a.setAttribute("aria-label","Toggle section"),a.setAttribute("type","button"),a.id=`toc-toggle-${t}`;const i=e.querySelector(":scope > a");if(i){const e=i.textContent.trim();a.setAttribute("aria-label",`Toggle ${e} section`),i.parentNode.insertBefore(a,i.nextSibling),l.setAttribute("role","group"),l.setAttribute("aria-labelledby",i.id||`toc-item-${t}`),i.id||(i.id=`toc-item-${t}`)}else e.appendChild(a);a.setAttribute("aria-controls",`toc-children-${t}`),l.id=`toc-children-${t}`,a.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation();e.classList.contains("collapsed")?(e.classList.remove("collapsed"),a.classList.remove("collapsed"),a.setAttribute("aria-expanded","true")):(e.classList.add("collapsed"),a.classList.add("collapsed"),a.setAttribute("aria-expanded","false"))})),a.addEventListener("keydown",(e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),a.click())}));e.querySelector("a.highlight-cfib41dyhcd99sm, a.active")?a.setAttribute("aria-expanded","true"):(e.classList.add("collapsed"),a.classList.add("collapsed"),a.setAttribute("aria-expanded","false"))}}))}document.addEventListener("DOMContentLoaded",(()=>{initCollapsibleMenu()})),document.addEventListener("highlight-menu-item",initCollapsibleMenu);
104
104
  function backToTop(){const n=document.createElement("a");n.id="back-to-top-a1zncgtqfpzsig8",n.href="#content",n.innerHTML="↑",document.body.appendChild(n);const t=function(n,t){let e;return function(){const o=this,c=arguments;clearTimeout(e),e=setTimeout((()=>n.apply(o,c)),t)}}((function(){window.scrollY>300?n.style.display="flex":n.style.display="none"}),600);window.addEventListener("scroll",(function(){t()}))}document.addEventListener("DOMContentLoaded",(function(){backToTop()}));
105
- function addAnchorsToTerms(){document.querySelectorAll('dt:has(> span[id^="term:"])').forEach((e=>{const t=function(e){const t=e.querySelector('span.transcluded-xref-term[id^="term:"]');if(t)return t;let r=e;for(;r.querySelector('span[id^="term:"]');)r=r.querySelector('span[id^="term:"]');return r}(e),r=t.getAttribute("id"),n=document.createElement("a");n.setAttribute("href",`#${r}`),n.setAttribute("class","toc-anchor d-print-none"),n.innerHTML="# ",t.parentNode.insertBefore(n,t)}))}document.addEventListener("DOMContentLoaded",(function(){addAnchorsToTerms()}));
105
+ function addAnchorsToTerms(){document.querySelectorAll('dt:has(> span[id^="term:"])').forEach((e=>{const t=function(e){const t=e.querySelector('span.transcluded-xref-term[id^="term:"]');if(t)return t;let r=e;for(;r.querySelector('span[id^="term:"]');)r=r.querySelector('span[id^="term:"]');return r}(e),r=t.getAttribute("id"),n=document.createElement("a");n.setAttribute("href",`#${r}`),n.setAttribute("class","toc-anchor d-print-none"),n.innerHTML=(window.specConfig.anchor_symbol||"§")+" ",t.parentNode.insertBefore(n,t)}))}document.addEventListener("DOMContentLoaded",(function(){addAnchorsToTerms()}));
106
106
  function copyAnchorToCliboard(){document.addEventListener("click",(function(o){if(o.target.classList.contains("toc-anchor")){const c=o.target.href;navigator.clipboard.writeText(c).then((()=>{console.log("Anchor copied to clipboard"),notyf.success(`Anchor copied to clipboard: ${c}`)})).catch((o=>{console.error("Failed to copy anchor to clipboard",o)}))}}))}document.addEventListener("DOMContentLoaded",(function(){copyAnchorToCliboard()}));
107
107
  var Notyf=function(){"use strict";var t,i=function(){return(i=Object.assign||function(t){for(var i,e=1,n=arguments.length;e<n;e++)for(var o in i=arguments[e])Object.prototype.hasOwnProperty.call(i,o)&&(t[o]=i[o]);return t}).apply(this,arguments)},e=(n.prototype.on=function(t,i){var e=this.listeners[t]||[];this.listeners[t]=e.concat([i])},n.prototype.triggerEvent=function(t,i){var e=this;(this.listeners[t]||[]).forEach((function(t){return t({target:e,event:i})}))},n);function n(t){this.options=t,this.listeners={}}(s=t=t||{})[s.Add=0]="Add",s[s.Remove=1]="Remove";var o,s,a=(r.prototype.push=function(i){this.notifications.push(i),this.updateFn(i,t.Add,this.notifications)},r.prototype.splice=function(i,e){return e=this.notifications.splice(i,e)[0],this.updateFn(e,t.Remove,this.notifications),e},r.prototype.indexOf=function(t){return this.notifications.indexOf(t)},r.prototype.onUpdate=function(t){this.updateFn=t},r);function r(){this.notifications=[]}(s=o=o||{}).Dismiss="dismiss";var c={types:[{type:"success",className:"notyf__toast--success",backgroundColor:"#3dc763",icon:{className:"notyf__icon--success",tagName:"i"}},{type:"error",className:"notyf__toast--error",backgroundColor:"#ed3d3d",icon:{className:"notyf__icon--error",tagName:"i"}}],duration:2e3,ripple:!0,position:{x:"right",y:"bottom"},dismissible:!(s.Click="click")},p=(d.prototype.on=function(t,e){var n;this.events=i(i({},this.events),((n={})[t]=e,n))},d.prototype.update=function(i,e){e===t.Add?this.addNotification(i):e===t.Remove&&this.removeNotification(i)},d.prototype.removeNotification=function(t){var i,e,n=this;(t=this._popRenderedNotification(t))&&((e=t.node).classList.add("notyf__toast--disappear"),e.addEventListener(this.animationEndEventName,i=function(t){t.target===e&&(e.removeEventListener(n.animationEndEventName,i),n.container.removeChild(e))}))},d.prototype.addNotification=function(t){var i=this._renderNotification(t);this.notifications.push({notification:t,node:i}),this._announce(t.options.message||"Notification")},d.prototype._renderNotification=function(t){var i=this._buildNotificationCard(t),e=t.options.className;return e&&(t=i.classList).add.apply(t,e.split(" ")),this.container.appendChild(i),i},d.prototype._popRenderedNotification=function(t){for(var i=-1,e=0;e<this.notifications.length&&i<0;e++)this.notifications[e].notification===t&&(i=e);if(-1!==i)return this.notifications.splice(i,1)[0]},d.prototype.getXPosition=function(t){return(null===(t=null==t?void 0:t.position)||void 0===t?void 0:t.x)||"right"},d.prototype.getYPosition=function(t){return(null===(t=null==t?void 0:t.position)||void 0===t?void 0:t.y)||"bottom"},d.prototype.adjustContainerAlignment=function(t){var i=this.X_POSITION_FLEX_MAP[this.getXPosition(t)],e=this.Y_POSITION_FLEX_MAP[this.getYPosition(t)];(t=this.container.style).setProperty("justify-content",e),t.setProperty("align-items",i)},d.prototype._buildNotificationCard=function(t){var i=this,e=t.options,n=e.icon;this.adjustContainerAlignment(e);var s=this._createHTMLElement({tagName:"div",className:"notyf__toast"}),a=this._createHTMLElement({tagName:"div",className:"notyf__ripple"}),r=this._createHTMLElement({tagName:"div",className:"notyf__wrapper"}),c=this._createHTMLElement({tagName:"div",className:"notyf__message"});c.innerHTML=e.message||"";var p,d,l,u,f=e.background||e.backgroundColor;return n&&(p=this._createHTMLElement({tagName:"div",className:"notyf__icon"}),("string"==typeof n||n instanceof String)&&(p.innerHTML=new String(n).valueOf()),"object"==typeof n&&(d=n.tagName,l=n.className,u=n.text,n=void 0===(n=n.color)?f:n,u=this._createHTMLElement({tagName:void 0===d?"i":d,className:l,text:u}),n&&(u.style.color=n),p.appendChild(u)),r.appendChild(p)),r.appendChild(c),s.appendChild(r),f&&(e.ripple?(a.style.background=f,s.appendChild(a)):s.style.background=f),e.dismissible&&(a=this._createHTMLElement({tagName:"div",className:"notyf__dismiss"}),f=this._createHTMLElement({tagName:"button",className:"notyf__dismiss-btn"}),a.appendChild(f),r.appendChild(a),s.classList.add("notyf__toast--dismissible"),f.addEventListener("click",(function(e){var n,s;null!==(s=(n=i.events)[o.Dismiss])&&void 0!==s&&s.call(n,{target:t,event:e}),e.stopPropagation()}))),s.addEventListener("click",(function(e){var n,s;return null===(s=(n=i.events)[o.Click])||void 0===s?void 0:s.call(n,{target:t,event:e})})),e="top"===this.getYPosition(e)?"upper":"lower",s.classList.add("notyf__toast--"+e),s},d.prototype._createHTMLElement=function(t){var i=t.tagName,e=t.className;t=t.text,i=document.createElement(i);return e&&(i.className=e),i.textContent=t||null,i},d.prototype._createA11yContainer=function(){var t=this._createHTMLElement({tagName:"div",className:"notyf-announcer"});t.setAttribute("aria-atomic","true"),t.setAttribute("aria-live","polite"),t.style.border="0",t.style.clip="rect(0 0 0 0)",t.style.height="1px",t.style.margin="-1px",t.style.overflow="hidden",t.style.padding="0",t.style.position="absolute",t.style.width="1px",t.style.outline="0",document.body.appendChild(t),this.a11yContainer=t},d.prototype._announce=function(t){var i=this;this.a11yContainer.textContent="",setTimeout((function(){i.a11yContainer.textContent=t}),100)},d.prototype._getAnimationEndEventName=function(){var t,i=document.createElement("_fake"),e={MozTransition:"animationend",OTransition:"oAnimationEnd",WebkitTransition:"webkitAnimationEnd",transition:"animationend"};for(t in e)if(void 0!==i.style[t])return e[t];return"animationend"},d);function d(){this.notifications=[],this.events={},this.X_POSITION_FLEX_MAP={left:"flex-start",center:"center",right:"flex-end"},this.Y_POSITION_FLEX_MAP={top:"flex-start",center:"center",bottom:"flex-end"};var t=document.createDocumentFragment(),i=this._createHTMLElement({tagName:"div",className:"notyf"});t.appendChild(i),document.body.appendChild(t),this.container=i,this.animationEndEventName=this._getAnimationEndEventName(),this._createA11yContainer()}function l(t){var e=this;this.dismiss=this._removeNotification,this.notifications=new a,this.view=new p;var n=this.registerTypes(t);this.options=i(i({},c),t),this.options.types=n,this.notifications.onUpdate((function(t,i){return e.view.update(t,i)})),this.view.on(o.Dismiss,(function(t){var i=t.target;t=t.event;e._removeNotification(i),i.triggerEvent(o.Dismiss,t)})),this.view.on(o.Click,(function(t){var i=t.target;t=t.event;return i.triggerEvent(o.Click,t)}))}return l.prototype.error=function(t){return t=this.normalizeOptions("error",t),this.open(t)},l.prototype.success=function(t){return t=this.normalizeOptions("success",t),this.open(t)},l.prototype.open=function(t){var n=this.options.types.find((function(i){return i.type===t.type}))||{};n=i(i({},n),t);return this.assignProps(["ripple","position","dismissible"],n),n=new e(n),this._pushNotification(n),n},l.prototype.dismissAll=function(){for(;this.notifications.splice(0,1););},l.prototype.assignProps=function(t,i){var e=this;t.forEach((function(t){i[t]=(null==i[t]?e.options:i)[t]}))},l.prototype._pushNotification=function(t){var i=this;this.notifications.push(t);var e=(void 0!==t.options.duration?t:this).options.duration;e&&setTimeout((function(){return i._removeNotification(t)}),e)},l.prototype._removeNotification=function(t){-1!==(t=this.notifications.indexOf(t))&&this.notifications.splice(t,1)},l.prototype.normalizeOptions=function(t,e){return t={type:t},"string"==typeof e?t.message=e:"object"==typeof e&&(t=i(i({},t),e)),t},l.prototype.registerTypes=function(t){var e=(t&&t.types||[]).slice();return c.types.map((function(t){var n=-1;e.forEach((function(i,e){i.type===t.type&&(n=e)}));var o=-1!==n?e.splice(n,1)[0]:{};return i(i({},t),o)})).concat(e)},l}(),notyf=new Notyf({types:[{type:"success",background:"#1D6DAE",duration:3e3},{type:"error",background:"orange",duration:1e7,dismissible:!0}]});
108
108
  function showModal(e){const n=document.createElement("div");n.className="spec-up-t-modal-overlay";const c=document.createElement("div");c.className="spec-up-t-modal";const t=document.createElement("button");function o(){document.body.removeChild(n)}t.className="spec-up-t-modal-close",t.innerHTML="&times;",t.onclick=o,c.innerHTML=e,c.appendChild(t),n.appendChild(c),document.body.appendChild(n),n.onclick=function(e){e.target===n&&o()},document.addEventListener("keydown",(function(e){"Escape"===e.key&&o()}),{once:!0})}
109
109
  function tokenInput(){document.querySelector(".button-token-input").addEventListener("click",(()=>{const t=prompt("Please enter your GitHub token:");t?(localStorage.setItem("githubToken",t),console.log("GitHub token is set.")):alert("GitHub token is not set.")}))}document.addEventListener("DOMContentLoaded",(function(){tokenInput()}));
110
- function pdfDownload(){fetch("./index.pdf",{method:"HEAD"}).then((e=>{if(e.ok){let e=document.createElement("a");e.classList.add("button-pdf-download"),e.classList.add("btn","d-block","btn-sm","btn-outline-secondary"),e.target="_blank",e.rel="noopener noreferrer",e.href="./index.pdf",e.title="Download this page as a PDF",e.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" class="me-1" viewBox="0 0 16 16">\n <path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0H4zm0 1h5v4h4v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zm7 4h-1V2l3 3h-2z"/>\n <path d="M6.5 10.5a.5.5 0 0 1-.5-.5V7.5a.5.5 0 0 1 .5-.5H8a.5.5 0 0 1 .5.5V10a.5.5 0 0 1-.5.5H6.5z"/>\n </svg>\n ',e.style.display="inline-flex",e.style.alignItems="center",e.style.justifyContent="center",document.querySelector(".service-menu").prepend(e)}else console.log("PDF file does not exist. No PDF download button will be added.")})).catch((e=>{console.error("Error checking PDF file:",e)}))}document.addEventListener("DOMContentLoaded",(function(){pdfDownload()}));
110
+ !function(){"use strict";const e=e=>document.querySelector(e);async function t(){const t=e(".service-menu");if(!t)return;const n=[{href:"./index.pdf",title:"Download this page as a PDF",cls:"button-pdf-download"},{href:"./index.docx",title:"Download this page as a DOCX",cls:"button-docx-download"}],o=await Promise.all(n.map((e=>{return t=e.href,fetch(t,{method:"HEAD"}).then((e=>e.ok)).catch((()=>!1));var t})));let r=t.firstElementChild;n.forEach(((n,a)=>{if(!o[a])return;if(s=n.cls,e(`.service-menu .${s}`))return;var s;const c=function(e,t,n){const o=document.createElement("a");return o.classList.add(n,"btn","d-block","btn-sm","btn-outline-secondary"),o.target="_blank",o.rel="noopener noreferrer",o.href=e,o.title=t,o.setAttribute("aria-label",t),o.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" class="me-1" viewBox="0 0 16 16"> <path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0H4zm0 1h5v4h4v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zm7 4h-1V2l3 3h-2z"/> </svg>',o}(n.href,n.title,n.cls);t.insertBefore(c,r),r=c}))}window.SpecUpDownloads={addButtons:t},document.addEventListener("DOMContentLoaded",t,{once:!1});try{document.dispatchEvent(new CustomEvent("specup-downloads-ready"))}catch(e){}}();
111
111
  function insertTrefs(e){!function(e){const n=[];document.querySelectorAll("dl.terms-and-definitions-list dt span.transcluded-xref-term").forEach((e=>{const t=e.textContent.trim(),r=e.closest("dt");if(r){const e=r.nextElementSibling;if(e?.classList.contains("transcluded-xref-term")&&e.classList.contains("meta-info-content-wrapper"))return}n.push({element:e,textContent:t,dt:r,parent:r?.parentNode})}));const t=n.map((n=>{const{textContent:t,dt:r,parent:d}=n;if(!r||!d)return null;const o=e.xtrefs.find((e=>e.term===t)),s=document.createDocumentFragment(),i=document.createElement("dd");if(i.classList.add("transcluded-xref-term","meta-info-content-wrapper","collapsed"),o){const e=`\n| Property | Value |\n| -------- | ----- |\n| Owner | ${o.avatarUrl?`![avatar](${o.avatarUrl})`:""} ${o.owner||"Unknown"} |\n| Repo | ${o.repo&&o.repoUrl?`[${o.repo}](${o.repoUrl})`:"Unknown"} |\n| Commit hash | ${o.commitHash||"Unknown"} |\n `;i.innerHTML=md.render(e),s.appendChild(i);let n=o.content.split("\n").map((e=>e.replace(/^\s*~\s*/,""))).join("\n").replace(/\]\]/g,"");const t=document.createElement("div");t.innerHTML=md.render(n),t.querySelectorAll("a").forEach((e=>e.replaceWith(...e.childNodes))),n=t.innerHTML;const r=document.createElement("div");r.innerHTML=md.render(n);const d=r.querySelectorAll("dd");if(d.length>0)Array.from(d).forEach((e=>{const n=e.cloneNode(!0);n.classList.add("transcluded-xref-term","transcluded-xref-term-embedded"),s.appendChild(n)}));else{const e=document.createElement("dd");e.classList.add("transcluded-xref-term","transcluded-xref-term-embedded"),e.innerHTML=r.innerHTML,s.appendChild(e)}}else{i.innerHTML=md.render("\n| Property | Value |\n| -------- | ----- |\n| Owner | Unknown |\n| Repo | Unknown |\n| Commit hash | not found |\n "),s.appendChild(i);const e=document.createElement("dd");e.innerHTML="<p>This term was not found in the external repository.</p>",s.appendChild(e)}return{dt:r,parent:d,fragment:s}})).filter(Boolean);requestAnimationFrame((()=>{t.forEach((e=>{const{dt:n,parent:t,fragment:r}=e;t.insertBefore(r,n.nextSibling)})),document.dispatchEvent(new CustomEvent("trefs-inserted",{detail:{count:t.length}}))}))}(e)}function initializeOnTrefsInserted(e){let n=!1;document.addEventListener("trefs-inserted",(function(t){n||(n=!0,e(),t.detail&&console.log(`Collapsible definitions initialized after ${t.detail.count} xrefs were inserted`))})),setTimeout((()=>{n||(console.warn("trefs-inserted event was not received, initializing collapsible definitions anyway"),e(),n=!0)}),1e3)}document.addEventListener("DOMContentLoaded",(()=>{"undefined"!=typeof allXTrefs&&allXTrefs?.xtrefs?insertTrefs(allXTrefs):(console.error("allXTrefs is undefined or missing xtrefs property"),document.dispatchEvent(new CustomEvent("trefs-inserted",{detail:{count:0,error:"Missing xtrefs data"}})))}));
112
- function collapseDefinitions(){let{dds:t,dts:e,regularDds:s,specialDds:a}=function(){const t=document.querySelectorAll("#content dl.terms-and-definitions-list > dd");return{dds:t,dts:document.querySelectorAll("#content dl.terms-and-definitions-list > dt"),regularDds:Array.from(t).filter((t=>!i(t.textContent.trim()))),specialDds:Array.from(t).filter((t=>i(t.textContent.trim())))}}();function i(t){return["Source","See also","More in","Also see","See:","See also","See more","See more in","See more about","See more on","See more at","More:","Supporting definitions:"].some((e=>t.startsWith(e)))}a.forEach((t=>{t.classList.add("terms-def-extra-info")})),e.forEach((t=>{if(t.querySelector(".collapse-all-defs-button"))return;const e=document.createElement("button");e.classList.add("collapse-all-defs-button","btn-outline-secondary","d-print-none","btn","p-0","fs-5","d-flex","align-items-center","justify-content-center"),e.innerHTML='<span class="state-indicator" data-state="0">①</span><span class="state-indicator" data-state="1">②</span><span class="state-indicator" data-state="2">③</span>',e.setAttribute("id","toggleButton"),e.setAttribute("title","Change how much info is shown"),e.setAttribute("data-state","2"),e.querySelector('.state-indicator[data-state="2"]').classList.add("active"),t.appendChild(e)})),document.addEventListener("click",(e=>{if(e.target.classList.contains("collapse-all-defs-button")||e.target.classList.contains("state-indicator")){const i=e.target.classList.contains("collapse-all-defs-button")?e.target:e.target.closest(".collapse-all-defs-button"),n=(i.closest("dt"),i.getBoundingClientRect());document.documentElement.classList.add("definitions-transitioning"),i.style.position="fixed",i.style.top=`${n.top}px`,i.style.right=window.innerWidth-n.right+"px",i.style.zIndex="1000",function(){const e=document.querySelectorAll(".collapse-all-defs-button");switch((parseInt(e[0].dataset.state||0)+1)%3){case 0:t.forEach((t=>{t.classList.add("hidden"),t.classList.remove("visible")})),e.forEach((t=>{t.dataset.state=0,t.title="Show basic definitions",t.querySelectorAll(".state-indicator").forEach((t=>{0===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.add("defs-hidden");break;case 1:s.forEach((t=>{t.classList.remove("hidden"),t.classList.add("visible")})),a.forEach((t=>{t.classList.add("hidden"),t.classList.remove("visible")})),e.forEach((t=>{t.dataset.state=1,t.title="Show all definitions",t.querySelectorAll(".state-indicator").forEach((t=>{1===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.remove("defs-hidden");break;case 2:t.forEach((t=>{t.classList.remove("hidden"),t.classList.add("visible")})),a.forEach((t=>{t.classList.add("terms-def-extra-info")})),e.forEach((t=>{t.dataset.state=2,t.title="Hide all definitions",t.querySelectorAll(".state-indicator").forEach((t=>{2===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.remove("defs-hidden")}}(),requestAnimationFrame((()=>{i.style.position="",i.style.top="",i.style.right="",i.style.zIndex="",document.documentElement.classList.remove("definitions-transitioning");const t=i.getBoundingClientRect();window.scrollTo({top:window.scrollY+(t.top-n.top),behavior:"instant"})}))}}))}document.addEventListener("DOMContentLoaded",(function(){initializeOnTrefsInserted(collapseDefinitions)}));
112
+ function collapseDefinitions(){let{dds:t,dts:e,regularDds:s,specialDds:a}=function(){const t=document.querySelectorAll("#content dl.terms-and-definitions-list > dd");return{dds:t,dts:document.querySelectorAll("#content dl.terms-and-definitions-list > dt"),regularDds:Array.from(t).filter((t=>!i(t.textContent.trim()))),specialDds:Array.from(t).filter((t=>i(t.textContent.trim())))}}();function i(t){return["Source","See also","More in","Also see","See:","See also","See more","See more in","See more about","See more on","See more at","More:","Supporting definitions:"].some((e=>t.startsWith(e)))}a.forEach((t=>{t.classList.add("terms-def-extra-info")})),e.forEach((t=>{if(t.querySelector(".collapse-all-defs-button"))return;const e=document.createElement("button");e.classList.add("collapse-all-defs-button","btn-outline-secondary","d-print-none","btn","p-0","fs-5","d-flex","align-items-center","justify-content-center"),e.innerHTML='<span class="state-indicator" data-state="0">①</span><span class="state-indicator" data-state="1">②</span><span class="state-indicator" data-state="2">③</span>',e.setAttribute("id","toggleButton"),e.setAttribute("title","Change how much info is shown"),e.setAttribute("data-state","2"),e.querySelector('.state-indicator[data-state="2"]').classList.add("active"),t.appendChild(e)})),document.addEventListener("click",(e=>{if(e.target.classList.contains("collapse-all-defs-button")||e.target.classList.contains("state-indicator")){const i=e.target.classList.contains("collapse-all-defs-button")?e.target:e.target.closest(".collapse-all-defs-button"),n=i.getBoundingClientRect();document.documentElement.classList.add("definitions-transitioning"),i.style.position="fixed",i.style.top=`${n.top}px`,i.style.right=window.innerWidth-n.right+"px",i.style.zIndex="1000",function(){const e=document.querySelectorAll(".collapse-all-defs-button");switch((parseInt(e[0].dataset.state||0)+1)%3){case 0:t.forEach((t=>{t.classList.add("hidden"),t.classList.remove("visible")})),e.forEach((t=>{t.dataset.state=0,t.title="Show basic definitions",t.querySelectorAll(".state-indicator").forEach((t=>{0===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.add("defs-hidden");break;case 1:s.forEach((t=>{t.classList.remove("hidden"),t.classList.add("visible")})),a.forEach((t=>{t.classList.add("hidden"),t.classList.remove("visible")})),e.forEach((t=>{t.dataset.state=1,t.title="Show all definitions",t.querySelectorAll(".state-indicator").forEach((t=>{1===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.remove("defs-hidden");break;case 2:t.forEach((t=>{t.classList.remove("hidden"),t.classList.add("visible")})),a.forEach((t=>{t.classList.add("terms-def-extra-info")})),e.forEach((t=>{t.dataset.state=2,t.title="Hide all definitions",t.querySelectorAll(".state-indicator").forEach((t=>{2===parseInt(t.dataset.state)?t.classList.add("active"):t.classList.remove("active")}))})),document.querySelector("html").classList.remove("defs-hidden")}}(),requestAnimationFrame((()=>{i.style.position="",i.style.top="",i.style.right="",i.style.zIndex="",document.documentElement.classList.remove("definitions-transitioning");const t=i.getBoundingClientRect();window.scrollTo({top:window.scrollY+(t.top-n.top),behavior:"instant"})}))}}))}document.addEventListener("DOMContentLoaded",(function(){initializeOnTrefsInserted(collapseDefinitions)}));
113
113
  function createTermFilter(){const e=document.querySelector(".terms-and-definitions-list");if(0===(e?e.querySelectorAll("dt"):[]).length)return;const c=document.getElementById("terminology-section-utility-container"),t=document.createElement("div");t.className="d-flex mt-0";const n=document.createElement("div");n.className="form-check me-3",n.innerHTML='\n <input class="form-check-input" type="checkbox" id="showLocalTermsCheckbox" checked>\n <label class="form-check-label" for="showLocalTermsCheckbox">\n Show local terms\n </label>\n ';const o=document.createElement("div");o.className="form-check ms-3",o.innerHTML='\n <input class="form-check-input" type="checkbox" id="showExternalTermsCheckbox" checked>\n <label class="form-check-label" for="showExternalTermsCheckbox">\n Show external terms\n </label>\n ',t.appendChild(n),t.appendChild(o),t.addEventListener("change",(function(e){e.target.matches('input[type="checkbox"]')&&function(e){const c=t.querySelectorAll('input[type="checkbox"]'),n=Array.from(c).filter((e=>e.checked));e.target.checked||0===n.length&&c.forEach((c=>{c!==e.target&&(c.checked=!0)})),c.forEach((e=>{const c=document.querySelector("html");"showLocalTermsCheckbox"===e.id?c.classList.toggle("hide-local-terms",!e.checked):"showExternalTermsCheckbox"===e.id&&c.classList.toggle("hide-external-terms",!e.checked)}))}(e)})),c.appendChild(t)}document.addEventListener("DOMContentLoaded",(function(){createTermFilter()}));
114
114
  function createToggleButton(e){const t=document.createElement("button");t.classList.add("meta-info-toggle-button","btn"),t.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16" style="shape-rendering: geometricPrecision;"><path fill-rule="evenodd" d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588z"/><path d="M9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/></svg>',t.title="Meta info",t.addEventListener("click",(function(t){t.preventDefault(),t.stopPropagation();e.classList.contains("collapsed")?(e.classList.remove("collapsed"),e.getBoundingClientRect()):e.classList.add("collapsed")}));let n=e.previousElementSibling;for(;n&&"DT"!==n.tagName;)n=n.previousElementSibling;n?n.appendChild(t):e.insertBefore(t,e.firstChild)}function collapseMetaInfo(){document.querySelectorAll("dl > dd:has(table)").forEach((function(e){e.classList.add("meta-info-content-wrapper");const t=document.createElement("div");for(t.classList.add("meta-info-inner-wrapper");e.firstChild&&e.firstChild!==e.querySelector(".meta-info-toggle-button");)t.appendChild(e.firstChild);e.querySelector(".meta-info-toggle-button")||createToggleButton(e),e.appendChild(t),e.classList.add("collapsed")}))}document.addEventListener("DOMContentLoaded",(function(){initializeOnTrefsInserted(collapseMetaInfo)}));
115
115
  function fixLastDd(){document.querySelectorAll("dl.terms-and-definitions-list").forEach((t=>{t.querySelectorAll(":scope > dd").forEach(((t,e)=>{t.classList.remove("last-dd");let s=t.nextElementSibling;s&&"DT"!==s.tagName||t.classList.contains("last-dd")||t.classList.add("last-dd")}))}))}document.addEventListener("trefs-inserted",(function(){fixLastDd()}));
@@ -19,7 +19,7 @@ h2,h3,h4,h5,h6{margin-top:1.5em!important}#terminology-section-utility-container
19
19
  .hide-local-terms #content dl.terms-and-definitions-list>dd:not(.transcluded-xref-term),.hide-local-terms #content dl.terms-and-definitions-list>dt:not(.transcluded-xref-term){display:none!important}.hide-external-terms #content dl.terms-and-definitions-list>dd.transcluded-xref-term,.hide-external-terms #content dl.terms-and-definitions-list>dt.transcluded-xref-term{display:none!important}
20
20
  .spec-up-t-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.5);display:flex;justify-content:center;align-items:center;z-index:1000}.spec-up-t-modal{background-color:#fff;padding:2rem 20px 20px;border-radius:8px;max-width:80%;max-height:80%;overflow-y:auto;position:relative;box-shadow:0 2px 10px rgba(0,0,0,.1)}.spec-up-t-modal-close{position:absolute;top:0;right:5px;background-color:transparent;border:none;font-size:2rem;line-height:1;cursor:pointer}
21
21
  .alphabet-index-container{margin-bottom:1em}.alphabet-index-container,.number-of-terms{font-size:.8em;text-align:center;width:100%}.alphabet-index-container a{background-color:#f5f5f5;border:1px solid #e0e0e0;border-radius:50%;color:#333;display:inline-block;font-size:.9rem;height:30px;line-height:30px;margin:2px;text-align:center;text-decoration:none;width:30px}
22
- .button-pdf-download{transition:all .2s ease;border-radius:4px;cursor:pointer;font-weight:500;box-shadow:0 1px 3px rgba(0,0,0,.1);padding:5px}.button-pdf-download:hover{background-color:#e74c3c!important;border-color:#e74c3c!important;color:#fff!important;transform:translateY(-1px);box-shadow:0 3px 5px rgba(0,0,0,.15)}.button-pdf-download svg{vertical-align:middle;margin-right:4px}.button-pdf-download:active{transform:translateY(0);box-shadow:0 1px 2px rgba(0,0,0,.1)}
22
+ .button-docx-download,.button-pdf-download{transition:all .2s ease;border-radius:4px;cursor:pointer;font-weight:500;box-shadow:0 1px 3px rgba(0,0,0,.1);padding:5px}.button-docx-download:hover,.button-pdf-download:hover{background-color:#e74c3c!important;border-color:#e74c3c!important;color:#fff!important;transform:translateY(-1px);box-shadow:0 3px 5px rgba(0,0,0,.15)}.button-docx-download svg,.button-pdf-download svg{vertical-align:middle;margin-right:4px}.button-docx-download:active,.button-pdf-download:active{transform:translateY(0);box-shadow:0 1px 2px rgba(0,0,0,.1)}
23
23
  .loader{width:20px;height:20px;margin:auto;display:block;text-align:center;border:8px solid #ccc;border-top-color:#3498db;border-radius:50%;animation:spin 1s linear infinite}.loadertext{text-align:center;margin:.5em 0}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
24
24
  article a[href^="https://"]:not(.btn)::after,article a[href^=http]:not(.btn)::after{content:'';width:12px;height:12px;margin-left:4px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z'/%3E%3Cpath fill-rule='evenodd' d='M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z'/%3E%3C/svg%3E");background-position:center;background-repeat:no-repeat;background-size:contain;display:inline-block}
25
25
  #repo_issues>header{background:#eee;border-bottom:1px solid #ddd}#repo_issues>header span:first-of-type{font-weight:700;padding-top:.1em}#repo_issues>header .repo-issue-toggle{margin-left:auto;color:inherit;font-weight:700;text-decoration:none}#repo_issue_list{list-style:none;margin:0;padding:0 1.25em 1.25em;font-size:.85em;overflow:auto;-ms-overflow-style:none;scrollbar-width:none}#repo_issue_list::-webkit-scrollbar{display:none}#repo_issue_list:empty:before{content:"No issues found";display:block;text-align:center;font-size:1.1em;color:#aaa;margin:1em 0 0}.repo-issue detail-box{display:flex;flex-direction:column;padding:1em 0;border-bottom:1px solid #ddd}.repo-issue detail-box>section{order:1}.repo-issue detail-box>section:empty+.repo-issue-title [detail-box-toggle]{display:none}.repo-issue-title{display:flex;align-items:center}.repo-issue-link{flex:1;margin:0 0 0 .5em}.repo-issue-number{height:1em;margin:0 .4em 0 0;padding:.3em .25em 0;border-radius:3px;font-weight:700;background:#eee;border:1px solid #ddd;text-align:center;line-height:1em}.repo-issue-number:before{content:"#";font-weight:400;margin:0 .1em 0 0}.repo-issue [detail-box-toggle]{margin:0 0 0 1em;opacity:.35;transition:opacity .4s}.repo-issue [detail-box-toggle]:hover,.repo-issue detail-box[open] [detail-box-toggle]{opacity:1}
@@ -28,4 +28,5 @@ article a[href^="https://"]:not(.btn)::after,article a[href^=http]:not(.btn)::af
28
28
  #content .figure{width:100%;margin-bottom:1.5rem}#content .figure img{transition:all .3s ease}#content .figure img:hover{transform:scale(1.01);cursor:pointer}#content img.img-fluid{max-width:100%;height:auto}#content .figure-caption{margin-top:.5rem;font-style:italic;color:#6c757d}
29
29
  #content .figure:has(.scrollHintImage){padding:0;margin:0;width:auto;height:auto}
30
30
  .highlight2{padding-left:1em;padding-right:1em;border:1px dashed #71bbe6;background:#a9dde03b}
31
+ #toc ul.toc{counter-reset:toc-section}#toc ul.toc>li{counter-reset:toc-subsection}#toc ul.toc>li>ul>li{counter-reset:toc-subsubsection}#toc ul.toc>li>a::before{counter-increment:toc-section;content:counter(toc-section) ". ";font-weight:700;margin-right:.5em}#toc ul.toc>li>ul>li>a::before{counter-increment:toc-subsection;content:counter(toc-section) "." counter(toc-subsection) " ";font-weight:700;margin-right:.5em}#toc ul.toc>li>ul>li>ul>li>a::before{counter-increment:toc-subsubsection;content:counter(toc-section) "." counter(toc-subsection) "." counter(toc-subsubsection) " ";font-weight:700;margin-right:.5em}main article{counter-reset:main-section}main article h2{counter-reset:main-subsection}main article h3{counter-reset:main-subsubsection}main article h2 .toc-anchor::after{counter-increment:main-section;content:" " counter(main-section) ".";font-weight:700}main article h3 .toc-anchor::after{counter-increment:main-subsection;content:" " counter(main-section) "." counter(main-subsection);font-weight:700}main article h4 .toc-anchor::after{counter-increment:main-subsubsection;content:" " counter(main-section) "." counter(main-subsection) "." counter(main-subsubsection);font-weight:700}main article h5::before,main article h6::before{font-weight:700;margin-right:.5em}@media print{#toc ul.toc>li>a::before,#toc ul.toc>li>ul>li>a::before,#toc ul.toc>li>ul>li>ul>li>a::before,main article h2 .toc-anchor::after,main article h3 .toc-anchor::after,main article h4 .toc-anchor::after{color:#000!important}}
31
32
  :target{scroll-margin-top:calc(50vh)}body:not([hashscroll]) :target{animation:highlight-target 3.5s .25s ease}body:not([hashscroll]) dt:has(:target){animation:highlight-target-parent-dt 3.5s .25s ease}dl.terms-and-definitions-list>.highlight{background-color:#ff0!important;transition:background-color .3s ease-in-out}svg[icon]{width:1.25em;height:1.25em;vertical-align:text-top}@keyframes highlight-target{50%{background-color:#ff0}}@keyframes highlight-target-parent-dt{50%{background-color:#ff0;border:1px solid #00c8ff}}#svg{display:none}main *{overflow-wrap:anywhere;word-break:normal}.table-responsive{overflow-x:auto!important;-webkit-overflow-scrolling:touch;width:100%;max-width:100%}.table-responsive *{overflow-wrap:normal!important;word-break:normal!important;white-space:nowrap!important}dd td img{max-width:30px}.notice{margin:1em 0;padding:.5em .9em .55em .65em;border-left:.5em solid}.notice p{margin:.4em 0 0}.note{background:#e9fbe9;border-color:#52e052}.note .notice-link{display:block;color:#178217}.issue{background:#e9f0fb;border-color:#527fe0}.issue .notice-link:before{display:block;color:#1e4cae}.warning{background:#fbe9e9;border-color:#e05252}.warning .notice-link{display:block;color:#ae1e1e}.example{color:#cebe00;background:#1a1e23;border-left:.5em solid}.example .notice-link{display:block;color:inherit;font-size:1.1em;font-family:Heebo,sans-serif}.example pre[class*=language-]{padding:0;border-radius:0}.todo{background:#fbe4ff;border-color:#9700e2}.todo .notice-link{display:block;color:#6d00a2}.alert-primary{background-color:#f9fcff;border-color:#b2ebf2;color:#00838f}.alert-secondary{background-color:#f5f5f5;border-color:#e0e0e0;color:#616161}.alert-success{background-color:#e8f5e9;border-color:#c8e6c9;color:#388e3c}.alert-danger{background-color:#ffebee;border-color:#ef9a9a;color:#d32f2f}.alert-warning{background-color:#fffde7;border-color:#fff9c4;color:#f9a825}.alert-info{background-color:#e1f5fe;border-color:#b3e5fc;color:#0288d1}.alert-light{background-color:#f9f9f9;border-color:#eee;color:#424242}.alert-dark{background-color:#e0e0e0;border-color:#bdbdbd;color:#212121}.alert a{color:inherit;font-weight:700}.alert-primary a{color:#006064}.alert-success a{color:#2e7d32}.alert-danger a{color:#b71c1c}.alert-warning a{color:#f57f17}.alert-info a{color:#01579b}.alert-dark a{color:#000}[data-bs-theme=dark] .alert-primary{background-color:#004d40;border-color:#00695c;color:#b2dfdb}[data-bs-theme=dark] .alert-secondary{background-color:#424242;border-color:#616161;color:#e0e0e0}[data-bs-theme=dark] .alert-success{background-color:#1b5e20;border-color:#2e7d32;color:#a5d6a7}[data-bs-theme=dark] .alert-danger{background-color:#b71c1c;border-color:#c62828;color:#ef9a9a}[data-bs-theme=dark] .alert-warning{background-color:#f57f17;border-color:#ffb300;color:#ffe082}[data-bs-theme=dark] .alert-info{background-color:#01579b;border-color:#0277bd;color:#81d4fa}[data-bs-theme=dark] .alert-light{background-color:#303030;border-color:#424242;color:#e0e0e0}[data-bs-theme=dark] .alert-dark{background-color:#212121;border-color:#424242;color:#bdbdbd}[data-bs-theme=dark] .alert a{color:inherit;font-weight:700}[data-bs-theme=dark] .alert-primary a{color:#80cbc4}[data-bs-theme=dark] .alert-success a{color:#81c784}[data-bs-theme=dark] .alert-danger a{color:#ef5350}[data-bs-theme=dark] .alert-warning a{color:#ffca28}[data-bs-theme=dark] .alert-info a{color:#4fc3f7}[data-bs-theme=dark] .alert-dark a{color:#9e9e9e}#offcanvasSettings .btn-menu-item{border-radius:unset;width:100%;text-align:left;border:1px solid #dee2e6;background-color:var(--card-bg);color:var(--card-text);padding:10px 15px;margin-bottom:5px;transition:background-color .2s ease}#offcanvasSettings .btn-menu-item:hover{background-color:#e9ecef}
@@ -0,0 +1,92 @@
1
+ /*
2
+ * CSS Counters for Navigation Menu Items and Content Headings
3
+ * Description: Adds incremental numbering to TOC menu items and corresponding content headings
4
+ */
5
+
6
+ /* Reset and initialize counters for the table of contents */
7
+ #toc ul.toc {
8
+ counter-reset: toc-section;
9
+ }
10
+
11
+ #toc ul.toc > li {
12
+ counter-reset: toc-subsection;
13
+ }
14
+
15
+ #toc ul.toc > li > ul > li {
16
+ counter-reset: toc-subsubsection;
17
+ }
18
+
19
+ /* Add numbering to first-level TOC items (h2 equivalent) */
20
+ #toc ul.toc > li > a::before {
21
+ counter-increment: toc-section;
22
+ content: counter(toc-section) ". ";
23
+ font-weight: bold;
24
+ margin-right: 0.5em;
25
+ }
26
+
27
+ /* Add numbering to second-level TOC items (h3 equivalent) */
28
+ #toc ul.toc > li > ul > li > a::before {
29
+ counter-increment: toc-subsection;
30
+ content: counter(toc-section) "." counter(toc-subsection) " ";
31
+ font-weight: bold;
32
+ margin-right: 0.5em;
33
+ }
34
+
35
+ /* Add numbering to third-level TOC items (h4 equivalent) */
36
+ #toc ul.toc > li > ul > li > ul > li > a::before {
37
+ counter-increment: toc-subsubsection;
38
+ content: counter(toc-section) "." counter(toc-subsection) "." counter(toc-subsubsection) " ";
39
+ font-weight: bold;
40
+ margin-right: 0.5em;
41
+ }
42
+
43
+ /* Initialize counters for main content headings */
44
+ main article {
45
+ counter-reset: main-section;
46
+ }
47
+
48
+ main article h2 {
49
+ counter-reset: main-subsection;
50
+ }
51
+
52
+ main article h3 {
53
+ counter-reset: main-subsubsection;
54
+ }
55
+
56
+ /* Add numbering to main content headings after the anchor */
57
+ main article h2 .toc-anchor::after {
58
+ counter-increment: main-section;
59
+ content: " " counter(main-section) ".";
60
+ font-weight: bold;
61
+ }
62
+
63
+ main article h3 .toc-anchor::after {
64
+ counter-increment: main-subsection;
65
+ content: " " counter(main-section) "." counter(main-subsection);
66
+ font-weight: bold;
67
+ }
68
+
69
+ main article h4 .toc-anchor::after {
70
+ counter-increment: main-subsubsection;
71
+ content: " " counter(main-section) "." counter(main-subsection) "." counter(main-subsubsection);
72
+ font-weight: bold;
73
+ }
74
+
75
+ /* Optional: Style for h5 and h6 if needed */
76
+ main article h5::before,
77
+ main article h6::before {
78
+ font-weight: bold;
79
+ margin-right: 0.5em;
80
+ }
81
+
82
+ /* Print-friendly styles */
83
+ @media print {
84
+ #toc ul.toc > li > a::before,
85
+ #toc ul.toc > li > ul > li > a::before,
86
+ #toc ul.toc > li > ul > li > ul > li > a::before,
87
+ main article h2 .toc-anchor::after,
88
+ main article h3 .toc-anchor::after,
89
+ main article h4 .toc-anchor::after {
90
+ color: #000 !important;
91
+ }
92
+ }
@@ -1,7 +1,8 @@
1
1
  /**
2
- * PDF Download Button Styles
2
+ * Download Buttons (PDF/DOCX)
3
3
  */
4
- .button-pdf-download {
4
+ .button-pdf-download,
5
+ .button-docx-download {
5
6
  transition: all 0.2s ease;
6
7
  border-radius: 4px;
7
8
  cursor: pointer;
@@ -10,7 +11,8 @@
10
11
  padding: 5px;
11
12
  }
12
13
 
13
- .button-pdf-download:hover {
14
+ .button-pdf-download:hover,
15
+ .button-docx-download:hover {
14
16
  background-color: #e74c3c !important;
15
17
  border-color: #e74c3c !important;
16
18
  color: white !important;
@@ -18,12 +20,14 @@
18
20
  box-shadow: 0 3px 5px rgba(0,0,0,0.15);
19
21
  }
20
22
 
21
- .button-pdf-download svg {
23
+ .button-pdf-download svg,
24
+ .button-docx-download svg {
22
25
  vertical-align: middle;
23
26
  margin-right: 4px;
24
27
  }
25
28
 
26
- .button-pdf-download:active {
29
+ .button-pdf-download:active,
30
+ .button-docx-download:active {
27
31
  transform: translateY(0);
28
32
  box-shadow: 0 1px 2px rgba(0,0,0,0.1);
29
33
  }
@@ -28,7 +28,7 @@ function addAnchorsToTerms() {
28
28
  const a = document.createElement('a');
29
29
  a.setAttribute('href', `#${id}`);
30
30
  a.setAttribute('class', 'toc-anchor d-print-none');
31
- a.innerHTML = '# '; // was '§';
31
+ a.innerHTML = (window.specConfig.anchor_symbol || '§') + ' ';
32
32
  dt.parentNode.insertBefore(a, dt);
33
33
  });
34
34
  }
@@ -206,9 +206,6 @@ function collapseDefinitions() {
206
206
  event.target :
207
207
  event.target.closest('.collapse-all-defs-button');
208
208
 
209
- // Find the parent dt and dl elements
210
- const dtElement = button.closest('dt');
211
-
212
209
  // Get button's position in viewport and page
213
210
  const buttonRect = button.getBoundingClientRect();
214
211
 
@@ -7,21 +7,21 @@ customElements.define('slide-panels', class SidePanels extends HTMLElement {
7
7
  }
8
8
  constructor() {
9
9
  super();
10
-
10
+
11
11
  this.addEventListener('pointerup', e => {
12
12
  if (e.target === this) this.close();
13
13
  })
14
14
  }
15
- get active (){
15
+ get active() {
16
16
  return this.getAttribute('open');
17
17
  }
18
- toggle(panel){
18
+ toggle(panel) {
19
19
  this.active === panel ? this.close() : this.open(panel)
20
20
  }
21
- open (panel){
21
+ open(panel) {
22
22
  this.setAttribute('open', panel);
23
23
  }
24
- close (){
24
+ close() {
25
25
  this.removeAttribute('open');
26
26
  }
27
27
 
@@ -39,12 +39,12 @@ customElements.define('detail-box', class DetailBox extends HTMLElement {
39
39
  return ['open'];
40
40
  }
41
41
  constructor() {
42
- super();
43
-
42
+ super();
43
+
44
44
  this.addEventListener('pointerup', e => {
45
45
  if (e.target.hasAttribute('detail-box-toggle')) {
46
46
  e.stopPropagation();
47
- this.toggle();
47
+ this.toggle();
48
48
  }
49
49
  });
50
50
 
@@ -55,7 +55,7 @@ customElements.define('detail-box', class DetailBox extends HTMLElement {
55
55
  }
56
56
  });
57
57
  }
58
- toggle(){
58
+ toggle() {
59
59
  this.toggleAttribute('open');
60
60
  }
61
61
  attributeChangedCallback(attr, last, current) {
@@ -91,24 +91,22 @@ customElements.define('tab-panels', class TabPanels extends HTMLElement {
91
91
  }
92
92
  attributeChangedCallback(attr, last, current) {
93
93
  domReady.then(() => {
94
- switch(attr) {
95
- case 'selected-index':
96
- let index = current || 0;
97
- let nav = this.querySelector('nav');
98
- if (nav.parentElement === this) {
99
- let tabs = nav.children;
100
- let selected = tabs[index];
101
- for (let tab of tabs) tab.removeAttribute('selected');
102
- if (selected) selected.setAttribute('selected', '');
103
- let panel = Array.prototype.filter.call(this.children, node => {
104
- if (node.tagName === 'SECTION') {
105
- node.removeAttribute('selected');
106
- return true;
107
- }
108
- })[index];
109
- if (panel) panel.setAttribute('selected', '');
110
- }
111
- break;
94
+ if (attr === 'selected-index') {
95
+ let index = current || 0;
96
+ let nav = this.querySelector('nav');
97
+ if (nav.parentElement === this) {
98
+ let tabs = nav.children;
99
+ let selected = tabs[index];
100
+ for (let tab of tabs) tab.removeAttribute('selected');
101
+ if (selected) selected.setAttribute('selected', '');
102
+ let panel = Array.prototype.filter.call(this.children, node => {
103
+ if (node.tagName === 'SECTION') {
104
+ node.removeAttribute('selected');
105
+ return true;
106
+ }
107
+ })[index];
108
+ if (panel) panel.setAttribute('selected', '');
109
+ }
112
110
  }
113
111
  });
114
112
  }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Adds download buttons for PDF and DOCX (when files exist next to the page).
3
+ * Buttons are inserted at the start of .service-menu, left-to-right as: PDF, DOCX.
4
+ * Idempotent: safe to call multiple times.
5
+ */
6
+ (function () {
7
+ "use strict";
8
+
9
+ /** Small helpers */
10
+ const qs = (sel) => document.querySelector(sel);
11
+ const buttonExists = (cls) => !!qs(`.service-menu .${cls}`);
12
+ const checkExists = (url) =>
13
+ fetch(url, { method: "HEAD" })
14
+ .then((r) => r.ok)
15
+ .catch(() => false);
16
+
17
+ const fileIconSvg =
18
+ '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" class="me-1" viewBox="0 0 16 16">\
19
+ <path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5L9.5 0H4zm0 1h5v4h4v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zm7 4h-1V2l3 3h-2z"/>\
20
+ </svg>';
21
+
22
+ function createButton(href, title, cls) {
23
+ const a = document.createElement("a");
24
+ a.classList.add(cls, "btn", "d-block", "btn-sm", "btn-outline-secondary");
25
+ a.target = "_blank";
26
+ a.rel = "noopener noreferrer";
27
+ a.href = href;
28
+ a.title = title;
29
+ a.setAttribute("aria-label", title);
30
+ a.innerHTML = fileIconSvg;
31
+ return a;
32
+ }
33
+
34
+ async function addButtons() {
35
+ const container = qs(".service-menu");
36
+ if (!container) return;
37
+
38
+ const items = [
39
+ { href: "./index.pdf", title: "Download this page as a PDF", cls: "button-pdf-download" },
40
+ { href: "./index.docx", title: "Download this page as a DOCX", cls: "button-docx-download" },
41
+ ];
42
+
43
+ const exists = await Promise.all(items.map((i) => checkExists(i.href)));
44
+
45
+ // Insert at the start keeping order as defined in items
46
+ let anchor = container.firstElementChild;
47
+ items.forEach((item, idx) => {
48
+ if (!exists[idx]) return;
49
+ if (buttonExists(item.cls)) return;
50
+ const btn = createButton(item.href, item.title, item.cls);
51
+ container.insertBefore(btn, anchor);
52
+ anchor = btn;
53
+ });
54
+ }
55
+
56
+ // Expose minimal global for backward compatibility shims
57
+ window.SpecUpDownloads = { addButtons };
58
+
59
+ // Auto-run on DOM ready (safe if called multiple times)
60
+ document.addEventListener("DOMContentLoaded", addButtons, { once: false });
61
+
62
+ // Signal readiness for shims that want to call in response
63
+ try {
64
+ document.dispatchEvent(new CustomEvent("specup-downloads-ready"));
65
+ } catch (_) {
66
+ // no-op: older browsers without CustomEvent constructor support
67
+ }
68
+ })();
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ /**
5
+ * @fileoverview Unit tests for highlight-heading-plus-sibling-nodes.js
6
+ * Covers all exported functions to satisfy SonarQube coverage requirements.
7
+ */
8
+ const {
9
+ highlightHeadingSection,
10
+ getHeadingLevel,
11
+ collectHeadingSiblings,
12
+ wrapNodesWithHighlight,
13
+ removeExistingHighlights,
14
+ initializeAnchorHighlighting
15
+ } = require('./highlight-heading-plus-sibling-nodes');
16
+
17
+ describe('highlight-heading-plus-sibling-nodes', () => {
18
+ let container;
19
+
20
+ beforeEach(() => {
21
+ // Set up a DOM structure for testing
22
+ document.body.innerHTML = '';
23
+ container = document.createElement('div');
24
+ container.innerHTML = `
25
+ <h2 id="h2-1">Heading 2</h2>
26
+ <p id="p1">Paragraph 1</p>
27
+ <ul id="ul1"><li>Item</li></ul>
28
+ <h3 id="h3-1">Heading 3</h3>
29
+ <p id="p2">Paragraph 2</p>
30
+ <h2 id="h2-2">Heading 2b</h2>
31
+ `;
32
+ document.body.appendChild(container);
33
+ });
34
+
35
+ afterEach(() => {
36
+ document.body.innerHTML = '';
37
+ });
38
+
39
+ describe('getHeadingLevel', () => {
40
+ it('returns correct level for h2-h6', () => {
41
+ expect(getHeadingLevel(document.getElementById('h2-1'))).toBe(2);
42
+ expect(getHeadingLevel(document.getElementById('h3-1'))).toBe(3);
43
+ });
44
+ it('returns null for h1 or non-heading', () => {
45
+ const h1 = document.createElement('h1');
46
+ expect(getHeadingLevel(h1)).toBeNull();
47
+ expect(getHeadingLevel(document.getElementById('p1'))).toBeNull();
48
+ });
49
+ });
50
+
51
+ describe('collectHeadingSiblings', () => {
52
+ it('collects heading and following siblings until next heading of same or higher level', () => {
53
+ const h2 = document.getElementById('h2-1');
54
+ const siblings = collectHeadingSiblings(h2, 2);
55
+ expect(siblings.map(n => n.id)).toEqual(['h2-1', 'p1', 'ul1', 'h3-1', 'p2']);
56
+ });
57
+ it('stops at next heading of same or higher level', () => {
58
+ const h3 = document.getElementById('h3-1');
59
+ const siblings = collectHeadingSiblings(h3, 3);
60
+ expect(siblings.map(n => n.id)).toEqual(['h3-1', 'p2']);
61
+ });
62
+ });
63
+
64
+ describe('wrapNodesWithHighlight', () => {
65
+ it('wraps nodes in a div.highlight2', () => {
66
+ const nodes = [document.getElementById('h2-1'), document.getElementById('p1')];
67
+ const wrapper = wrapNodesWithHighlight(nodes);
68
+ expect(wrapper).not.toBeNull();
69
+ expect(wrapper.className).toBe('highlight2');
70
+ expect(wrapper.contains(nodes[0])).toBe(true);
71
+ expect(wrapper.contains(nodes[1])).toBe(true);
72
+ });
73
+ it('returns null if nodes is empty', () => {
74
+ expect(wrapNodesWithHighlight([])).toBeNull();
75
+ });
76
+ });
77
+
78
+ describe('removeExistingHighlights', () => {
79
+ it('removes all .highlight2 wrappers and restores children', () => {
80
+ const nodes = [document.getElementById('h2-1'), document.getElementById('p1')];
81
+ wrapNodesWithHighlight(nodes);
82
+ expect(document.querySelectorAll('.highlight2').length).toBe(1);
83
+ const removed = removeExistingHighlights();
84
+ expect(removed).toBe(1);
85
+ expect(document.querySelectorAll('.highlight2').length).toBe(0);
86
+ // Children are restored to parent
87
+ expect(container.contains(nodes[0])).toBe(true);
88
+ expect(container.contains(nodes[1])).toBe(true);
89
+ });
90
+ });
91
+
92
+ describe('highlightHeadingSection', () => {
93
+ it('highlights section for valid anchor', () => {
94
+ expect(highlightHeadingSection('#h2-1')).toBe(true);
95
+ const highlight = document.querySelector('.highlight2');
96
+ expect(highlight).not.toBeNull();
97
+ expect(highlight.contains(document.getElementById('h2-1'))).toBe(true);
98
+ });
99
+ it('returns false for invalid anchor', () => {
100
+ expect(highlightHeadingSection('#does-not-exist')).toBe(false);
101
+ expect(highlightHeadingSection('not-a-hash')).toBe(false);
102
+ expect(highlightHeadingSection('#')).toBe(false);
103
+ });
104
+ it('returns false for non-heading element', () => {
105
+ expect(highlightHeadingSection('#p1')).toBe(false);
106
+ });
107
+ });
108
+
109
+ describe('initializeAnchorHighlighting', () => {
110
+ it('sets up event listeners and highlights on hash', () => {
111
+ window.location.hash = '#h2-1';
112
+ // Remove highlights if any
113
+ removeExistingHighlights();
114
+ initializeAnchorHighlighting();
115
+ // Simulate hashchange
116
+ window.dispatchEvent(new HashChangeEvent('hashchange'));
117
+ expect(document.querySelector('.highlight2')).not.toBeNull();
118
+ });
119
+ });
120
+ });
@@ -18,7 +18,7 @@
18
18
  "assets/css/create-term-filter.css",
19
19
  "assets/css/modal.css",
20
20
  "assets/css/create-alphabet-index.css",
21
- "assets/css/pdf-download.css",
21
+ "assets/css/download-pdf-docx.css",
22
22
  "assets/css/loader.css",
23
23
  "assets/css/external-links.css",
24
24
  "assets/css/repo-issues.css",
@@ -27,6 +27,7 @@
27
27
  "assets/css/add-bootstrap-classes-to-images.css",
28
28
  "assets/css/horizontal-scroll-hint.css",
29
29
  "assets/css/highlight-heading-plus-sibling-nodes.css",
30
+ "assets/css/counter.css",
30
31
  "assets/css/index.css"
31
32
  ],
32
33
  "js": [
@@ -59,7 +60,7 @@
59
60
  "assets/js/notyf.js",
60
61
  "assets/js/modal.js",
61
62
  "assets/js/token-input.js",
62
- "assets/js/pdf-download.js",
63
+ "assets/js/download-pdf-docx.js",
63
64
  "assets/js/insert-trefs.js",
64
65
  "assets/js/collapse-definitions.js",
65
66
  "assets/js/create-term-filter.js",
package/index.js CHANGED
@@ -191,7 +191,7 @@ module.exports = async function (options = {}) {
191
191
  tocFirstLevel: 2,
192
192
  tocLastLevel: 4,
193
193
  tocCallback: (_md, _tokens, html) => toc = html,
194
- anchorLinkSymbol: '#', // was: §
194
+ anchorLinkSymbol: config.specs[0].anchor_symbol || '§',
195
195
  anchorClassName: 'toc-anchor d-print-none'
196
196
  })
197
197
  .use(require('@traptitech/markdown-it-katex'))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-up-t",
3
- "version": "1.3.0-beta",
3
+ "version": "1.3.1",
4
4
  "description": "Technical specification drafting tool that generates rich specification documents from markdown. Forked from https://github.com/decentralized-identity/spec-up by Daniel Buchner (https://github.com/csuwildcat)",
5
5
  "main": "./index",
6
6
  "repository": {
@@ -68,7 +68,8 @@
68
68
  "braces": ">=3.0.3"
69
69
  },
70
70
  "devDependencies": {
71
- "jest": "^29.7.0"
71
+ "jest": "^29.7.0",
72
+ "jest-environment-jsdom": "^30.0.5"
72
73
  },
73
74
  "scripts": {
74
75
  "test": "jest",
@@ -1,6 +1,7 @@
1
- sonar.projectKey=blockchainbird_spec-up-t
2
- sonar.organization=blockchainbird
3
- sonar.host.url=https://sonarcloud.io
4
- sonar.token=SONAR_TOKEN
5
- sonar.exclusions=assets/compiled/refs.json
6
- sonar.cpd.exclusions=**/*.test.js
1
+ # Temporarily disabled for Automatic Analysis
2
+ # sonar.projectKey=blockchainbird_spec-up-t
3
+ # sonar.organization=blockchainbird
4
+ # sonar.host.url=https://sonarcloud.io
5
+ # sonar.token=SONAR_TOKEN
6
+ # sonar.exclusions=assets/compiled/refs.json
7
+ # sonar.cpd.exclusions=**/*.test.js
@@ -83,7 +83,7 @@ function processNode(node, elements = []) {
83
83
  if (li.tagName.toLowerCase() === 'li') {
84
84
  elements.push(new Paragraph({
85
85
  text: li.textContent.trim(),
86
- bullet: tagName === 'ul' ? { level: 0 } : { level: 0 }
86
+ bullet: { level: 0 }
87
87
  }));
88
88
  }
89
89
  });