summaryrefslogtreecommitdiff
path: root/addons/website/static/src/js/editor/snippets.options.js
diff options
context:
space:
mode:
authorSamuel Degueldre <sad@odoo.com>2019-10-18 09:06:09 +0000
committerqsm-odoo <qsm@odoo.com>2019-11-18 09:56:08 +0000
commitf615cfda89dae2e9a550d25868b11bc06b97cfcb (patch)
tree03a13d7a551ffd5bab684a72ad4692f45877dd35 /addons/website/static/src/js/editor/snippets.options.js
parentbf5b4b69330747af7b09d48e59218b78a29a4b14 (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/js/editor/snippets.options.js')
-rw-r--r--addons/website/static/src/js/editor/snippets.options.js73
1 files changed, 56 insertions, 17 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, '-'));
+ },
});
/**