mirror of
https://github.com/wassname/template.git
synced 2026-07-24 13:20:06 +08:00
Fix bug discovered by Fred where katex in dev mode would interfere with svelte figures updating
This commit is contained in:
+39
-33
@@ -45,38 +45,41 @@ import { DistillHeader } from './distill-components/distill-header';
|
||||
import { DistillAppendix } from './distill-components/distill-appendix';
|
||||
import { DistillFooter } from './distill-components/distill-footer';
|
||||
|
||||
const distillMain = function() {
|
||||
|
||||
if (window.distillRunlevel < 1) {
|
||||
throw new Error('Insufficient Runlevel for Distill Template!');
|
||||
let templateIsLoading = false;
|
||||
let runlevel = 0;
|
||||
const initialize = function() {
|
||||
if (window.distill.runlevel < 1) {
|
||||
throw new Error("Insufficient Runlevel for Distill Template!");
|
||||
}
|
||||
|
||||
/* 1. Flag that we're being loaded */
|
||||
if ('distillTemplateIsLoading' in window && window.distillTemplateIsLoading) {
|
||||
throw new Error('Runlevel 1: Distill Template is getting loaded more than once, aborting!');
|
||||
if ("distill" in window && window.distill.templateIsLoading) {
|
||||
throw new Error(
|
||||
"Runlevel 1: Distill Template is getting loaded more than once, aborting!"
|
||||
);
|
||||
} else {
|
||||
window.distillTemplateIsLoading = true;
|
||||
console.debug('Runlevel 1: Distill Template has started loading.');
|
||||
window.distill.templateIsLoading = true;
|
||||
console.debug("Runlevel 1: Distill Template has started loading.");
|
||||
}
|
||||
|
||||
/* 2. Add styles if they weren't added during prerendering */
|
||||
makeStyleTag(document);
|
||||
console.debug('Runlevel 1: Static Distill styles have been added.');
|
||||
console.debug('Runlevel 1->2.');
|
||||
window.distillRunlevel += 1;
|
||||
console.debug("Runlevel 1: Static Distill styles have been added.");
|
||||
console.debug("Runlevel 1->2.");
|
||||
window.distill.runlevel += 1;
|
||||
|
||||
/* 3. Register Controller listener functions */
|
||||
/* Needs to happen before components to their connected callbacks have a controller to talk to. */
|
||||
for (const [functionName, callback] of Object.entries(Controller.listeners)) {
|
||||
if (typeof callback === 'function') {
|
||||
if (typeof callback === "function") {
|
||||
document.addEventListener(functionName, callback);
|
||||
} else {
|
||||
console.error('Runlevel 2: Controller listeners need to be functions!');
|
||||
console.error("Runlevel 2: Controller listeners need to be functions!");
|
||||
}
|
||||
}
|
||||
console.debug('Runlevel 2: We can now listen to controller events.');
|
||||
console.debug('Runlevel 2->3.');
|
||||
window.distillRunlevel += 1;
|
||||
console.debug("Runlevel 2: We can now listen to controller events.");
|
||||
console.debug("Runlevel 2->3.");
|
||||
window.distill.runlevel += 1;
|
||||
|
||||
/* 4. Register components */
|
||||
const components = [
|
||||
@@ -85,22 +88,22 @@ const distillMain = function() {
|
||||
Slider, Interstitial
|
||||
];
|
||||
|
||||
const distillComponents = [
|
||||
DistillHeader, DistillAppendix, DistillFooter,
|
||||
];
|
||||
const distillComponents = [DistillHeader, DistillAppendix, DistillFooter];
|
||||
|
||||
if (window.distillRunlevel < 2) {
|
||||
throw new Error('Insufficient Runlevel for adding custom elements!');
|
||||
if (window.distill.runlevel < 2) {
|
||||
throw new Error("Insufficient Runlevel for adding custom elements!");
|
||||
}
|
||||
const allComponents = components.concat(distillComponents);
|
||||
for (const component of allComponents) {
|
||||
console.debug('Runlevel 2: Registering custom element: ' + component.is);
|
||||
console.debug("Runlevel 2: Registering custom element: " + component.is);
|
||||
customElements.define(component.is, component);
|
||||
}
|
||||
|
||||
console.debug('Runlevel 3: Distill Template finished registering custom elements.');
|
||||
console.debug('Runlevel 3->4.');
|
||||
window.distillRunlevel += 1;
|
||||
console.debug(
|
||||
"Runlevel 3: Distill Template finished registering custom elements."
|
||||
);
|
||||
console.debug("Runlevel 3->4.");
|
||||
window.distill.runlevel += 1;
|
||||
|
||||
// If template was added after DOMContentLoaded we may have missed that event.
|
||||
// Controller will check for that case, so trigger the event explicitly:
|
||||
@@ -108,17 +111,20 @@ const distillMain = function() {
|
||||
Controller.listeners.DOMContentLoaded();
|
||||
}
|
||||
|
||||
console.debug('Runlevel 4: Distill Template initialisation complete.');
|
||||
console.debug("Runlevel 4: Distill Template initialisation complete.");
|
||||
window.distill.templateIsLoading = false;
|
||||
window.distill.templateHasLoaded = true;
|
||||
};
|
||||
|
||||
window.distillRunlevel = 0;
|
||||
window.distill = { runlevel, initialize, templateIsLoading };
|
||||
|
||||
/* 0. Check browser feature support; synchronously polyfill if needed */
|
||||
if (Polyfills.browserSupportsAllFeatures()) {
|
||||
console.debug('Runlevel 0: No need for polyfills.');
|
||||
console.debug('Runlevel 0->1.');
|
||||
window.distillRunlevel += 1;
|
||||
distillMain();
|
||||
console.debug("Runlevel 0: No need for polyfills.");
|
||||
console.debug("Runlevel 0->1.");
|
||||
window.distill.runlevel += 1;
|
||||
window.distill.initialize();
|
||||
} else {
|
||||
console.debug('Runlevel 0: Distill Template is loading polyfills.');
|
||||
Polyfills.load(distillMain);
|
||||
console.debug("Runlevel 0: Distill Template is loading polyfills.");
|
||||
Polyfills.load(window.distill.initialize);
|
||||
}
|
||||
|
||||
@@ -28,14 +28,16 @@ const findEndOfMath = function(delimiter, text, startIndex) {
|
||||
while (index < text.length) {
|
||||
const character = text[index];
|
||||
|
||||
if (braceLevel <= 0 &&
|
||||
text.slice(index, index + delimLength) === delimiter) {
|
||||
if (
|
||||
braceLevel <= 0 &&
|
||||
text.slice(index, index + delimLength) === delimiter
|
||||
) {
|
||||
return index;
|
||||
} else if (character === '\\') {
|
||||
} else if (character === "\\") {
|
||||
index++;
|
||||
} else if (character === '{') {
|
||||
} else if (character === "{") {
|
||||
braceLevel++;
|
||||
} else if (character === '}') {
|
||||
} else if (character === "}") {
|
||||
braceLevel--;
|
||||
}
|
||||
|
||||
@@ -49,7 +51,7 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
const finalData = [];
|
||||
|
||||
for (let i = 0; i < startData.length; i++) {
|
||||
if (startData[i].type === 'text') {
|
||||
if (startData[i].type === "text") {
|
||||
const text = startData[i].data;
|
||||
|
||||
let lookingForLeft = true;
|
||||
@@ -60,13 +62,14 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
if (nextIndex !== -1) {
|
||||
currIndex = nextIndex;
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(0, currIndex),
|
||||
type: "text",
|
||||
data: text.slice(0, currIndex)
|
||||
});
|
||||
lookingForLeft = false;
|
||||
}
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
while (true) {
|
||||
// eslint-disable-line no-constant-condition
|
||||
if (lookingForLeft) {
|
||||
nextIndex = text.indexOf(leftDelim, currIndex);
|
||||
if (nextIndex === -1) {
|
||||
@@ -74,8 +77,8 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(currIndex, nextIndex),
|
||||
type: "text",
|
||||
data: text.slice(currIndex, nextIndex)
|
||||
});
|
||||
|
||||
currIndex = nextIndex;
|
||||
@@ -83,20 +86,17 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
nextIndex = findEndOfMath(
|
||||
rightDelim,
|
||||
text,
|
||||
currIndex + leftDelim.length);
|
||||
currIndex + leftDelim.length
|
||||
);
|
||||
if (nextIndex === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'math',
|
||||
data: text.slice(
|
||||
currIndex + leftDelim.length,
|
||||
nextIndex),
|
||||
rawData: text.slice(
|
||||
currIndex,
|
||||
nextIndex + rightDelim.length),
|
||||
display: display,
|
||||
type: "math",
|
||||
data: text.slice(currIndex + leftDelim.length, nextIndex),
|
||||
rawData: text.slice(currIndex, nextIndex + rightDelim.length),
|
||||
display: display
|
||||
});
|
||||
|
||||
currIndex = nextIndex + rightDelim.length;
|
||||
@@ -106,8 +106,8 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(currIndex),
|
||||
type: "text",
|
||||
data: text.slice(currIndex)
|
||||
});
|
||||
} else {
|
||||
finalData.push(startData[i]);
|
||||
@@ -117,14 +117,16 @@ const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
return finalData;
|
||||
};
|
||||
|
||||
|
||||
const splitWithDelimiters = function(text, delimiters) {
|
||||
let data = [{type: 'text', data: text}];
|
||||
let data = [{ type: "text", data: text }];
|
||||
for (let i = 0; i < delimiters.length; i++) {
|
||||
const delimiter = delimiters[i];
|
||||
data = splitAtDelimiters(
|
||||
data, delimiter.left, delimiter.right,
|
||||
delimiter.display || false);
|
||||
data,
|
||||
delimiter.left,
|
||||
delimiter.right,
|
||||
delimiter.display || false
|
||||
);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
@@ -137,10 +139,10 @@ const renderMathInText = function(text, optionsCopy) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === 'text') {
|
||||
if (data[i].type === "text") {
|
||||
fragment.appendChild(document.createTextNode(data[i].data));
|
||||
} else {
|
||||
const tag = document.createElement('d-math');
|
||||
const tag = document.createElement("d-math");
|
||||
const math = data[i].data;
|
||||
// Override any display mode defined in the settings with that
|
||||
// defined by the text itself
|
||||
@@ -148,15 +150,14 @@ const renderMathInText = function(text, optionsCopy) {
|
||||
try {
|
||||
tag.textContent = math;
|
||||
if (optionsCopy.displayMode) {
|
||||
tag.setAttribute('block', '');
|
||||
tag.setAttribute("block", "");
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e instanceof katex.ParseError)) {
|
||||
throw e;
|
||||
}
|
||||
optionsCopy.errorCallback(
|
||||
'KaTeX auto-render: Failed to parse `' + data[i].data +
|
||||
'` with ',
|
||||
"KaTeX auto-render: Failed to parse `" + data[i].data + "` with ",
|
||||
e
|
||||
);
|
||||
fragment.appendChild(document.createTextNode(data[i].rawData));
|
||||
@@ -174,13 +175,17 @@ const renderElem = function(elem, optionsCopy) {
|
||||
const childNode = elem.childNodes[i];
|
||||
if (childNode.nodeType === 3) {
|
||||
// Text node
|
||||
const frag = renderMathInText(childNode.textContent, optionsCopy);
|
||||
i += frag.childNodes.length - 1;
|
||||
elem.replaceChild(frag, childNode);
|
||||
const text = childNode.textContent;
|
||||
if (optionsCopy.mightHaveMath(text)) {
|
||||
const frag = renderMathInText(text, optionsCopy);
|
||||
i += frag.childNodes.length - 1;
|
||||
elem.replaceChild(frag, childNode);
|
||||
}
|
||||
} else if (childNode.nodeType === 1) {
|
||||
// Element node
|
||||
const shouldRender = optionsCopy.ignoredTags.indexOf(
|
||||
childNode.nodeName.toLowerCase()) === -1;
|
||||
const shouldRender =
|
||||
optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) ===
|
||||
-1;
|
||||
|
||||
if (shouldRender) {
|
||||
renderElem(childNode, optionsCopy);
|
||||
@@ -192,27 +197,40 @@ const renderElem = function(elem, optionsCopy) {
|
||||
|
||||
const defaultAutoRenderOptions = {
|
||||
delimiters: [
|
||||
{left: '$$', right: '$$', display: true},
|
||||
{left: '\\[', right: '\\]', display: true},
|
||||
{left: '\\(', right: '\\)', display: false},
|
||||
{ left: "$$", right: "$$", display: true },
|
||||
{ left: "\\[", right: "\\]", display: true },
|
||||
{ left: "\\(", right: "\\)", display: false }
|
||||
// LaTeX uses this, but it ruins the display of normal `$` in text:
|
||||
// {left: '$', right: '$', display: false},
|
||||
],
|
||||
|
||||
ignoredTags: [
|
||||
'script', 'noscript', 'style', 'textarea', 'pre', 'code', 'svg',
|
||||
"script",
|
||||
"noscript",
|
||||
"style",
|
||||
"textarea",
|
||||
"pre",
|
||||
"code",
|
||||
"svg"
|
||||
],
|
||||
|
||||
errorCallback: function(msg, err) {
|
||||
console.error(msg, err);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export const renderMathInElement = function(elem, options) {
|
||||
if (!elem) {
|
||||
throw new Error('No element provided to render');
|
||||
throw new Error("No element provided to render");
|
||||
}
|
||||
|
||||
const optionsCopy = Object.assign({}, defaultAutoRenderOptions, options);
|
||||
const delimiterStrings = optionsCopy.delimiters.flatMap(d => [
|
||||
d.left,
|
||||
d.right
|
||||
]);
|
||||
const mightHaveMath = text =>
|
||||
delimiterStrings.some(d => text.indexOf(d) !== -1);
|
||||
optionsCopy.mightHaveMath = mightHaveMath;
|
||||
renderElem(elem, optionsCopy);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user