diff options
| author | qsm-odoo <qsm@odoo.com> | 2019-08-27 14:47:47 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2019-08-28 09:04:55 +0000 |
| commit | 4f27e52cabb77b8b1a9637a11185ddf882adc9af (patch) | |
| tree | b4b752daef0050988604260d43802413c856bbd7 | |
| parent | 05f9b1f4e680ef05fccf2b9b324ec24282daa65d (diff) | |
[IMP] web_editor, *: introduce and restore new web_editor UI
* mass_mailing, note, website, website_blog, website_form,
website_mass_mailing, website_sale
This commit, unfortunately, mixes three things:
- Restoring as much as possible the scss organisation to allow styling
the web_editor UI properly.
- Fixing some bugs like a border around the page once the editor is
loaded, no ability to scroll the snippets, etc
- Introducing a whole new UI for snippet options: a left panel instead
of the old dropdown & button overlay.
Note: this commit also do some linting and ES6 convertion even though
some of it has been done in the parent commit.
Note 2: some elements that were removed are still styled in the POS apps
but this is because part of a feature was removed while leaving dead
code behind, this is handled in another PR which is to be merged
(https://github.com/odoo/odoo/pull/36136).
Part of https://github.com/odoo/odoo/pull/36068
task-1942370
closes odoo/odoo#36068
Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
31 files changed, 1498 insertions, 2047 deletions
diff --git a/addons/mass_mailing/static/src/js/mass_mailing_snippets.js b/addons/mass_mailing/static/src/js/mass_mailing_snippets.js index fe8093b17d9..ad4864d0b07 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_snippets.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_snippets.js @@ -20,7 +20,6 @@ options.registry.mass_mailing_sizing_x = options.Class.extend({ this.isIMG = this.$target.is("img"); if (this.isIMG) { this.$overlay.find(".o_handle.w").addClass("readonly"); - this.$overlay.find(".oe_snippet_move, .oe_snippet_clone").addClass('d-none'); } var $body = $(this.ownerDocument.body); diff --git a/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss b/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss index 7aec2b165e9..e39e04498e6 100644 --- a/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss +++ b/addons/mass_mailing/static/src/scss/mass_mailing.ui.scss @@ -9,18 +9,18 @@ .o_mail_theme_selector { > a { @include o-position-absolute(0, 0, auto, 0); - height: $o-wysiwyg-toolbar-height; - line-height: $o-wysiwyg-toolbar-height; + height: $o-we-toolbar-height; + line-height: $o-we-toolbar-height; border-radius: 0; - background-color: $o-wysiwyg-bg-color; - color: $o-wysiwyg-color; + background-color: $o-we-bg-color; + color: $o-we-color; display: flex; justify-content: center; align-items: center; box-shadow: none !important; &:hover, &:focus, &:active { - color: $o-wysiwyg-color-light; + color: $o-we-color-light; } i { @@ -30,7 +30,7 @@ &.show > a { color: white; - background-color: $o-wysiwyg-color; + background-color: $o-we-color; } .dropdown-menu { @@ -42,7 +42,7 @@ margin: 0; border-radius: 0; overflow: auto; - background-color: $o-wysiwyg-bg-color; + background-color: $o-we-bg-color; z-index: 1050; &.show { @@ -61,7 +61,7 @@ display: none; background-size: cover; padding-top: 50%; - border: 1px solid $o-wysiwyg-border-color; + border: 1px solid $o-we-border-color; &.logo { @@ -71,7 +71,7 @@ &:hover { - background-color: $o-wysiwyg-bg-color; + background-color: $o-we-bg-color; .o_thumb { border: 1px solid black; @@ -80,7 +80,7 @@ &.selected .o_thumb { border: 2px solid $o-brand-odoo; - background-color: $o-wysiwyg-bg-color; + background-color: $o-we-bg-color; } } } @@ -113,8 +113,8 @@ body.o_force_mail_theme_choice { .o_thumb { display: none; padding-top: 107%; - border: 1px solid $o-wysiwyg-color-light; - border-top: 1px solid $o-wysiwyg-border-color; + border: 1px solid $o-we-color-light; + border-top: 1px solid $o-we-border-color; box-shadow: 0 5px 10px rgba(black, 0.8); will-change: transform; backface-visibility: hidden; @@ -135,7 +135,7 @@ body.o_force_mail_theme_choice { } &:hover { - background-color: $o-wysiwyg-color; + background-color: $o-we-color; .o_thumb { box-shadow: 0 5px 30px 1px rgba(black, 0.6); @@ -174,14 +174,16 @@ body.o_force_mail_theme_choice { } } -.o_basic_theme.o_in_iframe { +body.editor_enable.o_basic_theme.o_in_iframe { padding-left: 0px !important; + + #web_editor-top-edit .note-popover .popover { + left: 0 !important; + } + #oe_snippets { display: none; } - .note-editor.o_snippets_loaded { - padding-left: 0px!important; - } } .note-editable .o_layout { @@ -191,7 +193,7 @@ body.o_force_mail_theme_choice { #web_editor-toolbars .popover .note-color { .note-back-color-preview .dropdown-toggle, .note-fore-color-preview .dropdown-toggle { - height: $o-wysiwyg-toolbar-height - 1; + height: $o-we-toolbar-height - 1; } } diff --git a/addons/mass_mailing/views/snippets_themes.xml b/addons/mass_mailing/views/snippets_themes.xml index ac6c75ba128..b268850e6f7 100644 --- a/addons/mass_mailing/views/snippets_themes.xml +++ b/addons/mass_mailing/views/snippets_themes.xml @@ -2,11 +2,11 @@ <odoo> <!-- Snippets & Themes Menu --> <template id="email_designer_snippets" inherit_id="web_editor.snippets" primary="True"> - <xpath expr="//h2[@id='snippets_menu']" position="replace"> - <t t-set="company_id" t-value="res_company"/> - <h2 id="snippets_menu">Select a template</h2> + <xpath expr="//div[@id='snippets_menu']" position="inside"> + <button type="button" disabled="disabled">Select a template</button> </xpath> <xpath expr="//div[@id='o_scroll']" position="replace"> + <t t-set="company_id" t-value="res_company"/> <div id="o_scroll"> <div id="email_designer_themes"> <div data-name="basic" @@ -72,7 +72,6 @@ </div> </div> </xpath> - <xpath expr="//div[@id='snippet_options']" position="inside"> <t t-call="mass_mailing.snippet_options"/> </xpath> @@ -811,10 +810,10 @@ <div data-js="colorpicker" data-selector=".note-editable > div:not(.o_layout), .note-editable .oe_structure > div, td, th" data-exclude=".o_mail_no_colorpicker, .o_mail_no_options"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-eyedropper"/> Background Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> </template> </odoo> diff --git a/addons/note/static/src/scss/note.scss b/addons/note/static/src/scss/note.scss index f060c58d74e..2e15d5de46b 100644 --- a/addons/note/static/src/scss/note.scss +++ b/addons/note/static/src/scss/note.scss @@ -8,13 +8,9 @@ margin-bottom: 0; } .oe_form_field.oe_memo { - margin: 0 ($input-btn-padding-x-lg * -1); + margin: 0; padding: 0; min-height: 200px; - - .note-editor { - border: none; - } } &.o_form_readonly { .oe_memo { diff --git a/addons/web_editor/static/src/js/editor/editor.js b/addons/web_editor/static/src/js/editor/editor.js index 07947db56e4..31c31e5ce6a 100644 --- a/addons/web_editor/static/src/js/editor/editor.js +++ b/addons/web_editor/static/src/js/editor/editor.js @@ -106,7 +106,9 @@ var EditorMenuBar = Widget.extend({ // Snippets menu if (self.snippetsMenu) { - defs.push(this.snippetsMenu.insertAfter(this.$el)); + // TODO improve this, the editor can be relocated so here, + // 'insertAfter(this.$el)' won't work. + defs.push(this.snippetsMenu.appendTo(this.$el.parent())); } this.rte.editable().find('*').off('mousedown mouseup click'); 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 1f0bda9a1fc..fdb79ebd04a 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -1,6 +1,7 @@ odoo.define('web_editor.snippet.editor', function (require) { 'use strict'; +var concurrency = require('web.concurrency'); var core = require('web.core'); var dom = require('web.dom'); var Widget = require('web.Widget'); @@ -22,13 +23,9 @@ var SnippetEditor = Widget.extend({ template: 'web_editor.snippet_overlay', xmlDependencies: ['/web_editor/static/src/xml/snippets.xml'], events: { - 'click .oe_snippet_parent': '_onParentButtonClick', - 'click .oe_snippet_clone': '_onCloneClick', - 'click .oe_snippet_remove': '_onRemoveClick', - 'mousedown .oe_options [data-toggle="dropdown"]:first': '_onOpenCusomize', + 'mousedown': '_onUIMouseDown', }, custom_events: { - cover_update: '_onCoverUpdate', 'option_update': '_onOptionUpdate', }, @@ -49,57 +46,57 @@ var SnippetEditor = Widget.extend({ this.$target = $(target); this.$target.data('snippet-editor', this); this.templateOptions = templateOptions; + this.isTargetParentEditable = false; + this.isTargetMovable = false; }, /** * @override */ start: function () { - var self = this; var defs = [this._super.apply(this, arguments)]; - // Hide parent button if no parent - var $parent = globalSelector.closest(this.$target.parent()); - if (!$parent.length) { - this.$('.oe_snippet_parent').remove(); - } - // Initialize the associated options (see snippets.options.js) defs.push(this._initializeOptions()); + var $customize = this._customize$Elements[this._customize$Elements.length - 1]; + + this.isTargetParentEditable = this.$target.parent().is(':o_editable'); + this.isTargetMovable = this.isTargetParentEditable && this.isTargetMovable; // Initialize move/clone/remove buttons - if (!this.$target.is(':o_editable')) { - this.$el.find('.oe_snippet_move, .oe_snippet_clone, .oe_snippet_remove').remove(); - } else { + if (this.isTargetMovable) { this.dropped = false; this.$el.draggable({ greedy: true, appendTo: this.$body, cursor: 'move', - handle: '.oe_snippet_move', + handle: '.o_move_handle', cursorAt: { left: 18, top: 14 }, - helper: function () { - var $clone = $(this).clone().css({width: '24px', height: '24px', border: 0}); - $clone.find('.oe_overlay_options >:not(:contains(.oe_snippet_move)), .o_handle').remove(); - $clone.find(':not(.glyphicon)').css({position: 'absolute', top: 0, left: 0}); - $clone.appendTo(self.$body).removeClass('d-none'); + helper: () => { + var $clone = this.$el.clone().css({width: '24px', height: '24px', border: 0}); + $clone.appendTo(this.$body).removeClass('d-none'); return $clone; }, - start: _.bind(self._onDragAndDropStart, self), - stop: _.bind(self._onDragAndDropStop, self) + start: this._onDragAndDropStart.bind(this), + stop: this._onDragAndDropStop.bind(this), }); + } else { + this.$('.o_move_handle').addClass('d-none'); + $customize.find('.oe_snippet_clone').addClass('d-none'); } - this.$target.on('transitionstart.snippet_editor, animationstart.snippet_editor', function () { - self._targetIsAnimated = true; + if (!this.isTargetParentEditable) { + $customize.find('.oe_snippet_remove').addClass('d-none'); + } + + this.$target.on('transitionstart.snippet_editor, animationstart.snippet_editor', () => { + this._targetIsAnimated = true; }); - this.$target.on('transitionend.snippet_editor, animationend.snippet_editor', function () { - self._targetIsAnimated = false; - if (self.$el.is('.oe_active')) { - self.cover(); - } + this.$target.on('transitionend.snippet_editor, animationend.snippet_editor', () => { + this._targetIsAnimated = false; + this.cover(); }); return Promise.all(defs); @@ -143,9 +140,10 @@ var SnippetEditor = Widget.extend({ * Makes the editor overlay cover the associated snippet. */ cover: function () { - if (this._targetIsAnimated) { + if (this._targetIsAnimated || !this.isShown() || !this.$target.length) { // Do not cover a target being animated, it will be covered once the - // animation is completed. + // animation is completed. Also ignore if the overlay is not shown + // yet or that the $target element has been removed. return; } var offset = this.$target.offset(); @@ -161,6 +159,24 @@ var SnippetEditor = Widget.extend({ this.$el.toggleClass('o_top_cover', offset.top < this.$editable.offset().top); }, /** + * @returns {boolean} + */ + isOpened: function () { + return this.$el && this.$el.hasClass('o_we_options_opened'); + }, + /** + * @return {boolean} + */ + isShown: function () { + return this.$el && this.$el.parent().length && this.$el.hasClass('oe_active'); + }, + /** + * @return {boolean} + */ + isSticky: function () { + return this.$el && this.$el.hasClass('o_we_sticky'); + }, + /** * Removes the associated snippet from the DOM and destroys the associated * editor (itself). */ @@ -176,6 +192,7 @@ var SnippetEditor = Widget.extend({ }, }); + this.trigger_up('go_to_parent', {$snippet: this.$target}); var $parent = this.$target.parent(); this.$target.find('*').addBack().tooltip('dispose'); this.$target.remove(); @@ -217,51 +234,25 @@ var SnippetEditor = Widget.extend({ * snippet options are moved to the editor overlay. * * @param {boolean} focus - true to display, false to hide + * @param {boolean} [previewMode=false] + * @param {boolean} [onlyOverlay=false] */ - toggleFocus: function (focus) { + toggleFocus: function (focus, previewMode, onlyOverlay) { if (!this.$el) { return; } - var do_action = (focus ? _do_action_focus : _do_action_blur); - - // Attach own and parent options on the current overlay - var $style_button = this.$el.find('.oe_options'); - var $ul = $style_button.find('.dropdown-menu:first'); - var $headers = $ul.find('.dropdown-header:data(editor)'); - _.each($headers, (function (el) { - var $el = $(el); - var styles = _.values($el.data('editor').styles); - if ($el.data('editor') !== this) { - styles = _.filter(styles, function (option) { return !option.preventChildPropagation; }); - } - var count = 0; - _.each(_.sortBy(styles, '__order').reverse(), function (style) { - if (do_action(style, $el)) { - count++; - } - }); - $el.toggleClass('d-none', count === 0); - }).bind(this)); - - // Activate the overlay - $style_button.toggleClass('d-none', $ul.children(':not(.o_main_header):not(.dropdown-divider):not(.d-none)').length === 0); - this.cover(); - this.$el.toggleClass('oe_active', !!focus); - - if (focus) { - this.trigger_up('snippet_focused'); + if (!previewMode && !onlyOverlay) { + this._toggleOptions(focus ? (this._customize$Elements.length - 1) : false); } - - function _do_action_focus(style, $dest) { - style.$el.insertAfter($dest); - style.onFocus(); - return (style.$el.length > 0); - } - function _do_action_blur(style, $dest) { - style.$el.detach(); - style.onBlur(); - return false; + this._toggleOverlay(!!focus, previewMode ? undefined : !!focus); + }, + /** + * @param {boolean} [isTextEdition=false] + */ + toggleTextEdition: function (isTextEdition) { + if (this.$el) { + this.$el.toggleClass('o_keypress', !!isTextEdition && this.isShown()); } }, @@ -291,58 +282,112 @@ var SnippetEditor = Widget.extend({ * @private */ _initializeOptions: function () { - var self = this; - var $styles = this.$el.find('.oe_options'); - var $ul = $styles.find('.dropdown-menu:first'); + this._customize$Elements = []; this.styles = {}; this.selectorSiblings = []; this.selectorChildren = []; + var $element = this.$target.parent(); + while ($element.length) { + var parentEditor = $element.data('snippet-editor'); + if (parentEditor) { + this._customize$Elements = this._customize$Elements + .concat(parentEditor._customize$Elements); + break; + } + $element = $element.parent(); + } + + var $optionsSection = $(core.qweb.render('web_editor.customize_block_options_section', { + name: this._getName(), + })).data('editor', this); + $optionsSection.on('mouseover', this._onOptionsSectionMouseOver.bind(this)); + $optionsSection.on('mouseleave', this._onOptionsSectionMouseLeave.bind(this)); + $optionsSection.on('click', this._onOptionsSectionClick.bind(this)); + $optionsSection.on('click', '.oe_snippet_clone', this._onCloneClick.bind(this)); + $optionsSection.on('click', '.oe_snippet_remove', this._onRemoveClick.bind(this)); + this._customize$Elements.push($optionsSection); + var i = 0; - $ul.append($('<div/>', {class: 'dropdown-header o_main_header', text: this._getName()}).data('editor', this)); - var defs = _.map(this.templateOptions, function (val, option_id) { - if (!val.selector.is(self.$target)) { + var defs = _.map(this.templateOptions, val => { + if (!val.selector.is(this.$target)) { return; } - if (val['drop-near']) self.selectorSiblings.push(val['drop-near']); - if (val['drop-in']) self.selectorChildren.push(val['drop-in']); + if (val['drop-near']) { + this.selectorSiblings.push(val['drop-near']); + } + if (val['drop-in']) { + this.selectorChildren.push(val['drop-in']); + } var optionName = val.option; var $el = val.$el.children().clone(true).addClass('snippet-option-' + optionName); var option = new (options.registry[optionName] || options.Class)( - self, - val.base_target ? self.$target.find(val.base_target).eq(0) : self.$target, - self.$el, + this, + val.base_target ? this.$target.find(val.base_target).eq(0) : this.$target, + this.$el, val.data, - self.options + this.options ); - self.styles[optionName || _.uniqueId('option')] = option; + this.styles[optionName || _.uniqueId('option')] = option; option.__order = i++; - return option.attachTo($el); + var $optionSection = $(core.qweb.render('web_editor.customize_block_option')); + $optionSection.append($el); + return option.attachTo($optionSection); }); - $ul.append($('<div/>', {class: 'dropdown-divider mt-2'})); - var $parents = this.$target.parents(); - _.each($parents, function (parent) { - var parentEditor = $(parent).data('snippet-editor'); - if (parentEditor) { - for (var styleName in parentEditor.styles) { - if (!parentEditor.styles[styleName].preventChildPropagation) { - $ul.append($('<div/>', {class: 'dropdown-header o_parent_editor_header', text: parentEditor._getName()}).data('editor', parentEditor)); - break; - } - } - } - }); - - if (!this.selectorSiblings.length && !this.selectorChildren.length) { - this.$el.find('.oe_snippet_move, .oe_snippet_clone').addClass('d-none'); - } + this.isTargetMovable = (this.selectorSiblings.length > 0 || this.selectorChildren.length > 0); this.$el.find('[data-toggle="dropdown"]').dropdown(); return Promise.all(defs); }, + /** + * @private + * @param {integer|false} index + */ + _toggleOptions: function (index) { + if (index === false || !this._customize$Elements[index].parent().length) { + this.trigger_up('update_customize_elements', { + customize$Elements: index !== false ? this._customize$Elements : [], + }); + } + this._customize$Elements.forEach(($el, i) => { + var open = (i === index); + + $el.toggleClass('o_we_closed', !open); + + var editor = $el.data('editor'); + editor.$el.toggleClass('o_we_options_opened', open); + + var styles = _.values(editor.styles); + $el.toggleClass('d-none', styles.length === 0); + _.each(_.sortBy(styles, '__order').reverse(), function (style) { + if (open) { + style.$el.appendTo($el); + style.onFocus(); + } else { + style.$el.detach(); + style.onBlur(); + } + }); + }); + }, + /** + * @private + * @param {boolean} show - whether the overlay should be shown or not + * @param {boolean} [sticky] + * whether the overlay should be sticky or not (if the value is + * undefined, the stickyness is left unchanged) + */ + _toggleOverlay: function (show, sticky) { + this.$el.toggleClass('oe_active', show); + this.cover(); + + if (sticky !== undefined) { + this.$el.toggleClass('o_we_sticky', sticky); + } + }, //-------------------------------------------------------------------------- // Handlers @@ -356,7 +401,7 @@ var SnippetEditor = Widget.extend({ */ _onCloneClick: function (ev) { ev.preventDefault(); - this.trigger_up('cover_will_change'); + ev.stopPropagation(); this.trigger_up('snippet_will_be_cloned', {$target: this.$target}); @@ -378,15 +423,6 @@ var SnippetEditor = Widget.extend({ $clone.trigger('content_changed'); }, /** - * Called when the overlay dimensions/positions should be recomputed. - * - * @private - */ - _onCoverUpdate: function () { - this.trigger_up('cover_will_change'); - this.cover(); - }, - /** * Called when the snippet is starting to be dragged thanks to the 'move' * button. * @@ -440,8 +476,6 @@ var SnippetEditor = Widget.extend({ self.dropped = false; }, }); - - this.trigger_up('cover_will_change'); }, /** * Called when the snippet is dropped after being dragged thanks to the @@ -504,6 +538,47 @@ var SnippetEditor = Widget.extend({ }); }, /** + * @private + */ + _onOptionsSectionMouseOver: function (ev) { + var $optionsSection = $(ev.currentTarget); + if (!$optionsSection.hasClass('o_we_closed')) { + return; + } + + this.trigger_up('activate_snippet', { + $snippet: this.$target, + previewMode: true, + }); + }, + /** + * @private + */ + _onOptionsSectionMouseLeave: function (ev) { + this.trigger_up('activate_snippet', { + $snippet: false, + previewMode: true, + }); + }, + /** + * @private + */ + _onOptionsSectionClick: function (ev) { + var $optionsSection = $(ev.currentTarget); + if (!$optionsSection.hasClass('o_we_closed')) { + return; + } + + this.trigger_up('activate_snippet', { + $snippet: this.$target, + previewMode: false, + onlyOverlay: true, + }); + var $neighbors = $optionsSection.nextAll('we-customizeblock-options'); + var editor = $neighbors.length ? $neighbors.last().data('editor') : this; + editor._toggleOptions($optionsSection.index()); + }, + /** * Called when a child editor/option asks for another option to perform a * specific action/react to a specific event. * @@ -511,7 +586,6 @@ var SnippetEditor = Widget.extend({ * @param {OdooEvent} ev */ _onOptionUpdate: function (ev) { - this.trigger_up('cover_will_change'); // If multiple option names are given, we suppose it should not be // propagated to parent editor if (ev.data.optionNames) { @@ -535,28 +609,6 @@ var SnippetEditor = Widget.extend({ } }, /** - * Called when the user opens the customize menu. - * - * @private - * @param {OdooEvent} ev - */ - _onOpenCusomize: function (ev) { - this.trigger_up('request_history_undo_record', {$target: this.$target}); - }, - - /** - * Called when the 'parent' button is clicked. - * - * @private - * @param {Event} ev - */ - _onParentButtonClick: function (ev) { - ev.preventDefault(); - this.trigger_up('go_to_parent', { - $snippet: this.$target, - }); - }, - /** * Called when the 'remove' button is clicked. * * @private @@ -564,10 +616,24 @@ var SnippetEditor = Widget.extend({ */ _onRemoveClick: function (ev) { ev.preventDefault(); - this.trigger_up('cover_will_change'); + ev.stopPropagation(); this.trigger_up('request_history_undo_record', {$target: this.$target}); this.removeSnippet(); }, + /** + * The UI is displayed on hover and become sticky once the related target is + * clicked. If we click the UI while it is not sticky, it should become + * sticky. + * + * @private + */ + _onUIMouseDown: function (ev) { + if (!this.isOpened()) { + this.trigger_up('activate_snippet', { + $snippet: this.$target, + }); + } + } }); /** @@ -576,16 +642,21 @@ var SnippetEditor = Widget.extend({ var SnippetsMenu = Widget.extend({ id: 'oe_snippets', cacheSnippetTemplate: {}, - activeSnippets: [], + events: { + 'click we-collapse-area > we-toggler': '_onCollapseTogglerClick', + }, custom_events: { 'activate_insertion_zones': '_onActivateInsertionZones', + 'activate_snippet': '_onActivateSnippet', 'call_for_each_child_snippet': '_onCallForEachChildSnippet', + 'cover_update': '_onOverlaysCoverUpdate', 'deactivate_snippet': '_onDeactivateSnippet', 'drag_and_drop_stop': '_onDragAndDropStop', 'go_to_parent': '_onGoToParent', 'remove_snippet': '_onRemoveSnippet', 'snippet_removed': '_onSnippetRemoved', 'reload_snippet_dropzones': '_disableUndroppableSnippets', + 'update_customize_elements': '_onUpdateCustomizeElements', }, /** @@ -613,8 +684,8 @@ var SnippetsMenu = Widget.extend({ if (!this.options.snippets) { this.options.snippets = 'web_editor.snippets'; } - this.$activeSnippet = false; this.snippetEditors = []; + this._activateSnippetMutex = new concurrency.Mutex(); this.setSelectorEditableArea(options.$el, options.selectorEditableArea); }, @@ -622,7 +693,6 @@ var SnippetsMenu = Widget.extend({ * @override */ start: function () { - var self = this; var defs = [this._super.apply(this, arguments)]; this.ownerDocument = this.$el[0].ownerDocument; this.$document = $(this.ownerDocument); @@ -631,8 +701,12 @@ var SnippetsMenu = Widget.extend({ // Fetch snippet templates and compute it - defs.push(this.loadSnippets().then(function (html) { - return self._computeSnippetTemplates(html); + defs.push(this.loadSnippets().then(html => { + return this._computeSnippetTemplates(html); + }).then(() => { + this.customizePanel = document.createElement('div'); + this.customizePanel.classList.add('o_we_customize_panel', 'd-none'); + this.$el.append(this.customizePanel); })); // Prepare snippets editor environment @@ -653,7 +727,14 @@ var SnippetsMenu = Widget.extend({ }); var $target = $(srcElement); - if ($target.closest('.oe_overlay, .note-popover').length) { + if ($target.closest('#snippets_menu').length) { + this._activateSnippet(false); + return; + } + if (!$target.closest('body > *').length) { + return; + } + if ($target.closest('#web_editor-top-edit, #oe_snippets, #oe_manipulators, .o_technical_modal, .oe_drop_zone').length) { return; } this._activateSnippet($target); @@ -663,23 +744,23 @@ var SnippetsMenu = Widget.extend({ core.bus.on('snippet_editor_clean_for_save', this, this._onCleanForSaveDemand); // Adapt overlay covering when the window is resized / content changes - var debouncedCoverUpdate = _.debounce(function () { - self.updateCurrentSnippetEditorOverlay(); - }, 200); + var debouncedCoverUpdate = _.throttle(() => { + this.updateCurrentSnippetEditorOverlay(); + }, 50); this.$window.on('resize.snippets_menu', debouncedCoverUpdate); this.$window.on('content_changed.snippets_menu', debouncedCoverUpdate); // On keydown add a class on the active overlay to hide it and show it // again when the mouse moves - this.$document.on('keydown.snippets_menu', function () { - if (self.$activeSnippet && self.$activeSnippet.data('snippet-editor')) { - self.$activeSnippet.data('snippet-editor').$el.addClass('o_keypress'); - } + this.$document.on('keydown.snippets_menu', () => { + this.snippetEditors.forEach(editor => { + editor.toggleTextEdition(true); + }); }); - this.$document.on('mousemove.snippets_menu, mousedown.snippets_menu', function () { - if (self.$activeSnippet && self.$activeSnippet.data('snippet-editor')) { - self.$activeSnippet.data('snippet-editor').$el.removeClass('o_keypress'); - } + this.$document.on('mousemove.snippets_menu, mousedown.snippets_menu', () => { + this.snippetEditors.forEach(editor => { + editor.toggleTextEdition(false); + }); }); // Auto-selects text elements with a specific class and remove this @@ -694,12 +775,19 @@ var SnippetsMenu = Widget.extend({ $(range && range.sc).closest('.o_default_snippet_text').removeClass('o_default_snippet_text'); }); - return Promise.all(defs).then(function () { + return Promise.all(defs).then(() => { + this.$('[data-title]').tooltip({ + delay: 0, + title: function () { + return this.classList.contains('active') ? false : this.dataset.title; + }, + }); + // Trigger a resize event once entering edit mode as the snippets // menu will take part of the screen width (delayed because of // animation). (TODO wait for real animation end) - setTimeout(function () { - self.$window.trigger('resize'); + setTimeout(() => { + this.$window.trigger('resize'); }, 1000); }); }, @@ -782,11 +870,9 @@ var SnippetsMenu = Widget.extend({ * Updates the cover dimensions of the current snippet editor. */ updateCurrentSnippetEditorOverlay: function () { - if (this.$activeSnippet && this.$activeSnippet.data('snippet-editor')) { - this.$activeSnippet.data('snippet-editor').cover(); - } this.snippetEditors = _.filter(this.snippetEditors, function (snippetEditor) { if (snippetEditor.$target.closest('body').length) { + snippetEditor.cover(); return true; } snippetEditor.destroy(); @@ -946,38 +1032,36 @@ var SnippetsMenu = Widget.extend({ * first parent which is one is used instead. * * @param {jQuery|false} $snippet - * The DOM element whose editor need to be enabled. Only disable the - * current one if false is given. + * The DOM element whose editor (and its parent ones) need to be + * enabled. Only disable the current one if false is given. + * @param {boolean} [previewMode=false] + * @param {boolean} [onlyOverlay=false] * @returns {Promise<SnippetEditor>} * (might be async when an editor must be created) */ - _activateSnippet: function ($snippet) { - if ($snippet) { - if (!globalSelector.is($snippet)) { + _activateSnippet: function ($snippet, previewMode, onlyOverlay) { + return this._activateSnippetMutex.exec(() => { + // First disable all shown editors and also sticky ones if not in + // preview mode (so new sticky ones have to be shown) + this.snippetEditors.forEach(editor => { + if (!previewMode || editor.isShown() && !editor.isSticky()) { + editor.toggleFocus(false, previewMode, onlyOverlay); + } + }); + // Take the first parent of the provided DOM (or itself) which + // should have an associated snippet editor and create + enable it. + if ($snippet && $snippet.length) { $snippet = globalSelector.closest($snippet); + if (!$snippet.length) { + return Promise.resolve(null); + } + return this._createSnippetEditor($snippet).then(editor => { + editor.toggleFocus(true, previewMode, onlyOverlay); + return editor; + }); } - if (this.$activeSnippet && this.$activeSnippet[0] === $snippet[0]) { - return Promise.resolve($snippet.data('snippet-editor')); - } - } - var editor = null; - if (this.$activeSnippet) { - editor = this.$activeSnippet.data('snippet-editor'); - if (editor) { - editor.toggleFocus(false); - } - this.$activeSnippet = false; - } - if ($snippet && $snippet.length) { - var self = this; - this.trigger_up('activate_snippet', $snippet); - return this._createSnippetEditor($snippet).then(function (editor) { - self.$activeSnippet = $snippet; - editor.toggleFocus(true); - return editor; - }); - } - return Promise.resolve(editor); + return Promise.resolve(null); + }); }, /** * @private @@ -1362,7 +1446,7 @@ var SnippetsMenu = Widget.extend({ } } - $toInsert = $baseBody.clone().data('name', $baseBody.data('name')); + $toInsert = $baseBody.clone().attr('data-name', $baseBody.data('name')); if (!$selectorSiblings.length && !$selectorChildren.length) { console.warn($snippet.find('.oe_snippet_thumbnail_title').text() + " have not insert action: data-drop-near or data-drop-in"); @@ -1390,8 +1474,6 @@ var SnippetsMenu = Widget.extend({ } }, }); - - self.trigger_up('cover_will_change'); }, stop: function (ev, ui) { $toInsert.removeClass('oe_snippet_body'); @@ -1435,9 +1517,6 @@ var SnippetsMenu = Widget.extend({ editor.buildSnippet(); }).then(function () { $target.trigger('content_changed'); - if ($target.closest('body').length) { // can be destroyed (eg in test) - self._activateSnippet($target); - } }); }); } else { @@ -1481,6 +1560,15 @@ var SnippetsMenu = Widget.extend({ this._activateInsertionZones(ev.data.$selectorSiblings, ev.data.$selectorChildren); }, /** + * Called when a child editor asks to deactivate the current snippet + * overlay. + * + * @private + */ + _onActivateSnippet: function (ev) { + this._activateSnippet(ev.data.$snippet, ev.data.previewMode, ev.data.onlyOverlay); + }, + /** * Called when a child editor asks to operate some operation on all child * snippet of a DOM element. * @@ -1500,6 +1588,24 @@ var SnippetsMenu = Widget.extend({ this.cleanForSave(); }, /** + * @private + * @param {*} ev + */ + _onCollapseTogglerClick: function (ev) { + this.$('we-collapse-area > we-toggler').not(ev.currentTarget).removeClass('active'); + ev.currentTarget.classList.toggle('active'); + }, + /** + * Called when the overlay dimensions/positions should be recomputed. + * + * @private + */ + _onOverlaysCoverUpdate: function () { + this.snippetEditors.forEach(editor => { + editor.cover(); + }); + }, + /** * Called when a child editor asks to deactivate the current snippet * overlay. * @@ -1548,6 +1654,23 @@ var SnippetsMenu = Widget.extend({ _onSnippetRemoved: function () { this._disableUndroppableSnippets(); }, + /** + * @private + * @param {OdooEvent} ev + */ + _onUpdateCustomizeElements: function (ev) { + while (this.customizePanel.firstChild) { + this.customizePanel.removeChild(this.customizePanel.firstChild); + } + ev.data.customize$Elements.forEach($el => { + this.customizePanel.appendChild($el[0]); + }); + var customize = !!ev.data.customize$Elements.length; + this.$('#o_scroll').toggleClass('d-none', customize); + this.$('.o_we_add_snippet_btn').toggleClass('active', !customize); + this.customizePanel.classList.toggle('d-none', !customize); + this.$('.o_we_customize_snippet_btn').toggleClass('active', customize); + }, }); return { 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 893fd8adebb..63f0c38c7c3 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -18,23 +18,16 @@ var _t = core._t; var SnippetOption = Widget.extend({ events: { 'mouseenter': '_onLinkEnter', - 'mouseenter a': '_onLinkEnter', + 'mouseenter we-button': '_onLinkEnter', 'click': '_onLinkClick', - 'click a': '_onLinkClick', + 'click we-button': '_onLinkClick', 'mouseleave': '_onMouseleave', - 'mouseleave a': '_onMouseleave', - 'mouseleave .dropdown-menu': '_onMouseleave', + 'mouseleave we-button': '_onMouseleave', }, - /** - * When editing a snippet, its options are shown alongside the ones of its - * parent snippets. The parent options are only shown if the following flag - * is set to false (default). - */ - preventChildPropagation: false, /** - * The option `$el` is supposed to be the associated DOM element in the - * options dropdown. The option controls another DOM element: the snippet it + * The option `$el` is supposed to be the associated DOM UI element. + * The option controls another DOM element: the snippet it * customizes, which can be found at `$target`. Access to the whole edition * overlay is possible with `$overlay` (this is not recommended though). * @@ -120,7 +113,7 @@ var SnippetOption = Widget.extend({ /** * Default option method which allows to select one and only one class in * the option classes set and set it on the associated snippet. The common - * case is having a subdropdown with each item having a `data-select-class` + * case is having a sub-collapse with each item having a `data-select-class` * value allowing to choose the associated class. * * @param {boolean|string} previewMode @@ -131,12 +124,14 @@ var SnippetOption = Widget.extend({ * @param {jQuery} $opt - the related DOMElement option */ selectClass: function (previewMode, value, $opt) { - var $group = $opt && $opt.parents('.dropdown-submenu').last(); + var $group = $opt && $opt.parents('we-collapse-area').last(); if (!$group || !$group.length) { $group = this.$el; } - var $lis = $group.find('[data-select-class]').addBack('[data-select-class]'); - var classes = $lis.map(function () {return $(this).data('selectClass');}).get().join(' '); + var $lis = $group.find('[data-select-class]'); + var classes = $lis.map(function () { + return $(this).data('selectClass'); + }).get().join(' '); this.$target.removeClass(classes); if (value) { @@ -146,15 +141,19 @@ var SnippetOption = Widget.extend({ /** * Default option method which allows to select one or multiple classes in * the option classes set and set it on the associated snippet. The common - * case is having a subdropdown with each item having a `data-toggle-class` + * case is having a sub-collapse with each item having a `data-toggle-class` * value allowing to toggle the associated class. * * @see this.selectClass */ toggleClass: function (previewMode, value, $opt) { - var $lis = this.$el.find('[data-toggle-class]').addBack('[data-toggle-class]'); - var classes = $lis.map(function () {return $(this).data('toggleClass');}).get().join(' '); - var activeClasses = $lis.filter('.active, :has(.active)').map(function () {return $(this).data('toggleClass');}).get().join(' '); + var $lis = this.$el.find('[data-toggle-class]'); + var classes = $lis.map(function () { + return $(this).data('toggleClass'); + }).get().join(' '); + var activeClasses = $lis.filter('.active, :has(.active)').map(function () { + return $(this).data('toggleClass'); + }).get().join(' '); this.$target.removeClass(classes).addClass(activeClasses); if (value && previewMode !== 'reset') { @@ -168,7 +167,7 @@ var SnippetOption = Widget.extend({ /** * Override the helper method to search inside the $target element instead - * of the dropdown item element. + * of the UI item element. * * @override */ @@ -211,7 +210,7 @@ var SnippetOption = Widget.extend({ */ _reset: function () { var self = this; - var $actives = this.$el.find('.active').addBack('.active'); + var $actives = this.$el.find('we-button.active'); _.each($actives, function (activeElement) { var $activeElement = $(activeElement); self.__methodNames = _.without.apply(_, [self.__methodNames].concat(_.keys($activeElement.data()))); @@ -233,8 +232,6 @@ var SnippetOption = Widget.extend({ * @param {jQuery} $opt - the related DOMElement option */ _select: function (previewMode, $opt) { - var self = this; - // Options can say they respond to strong choice if (previewMode && ($opt.data('noPreview') || $opt.parent().data('noPreview'))) { return; @@ -244,7 +241,6 @@ var SnippetOption = Widget.extend({ if (!previewMode) { this._reset(); this.trigger_up('request_history_undo_record', {$target: this.$target}); - this.$target.trigger('content_changed'); } // Search for methods (data-...) (i.e. data-toggle-class) on the @@ -275,6 +271,8 @@ var SnippetOption = Widget.extend({ if (!previewMode) { this._setActive(); } + + this.$target.trigger('content_changed'); }, /** * Tweaks the option DOM elements to show the selected value according to @@ -286,7 +284,6 @@ var SnippetOption = Widget.extend({ _setActive: function () { var self = this; this.$el.find('[data-toggle-class]') - .addBack('[data-toggle-class]') .removeClass('active') .filter(function () { var className = $(this).data('toggleClass'); @@ -295,25 +292,20 @@ var SnippetOption = Widget.extend({ .addClass('active'); // Get submenus which are not inside submenus - var $submenus = this.$el.find('.dropdown-submenu') - .addBack('.dropdown-submenu') - .not('.dropdown-submenu .dropdown-submenu'); + var $submenus = this.$el.find('we-collapse-area') + .not('we-collapse-area we-collapse-area'); // Add unique active class for each submenu active item _.each($submenus, function (submenu) { - var $elements = _getSelectClassElements($(submenu)); + var $elements = $(submenu).find('[data-select-class]'); _processSelectClassElements($elements); }); // Add unique active class for out-of-submenu active item - var $externalElements = _getSelectClassElements(this.$el) - .not('.dropdown-submenu *, .dropdown-submenu'); + var $externalElements = this.$el.find('[data-select-class]') + .not('we-collapse-area *, we-collapse-area'); _processSelectClassElements($externalElements); - function _getSelectClassElements($el) { - return $el.find('[data-select-class]') - .addBack('[data-select-class]'); - } function _processSelectClassElements($elements) { var maxNbClasses = -1; $elements.removeClass('active') @@ -343,20 +335,11 @@ var SnippetOption = Widget.extend({ * @param {Event} ev */ _onLinkEnter: function (ev) { - var $opt = $(ev.target).closest('.dropdown-item'); + var $opt = $(ev.target).closest('we-button'); if (!$opt.length) { return; } - var $dsmenu = $opt.parent('.dropdown-submenu'); - if ($dsmenu.length) { - var $menu = $dsmenu.children('.dropdown-menu'); // FIXME - if ($menu.length) { - var menuRightPosition = $dsmenu.offset().left + $dsmenu.outerWidth() + $menu.outerWidth(); - $menu.toggleClass('o_open_to_left', menuRightPosition > $(window).outerWidth()); - } - } - if (!$opt.is(':hasData')) { return; } @@ -371,7 +354,7 @@ var SnippetOption = Widget.extend({ * @param {Event} ev */ _onLinkClick: function (ev) { - var $opt = $(ev.target).closest('.dropdown-item'); + var $opt = $(ev.target).closest('we-button'); if (ev.isDefaultPrevented() || !$opt.length || !$opt.is(':hasData')) { return; } @@ -403,8 +386,6 @@ var SnippetOption = Widget.extend({ var registry = {}; registry.sizing = SnippetOption.extend({ - preventChildPropagation: true, - /** * @override */ @@ -413,11 +394,8 @@ registry.sizing = SnippetOption.extend({ var def = this._super.apply(this, arguments); this.$handles = this.$overlay.find('.o_handle'); - var resizeValues = this._getSize(); - _.each(resizeValues, function (value, key) { - self.$handles.filter('.' + key).toggleClass('readonly', !value); - }); + var resizeValues = this._getSize(); this.$handles.on('mousedown', function (ev) { ev.preventDefault(); @@ -522,8 +500,19 @@ registry.sizing = SnippetOption.extend({ * @override */ onFocus: function () { + var resizeValues = this._getSize(); + _.each(resizeValues, (value, key) => { + this.$handles.filter('.' + key).toggleClass('readonly', !value); + }); + this._onResize(); }, + /** + * @override + */ + onBlur: function () { + this.$handles.addClass('readonly'); + }, //-------------------------------------------------------------------------- // Public @@ -596,6 +585,9 @@ registry.sizing = SnippetOption.extend({ width: ml, left: '-' + ml, }); + this.$overlay.find('.o_handle.e').css({ + width: 0, + }); _.each(this.$overlay.find(".o_handle.n, .o_handle.s"), function (handle) { var $handle = $(handle); var direction = $handle.hasClass('n') ? 'top': 'bottom'; @@ -671,7 +663,7 @@ registry.colorpicker = SnippetOption.extend({ var $clpicker = $(qweb.render('web_editor.colorpicker')); _.each($clpicker.find('.o_colorpicker_section'), function (elem) { - $(elem).prepend("<div class='text-muted mt8'>" + elem.dataset.display + "</div>"); + $(elem).prepend("<div>" + elem.dataset.display + "</div>"); }); // Retrieve excluded palettes list @@ -705,7 +697,7 @@ registry.colorpicker = SnippetOption.extend({ } $pt.find('.o_colorpicker_section_tabs').append($clpicker); - this.$el.find('.dropdown-menu').append($pt); + this.$el.find('we-collapse').append($pt); } var classes = []; @@ -945,7 +937,7 @@ registry.background = SnippetOption.extend({ _setCustomBackground: function (value) { this.__customImageSrc = value; this.background(false, this.__customImageSrc); - this.$target.addClass('oe_custom_bg'); + this.$target.toggleClass('oe_custom_bg', !!value); this._setActive(); this.$target.trigger('snippet-option-change', [this]); }, @@ -1193,7 +1185,7 @@ registry.many2one = SnippetOption.extend({ // create search button and bind search bar this.$btn = $(qweb.render('web_editor.many2one.button')) - .insertAfter(this.$overlay.find('.oe_options')); + .prependTo(this.$el); this.$ul = this.$btn.find('ul'); this.$search = this.$ul.find('li:first'); @@ -1203,17 +1195,10 @@ registry.many2one = SnippetOption.extend({ // move menu item setTimeout(function () { - if (self.$overlay.find('.oe_options').hasClass('d-none')) { - self.$btn.css('height', '0').find('> a').addClass('d-none'); - self.$ul.show().css({ - 'top': '-24px', 'margin': '0', 'padding': '2px 0', 'position': 'relative' - }); - } else { - self.$btn.find('a').on('click', function (e) { - self._clear(); - }); - } - },0); + self.$btn.find('a').on('click', function (e) { + self._clear(); + }); + }, 0); // bind search input this.$search.find('input') diff --git a/addons/web_editor/static/src/scss/web_editor.backend.scss b/addons/web_editor/static/src/scss/web_editor.backend.scss index ecbe42721f3..385bb370fd7 100644 --- a/addons/web_editor/static/src/scss/web_editor.backend.scss +++ b/addons/web_editor/static/src/scss/web_editor.backend.scss @@ -3,7 +3,7 @@ word-wrap: break-word; .note-editable { - min-height: 180px; + min-height: 330px; font: inherit !important; font-family: inherit !important; line-height: inherit !important; @@ -23,13 +23,16 @@ width: 100%; margin: 0; padding: 0; - border: 0; ul > li > p { margin: 0px; } min-height: 300px; min-height: -webkit-calc(100vh - 170px); min-height: calc(100vh - 170px); + + &.o_readonly { + border: none; + } } .rounded { border-radius: .25rem !important; 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 fd821c547c2..b03277b2b95 100644 --- a/addons/web_editor/static/src/scss/web_editor.variables.scss +++ b/addons/web_editor/static/src/scss/web_editor.variables.scss @@ -2,14 +2,22 @@ /// This files regroups the variables and mixins which are specific to the editor. /// -$o-we-font-family: Roboto, 'Montserrat', "Segoe UI","Helvetica Neue",Helvetica,Arial,sans-serif !default; +$o-we-font-family: Roboto, 'Montserrat', 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif !default; + +$o-we-font-size: 13px; +$o-we-bg-color: #F7F7F7 !default; +$o-we-bg-color-dark: #a7a7a7 !default; +$o-we-color: #212629 !default; +$o-we-border-width: 1px !default; +$o-we-border-color: rgba(0, 0, 0, 0.125) !default; +$o-we-dropdown-bg-color: #FFFFFF; +$o-we-dropdown-color: inherit; $o-we-color-dark: #2c2c36 !default; $o-we-color-darker: darken($o-we-color-dark, 2%) !default; $o-we-color-divider: #33363e !default; $o-we-color-light: #4e525b !default; -$o-we-color-normal: #50545d !default; -$o-we-color-paper: #fcfcfc !default; +$o-we-color-normal: #3D4047 !default; $o-we-color-text-normal: #999999 !default; $o-we-color-text-light: #d4d5d7 !default; $o-we-color-text-lighter: #ebecee !default; @@ -18,58 +26,38 @@ $o-we-color-warning: #f0ad4e !default; $o-we-color-success: #40ad67 !default; $o-we-color-info: #6999a8 !default; -$o-we-sidebar-width: 210px !default; +$o-we-sidebar-width: 230px !default; -$o-we-tab-active-bg: #3D4048 !default; +$o-we-handles-offset-to-hide: 10000px !default; +$o-we-handles-btn-size: 18px !default; +$o-we-handles-accent-color: #00e2ff !default; +$o-we-handles-accent-color-preview: $o-enterprise-color !default; +$o-we-handle-edge-size: 8px !default; +$o-we-handle-border-width: 2px !default; +$o-we-handle-border-width-preview: 6px !default; // Transitions $o-we-md-ease: cubic-bezier(0.19, 1, 0.22, 1) !default; // Editor -$o-we-dropzone-size: 40px !default; +$o-we-dropzone-size: 30px !default; // $grid-gutter-width (todo: allow to use the variable) $o-we-dropzone-border-width: 2px !default; $o-we-dropzone-border: $o-we-dropzone-border-width dashed $o-brand-odoo !default; -$o-we-handle-edge-size: 1px !default; -$o-we-handle-border-width: 1px !default; -$o-we-handles-offset-to-hide: 10000px !default; -$o-we-handles-accent-color: #00e2ff !default; -$o-we-handles-btn-size: 18px !default; - -$o-we-overlay-option-size: 25px !default; - $o-we-ace-color: #2F3129 !default; $o-we-switch-size: 2ex !default; -$o-we-switch-inactive-color: $o-we-color-paper !default; +$o-we-switch-inactive-color: $o-we-bg-color !default; // Checklist $o-checklist-margin-left: 20px; $o-checklist-checkmark-width: 2px; $o-checklist-before-size: 13px; -$o-wysiwyg-zindex: 1000; - -$o-wysiwyg-md-ease: cubic-bezier(0.19, 1, 0.22, 1) !default; - -$o-wysiwyg-font-family: Roboto, -"Montserrat", -"Segoe UI", -"Helvetica Neue", -Helvetica, -Arial, -sans-serif; - -$o-wysiwyg-toolbar-height: 32px; - -$o-wysiwyg-color: #212629 !default; -$o-wysiwyg-color-light: #616669 !default; -$o-wysiwyg-color-danger: #912629 !default; -$o-wysiwyg-color-success: #219629 !default; -$o-wysiwyg-bg-color: #f7f7f7 !default; -$o-wysiwyg-bg-color-dark: #a7a7a7 !default; -$o-wysiwyg-border-color: #a9a9a9 !default; +$o-we-zindex: 1000; +$o-we-overlay-zindex: $o-we-zindex - 10; +$o-we-toolbar-height: 32px; // ============ 'Preview' component Mixins =============== // Create a "preview" work-area to edit/customize specific elements @@ -191,7 +179,7 @@ $o-wysiwyg-border-color: #a9a9a9 !default; .modal-content { border-radius: 0; - background-color: $o-we-color-paper; + background-color: $o-we-bg-color; .modal-header { border-bottom-color: #e9ecef; @@ -222,7 +210,7 @@ $o-wysiwyg-border-color: #a9a9a9 !default; &.active { &, &:hover, &:focus { color: $o-we-color-normal; - background-color: $o-we-color-paper; + background-color: $o-we-bg-color; border-color: #dee2e6 #dee2e6 #FFFFFF; } } @@ -242,11 +230,11 @@ $o-wysiwyg-border-color: #a9a9a9 !default; @include button-variant($o-brand-primary, $o-brand-primary); } &.btn-secondary { - @include button-variant($o-we-color-paper, $o-we-color-paper); + @include button-variant($o-we-bg-color, $o-we-bg-color); color: $o-brand-primary; } &.btn-link { - @include button-variant($o-we-color-paper, $o-we-color-paper); + @include button-variant($o-we-bg-color, $o-we-bg-color); color: $o-brand-primary; } &.btn-success { @@ -268,8 +256,8 @@ $o-wysiwyg-border-color: #a9a9a9 !default; .card { padding: 19px; margin-bottom: 20px; - background-color: $o-we-color-paper; - border: 1px solid darken($o-we-color-paper, 5%); + background-color: $o-we-bg-color; + border: 1px solid darken($o-we-bg-color, 5%); border-radius: 0; box-shadow: none; } diff --git a/addons/web_editor/static/src/scss/wysiwyg.scss b/addons/web_editor/static/src/scss/wysiwyg.scss index cd8fa7bcf44..90180133f12 100644 --- a/addons/web_editor/static/src/scss/wysiwyg.scss +++ b/addons/web_editor/static/src/scss/wysiwyg.scss @@ -1,322 +1,168 @@ -// NOTE EDITOR +// Use css variables to control the default style of the editor so that an +// external assets bundle can influence it without duplicating the css. +:root { + --o-we-toolbar-height: #{$o-we-toolbar-height}; -body.editor_enable { - padding-top: $o-wysiwyg-toolbar-height !important; -} + --o-we-bg-color: #{$o-we-bg-color}; + --o-we-bg-color-dark: #{$o-we-bg-color-dark}; + --o-we-color: #{$o-we-color}; + --o-we-color-accent: #{$o-we-color}; -#wrapwrap { - height: calc(100vh - #{$o-wysiwyg-toolbar-height}); - border: 1px solid $o-wysiwyg-border-color; - border-left: 0; - border-top: 0; + --o-we-dropdown-bg-color: #{$o-we-dropdown-bg-color}; + --o-we-dropdown-color: #{$o-we-dropdown-color}; - .btn { - -webkit-user-select: none; - } + --o-we-snippets-bg-color: #{$o-we-bg-color}; + --o-we-snippets-color: #{$o-we-color}; } -// TOP BAR (EDIT) +// EDITOR TOP BAR AND POPOVER +body.editor_enable { + padding-top: var(--o-we-toolbar-height) !important; +} #web_editor-top-edit { - height: $o-wysiwyg-toolbar-height; - background-color: $o-wysiwyg-bg-color; - z-index: $o-wysiwyg-zindex - 2; + @include o-position-absolute(0, 0, auto, 0); position: fixed; - top: 0px; - right: 0px; - left: 0px; - white-space: nowrap; - border: 1px solid $o-wysiwyg-border-color; - border-bottom: 1px solid rgba(0, 0, 0, 0.125); - - transition: background-color 400ms $o-we-md-ease 0s; - font-family: $o-we-font-family; -} - -.note-editor.note-frame { - background-color: inherit; - - .note-editing-area .note-editable { - background-color: transparent !important; - color: inherit; - padding-left: 0; - padding-right: 0; - } - - &.fullscreen { - background-color: #fff; + z-index: $o-we-zindex; + height: var(--o-we-toolbar-height); + background-color: var(--o-we-bg-color); + + .note-popover .popover { + top: 0 !important; + left: 0 !important; + right: 0 !important; + border: none !important; } } -.note-editor:not(.note-frame) .note-editing-area { - overflow: visible; -} - -#web_editor-top-edit .note-popover .popover { - height: $o-wysiwyg-toolbar-height - 2; - top: 0 !important; - left: 0 !important; - padding: 0; +.wysiwyg_iframe, +.note-editor { + border: $o-we-border-width solid $o-we-border-color; margin: 0; - border: 0; - width: auto; - text-align: center; - box-shadow: none; - background-color: $o-wysiwyg-bg-color; - z-index: $o-wysiwyg-zindex; - - .popover-body { - height: $o-wysiwyg-toolbar-height - 2; - - > .btn-group { - height: $o-wysiwyg-toolbar-height - 2; - margin-top: 0; - } - - .btn { - height: $o-wysiwyg-toolbar-height - 2; - border-top: 0; - } - } + padding: 0; } +.note-popover .popover .popover-body, +.panel-heading.note-toolbar { + height: var(--o-we-toolbar-height); + padding-bottom: 0; + border-bottom: $o-we-border-width solid $o-we-border-color; + background-color: var(--o-we-bg-color); + font-family: $o-we-font-family; + white-space: nowrap; -#web_editor-toolbars .popover, -.note-popover.popover .popover-content, -.note-editor .note-toolbar { - font-family: $o-wysiwyg-font-family; - - h1, - h2, - h3, - h4, - h5, - h6, - .h1, - .h2, - .h3, - .h4, - .h5, - .h6 { - font-family: $o-wysiwyg-font-family; - } - - .btn { + // Main layout of buttons + .btn-group, .btn { + width: auto !important; + height: 100% !important; + margin-top: 0; + margin-bottom: 0; + background: transparent; border: none; border-radius: 0; - background-color: inherit; + } + .btn-secondary { color: inherit; - transition: all 0.3s ease 0s; + } + + // Active buttons and opened dropdowns + .btn { + padding: 0.5em 0.75em !important; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + color: var(--o-we-color); + font-size: $o-we-font-size !important; - >.fa { - color: inherit; + &.active { + background-color: var(--o-we-bg-color-dark); + color: var(--o-we-color-accent); } &:hover { - border-top: 2px solid inherit; - color: inherit; - - >.fa { - color: inherit; - } + color: var(--o-we-color-accent); } - .o_image_alt { - @include o-text-overflow(inline-block); - max-width: 100px; + &:focus, &:active, &:focus:active { + @extend %we-active-button; } - - &.active { - background-color: inherit; - color: inherit; - box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.5); - - >.fa { - color: inherit; - } + } + .btn-group.show { + > .btn { + @extend %we-active-button; } - - &.o_disabled { - opacity: 0.5; - pointer-events: none; + &::after { + content: ''; + @include o-position-absolute(100%, $o-we-border-width, auto, $o-we-border-width); + height: $o-we-border-width; + background-color: var(--o-we-dropdown-bg-color); } } - - .note-btn-group { - margin: 0; - } - - >.btn-group { - margin-top: 0; - - &.show, - .btn-group.show { - .dropdown-toggle { - border-top: 2px solid white; - background-color: $o-wysiwyg-bg-color-dark; - box-shadow: none; - - >.fa, - >span { - color: inherit; - } - } - } + %we-active-button { + border-left-color: $o-we-border-color; + border-right-color: $o-we-border-color; + background: var(--o-we-dropdown-bg-color); + box-shadow: none !important; + outline: none !important; } - .dropdown-menu { - margin: 0; + margin-top: 0; + border: $o-we-border-width solid $o-we-border-color; + border-top-color: transparent; border-radius: 0; - background-color: $o-wysiwyg-bg-color; - color: inherit; - white-space: normal; - - .dropdown-item { - width: 100%; - color: inherit; - - >.fa { - color: inherit; - } - - &:hover { - background-color: $o-wysiwyg-bg-color-dark; - color: inherit; - - >.fa { - color: inherit; - } - } - } + background-color: var(--o-we-dropdown-bg-color); + color: var(--o-we-dropdown-color); + box-shadow: none; } - - .note-para .dropdown-menu { + .dropdown-menu.show { // To overcome .note-XXX .dropdown-menu rules min-width: 0; - white-space: nowrap; } + .dropdown-item { // To overcome summernote rules breaking this in iframes + display: block; + max-width: none; + overflow: visible; + color: var(--o-we-color); - .note-color { - - .note-back-color-preview, - .note-fore-color-preview { - .dropdown-toggle { - padding: 0px 7px; - height: 35px; - width: auto; - border-top: none; - border-bottom: 3px solid; - - &:after { - display: none; - } - } - } - - .dropdown-menu { - min-width: 180px; - - .note-custom-color { - cursor: pointer; - border-radius: 5px; - - &:hover { - background-color: gray('400'); - color: black - } - } - } - - .dropdown-toggle:after { - display: none; - } - - .note-palette:first-child { - width: 100%; - - .note-color-reset, - .note-custom-color { - width: 162px; - } - - .note-color-reset { - padding: 0 3px !important; - height: 32px; - } - - .note-holder, - .note-color-palette .note-color-row, - .note-custom-color-palette .note-color-row { - height: auto !important; - - &::after { - content: ""; - display: table; - clear: both; - } - - .note-color-btn { - float: left; - height: 20px; - width: 20px; - margin: 1px 1px 0 0; - border: 1px solid black; - cursor: pointer; - @include o-alpha-button-preview; - - &.o_small { - width: 16px; - height: 16px; - margin: 3px 3px 2px 2px; - border-radius: 50%; - } - - &.o_clear { - clear: both; - } + &:hover { + background-color: var(--o-we-bg-color) !important; + color: var(--o-we-color-accent) !important; - &.o_btn_transparent { - display: none; - } - } + > * { + color: inherit !important; } } } -} - -.note-popover.popover.note-hint-popover .popover-content { - height: auto; -} -.note-popover, -.note-editor { - .modal .modal-footer p { - display: none; + // Specific elements + .o_image_alt { + @include o-text-overflow(); + max-width: 150px; } -} - -.note-handle { - pointer-events: none; - - .note-control-selection { - z-index: 1; - overflow: hidden; - - .note-control-se { - border-top: 0; - border-left: 0; - background: transparent; - } + .note-color-palette div .note-color-btn { + border-color: var(--o-we-dropdown-bg-color); } } -.o_fake_editable:not([data-oe-model]):focus { - outline: none; +// ANIMATIONS +@keyframes fadeInDownSmall { + 0% { + opacity: 0; + transform: translate(0, -5px); + } + 100% { + opacity: 1; + transform: translate(0, 0); + } } -.note-editor.dragover .note-dropzone { - z-index: $o-wysiwyg-zindex + 1; +@keyframes inputHighlighter { + from { + background: $o-brand-primary; + } + to { + width: 0; + background: transparent; + } } // MODALS - body .modal { // SELECT MEDIA @@ -362,7 +208,7 @@ body .modal { @include o-position-absolute($top: 0, $right: 0); border-radius: 0 0 0 2px; &:hover { - color: $o-wysiwyg-color-danger; + color: $o-we-color-danger; } } @@ -390,7 +236,7 @@ body .modal { } .font-icons-icons { - >span { + > span { text-align: center; font-size: 22px; margin: 5px; @@ -401,8 +247,8 @@ body .modal { &.o_selected { cursor: auto; - background-color: $o-wysiwyg-bg-color-dark; - box-shadow: 0px 0px 0px 1px $o-wysiwyg-color-success; + background-color: $o-we-bg-color-dark; + box-shadow: 0px 0px 0px 1px $o-we-color-success; } } } @@ -421,7 +267,7 @@ body .modal { position: relative; width: 100%; - >textarea { + > textarea { width: 100%; min-height: 95px; padding-bottom: 25px; @@ -460,7 +306,7 @@ body .modal { .cropper-point { background-color: white; - transition: all 400ms $o-wysiwyg-md-ease 0s; + transition: all 400ms $o-we-md-ease 0s; transform: scale(1.5, 1.5); border-radius: 10px; box-shadow: 0 0 1px 1px rgba(23, 23, 23, 0.5); @@ -482,7 +328,7 @@ body .modal { // LINK EDITOR DIALOG COLOR SELECTOR .o_link_dialog { - .o_link_dialog_color>.o_link_dialog_color_item { + .o_link_dialog_color > .o_link_dialog_color_item { position: relative; width: 30px; height: 30px; @@ -490,7 +336,7 @@ body .modal { border: 2px solid rgba(0, 0, 0, 0.25); border-radius: 50%; - input:checked+i::before { + input:checked + i::before { content: "\f00c"; @include o-position-absolute($top: 6px, $left: 5px); } @@ -498,7 +344,7 @@ body .modal { &.btn-link { padding: 3px 9px; - >span { + > span { text-decoration: underline; } } @@ -511,7 +357,7 @@ body .modal { .o_we_image_optimize_dialog { .o_we_title_label { - font-size: 1rem; + font-size: $o-we-font-size; } .o_we_preview_area { max-height: 400px; @@ -539,32 +385,3 @@ img.o_we_selected_image { img.o_we_custom_image.mx-auto { display: block; } - -// ENTER IN EDIT MODE - -.note-editor .css_editable_mode_display { - border: 1px dashed rgba(153, 153, 153, 0.5); - display: block !important; -} - -.note-editable { - - li, - p, - h1, - h2, - h3, - h4, - h5, - h6 { - &:empty:after { - content: "\00a0" - } - } -} - -.wysiwyg_iframe { - margin: 0; - padding: 0; - border: 0; -} diff --git a/addons/web_editor/static/src/scss/wysiwyg_iframe.scss b/addons/web_editor/static/src/scss/wysiwyg_iframe.scss index e1af34e41fa..e7554317994 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_iframe.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_iframe.scss @@ -16,21 +16,8 @@ iframe.wysiwyg_iframe.o_fullscreen { body.o_in_iframe { background-color: $o-view-background-color; - overflow: auto; - - .note-editable { - height: calc(100vh - #{$o-wysiwyg-toolbar-height} - 2px); - } .note-statusbar { display: none; } - - #web_editor-toolbars .popover .btn { - font-size: 1rem; - } - - .o_mail_theme_selector .btn { - font-size: 1rem; - } } diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss index 6b576acecba..70665b4861f 100644 --- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss +++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss @@ -2,86 +2,74 @@ /// This file contains all variables and mixins that are specific to the editor. /// -$o-wysiwyg-handles-accent-color: #00e2ff !default; -$o-wysiwyg-handle-edge-size: 1px !default; -$o-wysiwyg-dropzone-size: 40px !default; -$o-wysiwyg-sidebar-width: 210px !default; -$o-wysiwyg-sidebar-height: 36px !default; -$o-wysiwyg-overlay-option-size: 25px !default; -$o-wysiwyg-handles-btn-size: 18px !default; -$o-wysiwyg-handle-border-width: 1px !default; - -$o-wysiwyg-handles-offset-to-hide: 10000px !default; - // OVERRIDES FOR EDITOR WITH SNIPPETS body.editor_enable.editor_has_snippets { padding-left: $o-we-sidebar-width !important; #web_editor-top-edit .note-popover .popover { - margin: 0 0 0 $o-we-sidebar-width; - } -} - -// NOTE EDITOR -.note-editor.o_snippets_loaded { - transition: padding-left 400ms $o-wysiwyg-md-ease 0s; - padding-left: 210px !important; -} - -.note-editor.note-frame .note-editing-area .o_wrap_editable_snippets { - overflow: auto; - - .note-editable { - overflow: visible; + left: $o-we-sidebar-width !important; } } -.o_in_iframe .note-editor.o_snippets_loaded .note-editable { - padding-top: 30px; -} - // SNIPPET PANEL #oe_snippets { @include o-w-preserve-btn; + @include o-position-absolute(0, auto, 0, -$o-we-sidebar-width); + position: fixed; + z-index: $o-we-zindex; display: flex; flex-flow: column nowrap; - position: fixed; - top: 0; - width: $o-wysiwyg-sidebar-width; - z-index: $o-wysiwyg-zindex - 1; + width: $o-we-sidebar-width; - font-family: Roboto, $font-family-sans-serif; - border-right: 1px solid #aaa; - transition: left 400ms $o-wysiwyg-md-ease 0s; - background-image: linear-gradient(45deg, $o-wysiwyg-bg-color, darken($o-wysiwyg-bg-color, 10%)); + border-right: $o-we-border-width solid $o-we-border-color; + background-color: var(--o-we-snippets-bg-color); + color: var(--o-we-snippets-color); box-shadow: 0px 10px 10px -10px black inset; - border: 1px solid $o-wysiwyg-border-color; + font-family: Roboto, $font-family-sans-serif; + + transition: left 400ms $o-we-md-ease 0s; + + &.o_loaded { + left: 0 !important; + } #snippets_menu { flex: 0 0 auto; - height: $o-wysiwyg-toolbar-height; - line-height: $o-wysiwyg-sidebar-height; - margin: 0; - padding: 0; - background: $o-wysiwyg-bg-color; - text-align: center; - font-weight: normal; - font-size: 17px; - color: $o-wysiwyg-color; - font-family: $o-wysiwyg-font-family; + display: flex; + height: var(--o-we-toolbar-height); + background: var(--o-we-bg-color); + color: var(--o-we-color); + font-family: $o-we-font-family; + + > button { + flex: 1 1 auto; + border: none; + background: transparent; + color: inherit; + @include o-text-overflow(); + + &.active { + background: var(--o-we-snippets-bg-color); + color: var(--o-we-snippets-color); + } + } } - #o_scroll { + > #o_scroll, > .o_we_customize_panel { + flex: 1 1 auto; height: 100%; overflow: auto; + } + + > #o_scroll { .o_panel_header { display: flex; align-items: center; justify-content: center; padding: 3%; - color: $o-wysiwyg-color; + color: inherit; margin-bottom: 3%; i { @@ -149,24 +137,156 @@ body.editor_enable.editor_has_snippets { } } - &:nth-child(2n+1) { + &:nth-child(2n + 1) { clear: left; } } } } - &.o_loaded { - left: 0 !important; + > .o_we_customize_panel { + + we-button, we-toggler { + cursor: pointer; + @include o-text-overflow(inline-block); + padding: 0.25rem 0.5rem; + margin: 0; + background-color: var(--o-we-bg-color-dark); + color: var(--o-we-color); + line-height: 1.5; + font-weight: 500; + white-space: nowrap; + } + + %we-icon-button { + position: relative; + + &::after { + position: absolute; + width: 1em; + right: 0.5em; + text-align: center; + font-family: FontAwesome; + } + } + + @mixin we-icon-button($icon, $color: null) { + @extend %we-icon-button; + padding-right: 0.5em + 1em + 0.5em; + + &::after { + content: $icon; + color: $color; + } + } + + we-customizeblock-options { + display: block; + border: $o-we-border-width solid var(--o-we-snippets-color); + color: var(--o-we-snippets-color); + margin-top: 0.25rem; + + > we-title { + display: flex; + align-items: center; + margin: 0.25rem 0; + padding: 0 0.5rem; + font-weight: bold; + color: inherit !important; + + @include we-icon-button('\f107'); + + > we-button-group { + flex: 0 0 auto; + display: block; + margin-left: auto; + text-align: center; + + > we-button { + margin-left: 0.25rem; + width: 1.5rem; + padding: 0.125rem; + } + } + } + } + + we-customizeblock-option { + position: relative; + display: block; + overflow: hidden; + max-height: 500px; + transition: max-height 200ms ease 0s; + + > * { + display: block; + margin-top: 0.25rem; + } + + we-button, we-toggler { + display: block; + text-align: left; + border-radius: 0; + } + we-button { + &.we-button-hover-icon:hover { + @include we-icon-button('\f040'); + } + + &.active { + @include we-icon-button('\f00c', $o-we-color-success); + } + } + we-collapse { + position: relative; + display: block; + max-height: 0; + overflow: hidden; + transition: max-height 200ms ease 0s; + } + we-toggler { + @include we-icon-button('\f104'); + + &.active { + @include we-icon-button('\f107'); + + + we-collapse { + max-height: 500px; + } + } + } + + .dropdown-menu { + // FIXME temporary fix for m2o option for example + position: static !important; + } + } + + we-customizeblock-options.o_we_closed { + cursor: pointer; + + > we-title { + @include we-icon-button('\f104'); + } + > we-customizeblock-option { + max-height: 0; + transition-duration: 25ms; + + + we-customizeblock-option { + margin-top: 0; + } + } + } } } .oe_snippet { // No root because can be drag and drop (and the helper is in the body) position: relative; + z-index: $o-we-zindex; width: 100px; - background-color: $o-wysiwyg-bg-color; - z-index: $o-wysiwyg-zindex; + background-color: var(--o-we-snippets-bg-color); + color: var(--o-we-snippets-color); > :not(.oe_snippet_thumbnail) { display: none !important; @@ -178,7 +298,7 @@ body.editor_enable.editor_has_snippets { .oe_snippet_thumbnail_img { width: 100%; height: 0; - border: 1px solid $o-wysiwyg-border-color; + border: $o-we-border-width solid $o-we-border-color; padding-bottom: 75%; background-size: cover; background-position: center center; @@ -193,16 +313,14 @@ body.editor_enable.editor_has_snippets { .oe_snippet_thumbnail_title { display: block; - border: 1px solid $o-wysiwyg-bg-color; padding: 5px; font-size: 12px; font-weight: 300; text-shadow: none; - color: $o-wysiwyg-color; } &:hover .oe_snippet_thumbnail_title { - color: $o-wysiwyg-color-light; + color: var(--o-we-color-accent); } } } @@ -212,66 +330,59 @@ body.editor_enable.editor_has_snippets { .o_colorpicker_sections { font-size: 14px; - .o_colorpicker_section_tabs { - width: 225px; - height: 100%; - } - button { float: left; - height: 25px; - width: 25px; - margin: 1px 1px 0 2px; - border: 1px solid black; + width: percentage(1 / 8); + padding-top: percentage(1 / 8); + margin: 0; + border: none; + box-shadow: inset 0 0 0 1px var(--o-we-snippets-bg-color); } - div[data-group="transparent_grayscale"] button { - @include o-alpha-button-preview; - - &.o_small { - width: 23px; - height: 23px; - margin: 2px; - border-radius: 50%; - } + .o_colorpicker_section { - &:hover, - &.selected { - box-shadow: 0px 0px 2px 2px $o-wysiwyg-color; + > :first-child { + margin: 8px 0 4px; } + button { + position: relative; - &.selected:before { - content: "\f00c"; - font-family: "FontAwesome"; - padding-top: 1px; - color: theme-color('success'); - } + &.o_small { + border-radius: 50%; + } - &[data-event="foreColor"] { - background-color: $o-wysiwyg-bg-color; + &:hover, + &.selected { + box-shadow: inset 0 0 1px 1px var(--o-we-snippets-bg-color); + } - &:before { - background-color: rgba(white, 0.3); + &.selected::before { + @include o-position-absolute(0, 0, 0, 0); + content: "\f00c" !important; + display: flex; + justify-content: center; + align-items: center; + font-family: FontAwesome !important; + color: $o-we-color-success; } - } - &.o_btn_transparent::before { - background-color: transparent; + &.o_btn_transparent::before { + background-color: transparent; + } } - } - .note-color-palette>div { - clear: both; - } + &[data-name="transparent_grayscale"] button { + @include o-alpha-button-preview; - .note-color-row { - height: 28px; + &::before, &::after { + box-shadow: inherit; + } + } } } .note-palette-title { - padding: 10px 0px 10px 10px; - color: $o-wysiwyg-color-light; + padding: 10px 0 10px 10px; font-weight: bold; } @@ -282,14 +393,14 @@ body.editor_enable.editor_has_snippets { .note-color-reset { font-size: 20px !important; - color: desaturate(rgba($o-wysiwyg-color-danger, 0.6), 40%); + color: desaturate(rgba($o-we-color-danger, 0.6), 40%); margin: 1px 0 0; padding: 0; cursor: pointer; &:hover { background: transparent !important; - color: $o-wysiwyg-color-danger; + color: $o-we-color-danger; } } } @@ -298,50 +409,26 @@ body.editor_enable.editor_has_snippets { // DROPZONES @keyframes dropZoneInsert { to { - background-color: rgba($o-brand-odoo, 0.2); + background-color: rgba($o-brand-odoo, 0.3); } } -.note-editable .oe_drop_zone { - background-color: rgba($o-brand-odoo, 0.05); +.oe_drop_zone { + background-color: rgba($o-brand-odoo, 0.15); animation: dropZoneInsert 1s linear 0s infinite alternate; &.oe_insert { - z-index: $o-wysiwyg-zindex - 1; - - border: 2px dashed $o-wysiwyg-border-color; - border-top: none; - border-bottom: none; - position: relative; + z-index: $o-we-overlay-zindex; width: 100%; - height: $o-wysiwyg-dropzone-size; - margin: (-$o-wysiwyg-dropzone-size/2) 0; - - &:after { - content: ""; - display: block; - width: 100%; - height: 50%; - border-bottom: 2px dashed $o-wysiwyg-border-color; - box-sizing: content-box; - } + height: $o-we-dropzone-size; + margin: (-$o-we-dropzone-size/2) 0; + border: 2px dashed $o-we-border-color; &.oe_vertical { - border: 2px dashed $o-brand-odoo; - border-left: none; - border-right: none; - - width: $o-wysiwyg-dropzone-size; + width: $o-we-dropzone-size; float: left; - margin: 0 (-$o-wysiwyg-dropzone-size/2); - - &:after { - width: 50%; - height: 100%; - border-bottom: none; - border-right: 2px dashed $o-wysiwyg-border-color; - } + margin: 0 (-$o-we-dropzone-size/2); } } } @@ -349,13 +436,14 @@ body.editor_enable.editor_has_snippets { // MANIPULATORS #oe_manipulators { position: relative; - z-index: 1; + z-index: $o-we-overlay-zindex; // SNIPPET MANIPULATORS .oe_overlay { @include o-position-absolute; display: none; height: 0; + border-color: $o-we-handles-accent-color-preview; background: transparent; text-align: center; transition: opacity 400ms linear 0s; @@ -363,381 +451,82 @@ body.editor_enable.editor_has_snippets { &.o_keypress { opacity: 0; } - &.oe_active { display: block; } - - // OVERLAY OPTIONS - >.oe_overlay_options { - font-family: $o-wysiwyg-font-family; - @include o-position-absolute($bottom: 0, $left: 0); - width: 250px; // the parent oe_overlay has a width equal to the snippet width, the 250px is there to force the options to stay on one line without overriding bootstrap .btn-group - text-align: left; - z-index: $o-wysiwyg-zindex + 1; - - >.btn-group { - white-space: nowrap; - border: 0; - - .btn { - display: inline-block; - width: $o-wysiwyg-overlay-option-size; - height: $o-wysiwyg-overlay-option-size; - padding: 0; - border: 1px solid $o-wysiwyg-bg-color; - line-height: $o-wysiwyg-overlay-option-size; - font-size: 11px; - border-radius: 0; - font-weight: normal; - - transition: all 400ms ease 0s; - color: $o-wysiwyg-color; - background-color: $o-wysiwyg-bg-color; - - &:hover { - color: $o-wysiwyg-color-light; - background-color: lighten($o-wysiwyg-bg-color, 10%); - } - - &.oe_snippet_remove { - color: $o-wysiwyg-color; - background-color: $o-wysiwyg-color-danger; - border-color: darken($o-wysiwyg-color-danger, 20%); - - >.fa { - color: $o-wysiwyg-color; - } - - &:hover { - background-color: darken($o-wysiwyg-color-danger, 20%); - } - } - - &.oe_snippet_parent>i { - transform: scaleX(-1); - font-size: 12px; - } - - >.fa { - color: $o-wysiwyg-color; - line-height: inherit; - vertical-align: top; - } - } - - // CUSTOMIZE MENU BUTTON - >.oe_options { - .btn { - width: auto; - padding: 0 25px 0 5px; - background-color: $o-wysiwyg-bg-color; - text-transform: uppercase; - - &:hover, - &:active, - &:focus { - background-color: lighten($o-wysiwyg-bg-color, 5%); - border-color: lighten($o-wysiwyg-bg-color, 10%); - } - - &:before, - &:after { - content: ""; - width: 7px; - height: 2px; - background-color: $o-wysiwyg-color-light; - @include o-position-absolute(46%); - transition: all 0.3s ease 0s; - } - - &:before { - right: 9px; - transform: rotate(45deg); - } - - &:after { - right: 5px; - transform: rotate(-45deg); - } - } - - // Open menu - &.show .btn { - - &:active, - &:focus, - &:active:focus { - box-shadow: none; - } - - &:before, - &:after { - width: 9px; - } - - &:before { - right: 10px; - transform: translateX(5px) rotate(-45deg); - } - - &:after { - transform: rotate(45deg); - } - } - - // CUSTOMIZE MENU - .dropdown-menu { - margin: -1px 0 0 0; - padding: 0; - border: 1px solid $o-wysiwyg-bg-color; - border-radius: 0; - background-color: $o-wysiwyg-bg-color; - - .dropdown-item { - position: relative; - color: $o-wysiwyg-color-light; - font-weight: normal; - font-size: 12px; - padding: 5px 40px 5px 10px; - - &:hover { - background: transparent; - cursor: pointer; - } - - &.active { - &:before { - @include o-position-absolute($top: 5px, $right: 5px); - content: "\f00c"; - font-family: "FontAwesome"; - color: $o-brand-primary; - } - } - - >i { - width: 15px; - margin-right: 10px; - text-align: center; - } - } - - .dropdown-submenu { - position: relative; - - &::before { - @include o-position-absolute($top: 12px, $right: 10px); - @include o-caret-right(4px); - border-left-color: $o-wysiwyg-color-light; - } - - &:hover>.dropdown-menu { - display: block; - left: 100%; - top: 0; - - &.o_open_to_left { - left: auto; - right: 100%; - } - } - } - - .dropdown-divider { - display: block; - height: 1px; - border-top: 1px solid #666; - margin: 0; - } - - .dropdown-header { - color: $o-wysiwyg-color-light; - font-size: 11px; - margin-top: 2px; - text-transform: uppercase; - - &:hover { - background-color: initial; - } - - &.o_main_header { - padding-left: 10px; - } - - &.o_parent_editor_header { - position: relative; - color: $o-wysiwyg-color-light; - font-weight: 400; - font-size: 10px; - margin: 10px 0 0 10px; - text-transform: uppercase; - padding-bottom: .25em; - - &::before { - content: "\f148"; - @include o-position-absolute($top: 5px, $left: 4px); - font-family: FontAwesome; - transform: scaleX(-1); - } - - ~.dropdown-submenu .dropdown-item, - ~.dropdown-item { - font-size: 11px; - opacity: 0.7; - - &:hover { - opacity: 1; - } - } - - ~.dropdown-submenu::before { - @include o-position-absolute($top: 10px, $right: 10px); - } - } - } - } - } - } - } - - &.o_top_cover>.oe_overlay_options { - bottom: auto; - top: 1px; - right: 1px; + &.o_we_options_opened { + z-index: 1; } // HANDLES - >.o_handles { - @include o-position-absolute(-$o-wysiwyg-handles-offset-to-hide, 0, auto, 0); - z-index: $o-wysiwyg-zindex; - - &:hover>.o_handle { - background-color: rgba($o-wysiwyg-handles-accent-color, 0.05); - } - - >.o_handle { + > .o_handles { + @include o-position-absolute(-$o-we-handles-offset-to-hide, 0, auto, 0); + border-color: inherit; + > .o_handle, > .o_move_handle { position: relative; - border: 0 solid $o-wysiwyg-handles-accent-color; - transition: background 300ms ease 0s; - - &:hover, - &.o_active { - background-color: rgba($o-wysiwyg-handles-accent-color, 0.2); - - &:before { - content: ''; - @include o-position-absolute(0, $left: 50%); - width: 1px; - height: 100%; - margin-left: -1px; - background-color: rgba($o-wysiwyg-handles-accent-color, 0.5); - } - - &.w:before { - @include o-position-absolute(50%, $left: 0); - width: 100%; - height: 1px; - } - - &:after { - border-color: darken($o-wysiwyg-handles-accent-color, 10%); - background-color: darken($o-wysiwyg-handles-accent-color, 20%); - } - } - &:after { - display: block; - width: $o-wysiwyg-handles-btn-size; - height: $o-wysiwyg-handles-btn-size; - border: solid 1px darken($o-wysiwyg-handles-accent-color, 10%); - line-height: $o-wysiwyg-handles-btn-size - 2; - font-size: 14px; - font-family: FontAwesome; - background-color: darken($o-wysiwyg-handles-accent-color, 20%); - color: white; + &.w { + @include o-position-absolute($o-we-handles-offset-to-hide, auto, -$o-we-handles-offset-to-hide, 0); + width: $o-we-handle-edge-size; } - &.w:after, - &.e:after { - content: "\f07e"; + &.e { + @include o-position-absolute($o-we-handles-offset-to-hide, 0, -$o-we-handles-offset-to-hide, auto); + width: $o-we-handle-edge-size; } - &.s:after, - &.n:after { - content: "\f07d"; + &.n { + @include o-position-absolute($o-we-handles-offset-to-hide, 0, auto, 0); + height: $o-we-handle-edge-size; } - &.o_handle_start { - - &.w:after, - &.e:after { - content: '\f061'; - } - - &.n:after, - &.s:after { - content: '\f063'; - } + &.s { + @include o-position-absolute(auto, 0, -$o-we-handles-offset-to-hide, 0); + height: $o-we-handle-edge-size; } + } - &.o_handle_end { - - &.w:after, - &.e:after { - content: '\f060'; - } - - &.n:after, - &.s:after { - content: '\f062'; - } - } + > .o_handle { + border: 0 dashed transparent; + border-color: inherit; + transition: background 300ms ease 0s; &.w { - @include o-position-absolute($o-wysiwyg-handles-offset-to-hide, auto, -$o-wysiwyg-handles-offset-to-hide, 0); - width: $o-wysiwyg-handle-edge-size; - border-width: $o-wysiwyg-handle-border-width; + border-width: $o-we-handle-border-width-preview; border-right-width: 0; cursor: e-resize; &:after { @include o-position-absolute($top: 50%, $left: 40%); - margin-top: -$o-wysiwyg-handles-btn-size/2; + margin-top: -$o-we-handles-btn-size/2; } } - &.e { - @include o-position-absolute($o-wysiwyg-handles-offset-to-hide, 0, -$o-wysiwyg-handles-offset-to-hide, auto); - width: $o-wysiwyg-handle-edge-size; - border-right-width: $o-wysiwyg-handle-border-width; + border-right-width: $o-we-handle-border-width-preview; cursor: w-resize; &:after { @include o-position-absolute($top: 50%, $right: 40%); - margin-top: -$o-wysiwyg-handles-btn-size/2; + margin-top: -$o-we-handles-btn-size/2; } } - &.n { - @include o-position-absolute($o-wysiwyg-handles-offset-to-hide, 0, auto, 0); - border-top-width: $o-wysiwyg-handle-border-width; + border-top-width: $o-we-handle-border-width-preview; cursor: ns-resize; &:after { @include o-position-absolute($left: 50%, $top: 40%); - margin-left: -$o-wysiwyg-handles-btn-size/2; + margin-left: -$o-we-handles-btn-size/2; } } - &.s { - @include o-position-absolute(auto, 0, -$o-wysiwyg-handles-offset-to-hide, 0); - border-bottom-width: $o-wysiwyg-handle-border-width; + border-bottom-width: $o-we-handle-border-width-preview; cursor: ns-resize; &:after { @include o-position-absolute($left: 50%, $bottom: 40%); - margin-left: -$o-wysiwyg-handles-btn-size/2; + margin-left: -$o-we-handles-btn-size/2; } } @@ -753,6 +542,113 @@ body.editor_enable.editor_has_snippets { } } } + + > .o_move_handle { + cursor: pointer; + cursor: move; + } + } + + &.o_we_sticky { + border-color: $o-we-handles-accent-color; + + > .o_handles { + &:hover > .o_handle { + background-color: rgba($o-we-handles-accent-color, 0.05); + } + > .o_handle { + &:hover, + &.o_active { + background-color: rgba($o-we-handles-accent-color, 0.2); + + &:before { + content: ''; + @include o-position-absolute(0, $left: 50%); + width: 1px; + height: 100%; + margin-left: -1px; + background-color: rgba($o-we-handles-accent-color, 0.5); + } + + &.w:before { + @include o-position-absolute(50%, $left: 0); + width: 100%; + height: 1px; + } + + &:after { + border-color: darken($o-we-handles-accent-color, 10%); + background-color: darken($o-we-handles-accent-color, 20%); + } + } + + &:after { + z-index: 1; + display: block; + width: $o-we-handles-btn-size; + height: $o-we-handles-btn-size; + border: solid 1px darken($o-we-handles-accent-color, 10%); + line-height: $o-we-handles-btn-size - 2; + font-size: 14px; + font-family: FontAwesome; + background-color: darken($o-we-handles-accent-color, 20%); + color: white; + } + + &.w:after, + &.e:after { + content: "\f07e"; + } + + &.s:after, + &.n:after { + content: "\f07d"; + } + + &.o_handle_start { + + &.w:after, + &.e:after { + content: '\f061'; + } + + &.n:after, + &.s:after { + content: '\f063'; + } + } + + &.o_handle_end { + + &.w:after, + &.e:after { + content: '\f060'; + } + + &.n:after, + &.s:after { + content: '\f062'; + } + } + + &.w { + border-width: $o-we-handle-border-width; + border-right-width: 0; + } + &.e { + border-right-width: $o-we-handle-border-width; + } + &.n { + border-top-width: $o-we-handle-border-width; + } + &.s { + border-bottom-width: $o-we-handle-border-width; + } + } + } + } + &.o_we_options_opened > .o_handles > .o_handle { + border-style: solid; } } diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml index 6e2ae656f2d..89819b44396 100644 --- a/addons/web_editor/static/src/xml/snippets.xml +++ b/addons/web_editor/static/src/xml/snippets.xml @@ -3,29 +3,41 @@ <t t-name="web_editor.snippet_overlay"> <div class="oe_overlay"> <div class="o_handles"> + <!-- Visible overlay borders + allow to resize when not readonly --> <div class="o_handle n readonly"/> <div class="o_handle e readonly"/> <div class="o_handle w readonly"/> <div class="o_handle s readonly"/> - </div> - <div class="oe_overlay_options" contentEditable="false"> - <div class="btn-group"> - <a role="button" href="#" class="btn btn-secondary oe_snippet_parent" title="Select Parent Container" aria-label="Select Parent Container"><i class="fa fa-lg fa-level-up"/></a> - <div class="dropdown oe_options d-none btn-group"> - <a role="button" href="#" data-toggle="dropdown" class="btn btn-primary" title="Customize">Customize</a> - <div class="dropdown-menu" role="menu"/> - </div> - <a role="button" href="#" class="btn btn-secondary oe_snippet_move" title="Drag to Move" aria-label="Drag to Move"><i class="fa fa-arrows ml4 mr4"></i></a> - <a role="button" href="#" class="btn btn-secondary oe_snippet_clone" title="Duplicate Container" aria-label="Duplicate Container"><i class="fa fa-files-o ml4 mr4"></i></a> - <a role="button" href="#" class="btn btn-secondary oe_snippet_remove" title="Remove Block" aria-label="Remove Block"><i class="fa fa-trash-o ml4 mr4"></i></a> - </div> + + <!-- Invisible overlay borders which allow to drag and drop --> + <div class="o_move_handle n"/> + <div class="o_move_handle e"/> + <div class="o_move_handle w"/> + <div class="o_move_handle s"/> </div> </div> </t> + <t t-name="web_editor.customize_block_options_section"> + <we-customizeblock-options> + <we-title> + <span t-esc="name"/> + <we-button-group> + <we-button class="fa fa-files-o oe_snippet_clone" + title="Duplicate Container" + aria-label="Duplicate Container"/> + <we-button class="fa fa-trash-o oe_snippet_remove" + title="Remove Block" + aria-label="Remove Block"/> + </we-button-group> + </we-title> + </we-customizeblock-options> + </t> + <t t-name="web_editor.customize_block_option"> + <we-customizeblock-option/> + </t> <!-- options --> <div t-name="web_editor.snippet.option.colorpicker" class="colorpicker"> - <div class="note-palette-title">Background Color</div> <div class="btn-group palette-reset"> <div class="note-color-reset" data-event="foreColor" data-value="inherit" title="None" role="img" aria-label="No color"> <i class="fa fa-ban"/> diff --git a/addons/web_editor/static/tests/test_utils.js b/addons/web_editor/static/tests/test_utils.js index 3b1563d3182..7898ed63f95 100644 --- a/addons/web_editor/static/tests/test_utils.js +++ b/addons/web_editor/static/tests/test_utils.js @@ -79,25 +79,24 @@ MockServer.include({ 'data-drop-in=".note-editable" data-drop-near="p, h1, h2, h3, blockquote, .s_hr"></div>' + ' <div data-js="sizing_y" data-selector=".s_hr, .test_option_all"></div>' + ' <div data-js="colorpicker" data-selector=".test_option_all">' + - ' <div class="dropdown-submenu">' + - ' <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a>' + - ' <div class="dropdown-menu" role="menu"/>' + - ' </div>' + + ' <we-collapse-area>' + + ' <we-toggler><i class="fa fa-eyedropper"/> Background Color</we-toggler>' + + ' <we-collapse/>' + + ' </we-collapse-area>' + ' </div>' + ' <div data-js="background" data-selector=".test_option_all">' + - ' <a tabindex="-1" href="#" class="dropdown-item" data-choose-image="true" data-no-preview="true"><i class="fa fa-picture-o"/>Background Image</a>' + + ' <we-button data-choose-image="true" data-no-preview="true"><i class="fa fa-picture-o"/> Background Image</we-button>' + ' </div>' + ' <div data-js="option_test" data-selector=".s_hr">' + - ' <div class="dropdown-submenu">' + - ' <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows-v"/>Alignment</a>' + - ' <div class="dropdown-menu" role="menu">' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-start">Top</a>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-center">Middle</a>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-end">Bottom</a>' + - ' <div class="dropdown-divider"/>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-stretch">Equal height</a>' + - ' </div>' + - ' </div>' + + ' <we-collapse-area>' + + ' <we-toggler><i class="fa fa-arrows-v"/> Alignment</we-toggler>' + + ' <we-collapse>' + + ' <we-button data-select-class="align-items-start">Top</we-button>' + + ' <we-button data-select-class="align-items-center">Middle</we-button>' + + ' <we-button data-select-class="align-items-end">Bottom</we-button>' + + ' <we-button data-select-class="align-items-stretch">Equal height</we-button>' + + ' </we-collapse>' + + ' </we-collapse-area>' + ' </div>' + '</div>'; return Promise.resolve(template); @@ -255,25 +254,24 @@ function wysiwygData(data) { 'data-drop-in=".note-editable" data-drop-near="p, h1, h2, h3, blockquote, .s_hr"></div>' + ' <div data-js="sizing_y" data-selector=".s_hr, .test_option_all"></div>' + ' <div data-js="colorpicker" data-selector=".test_option_all">' + - ' <div class="dropdown-submenu">' + - ' <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a>' + - ' <div class="dropdown-menu" role="menu"/>' + - ' </div>' + + ' <we-collapse-area>' + + ' <we-toggler><i class="fa fa-eyedropper"/>Background Color</we-toggler>' + + ' <we-collapse/>' + + ' </we-collapse-area>' + ' </div>' + ' <div data-js="background" data-selector=".test_option_all">' + - ' <a tabindex="-1" href="#" class="dropdown-item" data-choose-image="true" data-no-preview="true"><i class="fa fa-picture-o"/>Background Image</a>' + + ' <we-button data-choose-image="true" data-no-preview="true"><i class="fa fa-picture-o"/> Background Image</we-button>' + ' </div>' + ' <div data-js="option_test" data-selector=".s_hr">' + - ' <div class="dropdown-submenu">' + - ' <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows-v"/>Alignment</a>' + - ' <div class="dropdown-menu" role="menu">' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-start">Top</a>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-center">Middle</a>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-end">Bottom</a>' + - ' <div class="dropdown-divider"/>' + - ' <a href="#" class="dropdown-item" data-select-class="align-items-stretch">Equal height</a>' + - ' </div>' + - ' </div>' + + ' <we-collapse-area>' + + ' <we-toggler><i class="fa fa-arrows-v"/> Alignment</we-toggler>' + + ' <we-collapse>' + + ' <we-button data-select-class="align-items-start">Top</we-button>' + + ' <we-button data-select-class="align-items-center">Middle</we-button>' + + ' <we-button data-select-class="align-items-end">Bottom</we-button>' + + ' <we-button data-select-class="align-items-stretch">Equal height</we-button>' + + ' </we-collapse>' + + ' </we-collapse-area>' + ' </div>' + '</div>'; } diff --git a/addons/web_editor/views/editor.xml b/addons/web_editor/views/editor.xml index c16aca1485a..484ca4994c4 100644 --- a/addons/web_editor/views/editor.xml +++ b/addons/web_editor/views/editor.xml @@ -19,6 +19,7 @@ <link rel="stylesheet" type="text/css" href="/web_editor/static/lib/cropper/css/cropper.css"/> <script type="text/javascript" src="/web_editor/static/lib/cropper/js/cropper.js"/> <script type="text/javascript" src="/web_editor/static/lib/jQuery.transfo.js"/> + <script type="text/javascript" src="/web_editor/static/lib/nearest/jquery.nearest.js"/> <!-- odoo utils --> @@ -30,11 +31,9 @@ <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg.scss"/> <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_iframe.scss"/> - <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_snippets.scss"/> <script type="text/javascript" src="/web_editor/static/src/js/wysiwyg/fonts.js"/> - <script type="text/javascript" src="/web_editor/static/lib/nearest/jquery.nearest.js"/> <script type="text/javascript" src="/web_editor/static/src/js/base.js"/> <script type="text/javascript" src="/web_editor/static/src/js/editor/editor.js"/> <script type="text/javascript" src="/web_editor/static/src/js/editor/rte.js"/> diff --git a/addons/web_editor/views/snippets.xml b/addons/web_editor/views/snippets.xml index 3a1c6614609..6bd1a5f1597 100644 --- a/addons/web_editor/views/snippets.xml +++ b/addons/web_editor/views/snippets.xml @@ -1,7 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> <template id="snippets"> - <h2 id="snippets_menu">Add blocks</h2> + <div id="snippets_menu"> + <button type="button" class="o_we_add_snippet_btn active"> + <i class="fa fa-plus"/> Add + </button> + <t t-set="customize_title">Select an element to customize it</t> + <button type="button" class="o_we_customize_snippet_btn" + t-att-data-title="customize_title" + disabled="disabled"> + <i class="fa fa-cog"/> Customize + </button> + </div> <div id="o_scroll"> <div id="snippet_structure" class="o_panel"> @@ -26,11 +36,8 @@ data-selector="[data-oe-many2one-model]:not([data-oe-readonly])" data-no-check="true"/> - <div data-js="content" - data-selector=".s_hr" - data-drop-near="p, h1, h2, h3, blockquote, .s_hr"> - </div> - + <div data-selector=".s_hr" + data-drop-near="p, h1, h2, h3, blockquote, .s_hr"/> </template> <!-- default block --> diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index d659677c478..d3f2e7e9730 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -1410,7 +1410,7 @@ options.registry.topMenuTransparency = options.Class.extend({ enabled = value; }, }); - this.$el.find('[data-transparent]').addBack('[data-transparent]').toggleClass('active', !!enabled); + this.$el.find('[data-transparent]').toggleClass('active', !!enabled); }, }); @@ -1465,7 +1465,6 @@ options.registry.topMenuColor = options.registry.colorpicker.extend({ */ options.registry.anchorName = options.Class.extend({ xmlDependencies: ['/website/static/src/xml/website.editor.xml'], - preventChildPropagation: true, //-------------------------------------------------------------------------- // Public diff --git a/addons/website/static/src/js/tours/banner.js b/addons/website/static/src/js/tours/banner.js index 5febdf1c749..f4ddc040c69 100644 --- a/addons/website/static/src/js/tours/banner.js +++ b/addons/website/static/src/js/tours/banner.js @@ -24,10 +24,14 @@ tour.register("banner", { position: "bottom", run: "text", }, { - trigger: ".oe_overlay_options .oe_options", + trigger: ".o_we_customize_panel", extra_trigger: "#wrapwrap .s_cover h1:not(:containsExact(\"Catchy Headline\"))", content: _t("Customize any block through this menu. Try to change the background color of this block."), - position: "top", + position: "right", +}, { + trigger: '.o_we_add_snippet_btn', + content: _t("Go back to the blocks menu."), + position: 'bottom', }, { trigger: "#snippet_structure .oe_snippet:eq(3) .oe_snippet_thumbnail", content: _t("Drag another block in your page, below the cover."), @@ -35,7 +39,6 @@ tour.register("banner", { run: "drag_and_drop #wrap", }, { trigger: "button[data-action=save]", - extra_trigger: ".oe_overlay_options .oe_options", content: _t("Click the <b>Save</b> button."), position: "bottom", }, { @@ -69,7 +72,6 @@ tour.register("banner", { run: "drag_and_drop #wrap", }, { trigger: "button[data-action=save]", - extra_trigger: ".oe_overlay_options .oe_options", content: _t("Click the <b>Save</b> button."), position: "bottom", }, { diff --git a/addons/website/static/src/scss/website.editor.ui.scss b/addons/website/static/src/scss/website.editor.ui.scss index 403b7929a92..bb51136ffac 100644 --- a/addons/website/static/src/scss/website.editor.ui.scss +++ b/addons/website/static/src/scss/website.editor.ui.scss @@ -8,7 +8,7 @@ >input { display: none; - +span { + + span { background-color: $o-we-switch-inactive-color; box-shadow: inset 0 0 0px 1px darken($o-we-switch-inactive-color, 10%); border-radius: 100rem; @@ -20,7 +20,7 @@ &:after { content: ""; - background: $o-we-color-paper; + background: $o-we-bg-color; display: block; width: $o-we-switch-size - 0.2; height: $o-we-switch-size - 0.2; diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss index 1f5151f5da8..3206e4b027a 100644 --- a/addons/website/static/src/scss/website.wysiwyg.scss +++ b/addons/website/static/src/scss/website.wysiwyg.scss @@ -1,48 +1,27 @@ -//------------------------------------------------------------------------------ -// Modifications applied on normal website DOM while being in the editor. -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -// Editor components style. -//------------------------------------------------------------------------------ - -body.editor_enable { - padding-top: $o-navbar-height !important; +// Override css variables to influence the default style of the editor without +// duplicating the css. +:root { + --o-we-toolbar-height: #{$o-navbar-height}; + --o-we-bg-color: #{$o-we-color-dark}; + --o-we-bg-color-dark: #{$o-we-color-darker}; + --o-we-color: #{$o-we-color-text-normal}; + --o-we-color-accent: #{$o-we-color-text-light}; + + --o-we-dropdown-bg-color: #{$o-we-color-darker}; + --o-we-dropdown-color: #{$o-we-color-text-normal}; + + --o-we-snippets-bg-color: #{$o-we-color-normal}; + --o-we-snippets-color: #{$o-we-color-text-light}; } -#wrapwrap { - height: calc(100vh - #{$o-navbar-height}); -} - -// TOP BAR (EDIT) +// EDITOR TOP BAR AND POPOVER #web_editor-top-edit { - height: $o-navbar-height; - background-color: $o-we-color-dark; - border: 0; - z-index: $zindex-modal - 9; - - .note-popover .popover { - width: 100%; - height: $o-navbar-height; - text-align: left; - - .popover-body { - height: $o-navbar-height; - - .btn { - height: $o-navbar-height; - } - } - } - form.navbar-form { + @include o-position-absolute(0, 0, 0, auto); + z-index: $zindex-popover + 5; height: $o-navbar-height; - z-index: 1060; margin: 0; padding: 0; - position: absolute; - top: -1px; - right: -1px; transition: right 0.4s $o-we-md-ease 0s; border-left: 1px solid $o-we-color-divider; @@ -96,19 +75,11 @@ body.editor_enable { } } -body:not(.editor_enable) form.navbar-form { +.note-statusbar { display: none; } -// SNIPPETS -#oe_snippets { - border: 0; - #snippets_menu { - height: $o-navbar-height; - } -} - -// Translations +// TRANSLATIONS .oe_translate_examples li { margin: 10px; padding: 4px; @@ -126,60 +97,10 @@ html[lang] > body.editor_enable [data-oe-translation-state] { } } -// NOTE EDITOR - -// SNIPPET PANEL -#oe_snippets { - @include o-w-preserve-btn; - position: fixed; - width: $o-we-sidebar-width; - z-index: 1042; - - border-top: 0; - border-right: 1px solid $o-we-color-divider; - transition: left 400ms $o-we-md-ease 0s; - background-image: linear-gradient(45deg, $o-we-color-normal, darken($o-we-color-normal, 10%)); - - #snippets_menu { - color: #999999; - background: $o-we-color-dark; - font-family: $o-we-font-family; - height: $o-navbar-height; - line-height: $o-navbar-height; - } - - #o_scroll { - .o_panel_header { - color: #999999; - } - } -} - -.oe_snippet { - background-color: $o-we-color-normal; - - .oe_snippet_thumbnail { - .oe_snippet_thumbnail_img { - border: 1px solid $o-we-color-normal; - } - - img.oe_snippet_thumbnail_img {} - - .oe_snippet_thumbnail_title { - border: 1px solid $o-we-color-dark; - color: $o-we-color-text-light; - } - - &:hover .oe_snippet_thumbnail_title { - color: $o-we-color-text-lighter; - } - } -} - // SNIPPET OPTIONS .colorpicker { .o_colorpicker_sections { - .note-color-palette>div { + .note-color-palette > div { color: $o-we-color-text-light; } } @@ -191,7 +112,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] { clear: both; } - >button { + > button { &:hover, &.selected { @@ -223,173 +144,22 @@ html[lang] > body.editor_enable [data-oe-translation-state] { } } -// DROPZONES -#wrapwrap .oe_drop_zone { - &.oe_insert { - height: $o-we-dropzone-size; - margin: (-$o-we-dropzone-size/2) 0; - - &:after { - border-bottom: $o-we-dropzone-border; - } - - &.oe_vertical { - width: $o-we-dropzone-size; - margin: 0 (-$o-we-dropzone-size/2); - - &:after { - border-right: $o-we-dropzone-border; - } - } - } -} - -// MANIPULATORS -#oe_manipulators { - - // SNIPPET MANIPULATORS - .oe_overlay { - - // OVERLAY OPTIONS - >.oe_overlay_options { - font-family: $o-we-font-family; - - >.btn-group { - .btn { - height: $o-we-overlay-option-size; - border: 1px solid $o-we-color-dark; - line-height: #{$o-we-overlay-option-size - 2px}; - - color: $o-we-color-text-light; - background-color: $o-we-color-light; - - &:hover { - background-color: lighten($o-we-color-dark, 10%); - } - - &.oe_snippet_remove { - background-color: $o-we-color-danger; - border-color: darken($o-we-color-danger, 20%); - - &:hover { - background-color: darken($o-we-color-danger, 20%); - } - } - - >.fa { - color: $o-we-color-text-light; - } - } - - // CUSTOMIZE MENU BUTTON - >.oe_options { - .btn { - background-color: $o-we-color-dark; - color: $o-we-color-text-light; - - &:hover, - &:active, - &:focus { - background-color: lighten($o-we-color-dark, 5%); - border-color: lighten($o-we-color-dark, 10%); - } - - &:before, - &:after { - background-color: $o-we-color-text-light; - } - } - - // Open menu - &.show .btn { - // background-color: $o-we-color-light; - } - - // CUSTOMIZE MENU - .dropdown-menu { - border: 1px solid $o-we-color-dark; - background-color: $o-we-color-light; - - .dropdown-item { - color: $o-we-color-text-light; - - &:hover { - background-color: fade-out($o-we-color-dark, 0.5); - } - - &.active { - background-color: fade-out($o-we-color-dark, 0.5); - } - } - - .dropdown-header { - color: wheat; - - &.o_parent_editor_header { - color: wheat; - } - } - - .dropdown-submenu { - &::before { - border-left-color: $o-we-color-text-light; - } - } - } - } - } - } - - &.o_top_cover>.oe_overlay_options { - top: $o-we-handle-border-width; - right: $o-we-handle-border-width; - } - - } -} - -// Animations -@keyframes fadeInDownSmall { - 0% { - opacity: 0; - transform: translate(0, -5px); - } - - 100% { - opacity: 1; - transform: translate(0, 0); - } -} - +// ANIMATIONS @keyframes fadeInOut { 0% { opacity: 0; } - 25% { opacity: 1; } - 75% { opacity: 1; } - 100% { opacity: 0; } } -@keyframes inputHighlighter { - from { - background: $o-brand-primary; - } - - to { - width: 0; - background: transparent; - } -} - // MODALS body .modal { @@ -547,109 +317,3 @@ body .modal { } } } - -.note-editor { - &>.note-toolbar-wrapper .note-toolbar { - height: $o-navbar-height; - - .btn { - height: $o-navbar-height !important; // force this because of themes - } - } - - &>.note-statusbar { - display: none; - } - - &>.note-editing-area { - overflow: visible; - } -} - -#web_editor-toolbars .popover, -.note-popover, -.note-editor>.note-toolbar-wrapper .note-toolbar { - // force this because of themes - background-color: $o-we-color-dark !important; - - .btn { - background-color: $o-we-color-dark !important; - color: $o-we-color-text-normal !important; - border: none !important; - padding: 0.0625rem 0.3125rem !important; - - >.fa { - color: $o-we-color-text-normal !important; - } - - &:hover { - color: $o-we-color-text-light !important; - - >.fa { - color: $o-we-color-text-light !important; - } - } - - &.active { - background-color: $o-we-color-dark !important; - color: $o-we-color-text-light !important; - - >.fa { - color: $o-we-color-text-light !important; - } - } - } - - >.btn-group { - margin-top: 0 !important; - - &.show, - .btn-group.show { - .dropdown-toggle { - border-top: 2px solid white !important; - background-color: $o-we-color-darker !important; - color: white !important; - box-shadow: none !important; - - >.fa, - >span { - color: white !important; - } - } - } - } - - .dropdown-menu { - margin: 0 !important; - border-radius: 0 !important; - background-color: $o-we-color-darker !important; - color: $o-we-color-text-normal !important; - white-space: normal !important; - - .dropdown-item { - width: 100% !important; - color: $o-we-color-text-light !important; - - >.fa { - color: $o-we-color-text-light !important; - } - - &:hover { - background-color: $o-we-tab-active-bg !important; - color: white !important; - - >.fa { - color: white !important; - } - } - } - } - - .note-para .dropdown-menu { - min-width: 147px !important; - } - - .note-style .dropdown-item * { - color: $o-we-color-text-light !important; - } -} diff --git a/addons/website/static/tests/tours/rte.js b/addons/website/static/tests/tours/rte.js index d8c8d768162..912cb6832e0 100644 --- a/addons/website/static/tests/tours/rte.js +++ b/addons/website/static/tests/tours/rte.js @@ -55,7 +55,7 @@ tour.register('rte_translator', { run: 'drag_and_drop #wrap', }, { content: "change content", - trigger: '.oe_overlay_options .oe_options:visible', + trigger: '#wrap', run: function () { $("#wrap p:first").replaceWith('<p>Write one or <font style="background-color: yellow;">two paragraphs <b>describing</b></font> your product or\ <font style="color: rgb(255, 0, 0);">services</font>. To be successful your content needs to be\ diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml index 159219b58d1..c42f86440a1 100644 --- a/addons/website/views/snippets.xml +++ b/addons/website/views/snippets.xml @@ -914,10 +914,10 @@ data-selector=".s_three_columns .row > div, .s_comparisons .row > div, .s_tabs .row > div" data-target=".card" data-palette-title="Box Color"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- COLOR | .s_hr --> @@ -927,20 +927,20 @@ data-color-prefix="border-" data-palette-exclude="transparent_grayscale, common" data-palette-title="Separator Color"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- COLOR | .s_cards --> <div data-js="colorpicker" data-selector=".s_card, .accordion .card" data-palette-title="Card Color"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- COLOR | .s_alert --> @@ -948,314 +948,331 @@ data-selector=".s_alert" data-color-prefix="alert-" data-palette-title="Box Color"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- STYLES | .s_title --> <div data-selector=".s_title" data-target="[class*='s_title_']"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-font"/>Typography</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="s_title_boxed">Boxed</a> - <a href="#" class="dropdown-item" data-select-class="s_title_lines">Line-On-Sides</a> - <a href="#" class="dropdown-item" data-select-class="s_title_thin">Thin</a> - <a href="#" class="dropdown-item" data-select-class="s_title_transparent">Transparent</a> - <a href="#" class="dropdown-item" data-select-class="s_title_underlined">Underlined</a> - <a href="#" class="dropdown-item" data-select-class="s_title_small_caps">Small Caps</a> - <div class="dropdown-divider"/> - <a href="#" class="dropdown-item" data-select-class="s_title_default">Default</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-font"/> Typography</we-toggler> + <we-collapse> + <we-button data-select-class="s_title_boxed">Boxed</we-button> + <we-button data-select-class="s_title_lines">Line-On-Sides</we-button> + <we-button data-select-class="s_title_thin">Thin</we-button> + <we-button data-select-class="s_title_transparent">Transparent</we-button> + <we-button data-select-class="s_title_underlined">Underlined</we-button> + <we-button data-select-class="s_title_small_caps">Small Caps</we-button> + <we-divider/> + <we-button data-select-class="s_title_default">Default</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- H-ALIGN | .s_btn --> <div data-selector=".s_btn, .s_share"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-align-left"/>Alignment</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="text-left">Left</a> - <a href="#" class="dropdown-item" data-select-class="text-center">Center</a> - <a href="#" class="dropdown-item" data-select-class="text-right">Right</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-align-left"/> Alignment</we-toggler> + <we-collapse> + <we-button data-select-class="text-left">Left</we-button> + <we-button data-select-class="text-center">Center</we-button> + <we-button data-select-class="text-right">Right</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-selector=".s_alert"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows"/>Size</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="s_alert_sm">Small</a> - <a href="#" class="dropdown-item" data-select-class="s_alert_md">Medium</a> - <a href="#" class="dropdown-item" data-select-class="s_alert_lg">Large</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-arrows"/> Size</we-toggler> + <we-collapse> + <we-button data-select-class="s_alert_sm">Small</we-button> + <we-button data-select-class="s_alert_md">Medium</we-button> + <we-button data-select-class="s_alert_lg">Large</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-selector=".s_alert, .s_card"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows-h"/>Width</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="w-25">25%</a> - <a href="#" class="dropdown-item" data-select-class="w-50">50%</a> - <a href="#" class="dropdown-item" data-select-class="w-75">75%</a> - <a href="#" class="dropdown-item" data-select-class="w-100">100%</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-arrows-h"/> Width</we-toggler> + <we-collapse> + <we-button data-select-class="w-25">25%</we-button> + <we-button data-select-class="w-50">50%</we-button> + <we-button data-select-class="w-75">75%</we-button> + <we-button data-select-class="w-100">100%</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- STYLES | .s_rating --> <div data-selector=".s_rating > div"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item">Icon</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="s_rating_stars"><i class="fa fa-star"/>Stars</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_squares"><i class="fa fa-square"/>Squares</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_hearts"><i class="fa fa-heart"/>Hearts</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_bar"><i class="fa fa-tasks"/>Progress Bar</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item">Value</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="">0</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_1">1/5</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_2">2/5</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_3">3/5</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_4">4/5</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_5">5/5</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item">Size</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="s_rating_1x">Small</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_2x">Medium</a> - <a href="#" class="dropdown-item" data-select-class="s_rating_3x">Big</a> - </div> - </div> + <we-collapse-area> + <we-toggler>Icon</we-toggler> + <we-collapse> + <we-button data-select-class="s_rating_stars"><i class="fa fa-fw fa-star"/> Stars</we-button> + <we-button data-select-class="s_rating_squares"><i class="fa fa-fw fa-square"/> Squares</we-button> + <we-button data-select-class="s_rating_hearts"><i class="fa fa-fw fa-heart"/> Hearts</we-button> + <we-button data-select-class="s_rating_bar"><i class="fa fa-fw fa-tasks"/> Progress Bar</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Value</we-toggler> + <we-collapse> + <we-button data-select-class="">0</we-button> + <we-button data-select-class="s_rating_1">1/5</we-button> + <we-button data-select-class="s_rating_2">2/5</we-button> + <we-button data-select-class="s_rating_3">3/5</we-button> + <we-button data-select-class="s_rating_4">4/5</we-button> + <we-button data-select-class="s_rating_5">5/5</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Size</we-toggler> + <we-collapse> + <we-button data-select-class="s_rating_1x">Small</we-button> + <we-button data-select-class="s_rating_2x">Medium</we-button> + <we-button data-select-class="s_rating_3x">Big</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- STYLES | .s_hr --> <div data-selector=".s_hr" data-target="hr"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-minus"/>Thickness</a> - <div class="dropdown-menu" role="menu"> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-minus"/> Thickness</we-toggler> + <we-collapse> <t t-foreach="range(1,6)" t-as="s_hr_thickness"> - <a href="#" class="dropdown-item" t-attf-data-select-class="s_hr_{{s_hr_thickness}}px"><t t-esc="s_hr_thickness"/>px</a> + <we-button t-attf-data-select-class="s_hr_{{s_hr_thickness}}px"><t t-esc="s_hr_thickness"/>px</we-button> </t> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-pencil"/>Style</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="s_hr_solid">Solid</a> - <a href="#" class="dropdown-item" data-select-class="s_hr_dashed">Dashed</a> - <a href="#" class="dropdown-item" data-select-class="s_hr_dotted">Dotted</a> - <a href="#" class="dropdown-item" data-select-class="s_hr_double">Double</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-arrows-h"/>Width</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="w-25">25%</a> - <a href="#" class="dropdown-item" data-select-class="w-50">50%</a> - <a href="#" class="dropdown-item" data-select-class="w-75">75%</a> - <a href="#" class="dropdown-item" data-select-class="w-100">100%</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-align-left"/>Alignment</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="mr-auto">Left</a> - <a href="#" class="dropdown-item" data-select-class="mx-auto">Center</a> - <a href="#" class="dropdown-item" data-select-class="ml-auto">Right</a> - </div> - </div> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-pencil"/> Style</we-toggler> + <we-collapse> + <we-button data-select-class="s_hr_solid">Solid</we-button> + <we-button data-select-class="s_hr_dashed">Dashed</we-button> + <we-button data-select-class="s_hr_dotted">Dotted</we-button> + <we-button data-select-class="s_hr_double">Double</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-arrows-h"/> Width</we-toggler> + <we-collapse> + <we-button data-select-class="w-25">25%</we-button> + <we-button data-select-class="w-50">50%</we-button> + <we-button data-select-class="w-75">75%</we-button> + <we-button data-select-class="w-100">100%</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-align-left"/> Alignment</we-toggler> + <we-collapse> + <we-button data-select-class="mr-auto">Left</we-button> + <we-button data-select-class="mx-auto">Center</we-button> + <we-button data-select-class="ml-auto">Right</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- Carousel | .s_carousel | .s_quotes_carousel --> <div data-js="carousel" data-selector=":not(.o_gallery > .container) > .carousel"> - <a href="#" class="dropdown-item" data-add-slide="true" data-no-preview="true"><i class="fa fa-plus-circle"/>Add Slide</a> - <a href="#" class="dropdown-item" data-remove-slide="true" data-no-preview="true"><i class="fa fa-trash-o"/>Remove Slide</a> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-clone"/>Transition</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="slide">Slide</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="carousel-fade slide">Fade</a> - <div class="dropdown-divider"/> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="">None</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-magic"/>Style</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="s_carousel_bordered">Bordered</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="s_carousel_boxed">Boxed</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="s_carousel_rounded">Rounded</a> - <div class="dropdown-divider"/> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="s_carousel_default">Default</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-clock-o"/>Speed</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-interval="1000">1s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="2000">2s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="3000">3s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="5000">5s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="10000">10s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="0">Disable autoplay</a> - </div> - </div> + <we-button data-add-slide="true" data-no-preview="true"> + <i class="fa fa-fw fa-plus-circle"/> Add Slide + </we-button> + <we-button data-remove-slide="true" data-no-preview="true"> + <i class="fa fa-fw fa-trash-o"/> Remove Slide + </we-button> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-clone"/>Transition</we-toggler> + <we-collapse> + <we-button data-select-class="slide">Slide</we-button> + <we-button data-select-class="carousel-fade slide">Fade</we-button> + <we-divider/> + <we-button data-select-class="">None</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-magic"/> Style</we-toggler> + <we-collapse> + <we-button data-select-class="s_carousel_bordered">Bordered</we-button> + <we-button data-select-class="s_carousel_boxed">Boxed</we-button> + <we-button data-select-class="s_carousel_rounded">Rounded</we-button> + <we-divider/> + <we-button data-select-class="s_carousel_default">Default</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-clock-o"/> Speed</we-toggler> + <we-collapse> + <we-button data-interval="1000">1s</we-button> + <we-button data-interval="2000">2s</we-button> + <we-button data-interval="3000">3s</we-button> + <we-button data-interval="5000">5s</we-button> + <we-button data-interval="10000">10s</we-button> + <we-button data-interval="0">Disable autoplay</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-js="navTabs" data-selector="section .row > div" data-target=".nav-tabs"> - <a href="#" class="dropdown-item" data-add-tab="1" data-no-preview="true"><i class="fa fa-plus"/>Add Tab</a> - <a href="#" class="dropdown-item" data-remove-tab="1" data-no-preview="true"><i class="fa fa-minus"/>Remove Tab</a> + <we-button data-add-tab="1" data-no-preview="true"> + <i class="fa fa-fw fa-plus"/> Add Tab + </we-button> + <we-button data-remove-tab="1" data-no-preview="true"> + <i class="fa fa-fw fa-minus"/> Remove Tab + </we-button> </div> <div data-js="gallery" data-selector=".o_gallery"> - <a href="#" class="dropdown-item" data-add-images="true" data-no-preview="true"><i class="fa fa-plus-circle"/>Add images</a> - <a href="#" class="dropdown-item" data-remove-all-images="true" data-no-preview="true"><i class="fa fa-trash"/>Remove all images</a> - <div class="dropdown-divider"/> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-magic"/>Mode</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-mode="nomode">Float</a> - <a href="#" class="dropdown-item" role="menuitem" data-mode="masonry">Masonry</a> - <a href="#" class="dropdown-item" role="menuitem" data-mode="grid">Grid</a> - <a href="#" class="dropdown-item" role="menuitem" data-mode="slideshow">Slideshow</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-clock-o"/>Slideshow speed</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-interval="1000">1s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="2000">2s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="3000">3s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="5000">5s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="10000">10s</a> - <a href="#" class="dropdown-item" role="menuitem" data-interval="0">Disable autoplay</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-th"/>Columns</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-columns="1">1</a> - <a href="#" class="dropdown-item" role="menuitem" data-columns="2">2</a> - <a href="#" class="dropdown-item" role="menuitem" data-columns="3">3</a> - <a href="#" class="dropdown-item" role="menuitem" data-columns="4">4</a> - <a href="#" class="dropdown-item" role="menuitem" data-columns="6">6</a> - <a href="#" class="dropdown-item" role="menuitem" data-columns="12">12</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows-h"/>Images spacing</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="o_spc-none">None</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="o_spc-small">Small</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="o_spc-medium">Medium</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-class="o_spc-big">Big</a> - </div> - </div> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-paint-brush"/>Styling</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-styling="">Square</a> - <a href="#" class="dropdown-item" role="menuitem" data-styling="rounded">Rounded corners</a> - <a href="#" class="dropdown-item" role="menuitem" data-styling="img-thumbnail">Thumbnails</a> - <a href="#" class="dropdown-item" role="menuitem" data-styling="rounded-circle">Circle</a> - <a href="#" class="dropdown-item" role="menuitem" data-styling="shadow">Shadows</a> - </div> - </div> + <we-button class="we-button-hover-icon" data-add-images="true" data-no-preview="true"> + <i class="fa fa-fw fa-plus-circle"/> Add images + </we-button> + <we-button data-remove-all-images="true" data-no-preview="true"> + <i class="fa fa-fw fa-trash"/> Remove all images + </we-button> + <we-divider/> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-magic"/> Mode</we-toggler> + <we-collapse> + <we-button data-mode="nomode">Float</we-button> + <we-button data-mode="masonry">Masonry</we-button> + <we-button data-mode="grid">Grid</we-button> + <we-button data-mode="slideshow">Slideshow</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-clock-o"/> Slideshow speed</we-toggler> + <we-collapse> + <we-button data-interval="1000">1s</we-button> + <we-button data-interval="2000">2s</we-button> + <we-button data-interval="3000">3s</we-button> + <we-button data-interval="5000">5s</we-button> + <we-button data-interval="10000">10s</we-button> + <we-button data-interval="0">Disable autoplay</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-th"/> Columns</we-toggler> + <we-collapse> + <we-button data-columns="1">1</we-button> + <we-button data-columns="2">2</we-button> + <we-button data-columns="3">3</we-button> + <we-button data-columns="4">4</we-button> + <we-button data-columns="6">6</we-button> + <we-button data-columns="12">12</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-arrows-h"/> Images spacing</we-toggler> + <we-collapse> + <we-button data-select-class="o_spc-none">None</we-button> + <we-button data-select-class="o_spc-small">Small</we-button> + <we-button data-select-class="o_spc-medium">Medium</we-button> + <we-button data-select-class="o_spc-big">Big</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-paint-brush"/> Styling</we-toggler> + <we-collapse> + <we-button data-styling="">Square</we-button> + <we-button data-styling="rounded">Rounded corners</we-button> + <we-button data-styling="img-thumbnail">Thumbnails</we-button> + <we-button data-styling="rounded-circle">Circle</we-button> + <we-button data-styling="shadow">Shadows</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-js="gallery_img" data-selector=".o_gallery img"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-refresh"/>Re-order</a> - <div class="dropdown-menu" role="menu" data-no-preview="true"> - <a href="#" class="dropdown-item" role="menuitem" data-position="first">Move to first</a> - <a href="#" class="dropdown-item" role="menuitem" data-position="prev">Move to previous</a> - <a href="#" class="dropdown-item" role="menuitem" data-position="next">Move to next</a> - <a href="#" class="dropdown-item" role="menuitem" data-position="last">Move to last</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-refresh"/> Re-order</we-toggler> + <we-collapse data-no-preview="true"> + <we-button data-position="first">Move to first</we-button> + <we-button data-position="prev">Move to previous</we-button> + <we-button data-position="next">Move to next</we-button> + <we-button data-position="last">Move to last</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- Facebook Page --> <div data-js="facebookPage" data-selector=".o_facebook_page"> - <a href="#" class="dropdown-item" data-fb-page-options="true" data-no-preview="true"><i class="fa fa-facebook"/>Options</a> + <we-button class="we-button-hover-icon" data-fb-page-options="true" data-no-preview="true"> + <i class="fa fa-fw fa-facebook"/> Options + </we-button> </div> <!-- Accordion --> <div data-js="collapse" data-selector='.accordion > .card' - data-drop-in='.accordion:has(> .card)'> - </div> + data-drop-in='.accordion:has(> .card)'/> <div data-js="layout_column" data-selector="section" data-target="> * > .row:not(.s_nb_column_fixed)"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-columns"/>Number of columns</a> - <div class="dropdown-menu" role="menu" data-no-preview="true"> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="1">1</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="2">2</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="3">3</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="4">4</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="5">5</a> - <a href="#" class="dropdown-item" role="menuitem" data-select-count="6">6</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-columns"/> Number of columns</we-toggler> + <we-collapse data-no-preview="true"> + <we-button data-select-count="1">1</we-button> + <we-button data-select-count="2">2</we-button> + <we-button data-select-count="3">3</we-button> + <we-button data-select-count="4">4</we-button> + <we-button data-select-count="5">5</we-button> + <we-button data-select-count="6">6</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- V-ALIGN --> <div id="row_valign_snippet_option" data-selector=".s_text_image, .s_image_text, .s_three_columns" data-target=".row"> - <div class="dropdown-submenu"> - <a tabindex="-2" href="#" class="dropdown-item"><i class="fa fa-arrows-v"/>Alignment</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" data-select-class="align-items-start">Top</a> - <a href="#" class="dropdown-item" data-select-class="align-items-center">Middle</a> - <a href="#" class="dropdown-item" data-select-class="align-items-end">Bottom</a> - <div class="dropdown-divider"/> - <a href="#" class="dropdown-item" data-select-class="align-items-stretch">Equal height</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-arrows-v"/> Alignment</we-toggler> + <we-collapse> + <we-button data-select-class="align-items-start">Top</we-button> + <we-button data-select-class="align-items-center">Middle</we-button> + <we-button data-select-class="align-items-end">Bottom</we-button> + <we-divider/> + <we-button data-select-class="align-items-stretch">Equal height</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- Background Image --> <div data-js="background" data-selector="section, .parallax, :not(.o_gallery > .container) > .carousel" data-exclude=".s_hr, .s_image_gallery"> - <a tabindex="-1" href="#" class="dropdown-item" data-choose-image="true" data-no-preview="true"><i class="fa fa-picture-o"/>Background Image</a> + <we-button class="we-button-hover-icon" data-choose-image="true" data-no-preview="true"> + <i class="fa fa-fw fa-picture-o"/> Background Image + </we-button> </div> <!-- Background Image --> <div data-js="background_position" data-selector="section, .parallax, :not(.o_gallery > .container) > .carousel"> - <a tabindex="-1" href="#" class="dropdown-item background_position_li" data-background-position="true" data-no-preview="true"><i class="fa fa-arrows"/>Background Image Sizing</a> + <we-button class="we-button-hover-icon" data-background-position="true" data-no-preview="true"> + <i class="fa fa-fw fa-arrows"/> Background Image Sizing + </we-button> </div> <!-- Parallax --> <div data-js="parallax" data-selector=".parallax"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-clock-o"/>Scroll Speed</a> - <div class="dropdown-menu" role="menu" name="parallax-scroll"> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="0">No-scroll</a> - <div class="dropdown-divider" role="separator"/> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="1">Fixed</a> - <div class="dropdown-divider" role="separator"/> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="0.6">Very Slow</a> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="1.2">Slow</a> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="1.6">Fast</a> - <a href="#" class="dropdown-item" role="menuitem" data-scroll="2">Very Fast</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-clock-o"/> Scroll Speed</we-toggler> + <we-collapse> + <we-button data-scroll="0">No-scroll</we-button> + <we-divider/> + <we-button data-scroll="1">Fixed</we-button> + <we-divider/> + <we-button data-scroll="0.6">Very Slow</we-button> + <we-button data-scroll="1.2">Slow</we-button> + <we-button data-scroll="1.6">Fast</we-button> + <we-button data-scroll="2">Very Fast</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- Color | Section --> @@ -1263,10 +1280,10 @@ data-js="colorpicker" data-selector="section, :not(.o_gallery > .container) > .carousel" data-exclude=".parallax"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Background Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- FILTER | .s_parallax --> @@ -1275,32 +1292,32 @@ data-palette-exclude="common, theme" data-palette-default="transparent_grayscale" data-palette-title="Overlay Color"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Filter</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Filter</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <!-- Color | Columns --> <div data-js="colorpicker" data-selector="section .row > div" data-exclude=".s_col_no_bgcolor, .s_col_no_bgcolor.row > div, .o_gallery .row > div"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a> - <div class="dropdown-menu" role="menu"/> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Background Color</we-toggler> + <we-collapse/> + </we-collapse-area> </div> <div data-selector="section .row > div" data-exclude=".s_col_no_bgcolor, .s_col_no_bgcolor.row > div, .o_gallery .row > div"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-magic"/>Styles</a> - <div class="dropdown-menu" role="menu"> - <a href="#" class="dropdown-item" role="menuitem" data-toggle-class="border">Border</a> - <a href="#" class="dropdown-item" role="menuitem" data-toggle-class="rounded">Rounded</a> - <a href="#" class="dropdown-item" role="menuitem" data-toggle-class="shadow">Shadow</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-magic"/> Styles</we-toggler> + <we-collapse> + <we-button data-toggle-class="border">Border</we-button> + <we-button data-toggle-class="rounded">Rounded</we-button> + <we-button data-toggle-class="shadow">Shadow</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-js="sizing_y" @@ -1309,22 +1326,21 @@ <div data-js="sizing_x" data-selector=".row > div" data-drop-near=".row > div" - data-exclude=".s_col_no_resize.row > div"> - </div> + data-exclude=".s_col_no_resize.row > div"/> <div id="so_snippet_addition" data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax" data-drop-in=":not(p).oe_structure:not(.oe_structure_solo), :not(p)[data-oe-type=html], :not(p).oe_structure.oe_structure_solo:not(:has(> section, > div))"/> - <div data-js="content" + <!-- Main content drop --> + <div id="so_content_addition" data-selector="blockquote, .s_btn, .s_card, .s_alert, .o_facebook_page, .s_share, .s_rating, .s_hr" data-drop-near="p, h1, h2, h3, blockquote, .s_btn, .s_card, .s_alert, .o_facebook_page, .s_share, .s_rating, .s_hr" - data-drop-in=".content"> - </div> + data-drop-in=".content"/> <div data-js="ul" data-selector=":not(li) > ul:has(ul,ol), :not(li) > ol:has(ul,ol)"> - <a href="#" class="dropdown-item" data-toggle-class="o_ul_folded">Folded list</a> + <we-button data-toggle-class="o_ul_folded">Folded list</we-button> </div> <div data-js="menu_data" @@ -1339,7 +1355,9 @@ <div data-js="topMenuTransparency" data-selector="[data-main-object^='website.page('] #wrapwrap > header" data-no-check="true"> - <a tabindex="-1" href="#" class="dropdown-item" data-transparent="true" data-no-preview="true"><i class="fa fa-eye-slash"/>Transparent</a> + <we-button data-transparent="true" data-no-preview="true"> + <i class="fa fa-fw fa-eye-slash"/> Transparent + </we-button> </div> <div data-js="topMenuColor" @@ -1348,17 +1366,19 @@ data-palette-default="transparent_grayscale" data-palette-title="Top Menu Color" data-no-check="true"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-eyedropper"/>Background Color</a> + <we-collapse-area> + <we-toggler><i class="fa fa-fw fa-eyedropper"/> Background Color</we-toggler> <div class="dropdown-menu"/> - </div> + </we-collapse-area> </div> <!-- Anchor Name --> <div data-js="anchorName" data-selector=":not(p).oe_structure > *, :not(p)[data-oe-type=html] > *, .row > div" data-exclude=".modal *"> - <a tabindex="-1" href="#" class="dropdown-item" data-no-preview="true" data-open-anchor-dialog=""><i class="fa fa-anchor"/>Anchor Name</a> + <we-button class="we-button-hover-icon" data-no-preview="true" data-open-anchor-dialog=""> + <i class="fa fa-fw fa-anchor"/> Anchor Name + </we-button> </div> </template> </odoo> diff --git a/addons/website_blog/static/src/js/tours/website_blog.js b/addons/website_blog/static/src/js/tours/website_blog.js index c8f04ed4659..ce35f60f40a 100644 --- a/addons/website_blog/static/src/js/tours/website_blog.js +++ b/addons/website_blog/static/src/js/tours/website_blog.js @@ -23,13 +23,9 @@ odoo.define("website_blog.tour", function (require) { position: "top", run: "text", }, { - trigger: "#oe_manipulators .oe_overlay.oe_active a.btn.btn-primary", + trigger: "we-button:containsExact(" + _t("Change Cover") + "):visible", extra_trigger: "#wrap div[data-oe-expression=\"blog_post.name\"]:not(:containsExact(\"\"))", content: _t("Set a blog post <b>cover</b>."), - position: "bottom", - }, { - trigger: "a:containsExact(" + _t("Change Cover") + "):visible", - content: _t("Click here to change your post cover."), position: "right", }, { trigger: ".o_select_media_dialog .o_existing_attachment_cell:nth(1) img", 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 19760a98e4d..de07e5440b2 100644 --- a/addons/website_blog/static/src/js/website_blog.editor.js +++ b/addons/website_blog/static/src/js/website_blog.editor.js @@ -236,7 +236,7 @@ options.registry.blog_cover = options.Class.extend({ var self = this; var isRegularCover = this.$target.is('.o_wblog_post_page_cover_regular'); - _.each(this.$el, function (el) { + _.each(this.$el.children(), function (el) { var $el = $(el); if (!$el.is('[data-change]')) { @@ -255,7 +255,7 @@ options.registry.blog_cover = options.Class.extend({ $el.find('.o_js_show_regular').toggleClass('d-none', !isRegularCover); }); - this.$el.filter('[data-clear]').toggleClass('d-none', !self.$target.hasClass('o_wblog_has_cover')); + this.$el.find('[data-clear]').toggleClass('d-none', !self.$target.hasClass('o_wblog_has_cover')); this.$filterValueOpts.removeClass('active'); this.$filterColorOpts.removeClass('active'); diff --git a/addons/website_blog/views/snippets.xml b/addons/website_blog/views/snippets.xml index ea2d33b4c3b..7cad9db75ca 100644 --- a/addons/website_blog/views/snippets.xml +++ b/addons/website_blog/views/snippets.xml @@ -8,66 +8,66 @@ <xpath expr="//div[@id='snippet_options']" position="inside"> <div data-js="blog_cover" data-selector=".website_blog .o_blog_cover_container" data-no-check="true"> - <a href="#" class="dropdown-item" data-change="true" data-no-preview="true">Change Cover</a> - <a href="#" class="dropdown-item" data-clear="true" data-no-preview="true">Remove Cover</a> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Size</a> - <div class="dropdown-menu" role="menu"> - <a role="menuitem" href="#" data-cover-opt="size" class="dropdown-item" data-select-class="o_wblog_has_cover cover_full"> + <we-button data-change="true" data-no-preview="true">Change Cover</we-button> + <we-button data-clear="true" data-no-preview="true">Remove Cover</we-button> + <we-collapse-area> + <we-toggler>Size</we-toggler> + <we-collapse> + <we-button data-cover-opt="size" data-select-class="o_wblog_has_cover cover_full"> <span class="o_js_hide_regular">Full Screen</span> <span class="o_js_show_regular">Large</span> - </a> - <a role="menuitem" href="#" data-cover-opt="size" class="dropdown-item o_wblog_cover_opt_size_default" data-select-class="o_wblog_has_cover cover_mid"> + </we-button> + <we-button data-cover-opt="size" class="o_wblog_cover_opt_size_default" data-select-class="o_wblog_has_cover cover_mid"> <span class="o_js_hide_regular">Half Screen</span> <span class="o_js_show_regular">Medium</span> - </a> - <a role="menuitem" href="#" data-cover-opt="size" class="dropdown-item" data-select-class="o_wblog_has_cover cover_auto"> + </we-button> + <we-button data-cover-opt="size" data-select-class="o_wblog_has_cover cover_auto"> <span class="o_js_hide_regular">Fit text</span> <span class="o_js_show_regular">Tiny</span> - </a> - </div> - </div> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Filter Intensity</a> - <div class="dropdown-menu" role="menu"> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-value="0.0">None</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-value="0.2">Low</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-value="0.4">Medium</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-value="0.6">High</a> - </div> - </div> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Filter Color</a> - <div class="dropdown-menu" role="menu"> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_black">Black</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="bg-primary">Primary</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_none">White</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_blue">Blue</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_yellow">Yellow</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_red">Red</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_purple">Purple</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="filters" data-filter-color="oe_green">Green</a> - </div> - </div> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Text Size</a> - <div class="dropdown-menu" role="menu"> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="o_wblog_cover_font_hero">Hero</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="o_wblog_cover_font_huge">Huge</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="o_wblog_cover_font_big">Big</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="">Regular</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="o_wblog_cover_font_small">Small</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_size" data-select-class="o_wblog_cover_font_tiny">Tiny</a> - </div> - </div> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Text Alignment</a> - <div class="dropdown-menu" role="menu"> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_align" data-select-class="">Left</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_align" data-select-class="text-center">Centered</a> - <a role="menuitem" href="#" class="dropdown-item" data-cover-opt="text_align" data-select-class="text-right">Right</a> - </div> - </div> + </we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Filter Intensity</we-toggler> + <we-collapse> + <we-button data-cover-opt="filters" data-filter-value="0.0">None</we-button> + <we-button data-cover-opt="filters" data-filter-value="0.2">Low</we-button> + <we-button data-cover-opt="filters" data-filter-value="0.4">Medium</we-button> + <we-button data-cover-opt="filters" data-filter-value="0.6">High</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Filter Color</we-toggler> + <we-collapse> + <we-button data-cover-opt="filters" data-filter-color="oe_black">Black</we-button> + <we-button data-cover-opt="filters" data-filter-color="bg-primary">Primary</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_none">White</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_blue">Blue</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_yellow">Yellow</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_red">Red</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_purple">Purple</we-button> + <we-button data-cover-opt="filters" data-filter-color="oe_green">Green</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Text Size</we-toggler> + <we-collapse> + <we-button data-cover-opt="text_size" data-select-class="o_wblog_cover_font_hero">Hero</we-button> + <we-button data-cover-opt="text_size" data-select-class="o_wblog_cover_font_huge">Huge</we-button> + <we-button data-cover-opt="text_size" data-select-class="o_wblog_cover_font_big">Big</we-button> + <we-button data-cover-opt="text_size" data-select-class="">Regular</we-button> + <we-button data-cover-opt="text_size" data-select-class="o_wblog_cover_font_small">Small</we-button> + <we-button data-cover-opt="text_size" data-select-class="o_wblog_cover_font_tiny">Tiny</we-button> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Text Alignment</we-toggler> + <we-collapse> + <we-button data-cover-opt="text_align" data-select-class="">Left</we-button> + <we-button data-cover-opt="text_align" data-select-class="text-center">Centered</we-button> + <we-button data-cover-opt="text_align" data-select-class="text-right">Right</we-button> + </we-collapse> + </we-collapse-area> </div> </xpath> </template> @@ -76,31 +76,31 @@ <template id="s_latest_posts_options" inherit_id="website.snippet_options"> <xpath expr="//div[@data-js='background']" position="before"> <div data-js="js_get_posts_selectBlog" data-selector=".s_latest_posts, .s_latest_posts_big_picture" data-target=".js_get_posts" data-no-check="true"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-folder-open"/>Choose a blog</a> - <div class="dropdown-menu"> - <a href="#" class="dropdown-item" data-filter-by-blog-id="0" data-no-preview="true">All blogs</a> + <we-collapse-area> + <we-toggler><i class="fa fa-folder-open"/> Choose a blog</we-toggler> + <we-collapse> + <we-button data-filter-by-blog-id="0" data-no-preview="true">All blogs</we-button> <!-- the blog list will be generated in js --> - </div> - </div> + </we-collapse> + </we-collapse-area> </div> <div data-js="js_get_posts_limit" data-selector=".s_latest_posts, .s_latest_posts_big_picture" data-target=".js_get_posts" data-no-check="true"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item"><i class="fa fa-sort-numeric-asc"/>Posts limit</a> - <div class="dropdown-menu" data-no-preview="true"> - <a href="#" class="dropdown-item" data-posts-limit="1">1 post max</a> - <a href="#" class="dropdown-item" data-posts-limit="2">2 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="3">3 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="4">4 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="5">5 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="6">6 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="7">7 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="8">8 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="9">9 posts max</a> - <a href="#" class="dropdown-item" data-posts-limit="10">10 posts max</a> - </div> - </div> + <we-collapse-area> + <we-toggler><i class="fa fa-sort-numeric-asc"/> Posts limit</we-toggler> + <we-collapse> + <we-button data-posts-limit="1">1 post max</we-button> + <we-button data-posts-limit="2">2 posts max</we-button> + <we-button data-posts-limit="3">3 posts max</we-button> + <we-button data-posts-limit="4">4 posts max</we-button> + <we-button data-posts-limit="5">5 posts max</we-button> + <we-button data-posts-limit="6">6 posts max</we-button> + <we-button data-posts-limit="7">7 posts max</we-button> + <we-button data-posts-limit="8">8 posts max</we-button> + <we-button data-posts-limit="9">9 posts max</we-button> + <we-button data-posts-limit="10">10 posts max</we-button> + </we-collapse> + </we-collapse-area> </div> </xpath> <xpath expr="//div[@data-js='layout_column']" position="attributes"> diff --git a/addons/website_form/static/tests/tours/website_form_editor.js b/addons/website_form/static/tests/tours/website_form_editor.js index ffbbf897922..b489fc33bad 100644 --- a/addons/website_form/static/tests/tours/website_form_editor.js +++ b/addons/website_form/static/tests/tours/website_form_editor.js @@ -57,12 +57,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Add a model field", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_modal]" + trigger: "[data-website_form_field_modal]" }, { content: "Select the date field", @@ -81,12 +77,12 @@ odoo.define('website_form_editor.tour', function(require) { run: "text Test Date" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]" + trigger: "[data-website_form_field_require]" }, { content: "Check the resulting field", @@ -102,12 +98,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Add a model field", - trigger: ".oe_overlay_options:visible .dropdown-item[data-website_form_field_modal]" + trigger: "[data-website_form_field_modal]" }, { content: "Select the record_name field", @@ -126,12 +118,12 @@ odoo.define('website_form_editor.tour', function(require) { run: "text Awesome Label" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Hidden", - trigger: ".oe_overlay_options .dropdown-item[data-toggle-class='o_website_form_field_hidden']" + trigger: "[data-toggle-class='o_website_form_field_hidden']" }, { content: "Check the resulting field", @@ -148,12 +140,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Add a model field", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_modal]" + trigger: "[data-website_form_field_modal]" }, { content: "Select the body_html field", @@ -172,12 +160,12 @@ odoo.define('website_form_editor.tour', function(require) { run: "text Your Message" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]" + trigger: "[data-website_form_field_require]" }, { content: "Check the resulting field", @@ -193,12 +181,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Add a model field", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_modal]" + trigger: "[data-website_form_field_modal]" }, { content: "Select the recipient_ids field", @@ -221,17 +205,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]", }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']", - run: function (actions) { - actions.auto(); - // I didn't find any other way to make that submenu element appear - $(".oe_options .dropdown-submenu .dropdown-menu").css("display", "block"); - } - }, - { content: "Click on Multiple Checkboxes in menu Add a custom field", - trigger: ".oe_options .dropdown-item:contains('Multiple Checkboxes')" + trigger: "we-button:contains('Multiple Checkboxes')", }, // Customize custom multiple checkboxes field @@ -257,7 +232,7 @@ odoo.define('website_form_editor.tour', function(require) { }, { content: "Duplicate Option 3", - trigger: ".oe_overlay_options:visible .oe_snippet_clone", + trigger: ".oe_snippet_clone:last", }, { content: "Change first Option 3 label", @@ -274,12 +249,12 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".col-form-label:contains('Products')" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]" + trigger: "[data-website_form_field_require]" }, { content: "Check the resulting field", @@ -298,12 +273,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]", }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Radio Buttons in menu Add a custom field", - trigger: ".oe_options .dropdown-item:contains('Radio Buttons')" + trigger: "we-button:contains('Radio Buttons')" }, // Customize Radio Buttons field @@ -328,7 +299,7 @@ odoo.define('website_form_editor.tour', function(require) { }, { content: "Duplicate Option 3", - trigger: ".oe_overlay_options:visible .oe_snippet_clone", + trigger: ".oe_snippet_clone:last", }, { content: "Change first Option 3 label", @@ -345,20 +316,16 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".col-form-label:contains('Service')" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]" - }, - { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + trigger: "[data-website_form_field_require]" }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]", + trigger: "[data-website_form_field_require]", extra_trigger: ".form-field.o_website_form_custom.o_website_form_required_custom" + ":has(.col-form-label:contains('Service'))", }, @@ -378,18 +345,10 @@ odoo.define('website_form_editor.tour', function(require) { { content: "Click on Form snippet", trigger: ".s_website_form[data-model_name]", - onend: function() { - // I didn't find any other way to make that submenu element appear - $(".oe_options > ul > li:has(ul) > ul").css("display", "block"); - } - }, - { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" }, { content: "Click on Selection in menu Add a custom field", - trigger: ".oe_options .dropdown-item:contains('Selection')" + trigger: "we-button:contains('Selection')", }, // Customize custom selection field @@ -414,7 +373,7 @@ odoo.define('website_form_editor.tour', function(require) { }, { content: "Duplicate Option 3", - trigger: ".oe_overlay_options:visible .oe_snippet_clone", + trigger: ".oe_snippet_clone:last", }, { content: "Change first Option 3 label", @@ -432,19 +391,19 @@ odoo.define('website_form_editor.tour', function(require) { }, { content: "Remove Germany Option", - trigger: ".oe_overlay_options:visible .oe_snippet_remove", + trigger: ".oe_snippet_remove:last", }, { content: "Click on field", trigger: ".col-form-label:contains('State')" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" + content: "Go to the row option", + trigger: 'we-customizeblock-options.o_we_closed:last', }, { content: "Click on Required", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_require]" + trigger: "[data-website_form_field_require]" }, { content: "Check the resulting snippet", @@ -464,12 +423,8 @@ odoo.define('website_form_editor.tour', function(require) { trigger: ".s_website_form[data-model_name]" }, { - content: "Click on Customize", - trigger: ".oe_overlay_options [title='Customize']" - }, - { content: "Click on Add a model field", - trigger: ".oe_overlay_options .dropdown-item[data-website_form_field_modal]" + trigger: "[data-website_form_field_modal]" }, { content: "Select the attachment_ids field", diff --git a/addons/website_form/views/snippets.xml b/addons/website_form/views/snippets.xml index b47e02eeda5..c485b64d8c3 100644 --- a/addons/website_form/views/snippets.xml +++ b/addons/website_form/views/snippets.xml @@ -30,29 +30,29 @@ <xpath expr="//div" position="after"> <!-- Form --> <div data-js="website_form_editor" data-selector=".s_website_form"> - <a href="#" class="dropdown-item" data-website_form_model_modal="" data-no-preview="true">Change Form Parameters</a> - <a href="#" class="dropdown-item" data-website_form_field_modal="" data-no-preview="true">Add an existing field</a> - <div class="dropdown-submenu"> - <a href="#" class="dropdown-item">Add a custom field</a> - <div class="dropdown-menu" role="menu" data-no-preview="true"> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="char">Text</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="text">Long Text</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="integer">Number</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="float">Decimal Number</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="boolean">Checkbox</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="selection">Radio Buttons</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="many2one">Selection</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="one2many">Multiple Checkboxes</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="date">Date</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="datetime">Date & Time</a> - <a href="#" class="dropdown-item" role="menuitem" data-website_form_custom_field="binary">File Upload</a> - </div> - </div> + <we-button data-website_form_model_modal="" data-no-preview="true">Change Form Parameters</we-button> + <we-button data-website_form_field_modal="" data-no-preview="true">Add an existing field</we-button> + <we-collapse-area> + <we-toggler>Add a custom field</we-toggler> + <we-collapse data-no-preview="true"> + <we-button data-website_form_custom_field="char">Text</we-button> + <we-button data-website_form_custom_field="text">Long Text</we-button> + <we-button data-website_form_custom_field="integer">Number</we-button> + <we-button data-website_form_custom_field="float">Decimal Number</we-button> + <we-button data-website_form_custom_field="boolean">Checkbox</we-button> + <we-button data-website_form_custom_field="selection">Radio Buttons</we-button> + <we-button data-website_form_custom_field="many2one">Selection</we-button> + <we-button data-website_form_custom_field="one2many">Multiple Checkboxes</we-button> + <we-button data-website_form_custom_field="date">Date</we-button> + <we-button data-website_form_custom_field="datetime">Date & Time</we-button> + <we-button data-website_form_custom_field="binary">File Upload</we-button> + </we-collapse> + </we-collapse-area> </div> <!-- Field --> <div data-js='website_form_editor' data-selector=".form-field" data-drop-near=".form-field"> - <a href="#" class="dropdown-item" data-toggle-class="o_website_form_field_hidden" data-no-preview="true">Hidden</a> + <we-button data-toggle-class="o_website_form_field_hidden" data-no-preview="true">Hidden</we-button> </div> <!-- Add move, duplicate and remove controllers to checkboxes and radio buttons --> @@ -63,7 +63,7 @@ <!-- Required option for fields that are not required fields of the model --> <div data-js='website_form_editor_field' data-selector=".form-field:not(.o_website_form_required)"> - <a href="#" class="dropdown-item" data-website_form_field_require="" data-toggle-class="o_website_form_required_custom" data-no-preview="true">Required</a> + <we-button data-website_form_field_require="" data-toggle-class="o_website_form_required_custom" data-no-preview="true">Required</we-button> </div> <!-- Remove the duplicate options of model fields --> diff --git a/addons/website_mass_mailing/static/src/scss/website_mass_mailing.editor.scss b/addons/website_mass_mailing/static/src/scss/website_mass_mailing.editor.scss index 83c45749d6d..11de90aeb0f 100644 --- a/addons/website_mass_mailing/static/src/scss/website_mass_mailing.editor.scss +++ b/addons/website_mass_mailing/static/src/scss/website_mass_mailing.editor.scss @@ -1,7 +1,7 @@ .editor_enable { .o_newsletter_modal { // set z-index so customize options visible on dialog. - z-index: $o-wysiwyg-zindex - 2; + z-index: $o-we-overlay-zindex - 5; // just for fake backdrop effect background-color: rgba(66, 66, 66, 0.4); } 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 507ee92882e..e4f271604b5 100644 --- a/addons/website_sale/static/src/js/website_sale.editor.js +++ b/addons/website_sale/static/src/js/website_sale.editor.js @@ -205,10 +205,10 @@ options.registry.WebsiteSaleProductsItem = options.Class.extend({ model: 'product.style', method: 'search_read', }).then(function (data) { - var $ul = self.$el.find('div[name="style"]'); + var $ul = self.$el.find('[name="style"]'); for (var k in data) { $ul.append( - $('<a class="dropdown-item" role="menuitem" data-style="' + data[k]['id'] + '" data-toggle-class="' + data[k]['html_class'] + '"/>') + $('<we-button data-style="' + data[k]['id'] + '" data-toggle-class="' + data[k]['html_class'] + '"/>') .append(data[k]['name']) ); } @@ -222,7 +222,7 @@ options.registry.WebsiteSaleProductsItem = options.Class.extend({ */ onFocus: function () { var listLayoutEnabled = this.$target.closest('#products_grid').hasClass('o_wsale_layout_list'); - this.$el.find('.o_wsale_soptions_menu_sizes').closest('.dropdown-submenu') + this.$el.find('.o_wsale_soptions_menu_sizes').closest('we-collapse-area') .toggleClass('d-none', listLayoutEnabled); }, diff --git a/addons/website_sale/static/src/scss/website_sale.editor.scss b/addons/website_sale/static/src/scss/website_sale.editor.scss index 2697fcae9e2..9a4f59d52f0 100644 --- a/addons/website_sale/static/src/scss/website_sale.editor.scss +++ b/addons/website_sale/static/src/scss/website_sale.editor.scss @@ -1,12 +1,12 @@ .o_wsale_soptions_menu_sizes { table { - margin-left: 20px; + margin: auto; td { margin: 0; padding: 0; - width: 20px; - height: 20px; + width: 40px; + height: 40px; border: 1px #dddddd solid; cursor: pointer; diff --git a/addons/website_sale/views/snippets.xml b/addons/website_sale/views/snippets.xml index 0391a2fdcf9..17b8ebf69e7 100644 --- a/addons/website_sale/views/snippets.xml +++ b/addons/website_sale/views/snippets.xml @@ -43,27 +43,27 @@ <div data-js="WebsiteSaleGridLayout" data-selector="#products_grid .o_wsale_products_grid_table_wrapper > table" data-no-check="true"> - <a href="#" class="dropdown-item" role="menuitem" data-no-preview="true" data-choose-ppg="1"> - <i class="fa fa-cart-plus"/>Choose number of products - </a> - <div class="dropdown-submenu o_wsale_ppr_submenu" role="menuitem" aria-haspopup="true"> - <a tabindex="-1" href="#" class="dropdown-item" role="menuitem"> - <i class="fa fa-columns"/>Number of Columns - </a> - <div class="dropdown-menu" role="menu" data-no-preview="true"> - <a href="#" class="dropdown-item" role="menuitem" data-set-ppr="2">2</a> - <a href="#" class="dropdown-item" role="menuitem" data-set-ppr="3">3</a> - <a href="#" class="dropdown-item" role="menuitem" data-set-ppr="4">4</a> - </div> - </div> + <we-button data-no-preview="true" data-choose-ppg="1"> + <i class="fa fa-cart-plus"/> Choose number of products + </we-button> + <we-collapse-area class="o_wsale_ppr_submenu"> + <we-toggler> + <i class="fa fa-columns"/> Number of Columns + </we-toggler> + <we-collapse data-no-preview="true"> + <we-button data-set-ppr="2">2</we-button> + <we-button data-set-ppr="3">3</we-button> + <we-button data-set-ppr="4">4</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-js="WebsiteSaleProductsItem" data-selector="#products_grid .oe_product" data-no-check="true"> - <div class="dropdown-submenu"> - <a tabindex="-1" href="#" class="dropdown-item">Size</a> - <div class="dropdown-menu o_wsale_soptions_menu_sizes" role="menu"> + <we-collapse-area> + <we-toggler>Size</we-toggler> + <we-collapse class="o_wsale_soptions_menu_sizes"> <table> <tr> <td/><td/><td/><td/> @@ -78,29 +78,31 @@ <td/><td/><td/><td/> </tr> </table> - </div> - </div> - <div class='dropdown-submenu' role="menuitem" aria-haspopup="true"> - <a tabindex="-1" href="#" class="dropdown-item">Styles</a> - <div class="dropdown-menu" role="menu" data-no-preview="true" name="style"/> - </div> - <div class='dropdown-submenu' role="menuitem" aria-haspopup="true"> - <a tabindex="-1" href="#" class="dropdown-item">Promote</a> - <div class="dropdown-menu" role="menu" data-no-preview="true"> - <a href="#" class="dropdown-item" role="menuitem" data-change-sequence="top">Push to top</a> - <a href="#" class="dropdown-item" role="menuitem" data-change-sequence="up">Push up</a> - <a href="#" class="dropdown-item" role="menuitem" data-change-sequence="down">Push down</a> - <a href="#" class="dropdown-item" role="menuitem" data-change-sequence="bottom">Push to bottom</a> - </div> - </div> + </we-collapse> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Styles</we-toggler> + <we-collapse data-no-preview="true" name="style"/> + </we-collapse-area> + <we-collapse-area> + <we-toggler>Promote</we-toggler> + <we-collapse data-no-preview="true"> + <we-button data-change-sequence="top">Push to top</we-button> + <we-button data-change-sequence="up">Push up</we-button> + <we-button data-change-sequence="down">Push down</we-button> + <we-button data-change-sequence="bottom">Push to bottom</we-button> + </we-collapse> + </we-collapse-area> </div> <div data-js="ProductsSearchBar" data-selector=".s_wsale_products_searchbar_input"> - <a tabindex="-1" href="#" class="dropdown-item" data-no-preview="true" data-open-searchbar-settings=""><i class="fa fa-search"></i>Products Search Bar</a> + <we-button data-no-preview="true" data-open-searchbar-settings=""> + <i class="fa fa-search"/> Products Search Bar + </we-button> </div> </xpath> - <xpath expr="//div[@data-js='content']" position="attributes"> + <xpath expr="//div[@id='so_content_addition']" position="attributes"> <attribute name="data-selector" add=".s_wsale_products_searchbar_input" separator=","/> <attribute name="data-drop-near" add=".s_wsale_products_searchbar_input" separator=","/> </xpath> |
