From: Tim Düsterhus Date: Tue, 5 Jan 2021 14:11:42 +0000 (+0100) Subject: Convert `Bbcode/Code` to TypeScript X-Git-Tag: 5.4.0_Alpha_1~480^2~3 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=f18e42f6b7ab3d2d3127c5f91dddc3334a964cd4;p=GitHub%2FWoltLab%2FWCF.git Convert `Bbcode/Code` to TypeScript --- diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Bbcode/Code.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Bbcode/Code.js index 1e307a1991..e6f5598c62 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Bbcode/Code.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Bbcode/Code.js @@ -6,110 +6,91 @@ * @license GNU Lesser General Public License * @module WoltLabSuite/Core/Bbcode/Code */ -define([ - 'Language', 'WoltLabSuite/Core/Ui/Notification', 'WoltLabSuite/Core/Clipboard', 'WoltLabSuite/Core/Prism', 'prism/prism-meta' -], function (Language, UiNotification, Clipboard, Prism, PrismMeta) { +define(["require", "exports", "tslib", "../Language", "../Clipboard", "../Ui/Notification", "../Prism", "../Prism/Helper", "../prism-meta"], function (require, exports, tslib_1, Language, Clipboard, UiNotification, Prism_1, PrismHelper, prism_meta_1) { "use strict"; - /** @const */ var CHUNK_SIZE = 50; - // Define idleify() for piecewiese highlighting to not block the UI thread. - var idleify = function (callback) { - return function () { - var args = arguments; - return new Promise(function (resolve, reject) { - var body = function () { - try { - resolve(callback.apply(null, args)); - } - catch (e) { - reject(e); - } - }; - if (window.requestIdleCallback) { - window.requestIdleCallback(body, { timeout: 5000 }); - } - else { - setTimeout(body, 0); + Language = tslib_1.__importStar(Language); + Clipboard = tslib_1.__importStar(Clipboard); + UiNotification = tslib_1.__importStar(UiNotification); + Prism_1 = tslib_1.__importDefault(Prism_1); + PrismHelper = tslib_1.__importStar(PrismHelper); + prism_meta_1 = tslib_1.__importDefault(prism_meta_1); + const CHUNK_SIZE = 50; + async function waitForIdle() { + return new Promise((resolve, _reject) => { + if (window.requestIdleCallback) { + window.requestIdleCallback(resolve, { timeout: 5000 }); + } + else { + setTimeout(resolve, 0); + } + }); + } + class Code { + constructor(container) { + var _a; + this.container = container; + this.codeContainer = this.container.querySelector(".codeBoxCode > code"); + this.language = (_a = Array.from(this.codeContainer.classList) + .find((klass) => /^language-([a-z0-9_-]+)$/.test(klass))) === null || _a === void 0 ? void 0 : _a.replace(/^language-/, ""); + } + static processAll() { + document.querySelectorAll(".codeBox:not([data-processed])").forEach((codeBox) => { + codeBox.dataset.processed = "1"; + const handle = new Code(codeBox); + if (handle.language) { + void handle.highlight(); } + handle.createCopyButton(); }); - }; - }; - /** - * @constructor - */ - function Code(container) { - var matches; - this.container = container; - this.codeContainer = elBySel('.codeBoxCode > code', this.container); - this.language = null; - for (var i = 0; i < this.codeContainer.classList.length; i++) { - if ((matches = this.codeContainer.classList[i].match(/language-(.*)/))) { - this.language = matches[1]; - } } - } - Code.processAll = function () { - elBySelAll('.codeBox:not([data-processed])', document, function (codeBox) { - elData(codeBox, 'processed', '1'); - var handle = new Code(codeBox); - if (handle.language) - handle.highlight(); - handle.createCopyButton(); - }); - }; - Code.prototype = { - createCopyButton: function () { - var header = elBySel('.codeBoxHeader', this.container); - var button = elCreate('span'); - button.className = 'icon icon24 fa-files-o pointer jsTooltip'; - button.setAttribute('title', Language.get('wcf.message.bbcode.code.copy')); - button.addEventListener('click', function () { - Clipboard.copyElementTextToClipboard(this.codeContainer).then(function () { - UiNotification.show(Language.get('wcf.message.bbcode.code.copy.success')); + createCopyButton() { + const header = this.container.querySelector(".codeBoxHeader"); + if (!header) { + return; + } + const button = document.createElement("span"); + button.className = "icon icon24 fa-files-o pointer jsTooltip"; + button.setAttribute("title", Language.get("wcf.message.bbcode.code.copy")); + button.addEventListener("click", () => { + void Clipboard.copyElementTextToClipboard(this.codeContainer).then(() => { + UiNotification.show(Language.get("wcf.message.bbcode.code.copy.success")); }); - }.bind(this)); + }); header.appendChild(button); - }, - highlight: function () { + } + async highlight() { if (!this.language) { - return Promise.reject(new Error('No language detected')); + throw new Error("No language detected"); } - if (!PrismMeta[this.language]) { - return Promise.reject(new Error('Unknown language ' + this.language)); + if (!prism_meta_1.default[this.language]) { + throw new Error(`Unknown language '${this.language}'`); } - this.container.classList.add('highlighting'); - return require(['prism/components/prism-' + PrismMeta[this.language].file]) - .then(idleify(function () { - var grammar = Prism.languages[this.language]; - if (!grammar) { - throw new Error('Invalid language ' + language + ' given.'); - } - var container = elCreate('div'); - container.innerHTML = Prism.highlight(this.codeContainer.textContent, grammar, this.language); - return container; - }.bind(this))) - .then(idleify(function (container) { - var highlighted = Prism.wscSplitIntoLines(container); - var highlightedLines = elBySelAll('[data-number]', highlighted); - var originalLines = elBySelAll('.codeBoxLine > span', this.codeContainer); - if (highlightedLines.length !== originalLines.length) { - throw new Error('Unreachable'); - } - var promises = []; - for (var chunkStart = 0, max = highlightedLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) { - promises.push(idleify(function (chunkStart) { - var chunkEnd = Math.min(chunkStart + CHUNK_SIZE, max); - for (var offset = chunkStart; offset < chunkEnd; offset++) { - originalLines[offset].parentNode.replaceChild(highlightedLines[offset], originalLines[offset]); - } - })(chunkStart)); + this.container.classList.add("highlighting"); + 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); + await waitForIdle(); + const grammar = Prism_1.default.languages[this.language]; + if (!grammar) { + throw new Error(`Invalid language '${this.language}' given.`); + } + const container = document.createElement("div"); + container.innerHTML = Prism_1.default.highlight(this.codeContainer.textContent, grammar, this.language); + 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) { + 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]); } - return Promise.all(promises); - }.bind(this))) - .then(function () { - this.container.classList.remove('highlighting'); - this.container.classList.add('highlighted'); - }.bind(this)); + } + this.container.classList.remove("highlighting"); + this.container.classList.add("highlighted"); } - }; + } return Code; }); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.js deleted file mode 100644 index a8bcae8d97..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Highlights code in the Code bbcode. - * - * @author Tim Duesterhus - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Bbcode/Code - */ -define([ - 'Language', 'WoltLabSuite/Core/Ui/Notification', 'WoltLabSuite/Core/Clipboard', 'WoltLabSuite/Core/Prism', 'prism/prism-meta' - ], - function( - Language, UiNotification, Clipboard, Prism, PrismMeta - ) -{ - "use strict"; - - /** @const */ var CHUNK_SIZE = 50; - - // Define idleify() for piecewiese highlighting to not block the UI thread. - var idleify = function (callback) { - return function () { - var args = arguments; - return new Promise(function (resolve, reject) { - var body = function () { - try { - resolve(callback.apply(null, args)); - } - catch (e) { - reject(e); - } - }; - - if (window.requestIdleCallback) { - window.requestIdleCallback(body, { timeout: 5000 }); - } - else { - setTimeout(body, 0); - } - }); - }; - }; - - /** - * @constructor - */ - function Code(container) { - var matches; - - this.container = container; - this.codeContainer = elBySel('.codeBoxCode > code', this.container); - this.language = null; - for (var i = 0; i < this.codeContainer.classList.length; i++) { - if ((matches = this.codeContainer.classList[i].match(/language-(.*)/))) { - this.language = matches[1]; - } - } - } - Code.processAll = function () { - elBySelAll('.codeBox:not([data-processed])', document, function (codeBox) { - elData(codeBox, 'processed', '1'); - - var handle = new Code(codeBox); - if (handle.language) handle.highlight(); - handle.createCopyButton(); - }) - }; - Code.prototype = { - createCopyButton: function () { - var header = elBySel('.codeBoxHeader', this.container); - var button = elCreate('span'); - button.className = 'icon icon24 fa-files-o pointer jsTooltip'; - button.setAttribute('title', Language.get('wcf.message.bbcode.code.copy')); - button.addEventListener('click', function () { - Clipboard.copyElementTextToClipboard(this.codeContainer).then(function () { - UiNotification.show(Language.get('wcf.message.bbcode.code.copy.success')); - }); - }.bind(this)); - - header.appendChild(button); - }, - highlight: function () { - if (!this.language) { - return Promise.reject(new Error('No language detected')); - } - if (!PrismMeta[this.language]) { - return Promise.reject(new Error('Unknown language ' + this.language)); - } - - this.container.classList.add('highlighting'); - - return require(['prism/components/prism-' + PrismMeta[this.language].file]) - .then(idleify(function () { - var grammar = Prism.languages[this.language]; - if (!grammar) { - throw new Error('Invalid language ' + language + ' given.'); - } - - var container = elCreate('div'); - container.innerHTML = Prism.highlight(this.codeContainer.textContent, grammar, this.language); - return container; - }.bind(this))) - .then(idleify(function (container) { - var highlighted = Prism.wscSplitIntoLines(container); - var highlightedLines = elBySelAll('[data-number]', highlighted); - var originalLines = elBySelAll('.codeBoxLine > span', this.codeContainer); - - if (highlightedLines.length !== originalLines.length) { - throw new Error('Unreachable'); - } - - var promises = []; - for (var chunkStart = 0, max = highlightedLines.length; chunkStart < max; chunkStart += CHUNK_SIZE) { - promises.push(idleify(function (chunkStart) { - var chunkEnd = Math.min(chunkStart + CHUNK_SIZE, max); - - for (var offset = chunkStart; offset < chunkEnd; offset++) { - originalLines[offset].parentNode.replaceChild(highlightedLines[offset], originalLines[offset]); - } - })(chunkStart)); - } - return Promise.all(promises); - }.bind(this))) - .then(function () { - this.container.classList.remove('highlighting'); - this.container.classList.add('highlighted'); - }.bind(this)) - } - }; - - return Code; -}); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.ts new file mode 100644 index 0000000000..d1857d460d --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.ts @@ -0,0 +1,122 @@ +/** + * Highlights code in the Code bbcode. + * + * @author Tim Duesterhus + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Bbcode/Code + */ + +import * as Language from "../Language"; +import * as Clipboard from "../Clipboard"; +import * as UiNotification from "../Ui/Notification"; +import Prism from "../Prism"; +import * as PrismHelper from "../Prism/Helper"; +import PrismMeta from "../prism-meta"; + +const CHUNK_SIZE = 50; + +async function waitForIdle(): Promise { + return new Promise((resolve, _reject) => { + if ((window as any).requestIdleCallback) { + (window as any).requestIdleCallback(resolve, { timeout: 5000 }); + } else { + setTimeout(resolve, 0); + } + }); +} + +class Code { + private readonly container: HTMLElement; + private codeContainer: HTMLElement; + private language: string | undefined; + + constructor(container: HTMLElement) { + this.container = container; + this.codeContainer = this.container.querySelector(".codeBoxCode > code") as HTMLElement; + + this.language = Array.from(this.codeContainer.classList) + .find((klass) => /^language-([a-z0-9_-]+)$/.test(klass)) + ?.replace(/^language-/, ""); + } + + public static processAll(): void { + document.querySelectorAll(".codeBox:not([data-processed])").forEach((codeBox: HTMLElement) => { + codeBox.dataset.processed = "1"; + + const handle = new Code(codeBox); + + if (handle.language) { + void handle.highlight(); + } + + handle.createCopyButton(); + }); + } + + public createCopyButton(): void { + const header = this.container.querySelector(".codeBoxHeader"); + + if (!header) { + return; + } + + const button = document.createElement("span"); + button.className = "icon icon24 fa-files-o pointer jsTooltip"; + button.setAttribute("title", Language.get("wcf.message.bbcode.code.copy")); + button.addEventListener("click", () => { + void Clipboard.copyElementTextToClipboard(this.codeContainer).then(() => { + UiNotification.show(Language.get("wcf.message.bbcode.code.copy.success")); + }); + }); + + header.appendChild(button); + } + + public async highlight(): Promise { + if (!this.language) { + throw new Error("No language detected"); + } + if (!PrismMeta[this.language]) { + throw new Error(`Unknown language '${this.language}'`); + } + + this.container.classList.add("highlighting"); + + await import("prism/components/prism-" + PrismMeta[this.language].file); + + await waitForIdle(); + + const grammar = Prism.languages[this.language]; + if (!grammar) { + throw new Error(`Invalid language '${this.language}' given.`); + } + + const container = document.createElement("div"); + container.innerHTML = Prism.highlight(this.codeContainer.textContent!, grammar, this.language); + + 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) { + 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]); + } + } + + this.container.classList.remove("highlighting"); + this.container.classList.add("highlighted"); + } +} + +export = Code;