commit ec7a725c1131327d995f42981444f69deaf80ca2 Author: Anthony Hughes Date: Sun Feb 8 21:44:05 2026 +0000 Initial commit diff --git a/404.html b/404.html new file mode 100644 index 0000000..e003cf4 --- /dev/null +++ b/404.html @@ -0,0 +1,417 @@ + + + + + + Notchee + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + +
+ +
+
+

Notchee #1: Good Governance

+

+

Four square heads look on suspiciously at another square head with rounded corners.

+

Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities

+
+
+

F =

+
+
+
+ + +

Content not found.

+

Go home.

+ + + + + +
+
+ + + + + + + diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000..6644433 --- /dev/null +++ b/about/index.html @@ -0,0 +1,405 @@ + + + + + + Notchee + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + +
+ +
+
+

Notchee #1: Good Governance

+

+

Four square heads look on suspiciously at another square head with rounded corners.

+

Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities

+
+
+

F =

+
+
+
+ + +

About

+

I am a person that writes stuff.

+ + + + +
+
+ + + + + + + diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 0000000..a77f8ee --- /dev/null +++ b/blog/index.html @@ -0,0 +1,413 @@ + + + + + + Notchee + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + +
+ +
+
+

Notchee #1: Good Governance

+

+

Four square heads look on suspiciously at another square head with rounded corners.

+

Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities

+
+
+

F =

+
+
+
+ + +

Archive

+ + +
    +
  1. + Notchee #1: Good Governance + +
  2. +
+ + + + + +
+
+ + + + + + + diff --git a/blog/notchee001/2O9wlKzLwf-1984.avif b/blog/notchee001/2O9wlKzLwf-1984.avif new file mode 100644 index 0000000..1698013 Binary files /dev/null and b/blog/notchee001/2O9wlKzLwf-1984.avif differ diff --git a/blog/notchee001/2O9wlKzLwf-1984.jpeg b/blog/notchee001/2O9wlKzLwf-1984.jpeg new file mode 100644 index 0000000..bd6ba7f Binary files /dev/null and b/blog/notchee001/2O9wlKzLwf-1984.jpeg differ diff --git a/blog/notchee001/2O9wlKzLwf-1984.webp b/blog/notchee001/2O9wlKzLwf-1984.webp new file mode 100644 index 0000000..dd18e43 Binary files /dev/null and b/blog/notchee001/2O9wlKzLwf-1984.webp differ diff --git a/blog/notchee001/index.html b/blog/notchee001/index.html new file mode 100644 index 0000000..a876716 --- /dev/null +++ b/blog/notchee001/index.html @@ -0,0 +1,556 @@ + + + + + + Notchee #1 + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + + +

Notchee #1: Good Governance

+

+ + + + +

Four square heads look on suspiciously at another square head with rounded corners.

+

+Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities +

+ +
+

F =

+
+ + + + + + +
+
+ + + + + + + diff --git a/blog/notchee001/uOBi7x7dUh-1871.avif b/blog/notchee001/uOBi7x7dUh-1871.avif new file mode 100644 index 0000000..9dd6f04 Binary files /dev/null and b/blog/notchee001/uOBi7x7dUh-1871.avif differ diff --git a/blog/notchee001/uOBi7x7dUh-1871.jpeg b/blog/notchee001/uOBi7x7dUh-1871.jpeg new file mode 100644 index 0000000..68ceca7 Binary files /dev/null and b/blog/notchee001/uOBi7x7dUh-1871.jpeg differ diff --git a/blog/notchee001/uOBi7x7dUh-1871.webp b/blog/notchee001/uOBi7x7dUh-1871.webp new file mode 100644 index 0000000..2271ce3 Binary files /dev/null and b/blog/notchee001/uOBi7x7dUh-1871.webp differ diff --git a/bundle.js b/bundle.js new file mode 100644 index 0000000..d3d4b14 --- /dev/null +++ b/bundle.js @@ -0,0 +1,10 @@ +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + diff --git a/content/feed/pretty-atom-feed.xsl b/content/feed/pretty-atom-feed.xsl new file mode 100644 index 0000000..6a1c4de --- /dev/null +++ b/content/feed/pretty-atom-feed.xsl @@ -0,0 +1,89 @@ + + + + + + + + <xsl:value-of select="atom:feed/atom:title"/> + + + + + + +
+
+

+ + + + + + + + + + + + + + + + + + + Web Feed Preview +

+

+

+

This preview only shows titles, but the actual feed contains the full content.

