From f312e1359a30e451e33e57c5751fbe9724e85af4 Mon Sep 17 00:00:00 2001 From: David Monjoie Date: Thu, 30 Sep 2021 11:15:39 +0000 Subject: [PATCH] [FIX] web_editor: do not encode link text These encode/decode shenanigans seem to be unnecessary since we are not using summernote anymore. Moreover, the encode process was destroying the html structure of nodes contained in the link, only making a special case to maintain images. This is not sufficient anymore because the Cards option of website mega menu does make use of custom html content inside a link. This content was therefore destroyed on edition and replaced by its textContent because of the encode function. task-2652361 closes odoo/odoo#77654 X-original-commit: 80004b1819fa1e1e7cfdd03a285de9d4ee845356 Signed-off-by: Quentin Smetz (qsm) --- .../static/src/js/wysiwyg/widgets/link.js | 58 ++----------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/link.js b/addons/web_editor/static/src/js/wysiwyg/widgets/link.js index 3ee8ffab55f..3b8e4c29052 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/link.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/link.js @@ -80,11 +80,10 @@ const Link = Widget.extend({ } $node = $node.parent(); } - const textLink = this.$link[0] || this.data.range.cloneContents(); - const [encodedText, images] = this._encodeNodeToText(textLink); - this.data.originalText = this._decodeText(encodedText, images); - this.data.content = encodedText; - this.data.images = images; + const linkNode = this.$link[0] || this.data.range.cloneContents(); + const linkText = linkNode.innerHTML || linkNode.textContent; + this.data.content = linkText.replace(/[ \t\r\n]+/g, ' '); + this.data.originalText = this.data.content; this.data.url = this.$link.attr('href') || ''; } else { this.data.content = this.data.content ? this.data.content.replace(/[ \t\r\n]+/g, ' ') : ''; @@ -189,8 +188,8 @@ const Link = Widget.extend({ if (data.content !== this.data.originalText || data.url !== this.data.url) { const content = (data.content && data.content.length) ? data.content : data.url; // If there is a this.data.originalText, it means that we selected - // the text and we could not change the content through the text input. - // .html() is needed in case we selected images. + // the text and we could not change the content through the text + // input.html() is needed in case we selected rich html content. if (this.data.originalText) { this.$link.html(content); } else { @@ -261,23 +260,6 @@ const Link = Widget.extend({ } return url; }, - /** - * Take an HTML string and return an escape HTML string with each instance - * of the string "[IMG]" is replaced with the HTML from the given images - * respectively. - * - * @private - * @param {string} text - * @param {Node[]} images - * @returns {string} - */ - _decodeText: function (text, images = []) { - text = _.escape(text); - for (const img of images) { - text = text.replace(/\[IMG\]/, img.outerHTML); - } - return text; - }, /** * Abstract method: return true if the URL should be stripped of its domain. * @@ -286,33 +268,6 @@ const Link = Widget.extend({ * @returns {boolean} */ _doStripDomain: function () {}, - /** - * Take an element and return a tuple with its inner text where each image - * is replaced with the string "[IMG]", and a list of the replaced image - * elements. - * - * @param {Node} rootNode - * @returns {[string, Node[]]} - */ - _encodeNodeToText: function (rootNode) { - const fake = document.createElement('fake'); - for (const node of [...rootNode.cloneNode(true).childNodes]) { - fake.appendChild(node); - } - - const nodes = this._getDescendants(fake); - const images = []; - for (const node of nodes) { - if (wysiwygUtils.isImg(node)) { - node.before(document.createTextNode('[IMG]')); - node.remove(); - images.push(node); - } - } - - const text = fake.innerText.replace(/[ \t\r\n]+/g, ' '); - return [text, images]; - }, /** * Get the link's data (url, content and styles). * @@ -323,7 +278,6 @@ const Link = Widget.extend({ var $url = this.$('input[name="url"]'); var url = $url.val(); var content = this.$('input[name="label"]').val() || url; - content = this._decodeText(content, this.data.images); if (!this.isButton && $url.prop('required') && (!url || !$url[0].checkValidity())) { return null;