Repository navigation
Conversation
|
(the label is still under dev .. I will likely be able to enable it this week) |
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as outdated.
This comment was marked as outdated.
|
+1, thank you @nchammas and @HyukjinKwon! |
dongjoon-hyun
left a comment
There was a problem hiding this comment.
Thank you for the upgrade, @nchammas. I reviewed the latest commit, 3a8ed3d, and left 9 inline comments. Here is a summary, ordered by priority.
Correctness and compatibility
licenses-binary/LICENSE-AnchorJS.txtL3: the copyright fix is not applied to the binary copy, which the binary tarball and the pyspark package ship.global.htmlL209: the page-wide selector also anchors the sidebar<h3>titles and the hero<h1>(not a regression), so the titles of 7 streaming pages get-1ids; scoping it to#contentwould fix this.global.htmlL209: right after a release, a browser with the oldmain.jsand 1.1.1 still cached can add every anchor twice.anchor.min.jsL8: the bareglobalThisdrops all anchors on Chrome < 71, Firefox < 65, and Safari < 12.1 (negligible in practice).
Maintainability
global.htmlL206: the inline config is not covered bydev/lint-js, unlike the same lines inmain.js.global.htmlL199: the sync note sits in the ignored body of<script src>, and its link returns 404 until apache/spark-website#700 is merged.
PR title and description
- Title:
[INFRA]maps to Project Infra, but docs front-end changes have used[DOCS]; AnchorJS itself was added as[SPARK-8353] [DOCS]. Could the title be[SPARK-60281][DOCS] Upgrade AnchorJS to v5.0.0, with the JIRA component to match? - Description: the generative-AI section does not have the
Generated-by: <tool> <version>phrase that the PR template asks for, e.g.Generated-by: GitHub Copilot <version>, and "AnchorsJS" is a typo. Both end up in the commit message.
Optional
global.htmlL206:placement: 'right'is the default, so the line has no effect.anchor.min.jsL8: FYI, 5.0.0 queries<base>once per heading (an upstream issue).main.jsL100: pre-existing and outside this PR: the resize handler keeps re-binding the dropdown hover handlers.
Items 1, 2, and 5 are the ones I would most like to see addressed here, and items 7 and 8 only need the PR title and description. The rest are optional.
| anchors.options = { placement: 'right' }; | ||
| // Note: AnchorJS 4.0+ excludes h1 from the default selector, but many | ||
| // Spark doc pages use h1 for section headings, so we include it explicitly. | ||
| anchors.add('h1, h2, h3, h4, h5, h6'); |
There was a problem hiding this comment.
2. This selector also anchors the layout's own headings, not just the page content. It matches the fixed sidebar titles from _includes/nav-left-wrapper-*.html (for example <h3><a href="sql-programming-guide.html">Spark SQL Guide</a></h3>) and the hero <h1> on the landing page. As a result:
- On the 151
sql*.htmlpages, the sidebar title gets an anchor to#spark-sql-guideon the current page, and screen readers read one more "Anchor" link there. - On the 7 streaming pages titled "Structured Streaming Programming Guide", the sidebar
<h3>comes first in DOM order, so it takes#structured-streaming-programming-guide, and the real page title gets#structured-streaming-programming-guide-1.
This is not a regression, because 1.1.1's default selector matched the same elements. But since this line is being rewritten anyway, could we scope it to the content? Both layout branches use id="content", so anchors.add('#content h1, #content h2, #content h3, #content h4, #content h5, #content h6'); keeps the page-title and section anchors and drops the sidebar and hero ones.
There was a problem hiding this comment.
Addressed. I used the more modern :is CSS selector here, as it's cleaner. Any browser released since early 2021 will support it.
| anchors.options = { placement: 'right' }; | ||
| // Note: AnchorJS 4.0+ excludes h1 from the default selector, but many | ||
| // Spark doc pages use h1 for section headings, so we include it explicitly. | ||
| anchors.add('h1, h2, h3, h4, h5, h6'); |
There was a problem hiding this comment.
- Minor: moving this call out of
main.jscan briefly double the anchors right after a release. spark.apache.org servesdocs/latest/js/*.jswith onlyLast-ModifiedandETag, withoutCache-ControlorExpires, so browsers may keep reusing cached copies for days afterdocs/latestmoves to a new release. A returning visitor who still has the oldmain.jsand the 1.1.1anchor.min.jscached runs this newanchors.add(...)first and the oldanchors.add()inmain.jssecond. 1.1.1 has no check for an existing anchor, so every heading shows two icons until the cache expires. It is cosmetic and temporary. Could we keep the call inmain.jsas in item 5, which avoids this mixed state?
There was a problem hiding this comment.
Don't think this is worth any cache-busting fixes. It's a minor and transient issue, as you noted. I will address item 5 separately.
| // Copyright (c) 2023 Bryan Braun; Licensed MIT | ||
| // | ||
| // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat | ||
| !function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(globalThis,function(){"use strict";return function(A){function u(A){A.icon=Object.prototype.hasOwnProperty.call(A,"icon")?A.icon:"",A.visible=Object.prototype.hasOwnProperty.call(A,"visible")?A.visible:"hover",A.placement=Object.prototype.hasOwnProperty.call(A,"placement")?A.placement:"right",A.ariaLabel=Object.prototype.hasOwnProperty.call(A,"ariaLabel")?A.ariaLabel:"Anchor",A.class=Object.prototype.hasOwnProperty.call(A,"class")?A.class:"",A.base=Object.prototype.hasOwnProperty.call(A,"base")?A.base:"",A.truncate=Object.prototype.hasOwnProperty.call(A,"truncate")?Math.floor(A.truncate):64,A.titleText=Object.prototype.hasOwnProperty.call(A,"titleText")?A.titleText:""}function d(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new TypeError("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],u(this.options),this.add=function(A){var e,t,o,i,n,s,a,r,l,c,h,p=[];if(u(this.options),0!==(e=d(A=A||"h2, h3, h4, h5, h6")).length){for(null===document.head.querySelector("style.anchorjs")&&((A=document.createElement("style")).className="anchorjs",A.appendChild(document.createTextNode("")),void 0===(h=document.head.querySelector('[rel="stylesheet"],style'))?document.head.appendChild(A):document.head.insertBefore(A,h),A.sheet.insertRule(".anchorjs-link{opacity:0;text-decoration:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}",A.sheet.cssRules.length),A.sheet.insertRule(":hover>.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i<e.length;i++)if(this.hasAnchorJSLink(e[i]))p.push(i);else{if(e[i].hasAttribute("id"))o=e[i].getAttribute("id");else if(e[i].hasAttribute("data-anchor-id"))o=e[i].getAttribute("data-anchor-id");else{for(r=a=this.urlify(e[i].textContent),s=0;n=t.indexOf(r=void 0!==n?a+"-"+s:r),s+=1,-1!==n;);n=void 0,t.push(r),e[i].setAttribute("id",r),o=r}(l=document.createElement("a")).className="anchorjs-link "+this.options.class,l.setAttribute("aria-label",this.options.ariaLabel),l.setAttribute("data-anchorjs-icon",this.options.icon),this.options.titleText&&(l.title=this.options.titleText),c=document.querySelector("base")?window.location.pathname+window.location.search:"",c=this.options.base||c,l.href=c+"#"+o,"always"===this.options.visible&&(l.style.opacity="1"),""===this.options.icon&&(l.style.font="1em/1 anchorjs-icons","left"===this.options.placement)&&(l.style.lineHeight="inherit"),"left"===this.options.placement?(l.style.position="absolute",l.style.marginLeft="-1.25em",l.style.paddingRight=".25em",l.style.paddingLeft=".25em",e[i].insertBefore(l,e[i].firstChild)):(l.style.marginLeft=".1875em",l.style.paddingRight=".1875em",l.style.paddingLeft=".1875em",e[i].appendChild(l))}for(i=0;i<p.length;i++)e.splice(p[i]-i,1);this.elements=this.elements.concat(e)}return this},this.remove=function(A){for(var e,t,o=d(A),i=0;i<o.length;i++)(t=o[i].querySelector(".anchorjs-link"))&&(-1!==(e=this.elements.indexOf(o[i]))&&this.elements.splice(e,1),o[i].removeChild(t));return this},this.removeAll=function(){this.remove(this.elements)},this.urlify=function(A){var e=document.createElement("textarea");return e.innerHTML=A,A=e.value,this.options.truncate||u(this.options),A.trim().replace(/'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); |
There was a problem hiding this comment.
- Minor: 5.0.0 passes a bare
globalThisto its UMD wrapper here, unlike 1.1.1 (plain ES5) and our Bootstrap 5.0.2 bundle (which checkstypeof globalThis). On Chrome < 71, Firefox < 65 (including ESR 60), and Safari < 12.1, which Bootstrap 5.0.2's.browserslistrcstill lists, this line throwsReferenceError: globalThis is not defined. Thenglobal.html:206throwsanchors is not defined, and those browsers get no heading anchors at all. The rest of the page still works, because the config runs in its own<script>. These browsers have been out of support for years, so accepting this is fine with me. Could you mention it in the PR description, or addif (typeof globalThis === 'undefined') { window.globalThis = window; }before this script if you want to keep them working?
There was a problem hiding this comment.
Chrome < 71, Firefox < 65 (including ESR 60), and Safari < 12.1
These browser versions date to early 2019 at the latest. I don't think code changes to support them are merited. I will update the PR description.
| <script> | ||
| // Display anchor links when hovering over headings. | ||
| // See: https://www.bryanbraun.com/anchorjs/ | ||
| anchors.options = { placement: 'right' }; |
There was a problem hiding this comment.
- Minor: moving these lines out of
docs/js/main.jsalso takes them out of the lint check.dev/lint-jsruns ESLint (eslint:recommended, which includesno-undef) ondocs/jsonly, and nothing lintsdocs/_layouts. So a later typo here, such asanchros.add(...), would pass CI and silently remove the anchors from every page, while the same typo inmain.jsfailsno-undef(which is whymain.jsdeclared/* global $, anchors */). A separate ready handler inmain.jskeeps both the lint check and the isolation you get from a separate script, because jQuery 3.7.1 runs each ready handler in its own promise chain, so an error in one does not skip the dropdown setup in the other:
$(function() {
anchors.options = { placement: 'right' };
anchors.add('h1, h2, h3, h4, h5, h6');
});Could you move the config back into main.js this way and restore /* global $, anchors */?
There was a problem hiding this comment.
We already include other libraries in global.html, like jQuery, MathJax, and DocSearch, which is why I moved AnchorJS there. I think the correct fix here is in a follow-up PR to add HTML linting via eslint-plugin-html.
| // Copyright (c) 2023 Bryan Braun; Licensed MIT | ||
| // | ||
| // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat | ||
| !function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(globalThis,function(){"use strict";return function(A){function u(A){A.icon=Object.prototype.hasOwnProperty.call(A,"icon")?A.icon:"",A.visible=Object.prototype.hasOwnProperty.call(A,"visible")?A.visible:"hover",A.placement=Object.prototype.hasOwnProperty.call(A,"placement")?A.placement:"right",A.ariaLabel=Object.prototype.hasOwnProperty.call(A,"ariaLabel")?A.ariaLabel:"Anchor",A.class=Object.prototype.hasOwnProperty.call(A,"class")?A.class:"",A.base=Object.prototype.hasOwnProperty.call(A,"base")?A.base:"",A.truncate=Object.prototype.hasOwnProperty.call(A,"truncate")?Math.floor(A.truncate):64,A.titleText=Object.prototype.hasOwnProperty.call(A,"titleText")?A.titleText:""}function d(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new TypeError("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],u(this.options),this.add=function(A){var e,t,o,i,n,s,a,r,l,c,h,p=[];if(u(this.options),0!==(e=d(A=A||"h2, h3, h4, h5, h6")).length){for(null===document.head.querySelector("style.anchorjs")&&((A=document.createElement("style")).className="anchorjs",A.appendChild(document.createTextNode("")),void 0===(h=document.head.querySelector('[rel="stylesheet"],style'))?document.head.appendChild(A):document.head.insertBefore(A,h),A.sheet.insertRule(".anchorjs-link{opacity:0;text-decoration:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}",A.sheet.cssRules.length),A.sheet.insertRule(":hover>.anchorjs-link,.anchorjs-link:focus{opacity:1}",A.sheet.cssRules.length),A.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",A.sheet.cssRules.length),A.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',A.sheet.cssRules.length)),h=document.querySelectorAll("[id]"),t=[].map.call(h,function(A){return A.id}),i=0;i<e.length;i++)if(this.hasAnchorJSLink(e[i]))p.push(i);else{if(e[i].hasAttribute("id"))o=e[i].getAttribute("id");else if(e[i].hasAttribute("data-anchor-id"))o=e[i].getAttribute("data-anchor-id");else{for(r=a=this.urlify(e[i].textContent),s=0;n=t.indexOf(r=void 0!==n?a+"-"+s:r),s+=1,-1!==n;);n=void 0,t.push(r),e[i].setAttribute("id",r),o=r}(l=document.createElement("a")).className="anchorjs-link "+this.options.class,l.setAttribute("aria-label",this.options.ariaLabel),l.setAttribute("data-anchorjs-icon",this.options.icon),this.options.titleText&&(l.title=this.options.titleText),c=document.querySelector("base")?window.location.pathname+window.location.search:"",c=this.options.base||c,l.href=c+"#"+o,"always"===this.options.visible&&(l.style.opacity="1"),""===this.options.icon&&(l.style.font="1em/1 anchorjs-icons","left"===this.options.placement)&&(l.style.lineHeight="inherit"),"left"===this.options.placement?(l.style.position="absolute",l.style.marginLeft="-1.25em",l.style.paddingRight=".25em",l.style.paddingLeft=".25em",e[i].insertBefore(l,e[i].firstChild)):(l.style.marginLeft=".1875em",l.style.paddingRight=".1875em",l.style.paddingLeft=".1875em",e[i].appendChild(l))}for(i=0;i<p.length;i++)e.splice(p[i]-i,1);this.elements=this.elements.concat(e)}return this},this.remove=function(A){for(var e,t,o=d(A),i=0;i<o.length;i++)(t=o[i].querySelector(".anchorjs-link"))&&(-1!==(e=this.elements.indexOf(o[i]))&&this.elements.splice(e,1),o[i].removeChild(t));return this},this.removeAll=function(){this.remove(this.elements)},this.urlify=function(A){var e=document.createElement("textarea");return e.innerHTML=A,A=e.value,this.options.truncate||u(this.options),A.trim().replace(/'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); |
There was a problem hiding this comment.
- Nit: FYI, 5.0.0's
add()callsdocument.querySelector('base')inside its per-heading loop (anchor.jsL140 at tag 5.0.0). Our pages have no<base>, so each heading triggers a scan of the whole document. On the largest page,sql-ref-functions-builtin.html(about 1.5 MB, ~48K elements, 48 headings), that is about 48 extra scans during parsing. I have not measured it, but it should be a few milliseconds. Nothing to change here, since this file should stay identical to upstream. Could it be worth an upstream issue to move that query out of the loop?
There was a problem hiding this comment.
I haven't looked into this. I think a future, dedicated performance analysis of the website would likely find higher-impact improvements we could make. At that time, we can pursue upstream fixes as needed.
| }; | ||
| anchors.add(); | ||
|
|
||
| // Make dropdown menus in nav bars show on hover instead of click |
There was a problem hiding this comment.
- Nit: this is pre-existing and outside this PR. The dropdown block below (L100-L119) calls
$dropdown.hover(...)again on everyloadorresizeevent at 768px or wider, without unbinding the previous handlers. jQuery'shover()is just.on("mouseenter", ...).on("mouseleave", ...), so the handlers pile up until the window becomes narrower than 768px. They are idempotent, so this only wastes work. The 768px threshold also differs from the navbar'snavbar-expand-lgbreakpoint (992px). This dates from SPARK-30654. Could$dropdown.off("mouseenter mouseleave").hover(...)go into a small follow-up?
Done.
I think I've submitted #59666 for our PR template to match ASF's guidance in suggesting |
What changes were proposed in this pull request?
Upgrade AnchorJS to v5.0.0, and update its config accordingly to maintain roughly the current production behavior.
Additionally:
global.html, which matches where we include and configure other vendored libraries.anchorsglobal frommain.js, which is no longer needed now that the config is handled outside of there.Why are the changes needed?
The current version of AnchorJS we are using is more than 11 years old. The releases since then have added more accessible heading links and more reliable fragment generation.
This upgrade will also keep the versions in sync with the main website's version of AnchorJS: apache/spark-website#700
Any browser released since early 2021 should support this new version without issue.
Does this PR introduce any user-facing change?
No, documentation behavior tweaks only.
How was this patch tested?
I built and reviewed the site locally with
SKIP_API=1 bundle exec jekyll serve. Confirmed that anchors work as expected, including forh1headings.Was this patch authored or co-authored using generative AI tooling?
Co-authored-by: GitHub Copilot