+ + + + + Visit Website → + +
+

Recent Items

+ +
+ + +
+ +
+

+ + + + + + +

+ + Published: + +
+
+
diff --git a/dist/0q5GqSX7mC.js b/dist/0q5GqSX7mC.js new file mode 100644 index 0000000..48eae47 --- /dev/null +++ b/dist/0q5GqSX7mC.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/1c3PUgvo-U.js b/dist/1c3PUgvo-U.js new file mode 100644 index 0000000..716af4d --- /dev/null +++ b/dist/1c3PUgvo-U.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 2; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/5D6kdO0bmj.js b/dist/5D6kdO0bmj.js new file mode 100644 index 0000000..ff63d0b --- /dev/null +++ b/dist/5D6kdO0bmj.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = "${n}"; + document.getElementById("fib_num").textContent = "${result}"; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/5jPJNnHVHc.js b/dist/5jPJNnHVHc.js new file mode 100644 index 0000000..ae2f55c --- /dev/null +++ b/dist/5jPJNnHVHc.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 8; // Example: change this number or get it dynamically + const result = fib(n-1); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/8XCmg52eCu.js b/dist/8XCmg52eCu.js new file mode 100644 index 0000000..95b5c57 --- /dev/null +++ b/dist/8XCmg52eCu.js @@ -0,0 +1,232 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = fib(1); \ No newline at end of file diff --git a/dist/8jwLSGQpSi.js b/dist/8jwLSGQpSi.js new file mode 100644 index 0000000..b85ee69 --- /dev/null +++ b/dist/8jwLSGQpSi.js @@ -0,0 +1,249 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = fib(1) { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; + }; \ No newline at end of file diff --git a/dist/8touSeoYz_.js b/dist/8touSeoYz_.js new file mode 100644 index 0000000..7d0d570 --- /dev/null +++ b/dist/8touSeoYz_.js @@ -0,0 +1,249 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/B8sDgsMUsD.js b/dist/B8sDgsMUsD.js new file mode 100644 index 0000000..830c06d --- /dev/null +++ b/dist/B8sDgsMUsD.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/EtgvdWNsiS.js b/dist/EtgvdWNsiS.js new file mode 100644 index 0000000..8f96ca1 --- /dev/null +++ b/dist/EtgvdWNsiS.js @@ -0,0 +1,249 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/FiU03Pf7Pn.js b/dist/FiU03Pf7Pn.js new file mode 100644 index 0000000..da4a3fe --- /dev/null +++ b/dist/FiU03Pf7Pn.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 4; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/I8MnV9ZEzM.js b/dist/I8MnV9ZEzM.js new file mode 100644 index 0000000..a00f521 --- /dev/null +++ b/dist/I8MnV9ZEzM.js @@ -0,0 +1,236 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/IRg55wT5QS.js b/dist/IRg55wT5QS.js new file mode 100644 index 0000000..e8bb4e6 --- /dev/null +++ b/dist/IRg55wT5QS.js @@ -0,0 +1,246 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F${n} = ${result}`; + }; \ No newline at end of file diff --git a/dist/JYf_9DlK1Z.js b/dist/JYf_9DlK1Z.js new file mode 100644 index 0000000..57f67cb --- /dev/null +++ b/dist/JYf_9DlK1Z.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n-1); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/KulkScvkSc.js b/dist/KulkScvkSc.js new file mode 100644 index 0000000..1d3614b --- /dev/null +++ b/dist/KulkScvkSc.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + }; \ No newline at end of file diff --git a/dist/LMRliuEw15.js b/dist/LMRliuEw15.js new file mode 100644 index 0000000..7798fad --- /dev/null +++ b/dist/LMRliuEw15.js @@ -0,0 +1,246 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/Lj0TJmfSgz.js b/dist/Lj0TJmfSgz.js new file mode 100644 index 0000000..e7f1a06 --- /dev/null +++ b/dist/Lj0TJmfSgz.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 5; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/MwbreJDqDS.js b/dist/MwbreJDqDS.js new file mode 100644 index 0000000..0e147c9 --- /dev/null +++ b/dist/MwbreJDqDS.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci + function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; + } + + // Run on page load + window.onload = function() { + const n = 10; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/N1XsrSkSKU.js b/dist/N1XsrSkSKU.js new file mode 100644 index 0000000..4144a5a --- /dev/null +++ b/dist/N1XsrSkSKU.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 8; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/QJCUSo7_oL.js b/dist/QJCUSo7_oL.js new file mode 100644 index 0000000..56304c7 --- /dev/null +++ b/dist/QJCUSo7_oL.js @@ -0,0 +1,246 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/UWIeyGsVja.js b/dist/UWIeyGsVja.js new file mode 100644 index 0000000..fcb009b --- /dev/null +++ b/dist/UWIeyGsVja.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/Vqt3TRrqGx.js b/dist/Vqt3TRrqGx.js new file mode 100644 index 0000000..033f651 --- /dev/null +++ b/dist/Vqt3TRrqGx.js @@ -0,0 +1,246 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/YZd7GbE6Kh.js b/dist/YZd7GbE6Kh.js new file mode 100644 index 0000000..0dcb0bc --- /dev/null +++ b/dist/YZd7GbE6Kh.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 5; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/YuGBzgYfsj.js b/dist/YuGBzgYfsj.js new file mode 100644 index 0000000..b1ffb7d --- /dev/null +++ b/dist/YuGBzgYfsj.js @@ -0,0 +1,236 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = ; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/_gbQ9z1H4C.js b/dist/_gbQ9z1H4C.js new file mode 100644 index 0000000..1d5d34a --- /dev/null +++ b/dist/_gbQ9z1H4C.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 2; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/bUsipRFsvJ.js b/dist/bUsipRFsvJ.js new file mode 100644 index 0000000..703e4b8 --- /dev/null +++ b/dist/bUsipRFsvJ.js @@ -0,0 +1,234 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + fib(1); + }; \ No newline at end of file diff --git a/dist/bXca3JBF0E.js b/dist/bXca3JBF0E.js new file mode 100644 index 0000000..1343e4d --- /dev/null +++ b/dist/bXca3JBF0E.js @@ -0,0 +1,236 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/cC8wS6ZjFU.js b/dist/cC8wS6ZjFU.js new file mode 100644 index 0000000..68efbdb --- /dev/null +++ b/dist/cC8wS6ZjFU.js @@ -0,0 +1,231 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } \ No newline at end of file diff --git a/dist/cddc0j585S.js b/dist/cddc0j585S.js new file mode 100644 index 0000000..1e26e05 --- /dev/null +++ b/dist/cddc0j585S.js @@ -0,0 +1,233 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +

