Rename the Cleanup module for CKEditor to `Normalizer`
authorAlexander Ebert <ebert@woltlab.com>
Wed, 10 May 2023 13:36:19 +0000 (15:36 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 10 May 2023 13:36:19 +0000 (15:36 +0200)
ts/WoltLabSuite/Core/Component/Ckeditor.ts
ts/WoltLabSuite/Core/Component/Ckeditor/Cleanup.ts [deleted file]
ts/WoltLabSuite/Core/Component/Ckeditor/Normalizer.ts [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor.js
wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Cleanup.js [deleted file]
wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Normalizer.js [new file with mode: 0644]

index 9b7703e3a0b2fd03ad748ed2560e67fc92c9935c..b9cb225ffe65114f82053fb82d5c7f6ba050f84e 100644 (file)
@@ -20,7 +20,7 @@ import { deleteDraft, initializeAutosave, setupRestoreDraft } from "./Ckeditor/A
 import { createConfigurationFor, Features } from "./Ckeditor/Configuration";
 import { dispatchToCkeditor } from "./Ckeditor/Event";
 import { setup as setupSubmitOnEnter } from "./Ckeditor/SubmitOnEnter";
-import { normalizeLegacyMessage } from "./Ckeditor/Cleanup";
+import { normalizeLegacyMessage } from "./Ckeditor/Normalizer";
 import Devtools from "../Devtools";
 
 import { ClassicEditor, EditorConfig, Element as CkeElement } from "./Ckeditor/Types";
diff --git a/ts/WoltLabSuite/Core/Component/Ckeditor/Cleanup.ts b/ts/WoltLabSuite/Core/Component/Ckeditor/Cleanup.ts
deleted file mode 100644 (file)
index 9b6447c..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * Cleans up the markup of legacy messages.
- *
- * Messages created in the previous editor used empty paragraphs to create empty
- * lines. In addition, Firefox kept trailing <br> in lines with content, which
- * causes issues with CKEditor.
- *
- * @author Alexander Ebert
- * @copyright 2001-2023 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @since 6.0
- */
-
-import DomUtil from "../../Dom/Util";
-
-function normalizeBr(div: HTMLElement): void {
-  div.querySelectorAll("br").forEach((br) => {
-    unwrapBr(br);
-    removeTrailingBr(br);
-  });
-}
-
-function unwrapBr(br: HTMLElement): void {
-  for (;;) {
-    if (br.previousSibling || br.nextSibling) {
-      return;
-    }
-
-    const parent = br.parentElement!;
-    switch (parent.tagName) {
-      case "B":
-      case "DEL":
-      case "EM":
-      case "I":
-      case "STRONG":
-      case "SUB":
-      case "SUP":
-      case "SPAN":
-      case "U":
-        parent.insertAdjacentElement("afterend", br);
-        parent.remove();
-        break;
-
-      default:
-        return;
-    }
-  }
-}
-
-function removeTrailingBr(br: HTMLElement): void {
-  if (br.dataset.ckeFiller === "true") {
-    return;
-  }
-
-  const paragraphOrTableCell = br.closest("p, td");
-  if (paragraphOrTableCell === null) {
-    return;
-  }
-
-  if (!DomUtil.isAtNodeEnd(br, paragraphOrTableCell)) {
-    return;
-  }
-
-  if (paragraphOrTableCell.tagName === "TD" || paragraphOrTableCell.childNodes.length > 1) {
-    br.remove();
-  }
-}
-
-function getPossibleSpacerParagraphs(div: HTMLElement): HTMLParagraphElement[] {
-  const paragraphs: HTMLParagraphElement[] = [];
-
-  div.querySelectorAll("p").forEach((paragraph) => {
-    paragraph.normalize();
-
-    if (paragraph.childNodes.length === 1) {
-      const child = paragraph.childNodes[0];
-      if (child instanceof HTMLBRElement && child.dataset.ckeFiller !== "true") {
-        paragraphs.push(paragraph);
-      }
-    }
-  });
-
-  return paragraphs;
-}
-
-function reduceSpacerParagraphs(paragraphs: HTMLParagraphElement[]): void {
-  if (paragraphs.length === 0) {
-    return;
-  }
-
-  for (let i = 0, length = paragraphs.length; i < length; i++) {
-    const candidate = paragraphs[i];
-    let offset = 0;
-
-    // Searches for adjacent paragraphs.
-    while (i + offset + 1 < length) {
-      const nextCandidate = paragraphs[i + offset + 1];
-      if (candidate.nextElementSibling !== nextCandidate) {
-        break;
-      }
-
-      offset++;
-    }
-
-    if (offset === 0) {
-      // An offset of 0 means that this is a single paragraph and we
-      // can safely remove it.
-      candidate.remove();
-    } else {
-      // We need to reduce the number of paragraphs by half, unless it
-      // is an uneven number in which case we need to remove one
-      // additional paragraph.
-      const totalNumberOfParagraphs = offset + 1;
-      const numberOfParagraphsToRemove = Math.ceil(totalNumberOfParagraphs / 2);
-
-      const removeParagraphs = paragraphs.slice(i, i + numberOfParagraphsToRemove);
-      removeParagraphs.forEach((paragraph) => {
-        paragraph.remove();
-      });
-
-      i += offset;
-    }
-  }
-}
-
-export function normalizeLegacyMessage(element: HTMLElement): void {
-  if (!(element instanceof HTMLTextAreaElement)) {
-    throw new TypeError("Expected the element to be a <textarea>.");
-  }
-
-  const div = document.createElement("div");
-  div.innerHTML = element.value;
-
-  normalizeBr(div);
-  const paragraphs = getPossibleSpacerParagraphs(div);
-  reduceSpacerParagraphs(paragraphs);
-
-  element.value = div.innerHTML;
-}
diff --git a/ts/WoltLabSuite/Core/Component/Ckeditor/Normalizer.ts b/ts/WoltLabSuite/Core/Component/Ckeditor/Normalizer.ts
new file mode 100644 (file)
index 0000000..9b6447c
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Cleans up the markup of legacy messages.
+ *
+ * Messages created in the previous editor used empty paragraphs to create empty
+ * lines. In addition, Firefox kept trailing <br> in lines with content, which
+ * causes issues with CKEditor.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2023 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 6.0
+ */
+
+import DomUtil from "../../Dom/Util";
+
+function normalizeBr(div: HTMLElement): void {
+  div.querySelectorAll("br").forEach((br) => {
+    unwrapBr(br);
+    removeTrailingBr(br);
+  });
+}
+
+function unwrapBr(br: HTMLElement): void {
+  for (;;) {
+    if (br.previousSibling || br.nextSibling) {
+      return;
+    }
+
+    const parent = br.parentElement!;
+    switch (parent.tagName) {
+      case "B":
+      case "DEL":
+      case "EM":
+      case "I":
+      case "STRONG":
+      case "SUB":
+      case "SUP":
+      case "SPAN":
+      case "U":
+        parent.insertAdjacentElement("afterend", br);
+        parent.remove();
+        break;
+
+      default:
+        return;
+    }
+  }
+}
+
+function removeTrailingBr(br: HTMLElement): void {
+  if (br.dataset.ckeFiller === "true") {
+    return;
+  }
+
+  const paragraphOrTableCell = br.closest("p, td");
+  if (paragraphOrTableCell === null) {
+    return;
+  }
+
+  if (!DomUtil.isAtNodeEnd(br, paragraphOrTableCell)) {
+    return;
+  }
+
+  if (paragraphOrTableCell.tagName === "TD" || paragraphOrTableCell.childNodes.length > 1) {
+    br.remove();
+  }
+}
+
+function getPossibleSpacerParagraphs(div: HTMLElement): HTMLParagraphElement[] {
+  const paragraphs: HTMLParagraphElement[] = [];
+
+  div.querySelectorAll("p").forEach((paragraph) => {
+    paragraph.normalize();
+
+    if (paragraph.childNodes.length === 1) {
+      const child = paragraph.childNodes[0];
+      if (child instanceof HTMLBRElement && child.dataset.ckeFiller !== "true") {
+        paragraphs.push(paragraph);
+      }
+    }
+  });
+
+  return paragraphs;
+}
+
+function reduceSpacerParagraphs(paragraphs: HTMLParagraphElement[]): void {
+  if (paragraphs.length === 0) {
+    return;
+  }
+
+  for (let i = 0, length = paragraphs.length; i < length; i++) {
+    const candidate = paragraphs[i];
+    let offset = 0;
+
+    // Searches for adjacent paragraphs.
+    while (i + offset + 1 < length) {
+      const nextCandidate = paragraphs[i + offset + 1];
+      if (candidate.nextElementSibling !== nextCandidate) {
+        break;
+      }
+
+      offset++;
+    }
+
+    if (offset === 0) {
+      // An offset of 0 means that this is a single paragraph and we
+      // can safely remove it.
+      candidate.remove();
+    } else {
+      // We need to reduce the number of paragraphs by half, unless it
+      // is an uneven number in which case we need to remove one
+      // additional paragraph.
+      const totalNumberOfParagraphs = offset + 1;
+      const numberOfParagraphsToRemove = Math.ceil(totalNumberOfParagraphs / 2);
+
+      const removeParagraphs = paragraphs.slice(i, i + numberOfParagraphsToRemove);
+      removeParagraphs.forEach((paragraph) => {
+        paragraph.remove();
+      });
+
+      i += offset;
+    }
+  }
+}
+
+export function normalizeLegacyMessage(element: HTMLElement): void {
+  if (!(element instanceof HTMLTextAreaElement)) {
+    throw new TypeError("Expected the element to be a <textarea>.");
+  }
+
+  const div = document.createElement("div");
+  div.innerHTML = element.value;
+
+  normalizeBr(div);
+  const paragraphs = getPossibleSpacerParagraphs(div);
+  reduceSpacerParagraphs(paragraphs);
+
+  element.value = div.innerHTML;
+}
index d9d96090ed6adee99638d525e07f94c7457cb6b4..81c0ce2a29bf8c61a424353f42ff48fff3325174 100644 (file)
@@ -11,7 +11,7 @@
  * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @since 6.0
  */
-define(["require", "exports", "tslib", "./Ckeditor/Attachment", "./Ckeditor/Media", "./Ckeditor/Mention", "./Ckeditor/Quote", "./Ckeditor/Autosave", "./Ckeditor/Configuration", "./Ckeditor/Event", "./Ckeditor/SubmitOnEnter", "./Ckeditor/Cleanup", "../Devtools", "ckeditor5-bundle"], function (require, exports, tslib_1, Attachment_1, Media_1, Mention_1, Quote_1, Autosave_1, Configuration_1, Event_1, SubmitOnEnter_1, Cleanup_1, Devtools_1) {
+define(["require", "exports", "tslib", "./Ckeditor/Attachment", "./Ckeditor/Media", "./Ckeditor/Mention", "./Ckeditor/Quote", "./Ckeditor/Autosave", "./Ckeditor/Configuration", "./Ckeditor/Event", "./Ckeditor/SubmitOnEnter", "./Ckeditor/Normalizer", "../Devtools", "ckeditor5-bundle"], function (require, exports, tslib_1, Attachment_1, Media_1, Mention_1, Quote_1, Autosave_1, Configuration_1, Event_1, SubmitOnEnter_1, Normalizer_1, Devtools_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.getCkeditorById = exports.getCkeditor = exports.setupCkeditor = void 0;
@@ -140,7 +140,7 @@ define(["require", "exports", "tslib", "./Ckeditor/Attachment", "./Ckeditor/Medi
             (0, Quote_1.setup)(element);
         }
         const configuration = initializeConfiguration(element, features, bbcodes);
-        (0, Cleanup_1.normalizeLegacyMessage)(element);
+        (0, Normalizer_1.normalizeLegacyMessage)(element);
         const cke = await window.CKEditor5.create(element, configuration);
         const ckeditor = new Ckeditor(cke, features);
         if (features.autosave) {
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Cleanup.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Cleanup.js
deleted file mode 100644 (file)
index 46f0f41..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Cleans up the markup of legacy messages.
- *
- * Messages created in the previous editor used empty paragraphs to create empty
- * lines. In addition, Firefox kept trailing <br> in lines with content, which
- * causes issues with CKEditor.
- *
- * @author Alexander Ebert
- * @copyright 2001-2023 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @since 6.0
- */
-define(["require", "exports", "tslib", "../../Dom/Util"], function (require, exports, tslib_1, Util_1) {
-    "use strict";
-    Object.defineProperty(exports, "__esModule", { value: true });
-    exports.normalizeLegacyMessage = void 0;
-    Util_1 = tslib_1.__importDefault(Util_1);
-    function normalizeBr(div) {
-        div.querySelectorAll("br").forEach((br) => {
-            unwrapBr(br);
-            removeTrailingBr(br);
-        });
-    }
-    function unwrapBr(br) {
-        for (;;) {
-            if (br.previousSibling || br.nextSibling) {
-                return;
-            }
-            const parent = br.parentElement;
-            switch (parent.tagName) {
-                case "B":
-                case "DEL":
-                case "EM":
-                case "I":
-                case "STRONG":
-                case "SUB":
-                case "SUP":
-                case "SPAN":
-                case "U":
-                    parent.insertAdjacentElement("afterend", br);
-                    parent.remove();
-                    break;
-                default:
-                    return;
-            }
-        }
-    }
-    function removeTrailingBr(br) {
-        if (br.dataset.ckeFiller === "true") {
-            return;
-        }
-        const paragraphOrTableCell = br.closest("p, td");
-        if (paragraphOrTableCell === null) {
-            return;
-        }
-        if (!Util_1.default.isAtNodeEnd(br, paragraphOrTableCell)) {
-            return;
-        }
-        if (paragraphOrTableCell.tagName === "TD" || paragraphOrTableCell.childNodes.length > 1) {
-            br.remove();
-        }
-    }
-    function getPossibleSpacerParagraphs(div) {
-        const paragraphs = [];
-        div.querySelectorAll("p").forEach((paragraph) => {
-            paragraph.normalize();
-            if (paragraph.childNodes.length === 1) {
-                const child = paragraph.childNodes[0];
-                if (child instanceof HTMLBRElement && child.dataset.ckeFiller !== "true") {
-                    paragraphs.push(paragraph);
-                }
-            }
-        });
-        return paragraphs;
-    }
-    function reduceSpacerParagraphs(paragraphs) {
-        if (paragraphs.length === 0) {
-            return;
-        }
-        for (let i = 0, length = paragraphs.length; i < length; i++) {
-            const candidate = paragraphs[i];
-            let offset = 0;
-            // Searches for adjacent paragraphs.
-            while (i + offset + 1 < length) {
-                const nextCandidate = paragraphs[i + offset + 1];
-                if (candidate.nextElementSibling !== nextCandidate) {
-                    break;
-                }
-                offset++;
-            }
-            if (offset === 0) {
-                // An offset of 0 means that this is a single paragraph and we
-                // can safely remove it.
-                candidate.remove();
-            }
-            else {
-                // We need to reduce the number of paragraphs by half, unless it
-                // is an uneven number in which case we need to remove one
-                // additional paragraph.
-                const totalNumberOfParagraphs = offset + 1;
-                const numberOfParagraphsToRemove = Math.ceil(totalNumberOfParagraphs / 2);
-                const removeParagraphs = paragraphs.slice(i, i + numberOfParagraphsToRemove);
-                removeParagraphs.forEach((paragraph) => {
-                    paragraph.remove();
-                });
-                i += offset;
-            }
-        }
-    }
-    function normalizeLegacyMessage(element) {
-        if (!(element instanceof HTMLTextAreaElement)) {
-            throw new TypeError("Expected the element to be a <textarea>.");
-        }
-        const div = document.createElement("div");
-        div.innerHTML = element.value;
-        normalizeBr(div);
-        const paragraphs = getPossibleSpacerParagraphs(div);
-        reduceSpacerParagraphs(paragraphs);
-        element.value = div.innerHTML;
-    }
-    exports.normalizeLegacyMessage = normalizeLegacyMessage;
-});
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Normalizer.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Normalizer.js
new file mode 100644 (file)
index 0000000..46f0f41
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * Cleans up the markup of legacy messages.
+ *
+ * Messages created in the previous editor used empty paragraphs to create empty
+ * lines. In addition, Firefox kept trailing <br> in lines with content, which
+ * causes issues with CKEditor.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2023 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 6.0
+ */
+define(["require", "exports", "tslib", "../../Dom/Util"], function (require, exports, tslib_1, Util_1) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.normalizeLegacyMessage = void 0;
+    Util_1 = tslib_1.__importDefault(Util_1);
+    function normalizeBr(div) {
+        div.querySelectorAll("br").forEach((br) => {
+            unwrapBr(br);
+            removeTrailingBr(br);
+        });
+    }
+    function unwrapBr(br) {
+        for (;;) {
+            if (br.previousSibling || br.nextSibling) {
+                return;
+            }
+            const parent = br.parentElement;
+            switch (parent.tagName) {
+                case "B":
+                case "DEL":
+                case "EM":
+                case "I":
+                case "STRONG":
+                case "SUB":
+                case "SUP":
+                case "SPAN":
+                case "U":
+                    parent.insertAdjacentElement("afterend", br);
+                    parent.remove();
+                    break;
+                default:
+                    return;
+            }
+        }
+    }
+    function removeTrailingBr(br) {
+        if (br.dataset.ckeFiller === "true") {
+            return;
+        }
+        const paragraphOrTableCell = br.closest("p, td");
+        if (paragraphOrTableCell === null) {
+            return;
+        }
+        if (!Util_1.default.isAtNodeEnd(br, paragraphOrTableCell)) {
+            return;
+        }
+        if (paragraphOrTableCell.tagName === "TD" || paragraphOrTableCell.childNodes.length > 1) {
+            br.remove();
+        }
+    }
+    function getPossibleSpacerParagraphs(div) {
+        const paragraphs = [];
+        div.querySelectorAll("p").forEach((paragraph) => {
+            paragraph.normalize();
+            if (paragraph.childNodes.length === 1) {
+                const child = paragraph.childNodes[0];
+                if (child instanceof HTMLBRElement && child.dataset.ckeFiller !== "true") {
+                    paragraphs.push(paragraph);
+                }
+            }
+        });
+        return paragraphs;
+    }
+    function reduceSpacerParagraphs(paragraphs) {
+        if (paragraphs.length === 0) {
+            return;
+        }
+        for (let i = 0, length = paragraphs.length; i < length; i++) {
+            const candidate = paragraphs[i];
+            let offset = 0;
+            // Searches for adjacent paragraphs.
+            while (i + offset + 1 < length) {
+                const nextCandidate = paragraphs[i + offset + 1];
+                if (candidate.nextElementSibling !== nextCandidate) {
+                    break;
+                }
+                offset++;
+            }
+            if (offset === 0) {
+                // An offset of 0 means that this is a single paragraph and we
+                // can safely remove it.
+                candidate.remove();
+            }
+            else {
+                // We need to reduce the number of paragraphs by half, unless it
+                // is an uneven number in which case we need to remove one
+                // additional paragraph.
+                const totalNumberOfParagraphs = offset + 1;
+                const numberOfParagraphsToRemove = Math.ceil(totalNumberOfParagraphs / 2);
+                const removeParagraphs = paragraphs.slice(i, i + numberOfParagraphsToRemove);
+                removeParagraphs.forEach((paragraph) => {
+                    paragraph.remove();
+                });
+                i += offset;
+            }
+        }
+    }
+    function normalizeLegacyMessage(element) {
+        if (!(element instanceof HTMLTextAreaElement)) {
+            throw new TypeError("Expected the element to be a <textarea>.");
+        }
+        const div = document.createElement("div");
+        div.innerHTML = element.value;
+        normalizeBr(div);
+        const paragraphs = getPossibleSpacerParagraphs(div);
+        reduceSpacerParagraphs(paragraphs);
+        element.value = div.innerHTML;
+    }
+    exports.normalizeLegacyMessage = normalizeLegacyMessage;
+});