Latest build deployed.

This commit is contained in:
2026-08-01 15:00:14 +00:00
parent e43fb0d0ff
commit 331f133dfe
1278 changed files with 19041 additions and 18362 deletions
Executable → Regular
+88 -21
View File
@@ -39,15 +39,44 @@ class SlideRevealer {
// mid animation state tracking
this.animation = null;
this.animationState = SlideRevealer.STATE.INACTIVE;
this.animatedElementInlineStyle = null;
this.triggerElement.addEventListener('click', (e) => this.onClick(e));
}
isBusy() {
return this.animationState !== SlideRevealer.STATE.INACTIVE || this.animatedElementInlineStyle !== null;
}
storeAnimatedElementInlineStyle() {
if (this.animatedElementInlineStyle !== null) return;
this.animatedElementInlineStyle = {
overflow: this.animatedElement.style.overflow,
height: this.animatedElement.style.height,
paddingTop: this.animatedElement.style.paddingTop,
paddingBottom: this.animatedElement.style.paddingBottom
};
}
restoreAnimatedElementInlineStyle() {
if (this.animatedElementInlineStyle === null) return;
this.animatedElement.style.overflow = this.animatedElementInlineStyle.overflow;
this.animatedElement.style.height = this.animatedElementInlineStyle.height;
this.animatedElement.style.paddingTop = this.animatedElementInlineStyle.paddingTop;
this.animatedElement.style.paddingBottom = this.animatedElementInlineStyle.paddingBottom;
this.animatedElementInlineStyle = null;
}
onClick(e) {
// Stop default behavior from the browser
if (e) e.preventDefault();
if (this.isBusy()) return;
// Add an overflow on the <details> to avoid content overflowing
this.storeAnimatedElementInlineStyle();
this.animatedElement.style.overflow = 'hidden';
// Check if the element is being closed or is already closed
@@ -56,29 +85,57 @@ class SlideRevealer {
this.animatedElement.setAttribute("open","");
this.triggerElement.setAttribute("open","");
this.contentElement.style.display = '';
// Trigger the animation to expand or collapse the knowl.
// Delay the MathJax typesetting until the knowl is visible to ensure proper measurements
// are taken, but before the unrolling begins. This helps avoid layout shifts and ensures
// smooth animation with correctly sized content.
MathJax.typesetPromise().then(() => window.requestAnimationFrame(() => this.toggle(true)));
this.contentElement.style.visibility = 'hidden';
let closedHeight = 0;
if (this.animatedElement.contains(this.triggerElement))
closedHeight = this.triggerElement.offsetHeight;
const naturalStyle = window.getComputedStyle(this.animatedElement);
const naturalPaddingTop = naturalStyle.paddingTop;
const naturalPaddingBottom = naturalStyle.paddingBottom;
this.animatedElement.style.height = `${closedHeight}px`;
this.animatedElement.style.paddingTop = '0px';
this.animatedElement.style.paddingBottom = '0px';
// Trigger the animation to expand or collapse the knowl
// We assume content is already rendered and size is accurate.
// If not, there may be a jump at the end of the animation when styles are cleared
const expandingMeasurements = {
fullHeight: this.contentElement === this.animatedElement
? this.contentElement.scrollHeight
: closedHeight + this.contentElement.offsetHeight,
paddingTop: naturalPaddingTop,
paddingBottom: naturalPaddingBottom
};
this.contentElement.style.visibility = '';
this.toggle(true, expandingMeasurements);
} else if (this.animationState === SlideRevealer.STATE.EXPANDING || this.animatedElement.hasAttribute("open")) {
this.toggle(false);
}
}
toggle(expanding) {
toggle(expanding, expandingMeasurements = null) {
let closedHeight = 0;
if (this.animatedElement.contains(this.triggerElement))
closedHeight = this.triggerElement.offsetHeight;
const fullHeight = closedHeight + this.contentElement.offsetHeight;
const startHeight = `${expanding ? closedHeight : fullHeight}px`;
const computedStyle = window.getComputedStyle(this.animatedElement);
const fullHeight = expandingMeasurements?.fullHeight ?? closedHeight + this.contentElement.offsetHeight;
const startHeight = `${expanding ? closedHeight : this.animatedElement.offsetHeight}px`;
const endHeight = `${expanding ? fullHeight : closedHeight}px`;
// Need to animate padding to avoid extra height for xref knowls
const padding = this.animatedElement.offsetHeight - this.animatedElement.clientHeight;
const startPad = `${expanding ? 0 : padding}px`;
const endPad = `${expanding ? padding : 0}px`;
const currentPaddingTop = computedStyle.paddingTop;
const currentPaddingBottom = computedStyle.paddingBottom;
const endPaddingTop = expandingMeasurements?.paddingTop ?? currentPaddingTop;
const endPaddingBottom = expandingMeasurements?.paddingBottom ?? currentPaddingBottom;
const startPadTop = expanding ? '0px' : currentPaddingTop;
const endPadTop = expanding ? endPaddingTop : '0px';
const startPadBottom = expanding ? '0px' : currentPaddingBottom;
const endPadBottom = expanding ? endPaddingBottom : '0px';
// Cancel any existing animation
if (this.animation) {
@@ -92,15 +149,18 @@ class SlideRevealer {
this.animationState = expanding ? SlideRevealer.STATE.EXPANDING : SlideRevealer.STATE.CLOSING;
this.animation = this.animatedElement.animate({
height: [startHeight, endHeight],
paddingTop: [startPad, endPad],
paddingBottom: [startPad, endPad]
paddingTop: [startPadTop, endPadTop],
paddingBottom: [startPadBottom, endPadBottom]
}, {
duration: animDuration,
easing: 'ease'
easing: 'ease-out'
});
this.animation.onfinish = () => { this.onAnimationFinish(expanding); };
this.animation.oncancel = () => { this.animationState = SlideRevealer.STATE.INACTIVE; };
this.animation.oncancel = () => {
this.animationState = SlideRevealer.STATE.INACTIVE;
this.restoreAnimatedElementInlineStyle();
};
}
onAnimationFinish(isOpen) {
@@ -115,9 +175,10 @@ class SlideRevealer {
}
// Clear styles used in animation
this.animatedElement.style.overflow = '';
this.restoreAnimatedElementInlineStyle();
if (!isOpen)
this.contentElement.style.display = 'none';
this.contentElement.style.visibility = '';
if (isOpen) {
let hasCallback = this.contentElement.querySelectorAll("[data-knowl-callback]");
@@ -148,6 +209,7 @@ class LinkKnowl {
constructor(knowlLinkElement) {
this.linkElement = knowlLinkElement;
this.outputElement = null;
this.slideHandler = null;
this.uid = LinkKnowl.xrefCount++;
knowlLinkElement.setAttribute("data-knowl-uid", this.uid);
@@ -262,21 +324,25 @@ class LinkKnowl {
// prevent navigation
event.preventDefault();
if (this.slideHandler?.isBusy()) {
return;
}
if (this.outputElement !== null) {
// output already created, toggle visibility
this.toggle();
} else {
this.createOutputElement();
const slideHandler = new SlideRevealer(this.linkElement, this.outputElement, this.outputElement);
this.slideHandler = new SlideRevealer(this.linkElement, this.outputElement, this.outputElement);
//slideHandler is now responsible for handling clicks to this element
this.linkElement.addEventListener('click', slideHandler);
this.linkElement.addEventListener('click', this.slideHandler);
// Wait up to a half second in hopes of avoiding double content change
// then render to show loading message
let loadingTimeout = setTimeout(() => {
loadingTimeout = null;
slideHandler.onClick(); //fake initial click
this.slideHandler.onClick(); //fake initial click
this.toggle();
}, 500);
@@ -291,7 +357,7 @@ class LinkKnowl {
}
// Now give code that follows .1 seconds to render before making visible
setTimeout(() => {
slideHandler.onClick(); //fake initial click
this.slideHandler.onClick(); //fake initial click
this.toggle();
}, 100);
@@ -316,6 +382,7 @@ class LinkKnowl {
// render any knowls and mathjax in the knowl
addKnowls(this.outputElement);
MathJax.typesetPromise([this.outputElement]);
// try prism highlighting
Prism.highlightAllUnder(this.outputElement);