diff options
| author | Samuel Degueldre <sad@odoo.com> | 2019-10-18 09:06:09 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2019-11-18 09:56:08 +0000 |
| commit | f615cfda89dae2e9a550d25868b11bc06b97cfcb (patch) | |
| tree | 03a13d7a551ffd5bab684a72ad4692f45877dd35 /addons/website/static/src | |
| parent | bf5b4b69330747af7b09d48e59218b78a29a4b14 (diff) | |
[IMP] website, *: rework snippet anchor system
* web_editor
Previously, the user could choose their anchor names using a modal
window, anchor names also have weird rules, this was not a great user
experience.
This commit makes the anchor button generate anchors automatically based
on the first title in a section, or the snippet name if there are none.
If the anchor name is already taken, it is suffixed by a number. After
it has been generated, it is also copied to the clipboard and the user
is shown a toast to tell them the anchor has been generated and copied.
The anchor is displayed in the toast along with an edit button that will
open the same edition modal as previously, but it is now less
restrictive.
Part of https://github.com/odoo/odoo/pull/38959
maintask-2066614
task-2088270
Diffstat (limited to 'addons/website/static/src')
| -rw-r--r-- | addons/website/static/src/js/editor/snippets.options.js | 73 | ||||
| -rw-r--r-- | addons/website/static/src/xml/website.editor.xml | 1 |
2 files changed, 56 insertions, 18 deletions
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index c3ea729d28d..cb94093c731 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -1547,7 +1547,7 @@ options.registry.topMenuColor = options.registry.colorpicker.extend({ /** * Handles the edition of snippet's anchor name. */ -options.registry.anchorName = options.Class.extend({ +options.registry.anchor = options.Class.extend({ xmlDependencies: ['/website/static/src/xml/website.editor.xml'], //-------------------------------------------------------------------------- @@ -1557,6 +1557,24 @@ options.registry.anchorName = options.Class.extend({ /** * @override */ + start: function () { + // Generate anchor and copy it to clipboard on click, show the tooltip on success + this.$button = this.$el.find('we-button'); + const clipboard = new ClipboardJS(this.$button[0], {text: () => this._getAnchorLink()}); + clipboard.on('success', () => { + const anchor = decodeURIComponent(this._getAnchorLink()); + this.displayNotification({ + title: _t("Copied !"), + message: _.str.sprintf(_t("The anchor has been copied to your clipboard.<br>Link: %s"), anchor), + buttons: [{text: _t("edit"), click: () => this.openAnchorDialog()}], + }); + }); + + return this._super.apply(this, arguments); + }, + /** + * @override + */ isTopOption: function () { return true; }, @@ -1568,20 +1586,19 @@ options.registry.anchorName = options.Class.extend({ }, //-------------------------------------------------------------------------- - // Options + // Private //-------------------------------------------------------------------------- - /** * @see this.selectClass for parameters */ openAnchorDialog: function (previewMode, value, $opt) { var self = this; var buttons = [{ - text: _t("Save"), + text: _t("Save & copy"), classes: 'btn-primary', click: function () { var $input = this.$('.o_input_anchor_name'); - var anchorName = $input.val().trim().replace(/\s/g, '_'); + var anchorName = self._text2Anchor($input.val()); if (self.$target[0].id === anchorName) { // If the chosen anchor name is already the one used by the // element, close the dialog and do nothing else @@ -1589,15 +1606,13 @@ options.registry.anchorName = options.Class.extend({ return; } - var isValid = /^[\w-]+$/.test(anchorName); - var alreadyExists = isValid && $('#' + anchorName).length > 0; - var anchorOK = isValid && !alreadyExists; - this.$('.o_anchor_not_valid').toggleClass('d-none', isValid); + const alreadyExists = !!document.getElementById(anchorName); this.$('.o_anchor_already_exists').toggleClass('d-none', !alreadyExists); - $input.toggleClass('is-invalid', !anchorOK); - if (anchorOK) { + $input.toggleClass('is-invalid', alreadyExists); + if (!alreadyExists) { self._setAnchorName(anchorName); this.close(); + self.$button[0].click(); } }, }, { @@ -1618,16 +1633,11 @@ options.registry.anchorName = options.Class.extend({ new Dialog(this, { title: _t("Link Anchor"), $content: $(qweb.render('website.dialog.anchorName', { - currentAnchor: this.$target.attr('id'), + currentAnchor: decodeURIComponent(this.$target.attr('id')), })), buttons: buttons, }).open(); }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - /** * @private * @param {String} value @@ -1643,6 +1653,35 @@ options.registry.anchorName = options.Class.extend({ } this.$target.trigger('content_changed'); }, + /** + * Returns anchor text. + * + * @private + * @returns {string} + */ + _getAnchorLink: function () { + if (!this.$target[0].id) { + const $titles = this.$target.find('h1, h2, h3, h4, h5, h6'); + const title = $titles.length > 0 ? $titles[0].innerText : this.data.snippetName; + const anchorName = this._text2Anchor(title); + let n = ''; + while (document.getElementById(anchorName + n)) { + n = (n || 1) + 1; + } + this._setAnchorName(anchorName + n); + } + return `#${this.$target[0].id}`; + }, + /** + * Creates a safe id/anchor from text. + * + * @private + * @param {string} text + * @returns {string} + */ + _text2Anchor: function (text) { + return encodeURIComponent(text.trim().replace(/\s+/g, '-')); + }, }); /** diff --git a/addons/website/static/src/xml/website.editor.xml b/addons/website/static/src/xml/website.editor.xml index 9f8a2e302fc..31ffb28704d 100644 --- a/addons/website/static/src/xml/website.editor.xml +++ b/addons/website/static/src/xml/website.editor.xml @@ -115,7 +115,6 @@ <div class="col-md-9"> <input type="text" class="form-control o_input_anchor_name" id="anchorName" t-attf-value="#{currentAnchor}" placeholder="Anchor name"/> <div class="invalid-feedback"> - <p class="d-none o_anchor_not_valid">The chosen name is not valid (use only a-Z A-Z 0-9 - _)</p> <p class="d-none o_anchor_already_exists">The chosen name already exists</p> </div> </div> |
