Convert `Ui/Redactor/Metacode` to TypeScript
authorAlexander Ebert <ebert@woltlab.com>
Tue, 3 Nov 2020 22:32:23 +0000 (23:32 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 3 Nov 2020 22:32:23 +0000 (23:32 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/Metacode.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.ts [new file with mode: 0644]

index c6bd329b27ef03cf1c4b709c2b6a5639730dd76c..5a580996aefd23b94d32dd17c147758d573e12b0 100644 (file)
 /**
  * Converts `<woltlab-metacode>` into the bbcode representation.
  *
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Ui/Redactor/Metacode
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Ui/Redactor/Metacode
  */
-define(['EventHandler', 'Dom/Util'], function (EventHandler, DomUtil) {
+define(["require", "exports", "tslib", "../../Event/Handler", "../../Dom/Util"], function (require, exports, tslib_1, EventHandler, Util_1) {
     "use strict";
-    if (!COMPILER_TARGET_DEFAULT) {
-        var Fake = function () { };
-        Fake.prototype = {
-            convert: function () { },
-            convertFromHtml: function () { },
-            _getOpeningTag: function () { },
-            _getClosingTag: function () { },
-            _getFirstParagraph: function () { },
-            _getLastParagraph: function () { },
-            _parseAttributes: function () { }
-        };
-        return Fake;
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.convertFromHtml = void 0;
+    EventHandler = tslib_1.__importStar(EventHandler);
+    Util_1 = tslib_1.__importDefault(Util_1);
+    /**
+     * Returns a text node representing the opening bbcode tag.
+     */
+    function getOpeningTag(name, attributes) {
+        let buffer = "[" + name;
+        if (attributes.length) {
+            buffer += "=";
+            buffer += attributes.map((attribute) => `'${attribute}'`).join(",");
+        }
+        return document.createTextNode(buffer + "]");
     }
     /**
-     * @exports     WoltLabSuite/Core/Ui/Redactor/Metacode
+     * Returns a text node representing the closing bbcode tag.
      */
-    return {
-        /**
-         * Converts `<woltlab-metacode>` into the bbcode representation.
-         *
-         * @param       {Element}       element         textarea element
-         */
-        convert: function (element) {
-            element.textContent = this.convertFromHtml(element.textContent);
-        },
-        convertFromHtml: function (editorId, html) {
-            var div = elCreate('div');
-            div.innerHTML = html;
-            var attributes, data, metacode, metacodes = elByTag('woltlab-metacode', div), name, tagClose, tagOpen;
-            while (metacodes.length) {
-                metacode = metacodes[0];
-                name = elData(metacode, 'name');
-                attributes = this._parseAttributes(elData(metacode, 'attributes'));
-                data = {
-                    attributes: attributes,
-                    cancel: false,
-                    metacode: metacode
-                };
-                EventHandler.fire('com.woltlab.wcf.redactor2', 'metacode_' + name + '_' + editorId, data);
-                if (data.cancel === true) {
-                    continue;
-                }
-                tagOpen = this._getOpeningTag(name, attributes);
-                tagClose = this._getClosingTag(name);
-                if (metacode.parentNode === div) {
-                    DomUtil.prepend(tagOpen, this._getFirstParagraph(metacode));
-                    this._getLastParagraph(metacode).appendChild(tagClose);
-                }
-                else {
-                    DomUtil.prepend(tagOpen, metacode);
-                    metacode.appendChild(tagClose);
-                }
-                DomUtil.unwrapChildNodes(metacode);
-            }
-            // convert `<kbd>…</kbd>` to `[tt]…[/tt]`
-            var inlineCode, inlineCodes = elByTag('kbd', div);
-            while (inlineCodes.length) {
-                inlineCode = inlineCodes[0];
-                inlineCode.insertBefore(document.createTextNode('[tt]'), inlineCode.firstChild);
-                inlineCode.appendChild(document.createTextNode('[/tt]'));
-                DomUtil.unwrapChildNodes(inlineCode);
-            }
-            return div.innerHTML;
-        },
-        /**
-         * Returns a text node representing the opening bbcode tag.
-         *
-         * @param       {string}        name            bbcode tag
-         * @param       {Array}         attributes      list of attributes
-         * @returns     {Text}          text node containing the opening bbcode tag
-         * @protected
-         */
-        _getOpeningTag: function (name, attributes) {
-            var buffer = '[' + name;
-            if (attributes.length) {
-                buffer += '=';
-                for (var i = 0, length = attributes.length; i < length; i++) {
-                    if (i > 0)
-                        buffer += ",";
-                    buffer += "'" + attributes[i] + "'";
-                }
-            }
-            return document.createTextNode(buffer + ']');
-        },
-        /**
-         * Returns a text node representing the closing bbcode tag.
-         *
-         * @param       {string}        name            bbcode tag
-         * @returns     {Text}          text node containing the closing bbcode tag
-         * @protected
-         */
-        _getClosingTag: function (name) {
-            return document.createTextNode('[/' + name + ']');
-        },
-        /**
-         * Returns the first paragraph of provided element. If there are no children or
-         * the first child is not a paragraph, a new paragraph is created and inserted
-         * as first child.
-         *
-         * @param       {Element}       element         metacode element
-         * @returns     {Element}       paragraph that is the first child of provided element
-         * @protected
-         */
-        _getFirstParagraph: function (element) {
-            var firstChild, paragraph;
-            if (element.childElementCount === 0) {
-                paragraph = elCreate('p');
-                element.appendChild(paragraph);
+    function getClosingTag(name) {
+        return document.createTextNode(`[/${name}]`);
+    }
+    /**
+     * Returns the first paragraph of provided element. If there are no children or
+     * the first child is not a paragraph, a new paragraph is created and inserted
+     * as first child.
+     */
+    function getFirstParagraph(element) {
+        let paragraph;
+        if (element.childElementCount === 0) {
+            paragraph = document.createElement("p");
+            element.appendChild(paragraph);
+        }
+        else {
+            const firstChild = element.children[0];
+            if (firstChild.nodeName === "P") {
+                paragraph = firstChild;
             }
             else {
-                firstChild = element.children[0];
-                if (firstChild.nodeName === 'P') {
-                    paragraph = firstChild;
-                }
-                else {
-                    paragraph = elCreate('p');
-                    element.insertBefore(paragraph, firstChild);
-                }
+                paragraph = document.createElement("p");
+                element.insertBefore(paragraph, firstChild);
             }
-            return paragraph;
-        },
-        /**
-         * Returns the last paragraph of provided element. If there are no children or
-         * the last child is not a paragraph, a new paragraph is created and inserted
-         * as last child.
-         *
-         * @param       {Element}       element         metacode element
-         * @returns     {Element}       paragraph that is the last child of provided element
-         * @protected
-         */
-        _getLastParagraph: function (element) {
-            var count = element.childElementCount, lastChild, paragraph;
-            if (count === 0) {
-                paragraph = elCreate('p');
-                element.appendChild(paragraph);
+        }
+        return paragraph;
+    }
+    /**
+     * Returns the last paragraph of provided element. If there are no children or
+     * the last child is not a paragraph, a new paragraph is created and inserted
+     * as last child.
+     */
+    function getLastParagraph(element) {
+        const count = element.childElementCount;
+        let paragraph;
+        if (count === 0) {
+            paragraph = document.createElement("p");
+            element.appendChild(paragraph);
+        }
+        else {
+            const lastChild = element.children[count - 1];
+            if (lastChild.nodeName === "P") {
+                paragraph = lastChild;
             }
             else {
-                lastChild = element.children[count - 1];
-                if (lastChild.nodeName === 'P') {
-                    paragraph = lastChild;
-                }
-                else {
-                    paragraph = elCreate('p');
-                    element.appendChild(paragraph);
-                }
+                paragraph = document.createElement("p");
+                element.appendChild(paragraph);
             }
-            return paragraph;
-        },
-        /**
-         * Parses the attributes string.
-         *
-         * @param       {string}        attributes      base64- and JSON-encoded attributes
-         * @return      {Array}         list of parsed attributes
-         * @protected
-         */
-        _parseAttributes: function (attributes) {
-            try {
-                attributes = JSON.parse(atob(attributes));
+        }
+        return paragraph;
+    }
+    /**
+     * Parses the attributes string.
+     */
+    function parseAttributes(attributes) {
+        try {
+            attributes = JSON.parse(atob(attributes));
+        }
+        catch (e) {
+            /* invalid base64 data or invalid json */
+        }
+        if (!Array.isArray(attributes)) {
+            return [];
+        }
+        return attributes.map((attribute) => {
+            return attribute.toString().replace(/^'(.*)'$/, "$1");
+        });
+    }
+    function convertFromHtml(editorId, html) {
+        const div = document.createElement("div");
+        div.innerHTML = html;
+        div.querySelectorAll("woltlab-metacode").forEach((metacode) => {
+            const name = metacode.dataset.name;
+            const attributes = parseAttributes(metacode.dataset.attributes || "");
+            const data = {
+                attributes: attributes,
+                cancel: false,
+                metacode: metacode,
+            };
+            EventHandler.fire("com.woltlab.wcf.redactor2", `metacode_${name}_${editorId}`, data);
+            if (data.cancel) {
+                return;
             }
-            catch (e) { /* invalid base64 data or invalid json */ }
-            if (!Array.isArray(attributes)) {
-                return [];
+            const tagOpen = getOpeningTag(name, attributes);
+            const tagClose = getClosingTag(name);
+            if (metacode.parentElement === div) {
+                const paragraph = getFirstParagraph(metacode);
+                paragraph.insertBefore(tagOpen, paragraph.firstChild);
+                getLastParagraph(metacode).appendChild(tagClose);
             }
-            var attribute, parsedAttributes = [];
-            for (var i = 0, length = attributes.length; i < length; i++) {
-                attribute = attributes[i];
-                if (typeof attribute === 'string') {
-                    attribute = attribute.replace(/^'(.*)'$/, '$1');
-                }
-                parsedAttributes.push(attribute);
+            else {
+                metacode.insertBefore(tagOpen, metacode.firstChild);
+                metacode.appendChild(tagClose);
             }
-            return parsedAttributes;
-        }
-    };
+            Util_1.default.unwrapChildNodes(metacode);
+        });
+        // convert `<kbd>…</kbd>` to `[tt]…[/tt]`
+        div.querySelectorAll("kbd").forEach((inlineCode) => {
+            inlineCode.insertBefore(document.createTextNode("[tt]"), inlineCode.firstChild);
+            inlineCode.appendChild(document.createTextNode("[/tt]"));
+            Util_1.default.unwrapChildNodes(inlineCode);
+        });
+        return div.innerHTML;
+    }
+    exports.convertFromHtml = convertFromHtml;
 });
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.js
deleted file mode 100644 (file)
index 2cf8796..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Converts `<woltlab-metacode>` into the bbcode representation.
- * 
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Ui/Redactor/Metacode
- */
-define(['EventHandler', 'Dom/Util'], function(EventHandler, DomUtil) {
-       "use strict";
-       
-       if (!COMPILER_TARGET_DEFAULT) {
-               var Fake = function() {};
-               Fake.prototype = {
-                       convert: function() {},
-                       convertFromHtml: function() {},
-                       _getOpeningTag: function() {},
-                       _getClosingTag: function() {},
-                       _getFirstParagraph: function() {},
-                       _getLastParagraph: function() {},
-                       _parseAttributes: function() {}
-               };
-               return Fake;
-       }
-       
-       /**
-        * @exports     WoltLabSuite/Core/Ui/Redactor/Metacode
-        */
-       return {
-               /**
-                * Converts `<woltlab-metacode>` into the bbcode representation.
-                * 
-                * @param       {Element}       element         textarea element
-                */
-               convert: function(element) {
-                       element.textContent = this.convertFromHtml(element.textContent);
-               },
-               
-               convertFromHtml: function (editorId, html) {
-                       var div = elCreate('div');
-                       div.innerHTML = html;
-                       
-                       var attributes, data, metacode, metacodes = elByTag('woltlab-metacode', div), name, tagClose, tagOpen;
-                       while (metacodes.length) {
-                               metacode = metacodes[0];
-                               name = elData(metacode, 'name');
-                               attributes = this._parseAttributes(elData(metacode, 'attributes'));
-                               
-                               data = {
-                                       attributes: attributes,
-                                       cancel: false,
-                                       metacode: metacode
-                               };
-                               
-                               EventHandler.fire('com.woltlab.wcf.redactor2', 'metacode_' + name + '_' + editorId, data);
-                               if (data.cancel === true) {
-                                       continue;
-                               }
-                               
-                               tagOpen = this._getOpeningTag(name, attributes);
-                               tagClose = this._getClosingTag(name);
-                               
-                               if (metacode.parentNode === div) {
-                                       DomUtil.prepend(tagOpen, this._getFirstParagraph(metacode));
-                                       this._getLastParagraph(metacode).appendChild(tagClose);
-                               }
-                               else {
-                                       DomUtil.prepend(tagOpen, metacode);
-                                       metacode.appendChild(tagClose);
-                               }
-                               
-                               DomUtil.unwrapChildNodes(metacode);
-                       }
-                       
-                       // convert `<kbd>…</kbd>` to `[tt]…[/tt]`
-                       var inlineCode, inlineCodes = elByTag('kbd', div);
-                       while (inlineCodes.length) {
-                               inlineCode = inlineCodes[0];
-                               
-                               inlineCode.insertBefore(document.createTextNode('[tt]'), inlineCode.firstChild);
-                               inlineCode.appendChild(document.createTextNode('[/tt]'));
-                               
-                               DomUtil.unwrapChildNodes(inlineCode);
-                       }
-                       
-                       return div.innerHTML;
-               },
-               
-               /**
-                * Returns a text node representing the opening bbcode tag.
-                * 
-                * @param       {string}        name            bbcode tag
-                * @param       {Array}         attributes      list of attributes
-                * @returns     {Text}          text node containing the opening bbcode tag
-                * @protected
-                */
-               _getOpeningTag: function(name, attributes) {
-                       var buffer = '[' + name;
-                       if (attributes.length) {
-                               buffer += '=';
-                               
-                               for (var i = 0, length = attributes.length; i < length; i++) {
-                                       if (i > 0) buffer += ",";
-                                       buffer += "'" + attributes[i] + "'";
-                               }
-                       }
-                       
-                       return document.createTextNode(buffer + ']');
-               },
-               
-               /**
-                * Returns a text node representing the closing bbcode tag.
-                * 
-                * @param       {string}        name            bbcode tag
-                * @returns     {Text}          text node containing the closing bbcode tag
-                * @protected
-                */
-               _getClosingTag: function(name) {
-                       return document.createTextNode('[/' + name + ']');
-               },
-               
-               /**
-                * Returns the first paragraph of provided element. If there are no children or
-                * the first child is not a paragraph, a new paragraph is created and inserted
-                * as first child.
-                * 
-                * @param       {Element}       element         metacode element
-                * @returns     {Element}       paragraph that is the first child of provided element
-                * @protected
-                */
-               _getFirstParagraph: function (element) {
-                       var firstChild, paragraph;
-                       
-                       if (element.childElementCount === 0) {
-                               paragraph = elCreate('p');
-                               element.appendChild(paragraph);
-                       }
-                       else {
-                               firstChild = element.children[0];
-                               
-                               if (firstChild.nodeName === 'P') {
-                                       paragraph = firstChild;
-                               }
-                               else {
-                                       paragraph = elCreate('p');
-                                       element.insertBefore(paragraph, firstChild);
-                               }
-                       }
-                       
-                       return paragraph;
-               },
-               
-               /**
-                * Returns the last paragraph of provided element. If there are no children or
-                * the last child is not a paragraph, a new paragraph is created and inserted
-                * as last child.
-                * 
-                * @param       {Element}       element         metacode element
-                * @returns     {Element}       paragraph that is the last child of provided element
-                * @protected
-                */
-               _getLastParagraph: function (element) {
-                       var count = element.childElementCount, lastChild, paragraph;
-                       
-                       if (count === 0) {
-                               paragraph = elCreate('p');
-                               element.appendChild(paragraph);
-                       }
-                       else {
-                               lastChild = element.children[count - 1];
-                               
-                               if (lastChild.nodeName === 'P') {
-                                       paragraph = lastChild;
-                               }
-                               else {
-                                       paragraph = elCreate('p');
-                                       element.appendChild(paragraph);
-                               }
-                       }
-                       
-                       return paragraph;
-               },
-               
-               /**
-                * Parses the attributes string.
-                * 
-                * @param       {string}        attributes      base64- and JSON-encoded attributes
-                * @return      {Array}         list of parsed attributes
-                * @protected
-                */
-               _parseAttributes: function(attributes) {
-                       try {
-                               attributes = JSON.parse(atob(attributes));
-                       }
-                       catch (e) { /* invalid base64 data or invalid json */ }
-                       
-                       if (!Array.isArray(attributes)) {
-                               return [];
-                       }
-                       
-                       var attribute, parsedAttributes = [];
-                       for (var i = 0, length = attributes.length; i < length; i++) {
-                               attribute = attributes[i];
-                               
-                               if (typeof attribute === 'string') {
-                                       attribute = attribute.replace(/^'(.*)'$/, '$1');
-                               }
-                               
-                               parsedAttributes.push(attribute);
-                       }
-                       
-                       return parsedAttributes;
-               }
-       };
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Metacode.ts
new file mode 100644 (file)
index 0000000..94d30bb
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * Converts `<woltlab-metacode>` into the bbcode representation.
+ *
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Ui/Redactor/Metacode
+ */
+
+import * as EventHandler from "../../Event/Handler";
+import DomUtil from "../../Dom/Util";
+
+type Attributes = string[];
+
+/**
+ * Returns a text node representing the opening bbcode tag.
+ */
+function getOpeningTag(name: string, attributes: Attributes): Text {
+  let buffer = "[" + name;
+  if (attributes.length) {
+    buffer += "=";
+    buffer += attributes.map((attribute) => `'${attribute}'`).join(",");
+  }
+
+  return document.createTextNode(buffer + "]");
+}
+
+/**
+ * Returns a text node representing the closing bbcode tag.
+ */
+function getClosingTag(name: string): Text {
+  return document.createTextNode(`[/${name}]`);
+}
+
+/**
+ * Returns the first paragraph of provided element. If there are no children or
+ * the first child is not a paragraph, a new paragraph is created and inserted
+ * as first child.
+ */
+function getFirstParagraph(element: HTMLElement): HTMLElement {
+  let paragraph: HTMLElement;
+  if (element.childElementCount === 0) {
+    paragraph = document.createElement("p");
+    element.appendChild(paragraph);
+  } else {
+    const firstChild = element.children[0] as HTMLElement;
+
+    if (firstChild.nodeName === "P") {
+      paragraph = firstChild;
+    } else {
+      paragraph = document.createElement("p");
+      element.insertBefore(paragraph, firstChild);
+    }
+  }
+
+  return paragraph;
+}
+
+/**
+ * Returns the last paragraph of provided element. If there are no children or
+ * the last child is not a paragraph, a new paragraph is created and inserted
+ * as last child.
+ */
+function getLastParagraph(element: HTMLElement): HTMLElement {
+  const count = element.childElementCount;
+
+  let paragraph: HTMLElement;
+  if (count === 0) {
+    paragraph = document.createElement("p");
+    element.appendChild(paragraph);
+  } else {
+    const lastChild = element.children[count - 1] as HTMLElement;
+
+    if (lastChild.nodeName === "P") {
+      paragraph = lastChild;
+    } else {
+      paragraph = document.createElement("p");
+      element.appendChild(paragraph);
+    }
+  }
+
+  return paragraph;
+}
+
+/**
+ * Parses the attributes string.
+ */
+function parseAttributes(attributes: string): Attributes {
+  try {
+    attributes = JSON.parse(atob(attributes));
+  } catch (e) {
+    /* invalid base64 data or invalid json */
+  }
+
+  if (!Array.isArray(attributes)) {
+    return [];
+  }
+
+  return attributes.map((attribute: string | number) => {
+    return attribute.toString().replace(/^'(.*)'$/, "$1");
+  });
+}
+
+export function convertFromHtml(editorId: string, html: string): string {
+  const div = document.createElement("div");
+  div.innerHTML = html;
+
+  div.querySelectorAll("woltlab-metacode").forEach((metacode: HTMLElement) => {
+    const name = metacode.dataset.name!;
+    const attributes = parseAttributes(metacode.dataset.attributes || "");
+
+    const data = {
+      attributes: attributes,
+      cancel: false,
+      metacode: metacode,
+    };
+
+    EventHandler.fire("com.woltlab.wcf.redactor2", `metacode_${name}_${editorId}`, data);
+    if (data.cancel) {
+      return;
+    }
+
+    const tagOpen = getOpeningTag(name, attributes);
+    const tagClose = getClosingTag(name);
+
+    if (metacode.parentElement === div) {
+      const paragraph = getFirstParagraph(metacode);
+      paragraph.insertBefore(tagOpen, paragraph.firstChild);
+      getLastParagraph(metacode).appendChild(tagClose);
+    } else {
+      metacode.insertBefore(tagOpen, metacode.firstChild);
+      metacode.appendChild(tagClose);
+    }
+
+    DomUtil.unwrapChildNodes(metacode);
+  });
+
+  // convert `<kbd>…</kbd>` to `[tt]…[/tt]`
+  div.querySelectorAll("kbd").forEach((inlineCode) => {
+    inlineCode.insertBefore(document.createTextNode("[tt]"), inlineCode.firstChild);
+    inlineCode.appendChild(document.createTextNode("[/tt]"));
+
+    DomUtil.unwrapChildNodes(inlineCode);
+  });
+
+  return div.innerHTML;
+}