summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2019-11-22 10:49:57 +0000
committerqsm-odoo <qsm@odoo.com>2019-12-01 15:49:57 +0000
commit3be9ae5672f76f85cd747f57539e7bc2919850f8 (patch)
treed8ae6bd1a102c98ddf7c3524a50be2d1fa0367b6
parentfdac73e99d6edce1544c25534f8903c637a5507e (diff)
[IMP] web_editor, *: automatically update snippet option UI on focus
* website, website_blog, website_sale Some snippet option already needed to implement this by themself and now that they use custom widget, this is even more needed. The long-term goal is that developers should not have to override the onFocus method or the updateUI method but only the _computeWidgetState method. Part of https://github.com/odoo/odoo/pull/40282 In preparation of task-2122935 and other tasks
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.editor.js1
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.options.js158
-rw-r--r--addons/website/static/src/js/editor/snippets.options.js123
-rw-r--r--addons/website_blog/static/src/js/s_latest_posts_editor.js1
-rw-r--r--addons/website_blog/static/src/js/website_blog.editor.js2
-rw-r--r--addons/website_sale/static/src/js/website_sale.editor.js37
6 files changed, 170 insertions, 152 deletions
diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js
index 693eaf4001b..ca9615f6e0f 100644
--- a/addons/web_editor/static/src/js/editor/snippets.editor.js
+++ b/addons/web_editor/static/src/js/editor/snippets.editor.js
@@ -319,6 +319,7 @@ var SnippetEditor = Widget.extend({
var styles = _.values(editor.styles);
_.sortBy(styles, '__order').forEach(style => {
if (show) {
+ style.updateUI();
style.onFocus();
} else {
style.onBlur();
diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index 6da88c2247a..81591af81a2 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -828,7 +828,7 @@ const MultiUserValueWidget = UserValueWidget.extend({
},
});
-const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ // FIXME should be reloaded on focus
+const ColorpickerUserValueWidget = SelectUserValueWidget.extend({
custom_events: {
'color_picked': '_onColorPicked',
'color_hover': '_onColorHovered',
@@ -1054,16 +1054,6 @@ const SnippetOptionWidget = Widget.extend({
this.uiFragment = null;
},
/**
- * Called when the option is initialized (i.e. the parent edition overlay is
- * shown for the first time).
- *
- * @override
- */
- start: async function () {
- await this._updateUI();
- return this._super.apply(this, arguments);
- },
- /**
* Called when the parent edition overlay is covering the associated snippet
* (the first time, this follows the call to the @see start method).
*
@@ -1308,9 +1298,38 @@ const SnippetOptionWidget = Widget.extend({
*/
setTarget: async function ($target) {
this.$target = $target;
- await this._updateUI();
+ await this.updateUI();
this.$target.trigger('snippet-option-change', [this]);
},
+ /**
+ * Updates the UI. For widget update, @see _computeWidgetState.
+ *
+ * @param {function} [callback] - used to filter widgets to update
+ * @returns {Promise}
+ */
+ updateUI: async function (callback) {
+ // For each widget, for each of their option method, notify to the
+ // widget the current value they should hold according to the $target's
+ // current state, related for that method.
+ const proms = this._userValueWidgets.map(async widget => {
+ if (callback && !callback(widget)) {
+ return;
+ }
+
+ const methodsNames = widget.getMethodsNames();
+ const proms = methodsNames.map(async methodName => {
+ const value = await this._computeWidgetState(methodName, widget.getMethodsParams(methodName));
+ const normalizedValue = this._normalizeWidgetValue(value);
+ widget.setValue(normalizedValue, methodName);
+ });
+ await Promise.all(proms);
+
+ // Refresh the UI of all widgets (after all the current values they
+ // hold have been updated).
+ return widget.updateUI();
+ });
+ return Promise.all(proms);
+ },
//--------------------------------------------------------------------------
// Private
@@ -1467,7 +1486,6 @@ const SnippetOptionWidget = Widget.extend({
return uiFragment;
},
-
/**
* @private
* @param {HTMLElement} parentEl
@@ -1513,7 +1531,7 @@ const SnippetOptionWidget = Widget.extend({
return this._renderOriginalXML($xml).then(uiFragment => {
this.$el.append(uiFragment);
- return this._updateUI();
+ return this.updateUI();
});
},
/**
@@ -1544,42 +1562,13 @@ const SnippetOptionWidget = Widget.extend({
});
if (!previewMode) {
- await this._updateUI(w => !w.isPreviewed() || w === widget);
+ await this.updateUI(w => !w.isPreviewed() || w === widget);
} else {
- await this._updateUI(w => w !== widget && !w.isPreviewed());
+ await this.updateUI(w => w !== widget && !w.isPreviewed());
}
this.$target.trigger('content_changed');
},
- /**
- * Updates the UI. For widget update, @see _computeWidgetState.
- *
- * @param {function} [callback] - used to filter widgets to update
- * @returns {Promise}
- */
- _updateUI: async function (callback) {
- // For each widget, for each of their option method, notify to the
- // widget the current value they should hold according to the $target's
- // current state, related for that method.
- const proms = this._userValueWidgets.map(async widget => {
- if (callback && !callback(widget)) {
- return;
- }
-
- const methodsNames = widget.getMethodsNames();
- const proms = methodsNames.map(async methodName => {
- const value = await this._computeWidgetState(methodName, widget.getMethodsParams(methodName));
- const normalizedValue = this._normalizeWidgetValue(value);
- widget.setValue(normalizedValue, methodName);
- });
- await Promise.all(proms);
-
- // Refresh the UI of all widgets (after all the current values they
- // hold have been updated).
- return widget.updateUI();
- });
- return Promise.all(proms);
- },
//--------------------------------------------------------------------------
// Handlers
@@ -1748,11 +1737,6 @@ registry.sizing = SnippetOptionWidget.extend({
* @override
*/
onFocus: function () {
- var resizeValues = this._getSize();
- _.each(resizeValues, (value, key) => {
- this.$handles.filter('.' + key).toggleClass('readonly', !value);
- });
-
this._onResize();
},
/**
@@ -1773,6 +1757,16 @@ registry.sizing = SnippetOptionWidget.extend({
await this._super(...arguments);
this._onResize();
},
+ /**
+ * @override
+ */
+ updateUI: function () {
+ this._super(...arguments);
+ const resizeValues = this._getSize();
+ _.each(resizeValues, (value, key) => {
+ this.$handles.filter('.' + key).toggleClass('readonly', !value);
+ });
+ },
//--------------------------------------------------------------------------
// Private
@@ -1968,6 +1962,20 @@ registry.background = SnippetOptionWidget.extend({
this.bindBackgroundEvents();
this.__customImageSrc = this._getSrcFromCssValue();
},
+ /**
+ * @override
+ */
+ updateUI: async function () {
+ await this._super(...arguments);
+ var src = this._getSrcFromCssValue();
+ this.removeBgWidget.el.classList.toggle('d-none', !src);
+ if (src) {
+ var split = src.split('/');
+ this.editBgTextEl.textContent = split[split.length - 1];
+ } else {
+ this.editBgTextEl.textContent = this._getDefaultTextContent();
+ }
+ },
//--------------------------------------------------------------------------
// Private
@@ -2029,20 +2037,6 @@ registry.background = SnippetOptionWidget.extend({
/**
* @override
*/
- _updateUI: async function () {
- await this._super.apply(this, arguments);
- var src = this._getSrcFromCssValue();
- this.removeBgWidget.el.classList.toggle('d-none', !src);
- if (src) {
- var split = src.split('/');
- this.editBgTextEl.textContent = split[split.length - 1];
- } else {
- this.editBgTextEl.textContent = this._getDefaultTextContent();
- }
- },
- /**
- * @override
- */
_renderCustomWidgets: async function (uiFragment) {
// Build option UI controls
this.editBgTextEl = document.createElement('span');
@@ -2082,7 +2076,7 @@ registry.background = SnippetOptionWidget.extend({
this.__customImageSrc = value;
this.background(false, this.__customImageSrc, {});
this.$target.toggleClass('oe_custom_bg', !!value);
- await this._updateUI();
+ await this.updateUI();
this.$target.trigger('snippet-option-change', [this]);
},
@@ -2142,7 +2136,7 @@ registry.BackgroundPosition = SnippetOptionWidget.extend({
this.$target.on('snippet-option-change', () => {
// Hides option if the bg image is removed in favor of a bg color
- this._updateUI();
+ this.updateUI();
// this.img is used to compute dragging speed
this.img.src = this._getSrcFromCssValue();
});
@@ -2160,12 +2154,6 @@ registry.BackgroundPosition = SnippetOptionWidget.extend({
$(window).off('.bgposition');
this._super.apply(this, arguments);
},
- /**
- * @override
- */
- onFocus: function () {
- this._updateUI();
- },
//--------------------------------------------------------------------------
// Options
@@ -2212,6 +2200,21 @@ registry.BackgroundPosition = SnippetOptionWidget.extend({
},
//--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+ /**
+ * Disables background position if no background image, disables size inputs
+ * in cover mode.
+ *
+ * @override
+ */
+ updateUI: async function () {
+ await this._super(...arguments);
+ this.$el.toggleClass('d-none', this.$target.css('background-image') === 'none');
+ this.$el.find('we-input').toggleClass('d-none', this.$target.css('background-repeat') !== 'repeat');
+ },
+
+ //--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -2318,17 +2321,6 @@ registry.BackgroundPosition = SnippetOptionWidget.extend({
window.setTimeout(() => $(document).on('click.bgposition', this._onDocumentClicked.bind(this)), 0);
},
/**
- * Disables background position if no background image, disables size inputs
- * in cover mode.
- *
- * @override
- */
- _updateUI: async function () {
- await this._super.apply(this, arguments);
- this.$el.toggleClass('d-none', this.$target.css('background-image') === 'none');
- this.$el.find('we-input').toggleClass('d-none', this.$target.css('background-repeat') !== 'repeat');
- },
- /**
* Returns the src value from a css value related to a background image
* (e.g. "url('blabla')" => "blabla" / "none" => "").
*
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index d38744d3192..e13a6715c14 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -107,7 +107,7 @@ options.registry.background.include({
delete target.dataset.bgVideoSrc;
}
this._refreshPublicWidgets();
- await this._updateUI();
+ await this.updateUI();
},
/**
* Returns whether the current target has a background video or not.
@@ -350,12 +350,18 @@ options.registry.CarouselItem = options.Class.extend({
this._super(...arguments);
this.$carousel.off('.carousel_item_option');
},
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
/**
* Updates the slide counter.
*
* @override
*/
- onFocus: function () {
+ updateUI: function () {
+ this._super(...arguments);
const $items = this.$carousel.find('.carousel-item');
const $activeSlide = $items.filter('.active');
const updatedText = ` (${$activeSlide.index() + 1}/${$items.length})`;
@@ -483,12 +489,24 @@ options.registry.navTabs = options.Class.extend({
$activeLink.parent().remove();
$activePane.remove();
self._findLinksAndPanes();
- self._updateUI(); // TODO forced to do this because we do not return deferred for options
+ self.updateUI(); // TODO forced to do this because we do not return deferred for options
});
$next.tab('show');
},
//--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ updateUI: async function () {
+ await this._super(...arguments);
+ this.$el.filter('[data-remove-tab]').toggleClass('d-none', this.$tabPanes.length <= 2);
+ },
+
+ //--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -522,14 +540,6 @@ options.registry.navTabs = options.Class.extend({
});
}
},
- /**
- * @private
- * @override
- */
- _updateUI: async function () {
- await this._super.apply(this, arguments);
- this.$el.filter('[data-remove-tab]').toggleClass('d-none', this.$tabPanes.length <= 2);
- },
});
options.registry.sizing_x = options.registry.sizing.extend({
@@ -1120,7 +1130,7 @@ options.registry.gallery = options.Class.extend({
}
this.mode('reset', this.getMode());
this.trigger_up('cover_update');
- this._updateUI();
+ this.updateUI();
});
dialog.open();
},
@@ -1352,6 +1362,21 @@ options.registry.gallery = options.Class.extend({
this.mode('reset', this.getMode());
}
},
+ /**
+ * @override
+ */
+ updateUI: async function () {
+ await this._super(...arguments);
+
+ this.$el.find('[data-interval]').closest('we-select')[0]
+ .classList.toggle('d-none', this.activeMode !== 'slideshow');
+
+ this.$el.find('[data-columns]').closest('we-select')[0]
+ .classList.toggle('d-none', !(this.activeMode === 'grid' || this.activeMode === 'masonry'));
+
+ this.el.querySelector('.o_w_image_spacing_option')
+ .classList.toggle('d-none', this.activeMode === 'slideshow');
+ },
//--------------------------------------------------------------------------
// Private
@@ -1440,21 +1465,6 @@ options.registry.gallery = options.Class.extend({
$container.empty().append($content);
return $container;
},
- /**
- * @override
- */
- _updateUI: async function () {
- await this._super(...arguments);
-
- this.$el.find('[data-interval]').closest('we-select')[0]
- .classList.toggle('d-none', this.activeMode !== 'slideshow');
-
- this.$el.find('[data-columns]').closest('we-select')[0]
- .classList.toggle('d-none', !(this.activeMode === 'grid' || this.activeMode === 'masonry'));
-
- this.el.querySelector('.o_w_image_spacing_option')
- .classList.toggle('d-none', this.activeMode === 'slideshow');
- },
});
options.registry.gallery_img = options.Class.extend({
@@ -1553,10 +1563,16 @@ options.registry.topMenuColor = options.Class.extend({
});
return def;
},
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
/**
* @override
*/
- onFocus: function () {
+ updateUI: function () {
+ this._super(...arguments);
this.trigger_up('action_demand', {
actionName: 'get_page_option',
params: ['header_overlay'],
@@ -1779,7 +1795,7 @@ options.registry.CoverProperties = options.Class.extend({
if (!this.$target.hasClass('o_record_has_cover')) {
this.$el.find('.o_record_cover_opt_size_default[data-select-class]').click();
}
- this._updateUI();
+ this.updateUI();
});
},
/**
@@ -1804,33 +1820,13 @@ options.registry.CoverProperties = options.Class.extend({
},
//--------------------------------------------------------------------------
- // Private
+ // Public
//--------------------------------------------------------------------------
/**
- * @override
- */
- _computeWidgetState: function (methodName, params) {
- switch (methodName) {
- case 'filterValue': {
- return parseFloat(this.$filter.css('opacity')).toFixed(1);
- }
- case 'filterColor': {
- const classes = this.filterColorClasses.split(' ');
- for (const className of classes) {
- if (this.$filter.hasClass(className)) {
- return className;
- }
- }
- return '';
- }
- }
- return this._super(...arguments);
- },
- /**
* @private
*/
- _updateUI: async function () {
+ updateUI: async function () {
await this._super(...arguments);
// Only show options which are useful to the current cover
@@ -1859,6 +1855,31 @@ options.registry.CoverProperties = options.Class.extend({
this.$target[0].dataset.filterValue = this.$filterValueOpts.filter('.active').data('filterValue') || 0.0;
this.$target[0].dataset.filterColor = this.$filterColorOpts.filter('.active').data('filterColor') || '';
},
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _computeWidgetState: function (methodName, params) {
+ switch (methodName) {
+ case 'filterValue': {
+ return parseFloat(this.$filter.css('opacity')).toFixed(1);
+ }
+ case 'filterColor': {
+ const classes = this.filterColorClasses.split(' ');
+ for (const className of classes) {
+ if (this.$filter.hasClass(className)) {
+ return className;
+ }
+ }
+ return '';
+ }
+ }
+ return this._super(...arguments);
+ },
});
/**
diff --git a/addons/website_blog/static/src/js/s_latest_posts_editor.js b/addons/website_blog/static/src/js/s_latest_posts_editor.js
index af6235f2e98..e70c4041e6d 100644
--- a/addons/website_blog/static/src/js/s_latest_posts_editor.js
+++ b/addons/website_blog/static/src/js/s_latest_posts_editor.js
@@ -26,7 +26,6 @@ sOptions.registry.js_get_posts_selectBlog = sOptions.Class.extend({
el.textContent = blog.name;
menuEl.appendChild(el);
}
- return this._updateUI();
});
},
});
diff --git a/addons/website_blog/static/src/js/website_blog.editor.js b/addons/website_blog/static/src/js/website_blog.editor.js
index a066451e764..2fdc791cbc9 100644
--- a/addons/website_blog/static/src/js/website_blog.editor.js
+++ b/addons/website_blog/static/src/js/website_blog.editor.js
@@ -111,7 +111,7 @@ options.registry.CoverProperties.include({
/**
* @override
*/
- _updateUI: async function () {
+ updateUI: async function () {
await this._super(...arguments);
var isRegularCover = this.$target.is('.o_wblog_post_page_cover_regular');
var $coverFull = this.$el.find('[data-select-class*="cover_full"]');
diff --git a/addons/website_sale/static/src/js/website_sale.editor.js b/addons/website_sale/static/src/js/website_sale.editor.js
index bbcca2baf74..7e52f53dc04 100644
--- a/addons/website_sale/static/src/js/website_sale.editor.js
+++ b/addons/website_sale/static/src/js/website_sale.editor.js
@@ -215,6 +215,27 @@ options.registry.WebsiteSaleProductsItem = options.Class.extend({
},
//--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ updateUI: async function () {
+ await this._super.apply(this, arguments);
+
+ var sizeX = parseInt(this.$target.attr('colspan') || 1);
+ var sizeY = parseInt(this.$target.attr('rowspan') || 1);
+
+ var $size = this.$el.find('.o_wsale_soptions_menu_sizes');
+ $size.find('tr:nth-child(-n + ' + sizeY + ') td:nth-child(-n + ' + sizeX + ')')
+ .addClass('selected');
+
+ // Adapt size array preview to fit ppr
+ $size.find('tr td:nth-child(n + ' + parseInt(this.ppr + 1) + ')').hide();
+ },
+
+ //--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -244,22 +265,6 @@ options.registry.WebsiteSaleProductsItem = options.Class.extend({
}
});
},
- /**
- * @override
- */
- _updateUI: async function () {
- await this._super.apply(this, arguments);
-
- var sizeX = parseInt(this.$target.attr('colspan') || 1);
- var sizeY = parseInt(this.$target.attr('rowspan') || 1);
-
- var $size = this.$el.find('.o_wsale_soptions_menu_sizes');
- $size.find('tr:nth-child(-n + ' + sizeY + ') td:nth-child(-n + ' + sizeX + ')')
- .addClass('selected');
-
- // Adapt size array preview to fit ppr
- $size.find('tr td:nth-child(n + ' + parseInt(this.ppr + 1) + ')').hide();
- },
//--------------------------------------------------------------------------
// Handlers