1

+ window.onload = fib(1); \ No newline at end of file diff --git a/dist/eKalzsYoRS.js b/dist/eKalzsYoRS.js new file mode 100644 index 0000000..6f7ec00 --- /dev/null +++ b/dist/eKalzsYoRS.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 8; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/fqsEuG6ZcE.js b/dist/fqsEuG6ZcE.js new file mode 100644 index 0000000..d0b33f2 --- /dev/null +++ b/dist/fqsEuG6ZcE.js @@ -0,0 +1,237 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/gi1CLnzG-d.js b/dist/gi1CLnzG-d.js new file mode 100644 index 0000000..1d7608e --- /dev/null +++ b/dist/gi1CLnzG-d.js @@ -0,0 +1,236 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 10; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/gjkXJxzy_W.js b/dist/gjkXJxzy_W.js new file mode 100644 index 0000000..9a78308 --- /dev/null +++ b/dist/gjkXJxzy_W.js @@ -0,0 +1,244 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = fib(1); \ No newline at end of file diff --git a/dist/iKirDyD45_.js b/dist/iKirDyD45_.js new file mode 100644 index 0000000..48e28e1 --- /dev/null +++ b/dist/iKirDyD45_.js @@ -0,0 +1,237 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 8; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/iuKmc0VMzy.js b/dist/iuKmc0VMzy.js new file mode 100644 index 0000000..677f4cf --- /dev/null +++ b/dist/iuKmc0VMzy.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci + function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; + } + + // Run on page load + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/ix_Ybx5UAh.js b/dist/ix_Ybx5UAh.js new file mode 100644 index 0000000..2ab2f62 --- /dev/null +++ b/dist/ix_Ybx5UAh.js @@ -0,0 +1,237 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = ; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/k7YWH9wzXb.js b/dist/k7YWH9wzXb.js new file mode 100644 index 0000000..c072cad --- /dev/null +++ b/dist/k7YWH9wzXb.js @@ -0,0 +1,237 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; + }; \ No newline at end of file diff --git a/dist/ldcr_VJC1Q.js b/dist/ldcr_VJC1Q.js new file mode 100644 index 0000000..229e0c0 --- /dev/null +++ b/dist/ldcr_VJC1Q.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/mH8Ns4hbWV.js b/dist/mH8Ns4hbWV.js new file mode 100644 index 0000000..3155607 --- /dev/null +++ b/dist/mH8Ns4hbWV.js @@ -0,0 +1,233 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +

