diff options
| author | qsm-odoo <qsm@odoo.com> | 2018-03-14 16:21:14 +0100 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2018-07-27 12:36:54 +0200 |
| commit | 1c1c0897e8eca607c7f1b96b68a06c026c543e6a (patch) | |
| tree | 1f667224be28146cbcbe602892094046052ea93b /addons/web_editor/static | |
| parent | 220e49f9d66f2e2ea875143c2da0c20919ec0b3e (diff) | |
[REF] *: BS4, adapt dropdowns and carets
- The dropdown structure was simplified, allowing to get rid of the
3-levels structure induced by <ul/> elements and dropdowns can now
contain anything. The class 'dropdown-item' is now mandatory for
each dropdown clickable element. The class 'dropdown-item-text' can
be used to add same padding and style but without making the element
have a clickable look.
- Dividers now use the class 'dropdown-divider'
- The way dropdowns are opened and hidden also changed (before the
'open' class was added on the `.dropdown-menu` parent, now the
'show' class is added on both the `.dropdown-menu` parent and the
`.dropdown-menu` itself).
- JS-wise, no click event handlers can be put on `.dropdown-toggle`
elements anymore (instead, use handlers for dropdown events).
- Carets are automatically put on `.dropdown-toggle` elements, so this
commit replaces the `.caret` elements with this. This feature was
possible to disable but would prevent us from adding a caret with
scss. Also, this simplifies the DOM. The 'o-no-caret' class was also
introduced to allow using the 'dropdown-toggle' class on non-caret
elements.
- Also adapt the scss to use $caret-width instead of $caret-width-base
Diffstat (limited to 'addons/web_editor/static')
9 files changed, 134 insertions, 133 deletions
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js index cd482a18d7c..fa993dff99a 100644 --- a/addons/web_editor/static/src/js/editor/rte.summernote.js +++ b/addons/web_editor/static/src/js/editor/rte.summernote.js @@ -142,7 +142,7 @@ renderer.tplPopovers = function (lang, options) { })).appendTo($resizefa); } var $colorfa = $airPopover.find('.note-color').clone(); - $colorfa.find("ul.dropdown-menu").css('min-width', '172px'); + $colorfa.find(".dropdown-menu").css('min-width', '172px'); $resizefa.after($colorfa); // show dialog box and delete 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 97bd73cb832..e3a8803619a 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -199,7 +199,7 @@ var SnippetEditor = Widget.extend({ // Attach own and parent options on the current overlay var $style_button = this.$el.find('.oe_options'); - var $ul = $style_button.find('ul:first'); + var $ul = $style_button.find('.dropdown-menu:first'); var $headers = $ul.find('.dropdown-header:data(editor)'); _.each($headers, (function (el) { var $el = $(el); @@ -218,7 +218,7 @@ var SnippetEditor = Widget.extend({ }).bind(this)); // Activate the overlay - $style_button.toggleClass('d-none', $ul.children(':not(.o_main_header):not(.divider):not(.d-none)').length === 0); + $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); @@ -262,13 +262,13 @@ var SnippetEditor = Widget.extend({ _initializeOptions: function () { var self = this; var $styles = this.$el.find('.oe_options'); - var $ul = $styles.find('ul:first'); + var $ul = $styles.find('.dropdown-menu:first'); this.styles = {}; this.selectorSiblings = []; this.selectorChildren = []; var i = 0; - $ul.append($('<li/>', {class: 'dropdown-header o_main_header', text: this._getName()}).data('editor', this)); + $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)) { return; @@ -277,7 +277,7 @@ var SnippetEditor = Widget.extend({ if (val['drop-in']) self.selectorChildren.push(val['drop-in']); var optionName = val.option; - var $el = val.$el.children('li').clone(true).addClass('snippet-option-' + optionName); + 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, @@ -288,7 +288,7 @@ var SnippetEditor = Widget.extend({ option.__order = i++; return option.attachTo($el); }); - $ul.append($('<li/>', {class: 'divider'})); + $ul.append($('<div/>', {class: 'dropdown-divider'})); var $parents = this.$target.parents(); _.each($parents, function (parent) { @@ -296,7 +296,7 @@ var SnippetEditor = Widget.extend({ if (parentEditor) { for (var styleName in parentEditor.styles) { if (!parentEditor.styles[styleName].preventChildPropagation) { - $ul.append($('<li/>', {class: 'dropdown-header o_parent_editor_header', text: parentEditor._getName()}).data('editor', parentEditor)); + $ul.append($('<div/>', {class: 'dropdown-header o_parent_editor_header', text: parentEditor._getName()}).data('editor', parentEditor)); break; } } 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 54e92b60028..463d2acf08e 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -17,10 +17,10 @@ var _t = core._t; */ var SnippetOption = Widget.extend({ events: { - 'mouseenter a': '_onLinkEnter', - 'click a': '_onLinkClick', + 'mouseenter': '_onLinkEnter', + 'click': '_onLinkClick', 'mouseleave': '_onMouseleave', - 'mouseleave ul': '_onMouseleave', + 'mouseleave .dropdown-menu': '_onMouseleave', }, /** * When editing a snippet, its options are shown alongside the ones of its @@ -30,7 +30,7 @@ var SnippetOption = Widget.extend({ preventChildPropagation: false, /** - * The option `$el` is supposed to be the associated <li/> element in the + * The option `$el` is supposed to be the associated DOM element in the * options dropdown. 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). @@ -115,18 +115,18 @@ 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 <li/> having a `data-select-class` + * case is having a subdropdown with each item having a `data-select-class` * value allowing to choose the associated class. * * @param {boolean|string} previewMode * - truthy if the option is enabled for preview or if leaving it (in * that second case, the value is 'reset') * - false if the option should be activated for good - * @param {*} value - the class to activate ($li.data('selectClass')) - * @param {jQuery} $li - the related DOMElement option + * @param {*} value - the class to activate ($opt.data('selectClass')) + * @param {jQuery} $opt - the related DOMElement option */ - selectClass: function (previewMode, value, $li) { - var $group = $li && $li.closest('.dropdown-submenu'); + selectClass: function (previewMode, value, $opt) { + var $group = $opt && $opt.closest('.dropdown-submenu'); if (!$group || !$group.length) { $group = this.$el; } @@ -141,12 +141,12 @@ 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 <li/> having a `data-toggle-class` + * case is having a subdropdown with each item having a `data-toggle-class` * value allowing to toggle the associated class. * * @see this.selectClass */ - toggleClass: function (previewMode, value, $li) { + 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(' '); @@ -163,7 +163,7 @@ var SnippetOption = Widget.extend({ /** * Override the helper method to search inside the $target element instead - * of the dropdown <li/> element. + * of the dropdown item element. * * @override */ @@ -225,13 +225,13 @@ var SnippetOption = Widget.extend({ * - truthy if the option is enabled for preview or if leaving it (in * that second case, the value is 'reset') * - false if the option should be activated for good - * @param {jQuery} $li - the related DOMElement option + * @param {jQuery} $opt - the related DOMElement option */ - _select: function (previewMode, $li) { + _select: function (previewMode, $opt) { var self = this; // Options can say they respond to strong choice - if (previewMode && ($li.data('noPreview') || $li.parent().data('noPreview'))) { + if (previewMode && ($opt.data('noPreview') || $opt.parent().data('noPreview'))) { return; } // If it is not preview mode, the user selected the option for good @@ -243,7 +243,7 @@ var SnippetOption = Widget.extend({ // Search for methods (data-...) (i.e. data-toggle-class) on the // selected (sub)option and its parents - var el = $li[0]; + var el = $opt[0]; var methods = []; do { methods.push([el, el.dataset]); @@ -302,20 +302,25 @@ var SnippetOption = Widget.extend({ * @param {Event} ev */ _onLinkEnter: function (ev) { - var $li = $(ev.currentTarget).parent(); - if ($li.is('.dropdown-submenu')) { - var $menu = $li.children('.dropdown-menu'); + var $opt = $(ev.target); + if (!$opt.hasClass('dropdown-item')) { + return; + } + + var $dsmenu = $opt.parent('.dropdown-submenu'); + if ($dsmenu.length) { + var $menu = $dsmenu.children('.dropdown-menu'); // FIXME if ($menu.length) { - var menuRightPosition = $li.offset().left + $li.outerWidth() + $menu.outerWidth(); + var menuRightPosition = $dsmenu.offset().left + $dsmenu.outerWidth() + $menu.outerWidth(); $menu.toggleClass('o_open_to_left', menuRightPosition > $(window).outerWidth()); } } - if (!$li.is(':hasData')) { + if (!$opt.is(':hasData')) { return; } this.__click = false; - this._select(true, $li); + this._select(true, $opt); this.$target.trigger('snippet-option-preview', [this]); }, /** @@ -325,13 +330,14 @@ var SnippetOption = Widget.extend({ * @param {Event} ev */ _onLinkClick: function (ev) { - var $li = $(ev.currentTarget).parent(':hasData'); - if (!$li.length) { + var $opt = $(ev.target); + if (!$opt.hasClass('dropdown-item') || !$opt.is(':hasData')) { return; } + ev.preventDefault(); this.__click = true; - this._select(false, $li); + this._select(false, $opt); this.$target.trigger('snippet-option-change', [this]); }, /** @@ -678,7 +684,7 @@ registry.colorpicker = SnippetOption.extend({ $toggles.parent().empty().append($clpicker); } - this.$el.find('li').append($pt); + this.$el.find('.dropdown-menu').append($pt); } var classes = []; @@ -781,7 +787,7 @@ registry.background = SnippetOption.extend({ * * @see this.selectClass for parameters */ - background: function (previewMode, value, $li) { + background: function (previewMode, value, $opt) { if (previewMode === 'reset' && value === undefined) { // No background has been selected and we want to reset back to the // original custom image @@ -800,16 +806,16 @@ registry.background = SnippetOption.extend({ /** * @override */ - selectClass: function (previewMode, value, $li) { - this.background(previewMode, '', $li); - this._super(previewMode, value ? (value + ' oe_img_bg') : value, $li); + selectClass: function (previewMode, value, $opt) { + this.background(previewMode, '', $opt); + this._super(previewMode, value ? (value + ' oe_img_bg') : value, $opt); }, /** * Opens a media dialog to add a custom background image. * * @see this.selectClass for parameters */ - chooseImage: function (previewMode, value, $li) { + chooseImage: function (previewMode, value, $opt) { // Put fake image in the DOM, edit it and use it as background-image var $image = $('<img/>', {class: 'd-none', src: value}).appendTo(this.$target); @@ -881,7 +887,7 @@ registry.background = SnippetOption.extend({ this._super.apply(this, arguments); var src = this._getSrcFromCssValue(); - this.$el.find('li[data-background]') + this.$el.find('[data-background]') .removeClass('active') .filter(function () { var bgOption = $(this).data('background'); @@ -889,7 +895,7 @@ registry.background = SnippetOption.extend({ }) .addClass('active'); - this.$el.find('li[data-choose-image]').toggleClass('active', this.$target.hasClass('oe_custom_bg')); + this.$el.find('[data-choose-image]').toggleClass('active', this.$target.hasClass('oe_custom_bg')); }, /** * Sets the given value as custom background image. @@ -938,7 +944,7 @@ registry.background_position = SnippetOption.extend({ * * @see this.selectClass for parameters */ - backgroundPosition: function (previewMode, value, $li) { + backgroundPosition: function (previewMode, value, $opt) { var self = this; this.previous_state = [this.$target.attr('class'), this.$target.css('background-size'), this.$target.css('background-position')]; diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js index 657a8bbac8c..784aab3493e 100644 --- a/addons/web_editor/static/src/js/editor/summernote.js +++ b/addons/web_editor/static/src/js/editor/summernote.js @@ -958,15 +958,15 @@ range.WrappedRange.prototype.isContentEditable = function () { renderer.tplButtonInfo.fontsize = function (lang, options) { var items = options.fontSizes.reduce(function (memo, v) { - return memo + '<li><a data-event="fontSize" href="#" data-value="' + v + '">' + + return memo + '<a data-event="fontSize" href="#" class="dropdown-item" data-value="' + v + '">' + '<i class="fa fa-check"></i> ' + v + - '</a></li>'; + '</a>'; }, ''); var sLabel = '<span class="note-current-fontsize">11</span>'; return renderer.getTemplate().button(sLabel, { title: lang.font.size, - dropdown: '<ul class="dropdown-menu">' + items + '</ul>' + dropdown: '<div class="dropdown-menu">' + items + '</div>' }); }; diff --git a/addons/web_editor/static/src/js/tours/rte.js b/addons/web_editor/static/src/js/tours/rte.js index 82c31da5259..0a4ae0b32c3 100644 --- a/addons/web_editor/static/src/js/tours/rte.js +++ b/addons/web_editor/static/src/js/tours/rte.js @@ -67,7 +67,7 @@ tour.register('rte', { trigger: ".note-color button.dropdown-toggle", }, { content: "change text color", - trigger: ".btn-group.open button[data-event=foreColor]:first", + trigger: ".btn-group.show button[data-event=foreColor]:first", }, { content: "change selection to change text bg-color again", trigger: '#editable_area > section .row > div:first h1 font:eq(2)', diff --git a/addons/web_editor/static/src/scss/web_editor.ui.scss b/addons/web_editor/static/src/scss/web_editor.ui.scss index e82ad579fe8..bb5cddcffe1 100644 --- a/addons/web_editor/static/src/scss/web_editor.ui.scss +++ b/addons/web_editor/static/src/scss/web_editor.ui.scss @@ -409,7 +409,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] { } } // Open menu - &.open .btn { + &.show .btn { background-color: $o-we-color-light; &:before, &:after { width: 9px; @@ -430,43 +430,21 @@ html[lang] > body.editor_enable [data-oe-translation-state] { border: 1px solid $o-we-color-dark; border-radius: 0; background-color: $o-we-color-light; - a { + + .dropdown-item { + position: relative; color: $o-we-color-text-light; font-weight: normal; font-size: 12px; padding: 5px 35px 5px 20px; - } - > li { - position: relative; &:hover { background-color: fade-out($o-we-color-dark, 0.5); - > a { - color: white; - background: transparent; - cursor: pointer; - } - > .dropdown-menu { - display: block; - left: 100%; - top: 0; - - &.o_open_to_left { - left: auto; - right: 100%; - } - } - } - &.dropdown-submenu:before { - @include o-position-absolute($top: 10px, $right: 10px); - @include o-caret-right(3px); - border-left-color: $o-we-color-text-light; - } - &.divider { - background-color: $o-we-color-divider; - margin: 0 8px; + color: white; + background: transparent; + cursor: pointer; } - &.active > a { + &.active { color: white; background-color: fade-out($o-we-color-dark, 0.5); &:before { @@ -476,53 +454,73 @@ html[lang] > body.editor_enable [data-oe-translation-state] { color: $o-brand-optional; } } - &.dropdown-header { - color: white; - font-weight: bold; - font-size: 12px; - margin-top: 2px; - &:hover { - background-color: initial; - } + > i { + width: 16px; + margin-right: 8px; + } + } - &.o_main_header { - padding-left: 8px; - } - &.o_parent_editor_header { - color: wheat; - font-weight: 400; - font-size: 10px; - margin: 7px 0 4px 4px; - &::before { - content: "\f148"; - @include o-position-absolute($top: 2px, $left: 8px); - font-family: FontAwesome; - transform: scaleX(-1); - } - ~ li:not(.dropdown-header) { - a { - font-size: 11px; - padding: 4px 35px 4px 20px; - opacity: 0.8; - &:hover { - opacity: 1; - } - } - } - } + .dropdown-submenu { + position: relative; + + &::before { + @include o-position-absolute($top: 10px, $right: 10px); + @include o-caret-right(3px); + border-left-color: $o-we-color-text-light; } - &.separator { + &:hover > .dropdown-menu { display: block; - margin: 4px 35px 4px 20px; - height: 1px; - background: rgba($o-we-color-text-light, 0.1); + left: 100%; + top: 0; + + &.o_open_to_left { + left: auto; + right: 100%; + } } + } - > a > i { - width: 16px; - margin-right: 8px; + .dropdown-divider { + display: block; + height: 1px; + background: rgba($o-we-color-text-light, 0.1); + margin: 0 8px; + } + + .dropdown-header { + color: white; + font-weight: bold; + font-size: 12px; + margin-top: 2px; + + &:hover { + background-color: initial; + } + + &.o_main_header { + padding-left: 8px; + } + &.o_parent_editor_header { + color: wheat; + font-weight: 400; + font-size: 10px; + margin: 7px 0 4px 4px; + &::before { + content: "\f148"; + @include o-position-absolute($top: 2px, $left: 8px); + font-family: FontAwesome; + transform: scaleX(-1); + } + ~ .dropdown-item { + font-size: 11px; + padding: 4px 35px 4px 20px; + opacity: 0.8; + &:hover { + opacity: 1; + } + } } } } @@ -749,7 +747,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] { > .btn-group { margin-top: -2px; - &.open, .btn-group.open { + &.show, .btn-group.show { .dropdown-toggle { border-top: 2px solid white; background-color: $o-we-color-darker; @@ -767,7 +765,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] { border-radius: 0; background-color: $o-we-color-darker; color: $o-we-color-text-normal; - > li > a { + .dropdown-item { width: 100%; color: $o-we-color-text-light; @@ -831,7 +829,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] { .note-popover .popover, .note-editor { .dropdown-menu { - > li > a { + .dropdown-item { > i { visibility: hidden; } diff --git a/addons/web_editor/static/src/xml/ace.xml b/addons/web_editor/static/src/xml/ace.xml index 257ce6af707..800a0ef2ced 100644 --- a/addons/web_editor/static/src/xml/ace.xml +++ b/addons/web_editor/static/src/xml/ace.xml @@ -6,10 +6,10 @@ <div class="form-inline o_ace_view_editor_title"> <div class="btn-group o_ace_type_switcher"> <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">XML (HTML)</button> - <ul class="dropdown-menu" role="menu"> - <li><a role="menuitem" href="#" class="o_ace_type_switcher_choice" data-type="xml">XML (HTML)</a></li> - <li><a role="menuitem" href="#" class="o_ace_type_switcher_choice" data-type="scss">SCSS (CSS)</a></li> - </ul> + <div class="dropdown-menu" role="menu"> + <a role="menuitem" href="#" class="dropdown-item o_ace_type_switcher_choice" data-type="xml">XML (HTML)</a> + <a role="menuitem" href="#" class="dropdown-item o_ace_type_switcher_choice" data-type="scss">SCSS (CSS)</a> + </div> </div> <select id="ace-view-list" class="o_res_list"/> <select id="ace-scss-list" class="o_res_list d-none"/> diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml index 1928572fc0d..96f126391cd 100644 --- a/addons/web_editor/static/src/xml/editor.xml +++ b/addons/web_editor/static/src/xml/editor.xml @@ -95,14 +95,11 @@ <div class="btn-group"> <button class="btn btn-primary o_upload_image_button" type="button">Upload an image</button> <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" type="button"> - <span class="caret"/> <span class="sr-only">Alternate Upload</span> </button> - <ul class="dropdown-menu" role="menu"> - <li> - <a role="menuitem" class="o_upload_image_button_no_optimization">Upload image without optimization</a> - </li> - </ul> + <div class="dropdown-menu" role="menu"> + <a role="menuitem" class="dropdown-item o_upload_image_button_no_optimization">Upload image without optimization</a> + </div> </div> </div> <div> diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml index 586b920edf0..a0c35288b93 100644 --- a/addons/web_editor/static/src/xml/snippets.xml +++ b/addons/web_editor/static/src/xml/snippets.xml @@ -13,7 +13,7 @@ <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> - <ul class="dropdown-menu" role="menu"/> + <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> @@ -41,9 +41,9 @@ <t t-name="web_editor.many2one.button"> <div class="btn-group"> <a role="button" href="#" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact" aria-label="Search Contact"><i class="fa fa-search"></i></a> - <ul class="dropdown-menu contact_menu" role="menu"> - <li><a role="menuitem"><input href="#" type="email" placeholder="Search"/></a></li> - </ul> + <div class="dropdown-menu contact_menu" role="menu"> + <a role="menuitem" class="dropdown-item"><input href="#" type="email" placeholder="Search"/></a> + </div> </div> </t> |
