diff options
| author | qsm-odoo <qsm@odoo.com> | 2020-08-22 15:02:21 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2020-08-22 16:50:55 +0000 |
| commit | d9c450ac97de40c71aebd487cff725bfda6a577b (patch) | |
| tree | 8d7d2793c5796ecc3518c792b3fcad5b59cf9e12 /addons/web_editor/static/src | |
| parent | 95239e523b194777b58e8dd9a409a93404b44c6d (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   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')
3 files changed, 137 insertions, 16 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, diff --git a/addons/web_editor/static/src/scss/web_editor.variables.scss b/addons/web_editor/static/src/scss/web_editor.variables.scss index ca8f9e6a080..add424313c0 100644 --- a/addons/web_editor/static/src/scss/web_editor.variables.scss +++ b/addons/web_editor/static/src/scss/web_editor.variables.scss @@ -117,8 +117,7 @@ $o-we-sidebar-content-main-title-font-size: 13px !default; $o-we-sidebar-content-block-spacing: 10px !default; -$o-we-sidebar-content-fold-block-bg: $o-we-bg-dark !default; -$o-we-sidebar-content-fold-block-inner-spacing: $o-we-sidebar-content-block-spacing !default; +$o-we-sidebar-content-fold-block-bg: $o-we-bg-light !default; $o-we-sidebar-content-field-spacing: $o-we-item-spacing !default; $o-we-sidebar-content-field-color: $o-we-fg-darker !default; diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss index 01963484889..5419eb8a133 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss @@ -427,14 +427,13 @@ body.editor_enable.editor_has_snippets { we-customizeblock-options { position: relative; display: block; - padding: 0 $o-we-sidebar-content-padding-base $o-we-sidebar-content-block-spacing * 1.5 $o-we-sidebar-content-indent; + padding: 0 0 ($o-we-sidebar-content-block-spacing * 1.5) 0; background-color: $o-we-bg-lighter; box-shadow: $o-we-item-standup-bottom rgba($o-we-item-standup-color-dark, 0.8); > we-title { display: flex; align-items: center; - margin: 0 (-$o-we-sidebar-content-padding-base) 0 (-$o-we-sidebar-content-indent); padding: $o-we-sidebar-content-block-spacing * .3 $o-we-sidebar-content-padding-base 0 $o-we-sidebar-content-indent; background-color: $o-we-bg-light; box-shadow: $o-we-item-standup-top rgba($o-we-item-standup-color-light, .2), $o-we-item-standup-bottom rgba($o-we-item-standup-color-dark, .5); @@ -454,7 +453,9 @@ body.editor_enable.editor_has_snippets { .oe_snippet_remove { font-size: 1.2em; } - + we-customizeblock-option { + padding: 0; + } we-button { margin-left: $o-we-sidebar-content-field-multi-spacing; padding: 0 $o-we-sidebar-content-field-multi-spacing; @@ -470,6 +471,7 @@ body.editor_enable.editor_has_snippets { we-customizeblock-option { position: relative; display: block; + padding: 0 $o-we-sidebar-content-padding-base 0 $o-we-sidebar-content-indent; .dropdown-menu { // FIXME temporary fix for m2o option for example @@ -1063,6 +1065,56 @@ body.editor_enable.editor_has_snippets { } } + we-collapse { + position: relative; + display: block; + padding-left: $o-we-sidebar-content-indent; + padding-right: $o-we-sidebar-content-padding-base; + margin-right: -$o-we-sidebar-content-padding-base; + margin-left: -$o-we-sidebar-content-indent; + // Allow inner margin to be considered inside the block + Visual space after/before previous/next widget + No flickering on opening + $-inner-spacing: ceil($o-we-sidebar-content-field-spacing / 2); + border-top: ($o-we-sidebar-content-field-spacing - $-inner-spacing) solid transparent; + padding-bottom: ($o-we-sidebar-content-field-spacing - $-inner-spacing); + margin-bottom: -($o-we-sidebar-content-field-spacing - $-inner-spacing); + background-clip: padding-box; + + > :first-child, .o_we_collapse_toggler { + margin-top: $-inner-spacing; + } + .o_we_collapse_toggler { + @include o-position-absolute($top: 0, $left: 0); + width: $o-we-sidebar-content-indent; + height: $o-we-sidebar-content-field-height; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + background: none; + border: none; + + &::after { + content: '\f0da'; + position: static; + transform: none; + } + &.active { + + &::after { + content: '\f0d7'; + } + + * { + background: none; + border: none; + box-shadow: none; + } + } + } + &.active { + background-color: $o-we-sidebar-content-fold-block-bg; + } + } + .o_we_image_weight { display: flex; justify-content: flex-end; |
