From 75166dbcd4962f30624fe19829757acbf8e76022 Mon Sep 17 00:00:00 2001 From: Benjamin Vray Date: Tue, 30 Aug 2022 13:44:23 +0000 Subject: [PATCH] [IMP] web_editor, website: adds label input to links in the editor panel This commit adds a new feature to the web editor of a website. A "text" input field has been added to the link editor panel, allowing users to edit the label of a link. The label will only be updated when the input is changed, to prevent loss of formatting (e.g. if one letter is bold). However, only formatting applied to the entire selection will be kept (e.g. if you have a "link like this", nothing will be in bold if you update the label in the editor panel). Additionally, if there is a media element (such as an image or icon) included in the selection, the "text" input will be hidden. task-2900529 closes odoo/odoo#99239 Signed-off-by: Benoit Socias (bso) --- .../static/src/js/wysiwyg/widgets/link.js | 16 ++++++---- .../src/js/wysiwyg/widgets/link_tools.js | 29 +++++++++++++++++-- .../static/src/js/wysiwyg/wysiwyg.js | 8 +++-- addons/web_editor/static/src/xml/wysiwyg.xml | 16 +++++----- .../website/static/tests/tours/link_tools.js | 25 +++++++++++++++- 5 files changed, 76 insertions(+), 18 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 5c881e71d0e..75b305c4b04 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/link.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/link.js @@ -31,8 +31,6 @@ const Link = Widget.extend({ title: _t("Link to"), }, this.options)); - this._setLinkContent = true; - this.data = data || {}; this.isButton = this.data.isButton; this.$button = $button; @@ -86,7 +84,7 @@ const Link = Widget.extend({ $node = $node.parent(); } const linkNode = this.$link[0] || this.data.range.cloneContents(); - const linkText = linkNode.textContent; + const linkText = linkNode.innerText; this.data.content = linkText.replace(/[ \t\r\n]+/g, ' '); this.data.originalText = this.data.content; if (linkNode instanceof DocumentFragment) { @@ -488,11 +486,19 @@ const Link = Widget.extend({ * @param {boolean} force */ _updateLinkContent($link, linkInfos, { force = false } = {}) { - if (force || (this._setLinkContent && (linkInfos.content !== this.data.originalText || linkInfos.url !== this.data.url))) { + if (force || (linkInfos.content !== this.data.originalText || linkInfos.url !== this.data.url)) { if (linkInfos.content === this.data.originalText) { $link.html(this.data.originalHTML); } else if (linkInfos.content && linkInfos.content.length) { - $link.text(linkInfos.content); + let contentWrapperEl = $link[0]; + // Update the first child element that has the same inner text + // as the link with the new content while preserving child + // elements within the link. (e.g. the link is bold and italic) + while (contentWrapperEl.firstElementChild + && (contentWrapperEl.firstElementChild.innerText === $link[0].innerText)) { + contentWrapperEl = contentWrapperEl.firstElementChild; + } + contentWrapperEl.innerText = linkInfos.content; } else { $link.text(linkInfos.url); } diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/link_tools.js b/addons/web_editor/static/src/js/wysiwyg/widgets/link_tools.js index b6cee090e9a..99160708d92 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/link_tools.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/link_tools.js @@ -23,6 +23,7 @@ const LinkTools = Link.extend({ 'change .link-custom-color-border input': '_onChangeCustomBorderWidth', 'keypress .link-custom-color-border input': '_onKeyPressCustomBorderWidth', 'click we-select [name="link_border_style"] we-button': '_onBorderStyleSelectOption', + 'input input[name="label"]': '_onLabelInput', }), /** @@ -31,8 +32,7 @@ const LinkTools = Link.extend({ init: function (parent, options, editable, data, $button, link) { this._link = link; this._observer = new MutationObserver(() =>{ - this._setLinkContent = false; - this._observer.disconnect(); + this._updateLabelInput(); }); this._observer.observe(this._link, {subtree: true, childList: true, characterData: true}); this._super(parent, options, editable, data, $button, this._link); @@ -358,6 +358,14 @@ const LinkTools = Link.extend({ this.$button.removeClass('active'); this.options.wysiwyg.odooEditor.observerActive("hint_classes"); }, + /** + * Updates the label input with the DOM content of the link. + * + * @private + */ + _updateLabelInput() { + this.el.querySelector('#o_link_dialog_label_input').value = this.linkEl.innerText; + }, //-------------------------------------------------------------------------- // Handlers @@ -440,6 +448,23 @@ const LinkTools = Link.extend({ this._adaptPreview(); this.options.wysiwyg.odooEditor.historyUnpauseSteps('_onURLInput'); }, + /** + * Updates the DOM content of the link with the input value. + * + * @private + * @param {Event} ev + */ + _onLabelInput(ev) { + const data = this._getData(); + if (!data) { + return; + } + this._observer.disconnect(); + // Force update of link's content with new data using 'force: true'. + // Without this, no update if input is same as original text. + this._updateLinkContent(this.$link, data, {force: true}); + this._observer.observe(this._link, {subtree: true, childList: true, characterData: true}); + }, }); return LinkTools; diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index e758e3b0cb2..0541879604c 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -1185,9 +1185,13 @@ const Wysiwyg = Widget.extend({ startNode: options.link || this.lastMediaClicked, }); if (!link) { - return + return; } - const linkToolsData = Object.assign({}, this.options.defaultDataForLinkTools); + const linkToolsData = Object.assign({}, this.options.defaultDataForLinkTools, { + // If the link contains an image or an icon do not + // display the label input (e.g. some mega menu links). + needLabel: !link.querySelector('.fa, img'), + }); this.linkTools = new weWidgets.LinkTools(this, { wysiwyg: this, noFocusUrl: options.noFocusUrl, diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index 2b92ae3a0ac..3030b377ea6 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -184,14 +184,6 @@ - - Link Label - -
- -
-
-
@@ -208,6 +200,14 @@ + + Label + +
+ +
+
+
Style diff --git a/addons/website/static/tests/tours/link_tools.js b/addons/website/static/tests/tours/link_tools.js index f365c6a477a..0ccdcd45186 100644 --- a/addons/website/static/tests/tours/link_tools.js +++ b/addons/website/static/tests/tours/link_tools.js @@ -34,10 +34,33 @@ wTourUtils.registerWebsitePreviewTour('link_tools', { clickOnImgStep, // 2. Edit the link with the link tools. { - content: "Click on the newly created link, change content to odoo website", + content: "Click on the newly created link", trigger: 'iframe .s_text_image a[href="http://odoo.com"]:contains("odoo.com")', + }, + { + content: "Change content (editing the label input) to odoo website_2", + trigger: '#o_link_dialog_label_input[value="odoo.com"]', + run: 'text odoo website_2', + }, + { + content: "Click again on the link", + trigger: 'iframe .s_text_image a[href="http://odoo.com"]:contains("odoo website_2")', + }, + { + content: "Change content (editing the DOM) to odoo website", + trigger: 'iframe .s_text_image a[href="http://odoo.com"]:contains("odoo website_2")', run: 'text odoo website', }, + clickOnImgStep, + { + content: "Click again on the link", + trigger: 'iframe .s_text_image a[href="http://odoo.com"]:contains("odoo website")', + }, + { + content: "Check that the label input contains the new content", + trigger: '#o_link_dialog_label_input[value="odoo website"]', + run: () => null, // it's a check + }, { content: "Link tools, should be open, change the url", trigger: '#o_link_dialog_url_input',