throw new Error(`Unknown language '${this.language}'`);
}
this.container.classList.add("highlighting");
+ // Step 1) Load the requested grammar.
await new Promise((resolve_1, reject_1) => { require(["prism/components/prism-" + prism_meta_1.default[this.language].file], resolve_1, reject_1); }).then(tslib_1.__importStar);
+ // Step 2) Perform the highlighting into a temporary element.
await waitForIdle();
const grammar = Prism_1.default.languages[this.language];
if (!grammar) {
}
const container = document.createElement("div");
container.innerHTML = Prism_1.default.highlight(this.codeContainer.textContent, grammar, this.language);
+ // Step 3) Insert the highlighted lines into the page.
+ // This is performed in small chunks to prevent the UI thread from being blocked for complex
+ // highlight results.
await waitForIdle();
- const highlighted = PrismHelper.splitIntoLines(container);
- const highlightedLines = highlighted.querySelectorAll("[data-number]");
const originalLines = this.codeContainer.querySelectorAll(".codeBoxLine > span");
- if (highlightedLines.length !== originalLines.length) {
- throw new Error("Unreachable");
- }
- for (let chunkStart = 0, max = highlightedLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) {
+ const highlightedLines = PrismHelper.splitIntoLines(container);
+ for (let chunkStart = 0, max = originalLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) {
await waitForIdle();
const chunkEnd = Math.min(chunkStart + CHUNK_SIZE, max);
for (let offset = chunkStart; offset < chunkEnd; offset++) {
- originalLines[offset].parentNode.replaceChild(highlightedLines[offset], originalLines[offset]);
+ const toReplace = originalLines[offset];
+ const replacement = highlightedLines.next().value;
+ toReplace.parentNode.replaceChild(replacement, toReplace);
}
}
this.container.classList.remove("highlighting");
+/**
+ * Provide helper functions for prism processing.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Prism/Helper
+ */
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.splitIntoLines = void 0;
- /**
- * Provide helper functions for prism processing.
- *
- * @author Tim Duesterhus
- * @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module WoltLabSuite/Core/Prism/Helper
- */
- function splitIntoLines(container) {
- const frag = document.createDocumentFragment();
- let lineNo = 1;
- const newLine = () => {
- const line = document.createElement("span");
- line.dataset.number = lineNo.toString();
- lineNo++;
- frag.appendChild(line);
- return line;
- };
+ function* splitIntoLines(container) {
const it = document.createNodeIterator(container, NodeFilter.SHOW_TEXT, {
acceptNode() {
return NodeFilter.FILTER_ACCEPT;
},
});
- let line = newLine();
+ let line = document.createElement("span");
let node;
while ((node = it.nextNode())) {
const text = node;
- text.data.split(/\r?\n/).forEach((codeLine, index) => {
+ const lines = text.data.split(/\r?\n/);
+ for (let i = 0, max = lines.length; i < max; i++) {
+ const codeLine = lines[i];
// We are behind a newline, insert \n and create new container.
- if (index >= 1) {
+ if (i >= 1) {
line.appendChild(document.createTextNode("\n"));
- line = newLine();
+ yield line;
+ line = document.createElement("span");
}
let current = document.createTextNode(codeLine);
// Copy hierarchy (to preserve CSS classes).
parent = parent.parentNode;
}
line.appendChild(current);
- });
+ }
}
- return frag;
+ yield line;
}
exports.splitIntoLines = splitIntoLines;
});
this.container.classList.add("highlighting");
+ // Step 1) Load the requested grammar.
await import("prism/components/prism-" + PrismMeta[this.language].file);
+ // Step 2) Perform the highlighting into a temporary element.
await waitForIdle();
const grammar = Prism.languages[this.language];
const container = document.createElement("div");
container.innerHTML = Prism.highlight(this.codeContainer.textContent!, grammar, this.language);
+ // Step 3) Insert the highlighted lines into the page.
+ // This is performed in small chunks to prevent the UI thread from being blocked for complex
+ // highlight results.
await waitForIdle();
- const highlighted = PrismHelper.splitIntoLines(container);
- const highlightedLines = highlighted.querySelectorAll("[data-number]");
const originalLines = this.codeContainer.querySelectorAll(".codeBoxLine > span");
+ const highlightedLines = PrismHelper.splitIntoLines(container);
- if (highlightedLines.length !== originalLines.length) {
- throw new Error("Unreachable");
- }
-
- for (let chunkStart = 0, max = highlightedLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) {
+ for (let chunkStart = 0, max = originalLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) {
await waitForIdle();
+
const chunkEnd = Math.min(chunkStart + CHUNK_SIZE, max);
for (let offset = chunkStart; offset < chunkEnd; offset++) {
- originalLines[offset]!.parentNode!.replaceChild(highlightedLines[offset], originalLines[offset]);
+ const toReplace = originalLines[offset]!;
+ const replacement = highlightedLines.next().value as Element;
+ toReplace.parentNode!.replaceChild(replacement, toReplace);
}
}
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @module WoltLabSuite/Core/Prism/Helper
*/
-export function splitIntoLines(container: Node): DocumentFragment {
- const frag = document.createDocumentFragment();
- let lineNo = 1;
- const newLine = () => {
- const line = document.createElement("span");
- line.dataset.number = lineNo.toString();
- lineNo++;
- frag.appendChild(line);
- return line;
- };
+export function* splitIntoLines(container: Node): Generator<Element, void> {
const it = document.createNodeIterator(container, NodeFilter.SHOW_TEXT, {
acceptNode() {
return NodeFilter.FILTER_ACCEPT;
},
});
- let line = newLine();
+ let line = document.createElement("span");
let node;
while ((node = it.nextNode())) {
const text = node as Text;
- text.data.split(/\r?\n/).forEach((codeLine, index) => {
+ const lines = text.data.split(/\r?\n/);
+
+ for (let i = 0, max = lines.length; i < max; i++) {
+ const codeLine = lines[i];
// We are behind a newline, insert \n and create new container.
- if (index >= 1) {
+ if (i >= 1) {
line.appendChild(document.createTextNode("\n"));
- line = newLine();
+ yield line;
+ line = document.createElement("span");
}
let current: Node = document.createTextNode(codeLine);
parent = parent.parentNode;
}
line.appendChild(current);
- });
+ }
}
- return frag;
+ yield line;
}