summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/editor/snippets.options.js
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2020-08-22 15:02:21 +0000
committerqsm-odoo <qsm@odoo.com>2020-08-22 16:50:55 +0000
commitd9c450ac97de40c71aebd487cff725bfda6a577b (patch)
tree8d7d2793c5796ecc3518c792b3fcad5b59cf9e12 /addons/web_editor/static/src/js/editor/snippets.options.js
parent95239e523b194777b58e8dd9a409a93404b44c6d (diff)
[IMP] web_editor, website: introduce foldable zones in the editor UI
Now any set of widgets and rows can be placed in a we-collapse element so that those elements can be foldable. The first element inside (or the mentioned "string" on the we-collapse element itself) is used as the always shown element (with a toggler on its left to toggle the visibility of the other items). we-collapse inside other we-collapse is supported as well. Limitations / Other infos: - The use of '⌙' and &emsp; characters is not automatic (yet?). Sometimes it actually make sense to use them without a we-collapse or to not use them in a we-collapse. - The use of we-collapse is limited to widgets inside the same option. So unfortunately, there is no current way to add all bg image options in a folable section as those contain many different options. Maybe in the future. Part of https://github.com/odoo/odoo/pull/56350 closes odoo/odoo#56350 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src/js/editor/snippets.options.js')
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.options.js92
1 files changed, 81 insertions, 11 deletions
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 7edee505ea1..23fe6ff1bfd 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -114,6 +114,41 @@ function _buildRowElement(title, options) {
return groupEl;
}
/**
+ * Build the correct DOM for a we-collapse element.
+ *
+ * @param {string} [title] - @see _buildElement
+ * @param {Object} [options] - @see _buildElement
+ * @param {HTMLElement[]} [options.childNodes]
+ * @returns {HTMLElement}
+ */
+function _buildCollapseElement(title, options) {
+ const groupEl = _buildElement('we-collapse', title, options);
+ const titleEl = groupEl.querySelector('we-title');
+
+ const children = options && options.childNodes || [];
+ if (titleEl) {
+ titleEl.remove();
+ children.unshift(titleEl);
+ }
+ let i = 0;
+ for (i = 0; i < children.length; i++) {
+ groupEl.appendChild(children[i]);
+ if (children[i].nodeType === Node.ELEMENT_NODE) {
+ break;
+ }
+ }
+
+ const togglerEl = document.createElement('we-toggler');
+ togglerEl.classList.add('o_we_collapse_toggler');
+ groupEl.appendChild(togglerEl);
+
+ const containerEl = document.createElement('div');
+ children.slice(i + 1).forEach(node => containerEl.appendChild(node));
+ groupEl.appendChild(containerEl);
+
+ return groupEl;
+}
+/**
* Creates a proxy for an object where one property is replaced by a different
* value. This value is captured in the closure and can be read and written to.
*
@@ -1729,6 +1764,9 @@ const userValueWidgetsRegistry = {
*/
const SnippetOptionWidget = Widget.extend({
tagName: 'we-customizeblock-option',
+ events: {
+ 'click .o_we_collapse_toggler': '_onCollapseTogglerClick',
+ },
custom_events: {
'user_value_update': '_onUserValueUpdate',
'user_value_widget_critical': '_onUserValueWidgetCritical',
@@ -2190,11 +2228,20 @@ const SnippetOptionWidget = Widget.extend({
await Promise.all(proms);
- // Hide rows which contains only hidden widgets
- for (const rowEl of this.$el.find('we-row')) {
- // TODO improve this, this is hackish to rely on DOM structure
- // here. Rows should be handled as widgets or something like that.
- rowEl.classList.toggle('d-none', $(rowEl).find('> div > .o_we_user_value_widget:not(.d-none)').length === 0);
+ // Hide layouting elements which contains only hidden widgets
+ // TODO improve this, this is hackish to rely on DOM structure here.
+ // Layouting elements should be handled as widgets or other.
+ for (const el of this.$el.find('we-row')) {
+ el.classList.toggle('d-none', !$(el).find('> div > .o_we_user_value_widget').not('.d-none').length);
+ }
+ for (const el of this.$el.find('we-collapse')) {
+ const $el = $(el);
+ el.classList.toggle('d-none', $el.children().first().hasClass('d-none'));
+ const hasNoVisibleElInCollapseMenu = !$el.children().last().children().not('.d-none').length;
+ if (hasNoVisibleElInCollapseMenu) {
+ this._toggleCollapseEl(el, false);
+ }
+ el.querySelector('.o_we_collapse_toggler').classList.toggle('d-none', hasNoVisibleElInCollapseMenu);
}
},
@@ -2399,12 +2446,14 @@ const SnippetOptionWidget = Widget.extend({
await this._renderCustomXML(uiFragment);
// Build layouting components first
- uiFragment.querySelectorAll('we-row').forEach(el => {
- const infos = this._extraInfoFromDescriptionElement(el);
- const groupEl = _buildRowElement(infos.title, infos.options);
- el.parentNode.insertBefore(groupEl, el);
- el.parentNode.removeChild(el);
- });
+ for (const [itemName, build] of [['we-row', _buildRowElement], ['we-collapse', _buildCollapseElement]]) {
+ uiFragment.querySelectorAll(itemName).forEach(el => {
+ const infos = this._extraInfoFromDescriptionElement(el);
+ const groupEl = build(infos.title, infos.options);
+ el.parentNode.insertBefore(groupEl, el);
+ el.parentNode.removeChild(el);
+ });
+ }
// Load widgets
await this._renderXMLWidgets(uiFragment);
@@ -2553,12 +2602,32 @@ const SnippetOptionWidget = Widget.extend({
}
return value;
},
+ /**
+ * @private
+ * @param {HTMLElement} collapseEl
+ * @param {boolean|undefined} [show]
+ */
+ _toggleCollapseEl(collapseEl, show) {
+ collapseEl.classList.toggle('active', show);
+ collapseEl.querySelector('.o_we_collapse_toggler').classList.toggle('active', show);
+ },
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
+ * @private
+ * @param {Event} ev
+ */
+ _onCollapseTogglerClick(ev) {
+ const currentCollapseEl = ev.currentTarget.parentNode;
+ this._toggleCollapseEl(currentCollapseEl);
+ for (const collapseEl of currentCollapseEl.querySelectorAll('we-collapse')) {
+ this._toggleCollapseEl(collapseEl, false);
+ }
+ },
+ /**
* Called when a widget notifies a preview/change/reset.
*
* @private
@@ -4438,6 +4507,7 @@ return {
buildElement: _buildElement,
buildTitleElement: _buildTitleElement,
buildRowElement: _buildRowElement,
+ buildCollapseElement: _buildCollapseElement,
// Other names for convenience
Class: SnippetOptionWidget,