05292f29e4c5dbdf30ad35ad9a67f9279119c7cd
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / WoltLabSuite / Core / Ui / Redactor / Metacode.js
1 /**
2 * Converts `<woltlab-metacode>` into the bbcode representation.
3 *
4 * @author Alexander Ebert
5 * @copyright 2001-2019 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Ui/Redactor/Metacode
8 * @woltlabExcludeBundle tiny
9 */
10 define(["require", "exports", "tslib", "../../Event/Handler", "../../Dom/Util", "../../StringUtil"], function (require, exports, tslib_1, EventHandler, Util_1, StringUtil) {
11 "use strict";
12 Object.defineProperty(exports, "__esModule", { value: true });
13 exports.convertFromHtml = void 0;
14 EventHandler = tslib_1.__importStar(EventHandler);
15 Util_1 = tslib_1.__importDefault(Util_1);
16 StringUtil = tslib_1.__importStar(StringUtil);
17 /**
18 * Returns a text node representing the opening bbcode tag.
19 */
20 function getOpeningTag(name, attributes) {
21 let buffer = "[" + name;
22 if (attributes.length) {
23 buffer += "=";
24 buffer += attributes
25 .map((attribute) => StringUtil.unescapeHTML(attribute))
26 .map((attribute) => `'${attribute}'`)
27 .join(",");
28 }
29 return document.createTextNode(buffer + "]");
30 }
31 /**
32 * Returns a text node representing the closing bbcode tag.
33 */
34 function getClosingTag(name) {
35 return document.createTextNode(`[/${name}]`);
36 }
37 /**
38 * Returns the first paragraph of provided element. If there are no children or
39 * the first child is not a paragraph, a new paragraph is created and inserted
40 * as first child.
41 */
42 function getFirstParagraph(element) {
43 let paragraph;
44 if (element.childElementCount === 0) {
45 paragraph = document.createElement("p");
46 element.appendChild(paragraph);
47 }
48 else {
49 const firstChild = element.children[0];
50 if (firstChild.nodeName === "P") {
51 paragraph = firstChild;
52 }
53 else {
54 paragraph = document.createElement("p");
55 element.insertBefore(paragraph, firstChild);
56 }
57 }
58 return paragraph;
59 }
60 /**
61 * Returns the last paragraph of provided element. If there are no children or
62 * the last child is not a paragraph, a new paragraph is created and inserted
63 * as last child.
64 */
65 function getLastParagraph(element) {
66 const count = element.childElementCount;
67 let paragraph;
68 if (count === 0) {
69 paragraph = document.createElement("p");
70 element.appendChild(paragraph);
71 }
72 else {
73 const lastChild = element.children[count - 1];
74 if (lastChild.nodeName === "P") {
75 paragraph = lastChild;
76 }
77 else {
78 paragraph = document.createElement("p");
79 element.appendChild(paragraph);
80 }
81 }
82 return paragraph;
83 }
84 /**
85 * Parses the attributes string.
86 */
87 function parseAttributes(attributes) {
88 try {
89 attributes = JSON.parse(atob(attributes));
90 }
91 catch (e) {
92 /* invalid base64 data or invalid json */
93 }
94 if (!Array.isArray(attributes)) {
95 return [];
96 }
97 return attributes.map((attribute) => {
98 return attribute.toString().replace(/^'(.*)'$/, "$1");
99 });
100 }
101 function convertFromHtml(editorId, html) {
102 const div = document.createElement("div");
103 div.innerHTML = html;
104 div.querySelectorAll("woltlab-metacode").forEach((metacode) => {
105 const name = metacode.dataset.name;
106 const attributes = parseAttributes(metacode.dataset.attributes || "");
107 const data = {
108 attributes: attributes,
109 cancel: false,
110 metacode: metacode,
111 };
112 EventHandler.fire("com.woltlab.wcf.redactor2", `metacode_${name}_${editorId}`, data);
113 if (data.cancel) {
114 return;
115 }
116 const tagOpen = getOpeningTag(name, attributes);
117 const tagClose = getClosingTag(name);
118 if (metacode.parentElement === div) {
119 const paragraph = getFirstParagraph(metacode);
120 paragraph.insertBefore(tagOpen, paragraph.firstChild);
121 getLastParagraph(metacode).appendChild(tagClose);
122 }
123 else {
124 metacode.insertBefore(tagOpen, metacode.firstChild);
125 metacode.appendChild(tagClose);
126 }
127 Util_1.default.unwrapChildNodes(metacode);
128 });
129 // convert `<kbd>…</kbd>` to `[tt]…[/tt]`
130 div.querySelectorAll("kbd").forEach((inlineCode) => {
131 inlineCode.insertBefore(document.createTextNode("[tt]"), inlineCode.firstChild);
132 inlineCode.appendChild(document.createTextNode("[/tt]"));
133 Util_1.default.unwrapChildNodes(inlineCode);
134 });
135 return div.innerHTML;
136 }
137 exports.convertFromHtml = convertFromHtml;
138 });