1

+ window.onload = fib(1); \ No newline at end of file diff --git a/dist/pK5dGeN6cR.js b/dist/pK5dGeN6cR.js new file mode 100644 index 0000000..fdfd1ea --- /dev/null +++ b/dist/pK5dGeN6cR.js @@ -0,0 +1,235 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +

1

+ window.onload = function() { + fib(1); + }; \ No newline at end of file diff --git a/dist/uqzqyPsa5S.js b/dist/uqzqyPsa5S.js new file mode 100644 index 0000000..f3793c9 --- /dev/null +++ b/dist/uqzqyPsa5S.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/uteBBWdAf7.js b/dist/uteBBWdAf7.js new file mode 100644 index 0000000..58c47d1 --- /dev/null +++ b/dist/uteBBWdAf7.js @@ -0,0 +1,237 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +window.onload = function() { + const n = 10; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/wbPsFzqn9h.js b/dist/wbPsFzqn9h.js new file mode 100644 index 0000000..41175bd --- /dev/null +++ b/dist/wbPsFzqn9h.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + window.onload = function() { + const n = 1; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; // Doesn't render properly on mobile; figure out subscript numbers... + }; \ No newline at end of file diff --git a/dist/xtOprDpcek.js b/dist/xtOprDpcek.js new file mode 100644 index 0000000..513ab79 --- /dev/null +++ b/dist/xtOprDpcek.js @@ -0,0 +1,247 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + return b; +} + + + window.onload = function() { + const n = 4; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/dist/ytDKgl3ZR7.js b/dist/ytDKgl3ZR7.js new file mode 100644 index 0000000..f81a88b --- /dev/null +++ b/dist/ytDKgl3ZR7.js @@ -0,0 +1,248 @@ +// Thank you to https://github.com/daviddarnes/heading-anchors +// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + +let globalInstanceIndex = 0; + +class HeadingAnchors extends HTMLElement { + static register(tagName = "heading-anchors", registry = window.customElements) { + if(registry && !registry.get(tagName)) { + registry.define(tagName, this); + } + } + + static attributes = { + exclude: "data-ha-exclude", + prefix: "prefix", + content: "content", + } + + static classes = { + anchor: "ha", + placeholder: "ha-placeholder", + srOnly: "ha-visualhide", + } + + static defaultSelector = "h2,h3,h4,h5,h6"; + + static css = ` +.${HeadingAnchors.classes.srOnly} { + clip: rect(0 0 0 0); + height: 1px; + overflow: hidden; + position: absolute; + width: 1px; +} +.${HeadingAnchors.classes.anchor} { + position: absolute; + left: var(--ha_offsetx); + top: var(--ha_offsety); + text-decoration: none; + opacity: 0; +} +.${HeadingAnchors.classes.placeholder} { + opacity: .3; +} +.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) { + opacity: 1; +} +.${HeadingAnchors.classes.anchor}, +.${HeadingAnchors.classes.placeholder} { + display: inline-block; + padding: 0 .25em; + + /* Disable selection of visually hidden label */ + -webkit-user-select: none; + user-select: none; +} + +@supports (anchor-name: none) { + .${HeadingAnchors.classes.anchor} { + position: absolute; + left: anchor(left); + top: anchor(top); + } +}`; + + get supports() { + return "replaceSync" in CSSStyleSheet.prototype; + } + + get supportsAnchorPosition() { + return CSS.supports("anchor-name: none"); + } + + constructor() { + super(); + + if(!this.supports) { + return; + } + + let sheet = new CSSStyleSheet(); + sheet.replaceSync(HeadingAnchors.css); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; + + this.headingStyles = {}; + this.instanceIndex = globalInstanceIndex++; + } + + connectedCallback() { + if (!this.supports) { + return; + } + + this.headings.forEach((heading, index) => { + if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) { + let anchor = this.getAnchorElement(heading); + let placeholder = this.getPlaceholderElement(); + + // Prefers anchor position approach for better accessibility + // https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/ + if(this.supportsAnchorPosition) { + let anchorName = `--ha_${this.instanceIndex}_${index}`; + placeholder.style.setProperty("anchor-name", anchorName); + anchor.style.positionAnchor = anchorName; + } + + heading.appendChild(placeholder); + heading.after(anchor); + } + }); + } + + // Polyfill-only + positionAnchorFromPlaceholder(placeholder) { + if(!placeholder) { + return; + } + + let heading = placeholder.closest("h1,h2,h3,h4,h5,h6"); + if(!heading.nextElementSibling) { + return; + } + + // TODO next element could be more defensive + this.positionAnchor(heading.nextElementSibling); + } + + // Polyfill-only + positionAnchor(anchor) { + if(!anchor || !anchor.previousElementSibling) { + return; + } + + // TODO previous element could be more defensive + let heading = anchor.previousElementSibling; + this.setFontProp(heading, anchor); + + if(this.supportsAnchorPosition) { + // quit early + return; + } + + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`); + anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`); + } + } + + setFontProp(heading, anchor) { + let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + let style = getComputedStyle(placeholder); + let props = ["font-weight", "font-size", "line-height", "font-family"]; + let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name)); + anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`); + let vars = style.getPropertyValue("font-variation-settings"); + if(vars) { + anchor.style.setProperty("font-variation-settings", vars); + } + } + } + + getAccessibleTextPrefix() { + // Useful for i18n + return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled"; + } + + getContent() { + if(this.hasAttribute(HeadingAnchors.attributes.content)) { + return this.getAttribute(HeadingAnchors.attributes.content); + } + return "#"; + } + + // Placeholder nests inside of heading + getPlaceholderElement() { + let ph = document.createElement("span"); + ph.setAttribute("aria-hidden", true); + ph.classList.add(HeadingAnchors.classes.placeholder); + let content = this.getContent(); + if(content) { + ph.textContent = content; + } + + ph.addEventListener("mouseover", (e) => { + let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`); + if(placeholder) { + this.positionAnchorFromPlaceholder(placeholder); + } + }); + + return ph; + } + + getAnchorElement(heading) { + let anchor = document.createElement("a"); + anchor.href = `#${heading.id}`; + anchor.classList.add(HeadingAnchors.classes.anchor); + + let content = this.getContent(); + anchor.innerHTML = `${this.getAccessibleTextPrefix()}: ${heading.textContent}${content ? `` : ""}`; + + anchor.addEventListener("focus", e => { + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + if(anchor) { + this.positionAnchor(anchor); + } + }); + + anchor.addEventListener("mouseover", (e) => { + // when CSS anchor positioning is supported, this is only used to set the font + let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`); + this.positionAnchor(anchor); + }); + + return anchor; + } + + get headings() { + return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`)); + } + + get selector() { + return this.getAttribute("selector") || HeadingAnchors.defaultSelector; + } +} + +HeadingAnchors.register(); + +export { HeadingAnchors } +// Efficient iterative Fibonacci +function fib(n) { + if (n < 2) return n; + let a = 0, b = 1; + for (let i = 2; i <= n; i++) { + [a, b] = [b, a + b]; + } + document.getElementById("fib_seq").textContent = n; + document.getElementById("fib_num").textContent = result; +} + + + window.onload = function() { + const n = 3; // Example: change this number or get it dynamically + const result = fib(n); + document.getElementById("fib").textContent = `F(${n}) = ${result}`; + }; \ No newline at end of file diff --git a/feed/feed.xml b/feed/feed.xml new file mode 100644 index 0000000..156dc3c --- /dev/null +++ b/feed/feed.xml @@ -0,0 +1,23 @@ + + + + Blog Title + This is a longer description about your blog. + + + 2025-10-24T00:00:00Z + https://example.com/ + + Your Name + + + Notchee #1 + + 2025-10-24T00:00:00Z + https://example.com/blog/notchee001/ + <p><picture><source type="image/avif" srcset="https://example.com/blog/notchee001/uOBi7x7dUh-1871.avif 1871w"><source type="image/webp" srcset="https://example.com/blog/notchee001/uOBi7x7dUh-1871.webp 1871w"><img loading="lazy" decoding="async" src="https://example.com/blog/notchee001/uOBi7x7dUh-1871.jpeg" alt="Four square heads look on suspiciously at another square head with rounded corners." width="1871" height="1171"></picture></p> +<p style="text-align:center;"><em> +Gary&#39;s new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities +</em></p> + + \ No newline at end of file diff --git a/feed/pretty-atom-feed.xsl b/feed/pretty-atom-feed.xsl new file mode 100644 index 0000000..6a1c4de --- /dev/null +++ b/feed/pretty-atom-feed.xsl @@ -0,0 +1,89 @@ + + + + + + + + <xsl:value-of select="atom:feed/atom:title"/> + + + + + + +
+
+

+ + + + + + + + + + + + + + + + + + + Web Feed Preview +

+

+

+

This preview only shows titles, but the actual feed contains the full content.

+ + + + + Visit Website → + +
+

Recent Items

+ +
+ + +
+ +
+

+ + + + + + +

+ + Published: + +
+
+
diff --git a/img/.gitkeep b/img/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/img/2O9wlKzLwf-1984.avif b/img/2O9wlKzLwf-1984.avif new file mode 100644 index 0000000..1698013 Binary files /dev/null and b/img/2O9wlKzLwf-1984.avif differ diff --git a/img/2O9wlKzLwf-1984.jpeg b/img/2O9wlKzLwf-1984.jpeg new file mode 100644 index 0000000..bd6ba7f Binary files /dev/null and b/img/2O9wlKzLwf-1984.jpeg differ diff --git a/img/2O9wlKzLwf-1984.webp b/img/2O9wlKzLwf-1984.webp new file mode 100644 index 0000000..dd18e43 Binary files /dev/null and b/img/2O9wlKzLwf-1984.webp differ diff --git a/img/eCT5mOL4LD-60.avif b/img/eCT5mOL4LD-60.avif new file mode 100644 index 0000000..1fb020e Binary files /dev/null and b/img/eCT5mOL4LD-60.avif differ diff --git a/img/eCT5mOL4LD-60.jpeg b/img/eCT5mOL4LD-60.jpeg new file mode 100644 index 0000000..1d475fb Binary files /dev/null and b/img/eCT5mOL4LD-60.jpeg differ diff --git a/img/eCT5mOL4LD-60.webp b/img/eCT5mOL4LD-60.webp new file mode 100644 index 0000000..393c0fc Binary files /dev/null and b/img/eCT5mOL4LD-60.webp differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000..c2ff875 Binary files /dev/null and b/img/logo.png differ diff --git a/img/notchee-logo.jpg b/img/notchee-logo.jpg new file mode 100644 index 0000000..8a3e3f5 Binary files /dev/null and b/img/notchee-logo.jpg differ diff --git a/img/uOBi7x7dUh-1871.avif b/img/uOBi7x7dUh-1871.avif new file mode 100644 index 0000000..9dd6f04 Binary files /dev/null and b/img/uOBi7x7dUh-1871.avif differ diff --git a/img/uOBi7x7dUh-1871.jpeg b/img/uOBi7x7dUh-1871.jpeg new file mode 100644 index 0000000..68ceca7 Binary files /dev/null and b/img/uOBi7x7dUh-1871.jpeg differ diff --git a/img/uOBi7x7dUh-1871.webp b/img/uOBi7x7dUh-1871.webp new file mode 100644 index 0000000..2271ce3 Binary files /dev/null and b/img/uOBi7x7dUh-1871.webp differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..e2a9260 --- /dev/null +++ b/index.html @@ -0,0 +1,422 @@ + + + + + + Notchee + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + +
+ +
+
+

Notchee #1: Good Governance

+

+

Four square heads look on suspiciously at another square head with rounded corners.

+

Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities

+
+
+

F =

+
+
+
+ + + + +

Archive

+ + + +
    +
  1. + Notchee #1: Good Governance + +
  2. +
+ + + + + + + + + + + +
+
+ + + + + + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..e8d22fd --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,45 @@ + + + + + + https://notchee.art/blog/notchee001/ + 2025-10-24 + + + + + + https://notchee.art/about/ + 2025-10-25 + + + + + + https://notchee.art/blog/ + 2025-10-25 + + + + + + https://notchee.art/ + 2025-10-25 + + + + + + https://notchee.art/tags/ + 2025-10-25 + + + + + + https://notchee.art/feed/feed.xml + 2025-10-26 + + + diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000..2521dbe --- /dev/null +++ b/tags/index.html @@ -0,0 +1,408 @@ + + + + + + Notchee + + + + + + + + + + + + + +
+ + notchee logo Notchee + +
+ +
+ + + +
+ +
+
+

Notchee #1: Good Governance

+

+

Four square heads look on suspiciously at another square head with rounded corners.

+

Gary's new haircut manages to completely derail the meeting of the Society Questioning UnApproved Rounded Entities

+
+
+

F =

+
+
+
+ + +

Tags

+ +
    + +
+ + + + +
+
+ + + + + + +