Convert `Bbcode/Code` to TypeScript
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 5 Jan 2021 14:11:42 +0000 (15:11 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 5 Jan 2021 15:56:16 +0000 (16:56 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Bbcode/Code.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Bbcode/Code.ts [new file with mode: 0644]

index 1e307a19912817719b4a414af0c47c9b50d97206..e6f5598c62413e881d015491da04f863cd98cbaa 100644 (file)
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @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 (file)
index a8bcae8..0000000
+++ /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 <http://opensource.org/licenses/lgpl-license.php>
- * @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 (file)
index 0000000..d1857d4
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * Highlights code in the Code bbcode.
+ *
+ * @author     Tim Duesterhus
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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<void> {
+  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<void> {
+    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;