From b9c7aaf7fb507c85cb20ea61fc0146dada11a12f Mon Sep 17 00:00:00 2001 From: "lina.wolf" Date: Fri, 11 Sep 2026 18:00:15 +0200 Subject: [PATCH] [BUGFIX] Guard the search scope select against a missing page header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit search-form.js added a "Search current" option to #searchscope after checking the URL but not the DOM, so add() dereferenced null when the element was absent, and the uncaught error aborted the remaining page scripts. Same guard CybotTM applied to versions.js in #1361. Not reachable on docs.typo3.org, whose page header always renders the select — but reachable since #1190 made templates overridable. Errors thrown inside a listener never reach the dispatchEvent caller, so both regression tests listen for the window error event. The test from guard removed; it now fails. Signed-off-by: lina.wolf Assisted-by: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_019EuSAzF5qw81NzPusWy2hC --- .../typo3-docs-theme/assets/js/search-form.js | 9 +++ .../resources/public/js/theme.min.js | 2 +- .../tests/js/search-form.test.js | 81 +++++++++++++++++++ .../tests/js/versions.test.js | 18 ++++- 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 packages/typo3-docs-theme/tests/js/search-form.test.js diff --git a/packages/typo3-docs-theme/assets/js/search-form.js b/packages/typo3-docs-theme/assets/js/search-form.js index f05bc5e3d..431fa0d5f 100644 --- a/packages/typo3-docs-theme/assets/js/search-form.js +++ b/packages/typo3-docs-theme/assets/js/search-form.js @@ -8,6 +8,15 @@ if (manualPath) { const searchScopeSelectList = document.getElementById(SELECTOR_SEARCH_SCOPE_SELECT_LIST); + + // The scope select lives in the theme's page header. A project that + // overrides that template can match the manual URL pattern without + // rendering it, and the add() below would then dereference null and + // abort the remaining page scripts. + if (!searchScopeSelectList) { + return; + } + const newOption = document.createElement('option'); newOption.value = manualPath; newOption.text = 'Search current'; diff --git a/packages/typo3-docs-theme/resources/public/js/theme.min.js b/packages/typo3-docs-theme/resources/public/js/theme.min.js index a89611d25..1dd193e01 100644 --- a/packages/typo3-docs-theme/resources/public/js/theme.min.js +++ b/packages/typo3-docs-theme/resources/public/js/theme.min.js @@ -66,7 +66,7 @@ class AllDocumentationsMenuBase extends HTMLElement{MAINMENU_JSON_URL="https://d  TER - `),l(u))})})(),function(){"use strict";var N={maxZoom:4,minZoom:1,zoomStep:.25,inlineMaxZoom:3,lensZoomFactor:2};function P(e,t,n){var r=document.createElement(e);return t&&(r.className=t),n&&Object.keys(n).forEach(function(e){"text"===e?r.textContent=n[e]:r.setAttribute(e,n[e])}),r}function A(e){var t;return e.length<2?0:(t=e[0].clientX-e[1].clientX,e=e[0].clientY-e[1].clientY,Math.sqrt(t*t+e*e))}function O(e,a,t,n,r,l){var o;function i(){var e,t,n,r;0',o.style.cssText="position:absolute;font-size:14px;opacity:0.7;z-index:10;color:#333;text-shadow:0 0 3px #fff, 0 0 5px #fff, 0 0 7px #fff;cursor:"+(l||"zoom-in")+";",n&&o.setAttribute("title",n),o.addEventListener("click",function(e){e.stopPropagation(),a.click()}),o.addEventListener("wheel",function(e){e.preventDefault(),e.stopPropagation();e=new WheelEvent("wheel",{deltaY:e.deltaY,deltaX:e.deltaX,clientX:e.clientX,clientY:e.clientY,bubbles:!0,cancelable:!0});a.dispatchEvent(e)},{passive:!1}),e.style.position="relative",e.appendChild(o),a.complete?i():a.addEventListener("load",i),window.addEventListener("resize",i))}function e(){document.querySelectorAll('[data-zoom="lightbox"]').forEach(function(e){var t,n,r,a,l="IMG"===e.tagName?e:e.querySelector("img");l&&(r=l.src,t="",t=(a=e.querySelector("figcaption"))?a.textContent:l.alt||"",n=P("dialog","image-lightbox-dialog"),a=P("img","",{src:r,alt:t}),r=P("button","lightbox-close",{"aria-label":"Close",text:"×"}),n.appendChild(r),n.appendChild(a),t&&(a=P("p","lightbox-caption",{text:t}),n.appendChild(a)),document.body.appendChild(n),l.setAttribute("tabindex","0"),l.setAttribute("role","button"),l.setAttribute("aria-label","Click to enlarge: "+(t||"image")),l.classList.add("lightbox-trigger"),(a=P("span","zoom-trigger-wrapper")).style.cssText="display:inline-block;position:relative;line-height:0;",l.parentNode.insertBefore(a,l),a.appendChild(l),O(a,l,"fa-magnifying-glass-plus","Click to enlarge",e),l.addEventListener("dragstart",function(e){e.preventDefault()}),l.addEventListener("click",function(e){e.preventDefault(),n.showModal()}),l.addEventListener("keydown",function(e){"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),n.showModal())}),n.addEventListener("click",function(e){e.target.classList.contains("lightbox-close")||n.close()}),r.addEventListener("click",function(){n.close()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&n.close()}))})}function t(){var r,e,t,n,a,l,o,i,s,u,c,d,f,p,m,h,g,y,v,b,k,w={};function S(e){var t,n;"Tab"===e.key&&0!==(n=r.querySelectorAll("button:not([disabled])")).length&&(t=n[0],n=n[n.length-1],e.shiftKey&&document.activeElement===t?(e.preventDefault(),n.focus()):e.shiftKey||document.activeElement!==n||(e.preventDefault(),t.focus()))}function E(e,t){g=document.activeElement,(p=w[e]).currentIndex=t,p.zoom=1,p.panX=0,p.panY=0,C(),r.classList.add("active"),document.body.style.overflow="hidden",c.textContent=p.images.length;var n=r.querySelector(".gallery-close");n&&setTimeout(function(){n.focus()},50),r.addEventListener("keydown",S)}function x(){r.classList.remove("active"),document.body.style.overflow="",r.removeEventListener("keydown",S),g&&g.focus&&g.focus(),g=p=null}function C(){var e;p&&(e=p.images[p.currentIndex],i.onerror=function(){i.alt="Image failed to load: "+e.src,i.style.opacity="0.5"},i.onload=function(){i.style.opacity="1"},i.src=e.src,i.alt=e.caption,s.textContent=e.caption,u.textContent=p.currentIndex+1,_())}function L(e){var t;p&&(t=p.images.length,p.currentIndex=(p.currentIndex+e+t)%t,C())}function T(e){p&&(p.zoom=Math.max(p.minZoom,Math.min(p.maxZoom,e)),1===p.zoom&&(p.panX=0,p.panY=0),z())}function _(){p&&(p.zoom=1,p.panX=0,p.panY=0,z())}function z(){p&&(i.style.transform="translate("+p.panX+"px, "+p.panY+"px) scale("+p.zoom+")",d.textContent=Math.round(100*p.zoom)+"%",i.style.cursor=1=r.left&&t<=r.right&&n>=r.top&&n<=r.bottom?(t=m(),n=e.clientX-t.left,r=e.clientY-t.top,l=n/t.width*100,o=r/t.height*100,a||f(),d(n,r)):a&&p()}),c.addEventListener("mouseleave",function(){p()}),e.addEventListener("keydown",function(e){var t,n;switch(e.key){case"Enter":case" ":e.preventDefault(),a?(p(),r.textContent="Lens deactivated"):(f(),d((n=c.getBoundingClientRect()).width*(l/100),n.height*(o/100)),r.textContent="Lens activated. Use arrow keys to move.");break;case"Escape":e.preventDefault(),a&&(p(),r.textContent="Lens deactivated");break;case"ArrowUp":a&&(e.preventDefault(),o=Math.max(0,o-5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowDown":a&&(e.preventDefault(),o=Math.min(100,o+5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowLeft":a&&(e.preventDefault(),l=Math.max(0,l-5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowRight":a&&(e.preventDefault(),l=Math.min(100,l+5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)))}}))})}function a(){e(),t(),n(),r()}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",a):a(),window.TYPO3DocsImageZoom={init:a,initDialogLightbox:e,initGallery:t,initInlineZoom:n,initLensZoom:r}}(),(()=>{const s="#permalink-uri",u="#permalink-short",c="#permalink-md",d="#permalink-html";function f(e,t,n,r,a){var l="https://docs.typo3.org/permalink/",e=e.dataset.interlinkShortcode||"somemanual",e=e.replaceAll("/","-",e);return r?l+e+":"+r:""===a?"":l+e+`:${a}#`+(t?.id||"")}function p(r){const a=r.querySelector("#permalink-alert-success");var e=r.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,n=this.getAttribute("data-target"),n=r.querySelector("#"+n);n?(a.classList.remove("d-none"),a.innerHTML=`Snippet ${e=n.value,t=document.createElement("div"),t.textContent=e,t.innerHTML} was copied to your clipboard.`,navigator.clipboard.writeText(n.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const m=document.querySelector("#linkReferenceModal");m&&m.addEventListener("show.bs.modal",function(e){var e=e.relatedTarget,t=e.closest("section"),n=e.dataset.id||(t?t.dataset.rstAnchor:null),r=e.closest("h1, h2, h3, h4, h5, h6, dt"),r=r?r.innerText.replace(/^\s+|\s+$/gu,""):"",a=e.dataset.rstcode,e=e.title,l=(l=m,i=n||a,o=l.querySelector(".alert-permalink-rst"),l=l.querySelector(".permalink-short-wrapper"),i?(o.classList.add("d-none"),l.classList.remove("d-none")):(o.classList.remove("d-none"),l.classList.add("d-none")),i=t,o=n,"null"===window.location.origin||"file://"===window.location.origin?null:o?""+window.location.origin+window.location.pathname+"#"+o:""+window.location.origin+window.location.pathname+"#"+(i?.id||"")),o=m.dataset.currentFilename,a=a||(i=m,a=r,(i=f(i,t,0,n,o))?`\`${a} <${i}>\`_`:""),i=f(m,t,0,n,o);t=m,o=r,r=l,a=a,n=n?i:l,(i=e)&&(t.querySelector("h5").textContent=i),null===r?(t.querySelector(s).value="",t.querySelector(d).value="",t.querySelector(c).value="",t.querySelector(u).value=""):(t.querySelector(s).value=r,t.querySelector(u).value=n,t.querySelector(c).value=`[${o}](${n})`,t.querySelector(d).value=`${o}`),i=t.querySelector("#permalink-rst"),n=i.closest("div"),""===a?n.classList.add("d-none"):(n.classList.remove("d-none"),i.value=a),p(m)})})(),(()=>{"use strict";function n(e){e.preventDefault();e=e.currentTarget;const t=e.parentElement;t.parentElement.parentElement.querySelectorAll("li.active").forEach(e=>{e!==t&&(e.classList.remove("active"),e=e.querySelector(":scope > .toctree-expand"))&&e.setAttribute("aria-expanded","false")}),t.classList.toggle("active"),e.setAttribute("aria-expanded",t.classList.contains("active"))}{const r=document.getElementById("toc-toggle");r.addEventListener("click",()=>{return e=r,(t=document.getElementById("toc-collapse")).classList.toggle("show"),void e.setAttribute("aria-expanded",t.classList.contains("show"));var e,t},!0)}var e;(e=document.getElementById("search-toggle"))&&e.addEventListener("click",()=>{document.getElementById("global-search-root")?.querySelector("button")?.click()},!0),window.addEventListener("all-documentation-menu-loaded",()=>{var e;e=document.getElementsByClassName("main_menu"),Array.from(e).forEach(e=>{e=e.getElementsByTagName("a");Array.from(e).forEach(e=>{var t;e.nextSibling&&((t=document.createElement("button")).classList.add("toctree-expand"),t.setAttribute("aria-expanded","false"),t.setAttribute("aria-label","Toggle "+e.textContent.trim()),t.addEventListener("click",n,!0),e.after(t))})})})})(),document.addEventListener("DOMContentLoaded",function(){const e=document.querySelector("header"),n=document.querySelectorAll("[id]");function t(){const t=(e?e.offsetHeight:80)+10+"px";n.forEach(e=>{e.style.scrollMarginTop=t})}function r(e="smooth"){var t=window.location.hash.substring(1);if(t)if("top"===t)window.scrollTo({top:0,behavior:e});else{const n=document.getElementById(t);n&&setTimeout(()=>{n.scrollIntoView({behavior:e,block:"start"})},50)}}var a,l;t(),setTimeout(()=>r("auto"),100),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();e=this.getAttribute("href").substring(1);history.pushState(null,null,"#"+e),r()})}),a=document.querySelector(".page-main-navigation nav"),l=a?.querySelector(".main_menu .active"),a&&l&&(a.scrollTop=l.offsetTop-a.clientHeight/2+l.clientHeight/2);let o;window.addEventListener("resize",()=>{clearTimeout(o),o=setTimeout(t,100)},{passive:!0})}),window.addEventListener("load",()=>{var e,t,n=window.location.pathname.match(/^\/(c|m|p|h|other)\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-.]+\/[A-Za-z0-9\-]+\/(Changelog\/[A-Za-z0-9\-.]+\/)?/),n=n?n[0]:null;n&&(e=document.getElementById("searchscope"),(t=document.createElement("option")).value=n,t.text="Search current",e.add(t))});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,l,o,i)=>{if(l&&"object"==typeof l||"function"==typeof l)for(var s,u=r(l),c=0,d=u.length;cl[e]).bind(null,s),enumerable:!(i=n(l,s))||i.enumerable});return e},c=(n,r,l)=>(l=null==n?{}:e(i(n)),s(!r&&n&&n.__esModule&&a.call(n,"default")?l:t(l,"default",{value:n,enumerable:!0}),n)),l=o(e=>{var d=Symbol.for("react.transitional.element"),f=Symbol.for("react.portal"),t=Symbol.for("react.fragment"),n=Symbol.for("react.strict_mode"),r=Symbol.for("react.profiler"),a=Symbol.for("react.consumer"),l=Symbol.for("react.context"),o=Symbol.for("react.forward_ref"),i=Symbol.for("react.suspense"),s=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),u=Symbol.for("react.activity"),m=Symbol.iterator;var c={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||c}function v(){}function b(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||c}y.prototype.isReactComponent={},y.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},y.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},v.prototype=y.prototype;var k=b.prototype=new v,w=(k.constructor=b,h(k,y.prototype),k.isPureReactComponent=!0,Array.isArray);function S(){}var E={H:null,A:null,T:null,S:null},x=Object.prototype.hasOwnProperty;function C(e,t,n){var r=n.ref;return{$$typeof:d,type:e,key:t,ref:void 0===r?null:r,props:n}}function L(e){return"object"==typeof e&&!!e&&e.$$typeof===d}var T=/\/+/g;function _(e,t){return"object"==typeof e&&e&&null!=e.key?(e=""+e.key,n={"=":"=0",":":"=2"},"$"+e.replace(/[=:]/g,function(e){return n[e]})):t.toString(36);var n}function z(e,t,n,r,a){var l,o=typeof e,i=!1;if(null===(e="undefined"!==o&&"boolean"!==o?e:null))i=!0;else switch(o){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case d:case f:i=!0;break;case p:return z((i=e._init)(e._payload),t,n,r,a)}}if(i)return a=a(e),i=""===r?"."+_(e,0):r,w(a)?(n="",z(a,t,n=null!=i?i.replace(T,"$&/")+"/":n,"",function(e){return e})):null!=a&&(L(a)&&(s=n+(null==(l=a).key||e&&e.key===a.key?"":(""+a.key).replace(T,"$&/")+"/")+i,a=C(l.type,s,l.props)),t.push(a)),1;var s,i=0,u=""===r?".":r+":";if(w(e))for(var c=0;c{t.exports=l()}),d=o(o=>{function l(e,t){var n=e.length;for(e.push(t);0>>1,a=e[r];if(!(0>>1;re&&z());){var r=p.callback;if("function"==typeof r){p.callback=null,m=p.priorityLevel;var a=r(p.expirationTime<=e),e=o.unstable_now();if("function"==typeof a){p.callback=a,k(e),t=!0;break t}p===i(u)&&s(u),k(e)}else s(u);p=i(u)}var l,t=null!==p||(null!==(l=i(d))&&P(w,l.startTime-e),!1)}break e}finally{p=null,m=n,h=!1}t=void 0}}finally{t?S():C=!1}}}function P(e,t){L=r(function(){e(o.unstable_now())},t)}S="function"==typeof a?function(){a(N)}:typeof MessageChannel<"u"?(E=new MessageChannel,x=E.port2,E.port1.onmessage=N,function(){x.postMessage(null)}):function(){r(N,0)},o.unstable_IdlePriority=5,o.unstable_ImmediatePriority=1,o.unstable_LowPriority=4,o.unstable_NormalPriority=3,o.unstable_Profiling=null,o.unstable_UserBlockingPriority=2,o.unstable_cancelCallback=function(e){e.callback=null},o.unstable_forceFrameRate=function(e){e<0||125{t.exports=d()}),p=o(e=>{var t=u();function r(e,t){var n="https://react.dev/errors/"+e;if(1{(function e(){if(!("u"{var n=f(),l=u(),e=m();function F(e,t){var n="https://react.dev/errors/"+e;if(1',o.style.cssText="position:absolute;font-size:14px;opacity:0.7;z-index:10;color:#333;text-shadow:0 0 3px #fff, 0 0 5px #fff, 0 0 7px #fff;cursor:"+(l||"zoom-in")+";",n&&o.setAttribute("title",n),o.addEventListener("click",function(e){e.stopPropagation(),a.click()}),o.addEventListener("wheel",function(e){e.preventDefault(),e.stopPropagation();e=new WheelEvent("wheel",{deltaY:e.deltaY,deltaX:e.deltaX,clientX:e.clientX,clientY:e.clientY,bubbles:!0,cancelable:!0});a.dispatchEvent(e)},{passive:!1}),e.style.position="relative",e.appendChild(o),a.complete?i():a.addEventListener("load",i),window.addEventListener("resize",i))}function e(){document.querySelectorAll('[data-zoom="lightbox"]').forEach(function(e){var t,n,r,a,l="IMG"===e.tagName?e:e.querySelector("img");l&&(r=l.src,t="",t=(a=e.querySelector("figcaption"))?a.textContent:l.alt||"",n=P("dialog","image-lightbox-dialog"),a=P("img","",{src:r,alt:t}),r=P("button","lightbox-close",{"aria-label":"Close",text:"×"}),n.appendChild(r),n.appendChild(a),t&&(a=P("p","lightbox-caption",{text:t}),n.appendChild(a)),document.body.appendChild(n),l.setAttribute("tabindex","0"),l.setAttribute("role","button"),l.setAttribute("aria-label","Click to enlarge: "+(t||"image")),l.classList.add("lightbox-trigger"),(a=P("span","zoom-trigger-wrapper")).style.cssText="display:inline-block;position:relative;line-height:0;",l.parentNode.insertBefore(a,l),a.appendChild(l),O(a,l,"fa-magnifying-glass-plus","Click to enlarge",e),l.addEventListener("dragstart",function(e){e.preventDefault()}),l.addEventListener("click",function(e){e.preventDefault(),n.showModal()}),l.addEventListener("keydown",function(e){"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),n.showModal())}),n.addEventListener("click",function(e){e.target.classList.contains("lightbox-close")||n.close()}),r.addEventListener("click",function(){n.close()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&n.close()}))})}function t(){var r,e,t,n,a,l,o,i,s,u,c,d,f,p,m,h,g,y,v,b,k,w={};function S(e){var t,n;"Tab"===e.key&&0!==(n=r.querySelectorAll("button:not([disabled])")).length&&(t=n[0],n=n[n.length-1],e.shiftKey&&document.activeElement===t?(e.preventDefault(),n.focus()):e.shiftKey||document.activeElement!==n||(e.preventDefault(),t.focus()))}function E(e,t){g=document.activeElement,(p=w[e]).currentIndex=t,p.zoom=1,p.panX=0,p.panY=0,C(),r.classList.add("active"),document.body.style.overflow="hidden",c.textContent=p.images.length;var n=r.querySelector(".gallery-close");n&&setTimeout(function(){n.focus()},50),r.addEventListener("keydown",S)}function x(){r.classList.remove("active"),document.body.style.overflow="",r.removeEventListener("keydown",S),g&&g.focus&&g.focus(),g=p=null}function C(){var e;p&&(e=p.images[p.currentIndex],i.onerror=function(){i.alt="Image failed to load: "+e.src,i.style.opacity="0.5"},i.onload=function(){i.style.opacity="1"},i.src=e.src,i.alt=e.caption,s.textContent=e.caption,u.textContent=p.currentIndex+1,_())}function L(e){var t;p&&(t=p.images.length,p.currentIndex=(p.currentIndex+e+t)%t,C())}function T(e){p&&(p.zoom=Math.max(p.minZoom,Math.min(p.maxZoom,e)),1===p.zoom&&(p.panX=0,p.panY=0),z())}function _(){p&&(p.zoom=1,p.panX=0,p.panY=0,z())}function z(){p&&(i.style.transform="translate("+p.panX+"px, "+p.panY+"px) scale("+p.zoom+")",d.textContent=Math.round(100*p.zoom)+"%",i.style.cursor=1=r.left&&t<=r.right&&n>=r.top&&n<=r.bottom?(t=m(),n=e.clientX-t.left,r=e.clientY-t.top,l=n/t.width*100,o=r/t.height*100,a||f(),d(n,r)):a&&p()}),c.addEventListener("mouseleave",function(){p()}),e.addEventListener("keydown",function(e){var t,n;switch(e.key){case"Enter":case" ":e.preventDefault(),a?(p(),r.textContent="Lens deactivated"):(f(),d((n=c.getBoundingClientRect()).width*(l/100),n.height*(o/100)),r.textContent="Lens activated. Use arrow keys to move.");break;case"Escape":e.preventDefault(),a&&(p(),r.textContent="Lens deactivated");break;case"ArrowUp":a&&(e.preventDefault(),o=Math.max(0,o-5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowDown":a&&(e.preventDefault(),o=Math.min(100,o+5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowLeft":a&&(e.preventDefault(),l=Math.max(0,l-5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)));break;case"ArrowRight":a&&(e.preventDefault(),l=Math.min(100,l+5),d((t=c.getBoundingClientRect()).width*(l/100),t.height*(o/100)))}}))})}function a(){e(),t(),n(),r()}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",a):a(),window.TYPO3DocsImageZoom={init:a,initDialogLightbox:e,initGallery:t,initInlineZoom:n,initLensZoom:r}}(),(()=>{const s="#permalink-uri",u="#permalink-short",c="#permalink-md",d="#permalink-html";function f(e,t,n,r,a){var l="https://docs.typo3.org/permalink/",e=e.dataset.interlinkShortcode||"somemanual",e=e.replaceAll("/","-",e);return r?l+e+":"+r:""===a?"":l+e+`:${a}#`+(t?.id||"")}function p(r){const a=r.querySelector("#permalink-alert-success");var e=r.querySelectorAll(".copy-button");navigator.clipboard&&navigator.clipboard.writeText?e.forEach(e=>{e.addEventListener("click",function(){var e,t,n=this.getAttribute("data-target"),n=r.querySelector("#"+n);n?(a.classList.remove("d-none"),a.innerHTML=`Snippet ${e=n.value,t=document.createElement("div"),t.textContent=e,t.innerHTML} was copied to your clipboard.`,navigator.clipboard.writeText(n.value)):console.warn("Cannot copy link as no input is available!")})}):(console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard'),e.forEach(e=>e.disabled=!0))}const m=document.querySelector("#linkReferenceModal");m&&m.addEventListener("show.bs.modal",function(e){var e=e.relatedTarget,t=e.closest("section"),n=e.dataset.id||(t?t.dataset.rstAnchor:null),r=e.closest("h1, h2, h3, h4, h5, h6, dt"),r=r?r.innerText.replace(/^\s+|\s+$/gu,""):"",a=e.dataset.rstcode,e=e.title,l=(l=m,i=n||a,o=l.querySelector(".alert-permalink-rst"),l=l.querySelector(".permalink-short-wrapper"),i?(o.classList.add("d-none"),l.classList.remove("d-none")):(o.classList.remove("d-none"),l.classList.add("d-none")),i=t,o=n,"null"===window.location.origin||"file://"===window.location.origin?null:o?""+window.location.origin+window.location.pathname+"#"+o:""+window.location.origin+window.location.pathname+"#"+(i?.id||"")),o=m.dataset.currentFilename,a=a||(i=m,a=r,(i=f(i,t,0,n,o))?`\`${a} <${i}>\`_`:""),i=f(m,t,0,n,o);t=m,o=r,r=l,a=a,n=n?i:l,(i=e)&&(t.querySelector("h5").textContent=i),null===r?(t.querySelector(s).value="",t.querySelector(d).value="",t.querySelector(c).value="",t.querySelector(u).value=""):(t.querySelector(s).value=r,t.querySelector(u).value=n,t.querySelector(c).value=`[${o}](${n})`,t.querySelector(d).value=`${o}`),i=t.querySelector("#permalink-rst"),n=i.closest("div"),""===a?n.classList.add("d-none"):(n.classList.remove("d-none"),i.value=a),p(m)})})(),(()=>{"use strict";function n(e){e.preventDefault();e=e.currentTarget;const t=e.parentElement;t.parentElement.parentElement.querySelectorAll("li.active").forEach(e=>{e!==t&&(e.classList.remove("active"),e=e.querySelector(":scope > .toctree-expand"))&&e.setAttribute("aria-expanded","false")}),t.classList.toggle("active"),e.setAttribute("aria-expanded",t.classList.contains("active"))}{const r=document.getElementById("toc-toggle");r.addEventListener("click",()=>{return e=r,(t=document.getElementById("toc-collapse")).classList.toggle("show"),void e.setAttribute("aria-expanded",t.classList.contains("show"));var e,t},!0)}var e;(e=document.getElementById("search-toggle"))&&e.addEventListener("click",()=>{document.getElementById("global-search-root")?.querySelector("button")?.click()},!0),window.addEventListener("all-documentation-menu-loaded",()=>{var e;e=document.getElementsByClassName("main_menu"),Array.from(e).forEach(e=>{e=e.getElementsByTagName("a");Array.from(e).forEach(e=>{var t;e.nextSibling&&((t=document.createElement("button")).classList.add("toctree-expand"),t.setAttribute("aria-expanded","false"),t.setAttribute("aria-label","Toggle "+e.textContent.trim()),t.addEventListener("click",n,!0),e.after(t))})})})})(),document.addEventListener("DOMContentLoaded",function(){const e=document.querySelector("header"),n=document.querySelectorAll("[id]");function t(){const t=(e?e.offsetHeight:80)+10+"px";n.forEach(e=>{e.style.scrollMarginTop=t})}function r(e="smooth"){var t=window.location.hash.substring(1);if(t)if("top"===t)window.scrollTo({top:0,behavior:e});else{const n=document.getElementById(t);n&&setTimeout(()=>{n.scrollIntoView({behavior:e,block:"start"})},50)}}var a,l;t(),setTimeout(()=>r("auto"),100),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();e=this.getAttribute("href").substring(1);history.pushState(null,null,"#"+e),r()})}),a=document.querySelector(".page-main-navigation nav"),l=a?.querySelector(".main_menu .active"),a&&l&&(a.scrollTop=l.offsetTop-a.clientHeight/2+l.clientHeight/2);let o;window.addEventListener("resize",()=>{clearTimeout(o),o=setTimeout(t,100)},{passive:!0})}),window.addEventListener("load",()=>{var e,t,n=window.location.pathname.match(/^\/(c|m|p|h|other)\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-_]+\/[A-Za-z0-9\-.]+\/[A-Za-z0-9\-]+\/(Changelog\/[A-Za-z0-9\-.]+\/)?/),n=n?n[0]:null;n&&(e=document.getElementById("searchscope"))&&((t=document.createElement("option")).value=n,t.text="Search current",e.add(t))});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,l,o,i)=>{if(l&&"object"==typeof l||"function"==typeof l)for(var s,u=r(l),c=0,d=u.length;cl[e]).bind(null,s),enumerable:!(i=n(l,s))||i.enumerable});return e},c=(n,r,l)=>(l=null==n?{}:e(i(n)),s(!r&&n&&n.__esModule&&a.call(n,"default")?l:t(l,"default",{value:n,enumerable:!0}),n)),l=o(e=>{var d=Symbol.for("react.transitional.element"),f=Symbol.for("react.portal"),t=Symbol.for("react.fragment"),n=Symbol.for("react.strict_mode"),r=Symbol.for("react.profiler"),a=Symbol.for("react.consumer"),l=Symbol.for("react.context"),o=Symbol.for("react.forward_ref"),i=Symbol.for("react.suspense"),s=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),u=Symbol.for("react.activity"),m=Symbol.iterator;var c={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||c}function v(){}function b(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||c}y.prototype.isReactComponent={},y.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},y.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},v.prototype=y.prototype;var k=b.prototype=new v,w=(k.constructor=b,h(k,y.prototype),k.isPureReactComponent=!0,Array.isArray);function S(){}var E={H:null,A:null,T:null,S:null},x=Object.prototype.hasOwnProperty;function C(e,t,n){var r=n.ref;return{$$typeof:d,type:e,key:t,ref:void 0===r?null:r,props:n}}function L(e){return"object"==typeof e&&!!e&&e.$$typeof===d}var T=/\/+/g;function _(e,t){return"object"==typeof e&&e&&null!=e.key?(e=""+e.key,n={"=":"=0",":":"=2"},"$"+e.replace(/[=:]/g,function(e){return n[e]})):t.toString(36);var n}function z(e,t,n,r,a){var l,o=typeof e,i=!1;if(null===(e="undefined"!==o&&"boolean"!==o?e:null))i=!0;else switch(o){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case d:case f:i=!0;break;case p:return z((i=e._init)(e._payload),t,n,r,a)}}if(i)return a=a(e),i=""===r?"."+_(e,0):r,w(a)?(n="",z(a,t,n=null!=i?i.replace(T,"$&/")+"/":n,"",function(e){return e})):null!=a&&(L(a)&&(s=n+(null==(l=a).key||e&&e.key===a.key?"":(""+a.key).replace(T,"$&/")+"/")+i,a=C(l.type,s,l.props)),t.push(a)),1;var s,i=0,u=""===r?".":r+":";if(w(e))for(var c=0;c{t.exports=l()}),d=o(o=>{function l(e,t){var n=e.length;for(e.push(t);0>>1,a=e[r];if(!(0>>1;re&&z());){var r=p.callback;if("function"==typeof r){p.callback=null,m=p.priorityLevel;var a=r(p.expirationTime<=e),e=o.unstable_now();if("function"==typeof a){p.callback=a,k(e),t=!0;break t}p===i(u)&&s(u),k(e)}else s(u);p=i(u)}var l,t=null!==p||(null!==(l=i(d))&&P(w,l.startTime-e),!1)}break e}finally{p=null,m=n,h=!1}t=void 0}}finally{t?S():C=!1}}}function P(e,t){L=r(function(){e(o.unstable_now())},t)}S="function"==typeof a?function(){a(N)}:typeof MessageChannel<"u"?(E=new MessageChannel,x=E.port2,E.port1.onmessage=N,function(){x.postMessage(null)}):function(){r(N,0)},o.unstable_IdlePriority=5,o.unstable_ImmediatePriority=1,o.unstable_LowPriority=4,o.unstable_NormalPriority=3,o.unstable_Profiling=null,o.unstable_UserBlockingPriority=2,o.unstable_cancelCallback=function(e){e.callback=null},o.unstable_forceFrameRate=function(e){e<0||125{t.exports=d()}),p=o(e=>{var t=u();function r(e,t){var n="https://react.dev/errors/"+e;if(1{(function e(){if(!("u"{var n=f(),l=u(),e=m();function F(e,t){var n="https://react.dev/errors/"+e;if(1)":-1 { + event.preventDefault(); + errors.push(event.error ?? event.message); + }; + window.addEventListener('error', onError); + return { + errors, + stop: () => window.removeEventListener('error', onError), + }; +} + +describe('search scope option', () => { + let capture; + + beforeEach(() => { + document.body.replaceChildren(); + capture = captureListenerErrors(); + }); + + afterEach(() => { + capture.stop(); + }); + + it('adds a "Search current" option scoped to the manual', () => { + const select = document.createElement('select'); + select.id = 'searchscope'; + document.body.appendChild(select); + visitManualPage(); + + window.dispatchEvent(new Event('load')); + + expect(Array.from(select.options).map(option => option.value)).toContain(MANUAL_PATH); + expect(capture.errors).toEqual([]); + }); + + it('does not throw when the page header has no scope select', () => { + // URL matches a manual path, but #searchscope is absent. + visitManualPage(); + + window.dispatchEvent(new Event('load')); + + expect(capture.errors).toEqual([]); + }); + + it('adds nothing outside a manual path', () => { + const select = document.createElement('select'); + select.id = 'searchscope'; + document.body.appendChild(select); + window.history.pushState({}, '', '/search/search?q=example'); + + window.dispatchEvent(new Event('load')); + + expect(select.options).toHaveLength(0); + expect(capture.errors).toEqual([]); + }); +}); diff --git a/packages/typo3-docs-theme/tests/js/versions.test.js b/packages/typo3-docs-theme/tests/js/versions.test.js index fee40dafb..31014a534 100644 --- a/packages/typo3-docs-theme/tests/js/versions.test.js +++ b/packages/typo3-docs-theme/tests/js/versions.test.js @@ -130,6 +130,22 @@ describe('version switcher', () => { // versionSelect.getAttribute() call threw "Cannot read properties of null". document.body.replaceChildren(); - expect(() => document.dispatchEvent(new Event('DOMContentLoaded'))).not.toThrow(); + // Errors thrown inside an event listener do not propagate to the + // dispatchEvent caller — the DOM reports them instead — so asserting on + // dispatchEvent not throwing would pass even without the guard. + const errors = []; + const onError = (event) => { + event.preventDefault(); + errors.push(event.error ?? event.message); + }; + window.addEventListener('error', onError); + + try { + document.dispatchEvent(new Event('DOMContentLoaded')); + } finally { + window.removeEventListener('error', onError); + } + + expect(errors).toEqual([]); }); });