diff options
Diffstat (limited to 'addons/web/static/src')
97 files changed, 1493 insertions, 1476 deletions
diff --git a/addons/web/static/src/js/chrome/control_panel.js b/addons/web/static/src/js/chrome/control_panel.js index 0913b574a3d..fb265390f51 100644 --- a/addons/web/static/src/js/chrome/control_panel.js +++ b/addons/web/static/src/js/chrome/control_panel.js @@ -245,11 +245,12 @@ var ControlPanel = Widget.extend({ var self = this; var is_last = (index === length-1); var li_content = bc.title && _.escape(bc.title.trim()) || data.noDisplayContent; - var $bc = $('<li>') - .append(is_last ? li_content : $('<a>').html(li_content)) + var $bc = $('<li>', {class: 'breadcrumb-item'}) + .append(is_last ? li_content : $('<a>', {href: '#'}).html(li_content)) .toggleClass('active', is_last); if (!is_last) { - $bc.click(function () { + $bc.click(function (ev) { + ev.preventDefault(); self.trigger_up('breadcrumb_clicked', {controllerID: bc.controllerID}); }); } diff --git a/addons/web/static/src/js/chrome/menu.js b/addons/web/static/src/js/chrome/menu.js index 1e253ba54f7..c96d4b17f8c 100644 --- a/addons/web/static/src/js/chrome/menu.js +++ b/addons/web/static/src/js/chrome/menu.js @@ -2,6 +2,7 @@ odoo.define('web.Menu', function (require) { "use strict"; var core = require('web.core'); +var dom = require('web.dom'); var session = require('web.session'); var Widget = require('web.Widget'); @@ -37,66 +38,10 @@ var Menu = Widget.extend({ } this.trigger('menu_bound'); - var lazyreflow = _.debounce(this.reflow.bind(this), 200); - core.bus.on('resize', this, function() { - if ($(window).width() < 768 ) { - lazyreflow('all_outside'); - } else { - lazyreflow(); - } - }); - core.bus.trigger('resize'); + dom.initAutoMoreMenu(this.$el); this.is_bound.resolve(); }, - - /** - * Reflow the menu items and dock overflowing items into a "More" menu item. - * Automatically called when 'menu_bound' event is triggered and on window resizing. - * - * @param {string} behavior If set to 'all_outside', all the items are displayed. - * If not set, only the overflowing items are hidden. - */ - reflow: function(behavior) { - var self = this; - var $more_container = this.$('#menu_more_container').hide(); - var $more = this.$('#menu_more'); - var $systray = this.$el.parents().find('.oe_systray'); - - $more.children('li').insertBefore($more_container); // Pull all the items out of the more menu - - // 'all_outside' beahavior should display all the items, so hide the more menu and exit - if (behavior === 'all_outside') { - // Show list of menu items - self.$el.show(); - this.$el.find('li').show(); - $more_container.hide(); - return; - } - - // Hide all menu items - var $toplevel_items = this.$el.find('li').not($more_container).not($systray.find('li')).hide(); - // Show list of menu items (which is empty for now since all menu items are hidden) - self.$el.show(); - $toplevel_items.each(function() { - var remaining_space = self.$el.parent().width() - $more_container.outerWidth(); - self.$el.parent().children(':visible').each(function() { - remaining_space -= $(this).outerWidth(); - }); - - if ($(this).width() >= remaining_space) { - return false; // the current item will be appended in more_container - } - $(this).show(); // show the current item in menu bar - }); - $more.append($toplevel_items.filter(':hidden').show()); - $more_container.toggle(!!$more.children().length); - // Hide toplevel item if there is only one - var $toplevel = self.$el.children("li:visible"); - if ($toplevel.length === 1) { - $toplevel.hide(); - } - }, /** * Opens a given menu by id, as if a user had browsed to that menu by hand * except does not trigger any event on the way @@ -143,7 +88,7 @@ var Menu = Widget.extend({ } // add a tooltip to cropped menu items this.$secondary_menus.find('.oe_secondary_submenu li a span').each(function() { - $(this).tooltip(this.scrollWidth > this.clientWidth ? {title: $(this).text().trim(), placement: 'right'} :'destroy'); + $(this).tooltip(this.scrollWidth > this.clientWidth ? {title: $(this).text().trim(), placement: 'right'} : 'dispose'); }); }, /** diff --git a/addons/web/static/src/js/chrome/sidebar.js b/addons/web/static/src/js/chrome/sidebar.js index 47d598aaeb8..d02c936f470 100644 --- a/addons/web/static/src/js/chrome/sidebar.js +++ b/addons/web/static/src/js/chrome/sidebar.js @@ -11,7 +11,7 @@ var _t = core._t; var Sidebar = Widget.extend({ events: { - "click .dropdown-menu li a": "_onDropdownClicked" + "click .dropdown-item": "_onDropdownClicked" }, /** * @override @@ -177,9 +177,10 @@ var Sidebar = Widget.extend({ this.$el.html(QWeb.render('Sidebar', {widget: this})); // Hides Sidebar sections when item list is empty - this.$('.o_dropdown').each(function () { - if (!$(this).find('li').length) { - $(this).hide(); + _.each(this.$('.o_dropdown'), function (el) { + var $dropdown = $(el); + if (!$dropdown.find('.dropdown-item').length) { + $dropdown.hide(); } }); this.$("[title]").tooltip({ diff --git a/addons/web/static/src/js/chrome/user_menu.js b/addons/web/static/src/js/chrome/user_menu.js index 84c16b51f82..1251c9b6b5b 100644 --- a/addons/web/static/src/js/chrome/user_menu.js +++ b/addons/web/static/src/js/chrome/user_menu.js @@ -23,7 +23,7 @@ var UserMenu = Widget.extend({ start: function () { var self = this; var session = this.getSession(); - this.$el.on('click', 'li a[data-menu]', function (ev) { + this.$el.on('click', '[data-menu]', function (ev) { ev.preventDefault(); var menu = $(this).data('menu'); self['_onMenu' + menu.charAt(0).toUpperCase() + menu.slice(1)](); diff --git a/addons/web/static/src/js/chrome/web_client.js b/addons/web/static/src/js/chrome/web_client.js index c4886cd0e89..d3ebabfab1e 100644 --- a/addons/web/static/src/js/chrome/web_client.js +++ b/addons/web/static/src/js/chrome/web_client.js @@ -3,6 +3,7 @@ odoo.define('web.WebClient', function (require) { var AbstractWebClient = require('web.AbstractWebClient'); var config = require('web.config'); +var core = require('web.core'); var data_manager = require('web.data_manager'); var dom = require('web.dom'); var framework = require('web.framework'); @@ -48,6 +49,9 @@ return AbstractWebClient.extend({ return $.when(systray_menu_loaded, user_menu_loaded).then(function() { self.menu.start(); self.bind_hashchange(); + setTimeout(function () { + self.menu.$el.removeClass('d-none'); + }, 200) }); }, @@ -165,7 +169,7 @@ return AbstractWebClient.extend({ toggle_fullscreen: function(fullscreen) { this._super(fullscreen); if (!fullscreen) { - this.menu.reflow(); + core.bus.trigger('resize'); } }, diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js index 847845ae17e..9cca9c1127a 100644 --- a/addons/web/static/src/js/core/dialog.js +++ b/addons/web/static/src/js/core/dialog.js @@ -40,7 +40,7 @@ var Dialog = Widget.extend({ * button is added to allow closing the dialog * @param {string} [options.buttons[].text] * @param {string} [options.buttons[].classes] - * Default to 'btn-primary' if only one button, 'btn-default' + * Default to 'btn-primary' if only one button, 'btn-secondary' * otherwise * @param {boolean} [options.buttons[].close=false] * @param {function} [options.buttons[].click] @@ -123,7 +123,7 @@ var Dialog = Widget.extend({ _.each(buttons, function (buttonData) { var $button = dom.renderButton({ attrs: { - class: buttonData.classes || (buttons.length > 1 ? 'btn-default' : 'btn-primary'), + class: buttonData.classes || (buttons.length > 1 ? 'btn-secondary' : 'btn-primary'), disabled: buttonData.disabled, }, icon: buttonData.icon, diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js index e82db818bb5..a34a207fda8 100644 --- a/addons/web/static/src/js/core/dom.js +++ b/addons/web/static/src/js/core/dom.js @@ -20,6 +20,7 @@ odoo.define('web.dom', function (require) { * something happens in the DOM. */ +var config = require('web.config'); var core = require('web.core'); /** @@ -208,11 +209,10 @@ return { * @param {Object} options * @param {Object} [options.attrs] - Attributes to put on the button element * @param {string} [options.attrs.type='button'] - * @param {string} [options.attrs.class='btn-default'] + * @param {string} [options.attrs.class='btn-secondary'] * Note: automatically completed with "btn btn-X" * (@see options.size for the value of X) - * @param {string} [options.size='sm'] - @see options.attrs.class - * Note: use 'md' for no sizing class + * @param {string} [options.size] - @see options.attrs.class * @param {string} [options.icon] * The specific fa icon class (for example "fa-home") or an URL for * an image to use as icon. @@ -235,10 +235,10 @@ return { } jQueryParams.class = 'btn'; - if (options.size !== 'md') { - jQueryParams.class += (' btn-' + (options.size || 'sm')); + if (options.size) { + jQueryParams.class += (' btn-' + options.size); } - jQueryParams.class += (' ' + (extraClasses || 'btn-default')); + jQueryParams.class += (' ' + (extraClasses || 'btn-secondary')); var $button = $('<button/>', jQueryParams); @@ -262,33 +262,41 @@ return { return $button; }, /** - * Renders a checkbox with standard odoo template. This does not use any xml - * template to avoid forcing the frontend part to lazy load a xml file for - * each widget which might want to create a simple checkbox. + * Renders a checkbox with standard odoo/BS template. This does not use any + * xml template to avoid forcing the frontend part to lazy load a xml file + * for each widget which might want to create a simple checkbox. * * @param {Object} [options] * @param {Object} [options.prop] * Allows to set the input properties (disabled and checked states). * @param {string} [options.text] * The checkbox's associated text. If none is given then a simple - * checkbox without label structure is rendered. + * checkbox is rendered. * @returns {jQuery} */ renderCheckbox: function (options) { - var $container = $('<div class="o_checkbox"><input type="checkbox"/><span/></div>'); - if (options && options.prop) { - $container.children('input').prop(options.prop); + var id = _.uniqueId('checkbox-'); + var $container = $('<div/>', { + class: 'custom-control custom-checkbox', + }); + var $input = $('<input/>', { + type: 'checkbox', + id: id, + class: 'custom-control-input', + }); + var $label = $('<label/>', { + for: id, + class: 'custom-control-label', + text: options && options.text || '', + }); + if (!options || !options.text) { + $label.html('​'); // BS checkboxes need some label content (so + // add a zero-width space when there is no text) } - if (options && options.text) { - $container = $('<label/>').append( - $container, - $('<span/>', { - class: 'ml8', - text: options.text, - }) - ); + if (options && options.prop) { + $input.prop(options.prop); } - return $container; + return $container.append($input, $label); }, /** * Sets the selection range of a given input or textarea @@ -308,5 +316,117 @@ return { .select(); } }, + /** + * Creates an automatic 'more' dropdown-menu for a set of navbar items. + * + * @param {jQuery} $el + * @param {Object} [options] + * @param {string} [options.unfoldable='none'] + * @param {function} [options.maxWidth] + * @param {string} [options.sizeClass='SM'] + */ + initAutoMoreMenu: function ($el, options) { + options = _.extend({ + unfoldable: 'none', + maxWidth: false, + sizeClass: 'SM', + }, options || {}); + + var $extraItemsToggle = null; + + var debouncedAdapt = _.debounce(_adapt, 250); + core.bus.on('resize', null, debouncedAdapt); + _adapt(); + + $el.data('dom:autoMoreMenu:destroy', function () { + _restore(); + core.bus.off('resize', null, debouncedAdapt); + $el.removeData('dom:autoMoreMenu:destroy'); + }); + + function _restore() { + if ($extraItemsToggle === null) { + return; + } + var $items = $extraItemsToggle.children('.dropdown-menu').children(); + $items.addClass('nav-item'); + $items.children().removeClass('dropdown-item').addClass('nav-link'); + $items.insertBefore($extraItemsToggle); + $extraItemsToggle.remove(); + $extraItemsToggle = null; + } + + function _adapt() { + if (!$el.is(':visible')) { + return; + } + + _restore(); + if (config.device.size_class <= config.device.SIZES[options.sizeClass]) { + return; + } + + var $allItems = $el.children(); + var $unfoldableItems = $allItems.filter(options.unfoldable); + var $items = $allItems.not($unfoldableItems); + + var maxWidth = 0; + if (options.maxWidth) { + maxWidth = options.maxWidth(); + } else { + var rect = $el[0].getBoundingClientRect(); + var style = window.getComputedStyle($el[0]); + maxWidth = (rect.right - rect.left); + maxWidth -= (parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth)); + maxWidth -= _.reduce($unfoldableItems, function (sum, el) { + return sum + computeFloatOuterWidthWithMargins(el); + }, 0); + } + + var nbItems = $items.length; + var menuItemsWidth = _.reduce($items, function (sum, el) { + return sum + computeFloatOuterWidthWithMargins(el); + }, 0); + + if (maxWidth - menuItemsWidth >= -0.001) { + return + } + + var $dropdownMenu = $('<ul/>', {class: 'dropdown-menu'}); + $extraItemsToggle = $('<li/>', {class: 'nav-item dropdown o_extra_menu_items'}) + .append($('<a/>', {href: '#', class: 'nav-link dropdown-toggle o-no-caret', 'data-toggle': 'dropdown'}) + .append($('<i/>', {class: 'fa fa-plus'}))) + .append($dropdownMenu); + $extraItemsToggle.insertAfter($items.last()); + + menuItemsWidth += computeFloatOuterWidthWithMargins($extraItemsToggle[0]); + do { + menuItemsWidth -= computeFloatOuterWidthWithMargins($items.eq(--nbItems)[0]); + } while (menuItemsWidth > maxWidth); + + var $extraItems = $items.slice(nbItems).detach(); + $extraItems.removeClass('nav-item'); + $extraItems.children().removeClass('nav-link').addClass('dropdown-item'); + $dropdownMenu.append($extraItems); + $extraItemsToggle.find('.nav-link').toggleClass('active', $extraItems.children().hasClass('active')); + } + + function computeFloatOuterWidthWithMargins(el) { + var rect = el.getBoundingClientRect(); + var style = window.getComputedStyle(el); + return rect.right - rect.left + parseFloat(style.marginLeft) + parseFloat(style.marginRight); + } + }, + /** + * Cleans what has been done by `initAutoMoreMenu'. + * + * @param {jQuery} $el + */ + destroyAutoMoreMenu: function ($el) { + var destroyFunc = $el.data('dom:autoMoreMenu:destroy'); + if (destroyFunc) { + destroyFunc.call(null); + } + }, }; }); diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index eab0093ed50..7cf72791be5 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -304,7 +304,6 @@ var AbstractField = Widget.extend({ this._reset(record, event); return this._render() || $.when(); }, - /** * Remove the invalid class on a field */ @@ -312,7 +311,15 @@ var AbstractField = Widget.extend({ this.$el.removeClass('o_field_invalid'); this.$el.removeAttr('aria-invalid'); }, - + /** + * Sets the given id on the focusable element of the field and as 'for' + * attribute of potential internal labels. + * + * @param {string} id + */ + setIDForLabel: function (id) { + this.getFocusableElement().attr('id', id); + }, /** * add the invalid class on a field */ @@ -320,7 +327,6 @@ var AbstractField = Widget.extend({ this.$el.addClass('o_field_invalid'); this.$el.attr('aria-invalid', 'true'); }, - /** * Update the modifiers with the newest value. * Now this.attrs.modifiersValue can be used consistantly even with diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 51816220c9f..bd13305df0c 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -701,8 +701,8 @@ var FieldBoolean = AbstractField.extend({ // The formatValue of boolean fields renders HTML elements similar to // the one rendered by the widget itself. Even though the event might // have been fired on the non-widget version of this field, we can still - // test the presence of its o_checkbox class. - if (activated && options && options.event && $(options.event.target).parents('.o_checkbox').length) { + // test the presence of its custom class. + if (activated && options && options.event && $(options.event.target).closest('.custom-control.custom-checkbox').length) { this._setValue(!this.value); // Toggle the checkbox } return activated; @@ -737,6 +737,15 @@ var FieldBoolean = AbstractField.extend({ } return rendered; }, + /** + * Associates the 'for' attribute of the internal label. + * + * @override + */ + setIDForLabel: function (id) { + this._super.apply(this, arguments); + this.$('.custom-control-label').attr('for', id); + }, //-------------------------------------------------------------------------- // Private @@ -1612,10 +1621,7 @@ var AttachmentImage = AbstractField.extend({ var StateSelectionWidget = AbstractField.extend({ template: 'FormSelection', events: { - 'click a': function (e) { - e.preventDefault(); - }, - 'click li': '_setSelection' + 'click .dropdown-item': '_setSelection', }, supportedFieldTypes: ['selection'], @@ -1696,13 +1702,12 @@ var StateSelectionWidget = AbstractField.extend({ * @param {MouseEvent} ev */ _setSelection: function (ev) { - var li = $(ev.target).closest('li'); - if (li.length) { - var value = String(li.data('value')); - this._setValue(value); - if (this.mode === 'edit') { - this._render(); - } + ev.preventDefault(); + var $item = $(ev.currentTarget); + var value = String($item.data('value')); + this._setValue(value); + if (this.mode === 'edit') { + this._render(); } }, }); @@ -1778,7 +1783,7 @@ var LabelSelection = AbstractField.extend({ _render: function () { this.classes = this.nodeOptions && this.nodeOptions.classes || {}; var labelClass = this.classes[this.value] || 'primary'; - this.$el.addClass('label label-' + labelClass).text(this._formatValue(this.value)); + this.$el.addClass('badge badge-' + labelClass).text(this._formatValue(this.value)); }, }); @@ -2693,9 +2698,9 @@ var ImageSelection = AbstractField.extend({ var self = this; this.$el.empty(); _.each(this.nodeOptions, function (val, key) { - var $container = $('<div>').addClass('col-xs-3 text-center'); + var $container = $('<div>').addClass('col-3 text-center'); var $img = $('<img>') - .addClass('img img-responsive img-thumbnail ml16') + .addClass('img img-fluid img-thumbnail ml16') .toggleClass('btn-info', key === self.value) .attr('src', val.image_link) .data('key', key); diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index c1c458d1935..ba83de415e7 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -968,7 +968,7 @@ var FieldX2Many = AbstractField.extend({ _renderButtons: function () { if (!this.isReadonly && this.view.arch.tag === 'kanban') { this.$buttons = $(qweb.render('KanbanView.buttons', { - btnClass: 'btn-default', + btnClass: 'btn-secondary', create_text: this.nodeOptions.create_text, })); this.$buttons.on('click', 'button.o-kanban-button-new', this._onAddRecord.bind(this)); @@ -1887,7 +1887,7 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({ this.$color_picker.dropdown('toggle'); this.$color_picker.attr("tabindex", 1).focus(); if (!tagColor) { - this.$('.o_checkbox input').prop('checked', true); + this.$('.custom-checkbox input').prop('checked', true); } } }, @@ -1909,7 +1909,7 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({ var changes = {}; if ($target.is('.o_hide_in_kanban')) { - var $checkbox = $('.o_hide_in_kanban .o_checkbox input'); + var $checkbox = $('.o_hide_in_kanban .custom-checkbox input'); $checkbox.prop('checked', !$checkbox.prop('checked')); // toggle checkbox this.prevColors = this.prevColors ? this.prevColors : {}; if ($checkbox.is(':checked')) { diff --git a/addons/web/static/src/js/fields/upgrade_fields.js b/addons/web/static/src/js/fields/upgrade_fields.js index 119a64881e3..dd91ca2efc2 100644 --- a/addons/web/static/src/js/fields/upgrade_fields.js +++ b/addons/web/static/src/js/fields/upgrade_fields.js @@ -94,7 +94,7 @@ var AbstractFieldUpgrade = { this._super.apply(this, arguments); this._insertEnterpriseLabel($("<span>", { text: "Enterprise", - 'class': "label label-primary oe_inline o_enterprise_label" + 'class': "badge badge-primary oe_inline o_enterprise_label" })); }, /** diff --git a/addons/web/static/src/js/libs/bootstrap.js b/addons/web/static/src/js/libs/bootstrap.js index 04ca2381d7d..135a6b65df6 100644 --- a/addons/web/static/src/js/libs/bootstrap.js +++ b/addons/web/static/src/js/libs/bootstrap.js @@ -7,23 +7,19 @@ odoo.define('web.bootstrap.extensions', function () { */ /* Bootstrap defaults overwrite */ -$.fn.tooltip.Constructor.DEFAULTS.placement = 'auto top'; -$.fn.tooltip.Constructor.DEFAULTS.html = true; -$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover focus click'; -$.fn.tooltip.Constructor.DEFAULTS.container = 'body'; -$.fn.tooltip.Constructor.DEFAULTS.delay = { show: 1000, hide: 0 }; -//overwrite bootstrap tooltip method to prevent showing 2 tooltip at the same time -var bootstrap_show_function = $.fn.tooltip.Constructor.prototype.show; -$.fn.modal.Constructor.prototype.enforceFocus = function () { }; +$.fn.tooltip.Constructor.Default.placement = 'top'; +$.fn.tooltip.Constructor.Default.fallbackPlacement = ['bottom', 'right', 'left', 'top']; +$.fn.tooltip.Constructor.Default.html = true; +$.fn.tooltip.Constructor.Default.trigger = 'hover focus click'; +$.fn.tooltip.Constructor.Default.container = 'body'; +$.fn.tooltip.Constructor.Default.delay = { show: 1000, hide: 0 }; + +var bootstrapShowFunction = $.fn.tooltip.Constructor.prototype.show; $.fn.tooltip.Constructor.prototype.show = function () { + // Overwrite bootstrap tooltip method to prevent showing 2 tooltip at the + // same time $('.tooltip').remove(); - //the following fix the bug when using placement - //auto and the parent element does not exist anymore resulting in - //an error. This should be remove once we updade bootstrap to a version that fix the bug - //edit: bug has been fixed here : https://github.com/twbs/bootstrap/pull/13752 - var e = $.Event('show.bs.' + this.type); - var inDom = $.contains(document.documentElement, this.$element[0]); - if (e.isDefaultPrevented() || !inDom) return; - return bootstrap_show_function.call(this); + + return bootstrapShowFunction.call(this); }; }); diff --git a/addons/web/static/src/js/services/config.js b/addons/web/static/src/js/services/config.js index d05a263ef4e..946f7d39f55 100644 --- a/addons/web/static/src/js/services/config.js +++ b/addons/web/static/src/js/services/config.js @@ -41,22 +41,23 @@ var config = { /** * A frequent use case is to have a different render in 'mobile' mode, * meaning when the screen is small. This flag (boolean) is true when - * the size is XXS or XS. It is also updated dynamically. + * the size is XS/VSM/SM. It is also updated dynamically. * * @type Boolean */ isMobile: null, /** - * Mapping between the numbers 0,1,2,3,4,5 and some descriptions + * Mapping between the numbers 0,1,2,3,4,5,6 and some descriptions */ - SIZES: { XXS: 0, XS: 1, SM: 2, MD: 3, LG: 4, XL: 5 }, + SIZES: { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 }, }, }; var medias = [ window.matchMedia('(max-width: 474px)'), - window.matchMedia('(min-width: 475px) and (max-width: 767px)'), + window.matchMedia('(min-width: 475px) and (max-width: 575px)'), + window.matchMedia('(min-width: 576px) and (max-width: 767px)'), window.matchMedia('(min-width: 768px) and (max-width: 991px)'), window.matchMedia('(min-width: 992px) and (max-width: 1199px)'), window.matchMedia('(min-width: 1200px) and (max-width: 1533px)'), @@ -69,8 +70,8 @@ var medias = [ * @returns {integer} a number between 0 and 5, included */ function _getSizeClass() { - for(var i = 0 ; i < medias.length ; i++) { - if(medias[i].matches) { + for (var i = 0 ; i < medias.length ; i++) { + if (medias[i].matches) { return i; } } @@ -83,7 +84,7 @@ function _updateSizeProps() { var sc = _getSizeClass(); if (sc !== config.device.size_class) { config.device.size_class = sc; - config.device.isMobile = config.device.size_class <= config.device.SIZES.SM; + config.device.isMobile = config.device.size_class <= config.device.SIZES.MD; } } diff --git a/addons/web/static/src/js/services/crash_manager.js b/addons/web/static/src/js/services/crash_manager.js index a5b8cb32c13..b105913464e 100644 --- a/addons/web/static/src/js/services/crash_manager.js +++ b/addons/web/static/src/js/services/crash_manager.js @@ -142,7 +142,7 @@ var CrashManager = core.Class.extend({ }); }); dialog.on("closed", this, function () { - $clipboardBtn.tooltip("destroy"); + $clipboardBtn.tooltip('dispose'); clipboard.destroy(); }); diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 13a00dda046..197892f3361 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -152,7 +152,6 @@ var BasicRenderer = AbstractRenderer.extend({ // widget's $el $node = $node.length ? $node : widget.$el; $node.tooltip({ - delay: { show: 1000, hide: 0 }, title: function () { return qweb.render('WidgetLabel.tooltip', { debug: config.debug, diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js index 4b4050b67cc..ffb4f41ad6b 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -98,7 +98,7 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, { this.many2one.filter_ids = _.without(_.pluck(this.filters, 'value'), 'all'); } this.$el.on('click', '.o_remove', this._onFilterRemove.bind(this)); - this.$el.on('click', '.o_checkbox input', this._onFilterActive.bind(this)); + this.$el.on('click', '.custom-checkbox input', this._onFilterActive.bind(this)); }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 646dfdd8c40..276173c6f9a 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -35,7 +35,7 @@ var FormRenderer = BasicRenderer.extend({ * @override */ start: function () { - if (config.device.size_class <= config.device.SIZES.XXS) { + if (config.device.size_class <= config.device.SIZES.XS) { this.$el.addClass('o_xxs_form_view'); } return this._super.apply(this, arguments); @@ -159,9 +159,9 @@ var FormRenderer = BasicRenderer.extend({ .removeAttr('disabled'); }, /** - * Put the focus on the last activated widget. + * Put the focus on the last activated widget. * This function is used when closing a dialog to give the focus back to the - * form that has opened it and ensures that the focus is in the correct + * form that has opened it and ensures that the focus is in the correct * field. */ focusLastActivatedWidget: function () { @@ -181,7 +181,7 @@ var FormRenderer = BasicRenderer.extend({ var $notebook = $(this); var name = $notebook.data('name'); var index = -1; - $notebook.find('li').each(function (i) { + $notebook.find('.nav-link').each(function (i) { if ($(this).hasClass('active')) { index = i; } @@ -265,7 +265,6 @@ var FormRenderer = BasicRenderer.extend({ _addButtonTooltip: function (node, $button) { var self = this; $button.tooltip({ - delay: { show: 1000, hide: 0 }, title: function () { return qweb.render('WidgetButton.tooltip', { debug: config.debug, @@ -364,11 +363,11 @@ var FormRenderer = BasicRenderer.extend({ text: _t("More"), })); - var $ul = $("<ul>", {'class': "dropdown-menu o_dropdown_more", role: "menu"}); + var $dropdown = $("<div>", {'class': "dropdown-menu o_dropdown_more", role: "menu"}); _.each(folded_buttons, function ($button) { - $('<li>').appendTo($ul).append($button); + $button.addClass('dropdown-item').appendTo($dropdown); }); - $ul.appendTo($result); + $dropdown.appendTo($result); } this._handleAttributes($result, node); @@ -397,12 +396,13 @@ var FormRenderer = BasicRenderer.extend({ // Current API of odoo for rendering buttons is "if classes are given // use those on top of the 'btn' and 'btn-{size}' classes, otherwise act - // as if 'btn-default' class was given". The problem is that, for header - // buttons only, we allowed users to only indicate their custom classes - // without having to explicitely ask for the 'btn-default' class to be - // added. We force it so here when no bootstrap btn type class is found. - if ($button.not('.btn-primary, .btn-default, .btn-link, .btn-success, .btn-info, .btn-warning, .btn-danger').length) { - $button.addClass('btn-default'); + // as if 'btn-secondary' class was given". The problem is that, for + // header buttons only, we allowed users to only indicate their custom + // classes without having to explicitely ask for the 'btn-secondary' + // class to be added. We force it so here when no bootstrap btn type + // class is found. + if ($button.not('.btn-primary, .btn-secondary, .btn-link, .btn-success, .btn-info, .btn-warning, .btn-danger').length) { + $button.addClass('btn-secondary'); } this._addOnClickAction($button, node); @@ -612,10 +612,11 @@ var FormRenderer = BasicRenderer.extend({ 'data-toggle': 'tab', disable_anchor: 'true', href: '#' + page_id, + class: 'nav-link', role: 'tab', text: page.attrs.string, }); - return $('<li>').append($a); + return $('<li>', {class: 'nav-item'}).append($a); }, /** * @private @@ -761,7 +762,7 @@ var FormRenderer = BasicRenderer.extend({ _renderTagNotebook: function (node) { var self = this; var $headers = $('<ul class="nav nav-tabs">'); - var $pages = $('<div class="tab-content nav nav-tabs">'); + var $pages = $('<div class="tab-content">'); var autofocusTab = -1; // renderedTabs is used to aggregate the generated $headers and $pages // alongside their node, so that their modifiers can be registered once @@ -785,7 +786,7 @@ var FormRenderer = BasicRenderer.extend({ }); if (renderedTabs.length) { var tabToFocus = renderedTabs[Math.max(0, autofocusTab)]; - tabToFocus.$header.addClass('active'); + tabToFocus.$header.find('.nav-link').addClass('active'); tabToFocus.$page.addClass('active'); } // register the modifiers for each tab @@ -793,12 +794,13 @@ var FormRenderer = BasicRenderer.extend({ self._registerModifiers(tab.node, self.state, tab.$header, { callback: function (element, modifiers) { // if the active tab is invisible, activate the first visible tab instead - if (modifiers.invisible && element.$el.hasClass('active')) { - element.$el.removeClass('active'); + var $link = element.$el.find('.nav-link'); + if (modifiers.invisible && $link.hasClass('active')) { + $link.removeClass('active'); tab.$page.removeClass('active'); - var $firstVisibleTab = $headers.find('li:not(.o_invisible_modifier):first()'); + var $firstVisibleTab = $headers.find('li:not(.o_invisible_modifier):first() > a'); $firstVisibleTab.addClass('active'); - $pages.find($firstVisibleTab.find('a').attr('href')).addClass('active'); + $pages.find($firstVisibleTab.attr('href')).addClass('active'); } }, }); @@ -859,7 +861,7 @@ var FormRenderer = BasicRenderer.extend({ this.defs = defs; var $form = this._renderNode(this.arch).addClass(this.className); delete this.defs; - + return $.when.apply($, defs).then(function () { self._updateView($form.contents()); }, function () { @@ -867,7 +869,7 @@ var FormRenderer = BasicRenderer.extend({ }).then(function(){ if (self.lastActivatedFieldIndex >= 0) { self._activateNextFieldWidget(self.state, self.lastActivatedFieldIndex); - } + } }); }, /** @@ -900,7 +902,7 @@ var FormRenderer = BasicRenderer.extend({ // enterprise label will be displayed as many times as the field // exists on settings. var $widgets = self.$('.o_field_widget[name=' + widget.name + ']'); - var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $(); + var $label = idForLabel ? self.$('.o_form_label[for=' + idForLabel + ']') : $(); $label = $label.eq($widgets.index(widget.$el)); if (config.debug || widget.attrs.help || widget.field.help) { self._addFieldTooltip(widget, $label); @@ -920,7 +922,7 @@ var FormRenderer = BasicRenderer.extend({ * @param {idForLabel} string */ _setIDForLabel: function (widget, idForLabel) { - widget.getFocusableElement().attr('id', idForLabel); + widget.setIDForLabel(idForLabel); }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/js/views/graph/graph_controller.js b/addons/web/static/src/js/views/graph/graph_controller.js index e7f25c23fdd..b6a1c121f0f 100644 --- a/addons/web/static/src/js/views/graph/graph_controller.js +++ b/addons/web/static/src/js/views/graph/graph_controller.js @@ -45,7 +45,7 @@ var GraphController = AbstractController.extend(GroupByMenuInterfaceMixin,{ destroy: function () { if (this.$buttons) { // remove jquery's tooltip() handlers - this.$buttons.find('button').off().tooltip('destroy'); + this.$buttons.find('button').off().tooltip('dispose'); } this._super.apply(this, arguments); }, @@ -161,8 +161,9 @@ var GraphController = AbstractController.extend(GroupByMenuInterfaceMixin,{ this.$buttons .find('.o_graph_button[data-mode="' + state.mode + '"]') .addClass('active'); - this.$measureList.find('li').each(function (index, li) { - $(li).toggleClass('selected', $(li).data('field') === state.measure); + _.each(this.$measureList.find('.dropdown-item'), function (item) { + var $item = $(item); + $item.toggleClass('selected', $item.data('field') === state.measure); }); }, @@ -185,8 +186,7 @@ var GraphController = AbstractController.extend(GroupByMenuInterfaceMixin,{ } else if ($target.parents('.o_graph_measures_list').length) { event.preventDefault(); event.stopPropagation(); - parent = $target.parent(); - field = parent.data('field'); + field = $target.data('field'); this._setMeasure(field); } }, diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js index 1fbd6572a9a..686bbaee842 100644 --- a/addons/web/static/src/js/views/graph/graph_renderer.js +++ b/addons/web/static/src/js/views/graph/graph_renderer.js @@ -243,7 +243,7 @@ return AbstractRenderer.extend({ svg.transition().duration(100); - var legend_right = config.device.size_class > config.device.SIZES.XS; + var legend_right = config.device.size_class > config.device.SIZES.VSM; var chart = nv.models.pieChart().labelType('percent'); chart.options({ diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js index 95e3f1e85b1..a1c7e415470 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -153,7 +153,7 @@ var KanbanColumn = Widget.extend({ this.$el.toggleClass('o_column_folded', this.folded && !config.device.isMobile); var tooltip = this.data.count + _t(' records'); tooltip = '<p>' + tooltip + '</p>' + this.tooltipInfo; - this.$header.find('.o_kanban_header_title').tooltip({html: true}).attr('data-original-title', tooltip); + this.$header.find('.o_kanban_header_title').tooltip({}).attr('data-original-title', tooltip); if (!this.remaining) { this.$('.o_kanban_load_more').remove(); } else { diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js index 7af6b677dcf..0bfe5027876 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js @@ -133,9 +133,8 @@ var KanbanColumnProgressBar = Widget.extend({ }); if (this.progressBarHelp && _.every(this.subgroupCounts, function (val) { return val === 0; })) { this.$el.tooltip({ - delay: '0', - trigger:'hover', - placement: 'top', + delay: 0, + trigger: 'hover', title: this.progressBarHelp, }); } @@ -152,9 +151,8 @@ var KanbanColumnProgressBar = Widget.extend({ // Adapt tooltip $bar.attr('data-original-title', count + ' ' + key); $bar.tooltip({ - delay: '0', - trigger:'hover', - placement: 'top' + delay: 0, + trigger: 'hover', }); // Adapt active state diff --git a/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js b/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js index 170b950a49d..b2a38d4e53e 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js @@ -184,7 +184,7 @@ var ColumnQuickCreate = Widget.extend({ examples: this.examples, })), buttons: [{ - classes: 'btn-primary pull-right', + classes: 'btn-primary float-right', close: true, text: _t('Got it'), }], diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 26846e2c511..ab05fabd517 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -119,7 +119,7 @@ var KanbanController = BasicController.extend({ return this._super.apply(this, arguments); }, /** - * In grouped mode, set 'Create' button as btn-default if there is no column + * In grouped mode, set 'Create' button as btn-secondary if there is no column * (except if we can't create new columns) * * @private diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index 247f8eca90f..627543b3422 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -99,8 +99,7 @@ var KanbanRecord = Widget.extend({ var tooltip = $el.attr('tooltip'); if (tooltip) { $el.tooltip({ - 'html': true, - 'title': self.qweb.render(tooltip, self.qweb_context) + title: self.qweb.render(tooltip, self.qweb_context) }); } }); @@ -350,7 +349,7 @@ var KanbanRecord = Widget.extend({ _setFieldDisplay: function ($el, fieldName) { // attribute display if (this.fieldsInfo[fieldName].display === 'right') { - $el.addClass('pull-right'); + $el.addClass('float-right'); } else if (this.fieldsInfo[fieldName].display === 'full') { $el.addClass('o_text_block'); } @@ -490,7 +489,7 @@ var KanbanRecord = Widget.extend({ if (elem === event.currentTarget) { ischild = false; } - var test_event = events && events.click && (events.click.length > 1 || events.click[0].namespace !== "tooltip"); + var test_event = events && events.click && (events.click.length > 1 || events.click[0].namespace !== 'bs.tooltip'); if (ischild) { children.push(elem); if (test_event) { diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index 82a08b3b27f..20d68744f6a 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -653,7 +653,7 @@ var ListRenderer = BasicRenderer.extend({ return this._super(); } - var $table = $('<table>').addClass('o_list_view table table-condensed table-hover table-striped'); + var $table = $('<table>').addClass('o_list_view table table-sm table-hover table-striped'); this.$el .addClass('table-responsive') .append($table); diff --git a/addons/web/static/src/js/views/pivot/pivot_controller.js b/addons/web/static/src/js/views/pivot/pivot_controller.js index f0976c9a8b4..945cc132b03 100644 --- a/addons/web/static/src/js/views/pivot/pivot_controller.js +++ b/addons/web/static/src/js/views/pivot/pivot_controller.js @@ -164,9 +164,9 @@ var PivotController = AbstractController.extend({ fields: fields })); - this.$fieldSelection.find('ul').first() + this.$fieldSelection.find('.dropdown-menu').first() .css({top: top, left: left}) - .show(); + .addClass('show'); }, /** * @private @@ -186,7 +186,7 @@ var PivotController = AbstractController.extend({ var state = this.model.get({raw: true}); _.each(this.measures, function (measure, name) { var isSelected = _.contains(state.measures, name); - self.$buttons.find('li[data-field="' + name + '"]') + self.$buttons.find('.dropdown-item[data-field="' + name + '"]') .toggleClass('selected', isSelected); }); }, @@ -215,8 +215,7 @@ var PivotController = AbstractController.extend({ .then(this.update.bind(this, {}, {reload: false})); } if ($target.parents('.o_pivot_measures_list').length) { - var parent = $target.parent(); - var field = parent.data('field'); + var field = $target.data('field'); event.preventDefault(); event.stopPropagation(); this.model @@ -298,11 +297,11 @@ var PivotController = AbstractController.extend({ _onFieldMenuSelection: function (event) { event.preventDefault(); var $target = $(event.target); - if ($target.parent().hasClass('disabled')) { + if ($target.hasClass('disabled')) { event.stopPropagation(); return; } - var field = $target.parent().data('field'); + var field = $target.data('field'); var interval = $target.data('interval'); var header = this.model.getHeader(this.lastHeaderSelected); if (interval) { diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js index b3953076161..9312b27f1ef 100644 --- a/addons/web/static/src/js/views/pivot/pivot_renderer.js +++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js @@ -9,7 +9,7 @@ var QWeb = core.qweb; var PivotRenderer = AbstractRenderer.extend({ tagName: 'table', - className: 'table-hover table-condensed table-bordered', + className: 'table-hover table-sm table-bordered', events: _.extend({}, AbstractRenderer.prototype.events, { 'hover td': '_onTdHover', }), @@ -105,7 +105,7 @@ var PivotRenderer = AbstractRenderer.extend({ } $row.append($cell); - $cell.toggleClass('hidden-xs', (cell.expanded !== undefined) || (cell.measure !== undefined && j < headers[i].length - this.state.measures.length)); + $cell.toggleClass('d-none d-md-table-cell', (cell.expanded !== undefined) || (cell.measure !== undefined && j < headers[i].length - this.state.measures.length)); if (cell.height > 1) { $cell.css('padding', 0); } @@ -159,7 +159,7 @@ var PivotRenderer = AbstractRenderer.extend({ } $row.append($cell); - $cell.toggleClass('hidden-xs', j < length - nbrMeasures); + $cell.toggleClass('d-none d-md-table-cell', j < length - nbrMeasures); } $tbody.append($row); } diff --git a/addons/web/static/src/js/views/search/favorites_menu.js b/addons/web/static/src/js/views/search/favorites_menu.js index 1e62ffb5ce3..47e99aec573 100644 --- a/addons/web/static/src/js/views/search/favorites_menu.js +++ b/addons/web/static/src/js/views/search/favorites_menu.js @@ -14,14 +14,11 @@ var _t = core._t; return Widget.extend({ template: 'SearchView.FavoriteMenu', events: { - 'click li': function (event) { - event.stopImmediatePropagation(); + 'click .dropdown-item': function (ev) { + ev.preventDefault(); }, - 'click li a': function (event) { - event.preventDefault(); - }, - 'click .o_save_search a': function (event) { - event.preventDefault(); + 'click .o_save_search': function (ev) { + ev.preventDefault(); this.toggle_save_menu(); }, 'click .o_save_name button': 'save_favorite', @@ -49,8 +46,8 @@ return Widget.extend({ this.$save_search = this.$('.o_save_search'); this.$save_name = this.$('.o_save_name'); this.$inputs = this.$save_name.find('input'); - this.$user_divider = this.$('.divider.user_filter'); - this.$shared_divider = this.$('.divider.shared_filter'); + this.$user_divider = this.$('.dropdown-divider.user_filter'); + this.$shared_divider = this.$('.dropdown-divider.shared_filter'); this.$inputs.eq(0).val(this.searchview.get_title()); var $shared_filter = this.$inputs.eq(1), $default_filter = this.$inputs.eq(2); @@ -207,7 +204,7 @@ return Widget.extend({ }; }, clear_selection: function () { - this.$('li.selected').removeClass('selected'); + this.$('.selected').removeClass('selected'); }, /** * Adds a filter description to the filters dict @@ -230,10 +227,10 @@ return Widget.extend({ this.$shared_divider.show(); } if (!(key in this.$filters)) { - var $filter = $('<li>') + var $filter = $('<div>', {class: 'position-relative'}) .addClass(filter.user_id ? 'o-searchview-custom-private' : 'o-searchview-custom-public') - .append($('<a>', {'href': '#'}).text(filter.name)) + .append($('<a>', {href: '#', class: 'dropdown-item'}).text(filter.name)) .append($('<span>', { class: 'fa fa-trash-o o-remove-filter', on: { @@ -256,7 +253,7 @@ return Widget.extend({ }); if (current) { this.query.remove(current); - this.$filters[this.key_for(filter)].removeClass('selected'); + this.$filters[this.key_for(filter)].find('.dropdown-item').removeClass('selected'); return; } this.query.reset([this.facet_for(filter)], { @@ -268,7 +265,7 @@ return Widget.extend({ this.searchview.dataset.set_sort(sort_items); } - this.$filters[this.key_for(filter)].addClass('selected'); + this.$filters[this.key_for(filter)].find('.dropdown-item').addClass('selected'); }, remove_filter: function (filter, $filter, key) { var self = this; diff --git a/addons/web/static/src/js/views/search/filters_menu.js b/addons/web/static/src/js/views/search/filters_menu.js index 221f98faa97..af5425ec2d7 100644 --- a/addons/web/static/src/js/views/search/filters_menu.js +++ b/addons/web/static/src/js/views/search/filters_menu.js @@ -76,7 +76,7 @@ var FiltersMenu = DropdownMenu.extend({ category: 'filterCategory', title: 'Filters', icon: 'fa fa-filter', - symbol: this.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret' + symbol: this.isMobile ? 'fa fa-chevron-right float-right mt4' : false, }; this._super(parent, dropdownHeader, filters, this.fields); }, @@ -88,7 +88,7 @@ var FiltersMenu = DropdownMenu.extend({ * @private */ start: function () { - this.$menu = this.$('ul.o_dropdown_menu'); + this.$menu = this.$('.o_dropdown_menu'); this.$menu.addClass('o_filters_menu'); var generatorMenu = QWeb.render('FiltersMenuGenerator', {widget: this}); this.$menu.append(generatorMenu); diff --git a/addons/web/static/src/js/views/search/groupby_menu.js b/addons/web/static/src/js/views/search/groupby_menu.js index 7b3b8e31fef..d686a4d55cb 100644 --- a/addons/web/static/src/js/views/search/groupby_menu.js +++ b/addons/web/static/src/js/views/search/groupby_menu.js @@ -14,7 +14,7 @@ var DEFAULT_INTERVAL = 'month'; var GroupByMenu = DropdownMenu.extend({ events: _.extend({}, DropdownMenu.prototype.events, { - 'click .o_add_custom_group a': '_onAddCustomGroupClick', + 'click .o_add_custom_group': '_onAddCustomGroupClick', 'click button.o_apply_group': '_onButtonApplyClick', 'click .o_group_selector': '_onGroupSelectorClick', }), @@ -78,14 +78,14 @@ var GroupByMenu = DropdownMenu.extend({ if (options && options.headerStyle === 'primary') { style = { el: {class: 'btn-group o_graph_groupbys_menu o_dropdown', attrs: {'role': 'group'}}, - mainButton: {class: 'btn btn-primary btn-sm dropdown-toggle'}, + mainButton: {class: 'btn btn-primary dropdown-toggle'}, }; } var dropdownHeader = { category: 'groupByCategory', title: 'Group By', icon: 'fa fa-bars', - symbol: this.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret', + symbol: this.isMobile ? 'fa fa-chevron-right float-right mt4' : false, style: style, }; this._super(parent, dropdownHeader, groupbys, options); @@ -98,7 +98,7 @@ var GroupByMenu = DropdownMenu.extend({ * @private */ start: function () { - this.$menu = this.$('ul.o_dropdown_menu'); + this.$menu = this.$('.o_dropdown_menu'); this.$menu.addClass('o_group_by_menu'); var $generatorMenu = QWeb.render('GroupbyMenuGenerator', {widget: this}); this.$menu.append($generatorMenu); diff --git a/addons/web/static/src/js/views/search/search_inputs.js b/addons/web/static/src/js/views/search/search_inputs.js index ee179d7da74..81f53ee4053 100644 --- a/addons/web/static/src/js/views/search/search_inputs.js +++ b/addons/web/static/src/js/views/search/search_inputs.js @@ -503,8 +503,13 @@ var ManyToOneField = CharField.extend({ var FilterGroup = Input.extend(/** @lends instance.web.search.FilterGroup# */{ template: 'SearchView.filters', + events: { + click: 'toggle_filter', + }, + icon: "fa-filter", completion_label: _lt("Filter on: %s"), + /** * Inclusive group of filters, creates a continuous "button" with clickable * sections (the normal display for filters is to be a self-contained button) @@ -536,7 +541,6 @@ var FilterGroup = Input.extend(/** @lends instance.web.search.FilterGroup# */{ this.searchview.query.on('add remove change reset', this.proxy('search_change')); }, start: function () { - this.$el.on('click', 'a', this.proxy('toggle_filter')); return $.when(null); }, /** @@ -684,7 +688,7 @@ var FilterGroup = Input.extend(/** @lends instance.web.search.FilterGroup# */{ toggle_filter: function (e) { e.preventDefault(); e.stopPropagation(); - this.toggle(this.filters[Number($(e.target).parent().data('index'))]); + this.toggle(this.filters[Number($(e.currentTarget).data('index'))]); }, toggle: function (filter, options) { this.searchview.query.toggle(this.make_facet([this.make_value(filter)]), options); diff --git a/addons/web/static/src/js/views/search/search_view.js b/addons/web/static/src/js/views/search/search_view.js index 9e1f70fec22..2bac31ed27f 100644 --- a/addons/web/static/src/js/views/search/search_view.js +++ b/addons/web/static/src/js/views/search/search_view.js @@ -535,7 +535,7 @@ var SearchView = Widget.extend({ * puts the focus on the search input */ _focusInput: function () { - if (!config.device.touch && config.device.size_class >= config.device.SIZES.SM) { + if (!config.device.touch && config.device.size_class >= config.device.SIZES.MD) { this.$('input').focus(); } }, diff --git a/addons/web/static/src/js/views/search/search_view_mobile.js b/addons/web/static/src/js/views/search/search_view_mobile.js index 852a65c0a37..ea7fe33ad81 100644 --- a/addons/web/static/src/js/views/search/search_view_mobile.js +++ b/addons/web/static/src/js/views/search/search_view_mobile.js @@ -54,7 +54,7 @@ SearchView.include({ * @private */ _toggleMobileSearchView: function () { - this.$('.o_enable_searchview').toggleClass('btn-default', !!this.query.length); + this.$('.o_enable_searchview').toggleClass('btn-secondary', !!this.query.length); this.$('.o_mobile_search').toggleClass('o_hidden'); }, diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js index ed0adf0ff3b..e99f81ccb08 100644 --- a/addons/web/static/src/js/views/view_dialogs.js +++ b/addons/web/static/src/js/views/view_dialogs.js @@ -109,7 +109,7 @@ var FormViewDialog = ViewDialog.extend({ options = options || {}; options.buttons = [{ text: (readonly ? _t("Close") : _t("Discard")), - classes: "btn-default o_form_button_cancel", + classes: "btn-secondary o_form_button_cancel", close: true, click: function () { if (!readonly) { @@ -360,7 +360,7 @@ var SelectCreateDialog = ViewDialog.extend({ // Set the dialog's buttons self.__buttons = [{ text: _t("Cancel"), - classes: "btn-default o_form_button_cancel", + classes: "btn-secondary o_form_button_cancel", close: true, }]; if (!self.options.no_create) { diff --git a/addons/web/static/src/js/widgets/data_export.js b/addons/web/static/src/js/widgets/data_export.js index 30e17604077..d05bf2d33fc 100644 --- a/addons/web/static/src/js/widgets/data_export.js +++ b/addons/web/static/src/js/widgets/data_export.js @@ -49,7 +49,7 @@ var DataExport = Dialog.extend({ function process_children() { var $this = $(this); - if($this.hasClass('open')) { + if($this.hasClass('show')) { $this.children('.o_export_tree_item') .addClass('o_selected') .each(process_children); @@ -77,19 +77,19 @@ var DataExport = Dialog.extend({ switch(e.keyCode || e.which) { case $.ui.keyCode.LEFT: - if ($elem.hasClass('open')) { + if ($elem.hasClass('show')) { this.on_expand_action(record); } break; case $.ui.keyCode.RIGHT: - if (!$elem.hasClass('open')) { + if (!$elem.hasClass('show')) { this.on_expand_action(record); } break; case $.ui.keyCode.UP: var $prev = $elem.prev('.o_export_tree_item'); if($prev.length === 1) { - while($prev.hasClass('open')) { + while($prev.hasClass('show')) { $prev = $prev.children('.o_export_tree_item').last(); } } else { @@ -104,7 +104,7 @@ var DataExport = Dialog.extend({ break; case $.ui.keyCode.DOWN: var $next; - if($elem.hasClass('open')) { + if($elem.hasClass('show')) { $next = $elem.children('.o_export_tree_item').first(); } else { $next = $elem.next('.o_export_tree_item'); @@ -408,7 +408,7 @@ var DataExport = Dialog.extend({ var self = this; if(expansion) { this.$('.o_export_tree_item[data-id="' + expansion + '"]') - .addClass('open') + .addClass('show') .find('.o_expand_parent') .toggleClass('fa-chevron-right fa-chevron-down') .next() @@ -429,8 +429,8 @@ var DataExport = Dialog.extend({ }, show_content: function(id) { var $this = this.$('.o_export_tree_item[data-id="' + id + '"]'); - $this.toggleClass('open'); - var is_open = $this.hasClass('open'); + $this.toggleClass('show'); + var is_open = $this.hasClass('show'); $this.children('.o_expand_parent').toggleClass('fa-chevron-down', !!is_open).toggleClass('fa-chevron-right', !is_open); @@ -441,8 +441,8 @@ var DataExport = Dialog.extend({ if(!is_open) { $child.hide(); } else if(child_len === $child_field.eq(i).data('id').split("/").length) { - if ($child.hasClass('open')) { - $child.removeClass('open'); + if ($child.hasClass('show')) { + $child.removeClass('show'); $child.children('.o_expand_parent').removeClass('fa-chevron-down').addClass('fa-chevron-right'); } $child.show(); diff --git a/addons/web/static/src/js/widgets/date_picker.js b/addons/web/static/src/js/widgets/date_picker.js index 8f87b36c874..9d47e79f6a7 100644 --- a/addons/web/static/src/js/widgets/date_picker.js +++ b/addons/web/static/src/js/widgets/date_picker.js @@ -1,69 +1,74 @@ odoo.define('web.datepicker', function (require) { "use strict"; -var core = require('web.core'); var field_utils = require('web.field_utils'); var time = require('web.time'); var Widget = require('web.Widget'); -var _t = core._t; - var DateWidget = Widget.extend({ template: "web.datepicker", type_of_date: "date", events: { - 'dp.change': 'changeDatetime', - 'dp.show': '_onShow', + 'change.datetimepicker': 'changeDatetime', + 'show.datetimepicker': '_onShow', + 'click input.o_datepicker_input': '_onClick', 'change .o_datepicker_input': 'changeDatetime', + 'input input': '_onInput', }, /** * @override */ - init: function(parent, options) { + init: function (parent, options) { this._super.apply(this, arguments); - var l10n = _t.database.parameters; - this.name = parent.name; - this.options = _.defaults(options || {}, { + this.options = _.extend({ format : this.type_of_date === 'datetime' ? time.getLangDatetimeFormat() : time.getLangDateFormat(), minDate: moment({ y: 1900 }), maxDate: moment().add(200, "y"), - calendarWeeks: true, + useCurrent: false, icons: { time: 'fa fa-clock-o', date: 'fa fa-calendar', - next: 'fa fa-chevron-right', - previous: 'fa fa-chevron-left', up: 'fa fa-chevron-up', down: 'fa fa-chevron-down', - close: 'fa fa-times', + previous: 'fa fa-chevron-left', + next: 'fa fa-chevron-right', + today: 'fa fa-calendar-check-o', + clear: 'fa fa-delete', + close: 'fa fa-times' + }, + calendarWeeks: true, + buttons: { + showToday: false, + showClear: false, + showClose: false, }, - locale : moment.locale(), - allowInputToggle: true, - keyBinds: null, widgetParent: 'body', - useCurrent: false, - }); + keyBinds: null, + allowInputToggle: true, + }, options || {}); }, /** * @override */ - start: function() { + start: function () { this.$input = this.$('input.o_datepicker_input'); - this.$input.focus(function(e) { + this.$input.focus(function (e) { e.stopImmediatePropagation(); }); + this.__libInput = true; this.$input.datetimepicker(this.options); - this.picker = this.$input.data('DateTimePicker'); - this.$input.click(this.picker.toggle.bind(this.picker)); + this.__libInput = false; this._setReadonly(false); }, /** * @override */ - destroy: function() { - this.picker.destroy(); + destroy: function () { + this.__libInput = true; + this.$input.datetimepicker('destroy'); + this.__libInput = false; this._super.apply(this, arguments); }, @@ -82,7 +87,7 @@ var DateWidget = Widget.extend({ var hasChanged = !oldValue !== !newValue; if (oldValue && newValue) { var formattedOldValue = oldValue.format(time.getLangDatetimeFormat()); - var formattedNewValue = newValue.format(time.getLangDatetimeFormat()) + var formattedNewValue = newValue.format(time.getLangDatetimeFormat()); if (formattedNewValue !== formattedOldValue) { hasChanged = true; } @@ -106,13 +111,13 @@ var DateWidget = Widget.extend({ */ isValid: function () { var value = this.$input.val(); - if(value === "") { + if (value === "") { return true; } else { try { this._parseClient(value); return true; - } catch(e) { + } catch (e) { return false; } } @@ -124,9 +129,9 @@ var DateWidget = Widget.extend({ this.set({'value': value}); var formatted_value = value ? this._formatClient(value) : null; this.$input.val(formatted_value); - if (this.picker) { - this.picker.date(value || null); - } + this.__libInput = true; + this.$input.datetimepicker('date', value || null); + this.__libInput = false; }, //-------------------------------------------------------------------------- @@ -162,7 +167,7 @@ var DateWidget = Widget.extend({ * * @private */ - _setValueFromUi: function() { + _setValueFromUi: function () { var value = this.$input.val() || false; this.setValue(this._parseClient(value)); }, @@ -172,6 +177,23 @@ var DateWidget = Widget.extend({ //-------------------------------------------------------------------------- /** + * @private + */ + _onClick: function () { + this.__libInput = true; + this.$input.datetimepicker('toggle'); + this.__libInput = false; + }, + /** + * @private + * @param {Event} ev + */ + _onInput: function (ev) { + if (this.__libInput) { + ev.stopImmediatePropagation(); + } + }, + /** * set the date of the picker by the current date or the today date * * @private @@ -179,9 +201,11 @@ var DateWidget = Widget.extend({ _onShow: function () { //when opening datetimepicker the date and time by default should be the one from //the input field if any or the current day otherwise - if(this.$input.val().length !== 0 && this.isValid()) { + if (this.$input.val().length !== 0 && this.isValid()) { var value = this._parseClient(this.$input.val()); - this.picker.date(value); + this.__libInput = true; + this.$input.datetimepicker('date', value); + this.__libInput = false; this.$input.select(); } }, @@ -189,11 +213,14 @@ var DateWidget = Widget.extend({ var DateTimeWidget = DateWidget.extend({ type_of_date: "datetime", - init: function() { - this._super.apply(this, arguments); - this.options = _.defaults(this.options, { - showClose: true, - }); + init: function (parent, options) { + this._super(parent, _.extend({ + buttons: { + showToday: false, + showClear: false, + showClose: true, + }, + }, options || {})); }, }); diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js index 4eee9266594..d553387f153 100644 --- a/addons/web/static/src/js/widgets/debug_manager.js +++ b/addons/web/static/src/js/widgets/debug_manager.js @@ -23,12 +23,12 @@ var DebugManager = Widget.extend({ template: "WebClient.DebugManager", events: { "click a[data-action]": "perform_callback", - "mouseover .o_debug_dropdowns > li:not(.open)": function(e) { + "mouseover .o_debug_dropdowns > li:not(.show)": function(e) { // Open other dropdowns on mouseover - var $opened = this.$('.o_debug_dropdowns > li.open'); + var $opened = this.$('.o_debug_dropdowns > li.show'); if($opened.length) { - $opened.removeClass('open'); - $(e.currentTarget).addClass('open').find('> a').focus(); + $opened.removeClass('show'); + $(e.currentTarget).addClass('show').find('> a').focus(); } }, }, diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js index c5a561b1b77..dab0c97108b 100644 --- a/addons/web/static/src/js/widgets/domain_selector.js +++ b/addons/web/static/src/js/widgets/domain_selector.js @@ -161,7 +161,7 @@ var DomainNode = Widget.extend({ var DomainTree = DomainNode.extend({ template: "DomainTree", events: _.extend({}, DomainNode.prototype.events, { - "click .o_domain_tree_operator_selector > ul > li > a": "_onOperatorChange", + "click .o_domain_tree_operator_selector .dropdown-item": "_onOperatorChange", }), custom_events: { // If a domain child sends a request to add a child or remove one, call diff --git a/addons/web/static/src/js/widgets/dropdown_menu.js b/addons/web/static/src/js/widgets/dropdown_menu.js index a3a83519678..6f8f78a13d5 100644 --- a/addons/web/static/src/js/widgets/dropdown_menu.js +++ b/addons/web/static/src/js/widgets/dropdown_menu.js @@ -11,8 +11,8 @@ var QWeb = core.qweb; var DropdownMenu = Widget.extend({ template: 'web.DropdownMenu', events: { - 'click li.o_menu_item': '_onItemClick', - 'click li.o_item_option': '_onOptionClick', + 'click .o_menu_item': '_onItemClick', + 'click .o_item_option': '_onOptionClick', 'click span.o_trash_button': '_onTrashClick', 'hidden.bs.dropdown': '_onBootstrapClose', }, @@ -44,12 +44,12 @@ var DropdownMenu = Widget.extend({ this.dropdownCategory = dropdownHeader.category; this.dropdownTitle = dropdownHeader.title; this.dropdownIcon = dropdownHeader.icon; - this.dropdownSymbol = dropdownHeader.symbol || 'caret'; + this.dropdownSymbol = dropdownHeader.symbol || false; // this parameter fixes the menu style. By default, // the style used is the one used in the search view this.dropdownStyle = dropdownHeader.style || { el: {class: 'btn-group o_dropdown', attrs: {}}, - mainButton: {class: 'o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle'}, + mainButton: {class: 'o_dropdown_toggler_btn btn btn-secondary dropdown-toggle' + (this.dropdownSymbol ? ' o-no-caret' : '')}, }; this.items = items; _.each(this.items, this._prepareItem.bind(this)); @@ -105,8 +105,8 @@ var DropdownMenu = Widget.extend({ */ _renderMenuItems: function () { var newMenuItems = QWeb.render('DropdownMenu.MenuItems', {widget: this}); - this.$el.find('.o_menu_item,.divider[data-removable="1"]').remove(); - this.$('ul.o_dropdown_menu').prepend($(newMenuItems)); + this.$el.find('.o_menu_item, .dropdown-divider[data-removable="1"]').remove(); + this.$('.o_dropdown_menu').prepend($(newMenuItems)); }, /** * this function computes some default values for some of the item keys @@ -189,7 +189,7 @@ var DropdownMenu = Widget.extend({ * @param {jQueryEvent} event */ _onBootstrapClose: function () { - _.each(this.items, function(item) { + _.each(this.items, function (item) { item.isOpen = false; }); this._renderMenuItems(); diff --git a/addons/web/static/src/js/widgets/model_field_selector.js b/addons/web/static/src/js/widgets/model_field_selector.js index 81abfbe0d6c..e9990ac5105 100644 --- a/addons/web/static/src/js/widgets/model_field_selector.js +++ b/addons/web/static/src/js/widgets/model_field_selector.js @@ -253,7 +253,7 @@ var ModelFieldSelector = Widget.extend({ if (!this._isOpen) return; this._isOpen = false; - this.$popover.addClass("hidden"); + this.$popover.addClass('d-none'); if (this.dirty) { this.dirty = false; @@ -332,7 +332,7 @@ var ModelFieldSelector = Widget.extend({ })); // Toggle the warning message - this.$valid.toggleClass("hidden", !!this.isValid()); + this.$valid.toggleClass('d-none', !!this.isValid()); // Adapt the popover content var page = _.last(this.pages); @@ -376,7 +376,7 @@ var ModelFieldSelector = Widget.extend({ if (this._isOpen) return; this._isOpen = true; - this.$popover.removeClass("hidden"); + this.$popover.removeClass('d-none'); }, /** * Toggles the valid status of the widget and display the error message if diff --git a/addons/web/static/src/js/widgets/switch_company_menu.js b/addons/web/static/src/js/widgets/switch_company_menu.js index 01c224370d2..c9498950a04 100644 --- a/addons/web/static/src/js/widgets/switch_company_menu.js +++ b/addons/web/static/src/js/widgets/switch_company_menu.js @@ -18,7 +18,7 @@ var _t = core._t; var SwitchCompanyMenu = Widget.extend({ template: 'SwitchCompanyMenu', events: { - 'click .dropdown-menu li a[data-menu]': '_onClick', + 'click .dropdown-item[data-menu]': '_onClick', }, /** * @override @@ -53,8 +53,8 @@ var SwitchCompanyMenu = Widget.extend({ } else { a = '<span style="margin-right: 24px;"/>'; } - companiesList += '<li><a href="#" data-menu="company" data-company-id="' + - company[0] + '">' + a + company[1] + '</a></li>'; + companiesList += '<a href="#" class="dropdown-item" data-menu="company" data-company-id="' + + company[0] + '">' + a + company[1] + '</a>'; }); this.$('.dropdown-menu').html(companiesList); return this._super(); diff --git a/addons/web/static/src/scss/animation.scss b/addons/web/static/src/scss/animation.scss index 92097a23298..d65a509bcad 100644 --- a/addons/web/static/src/scss/animation.scss +++ b/addons/web/static/src/scss/animation.scss @@ -144,19 +144,3 @@ transform: scale3d(1, 1, 1); } } - -/************** MIXINS for ANIMATIONS **************/ -@mixin o-display-marked($content, $top, $left, $color) { - @include o-position-absolute($top: $top, $left: $left); - font-size: 300px; - font-family: "FontAwesome"; - content: $content; - color: $color; - @include o-transform-origin; - @include o-animation(markAnim, 1s, ease-in-out, 0s, 1, normal, forwards); - - @media (max-width: $screen-sm-max) { - left: 40%; - font-size: 30vw; - } -} diff --git a/addons/web/static/src/scss/base_settings.scss b/addons/web/static/src/scss/base_settings.scss index 7cd25c7e578..436298872da 100644 --- a/addons/web/static/src/scss/base_settings.scss +++ b/addons/web/static/src/scss/base_settings.scss @@ -1,16 +1,16 @@ // MIXINS -@mixin o-base-settings-horizontal-padding($padding-base: $padding-small-vertical) { +@mixin o-base-settings-horizontal-padding($padding-base: $input-btn-padding-y-sm) { padding: $padding-base $o-horizontal-padding; - @media (min-width: $screen-lg-min) { + @include media-breakpoint-up(xl) { padding-left: $o-horizontal-padding*2;; } } // Use a very specif selector to overwrite generic form-view rules .o_form_view.o_form_nosheet.o_base_settings { - @include o-flex-display; - @include o-flex-flow(column, nowrap); + display: flex; + flex-flow: column nowrap; padding: 0px; } @@ -18,20 +18,20 @@ .o_base_settings { height: 100%; - @media (max-width: $screen-xs-max) { - @include o-flex-flow(column, nowrap); + @include media-breakpoint-down(sm) { + flex-flow: column nowrap; } .o_control_panel { .o_panel { - @include o-flex-display; - @include o-flex-flow(row, wrap); + display: flex; + flex-flow: row wrap; margin-bottom: $o-sheet-vpadding*0.5; width: 100%; .title, .o_setting_search { - @include o-flex(1, 0, auto); - width: $screen-xs-min*0.5; + flex: 1 0 auto; + width: map-get($o-extra-grid-breakpoints, vsm) / 2; } .o_setting_search { @@ -41,15 +41,15 @@ height: 28px; padding: 0px; border: 0px; - border-bottom: 1px solid $gray-lighter-darker; - border-color: $gray; + border-bottom: 1px solid gray('400'); + border-color: gray('700'); box-shadow: none; font-weight: 500; } .searchIcon { @include o-position-absolute(4px, 0); - color: $gray; + color: gray('700'); } } } @@ -60,7 +60,7 @@ border: 0; .btn-primary, .btn-link { - padding: $padding-small-vertical $padding-small-horizontal; + padding: $btn-padding-y-sm $btn-padding-x-sm; } .btn-link { @@ -70,34 +70,34 @@ } .o_setting_container { - @include o-flex-display; - @include o-flex(1, 1, auto); + display: flex; + flex: 1 1 auto; overflow: auto; - @media (max-width: $screen-xs-max) { - @include o-flex-flow(column, nowrap); + @include media-breakpoint-down(sm) { + flex-flow: column nowrap; } .settings_tab { - @include o-flex-display; - @include o-flex(0, 0, auto); - @include o-flex-flow(column, nowrap); - background: $gray-dark; + display: flex; + flex: 0 0 auto; + flex-flow: column nowrap; + background: gray('900'); overflow: auto; padding-top: $o-horizontal-padding*0.5; - @media (max-width: $screen-xs-max) { - @include o-flex(0, 0, $o-base-settings-mobile-tabs-height); - @include o-inline-flex-display; + @include media-breakpoint-down(sm) { + flex: 0 0 $o-base-settings-mobile-tabs-height; + display: inline-flex; position: relative; overflow: hidden; padding: 0; } .selected { - background-color: $gray-darker; - box-shadow: inset 3px 0 0 $o-brand-optional; + background-color: gray('900'); + box-shadow: inset 3px 0 0 $o-brand-primary; .app_name { color: white; @@ -105,10 +105,10 @@ } .tab { - @include o-flex-display; + display: flex; padding: 0 $o-horizontal-padding*2 0 $o-horizontal-padding; height: 40px; - color: $gray-lighter-darker; + color: gray('400'); font-size: 13px; line-height: 40px; cursor: pointer; @@ -119,7 +119,7 @@ } // Mobile Tabs - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { display: block; @include o-position-absolute($left:100%); @include size(auto, $o-base-settings-mobile-tabs-height); @@ -128,8 +128,8 @@ font-size: 14px; font-weight: 500; line-height: inherit; - @include o-transition(0.2s, all); - @include o-transform(translate3d(0,0,0)); + transition: 0.2s all ease 0s; + transform: translate3d(0,0,0); .app_name { display: block; @@ -138,11 +138,11 @@ &:after { content: ''; - background: $o-brand-optional; + background: $o-brand-primary; opacity: 0; @include o-position-absolute(auto, 0, 0, 0); @include size(100%, 3px); - @include o-transition(0.2s, all); + transition: 0.2s all ease 0s; } &.previous, &.before { @@ -171,7 +171,7 @@ .settings { position: relative; - @include o-flex(1, 1, 100%); + flex: 1 1 100%; background-color: $o-view-background-color; overflow: auto; @@ -179,7 +179,7 @@ h2 { margin-bottom: 0; @include o-base-settings-horizontal-padding; - background-color: $gray-lighter; + background-color: gray('200'); font-size: 15px; font-weight: bold; @@ -190,19 +190,20 @@ } .o_settings_container { - max-width: $screen-md-min; // Provide a maximum container size to ensure readability + max-width: map-get($grid-breakpoints, lg); // Provide a maximum container size to ensure readability @include o-base-settings-horizontal-padding(0); } } .settingSearchHeader { - @include o-flex-display; + display: flex; margin: 30px 0 10px; @include o-base-settings-horizontal-padding; - background-color: $gray-lighter; + background-color: gray('200'); .icon { - @include square(25px); + width: 25px; + height: 25px; margin-right: 10px; } diff --git a/addons/web/static/src/scss/bootstrap_overridden.scss b/addons/web/static/src/scss/bootstrap_overridden.scss index 9701ead0539..8d0cf644b62 100644 --- a/addons/web/static/src/scss/bootstrap_overridden.scss +++ b/addons/web/static/src/scss/bootstrap_overridden.scss @@ -1,85 +1,91 @@ -// ------------------------------------------------------------------ -// Bootstrap variables -// ------------------------------------------------------------------ - -//== Grid -$grid-gutter-width: $o-horizontal-padding*2; - -//== Colors -$brand-primary: $o-brand-primary; - -//== Greyscale -$gray-base: #000; -$gray-darker: lighten($gray-base, 13.5%); -$gray-dark: lighten($gray-base, 20%); -$gray: lighten($gray-base, 33.5%); -$gray-light: $o-color-gray-light; -$gray-lighter: $o-color-silver; - -//== Titles -$font-size-h1: $o-font-size-base + 13px; -$font-size-h2: $o-font-size-base + 7px; -$font-size-h3: $o-font-size-base + 3px; -$font-size-h4: $o-font-size-base + 2px; -$font-size-h5: $o-font-size-base + 1px; -$font-size-h6: $o-font-size-base; - -//== Scaffolding +/// +/// This file is a copy of the bootstrap _variables.scss file where all the +/// left-untouched variables definition have been removed. +/// + +// +// Color system +// + +// All of those are BS default +$white: #fff !default; +$gray-100: $o-gray-100 !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; + +$primary: $o-brand-primary; +$secondary: $white; + +// Body +// +// Settings for the `<body>` element. + $body-bg: $o-brand-secondary; -$text-color: $o-main-text-color; -$link-color: $o-brand-optional; +$body-color: $o-main-text-color; + +// Links +// +// Style anchor elements. + $link-hover-decoration: none; -//== Typography +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-gutter-width: $o-horizontal-padding * 2; + +// Components +// +// Define common padding and border radius sizes and more. + +$border-radius: 3px; + +$component-active-color: $o-brand-primary; +$component-active-bg: $gray-200; + +// Fonts +// +// Font, line-height, and color for body text, headings, and more. + $font-family-sans-serif: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif; + $font-size-base: $o-font-size-base; -$headings-font-weight: bold; $line-height-base: $o-line-height-base; -//== Components -$border-radius-base: 3px; -$component-active-bg: $gray-lighter; -$component-active-color: $o-brand-optional; +$h1-font-size: $o-font-size-base * 2.0; +$h2-font-size: $o-font-size-base * 1.5; +$h3-font-size: $o-font-size-base * 1.3; +$h4-font-size: $o-font-size-base * 1.2; +$h5-font-size: $o-font-size-base * 1.1; -//== Badges -$badge-bg: $o-brand-optional; -$badge-color: white; -$badge-line-height: $o-line-height-base; -$badge-font-weight: normal; +$headings-font-weight: bold; + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +$table-accent-bg: #EFEFF8; // FIXME: expose +$table-hover-bg: darken($table-accent-bg, 5%); + +// Dropdowns +// +// Dropdown menu container and contents. + +$dropdown-border-color: $gray-300; -//== Breadcrumbs -$breadcrumb-active-color: #777777; -$breadcrumb-bg: $o-control-panel-background-color; -$breadcrumb-color: #777777; -$breadcrumb-padding-horizontal: 0; -$breadcrumb-padding-vertical: 0; - -//== Buttons -$btn-default-bg: white; -$btn-default-border: #cccccc; -$btn-default-color: $o-main-text-color; -$btn-primary-bg: $o-brand-optional; -$btn-primary-border: $o-brand-optional; -$btn-primary-color: white; - -//== Dropdowns -$dropdown-bg: white; -$dropdown-border: $gray-lighter-dark; -$dropdown-divider-bg: $gray-lighter-dark; $dropdown-link-color: $o-main-text-color; -$dropdown-link-hover-color: $gray-dark; -$dropdown-link-hover-bg: $gray-lighter; -$dropdown-link-active-color: $component-active-color; -$dropdown-link-active-bg: $component-active-bg; -$dropdown-link-disabled-color: $gray-light; -$dropdown-header-color: $gray-light; - -//== Modals -$modal-sm: 300px; -$modal-md: 650px; -$modal-lg: 980px; -$modal-inner-padding: $o-horizontal-padding; -$modal-title-padding: $o-horizontal-padding; +$dropdown-link-hover-color: $gray-900; +$dropdown-link-hover-bg: $gray-200; + +// Z-index master list // Change the z-index of the modal-backdrop elements to be equal to the // modal elements' ones. Bootstrap does not support multi-modals, and without @@ -90,31 +96,45 @@ $modal-title-padding: $o-horizontal-padding; // cannot happen in odoo though as modals are not hidden but removed from // the DOM and are always put at the end of the body when opened. // -// Note that the variable $zindex-modal-background may be renamed/removed in -// newer versions of bootstrap. -// // TODO the following code was disabled because it is saas-incompatible // -// $zindex-modal-background: $zindex-modal; +// $zindex-modal-backdrop: $zindex-modal; + +// Navs + +$nav-tabs-link-active-bg: $white; -//== Navs -$nav-link-padding: 10px 15px; $nav-pills-border-radius: 0; -$nav-pills-active-link-hover-color: white; -$nav-pills-active-link-hover-bg: $o-brand-optional; -$nav-tabs-active-link-hover-bg: white; - -//== Navbar -$navbar-height: $o-navbar-height - 2; -$navbar-margin-bottom: 0; -$navbar-inverse-bg: #222222; -$navbar-inverse-link-color: #9d9d9d; -$navbar-inverse-link-hover-bg: #222222; -$navbar-inverse-toggle-hover-bg: #222222; -$navbar-border-radius: 0; - -//== Tables -$table-bg-accent: #efeff8; // FIXME: expose -$table-bg-hover: darken($table-bg-accent,5%); - -$icon-font-path: "/web/static/lib/bootstrap/fonts/"; +$nav-pills-link-active-color: $white; +$nav-pills-link-active-bg: $o-brand-primary; + +// Navbar + +// FIXME $navbar-height ? $navbar-margin-bottom ? $navbar-inverse-* ? $navbar-border-radius ? + +// Badges + +// FIXME $badge-bg, $badge-color, $badge-line-height ? +$badge-font-weight: normal; + +// Modals + +// Padding applied to the modal body +$modal-inner-padding: $o-horizontal-padding; + +// FIXME $modal-title-padding ? + +$modal-lg: 980px; +$modal-md: 650px; + +// Breadcrumbs + +$breadcrumb-padding-y: 0; +$breadcrumb-padding-x: 0; +$breadcrumb-margin-bottom: 0; + +$breadcrumb-bg: $o-control-panel-background-color; +// FIXME $breadcrumb-color ? +$breadcrumb-active-color: #777777; + +// FIXME $icon-font-path ? diff --git a/addons/web/static/src/scss/bootstrap_overridden_frontend.scss b/addons/web/static/src/scss/bootstrap_overridden_frontend.scss index e69de29bb2d..19ced6c9d8f 100644 --- a/addons/web/static/src/scss/bootstrap_overridden_frontend.scss +++ b/addons/web/static/src/scss/bootstrap_overridden_frontend.scss @@ -0,0 +1,3 @@ + +$black: black; +$white: white; diff --git a/addons/web/static/src/scss/bs_mixins_overrides.scss b/addons/web/static/src/scss/bs_mixins_overrides.scss new file mode 100644 index 00000000000..fd08c94a217 --- /dev/null +++ b/addons/web/static/src/scss/bs_mixins_overrides.scss @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// Bootstrap Mixins and Functions Extensions +// Those will affect the way bootstrap is generated wherever bootstrap is used +//------------------------------------------------------------------------------ + +// Override background utilities so that they come with a default contrasted +// color (especially useful in the frontend editor for example). Also modifies +// the way .text-muted elements are rendered in those environments. +@mixin bg-variant($parent, $color, $text-color: null) { + #{$parent} { + $-yiq-color: if($text-color, $text-color, color-yiq($color)); + background-color: $color !important; + color: $-yiq-color; // not important so that text utilities still work + + .text-muted { + color: rgba($-yiq-color, 0.4) !important; + } + } + a#{$parent}, + button#{$parent} { + $-darken-color: darken($color, 10%); + @include hover-focus { + background-color: $-darken-color !important; + color: if($text-color, $text-color, color-yiq($-darken-color)); + } + } +} +@mixin bg-gradient-variant($parent, $color, $text-color: null) { + #{$parent} { + $-yiq-color: if($text-color, $text-color, color-yiq($color)); + background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x !important; + color: $-yiq-color; + + .text-muted { + color: rgba($-yiq-color, 0.4) !important; + } + } +} diff --git a/addons/web/static/src/scss/control_panel.scss b/addons/web/static/src/scss/control_panel.scss index 13913bdf3d5..b4f7d189f9e 100644 --- a/addons/web/static/src/scss/control_panel.scss +++ b/addons/web/static/src/scss/control_panel.scss @@ -1,14 +1,13 @@ .o_control_panel { - @include o-flex-display; - @include o-flex-flow(row, wrap); + display: flex; + flex-flow: row wrap; border-bottom: 1px solid darken($o-control-panel-background-color, 20%); @include o-webclient-padding($top: 10px, $bottom: 10px); background-color: $o-control-panel-background-color; > .breadcrumb { width: 50%; - margin: 0px; font-size: 18px; > li { @@ -36,8 +35,8 @@ } > .o_cp_left { - @include o-flex-display; - @include o-justify-content(space-between); + display: flex; + justify-content: space-between; width: 50%; margin-top: 5px; @@ -55,10 +54,10 @@ } .o_form_binary_form span { padding: 3px 25px; - color: $btn-default-color; + color: $o-brand-primary; } .o_form_binary_form:hover { - background-color: $table-bg-hover; + background-color: $table-hover-bg; } } .o_sidebar_delete_attachment { @@ -71,7 +70,7 @@ } > .o_cp_right { - @include o-flex-display; + display: flex; width: 50%; margin-top: 5px; @@ -79,11 +78,11 @@ margin: auto 0 auto auto; padding-left: 5px; text-align: center; - @include user-select(none); + user-select: none; > div { - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; } .o_pager_counter { @@ -93,7 +92,7 @@ > .o_cp_switch_buttons > .btn:first-child { margin-left: $o-horizontal-padding; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { margin-left: $o-horizontal-padding - 6; } } @@ -101,11 +100,11 @@ } .o_x2m_control_panel { - @include o-flex-display; - @include o-flex-flow(row, wrap); + display: flex; + flex-flow: row wrap; .o_cp_buttons { - @include o-flex-display; + display: flex; margin-right: auto; > div { margin-top: 5px; @@ -115,7 +114,7 @@ } } .o_cp_pager { - @include o-flex-display; + display: flex; margin-left: auto; } } diff --git a/addons/web/static/src/scss/data_export.scss b/addons/web/static/src/scss/data_export.scss index 17cec27d3a5..c03d13b355b 100644 --- a/addons/web/static/src/scss/data_export.scss +++ b/addons/web/static/src/scss/data_export.scss @@ -1,23 +1,23 @@ .o_web_client .o_export { - @include o-flex(1, 1, auto); - @include o-flex-display; - @include o-flex-flow(column, nowrap); + flex: 1 1 auto; + display: flex; + flex-flow: column nowrap; min-height: 0; > p, > .row { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } .o_export_panel { - @include o-flex(1, 1, auto); + flex: 1 1 auto; position: relative; min-height: 0; > div { height: 100%; - @include o-flex-display; - @include o-flex-flow(column, nowrap); - @include o-justify-content(center); + display: flex; + flex-flow: column nowrap; + justify-content: center; &.o_left_panel { // Needed because of chrome @include o-position-absolute($top: 0, $bottom: 0, $left: 0, $right: 57%); @@ -30,18 +30,18 @@ } > h4, > div { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } > button { - @include o-flex(0, 0, auto); + flex: 0 0 auto; margin-top: 10px; } .o_left_field_panel, .o_fields_list { border: 1px solid $o-brand-lightsecondary; overflow: auto; - @include o-flex(1, 1, auto); + flex: 1 1 auto; min-height: 0; } @@ -49,10 +49,10 @@ cursor: pointer; position: relative; padding-left: 20px; - @include user-select(none); + user-select: none; &.o_selected > .o_tree_column { - background-color: $o-brand-primary; + background-color: $o-brand-odoo; color: white; } @@ -74,16 +74,16 @@ } .o_save_list, .o_exported_lists { - @include o-flex-display; - @include o-align-items(baseline); + display: flex; + align-items: baseline; > label, > button { margin: 0 0 5px; - @include o-flex(0, 0, auto); + flex: 0 0 auto; } > input, > select { width: 0; - @include o-flex(1, 0, auto); + flex: 1 0 auto; } } } diff --git a/addons/web/static/src/scss/datepicker.scss b/addons/web/static/src/scss/datepicker.scss index d8d4ba1d520..c4df0ca2ed2 100644 --- a/addons/web/static/src/scss/datepicker.scss +++ b/addons/web/static/src/scss/datepicker.scss @@ -27,24 +27,29 @@ } } -// Need to put datetimepicker widget above everything else -// The '.dropdown-menu' part is needed to override default bootstrap rule as + +// The 'div.dropdown-menu' part is needed to override default bootstrap rule as // this file is unfortunately placed in common assets. -.bootstrap-datetimepicker-widget.dropdown-menu { +div.dropdown-menu.bootstrap-datetimepicker-widget{ + // Need to put datetimepicker widget above everything else z-index: $zindex-modal + 1; + + // Also fix the dropdown width + width: auto; + min-width: 15rem; } .datepicker { - .table-condensed { + .table-sm { > thead { color: white; - background-color: $o-brand-primary; + background-color: $o-brand-odoo; > tr { &:first-child { th:hover { color: white; - background-color: darken($o-brand-primary, 10%); + background-color: darken($o-brand-odoo, 10%); } } @@ -62,12 +67,12 @@ > tr { > td { &.active, .active { - background-color: $o-brand-optional; + background-color: $o-brand-primary; border-radius: 100px; } &.today:before { - border-bottom-color: $o-brand-optional; + border-bottom-color: $o-brand-primary; } } } diff --git a/addons/web/static/src/scss/domain_selector.scss b/addons/web/static/src/scss/domain_selector.scss index 6755bed49e9..b35934973b9 100644 --- a/addons/web/static/src/scss/domain_selector.scss +++ b/addons/web/static/src/scss/domain_selector.scss @@ -9,12 +9,12 @@ // Rows in a domain node (selector) have a minimum height and holds the control panel .o_domain_selector_row { - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; min-height: $o-domain-selector-row-height; > * { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } > .o_domain_node_control_panel { @@ -35,7 +35,7 @@ padding-left: 5px; &:hover { - color: $brand-danger; + color: theme-color('danger'); } } } @@ -74,7 +74,7 @@ display: block; margin-top: 16px; padding: 8px 10px 12px; - background: $gray-dark; + background: gray('900'); color: rgba(white, 0.5); font-family: monospace; font-weight: normal; @@ -92,7 +92,7 @@ // Rules specific to domain parts which do not contain sub-domain parts &.o_domain_leaf { &.o_read_mode { - @include o-inline-flex-display; + display: inline-flex; margin-right: 4px; } @@ -119,21 +119,21 @@ } > .o_domain_leaf_edition { - @include o-flex-display; + display: flex; width: 100%; padding: 4px ($o-domain-selector-panel-space/2) 4px 0; > * { - @include o-flex(1, 1, 15%); // operator select + flex: 1 1 15%; // operator select width: auto; background-color: white; &:first-child { // field selector - @include o-flex(0, 1, 55%); + flex: 0 1 55%; } &:last-child { // field value - @include o-flex(1, 1, 25%); + flex: 1 1 25%; } + * { @@ -146,13 +146,13 @@ } .o_domain_leaf_value_tags { - @include o-flex-display; + display: flex; > * { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } > input { - @include o-flex(1, 1, auto); + flex: 1 1 auto; width: 0; min-width: 50px; } @@ -164,7 +164,7 @@ } // Animation effects - @include o-transition(margin-bottom, .05s, ease, .05s); + transition: margin-bottom .05s ease .05s; &::after { content: ""; @@ -172,8 +172,8 @@ display: block; height: $o-domain-animation-bar-height; max-height: 0; - @include o-linear-gradient(45deg, rgba($o-brand-optional, 0.4), rgba($o-brand-optional, 0.1)); - @include o-transition(max-height, .05s, ease, .05s); + background-image: linear-gradient(45deg, rgba($o-brand-primary, 0.4), rgba($o-brand-primary, 0.1)); + transition: max-height .05s ease .05s; } &.o_hover_btns, &.o_hover_add_node { @@ -191,11 +191,11 @@ &.o_hover_add_node { margin-bottom: $o-domain-animation-bar-height; - @include o-transition(margin, .15s, ease, .5s); + transition: margin .15s ease .5s; &::after { max-height: $o-domain-animation-bar-height; - @include o-transition(max-height, .15s, ease, .5s); + transition: max-height .15s ease .5s; } &.o_hover_add_inset_node::after { left: $o-domain-selector-indent; diff --git a/addons/web/static/src/scss/dropdown.scss b/addons/web/static/src/scss/dropdown.scss index 7db8b2fcb3c..90deb20083f 100644 --- a/addons/web/static/src/scss/dropdown.scss +++ b/addons/web/static/src/scss/dropdown.scss @@ -5,7 +5,7 @@ .ui-autocomplete { // Copy style of bootstrap dropdown background-image: none; background-color: $dropdown-bg; - border: 1px solid $dropdown-border; + border: $dropdown-border-width solid $dropdown-border-color; font-size: $font-size-base; padding: 5px 0px; box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.176); @@ -21,7 +21,7 @@ &.ui-state-focus { background-image: none; - background-color: $o-brand-primary; + background-color: $o-brand-odoo; border: none; font-weight: normal; margin: 0; @@ -29,7 +29,7 @@ &.o_m2o_dropdown_option { padding-left: 20px; > a { - color: $o-brand-primary; + color: $o-brand-odoo; } } } @@ -41,7 +41,7 @@ .o_inline_dropdown { position: relative; - &> .dropdown-menu { + & > .dropdown-menu { top: 0; left: 100%; } @@ -52,9 +52,12 @@ } @mixin dropdown-menu-mixin { - .open .dropdown-menu > li { - position: relative; // to allow absolute positionning inside the li - > a { + .show .dropdown-menu { + > * { + position: relative; // to allow absolute positionning inside the items + } + + .dropdown-item { &:focus, &:active, &:focus:active { outline: none; } @@ -62,11 +65,11 @@ @extend %dropdown-li-a-padding; } - &.dropdown-header { + .dropdown-header { @extend %dropdown-li-a-padding; color: $o-main-text-color; - @media (max-width: $screen-sm-max) { + @include media-breakpoint-down(md) { color: white; text-decoration: underline; } diff --git a/addons/web/static/src/scss/dropdown_extra.scss b/addons/web/static/src/scss/dropdown_extra.scss index c14144e02d3..ca57d9561f2 100644 --- a/addons/web/static/src/scss/dropdown_extra.scss +++ b/addons/web/static/src/scss/dropdown_extra.scss @@ -1,9 +1,9 @@ .ui-autocomplete .ui-menu-item { &.ui-state-focus { - background-color: $o-brand-primary; + background-color: $o-brand-odoo; } &.o_m2o_dropdown_option > a { - color: $o-brand-primary; + color: $o-brand-odoo; } &.ui-state-focus > a, &.ui-state-focus.o_m2o_dropdown_option > a { @@ -41,7 +41,7 @@ margin: 0; padding: 2px 8px; &:hover { - @include o-vertical-gradient(#f0f0fa, #eeeef6); + background-image: linear-gradient(to bottom, #f0f0fa, #eeeef6); box-shadow: none; } > a { diff --git a/addons/web/static/src/scss/dropdown_menu.scss b/addons/web/static/src/scss/dropdown_menu.scss index 8024783d3c2..8f5b0c1f00a 100644 --- a/addons/web/static/src/scss/dropdown_menu.scss +++ b/addons/web/static/src/scss/dropdown_menu.scss @@ -1,38 +1,23 @@ .o_dropdown_menu { - > li.divider:first-child { + > .dropdown-divider:first-child { display: none; } - max-height: calc(100vh - 125px); + max-height: calc(100vh - 125px); // FIXME overflow: auto; - .o_submenu_switcher { - float:right; - width: 25px; - text-align: center; - } - .o_trash_button { - float:right; - + .o_submenu_switcher { - margin-right: 6px; - } - } - ul { - list-style-type: none; - padding-left: 20px; - } - li.o_menu_item { + .o_menu_item { position: relative; - > a { + > .dropdown-item { color: $o-main-text-color; - padding-right: 25px; + &:hover { color: darken($o-main-text-color, 10%); } } &.selected { - > a { + > .dropdown-item { color: darken($o-main-text-color, 10%); font-weight: bold; &:before { @@ -43,7 +28,7 @@ } } } - li.divider:first-child { + .dropdown-divider:first-child { display: none; } .o_item_option { diff --git a/addons/web/static/src/scss/fields.scss b/addons/web/static/src/scss/fields.scss index 370fdc036b3..cbf0eec7d01 100644 --- a/addons/web/static/src/scss/fields.scss +++ b/addons/web/static/src/scss/fields.scss @@ -6,8 +6,8 @@ // Invalid .o_field_invalid { &.o_input, .o_input, &.o_form_label { - color: $brand-danger!important; - border-color: $brand-danger!important; // enterprise o_required_modifier rule overrides this without !important + color: theme-color('danger')!important; + border-color: theme-color('danger')!important; // enterprise o_required_modifier rule overrides this without !important } } @@ -39,15 +39,15 @@ // Flex fields (inline) &.o_field_many2one, &.o_field_radio, &.o_field_many2manytags, &.o_field_percent_pie, &.o_field_monetary, &.o_field_binary_file { - @include o-inline-flex-display; + display: inline-flex; > span, > button { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } } // Dropdowns input (many2one, ...) .o_input_dropdown { - @include o-flex(1, 1, auto); + flex: 1 1 auto; position: relative; width: 100%; @@ -75,28 +75,28 @@ // Monetary &.o_field_monetary { &.o_input { - @include o-align-items(baseline); + align-items: baseline; > input { width: 100px; - @include o-flex(1, 0, auto); + flex: 1 0 auto; } } } // Many2many tags &.o_field_many2manytags { - @include o-flex-flow(row, wrap); - @include o-align-items(baseline); + flex-flow: row wrap; + align-items: baseline; > .o_field_widget { - @include o-flex(1, 0, 100px); + flex: 1 0 100px; position: initial; max-width: 100%; } > .badge { - @include o-flex(0, 0, auto); + flex: 0 0 auto; border: 0; font-size: 12px; color: white; @@ -119,7 +119,7 @@ display: inline-block; margin: 5px 5px 0 0; // FIXME was $o-kanban-inner-hmargin before scss convertion border: 1px solid white; - box-shadow: 0 0 0 1px $gray-lighter-dark; + box-shadow: 0 0 0 1px gray('300'); > a { display: block; @@ -225,7 +225,7 @@ // Specific success color for toggle_button widget .fa.o_toggle_button_success { - color: $brand-success; + color: theme-color('success'); } // Handle widget @@ -239,21 +239,21 @@ margin: 0px 0px 4px 4px; padding: 1px 6px; color: $o-main-color-muted; - border: 1px solid $o-color-silver-dark; + border: 1px solid gray('300'); cursor: pointer; &.active { - color: $o-brand-optional; - border-color: $o-brand-optional; + color: $o-brand-primary; + border-color: $o-brand-primary; } &:hover:not(.active) { - color: darken($o-color-silver-dark, 30%); - border-color: darken($o-color-silver-dark, 30%); + color: darken(gray('300'), 30%); + border-color: darken(gray('300'), 30%); } } } // Radio buttons &.o_field_radio { - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { display: inline-block; } .o_radio_input { @@ -261,17 +261,7 @@ } .o_radio_item { - @include o-flex(0, 0, auto); - @include o-flex-display; - @include o-align-items(center); - - > input { - @include o-flex(0, 0, auto); - margin: 0 $o-form-spacing-unit 0 0; - } - > label { - margin: 0; - } + flex: 0 0 auto; } &.o_horizontal { @@ -281,7 +271,7 @@ } &.o_vertical { - @include o-flex-flow(column, nowrap); + flex-flow: column nowrap; .o_radio_item { margin-bottom: $o-form-spacing-unit; } @@ -290,7 +280,7 @@ // Percent pie &.o_field_percent_pie { - @include o-align-items(center); + align-items: center; > .o_pie { position: relative; @@ -299,7 +289,7 @@ margin-right: 10px; border-radius: 100%; overflow: hidden; - background-color: $o-brand-optional; + background-color: $o-brand-primary; &:after { // Outside pie border to go over border-radius irregularities content: " "; @@ -311,7 +301,7 @@ .o_mask { @include o-position-absolute(0, 0); - @include o-transform-origin(0); + transform-origin: 0; width: 50%; height: 100%; background-color: $o-view-background-color; @@ -321,14 +311,14 @@ } .o_pie_value { - @include o-flex-display; - @include o-justify-content(center); - @include o-align-items(center); + display: flex; + justify-content: center; + align-items: center; border-radius: 100%; font-weight: 700; - color: $o-brand-primary; + color: $o-brand-odoo; } } } @@ -351,7 +341,7 @@ width: 100%; color: white; - background-color: $o-brand-optional; + background-color: $o-brand-primary; opacity: 0; transition: opacity ease 400ms; @@ -365,7 +355,7 @@ cursor: pointer; } } - @media (max-width: $screen-xs-min) { + @include media-breakpoint-down(xs, $o-extra-grid-breakpoints) { .o_form_image_controls{ position: initial; opacity: 1; @@ -375,10 +365,10 @@ margin: 0px; text-align: center; &.o_select_file_button{ - background: $o-brand-optional; + background: $o-brand-primary; } &.o_clear_file_button{ - background: $brand-danger; + background: theme-color('danger'); } } } @@ -389,7 +379,7 @@ } &.o_field_invalid > img { - border: 1px solid $brand-danger; + border: 1px solid theme-color('danger'); } } @@ -417,9 +407,9 @@ &.o_field_copy { position: relative; border-radius: 5px; - border: 1px solid $btn-primary-border; - font-size: $font-size-small; - color: $o-brand-optional; + border: 1px solid $primary; + font-size: $font-size-sm; + color: $o-brand-primary; font-weight: $badge-font-weight; text-align: center; .o_clipboard_button { diff --git a/addons/web/static/src/scss/fields_extra.scss b/addons/web/static/src/scss/fields_extra.scss index 7e45291305f..47fca992eb5 100644 --- a/addons/web/static/src/scss/fields_extra.scss +++ b/addons/web/static/src/scss/fields_extra.scss @@ -43,7 +43,7 @@ margin-left: 5px; &:after { // Outside pie border to go over border-radius irregularities - border: 1px solid $o-brand-primary; + border: 1px solid $o-brand-odoo; } .o_pie_value { diff --git a/addons/web/static/src/scss/form_view.scss b/addons/web/static/src/scss/form_view.scss index f46de22e9db..730f5b9521b 100644 --- a/addons/web/static/src/scss/form_view.scss +++ b/addons/web/static/src/scss/form_view.scss @@ -16,7 +16,7 @@ } .oe_inline { width: auto!important; - @media (min-width: $screen-xs-min) { + @include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) { &.o_inner_group { width: 1px!important; } @@ -31,19 +31,19 @@ float: right!important; } - @media (min-width: $screen-xs-min) { + @include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) { .o_row { &, &.o_field_widget { // Some field may want to use o_row as root and these rules must prevalue - @include o-flex-display; + display: flex; width: auto!important; } - @include o-align-items(baseline); + align-items: baseline; min-width: 50px; margin: 0 (-$o-form-spacing-unit/2); > div, > span, > button, > label, > a, > input { // > * did not add a level of priority to the rule - @include o-flex(0, 0, auto); + flex: 0 0 auto; width: auto!important; margin-right: $o-form-spacing-unit/2; margin-left: $o-form-spacing-unit/2; @@ -57,7 +57,7 @@ padding-bottom: 0; } > .o_field_boolean { - @include o-align-self(center); + align-self: center; } } } @@ -100,17 +100,17 @@ } .oe_title { - max-width: $container-sm - (2 * $o-horizontal-padding); + max-width: map-get($container-max-widths, md) - (2 * $o-horizontal-padding); } - @media (min-width: $screen-xs-min) { + @include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) { .o_row { > .o_field_widget, > div { - @include o-flex(1, 1, auto); + flex: 1 1 auto; width: 0!important; // 3rd flex argument does not work with input (must be auto and real width 0) &.o_field_boolean, &.o_priority { - @include o-flex(0, 0, auto); + flex: 0 0 auto; width: auto!important; } } @@ -140,25 +140,25 @@ // Statusbar .o_form_statusbar { position: relative; // Needed for the "More" dropdown - @include o-flex-display; - @include o-justify-content(space-between); + display: flex; + justify-content: space-between; padding-left: $o-horizontal-padding; - border-bottom: 1px solid $gray-lighter-darker; + border-bottom: 1px solid gray('400'); background-color: $o-view-background-color; > .o_statusbar_buttons, > .o_statusbar_status { - @include o-flex-display; - @include o-align-items(center); - @include o-align-content(space-around); + display: flex; + align-items: center; + align-content: space-around; } > .o_field_widget { - @include o-align-self(center); + align-self: center; margin-bottom: 0px; } > .o_statusbar_buttons { - @include o-flex-flow(row, wrap); + flex-flow: row wrap; > .btn { $o-statusbar-buttons-vmargin: 4px; @@ -171,9 +171,9 @@ > .o_statusbar_status { margin-left: auto; - @include o-flex-flow(row-reverse, wrap-reverse); - @include o-align-self(stretch); - @include o-align-items(stretch); + flex-flow: row-reverse wrap-reverse; + align-self: stretch; + align-items: stretch; overflow-x: hidden; // to prevent horizontal scroll due to last arrow > .o_arrow_button { @@ -182,17 +182,17 @@ font-weight: bold; position: relative; padding-left: $o-statusbar-arrow-width*2; - color: $gray; + color: gray('700'); border-width: 0 0 0; border-radius: 0; - @include o-transition(all, 0.1s); + transition: all 0.1s ease 0s; &:first-child { padding-right: $o-horizontal-padding; // Compensate container padding } &:last-child { padding-left: $o-horizontal-padding - 1; - border-left: 1px solid $gray-lighter-darker; + border-left: 1px solid gray('400'); } &:active { @@ -203,7 +203,7 @@ opacity: 1.0; color: $text-muted; pointer-events: none; - border-left: 1px solid $gray-lighter-dark; + border-left: 1px solid gray('300'); } &:before, &:after { @@ -215,34 +215,34 @@ border-bottom: ceil($o-statusbar-height/2) solid transparent; border-right: none; border-left: $o-statusbar-arrow-width solid $o-view-background-color; - @include o-transition(border, 0.2s); + transition: border 0.2s ease 0s; -moz-transform: scale(0.9999); // Smooth the triangle on firefox } &:not(.disabled) { &:hover, &:active, &:focus { - color: $o-brand-optional; - background-color: $gray-lighter; + color: $o-brand-primary; + background-color: gray('200'); &:after { - border-left-color: $gray-lighter; + border-left-color: gray('200'); } } } &:before { right: -$o-statusbar-arrow-width; - border-left-color: $gray-lighter-dark; + border-left-color: gray('300'); } &.btn-primary.disabled { - color: $o-brand-primary; + color: $o-brand-odoo; font-size: 11px; - background-color: $gray-lighter; + background-color: gray('200'); cursor: default; &:after { - border-left-color: $gray-lighter; + border-left-color: gray('200'); } } @@ -274,7 +274,7 @@ padding: 5px 0 2px 0; min-width: 100px; - > li > .btn { + .dropdown-item.btn { min-width: 100%; margin-bottom: 3px; } @@ -349,7 +349,7 @@ width: 100%; > .btn { - @include o-flex(0, 0, auto); + flex: 0 0 auto; padding: 0 10px; } } @@ -361,7 +361,7 @@ // Makes extra buttons (e.g. m2o external button) overflow on the // right padding of the parent element .o_input_dropdown { - @include o-flex(1, 0, auto); + flex: 1 0 auto; } } @@ -377,7 +377,7 @@ // Separators .o_horizontal_separator { - font-size: $font-size-h2; + font-size: $h2-font-size; margin: $o-form-spacing-unit 0; &:empty { height: $o-form-spacing-unit * 2; @@ -425,7 +425,7 @@ // Text field with oe_inline class .o_field_text.oe_inline { width: 100%!important; - @media (min-width: $screen-xs-min) { + @include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) { width: 45%!important; } } @@ -463,7 +463,7 @@ .o_field_widget { text-align: right; - @include o-justify-content(flex-end); + justify-content: flex-end; width: 100%; } } @@ -475,7 +475,7 @@ .oe_subtotal_footer_separator { width: 100%; text-align: right; - border-top: 1px solid $gray-lighter-dark; + border-top: 1px solid gray('300'); font-weight: bold; font-size: 1.3em; } @@ -484,7 +484,7 @@ .o_address_format { width: 100%; .o_address_street, .o_address_country { - @include o-flex-display; + display: flex; } .o_address_city { @@ -559,7 +559,7 @@ // Timezone widget warning .o_tz_warning { - color: $brand-danger; + color: theme-color('danger'); cursor: help; position: absolute; margin-left: -40px; @@ -675,11 +675,11 @@ label.o_light_label, .o_light_label label { display: block; > tr { - @include o-flex-display; - @include o-flex-flow(row, wrap); + display: flex; + flex-flow: row wrap; > td { - @include o-flex(1, 0, auto); + flex: 1 0 auto; display: block; max-width: 100%; padding: 0; @@ -718,9 +718,9 @@ label.o_light_label, .o_light_label label { // Settings form views .o_settings_container { - @include o-flex-display; - @include o-flex(0, 1, auto); - @include o-flex-flow(row, wrap); + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; .o_setting_box:visible:nth-child(odd) { clear: left; } diff --git a/addons/web/static/src/scss/form_view_extra.scss b/addons/web/static/src/scss/form_view_extra.scss index 29c2512c1ab..cadce3f6809 100644 --- a/addons/web/static/src/scss/form_view_extra.scss +++ b/addons/web/static/src/scss/form_view_extra.scss @@ -75,7 +75,7 @@ .o_stat_value { @include o-text-overflow(block); font-weight: 700; - color: $o-brand-primary; + color: $o-brand-odoo; } .o_stat_text { @include o-text-overflow(block); @@ -144,7 +144,7 @@ // Separators .o_horizontal_separator { - color: $o-brand-optional; + color: $o-brand-primary; font-weight: bold; } diff --git a/addons/web/static/src/scss/import_bootstrap.scss b/addons/web/static/src/scss/import_bootstrap.scss deleted file mode 100644 index cbd46a7afcf..00000000000 --- a/addons/web/static/src/scss/import_bootstrap.scss +++ /dev/null @@ -1 +0,0 @@ -@import "bootstrap"; diff --git a/addons/web/static/src/scss/import_bootstrap_part1.scss b/addons/web/static/src/scss/import_bootstrap_part1.scss new file mode 100644 index 00000000000..09f4d3579ac --- /dev/null +++ b/addons/web/static/src/scss/import_bootstrap_part1.scss @@ -0,0 +1,11 @@ + +// This file is importing bootstrap. While a simple "import "bootstrap";" +// should be enough, this does not allow overridding mixins. Overridding mixins +// is necessary for some of our need and allow to generate more efficient CSS +// than adding more rules. This file instead copies the first part of the +// content of the "bootstrap.scss" files to allow adding mixin overrides in +// between. + +@import "functions"; +@import "variables"; +@import "mixins"; diff --git a/addons/web/static/src/scss/import_bootstrap_part2.scss b/addons/web/static/src/scss/import_bootstrap_part2.scss new file mode 100644 index 00000000000..c15793019ad --- /dev/null +++ b/addons/web/static/src/scss/import_bootstrap_part2.scss @@ -0,0 +1,40 @@ + +// This file is importing bootstrap. While a simple "import "bootstrap";" +// should be enough, this does not allow overridding mixins. Overridding mixins +// is necessary for some of our need and allow to generate more efficient CSS +// than adding more rules. This file instead copies the second part of the +// content of the "bootstrap.scss" files to allow adding mixin overrides in +// between. + +@import "root"; +@import "reboot"; +@import "type"; +@import "images"; +@import "code"; +@import "grid"; +@import "tables"; +@import "forms"; +@import "buttons"; +@import "transitions"; +@import "dropdown"; +@import "button-group"; +@import "input-group"; +@import "custom-forms"; +@import "nav"; +@import "navbar"; +@import "card"; +@import "breadcrumb"; +@import "pagination"; +@import "badge"; +@import "jumbotron"; +@import "alert"; +@import "progress"; +@import "media"; +@import "list-group"; +@import "close"; +@import "modal"; +@import "tooltip"; +@import "popover"; +@import "carousel"; +@import "utilities"; +@import "print"; diff --git a/addons/web/static/src/scss/kanban_column_progressbar.scss b/addons/web/static/src/scss/kanban_column_progressbar.scss index 2cb35d33a2e..5f16a222736 100644 --- a/addons/web/static/src/scss/kanban_column_progressbar.scss +++ b/addons/web/static/src/scss/kanban_column_progressbar.scss @@ -56,16 +56,16 @@ .o_kanban_counter { position: relative; - @include o-flex-display; - @include o-align-items(center); - @include o-transition(opacity, 0.3s); + display: flex; + align-items: center; + transition: opacity 0.3s ease 0s; margin-bottom: $o-kanban-record-margin*2; > .o_kanban_counter_progress { width: 76%; - height: $font-size-small; + height: $font-size-sm; margin-bottom: 0; - background-color: $gray-lighter-dark; + background-color: gray('300'); box-shadow: none; .progress-bar { @@ -81,7 +81,7 @@ .o_kanban_counter_label { font-size: 10px; - @include user-select(none); + user-select: none; } } @@ -91,14 +91,14 @@ color: $headings-color; text-align: right; white-space: nowrap; - @include o-transform-origin(right, center); + transform-origin: right center; &.o_kanban_grow { - @include o-animation(grow, 1s, ease); + animation: grow 1s ease 0s 1 normal none running; } &.o_kanban_grow_huge { - @include o-animation(grow_huge, 1s, ease); + animation: grow_huge 1s ease 0s 1 normal none running; } // Target currency icon @@ -112,16 +112,16 @@ } .o_kanban_view .o_kanban_group { - @include o-kanban-css-filter(success, $brand-success); - @include o-kanban-css-filter(warning, $brand-warning); - @include o-kanban-css-filter(danger, $brand-danger); + @include o-kanban-css-filter(success, theme-color('success')); + @include o-kanban-css-filter(warning, theme-color('warning')); + @include o-kanban-css-filter(danger, theme-color('danger')); &.o_kanban_group_show { - @include o-flex-display; - @include o-flex-flow(column, nowrap); + display: flex; + flex-flow: column nowrap; > * { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } } } diff --git a/addons/web/static/src/scss/kanban_dashboard.scss b/addons/web/static/src/scss/kanban_dashboard.scss index e6317d4f89e..3330be5bba6 100644 --- a/addons/web/static/src/scss/kanban_dashboard.scss +++ b/addons/web/static/src/scss/kanban_dashboard.scss @@ -1,16 +1,16 @@ .o_kanban_view.o_kanban_dashboard { // correctly display the no_content_helper in dashboards - @include o-flex-flow(row, wrap); + flex-flow: row wrap; .o_kanban_record { position: relative; - @include o-flex-display; - @include o-flex-flow(column, nowrap); - @include o-justify-content(space-between); + display: flex; + flex-flow: column nowrap; + justify-content: space-between; padding: $o-kanban-dashboard-vpadding $o-kanban-dashboard-hpadding; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { margin-bottom: 10px; } @@ -41,7 +41,7 @@ } > .o_kanban_card_manage_section { - border-bottom: 1px solid $gray-lighter-dark; + border-bottom: 1px solid gray('300'); margin-bottom: 10px; > div { @@ -55,9 +55,9 @@ max-width: 400px; .row { - @include o-flex-display; - @include o-flex-flow(row, nowrap); - @include o-justify-content(space-between); + display: flex; + flex-flow: row nowrap; + justify-content: space-between; margin-left: 0; margin-right: 0; padding-left: $o-kanban-dashboard-dropdown-complex-gap*2; @@ -65,14 +65,14 @@ } div[class*="col-"] { - @include o-flex(1, 1, percentage(100/3)); + flex: 1 1 percentage(100/3); padding-left: $o-kanban-dashboard-dropdown-complex-gap; padding-right: $o-kanban-dashboard-dropdown-complex-gap; > .o_kanban_card_manage_title { - margin: ($line-height-computed / 2) 0; + margin: (($font-size-base * $line-height-base) / 2) 0; color: $headings-color; - font-size: $font-size-h5; + font-size: $h5-font-size; font-weight: 500; line-height: $headings-line-height; } @@ -82,7 +82,7 @@ } .row.o_kanban_card_manage_settings { - border-top: 1px solid $gray-lighter-dark; + border-top: 1px solid gray('300'); padding-top: $o-kanban-dashboard-dropdown-complex-gap*3; .oe_kanban_colorpicker { @@ -91,7 +91,7 @@ } div[class*="col-"] + div[class*="col-"] { - border-left: 1px solid $gray-lighter-dark; + border-left: 1px solid gray('300'); } // Default options box @@ -137,7 +137,7 @@ // Identify subtitles without classes .o_kanban_primary_left .o_primary > span:nth-child(2) > strong { font-weight: 500; - font-size: $font-size-small; + font-size: $font-size-sm; color: $text-muted; } @@ -154,10 +154,10 @@ } .o_kanban_card_header + .container.o_kanban_card_content { - @include o-flex(1, 0, auto); - @include o-flex-display; - @include o-flex-flow(column, nowrap); - @include o-justify-content(space-between); + flex: 1 0 auto; + display: flex; + flex-flow: column nowrap; + justify-content: space-between; margin-top: $o-kanban-dashboard-vpadding * 2; padding-right: 0; padding-left: 0; @@ -176,8 +176,8 @@ margin-bottom: -$o-kanban-dashboard-vpadding; &.bottom_block { - border-top: 1px solid $gray-lighter-dark; - background-color: $gray-lighter; + border-top: 1px solid gray('300'); + background-color: gray('200'); padding-top: $o-kanban-dashboard-vpadding; padding-bottom: $o-kanban-dashboard-vpadding; } diff --git a/addons/web/static/src/scss/kanban_examples_dialog.scss b/addons/web/static/src/scss/kanban_examples_dialog.scss index a42962ed8f0..65eadc9e0b4 100644 --- a/addons/web/static/src/scss/kanban_examples_dialog.scss +++ b/addons/web/static/src/scss/kanban_examples_dialog.scss @@ -1,17 +1,17 @@ .o_kanban_examples_dialog { - @include o-flex-display; + display: flex; padding: 0px; - background: $o-color-silver; + background: theme-color('light'); // sidebar .o_kanban_examples_dialog_nav { - @include o-flex(0, 0, auto); - border-right: 1px solid $gray-lighter-dark; + flex: 0 0 auto; + border-right: 1px solid gray('300'); background: white; > ul > li { margin: 0; - border-bottom: 1px solid $gray-lighter-dark; + border-bottom: 1px solid gray('300'); > a { padding: 12px 15px; @@ -23,7 +23,7 @@ } &.active > a { color: $headings-color; - border-left-color: $o-brand-optional; + border-left-color: $o-brand-primary; font-weight: bold; } } @@ -31,28 +31,28 @@ // content .o_kanban_examples_dialog_content { - @include o-flex(1, 1, 100%); + flex: 1 1 100%; .o_kanban_examples_description { padding: 16px 16px 0; text-align: justify; } .o_kanban_examples { - @include o-flex-display; + display: flex; padding: 0 6px; .o_kanban_examples_group { - @include o-flex(1, 1, 100%); + flex: 1 1 100%; margin: 10px; .o_kanban_examples_ghost { padding: 5px; margin-top: -1px; - border: thin solid $gray-lighter-dark; + border: thin solid gray('300'); background-color: white; .o_ghost_content { height: 12px; - background: $gray-lighter-dark; + background: gray('300'); &.o_ghost_tag { display: inline-block; width: 40%; diff --git a/addons/web/static/src/scss/kanban_view.scss b/addons/web/static/src/scss/kanban_view.scss index 4d00f1be3cf..c00e5ab0d26 100644 --- a/addons/web/static/src/scss/kanban_view.scss +++ b/addons/web/static/src/scss/kanban_view.scss @@ -1,27 +1,27 @@ // ------- Kanban View Layout ------- .o_kanban_view { - @include o-flex-display; - @include o-align-content(stretch); + display: flex; + align-content: stretch; overflow-x: visible; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { padding: 0px!important; overflow-x: auto; } .o_kanban_record, .o_kanban_quick_create { padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter; - border: 1px solid $gray-lighter-dark; + border: 1px solid gray('300'); background-color: white; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter-mobile; } &:focus, &:focus-within { - -webkit-box-shadow: 1px 1px 1px 0px $gray-light; - -moz-box-shadow: 1px 1px 1px 0px $gray-light; - box-shadow: 1px 1px 1px 0px $gray-light; + -webkit-box-shadow: 1px 1px 1px 0px gray('600'); + -moz-box-shadow: 1px 1px 1px 0px gray('600'); + box-shadow: 1px 1px 1px 0px gray('600'); z-index: 1; // show the shadow on top of the previous & next cards in grouped mode outline: none; } @@ -43,7 +43,7 @@ .o_kanban_record { position: relative; display: inline-block; // Force the creation of a block formatting context to clear float items - border-color: $gray-lighter-darker; + border-color: gray('400'); min-width: 150px; margin: 0 0 -1px; @@ -61,11 +61,11 @@ } .o_kanban_record_top, .o_kanban_record_bottom { - @include o-flex-display; + display: flex; } .o_kanban_record_top { - @include o-align-items(flex-start); + align-items: flex-start; .o_dropdown_kanban { // For v11 layout, reset positioning to default to properly use @@ -77,7 +77,7 @@ .o_kanban_record_headings { line-height: 1.2; - @include o-flex(1, 1, auto); + flex: 1 1 auto; // Ensure long word doesn't break out of container word-wrap: break-word; overflow: hidden; @@ -95,12 +95,12 @@ .o_kanban_record_bottom { .oe_kanban_bottom_left, .oe_kanban_bottom_right { - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; height: 20px; } .oe_kanban_bottom_left { - @include o-flex(1, 1, auto); + flex: 1 1 auto; > * { margin-right: 6px; @@ -113,7 +113,7 @@ } } .oe_kanban_bottom_right{ - @include o-flex(0, 1, auto); + flex: 0 1 auto; .oe_kanban_avatar { width: 20px; @@ -122,9 +122,9 @@ } } .o_link_muted { - color: $text-color; + color: $body-color; &:hover { - color: $brand-primary; + color: theme-color('primary'); text-decoration: underline; } } @@ -142,7 +142,7 @@ .o_dropdown_kanban { @include o-position-absolute($o-kanban-inside-vgutter, $o-kanban-inside-hgutter); visibility: hidden; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { visibility: visible; } @@ -150,7 +150,7 @@ @include o-kanban-dropdown; margin: (-$o-kanban-inside-vgutter - 1px) (-$o-kanban-inside-hgutter - 1px) 0 0; } - &.open .dropdown-toggle { + &.show .dropdown-toggle { @include o-kanban-dropdown-open; } .dropdown-menu { @@ -159,7 +159,7 @@ } } - &:hover .o_dropdown_kanban, .o_dropdown_kanban.open { + &:hover .o_dropdown_kanban, .o_dropdown_kanban.show { visibility: visible; } @@ -207,7 +207,7 @@ > button, > a { @include o-position-absolute($right: $o-kanban-record-margin, $bottom: $o-kanban-record-margin); - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { right: $o-kanban-inside-hgutter-mobile; } } @@ -219,9 +219,9 @@ } &.ui-sortable-helper { - @include o-transform(rotate(-3deg)); + transform: rotate(-3deg); box-shadow: 0 5px 25px -10px black; - @include transition(transform 0.6s, box-shadow 0.3s); + transition: transform 0.6s, box-shadow 0.3s; } .o_attachment_image > img { @@ -230,18 +230,18 @@ } .o_progressbar { - @include o-flex-display; + display: flex; height: $o-kanban-progressbar-height; .o_progressbar_title { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } .o_progress { - @include o-flex(1, 1, auto); + flex: 1 1 auto; margin-top: 3px; } .o_progressbar_value { - @include o-flex(0, 0, auto); + flex: 0 0 auto; width: auto; height: 100%; text-align: right; @@ -258,7 +258,7 @@ + div { padding-left: $o-kanban-image-width + $o-kanban-inside-hgutter; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { padding-left: $o-kanban-image-width + $o-kanban-inside-hgutter-mobile; } } @@ -270,7 +270,7 @@ margin-bottom: $o-kanban-inner-hmargin*0.5;; padding-left: 0; list-style: none; - font-size: $font-size-small; + font-size: $font-size-sm; li { margin-bottom: 2px; @@ -279,11 +279,11 @@ } .o_kanban_footer { - @include o-flex-display; - @include o-justify-content(space-between); - @include o-align-items(center); + display: flex; + justify-content: space-between; + align-items: center; > * { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } } @@ -305,7 +305,7 @@ &.o_kanban_grouped { min-height: 100%; padding: 0; - background-color: $gray-lighter; + background-color: theme-color('light'); .o_kanban_record, .o_kanban_quick_create { width: 100%; @@ -320,14 +320,14 @@ // Kanban Grouped Layout - Column default .o_kanban_group { - @include o-flex(0, 0, auto); + flex: 0 0 auto; padding: 0 $o-kanban-group-padding $o-kanban-group-padding $o-kanban-group-padding; .o_kanban_header > .o_kanban_header_title { @include o-kanban-header-title; .o_column_title { - @include o-flex(1, 1, auto); + flex: 1 1 auto; @include o-text-overflow; font-size: 16px; font-weight: 500; @@ -342,7 +342,7 @@ margin-left: $o-kanban-inside-hgutter*2; } - &:hover .o_kanban_config, .o_kanban_config.open { + &:hover .o_kanban_config, .o_kanban_config.show { visibility: visible; margin-left: $o-kanban-inside-hgutter; } @@ -430,7 +430,7 @@ .o_kanban_add_column { display: inline-block; padding: 10px 14px; - background-color: $o-color-silver-dark; + background-color: gray('300'); } .o_kanban_title { margin-left: 10px; @@ -443,7 +443,7 @@ height: 100%; border: none; box-shadow: 0 0 20px -10px; - background-color: $gray-lighter; + background-color: theme-color('light'); .o_kanban_header { height: 50px; @@ -453,18 +453,13 @@ } input, input:focus, input:hover { - margin-top: 3px; font-size: 16px; background: transparent; } - - .o_kanban_add { - margin-left: 10px; - } } .o_kanban_muted_record { - background: $gray-lighter-dark; + background: gray('300'); height: 70px; margin: 10px 0px; } @@ -474,19 +469,19 @@ // Kanban UN-grouped Layout &.o_kanban_ungrouped { - @include o-flex-flow(row, wrap); - @include o-justify-content(flex-start); + flex-flow: row wrap; + justify-content: flex-start; padding: $o-kanban-record-margin ($o-horizontal-padding - $o-kanban-record-margin); .o_kanban_record { - @include o-flex(1, 1, auto); + flex: 1 1 auto; width: $o-kanban-default-record-width; margin: ($o-kanban-record-margin * 0.5) $o-kanban-record-margin; - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { margin: 0 0 -1px 0; - @include o-flex(1, 0, 100%); + flex: 1 0 100%; } &.o_kanban_ghost { diff --git a/addons/web/static/src/scss/kanban_view_mobile.scss b/addons/web/static/src/scss/kanban_view_mobile.scss index ed4e6ad8436..b74ae8aaea5 100644 --- a/addons/web/static/src/scss/kanban_view_mobile.scss +++ b/addons/web/static/src/scss/kanban_view_mobile.scss @@ -1,4 +1,4 @@ -@media (max-width: $screen-xs-max) { +@include media-breakpoint-down(sm) { .o_kanban_view.o_kanban_grouped { display: block; position: relative; @@ -11,7 +11,7 @@ .o_kanban_mobile_tab { @include o-position-absolute($left: 100%); - @include o-transform(translateX(-50%)); + transform: translateX(-50%); height: $o-kanban-mobile-tabs-height; padding: 10px; font-size: 14px; @@ -19,7 +19,7 @@ &.o_current { font-weight: bold; - border-bottom: 3px solid $o-brand-optional; + border-bottom: 3px solid $o-brand-primary; } .o_column_title { white-space: nowrap; diff --git a/addons/web/static/src/scss/layout_background.scss b/addons/web/static/src/scss/layout_background.scss index e23b2585b50..400ba12789b 100644 --- a/addons/web/static/src/scss/layout_background.scss +++ b/addons/web/static/src/scss/layout_background.scss @@ -1,9 +1,9 @@ .o_background_footer, .o_background_header, .o_report_layout_background { font-family: 'Lato'; - color: $gray; + color: gray('700'); } .o_background_header { - border-bottom: 1px solid $gray-lighter; + border-bottom: 1px solid gray('200'); .company_address { min-width: 300px; } @@ -13,19 +13,19 @@ margin-right: 16px; } h3 { - color: $o-brand-primary; + color: $o-brand-odoo; font-weight: 700; max-width: 300px; } } .o_background_footer { ul { - border-top: 1px solid $o-brand-primary; - border-bottom: 1px solid $o-brand-primary; + border-top: 1px solid $o-brand-odoo; + border-bottom: 1px solid $o-brand-odoo; padding: 4px 0; margin: 0 0 4px 0; li { - color: $o-brand-primary; + color: $o-brand-odoo; } } } @@ -36,10 +36,10 @@ background-repeat: no-repeat; min-height: 900px; thead tr th, h2 { - color: $o-brand-primary; + color: $o-brand-odoo; } tbody { - color: $gray; + color: gray('700'); tr:nth-child(odd) { background-color: rgba(184, 171, 180, 0.2); } @@ -48,7 +48,7 @@ } } /*Total table*/ - .row > .col-xs-4 > table { + .row > .col-4 > table { tr:nth-child(odd) { background-color: transparent !important; } @@ -57,7 +57,7 @@ border-top: none !important; } tr:last-child td { - color: $o-brand-primary; + color: $o-brand-odoo; } } #total { diff --git a/addons/web/static/src/scss/layout_boxed.scss b/addons/web/static/src/scss/layout_boxed.scss index 92208945f45..426b3dd2aac 100644 --- a/addons/web/static/src/scss/layout_boxed.scss +++ b/addons/web/static/src/scss/layout_boxed.scss @@ -1,10 +1,10 @@ .o_boxed_footer, .o_boxed_header, .o_report_layout_boxed { font-family: 'Lato'; - color: $gray; + color: gray('700'); font-size: 12px; } .o_boxed_header { - border-bottom: 1px solid $gray-lighter; + border-bottom: 1px solid gray('200'); img { max-height: 100px; } @@ -17,7 +17,7 @@ .o_boxed_footer { margin-top: 200px; white-space: nowrap; - border-top: 3px solid $gray; + border-top: 3px solid gray('700'); ul { margin: 4px 0; } @@ -26,7 +26,7 @@ // This is not a general rule since the id is not used in all the reports, // we should make a general structure for report body to use it everywhere #informations { - border: 1px solid $gray; + border: 1px solid gray('700'); padding-top: 10px; margin: 0; } @@ -34,28 +34,28 @@ text-transform: uppercase; } table { - border: 1px solid $gray; + border: 1px solid gray('700'); thead { tr th { - border-bottom: 3px solid $gray !important; + border-bottom: 3px solid gray('700') !important; text-transform: uppercase; } } tbody { - color: $gray; + color: gray('700'); tr { td { border-top: none; - border-right: 1px solid $gray; + border-right: 1px solid gray('700'); } td:last-child { - background-color: $gray-lighter; + background-color: gray('200'); } } } } /*Total table*/ - .row > .col-xs-4 > table { + .row > .col-4 > table { td { border-right: none; } @@ -67,7 +67,7 @@ background-color: transparent; } tr:last-child td { - background-color: $gray; + background-color: gray('700'); color: #fff; } } diff --git a/addons/web/static/src/scss/layout_clean.scss b/addons/web/static/src/scss/layout_clean.scss index 64ec2fd5245..06b2e808dd4 100644 --- a/addons/web/static/src/scss/layout_clean.scss +++ b/addons/web/static/src/scss/layout_clean.scss @@ -12,16 +12,16 @@ .o_clean_footer { margin: 0 3px; margin-top: 200px; - border-top: 3px solid $o-brand-primary; + border-top: 3px solid $o-brand-odoo; h4 { - color: $o-brand-primary; + color: $o-brand-odoo; font-weight: bolder; } .pagenumber { width: 35px; height: 35px; - border: 3px solid $o-brand-primary; - background-color: $o-brand-optional; + border: 3px solid $o-brand-odoo; + background-color: $o-brand-primary; color: white; padding-top: 6px; text-align: center; @@ -29,17 +29,17 @@ } .o_report_layout_clean { h1, h2, h3 { - color: $o-brand-optional; + color: $o-brand-primary; font-weight: bolder; } strong { - color: $o-brand-primary; + color: $o-brand-odoo; } table { thead { - color: $o-brand-primary; + color: $o-brand-odoo; tr th { - border-top: 3px solid $o-brand-primary !important; + border-top: 3px solid $o-brand-odoo !important; text-transform: uppercase; } tr th:last-child { @@ -54,7 +54,7 @@ border-top: none; } tr:last-child td { - border-bottom: 3px solid $o-brand-primary; + border-bottom: 3px solid $o-brand-odoo; } tr { td { @@ -66,13 +66,13 @@ } } /*Total table*/ - .row > .col-xs-4 { + .row > .col-4 { width: 43%; position: relative; top: -20px; > table { tr:last-child td { - border-top: 1px solid $gray-lighter !important; + border-top: 1px solid gray('200') !important; } tr:first-child td { /*we could get rid of this rule if .border-black td would be terminated in report.scss*/ diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss index 27c10cda556..ba5cd8a4dab 100644 --- a/addons/web/static/src/scss/list_view.scss +++ b/addons/web/static/src/scss/list_view.scss @@ -5,10 +5,15 @@ background-color: $o-view-background-color; margin-bottom: 0px; + // Don't understand why but without those, the list view appears broken + // in both form views and standalone list views. + border-collapse: initial; + border-spacing: 0; + // Checkbox in editable list // should be clickable and activate the row &.o_editable_list .o_data_row:not(.o_selected_row) .o_data_cell { - .o_checkbox:not(.o_readonly_modifier) { + .custom-checkbox:not(.o_readonly_modifier) { pointer-events: none; } } @@ -41,7 +46,7 @@ .o_column_sortable { position: relative; - @include user-select(none); // Prevent unwanted selection while sorting + user-select: none; // Prevent unwanted selection while sorting &::after { font-family: FontAwesome; @@ -96,11 +101,12 @@ } .o_group_pager { cursor: text; - @include user-select(none); + user-select: none; text-align: right; - padding-top: 0; - padding-bottom: 0; + padding-top: 0 !important; + padding-bottom: 0 !important; .o_pager_previous, .o_pager_next { + max-height: 30px; background-color: $o-list-group-header-color; &:hover { background-color: darken($o-list-group-header-color, 10%); @@ -182,7 +188,7 @@ width: 16px; // to have some space on the right } .o_input { - padding: $table-condensed-cell-padding; + padding: $table-cell-padding-sm; background-color: white; .o_input { diff --git a/addons/web/static/src/scss/list_view_extra.scss b/addons/web/static/src/scss/list_view_extra.scss index ec53efc6df5..83791ce42dd 100644 --- a/addons/web/static/src/scss/list_view_extra.scss +++ b/addons/web/static/src/scss/list_view_extra.scss @@ -5,6 +5,6 @@ } tbody > tr.o_group_header { - @include o-vertical-gradient(#fcfcfc, #dedede); + background-image: linear-gradient(to bottom, #fcfcfc, #dedede); } } diff --git a/addons/web/static/src/scss/modal.scss b/addons/web/static/src/scss/modal.scss index 82faabfa3bc..5dc3c1eb7d0 100644 --- a/addons/web/static/src/scss/modal.scss +++ b/addons/web/static/src/scss/modal.scss @@ -31,7 +31,7 @@ } - @media (min-width: $screen-sm-min) { + @include media-breakpoint-up(md) { .modal-dialog { height: 100%; padding: 30px 0; @@ -39,11 +39,11 @@ .modal-content { max-height: 100%; - @include o-flex-display; - @include o-flex-flow(column, nowrap); + display: flex; + flex-flow: column nowrap; .modal-header, .modal-footer { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } .modal-body { @@ -54,15 +54,15 @@ &.o_dialog_error { overflow: visible; - @include o-flex-display; - @include o-flex-flow(column, nowrap); + display: flex; + flex-flow: column nowrap; > .alert, > button { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } > .o_error_detail { - @include o-flex(1, 1, auto); + flex: 1 1 auto; min-height: 0; overflow: auto; } diff --git a/addons/web/static/src/scss/model_field_selector.scss b/addons/web/static/src/scss/model_field_selector.scss index 0eec3e60049..1acd3b0cc90 100644 --- a/addons/web/static/src/scss/model_field_selector.scss +++ b/addons/web/static/src/scss/model_field_selector.scss @@ -3,9 +3,9 @@ position: relative; > .o_field_selector_value { - @include o-flex-display; - @include o-flex-flow(row, wrap); - @include o-align-items(center); + display: flex; + flex-flow: row wrap; + align-items: center; height: 100%; min-height: 20px; // needed when there is no value in it and used standalone &:active, &:focus, &:active:focus { @@ -19,15 +19,15 @@ margin-bottom: 1px; } > i { - @include o-align-self(center); + align-self: center; margin: 0 2px; font-size: 10px; } } > .o_field_selector_controls { @include o-position-absolute(0, 0, 1px); - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; cursor: pointer; } @@ -51,7 +51,7 @@ .o_field_selector_popover_header { color: white; - background: $brand-primary; + background: theme-color('primary'); font-weight: bold; padding: 5px 0 5px 0.4em; @@ -67,14 +67,14 @@ &.o_prev_page { left: 0; - border-right: 1px solid darken($brand-primary, 10%); + border-right: 1px solid darken(theme-color('primary'), 10%); } &.o_field_selector_close { right: 0; - border-left: 1px solid darken($brand-primary, 10%); + border-left: 1px solid darken(theme-color('primary'), 10%); } &:hover { - background: darken($brand-primary, 10%); + background: darken(theme-color('primary'), 10%); } } &:before { @@ -82,7 +82,7 @@ content: ""; border-left: $o-field-selector-arrow-height solid rgba(0, 0, 0, 0); border-right: $o-field-selector-arrow-height solid rgba(0, 0, 0, 0); - border-bottom: $o-field-selector-arrow-height solid $brand-primary; + border-bottom: $o-field-selector-arrow-height solid theme-color('primary'); } } .o_field_selector_popover_body { @@ -110,15 +110,15 @@ } .o_field_selector_relation_icon { @include o-position-absolute($top: 0, $right: 0, $bottom: 0); - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; padding: 10px; } } } } .o_field_selector_popover_footer { - background: $brand-primary; + background: theme-color('primary'); padding: 5px 0.4em; > input { diff --git a/addons/web/static/src/scss/navbar.scss b/addons/web/static/src/scss/navbar.scss index 770532d6693..aa1a2c23067 100644 --- a/addons/web/static/src/scss/navbar.scss +++ b/addons/web/static/src/scss/navbar.scss @@ -3,7 +3,7 @@ position: relative; height: $o-navbar-height; border-bottom: 1px solid $o-navbar-inverse-link-hover-bg; - background-color: $o-brand-primary; + background-color: $o-brand-odoo; color: white; > a, > button { @@ -17,7 +17,7 @@ color: inherit; font-size: 18px; - @include user-select(none); + user-select: none; &:hover, &:focus { background-color: $o-navbar-inverse-link-hover-bg; @@ -32,13 +32,13 @@ display: block; float: left; margin-right: 35px; - @include user-select(none); + user-select: none; color: white; font-size: 22px; font-weight: 500; line-height: $o-navbar-height; - @media (max-width: $screen-sm-max) { + @include media-breakpoint-down(md) { float: none; margin: 0; border-bottom: 1px solid $o-navbar-inverse-link-hover-bg; @@ -86,21 +86,21 @@ width: $o-navbar-height; text-align: center; } - &.open > ul { + &.show > ul { padding: 0; > li { > a { - background-color: $o-brand-primary; + background-color: $o-brand-odoo; color: white; border-bottom: 1px solid $o-brand-lightsecondary; &.dropdown-toggle { - background-color: lighten($o-brand-primary, 15%); + background-color: lighten($o-brand-odoo, 15%); pointer-events: none; // hack to prevent clicking on it because dropdown always opened } } - > ul { // remove dropdown-menu default style as it is nested in another one + > .dropdown-menu { // remove dropdown-menu default style as it is nested in another one position: static; float: none; display: block; @@ -115,27 +115,23 @@ &.o_menu_systray { float: right; - .open .dropdown-menu { - left: auto; - right: 0; - } } } - .open .dropdown-menu { + .dropdown-menu.show { max-height: 90vh; // the dropdown should not overstep the viewport min-width: 100%; overflow: auto; margin-top: 0; @for $index from 3 through 5 { - > li.o_menu_header_lvl_#{$index}, > li .o_menu_entry_lvl_#{$index} { + .o_menu_header_lvl_#{$index}, .o_menu_entry_lvl_#{$index} { padding-left: $o-dropdown-hpadding + ($index - 2)*12px; } } } - .open .dropdown-toggle { + .show .dropdown-toggle { background-color: $o-navbar-inverse-link-hover-bg; } .o_user_menu { @@ -147,12 +143,12 @@ .oe_topbar_avatar { height: 17px; - @include o-transform(translateY(-2px)); + transform: translateY(-2px); } } - @media (max-width: $screen-sm-max) { - @include o-transition(height, 200ms, linear); + @include media-breakpoint-down(md) { + transition: height 200ms linear 0s; position: relative; height: $o-navbar-height; @@ -165,7 +161,7 @@ display: none; } - &.open .dropdown-menu { + .dropdown-menu.show { max-height: none; } } @@ -173,7 +169,7 @@ &.o_menu_sections { width: 100%; - > li.open .dropdown-menu { + .dropdown-menu.show { position: static; float: none; background-color: transparent; @@ -181,7 +177,7 @@ border: none; overflow: visible; - > li > a { + > .dropdown-item { background-color: transparent; color: inherit; } @@ -196,7 +192,7 @@ > li { display: inline-block; - &.open .dropdown-menu { + .dropdown-menu.show { @include o-position-absolute($o-navbar-height, 0, 0, 0); position: fixed; width: auto; @@ -211,7 +207,7 @@ } } -@media (max-width: $screen-sm-max) { +@include media-breakpoint-down(md) { body.o_mobile_menu_opened { overflow: hidden; height: 100%; @@ -224,11 +220,11 @@ } } -@media (max-width: $screen-sm-max) { - .o_switch_company_menu > .dropdown-menu { - padding-top: 0px; - li.bg-info { - padding: 10px; - } - } - } +@include media-breakpoint-down(md) { + .o_switch_company_menu > .dropdown-menu { + padding-top: 0px; + .bg-info { + padding: 10px; + } + } +} diff --git a/addons/web/static/src/scss/pivot_view.scss b/addons/web/static/src/scss/pivot_view.scss index 3efddd8eab2..d10c4997f43 100644 --- a/addons/web/static/src/scss/pivot_view.scss +++ b/addons/web/static/src/scss/pivot_view.scss @@ -5,7 +5,7 @@ // items corresponding to the clicked cell &.o_enable_linking { .o_pivot_cell_value:hover { - color: $o-brand-optional; + color: $o-brand-primary; cursor: pointer; } } @@ -23,7 +23,7 @@ background-color: lighten($o-brand-secondary, 40%); cursor: pointer; white-space: nowrap; - @include user-select(none); + user-select: none; &:hover { background-color: lighten($o-brand-secondary, 30%); } diff --git a/addons/web/static/src/scss/primary_variables.scss b/addons/web/static/src/scss/primary_variables.scss index b394aeafe26..0f7f43411c4 100644 --- a/addons/web/static/src/scss/primary_variables.scss +++ b/addons/web/static/src/scss/primary_variables.scss @@ -4,20 +4,21 @@ /// // Font sizes -$o-font-size-base: 13px; -$o-line-height-base: 1.428571429; // This is BS default +$o-root-font-size: 13px; +$o-font-size-base: 1rem; +$o-line-height-base: 1.5; // This is BS default // Colors -$o-brand-primary: #7c7bad; -$o-brand-optional: #7c7bad; +$o-community-color: #7C7BAD; +$o-enterprise-color: #875A7B; + +$o-brand-odoo: $o-community-color; +$o-brand-primary: $o-community-color; + $o-brand-secondary: #f0eeee; $o-brand-lightsecondary: #e2e2e0; -$o-color-silver: #F9F9F9; -$o-color-silver-dark: #E5E5E5; -$o-color-silver-darker: #d9d7d7; -$o-color-gray-light: lighten(#000, 46.7%); // This is BS default +$o-gray-100: #f8f9fa; // This is BS default -$o-color-pink: #875A7B; // Enterprise $o-brand-primary $o-main-color-muted: #a8a8a8; $o-main-text-color: #4c4c4c; @@ -36,8 +37,21 @@ $o-tooltip-text-color: #777777; $o-tooltip-title-text-color: #4c4c4c; // Layout -$screen-xs-min: 475px; -$screen-xl-min: 1534px; +// +// Extension of BS4. This is not redefining the BS4 variable directly as we only +// need the extra ones for media queries (not creating new breakpoint classes). +// Note: default BS4 values are hardcoded here while it should be possible to +// merge with the default BS variable (but we would have to take care of +// ordering & cie). +$o-extra-grid-breakpoints: ( + xs: 0, + vsm: 475px, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1534px, +); $o-form-group-cols: 12; $o-form-spacing-unit: 5px; diff --git a/addons/web/static/src/scss/progress_bar.scss b/addons/web/static/src/scss/progress_bar.scss index 8aaade8812f..71af77082f6 100644 --- a/addons/web/static/src/scss/progress_bar.scss +++ b/addons/web/static/src/scss/progress_bar.scss @@ -23,7 +23,7 @@ } .o_progressbar_complete { - background-color: $o-brand-optional; + background-color: $o-brand-primary; height: 100%; } } diff --git a/addons/web/static/src/scss/rainbow.scss b/addons/web/static/src/scss/rainbow.scss index 8a705242adc..fa666fca246 100644 --- a/addons/web/static/src/scss/rainbow.scss +++ b/addons/web/static/src/scss/rainbow.scss @@ -10,31 +10,31 @@ z-index: $zindex-modal; padding: 50px; margin: -5% auto 0 (-$reward-size / 2); - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { margin: -5% auto 0 (-$reward-size-mobile / 2); } background-image: -webkit-radial-gradient(#EDEFF4 30%, transparent 70%, transparent); background-image: -o-radial-gradient(#EDEFF4 30%, transparent 70%, transparent); background-image: radial-gradient(#EDEFF4 30%, transparent 70%, transparent); - @include o-animation(reward-fading, $reward-base-time * 0.5, ease-in-out, 0s, 1, normal, forwards); + animation: reward-fading ($reward-base-time * 0.5) ease-in-out 0s 1 normal forwards; @include o-position-absolute(20%, auto, auto, 50%); @include size($reward-size, $reward-size); - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { @include size($reward-size-mobile, $reward-size-mobile); } &.o_reward_fading { display: block; - @include o-animation(reward-fading-reverse, ($reward-base-time * 0.4), ease-in-out, 0s, 1, normal, forwards); + animation: reward-fading-reverse ($reward-base-time * 0.4) ease-in-out 0s 1 normal forwards; .o_reward_face_group { - @include o-animation(reward-jump-reverse, ($reward-base-time * 0.4), ease-in-out, 0s, 1, normal, forwards); + animation: reward-jump-reverse ($reward-base-time * 0.4) ease-in-out 0s 1 normal forwards; } .o_reward_rainbow { path { - @include o-animation(reward-rainbow-reverse, ($reward-base-time * 0.5), ease-out, 0s, 1, normal, forwards); + animation: reward-rainbow-reverse ($reward-base-time * 0.5) ease-out 0s 1 normal forwards; } } @@ -51,13 +51,13 @@ fill: none; stroke-linecap: round; stroke-width: 21px; - @include o-animation(reward-rainbow, ($reward-base-time ), ease-out, 0s, 1, normal, forwards); + animation: reward-rainbow $reward-base-time ease-out 0s 1 normal forwards; } } .o_reward_face_group { transform-origin: center; - @include o-animation(reward-jump, $reward-base-time * 0.8, ease-in-out); + animation: reward-jump $reward-base-time * 0.8 ease-in-out 0s 1 normal none running; @include o-position-absolute(6%, 0, 0, 0); @include size(100%, 60%); } @@ -68,14 +68,14 @@ position: relative; border-radius: 100%; background: center center / contain no-repeat; - @include o-animation(reward-float, $reward-base-time, ease-in-out, $reward-base-time, infinite, alternate); + animation: reward-float $reward-base-time ease-in-out $reward-base-time infinite alternate; @include size(34%, 56.67%); } .o_reward_stars { display: block; @include size($reward-size * 0.75, $reward-size / 2); - @media (max-width: $screen-xs-max) { + @include media-breakpoint-down(sm) { @include size($reward-size-mobile * 0.75, $reward-size-mobile / 2); } @include o-position-absolute(18%, 7%); @@ -83,10 +83,10 @@ svg { transform-origin: center center; @include o-position-absolute(28%, $left:3%); - @include o-animation(reward-stars, $reward-base-time, ease-in-out, 0s, infinite, alternate-reverse); + animation: reward-stars $reward-base-time ease-in-out 0s infinite alternate-reverse; &.star2, &.star4 { - @include o-animation(reward-stars, ($reward-base-time*1.2), ease-in-out, 0s, infinite, alternate); + animation: reward-stars ($reward-base-time*1.2) ease-in-out 0s infinite alternate; } &.star2 { @@ -110,7 +110,7 @@ .o_reward_thumbup { width: 40px; display: block; - @include o-animation(reward-scale, $reward-base-time * 0.5, ease-in-out, 0s, infinite, alternate); + animation: reward-scale ($reward-base-time * 0.5) ease-in-out 0s infinite alternate; @include o-position-absolute(63%, auto, auto, 65%); } @@ -121,9 +121,9 @@ margin-left: 15%; // Translate before animate - @include o-transform(translateY(5px)); + transform: translateY(5px); - @include o-animation(reward-float, $reward-base-time, ease-in-out, $reward-base-time, infinite, alternate-reverse); + animation: reward-float $reward-base-time ease-in-out $reward-base-time infinite alternate-reverse; @include o-position-absolute(85%, auto, auto, 0%); .o_reward_thumb_right { @@ -155,16 +155,16 @@ } .o_reward_shadow_container { - @include o-transform(translateY(0px) rotateZ(0)); - @include o-animation(reward-float, $reward-base-time, ease-in-out, $reward-base-time, infinite, alternate); + transform: translateY(0px) rotateZ(0); + animation: reward-float $reward-base-time ease-in-out $reward-base-time infinite alternate; } .o_reward_shadow { @include size(100%, 12px); background-color: #e7eaf0; border-radius: 100%; - @include o-transform(scale(0.8) rotateZ(0)); - @include o-animation(reward-scale, $reward-base-time, ease-in-out, $reward-base-time, infinite, alternate); + transform: scale(0.8) rotateZ(0); + animation: reward-scale $reward-base-time ease-in-out $reward-base-time infinite alternate; @include o-position-absolute(auto, auto, -40px, 0); } } @@ -187,25 +187,25 @@ @keyframes reward-jump { 0% { - @include o-transform(scale(0.5)); + transform: scale(0.5); } 50% { - @include o-transform(scale(1.05)); + transform: scale(1.05); } to { - @include o-transform(scale(1)); + transform: scale(1); } } @keyframes reward-jump-reverse { 0% { - @include o-transform(scale(1)); + transform: scale(1); } 50% { - @include o-transform(scale(1.05)); + transform: scale(1.05); } to { - @include o-transform(scale(0.5)); + transform: scale(0.5); } } @@ -226,30 +226,30 @@ @keyframes reward-float { from { - @include o-transform(translateY(0px)); + transform: translateY(0px); } to { - @include o-transform(translateY(5px)); + transform: translateY(5px); } } @keyframes reward-stars { from { - @include o-transform(scale(0.3) rotate(0deg)); + transform: scale(0.3) rotate(0deg); } 50% { - @include o-transform(scale(1.0) rotate(20deg)); + transform: scale(1.0) rotate(20deg); } to { - @include o-transform(scale(0.3) rotate(80deg)); + transform: scale(0.3) rotate(80deg); } } @keyframes reward-scale { from { - @include o-transform(scale(0.8)); + transform: scale(0.8); } to { - @include o-transform(scale(1.0)); + transform: scale(1.0); } } diff --git a/addons/web/static/src/scss/report.scss b/addons/web/static/src/scss/report.scss index a2df1fbc69b..cce5c6d3be5 100644 --- a/addons/web/static/src/scss/report.scss +++ b/addons/web/static/src/scss/report.scss @@ -11,7 +11,7 @@ body { } /* See https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524 */ -.table-condensed { +.table-sm { > thead > tr > th { border-bottom: none !important; } @@ -30,7 +30,7 @@ body { } /* Wkhtmltopdf doesn't support very well the media-print CSS (depends on the version) */ -.hidden-print{ +.d-print-none{ display: none; } diff --git a/addons/web/static/src/scss/search_groupby_menu.scss b/addons/web/static/src/scss/search_groupby_menu.scss deleted file mode 100644 index 4092b4b5fb7..00000000000 --- a/addons/web/static/src/scss/search_groupby_menu.scss +++ /dev/null @@ -1,16 +0,0 @@ -// Group By -.o_group_by_menu { - @include o-selected-li; - - max-height: calc(100vh - 125px); - overflow: auto; - - .o_add_group { // add button - @include o-search-options-dropdown-custom-li; - } - - .o_submenu_switcher { - position: absolute; - right: 0px; - } -} diff --git a/addons/web/static/src/scss/search_view.scss b/addons/web/static/src/scss/search_view.scss index 0ff5fd320e7..700c13f7e84 100644 --- a/addons/web/static/src/scss/search_view.scss +++ b/addons/web/static/src/scss/search_view.scss @@ -1,11 +1,10 @@ -@mixin o-search-options-dropdown-custom-li { - margin: 3px 25px; +@mixin o-search-options-dropdown-custom-item { width: auto; max-width: 250px; } .o_searchview { - @include o-align-items(flex-end); + align-items: flex-end; position: relative; padding: 0 20px 1px 0; @@ -15,25 +14,25 @@ } .o_searchview_input_container { - @include o-flex-display; - @include o-flex-flow(row, wrap); + display: flex; + flex-flow: row wrap; .o_searchview_facet { $o-searchview-facet-remove-width: 18px; - @include o-flex(0, 0, auto); + flex: 0 0 auto; max-width: 100%; - @include o-flex-display; + display: flex; position: relative; margin: 1px 3px 0 0; .o_searchview_facet_label { - @include o-flex(0, 0, auto); + flex: 0 0 auto; @include o-text-overflow; padding: 0 3px; color: white; - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; } .o_facet_values { @@ -43,10 +42,10 @@ } } .o_facet_remove { - @include o-flex(0, 0, auto); - @include o-flex-display; - @include o-justify-content(center); - @include o-align-items(center); + flex: 0 0 auto; + display: flex; + justify-content: center; + align-items: center; @include o-position-absolute(0, 0, 0); width: $o-searchview-facet-remove-width; cursor: pointer; @@ -54,7 +53,7 @@ } .o_searchview_input { width: 100px; - @include o-flex(1, 0, auto); + flex: 1 0 auto; } .o_searchview_more { @@ -107,7 +106,7 @@ display: inline-block; cursor: pointer; - @include user-select(none); // Prevent text selection when toggling the dropdowns + user-select: none; // Prevent text selection when toggling the dropdowns > a { // dropdown togglers color: $o-main-text-color; &:hover { @@ -116,7 +115,7 @@ color: darken($o-main-text-color, 10%); } } - &.open > a { + &.show > a { font-weight: bold; color: darken($o-main-text-color, 10%); } @@ -130,7 +129,7 @@ a:before { @include o-caret-right; @include o-position-absolute($top: 50%, $left: 10px); - margin-top: (-$caret-width-base); + margin-top: (-$caret-width); } } .o_open_menu { @@ -138,7 +137,7 @@ a:before { @include o-caret-down; @include o-position-absolute($top: 50%, $left: 10px); - margin-top: (-$caret-width-base); + margin-top: (-$caret-width); } } @@ -150,7 +149,7 @@ overflow: auto; .o_filter_condition { - @include o-search-options-dropdown-custom-li; + @include o-search-options-dropdown-custom-item; margin-bottom: 8px; .o_or_filter { // or between conditions display: none; // hidden for the first condition @@ -177,7 +176,7 @@ } .o_add_filter_menu { // apply and add buttons display: none; // Needed by the webclient - @include o-search-options-dropdown-custom-li; + @include o-search-options-dropdown-custom-item; } .o_submenu_switcher { position: absolute; @@ -196,7 +195,7 @@ max-height: calc(100vh - 125px); overflow: auto; - .divider {display: none;} // hide the divider by default (no favorite) + .dropdown-divider {display: none;} // hide the divider by default (no favorite) .o-searchview-custom-private, .o-searchview-custom-public { .o-remove-filter { @include o-position-absolute(50%, 12px); @@ -212,6 +211,6 @@ } .o_save_name { // save button display: none; // hidden by default - @include o-search-options-dropdown-custom-li; + @include o-search-options-dropdown-custom-item; } } diff --git a/addons/web/static/src/scss/search_view_extra.scss b/addons/web/static/src/scss/search_view_extra.scss index d2098a5f9c3..1deba51bfba 100644 --- a/addons/web/static/src/scss/search_view_extra.scss +++ b/addons/web/static/src/scss/search_view_extra.scss @@ -1,21 +1,21 @@ .o_searchview { background-color: white; border: 1px solid #ccc; - border-radius: $border-radius-base; + border-radius: $border-radius; padding: 1px 25px 3px 5px; .o_searchview_facet { - border: 1px solid $gray-light; - background: lighten($o-brand-primary, 35%); + border: 1px solid gray('600'); + background: lighten($o-brand-odoo, 35%); .o_searchview_facet_label { - background-color: $gray-light; + background-color: gray('600'); } .o_facet_remove { - color: $gray-light; + color: gray('600'); &:hover { - color: $gray; + color: gray('700'); } } } @@ -28,7 +28,7 @@ @include o-position-absolute($top: 6px, $right: 5px); } .o_searchview_autocomplete li.o-selection-focus { - background-color: $o-brand-primary; + background-color: $o-brand-odoo; > a { color: white; } diff --git a/addons/web/static/src/scss/search_view_mobile.scss b/addons/web/static/src/scss/search_view_mobile.scss index c36f5d39850..f5ccd133cc1 100644 --- a/addons/web/static/src/scss/search_view_mobile.scss +++ b/addons/web/static/src/scss/search_view_mobile.scss @@ -48,7 +48,7 @@ .o_dropdown { width: 100%; margin: 15px 5px 0px 5px; - border: solid 1px darken($gray-lighter, 20%); + border: solid 1px darken(gray('200'), 20%); } .o_dropdown_toggler_btn { @@ -66,7 +66,7 @@ width: 100%; box-shadow: none; border: none; - color: $gray-light; + color: gray('600'); .divider { margin: 0px; } @@ -85,4 +85,4 @@ z-index: 1000; } } -}
\ No newline at end of file +} diff --git a/addons/web/static/src/scss/secondary_variables.scss b/addons/web/static/src/scss/secondary_variables.scss index 8ab2d5bc322..ee7f15eded6 100644 --- a/addons/web/static/src/scss/secondary_variables.scss +++ b/addons/web/static/src/scss/secondary_variables.scss @@ -1,30 +1,21 @@ -// Define $gray-lighter-dark as a minor bootstrap $gray-lighter variation used -// for design purposes only (e.g. cards' borders). We avoid to overwrite the -// default $gray-light because it is deeply used by bootstrap to define muted -// elements. -$gray-lighter-dark: $o-color-silver-dark; -$gray-lighter-darker: $o-color-silver-darker; - -$o-webclient-background-color: $o-color-silver; -$o-control-panel-background-color: $o-color-silver; +$o-webclient-background-color: $o-gray-100; +$o-control-panel-background-color: $o-gray-100; $o-list-footer-color: $o-main-text-color; $o-list-group-header-color: lighten($o-brand-lightsecondary, 10%); // UI custom colors for tags, kanban records' colors, ...) -$o-colors: $o-color-gray-light, #F06050, #F4A460, #F7CD1F, #6CC1ED, #814968, +// Note: the first value is the old BS3 gray-light value +$o-colors: lighten(#000, 46.7%), #F06050, #F4A460, #F7CD1F, #6CC1ED, #814968, #EB7E7F, #2C8397, #475577, #D6145F, #30C381, #9365B8; -$screen-xxs-max: ($screen-xs-min - 1); -$screen-lg-max: ($screen-xl-min - 1); - $o-sheet-cancel-hpadding: $o-horizontal-padding; $o-sheet-cancel-bpadding: $o-horizontal-padding; $o-statusbar-arrow-width: $o-statusbar-height / 3; $o-statusbar-disabled-bg: lighten($o-brand-lightsecondary, 7%); -$o-navbar-inverse-link-hover-bg: darken($o-brand-primary, 10%); +$o-navbar-inverse-link-hover-bg: darken($o-brand-odoo, 10%); $o-datepicker-week-bg-color: lighten($o-datepicker-week-color, 30%); diff --git a/addons/web/static/src/scss/tooltip.scss b/addons/web/static/src/scss/tooltip.scss index 765db1292da..e40852dd6bc 100644 --- a/addons/web/static/src/scss/tooltip.scss +++ b/addons/web/static/src/scss/tooltip.scss @@ -9,7 +9,7 @@ max-width: 100vw; background-color: $o-tooltip-background-color; color: $o-tooltip-color; - border-radius: $border-radius-base; + border-radius: $border-radius; box-shadow: 0px 0px 1px 1px $o-brand-secondary; padding: 5px; @@ -17,7 +17,7 @@ text-align: left; .oe_tooltip_string { - background-color: $o-brand-primary; + background-color: $o-brand-odoo; color: white; font-weight: bold; padding: 5px; diff --git a/addons/web/static/src/scss/ui.scss b/addons/web/static/src/scss/ui.scss index d88f21f83a1..d8c68853c0a 100644 --- a/addons/web/static/src/scss/ui.scss +++ b/addons/web/static/src/scss/ui.scss @@ -13,3 +13,13 @@ [aria-hidden="true"], [aria-hidden="1"] { display: none!important; } + +.dropdown-toggle { + white-space: nowrap; + + &.o-no-caret { + &::before, &::after { + content: normal; + } + } +} diff --git a/addons/web/static/src/scss/ui_extra.scss b/addons/web/static/src/scss/ui_extra.scss index 0d97c09092e..e69de29bb2d 100644 --- a/addons/web/static/src/scss/ui_extra.scss +++ b/addons/web/static/src/scss/ui_extra.scss @@ -1,10 +0,0 @@ -//------------------------------------------------------------------------------ -// Checkboxes -//------------------------------------------------------------------------------ -div.o_checkbox { - display: inline-block; - vertical-align: sub; - > input + span { - display: none; - } -} diff --git a/addons/web/static/src/scss/utils.scss b/addons/web/static/src/scss/utils.scss index efb8dce7598..9f254c82ecd 100644 --- a/addons/web/static/src/scss/utils.scss +++ b/addons/web/static/src/scss/utils.scss @@ -14,119 +14,6 @@ } // ------------------------------------------------------------------ -// Vendor prefixes -// ------------------------------------------------------------------ -// Flex -@mixin o-flex-display { - display: -ms-flexbox; - display: -moz-box; - display: -webkit-box; - display: -webkit-flex; - - display: flex; -} -@mixin o-inline-flex-display { - display: -ms-inline-flexbox; - display: -moz-inline-box; - display: -webkit-inline-box; - display: -webkit-inline-flex; - - display: inline-flex; -} -@mixin o-flex-flow($direction, $wrap) { - -ms-flex-flow: $direction $wrap; - -moz-flex-flow: $direction $wrap; - -webkit-flex-flow: $direction $wrap; - - flex-flow: $direction $wrap; -} -@mixin o-flex($grow, $schrink, $basis) { - -ms-flex: $grow $schrink $basis; - -moz-flex: $grow $schrink $basis; - -webkit-box-flex: $grow; - -webkit-flex: $grow $schrink $basis; - - flex: $grow $schrink $basis; -} -@mixin o-justify-content($justify) { - -moz-justify-content: $justify; - -webkit-justify-content: $justify; - - justify-content: $justify; -} -@mixin o-align-content($align) { - -webkit-align-content: $align; - - align-content: $align; -} -@mixin o-align-items($align) { - -webkit-align-items: $align; - - align-items: $align; -} -@mixin o-align-self($align) { - -webkit-align-self: $align; - - align-self: $align; -} - -// Background-size -@mixin o-background-size($size) { - -webkit-background-size: $size; - -moz-background-size: $size; - -o-background-size: $size; - background-size: $size; -} - -// ------------------------------------------------------------------ -// Select Appearance -// ------------------------------------------------------------------ -@mixin o-appearance($value) { - -webkit-appearance: $value; - -moz-appearance: $value; - appearance: $value; -} - -// ------------------------------------------------------------------ -// Transform -// ------------------------------------------------------------------ -@mixin o-transform-origin($x: 50%, $y: 50%, $z: 0) { - -ms-transform-origin: $x $y $z; - -webkit-transform-origin: $x $y $z; - -moz-transform-origin: $x $y $z; - transform-origin: $x $y $z; -} - -// ------------------------------------------------------------------ -// Animation -// ------------------------------------------------------------------ -@mixin o-animation($name: none, $duration: 0s, $timing-function: ease, $delay: 0s, $iteration-count: 1, $direction: normal, $fill-mode: none, $play-state: running) { - -webkit-animation: $name $duration $timing-function $delay $iteration-count $direction $fill-mode $play-state; - -moz-animation: $name $duration $timing-function $delay $iteration-count $direction $fill-mode $play-state; - -o-animation: $name $duration $timing-function $delay $iteration-count $direction $fill-mode $play-state; - animation: $name $duration $timing-function $delay $iteration-count $direction $fill-mode $play-state; -} - -// ------------------------------------------------------------------ -// Transition -// ------------------------------------------------------------------ -@mixin o-transition($property: all, $duration: 0s, $timing-function: ease, $transition-delay: 0s) { - -webkit-transition: $property $duration $timing-function $transition-delay; - -moz-transition: $property $duration $timing-function $transition-delay; - -o-transition: $property $duration $timing-function $transition-delay; - transition: $property $duration $timing-function $transition-delay; -} - -// ------------------------------------------------------------------ -// Columns -// ------------------------------------------------------------------ -@mixin o-columns($width: auto, $col: auto) { - -webkit-columns: $width $col; - -moz-columns: $width $col; - columns: $width $col; -} - -// ------------------------------------------------------------------ // Position absolute // ------------------------------------------------------------------ @mixin o-position-absolute($top: auto, $right: auto, $bottom: auto, $left: auto) { @@ -150,43 +37,6 @@ } // ------------------------------------------------------------------ -// Gradients -// ------------------------------------------------------------------ -@mixin o-linear-gradient($deg: 45deg, $start-color: #555, $end-color: #333) { - background-repeat: repeat-x; - background-image: -webkit-linear-gradient($deg, $start-color, $end-color); - background-image: -o-linear-gradient($deg, $start-color, $end-color); - background-image: linear-gradient($deg, $start-color, $end-color); -} -@mixin o-vertical-gradient($startColor: #555, $endColor: #333) { - background-color: mix($startColor, $endColor); - background-image: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor)); - background-image: -webkit-linear-gradient(top, $startColor, $endColor); - background-image: -moz-linear-gradient(top, $startColor, $endColor); - background-image: -ms-linear-gradient(top, $startColor, $endColor); - background-image: -o-linear-gradient(top, $startColor, $endColor); - background-image: linear-gradient(to bottom, $startColor, $endColor); -} -@mixin o-skew-gradient($startColor: #555, $endColor: #333) { - background-color: $endColor; - background: -moz-linear-gradient(135deg, $endColor, $startColor); - background: -o-linear-gradient(135deg, $startColor, $endColor); - background: -webkit-gradient(linear, left top, right bottom, from($startColor), to($endColor)); - background: -ms-linear-gradient(top, $startColor, $endColor); -} - -// ------------------------------------------------------------------ -// Transform -// ------------------------------------------------------------------ -@mixin o-transform($transform) { - -webkit-transform: $transform; - -moz-transform: $transform; - -ms-transform: $transform; - -o-transform: $transform; - transform: $transform; -} - -// ------------------------------------------------------------------ // Hovering effects // ------------------------------------------------------------------ @mixin o-hover-opacity($default-opacity: 0.5, $hover-opacity: 1) { @@ -222,7 +72,7 @@ // ------------------------------------------------------------------ // Caret // ------------------------------------------------------------------ -@mixin o-caret-down($caret-width: $caret-width-base) { +@mixin o-caret-down($caret-width: $caret-width) { @include utils-caret-boilerplate; border-bottom: 0; border-left: $caret-width solid transparent; @@ -230,7 +80,7 @@ border-top: $caret-width solid; -moz-transform: scale(0.9999); // Smooth the caret on firefox } -@mixin o-caret-up($caret-width: $caret-width-base) { +@mixin o-caret-up($caret-width: $caret-width) { @include utils-caret-boilerplate; border-bottom: $caret-width solid; border-left: $caret-width solid transparent; @@ -238,7 +88,7 @@ border-top: 0; -moz-transform: scale(0.9999); // Smooth the caret on firefox } -@mixin o-caret-left($caret-width: $caret-width-base) { +@mixin o-caret-left($caret-width: $caret-width) { @include utils-caret-boilerplate; border-bottom: $caret-width solid transparent; border-left: 0; @@ -246,7 +96,7 @@ border-top: $caret-width solid transparent; -moz-transform: scale(0.9999); // Smooth the caret on firefox } -@mixin o-caret-right($caret-width: $caret-width-base) { +@mixin o-caret-right($caret-width: $caret-width) { @include utils-caret-boilerplate; border-bottom: $caret-width solid transparent; border-left: $caret-width solid; @@ -258,25 +108,22 @@ // ------------------------------------------------------------------ // Dropdowns // ------------------------------------------------------------------ -@mixin o-selected-li { - li { +@mixin o-selected-li { // FIXME use active ? + .dropdown-item { position: relative; - > a { - color: $o-main-text-color; - &:hover { - color: darken($o-main-text-color, 10%); - } + color: $o-main-text-color; + &:hover { + color: darken($o-main-text-color, 10%); } + &.selected { - > a { - color: darken($o-main-text-color, 10%); - font-weight: bold; - &:before { - font-family: FontAwesome; - position: absolute; - left: 6px; - content: "\f00c"; - } + color: darken($o-main-text-color, 10%); + font-weight: bold; + &:before { + font-family: FontAwesome; + position: absolute; + left: 6px; + content: "\f00c"; } } } @@ -285,7 +132,7 @@ // ------------------------------------------------------------------ // Hovering effects // ------------------------------------------------------------------ -@mixin o-hover-text-color($default-color: $text-color, $hover-color: $link-color) { +@mixin o-hover-text-color($default-color: $body-color, $hover-color: $link-color) { color: $default-color; &:hover, &:focus, &.focus { @@ -316,7 +163,7 @@ display: block; text-align: center; color: $o-main-text-color; - font-size: $font-size-small; + font-size: $font-size-sm; cursor: pointer; @include o-hover-opacity($base-opacity); } @@ -339,22 +186,22 @@ } @mixin o-kanban-slim-col { position: relative; - @include o-flex(0, 0, auto); + flex: 0 0 auto; margin: 0; padding: 0 floor($o-kanban-group-padding * 0.7); cursor: pointer; } @mixin o-kanban-header-title { - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; height: $o-kanban-header-title-height; line-height: 2.2; color: $headings-color; } @mixin o-kanban-v-title { @include o-position-absolute($o-kanban-inside-vgutter * 2, $left: floor(-$o-kanban-inside-vgutter * 1.2)); - @include o-transform-origin(left, bottom, $z: 0); - @include o-transform(rotate(90deg)); + transform-origin: left bottom 0; + transform: rotate(90deg); overflow: visible; white-space: nowrap; font-size: 15px; @@ -374,7 +221,7 @@ border: 1px solid transparent; border-bottom: none; vertical-align: top; - color: $text-color; + color: $body-color; &:hover { color: $headings-color; @@ -386,13 +233,13 @@ @mixin o-kanban-dropdown-open { position: relative; background: white; - border-color: $gray-lighter-darker; + border-color: gray('400'); z-index: $zindex-dropdown + 1; } @mixin o-kanban-dropdown-menu { @include o-position-absolute($right: -1px); margin-top: -1px; - border-color: $gray-lighter-darker; + border-color: gray('400'); } @mixin o-kanban-colorpicker { max-width: 150px; @@ -402,7 +249,7 @@ display: inline-block; margin: $o-kanban-inner-hmargin $o-kanban-inner-hmargin 0 0; border: 1px solid white; - box-shadow: 0 0 0 1px $gray-lighter-dark; + box-shadow: 0 0 0 1px gray('300'); > a { display: block; @@ -424,7 +271,7 @@ display: block; width: 1px; height: 20px; - @include rotate(45deg); + transform: rotate(45deg); background-color: red; } &::after { @@ -441,11 +288,11 @@ > a { margin: auto auto auto (-$link-padding-gap); padding: 3px $link-padding-gap; - color: $text-color; + color: $body-color; display: block; &:hover { - background-color: $gray-lighter-dark; + background-color: gray('300'); color: $headings-color; } } diff --git a/addons/web/static/src/scss/views.scss b/addons/web/static/src/scss/views.scss index e3562026ffe..e4e86231940 100644 --- a/addons/web/static/src/scss/views.scss +++ b/addons/web/static/src/scss/views.scss @@ -18,13 +18,13 @@ border-radius: 6px; vertical-align: middle; - background-color: $gray-lighter-dark; + background-color: gray('300'); &.o_status_green { - background-color: $brand-success; + background-color: theme-color('success'); } &.o_status_red { - background-color: $brand-danger; + background-color: theme-color('danger'); } } diff --git a/addons/web/static/src/scss/web_calendar.scss b/addons/web/static/src/scss/web_calendar.scss index 7091cbc3c98..ae22efb2675 100644 --- a/addons/web/static/src/scss/web_calendar.scss +++ b/addons/web/static/src/scss/web_calendar.scss @@ -1,12 +1,12 @@ @keyframes backgroundfade { - from {background-color: rgba($o-brand-primary, 0.5);} + from {background-color: rgba($o-brand-odoo, 0.5);} to {background-color: #f5f5f5;} } .o_calendar_container { height: 100%; @include o-webclient-padding($top: $o-horizontal-padding/2, $bottom: $o-horizontal-padding/2); - @include o-flex-display; + display: flex; @for $index from 1 through $o-nb-calendar-colors { .o_calendar_color_#{$index} { @@ -28,7 +28,7 @@ } .o_calendar_view { - @include o-flex(1, 1, auto); + flex: 1 1 auto; min-width: 0; .o_calendar_widget { @@ -62,7 +62,7 @@ } .o_calendar_sidebar_container { - @include o-flex(0, 0, $o-horizontal-padding); + flex: 0 0 $o-horizontal-padding; position: relative; &.o_sidebar_hidden { @@ -97,13 +97,13 @@ padding: 0; .ui-widget-header { - @include o-flex-display; + display: flex; background: none; background-color: lighten($o-brand-secondary, 30%); border-radius: 0; .ui-datepicker-prev, .ui-datepicker-next { - @include o-flex(0, 0, auto); + flex: 0 0 auto; position: static; cursor: pointer; padding: 2px; @@ -133,7 +133,7 @@ } } .ui-datepicker-title { - @include o-flex(0, 0, auto); + flex: 0 0 auto; order: 2; display: inline-block; margin: 0 10px; @@ -151,22 +151,22 @@ } } .ui-state-default { - color: $o-brand-primary; + color: $o-brand-odoo; &:hover { background: none; - background-color: rgba($o-brand-primary, 0.5); - border-color: $o-brand-primary; + background-color: rgba($o-brand-odoo, 0.5); + border-color: $o-brand-odoo; color: $o-view-background-color; }; } .ui-state-active { background: none; - background-color: $o-brand-primary; + background-color: $o-brand-odoo; color: $o-view-background-color; } .o_selected_range.o_color { background: none; - background-color: $o-brand-primary; + background-color: $o-brand-odoo; animation: backgroundfade 3s forwards; } } @@ -199,12 +199,12 @@ } // Mobile rules -@media only screen and (max-width: 768px) { +@include media-breakpoint-down(sm) { .o_calendar_container { padding: 0; } } -@media (max-width: $screen-xs-max) { +@include media-breakpoint-down(sm) { .o_control_panel { .o_calendar_button_today { float: right; diff --git a/addons/web/static/src/scss/webclient.scss b/addons/web/static/src/scss/webclient.scss index 8f4dadb22df..8c213a57682 100644 --- a/addons/web/static/src/scss/webclient.scss +++ b/addons/web/static/src/scss/webclient.scss @@ -1,3 +1,7 @@ +:root { + font-size: $o-root-font-size; +} + // ------------------------------------------------------------------ // General // ------------------------------------------------------------------ @@ -13,7 +17,7 @@ width: 300px; max-width: 100%; - @include o-position-absolute($navbar-height, 0px); + @include o-position-absolute($nav-link-height, 0); z-index: 1100; // Bootstrap modal z-index is 1050 .o_notification { @@ -33,8 +37,8 @@ } .o_notification_title { - @include o-flex-display; - @include o-align-items(center); + display: flex; + align-items: center; border-bottom: 1px solid rgba(0, 0, 0, 0.1); padding: 10px 10px 10px 20px; @@ -101,26 +105,26 @@ div.o_boolean_toggle { } > input:checked + .slider { - background-color: $o-brand-optional; + background-color: $o-brand-primary; &:before { - @include translate(14px, 0px); + transform: translate(14px, 0px); } } } // Full bg colors (bootstrap extension) .bg-success-full { - background-color: $brand-success; + background-color: theme-color('success'); } .bg-warning-full { - background-color: $brand-warning; + background-color: theme-color('warning'); } .bg-danger-full { - background-color: $brand-danger; + background-color: theme-color('danger'); } .bg-info-full { - background-color: $brand-info; + background-color: theme-color('info'); } .o_web_accesskey_overlay { @@ -151,28 +155,26 @@ div.o_boolean_toggle { //== Badges .badge { margin: 1px 2px 1px 0; - padding-top: 0; - padding-bottom: 0; } // Btn-link variations .btn-link { font-weight: $btn-font-weight; - &.btn-default { - @include o-btn-link-variant($text-color, $headings-color); + &.btn-secondary { + @include o-btn-link-variant($body-color, $headings-color); } &.btn-success, &.text-success { - @include o-btn-link-variant($text-color, $brand-success); + @include o-btn-link-variant($body-color, theme-color('success')); } &.btn-warning, &.text-warning { - @include o-btn-link-variant($text-color, $brand-warning); + @include o-btn-link-variant($body-color, theme-color('warning')); } &.btn-danger, &.text-danger { - @include o-btn-link-variant($text-color, $brand-danger); + @include o-btn-link-variant($body-color, theme-color('danger')); } &.btn-info, &.text-info { - @include o-btn-link-variant($text-color, darken($brand-info, 20%)); + @include o-btn-link-variant($body-color, darken(theme-color('info'), 20%)); } } diff --git a/addons/web/static/src/scss/webclient_extra.scss b/addons/web/static/src/scss/webclient_extra.scss index cc87e526f8d..80e9390c534 100644 --- a/addons/web/static/src/scss/webclient_extra.scss +++ b/addons/web/static/src/scss/webclient_extra.scss @@ -8,7 +8,7 @@ } .o_input { border: 1px solid $o-form-lightsecondary; - border-radius: $border-radius-base; + border-radius: $border-radius; padding: 2px 4px; color: #1f1f1f; @@ -29,7 +29,7 @@ select { top: 0; right: 50%; padding: 4px 12px; - background-color: $o-color-pink; + background-color: $o-enterprise-color; // FIXME probably supposed to be primary to be auto-adapted in enterprise ? color: white; text-align: center; border-top: none; @@ -44,8 +44,3 @@ select { @include o-text-overflow; max-width: 150px; } - -// Button -.btn-icon { - @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border); -} diff --git a/addons/web/static/src/scss/webclient_layout.scss b/addons/web/static/src/scss/webclient_layout.scss index f811df48802..c8bb9e3c3ed 100644 --- a/addons/web/static/src/scss/webclient_layout.scss +++ b/addons/web/static/src/scss/webclient_layout.scss @@ -1,7 +1,7 @@ .o_web_client { - @include o-flex-display; - @include o-flex-flow(column, nowrap); + display: flex; + flex-flow: column nowrap; overflow: hidden; &.o_fullscreen { @@ -15,7 +15,7 @@ .navbar { - @include o-flex(0, 0, auto); + flex: 0 0 auto; li > a { padding: 4px 8px; @@ -30,20 +30,20 @@ } > .o_main { - @include o-flex(1, 1, auto); - @include o-flex-display; + flex: 1 1 auto; + display: flex; min-height: 0; // Allow flex to shrink this element as much as it wants height: 100%; .o_sub_menu { - @include o-flex(0, 0, 220px); - @include o-flex-display; - @include o-flex-flow(column, nowrap); + flex: 0 0 220px; + display: flex; + flex-flow: column nowrap; border-right: 1px solid darken($o-control-panel-background-color, 20%); background-color: $o-control-panel-background-color; .o_sub_menu_logo { - @include o-flex(0, 0, auto); + flex: 0 0 auto; text-align: center; position: relative; @@ -67,14 +67,14 @@ } .o_sub_menu_content { - @include o-flex(1, 1, auto); + flex: 1 1 auto; height:100%; overflow-y: auto; .oe_secondary_menu_section { font-weight: bold; margin-left: 8px; - color: $o-brand-optional; + color: $o-brand-primary; } .oe_secondary_submenu { margin: 3px 0px 10px; @@ -128,28 +128,28 @@ } .o_sub_menu_footer { - @include o-flex(0, 0, auto); + flex: 0 0 auto; text-align: center; > a { font-weight: bold; > span { - color: $o-color-pink; + color: $o-enterprise-color; // FIXME probably supposed to be primary to be auto-adapted in enterprise ? } } } } .o_main_content { - @include o-flex(1, 1, auto); - @include o-flex-display; - @include o-flex-flow(column, nowrap); + flex: 1 1 auto; + display: flex; + flex-flow: column nowrap; .o_control_panel { - @include o-flex(0, 0, auto); + flex: 0 0 auto; } .o_content { - @include o-flex(1, 1, auto); + flex: 1 1 auto; height: 100%; overflow: auto; position: relative; diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index b92c143dc5f..a30ed34c264 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -123,7 +123,7 @@ </div> <div class="o_notification_content" t-if="widget.message"><t t-raw="widget.message"/></div> <div t-if="widget.buttons.length" class="o_buttons"> - <button t-foreach="widget.buttons" t-as="button" t-attf-class="btn btn-sm #{button.primary ? 'btn-primary' : 'btn-default'}" type="button"> + <button t-foreach="widget.buttons" t-as="button" t-attf-class="btn #{button.primary ? 'btn-primary' : 'btn-secondary'}" type="button"> <t t-if="button.icon"> <i t-if="button.icon.indexOf('fa-') === 0" t-attf-class="fa fa-fw o_button_icon #{button.icon}" role="img" t-att-aria-label="button.name" t-att-title="button.name"/> <img t-else="" t-att-src="button.icon" t-att-alt="button.name"/> @@ -143,7 +143,7 @@ </div> <div t-name="CrashManager.error" class="o_dialog_error"> <div class="alert alert-warning clearfix" role="alert"> - <button class="btn btn-sm btn-primary pull-right ml8 o_clipboard_button"> + <button class="btn btn-primary float-right ml8 o_clipboard_button"> <i class="fa fa-clipboard mr8"/>Copy the full error to clipboard </button> <p><b>An error occurred</b></p> @@ -151,7 +151,7 @@ </div> <t t-set="errUID" t-value="_.uniqueId()"/> - <button class="btn btn-sm btn-link" t-att-data-target="'#o_error_detail' + errUID" data-toggle="collapse">See details</button> + <button class="btn btn-link" t-att-data-target="'#o_error_detail' + errUID" data-toggle="collapse">See details</button> <div t-att-id="'o_error_detail' + errUID" class="collapse alert alert-danger o_error_detail" role="alert"> <pre><t t-esc="error.message"/></pre> <pre><t t-esc="error.data.debug"/></pre> @@ -175,8 +175,8 @@ </tr> </table> - <button type="button" class="btn btn-sm btn-primary oe_form_button">Change Password</button> - <button type="button" class="btn btn-sm btn-default oe_form_button oe_form_button_cancel" href="javascript:void(0)">Cancel</button> + <button type="button" class="btn btn-primary oe_form_button">Change Password</button> + <button type="button" class="btn btn-secondary oe_form_button oe_form_button_cancel" href="javascript:void(0)">Cancel</button> </div> </form> @@ -191,7 +191,7 @@ <div class="o_cp_right"> <div class="btn-group o_search_options" role="search"/> <nav class="o_cp_pager" role="search" aria-label="Pager"/> - <nav class="btn-group btn-group-sm o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/> + <nav class="btn-group o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/> </div> </div> </t> @@ -204,7 +204,7 @@ <t t-name="ControlPanel.SwitchButton"> <button type="button" t-att-accesskey="view.accessKey" - t-attf-class="btn btn-icon fa fa-lg #{view.icon} o_cp_switch_#{view.type}" + t-attf-class="btn btn-secondary fa fa-lg #{view.icon} o_cp_switch_#{view.type}" t-attf-aria-label="View #{view.type}" t-att-data-view-type="view.type" t-attf-title="View #{view.type}" tabindex="-1"/> </t> @@ -231,31 +231,31 @@ <a href="#" title="Open Developer Tools" aria-label="Open Developer Tools" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> <span class="fa fa-bug"/> </a> - <ul class="dropdown-menu o_debug_dropdown" role="menu"/> + <div class="dropdown-menu dropdown-menu-right o_debug_dropdown" role="menu"/> </li> </t> <t t-name="WebClient.DebugManager.Global"> - <li><a role="menuitem" href="#" data-action="perform_js_tests">Run JS Tests</a></li> - <li><a role="menuitem" href="#" data-action="perform_js_mobile_tests">Run JS Mobile Tests</a></li> - <li><a role="menuitem" href="#" data-action="select_view">Open View</a></li> + <a role="menuitem" href="#" data-action="perform_js_tests" class="dropdown-item">Run JS Tests</a> + <a role="menuitem" href="#" data-action="perform_js_mobile_tests" class="dropdown-item">Run JS Mobile Tests</a> + <a role="menuitem" href="#" data-action="select_view" class="dropdown-item">Open View</a> <t t-if="manager._events"> - <li class="divider" role="separator"/> - <li><a role="menuitem" href="#" data-action="show_timelines">Toggle Timelines</a></li> - <li><a role="menuitem" href="#" data-action="requests_clear">Clear Events</a></li> + <div class="dropdown-divider" role="separator"/> + <a role="menuitem" href="#" data-action="show_timelines" class="dropdown-item">Toggle Timelines</a> + <a role="menuitem" href="#" data-action="requests_clear" class="dropdown-item">Clear Events</a> </t> - <li class="divider o_debug_leave_section" role="separator"/> - <li><a role="menuitem" href="#" data-action="split_assets">Activate Assets Debugging</a></li> - <li><a role="menuitem" href="#" data-action="regenerateAssets">Regenerate Assets Bundles</a></li> - <li><a role="menuitem" href="#" data-action="leave_debug_mode">Leave the Developer Tools</a></li> + <div class="dropdown-divider o_debug_leave_section" role="separator"/> + <a role="menuitem" href="#" data-action="split_assets" class="dropdown-item">Activate Assets Debugging</a> + <a role="menuitem" href="#" data-action="regenerateAssets" class="dropdown-item">Regenerate Assets Bundles</a> + <a role="menuitem" href="#" data-action="leave_debug_mode" class="dropdown-item">Leave the Developer Tools</a> </t> <t t-name="WebClient.DebugManager.Action"> <t t-if="action"> - <li class="divider" role="separator"/> - <li><a role="menuitem" href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id">Edit Action</a></li> + <div class="dropdown-divider" role="separator"/> + <a role="menuitem" href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id" class="dropdown-item">Edit Action</a> <t t-if="action.res_model"> - <li><a role="menuitem" href="#" data-action="get_view_fields">View Fields</a></li> - <li><a role="menuitem" href="#" data-action="manage_filters">Manage Filters</a></li> - <li><a role="menuitem" href="#" data-action="translate">Technical Translation</a></li> + <a role="menuitem" href="#" data-action="get_view_fields" class="dropdown-item">View Fields</a> + <a role="menuitem" href="#" data-action="manage_filters" class="dropdown-item">Manage Filters</a> + <a role="menuitem" href="#" data-action="translate" class="dropdown-item">Technical Translation</a> </t> </t> </t> @@ -272,26 +272,24 @@ </t> <t t-name="WebClient.DebugManager.View"> <t t-if="view"> - <li role="separator" class="divider"/> + <div role="separator" class="dropdown-divider"/> <t t-if="view.type === 'form'"> - <li><a role="menuitem" href="#" data-action="set_defaults">Set Defaults</a></li> + <a role="menuitem" href="#" data-action="set_defaults" class="dropdown-item">Set Defaults</a> <t t-if="controller.getSelectedIds().length === 1"> - <li><a role="menuitem" href="#" data-action="get_metadata">View Metadata</a></li> + <a role="menuitem" href="#" data-action="get_metadata" class="dropdown-item">View Metadata</a> </t> </t> - <li><a role="menuitem" href="#" data-action="fvg">Fields View Get</a></li> + <a role="menuitem" href="#" data-action="fvg" class="dropdown-item">Fields View Get</a> <t t-if="can_edit"> - <li> - <a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id"> + <a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id" class="dropdown-item"> Edit View: <t t-esc="_.str.capitalize(view.type)"/> - </a> - </li> - <li t-if="searchview and searchview.$el.is(':visible')"><a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.searchFieldsView.view_id">Edit SearchView</a></li> + </a> + <a t-if="searchview and searchview.$el.is(':visible')" role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.searchFieldsView.view_id" class="dropdown-item">Edit SearchView</a> </t> </t> </t> <t t-name="WebClient.DebugViewLog"> - <table class="table table-condensed table-striped"> + <table class="table table-sm table-striped"> <tr> <th>ID:</th> <td><t t-esc="perm.id"/></td> @@ -342,17 +340,17 @@ <t t-name="Sidebar"> <t t-foreach="widget.sections" t-as="section"> <div class="btn-group o_dropdown"> - <button t-if="section.name != 'buttons'" class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> + <button t-if="section.name != 'buttons'" class="o_dropdown_toggler_btn btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> <t t-if="section.name == 'files'" t-raw="widget.items[section.name].length || ''"/> - <t t-esc="section.label"/> <span class="caret"/> + <t t-esc="section.label"/> </button> <t t-if="section.name == 'buttons'" t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> <a t-att-title="item.title or None" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url or '#'" target="_blank"> <t t-raw="item.label"/> </a> </t> - <ul class="dropdown-menu" role="menu"> - <li role="menuitem" t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> + <div class="dropdown-menu" role="menu"> + <t t-foreach="widget.items[section.name]" t-as="item"> <t t-if="section.name == 'files'"> <t t-set="item.title"> <b>Attachment : </b><br/> @@ -369,12 +367,12 @@ <t t-raw="item.write_uid[1]"/> <t t-esc="item.write_date_string"/> </t> </t> - <a t-att-title="item.title or None" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url or '#'"> + <a t-attf-class="dropdown-item #{item.classname}" role="menuitem" t-att-title="item.title or None" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url or '#'"> <t t-raw="item.label"/> <span t-if="section.name == 'files' and widget.options.editable and !item.callback" class="fa fa-trash-o o_sidebar_delete_attachment" t-att-data-id="item.id" title="Delete this attachment" role="img" aria-label="Delete this attachment"/> </a> - </li> - <li role="menuitem" t-if="section.name == 'files' and widget.options.editable" class="o_sidebar_add_attachment"> + </t> + <div role="menuitem" t-if="section.name == 'files' and widget.options.editable" class="dropdown-item o_sidebar_add_attachment"> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileuploadId"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> @@ -384,8 +382,8 @@ <input type="hidden" name="session_id" t-att-value="widget.getSession().session_id" t-if="widget.getSession().override_session"/> <span>Add...</span> </t> - </li> - </ul> + </div> + </div> </div> </t> </t> @@ -393,14 +391,14 @@ <t t-name="ListView.buttons"> <div class="o_list_buttons" role="toolbar" aria-label="Main actions"> <t t-if="widget.is_action_enabled('create')"> - <button type="button" class="btn btn-primary btn-sm o_list_button_add" accesskey="c"> + <button type="button" class="btn btn-primary o_list_button_add" accesskey="c"> Create </button> </t> - <button type="button" class="btn btn-primary btn-sm o_list_button_save" accesskey="s"> + <button type="button" class="btn btn-primary o_list_button_save" accesskey="s"> Save </button> - <button type="button" class="btn btn-default btn-sm o_list_button_discard" accesskey="j"> + <button type="button" class="btn btn-secondary o_list_button_discard" accesskey="j"> Discard </button> </div> @@ -409,21 +407,21 @@ <t t-name="FormView.buttons"> <div class="o_form_buttons_view" role="toolbar" aria-label="Main actions"> <button t-if="widget.is_action_enabled('edit')" type="button" - class="btn btn-primary btn-sm o_form_button_edit" accesskey="a"> + class="btn btn-primary o_form_button_edit" accesskey="a"> Edit </button> <button t-if="widget.is_action_enabled('create')" type="button" - class="btn btn-default btn-sm o_form_button_create" accesskey="c"> + class="btn btn-secondary o_form_button_create" accesskey="c"> Create </button> </div> <div class="o_form_buttons_edit" role="toolbar" aria-label="Main actions"> <button type="button" - class="btn btn-primary btn-sm o_form_button_save" accesskey="s"> + class="btn btn-primary o_form_button_save" accesskey="s"> Save </button> <button type="button" - class="btn btn-default btn-sm o_form_button_cancel" accesskey="j"> + class="btn btn-secondary o_form_button_cancel" accesskey="j"> Discard </button> </div> @@ -447,7 +445,7 @@ <t t-name="FormButton.tooltip"> <div class="oe_tooltip_string" role="tooltip"> <div class="tooltip-inner"> - Hit ENTER to + Hit ENTER to <t t-esc="title"></t> </div> </div> @@ -509,22 +507,22 @@ </table> </form> <t t-name="GraphView.buttons"> - <div class="btn-group btn-group-sm" role="toolbar" aria-label="Main actions"> - <button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> - Measures <span class="caret"/> + <div class="btn-group" role="toolbar" aria-label="Main actions"> + <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> + Measures </button> - <ul class="dropdown-menu o_graph_measures_list" role="menu"> - <li t-foreach="measures" t-as="measure" t-att-data-field="measure[0]"> - <a role="menuitem" href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> - </li> - <li role="separator" class="divider"></li> - <li data-field="__count__"><a role="menuitem" href="#">Count</a></li> - </ul> + <div class="dropdown-menu o_graph_measures_list" role="menu"> + <t t-foreach="measures" t-as="measure"> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-field="measure[0]"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> + </t> + <div role="separator" class="dropdown-divider"/> + <a role="menuitem" href="#" class="dropdown-item" data-field="__count__">Count</a> + </div> </div> - <div class="btn-group btn-group-sm" role="toolbar" aria-label="Change graph"> - <button class="btn btn-default fa fa-bar-chart-o o_graph_button" title="Bar Chart" aria-label="Bar Chart" data-mode="bar"/> - <button class="btn btn-default fa fa-line-chart o_graph_button" title="Line Chart" aria-label="Line Chart" data-mode="line"/> - <button class="btn btn-default fa fa-pie-chart o_graph_button" title="Pie Chart" aria-label="Pie Chart" data-mode="pie"/> + <div class="btn-group" role="toolbar" aria-label="Change graph"> + <button class="btn btn-secondary fa fa-bar-chart-o o_graph_button" title="Bar Chart" aria-label="Bar Chart" data-mode="bar"/> + <button class="btn btn-secondary fa fa-line-chart o_graph_button" title="Line Chart" aria-label="Line Chart" data-mode="line"/> + <button class="btn btn-secondary fa fa-pie-chart o_graph_button" title="Pie Chart" aria-label="Pie Chart" data-mode="pie"/> </div> </t> <div t-name="GraphView.error" class="o_view_nocontent" role="alert"> @@ -538,48 +536,46 @@ <div class="o_field_selection"/> </div> <t t-name="PivotView.buttons"> - <div class="btn-group btn-group-sm" role="toolbar" aria-label="Main actions"> - <button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> - Measures <span class="caret"/> + <div class="btn-group" role="toolbar" aria-label="Main actions"> + <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> + Measures </button> - <ul class="dropdown-menu o_pivot_measures_list" role="menu"> - <li t-foreach="measures" t-as="measure" t-att-data-field="measure[0]"> - <a role="menuitem" href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> - </li> - <li role="separator" class="divider"></li> - <li data-field="__count"><a role="menuitem" href="#">Count</a></li> - </ul> + <div class="dropdown-menu o_pivot_measures_list" role="menu"> + <t t-foreach="measures" t-as="measure"> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-field="measure[0]"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> + </t> + <div role="separator" class="dropdown-divider"/> + <a role="menuitem" href="#" class="dropdown-item" data-field="__count">Count</a> + </div> </div> - <div class="btn-group btn-group-sm" role="toolbar" aria-label="Pivot settings"> - <button class="btn btn-default fa fa-expand o_pivot_flip_button" title="Flip axis" aria-label="Flip axis"/> - <button class="btn btn-default fa fa-arrows-alt o_pivot_expand_button" title="Expand all" aria-label="Expand all"/> - <button class="btn btn-default fa fa-download o_pivot_download" title="Download xls" aria-label="Download xls"/> + <div class="btn-group" role="toolbar" aria-label="Pivot settings"> + <button class="btn btn-secondary fa fa-expand o_pivot_flip_button" title="Flip axis" aria-label="Flip axis"/> + <button class="btn btn-secondary fa fa-arrows-alt o_pivot_expand_button" title="Expand all" aria-label="Expand all"/> + <button class="btn btn-secondary fa fa-download o_pivot_download" title="Download xls" aria-label="Download xls"/> </div> </t> <t t-name="PivotView.FieldSelection"> - <ul class="dropdown-menu o_pivot_field_menu" role="menu"> + <div class="dropdown-menu o_pivot_field_menu" role="menu"> <t t-foreach="fields" t-as="field"> <t t-if="(field[1].type === 'date') || (field[1].type === 'datetime')"> - <li role="menuitem" aria-haspopup="true" t-att-data-field="field[0]" t-attf-class="o_inline_dropdown#{field[2] ? ' disabled' : ''}"> - <a href="#" class="o_pivot_field_selection"> + <div role="menuitem" aria-haspopup="true" class="o_inline_dropdown"> + <a href="#" t-att-data-field="field[0]" t-attf-class="dropdown-item o_pivot_field_selection#{field[2] ? ' disabled' : ''}"> <t t-esc="field[1].string"/> </a> - <ul class="dropdown-menu" role="menu"> - <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'day'">Day</a></li> - <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'week'">Week</a></li> - <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'month'">Month</a></li> - <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'quarter'">Quarter</a></li> - <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'year'">Year</a></li> - </ul> - </li> + <div class="dropdown-menu" role="menu"> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-interval="'day'" t-att-data-field="field[0]">Day</a> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-interval="'week'" t-att-data-field="field[0]">Week</a> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-interval="'month'" t-att-data-field="field[0]">Month</a> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-interval="'quarter'" t-att-data-field="field[0]">Quarter</a> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-interval="'year'" t-att-data-field="field[0]">Year</a> + </div> + </div> </t> <t t-else=""> - <li t-att-data-field="field[0]" t-att-class="(field[2] ? 'disabled' : '')"> - <a role="menuitem" href="#"><t t-esc="field[1].string"/></a> - </li> + <a href="#" role="menuitem" t-att-data-field="field[0]" t-attf-class="dropdown-item#{field[2] ? ' disabled' : ''}"><t t-esc="field[1].string"/></a> </t> </t> - </ul> + </div> </t> <div t-name="PivotView.nodata"> <div class="o_view_nocontent" role="alert"> @@ -597,28 +593,27 @@ <t t-name="FormSelection"> <div class="btn-group o_selection" aria-atomic="true"> <a href="#" data-toggle="dropdown" aria-label="Dropdown menu" title="Dropdown menu"><span class="o_status"/></a> - <ul class="dropdown-menu state" role="menu"> - </ul> + <div class="dropdown-menu state" role="menu"/> </div> </t> <t t-name="FormSelection.items"> - <li t-foreach="states" t-as="rec" t-att-data-value="rec.name"> - <a role="menuitem" href="#"> + <t t-foreach="states" t-as="rec"> + <a role="menuitem" href="#" class="dropdown-item" t-att-data-value="rec.name"> <span t-att-class="'o_status ' + (rec.state_class && rec.state_class || '')"/> <t t-raw="rec.state_name"/> </a> - </li> + </t> </t> <t t-name="FieldDomain.content"> <div t-if="hasModel" class="o_field_domain_panel"> <i class="fa fa-arrow-right" role="img" aria-label="Domain" title="Domain"/> - <button t-if="isValid" class="btn btn-xs btn-default o_domain_show_selection_button" type="button"> + <button t-if="isValid" class="btn btn-sm btn-secondary o_domain_show_selection_button" type="button"> <t t-esc="nbRecords"/> record(s) </button> <span t-else="" class="text-warning" role="alert"><i class="fa fa-exclamation-triangle" role="img" aria-label="Warning" title="Warning"/> Invalid domain</span> - <button t-if="inDialogEdit" class="btn btn-xs btn-primary o_field_domain_dialog_button">Edit Domain</button> + <button t-if="inDialogEdit" class="btn btn-sm btn-primary o_field_domain_dialog_button">Edit Domain</button> </div> <div t-else="">Select a model to add a filter.</div> </t> @@ -631,15 +626,15 @@ </t> <t t-name="DomainTree.OperatorSelector"> <div t-if="!widget.readonly" class="btn-group o_domain_tree_operator_selector" aria-atomic="true"> - <button class="btn btn-xs btn-primary o_domain_tree_operator_caret" data-toggle="dropdown"> + <button class="btn btn-sm btn-primary o_domain_tree_operator_caret" data-toggle="dropdown"> <t t-if="widget.operator === '&'">All</t> <t t-if="widget.operator === '|'">Any</t> <t t-if="widget.operator === '!'">None</t> </button> - <ul class="dropdown-menu" role="menu"> - <li><a role="menuitem" href="#" data-operator="&">All</a></li> - <li><a role="menuitem" href="#" data-operator="|">Any</a></li> - </ul> + <div class="dropdown-menu" role="menu"> + <a role="menuitem" href="#" class="dropdown-item" data-operator="&">All</a> + <a role="menuitem" href="#" class="dropdown-item" data-operator="|">Any</a> + </div> </div> <strong t-else=""> <t t-if="widget.operator === '&'">ALL</t> @@ -650,7 +645,7 @@ <div aria-atomic="true" t-name="DomainSelector" t-attf-class="o_domain_node o_domain_tree o_domain_selector #{widget.readonly ? 'o_read_mode' : 'o_edit_mode'}"> <t t-if="widget.children.length === 0"> <span>Match <strong>all records</strong></span> - <button t-if="!widget.readonly" class="btn btn-xs btn-primary o_domain_add_first_node_button"><i class="fa fa-plus"/> Add filter</button> + <button t-if="!widget.readonly" class="btn btn-sm btn-primary o_domain_add_first_node_button"><i class="fa fa-plus"/> Add filter</button> </t> <t t-else=""> <div class="o_domain_tree_header"> @@ -692,7 +687,7 @@ </option> </select> </div> - <div t-attf-class="o_ds_value_cell#{_.contains(['set', 'not set'], widget.displayOperator) ? ' hidden' : ''}"> + <div t-attf-class="o_ds_value_cell#{_.contains(['set', 'not set'], widget.displayOperator) ? ' d-none' : ''}"> <t t-if="widget.selectionChoices !== null"> <select class="o_domain_leaf_value_input o_input"> <option t-foreach="widget.selectionChoices" t-as="val" @@ -705,13 +700,13 @@ <t t-else=""> <t t-if="_.contains(['in', 'not in'], widget.operator)"> <div class="o_domain_leaf_value_input"> - <span class="badge" t-foreach="widget.displayValue" t-as="val"> + <span class="badge badge-pill" t-foreach="widget.displayValue" t-as="val"> <t t-esc="val"/> <i class="o_domain_leaf_value_remove_tag_button fa fa-times" t-att-data-value="val" role="img" aria-label="Remove tag" title="Remove tag"/> </span> </div> <div class="o_domain_leaf_value_tags"> <input placeholder="Add new value" type="text" class="o_input"/> - <button class="btn btn-xs btn-primary fa fa-plus o_domain_leaf_value_add_tag_button" aria-label="Add tag" title="Add tag"/> + <button class="btn btn-sm btn-primary fa fa-plus o_domain_leaf_value_add_tag_button" aria-label="Add tag" title="Add tag"/> </div> </t> <t t-else=""> @@ -747,9 +742,9 @@ <div aria-atomic="true" t-name="ModelFieldSelector" t-attf-class="o_field_selector#{!widget.options.readonly ? ' o_edit_mode o_input' : ''}"> <div class="o_field_selector_value" tabindex="0"/> <div class="o_field_selector_controls" tabindex="0"> - <i role="alert" class="fa fa-exclamation-triangle o_field_selector_warning hidden" title="Invalid field chain" aria-label="Invalid field chain"/> + <i role="alert" class="fa fa-exclamation-triangle o_field_selector_warning d-none" title="Invalid field chain" aria-label="Invalid field chain"/> </div> - <div t-if="!widget.options.readonly" class="o_field_selector_popover hidden" tabindex="0"> + <div t-if="!widget.options.readonly" class="o_field_selector_popover d-none" tabindex="0"> <div class="o_field_selector_popover_header text-center"> <i class="fa fa-arrow-left o_field_selector_popover_option o_field_selector_prev_page" title="Previous" role="img" aria-label="Previous"/> <div class="o_field_selector_title"/> @@ -806,10 +801,10 @@ t-att-id="widget.idForLabel"/> </t> <t t-name="FieldRadio.button"> - <div class="o_radio_item" aria-atomic="true"> - <input type="radio" class="o_radio_input" t-att-checked="checked ? true : undefined" + <div class="custom-control custom-radio o_radio_item" aria-atomic="true"> + <input type="radio" class="custom-control-input o_radio_input" t-att-checked="checked ? true : undefined" t-att-data-value="value[0]" t-att-data-index="index" t-att-id="id"/> - <label class="o_form_label" t-att-for="id"><t t-esc="value[1]"/></label> + <label class="custom-control-label o_form_label" t-att-for="id"><t t-esc="value[1]"/></label> </div> </t> @@ -834,12 +829,12 @@ t-att-id="widget.idForLabel"/> <a role="button" class="o_dropdown_button" draggable="false"/> </div> - <button type="button" t-if="!widget.nodeOptions.no_open" class="fa fa-external-link btn btn-default o_external_button" tabindex="-1" draggable="false" aria-label="External link" title="External link"/> + <button type="button" t-if="!widget.nodeOptions.no_open" class="fa fa-external-link btn btn-secondary o_external_button" tabindex="-1" draggable="false" aria-label="External link" title="External link"/> </div> </t> <t t-name="FieldReference" t-extend="FieldMany2One"> <t t-jquery=".o_input_dropdown" t-operation="before"> - <select t-att-class="'o_input o_field_widget' + (widget.nodeOptions.hide_model and ' hidden' or '')"> + <select t-att-class="'o_input o_field_widget' + (widget.nodeOptions.hide_model and ' d-none' or '')"> <option/> <option t-foreach="widget.field.selection" t-as="model" t-att-value="model[0]"><t t-esc="model[1]"/></option> </select> @@ -849,7 +844,7 @@ <t t-foreach="elements" t-as="el"> <t t-set="color" t-value="el[colorField] || 0"/> <t t-set="colornames" t-value="['No color', 'Red', 'Orange', 'Yellow', 'Light blue', 'Dark purple', 'Salmon pink', 'Medium blue', 'Dark blue', 'Fushia', 'Green', 'Purple']"/> - <button t-attf-class="badge dropdown o_tag_color_#{color}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id" t-attf-title="Tag color: #{colornames[color]}"> + <button t-attf-class="badge badge-pill dropdown o_tag_color_#{color}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id" t-attf-title="Tag color: #{colornames[color]}"> <span class="o_badge_text"><span role="img" t-attf-aria-label="Tag color: #{colornames[color]}"/><t t-esc="el.display_name"/></span> <a t-if="!readonly" class="fa fa-times o_delete" title="Delete" aria-label="Delete"/> </button> @@ -873,10 +868,10 @@ <div role="menuitem" class="o_hide_in_kanban" t-att-data-id="tag_id" t-att-data-color="0"> - <div class="o_checkbox"> - <input type="checkbox"/> - <span/> - </div> Hide in Kanban + <div class="custom-control custom-checkbox"> + <input type="checkbox" id="o_hide_in_kanban_checkbox" class="custom-control-input"/> + <label for="o_hide_in_kanban_checkbox" class="custom-control-label">Hide in Kanban</label> + </div> </div> </li> </ul> @@ -901,12 +896,12 @@ </t> <t t-name="FieldStatus.content"> <t t-if="selection_folded.length"> - <button type="button" class="btn btn-sm o_arrow_button btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">More <span class="caret"/></button> - <ul class="dropdown-menu o-status-more" role="menu"> - <li t-foreach="selection_folded" t-as="i"> + <button type="button" class="btn o_arrow_button btn-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">More</button> + <div class="dropdown-menu o-status-more" role="menu"> + <t t-foreach="selection_folded" t-as="i"> <t t-call="FieldStatus.content.button"/> - </li> - </ul> + </t> + </div> </t> <t t-foreach="selection_unfolded.reverse()" t-as="i"> <t t-call="FieldStatus.content.button"/> @@ -915,15 +910,15 @@ <t t-name="FieldStatus.content.button"> <t t-set="disabled" t-value="!clickable"/> <button type="button" t-att-data-value="i.id" disabled="disabled" title="Current state" aria-pressed="true" - class="btn btn-sm o_arrow_button btn-primary disabled" t-if="i.selected" aria-current="step"> + class="btn o_arrow_button btn-primary disabled" t-if="i.selected" aria-current="step"> <t t-esc="i.display_name" role="img" t-attf-aria-label="#{i.display_name} is current state"/> </button> <button type="button" t-att-data-value="i.id" disabled="disabled" title="Not active state" aria-pressed="false" - class="btn btn-sm o_arrow_button btn-default disabled" t-if="!i.selected and disabled"> + class="btn o_arrow_button btn-secondary disabled" t-if="!i.selected and disabled"> <t t-esc="i.display_name" role="img" t-attf-aria-label="#{i.display_name} is not current state"/> </button> <button type="button" t-att-data-value="i.id" title="Not active state, click to change it" aria-pressed="false" - class="btn btn-sm o_arrow_button btn-default" t-if="!i.selected and !disabled"> + class="btn o_arrow_button btn-secondary" t-if="!i.selected and !disabled"> <t t-esc="i.display_name" role="img" t-attf-aria-label="Click to change current state to #{i.display_name}"/> </button> </t> @@ -931,8 +926,8 @@ <div class="o_field_image" aria-atomic="true"> <t t-if="widget.mode !== 'readonly'"> <div class="o_form_image_controls"> - <button class="fa fa-pencil fa-lg pull-left o_select_file_button" title="Edit" aria-label="Edit"/> - <button class="fa fa-trash-o fa-lg pull-right o_clear_file_button" title="Clear" aria-label="Clear"/> + <button class="fa fa-pencil fa-lg float-left o_select_file_button" title="Edit" aria-label="Edit"/> + <button class="fa fa-trash-o fa-lg float-right o_clear_file_button" title="Clear" aria-label="Clear"/> <span class="o_form_binary_progress">Uploading...</span> <t t-call="HiddenInputFile"> @@ -944,19 +939,19 @@ </div> </t> <t t-name="FieldBinaryImage-img"> - <img class="img img-responsive" + <img class="img img-fluid" alt="Binary file" t-att-src='url' t-att-border="widget.readonly ? 0 : 1" t-att-name="widget.name"/> </t> <t t-name="CopyClipboardText"> - <button class="btn btn-xs btn-primary o_clipboard_button o_btn_text_copy"> + <button class="btn btn-sm btn-primary o_clipboard_button o_btn_text_copy"> <span class="fa fa-clipboard">Copy Text</span> </button> </t> <t t-name="CopyClipboardChar"> - <button class="btn btn-xs btn-primary o_clipboard_button o_btn_char_copy"> + <button class="btn btn-sm btn-primary o_clipboard_button o_btn_char_copy"> <span class="fa fa-clipboard">Copy Text</span> </button> </t> @@ -970,9 +965,9 @@ t-att-tabindex="widget.attrs.tabindex" t-att-autofocus="widget.attrs.autofocus"/> - <button type="button" class="btn btn-sm btn-primary o_select_file_button" title="Select">Upload your file</button> - <button type="button" class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select" aria-label="Select"/> - <button type="button" class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear"/> + <button type="button" class="btn btn-primary o_select_file_button" title="Select">Upload your file</button> + <button type="button" class="btn btn-secondary fa fa-pencil o_select_file_button" title="Select" aria-label="Select"/> + <button type="button" class="btn btn-secondary fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear"/> <span class="o_form_binary_progress">Uploading...</span> <t t-call="HiddenInputFile"> @@ -1001,9 +996,9 @@ <div class="o_field_pdfviewer" aria-atomic="true"> <div t-if="widget.mode !== 'readonly'" class="o_form_pdf_controls mt8" role="toolbar" aria-label="PDF controls"> <span class="o_form_binary_progress">Uploading...</span> - <button type="button" class="btn btn-sm btn-primary o_select_file_button" title="Select">Upload your file</button> - <button class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select" aria-label="Select" type="button"></button> - <button class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear" type="button"></button> + <button type="button" class="btn btn-primary o_select_file_button" title="Select">Upload your file</button> + <button class="btn btn-secondary fa fa-pencil o_select_file_button" title="Select" aria-label="Select" type="button"></button> + <button class="btn btn-secondary fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear" type="button"></button> </div> <iframe class="o_pdfview_iframe o_field_pdfviewer"/> <t t-call="HiddenInputPDFFile"> @@ -1024,7 +1019,7 @@ <div t-name="FieldBinaryFileUploader" t-attf-class="oe_fileupload #{widget.attrs.class ? widget.attrs.class :''}" aria-atomic="true"> <div class="oe_placeholder_files"/> <div t-if="widget.mode !== 'readonly'" class="oe_add"> - <button class="btn btn-default o_attach" title="Attach"><span class="fa fa-paperclip" aria-label="Attach"/> <t t-esc="widget.string"/></button> + <button class="btn btn-secondary o_attach" title="Attach"><span class="fa fa-paperclip" aria-label="Attach"/> <t t-esc="widget.string"/></button> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileupload_id"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> @@ -1045,7 +1040,7 @@ <div t-foreach="widget.value.data" t-as="file" class="oe_attachment"> <t t-if="!file.data.upload"> <div> - <a href="#" class="fa fa-times pull-right oe_delete" title="Delete this file" aria-label="Delete this file" t-att-data-id="file.data.id"/> + <a href="#" class="fa fa-times float-right oe_delete" title="Delete this file" aria-label="Delete this file" t-att-data-id="file.data.id"/> <t t-raw="file.data.name || file.data.filename"/> </div> <a class="o_image" target="_blank" t-att-href="widget.metadata[file.id] ? widget.metadata[file.id].url : false" @@ -1069,71 +1064,67 @@ <t t-if="widget.items.length !== 0"> <t t-set="group" t-value="0"/> <t t-foreach="widget.items" t-as="item"> - <li t-if="group !== item.groupId" class="divider" data-removable="1"/> - <li t-att-class="'o_menu_item ' + (item.isActive ? 'selected ' : '')" + <div t-if="group !== item.groupId" class="dropdown-divider" data-removable="1"/> + <div t-attf-class="o_menu_item#{item.isActive ? ' selected ' : ''}" t-att-data-id="item.itemId"> - <a href="#"> + <a href="#" class="dropdown-item"> <t t-esc="item.description"/> <span t-if="item.isRemovable" t-att-data-id="item.itemId" class="o_trash_button" > <span class="fa fa-trash-o"></span> </span> <span t-if="item.hasOptions" t-att-data-id="item.itemId" class="o_submenu_switcher"> <span t-att-class="item.isOpen ? 'fa fa-caret-down' : 'fa fa-caret-right'"></span> </span> </a> - <ul t-if="item.hasOptions && item.isOpen"> + <ul t-if="item.hasOptions && item.isOpen" class="list-unstyled"> <t t-set="subgroup" t-value="0"/> <t t-foreach="_.values(item.options)" t-as="option"> - <li t-if="subgroup !== option.groupId" class="divider" data-removable="1"/> - <li t-att-class="'o_item_option ' + (item.currentOptionId === option.optionId ? 'selected': '')" + <li t-if="subgroup !== option.groupId" class="dropdown-divider" data-removable="1"/> + <li t-attf-class="o_item_option#{item.currentOptionId === option.optionId ? ' selected': ''}" t-att-data-item_id="item.itemId" t-att-data-option_id="option.optionId"> - <a href="#"><t t-esc="option.description"/></a> + <a href="#" class="dropdown-item pl-5"><t t-esc="option.description"/></a> </li> <t t-set="subgroup" t-value="option.groupId"/> </t> </ul> - </li> + </div> <t t-set="group" t-value="item.groupId"/> </t> </t> </t> -<div t-name="web.DropdownMenu" t-att-class="widget.dropdownStyle.el.class" t-att="widget.dropdownStyle.el.attrs" > +<div t-name="web.DropdownMenu" t-att-class="widget.dropdownStyle.el.class" t-att="widget.dropdownStyle.el.attrs"> <button t-att-class="widget.dropdownStyle.mainButton.class" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> - <span t-att-class="widget.dropdownIcon"/> <t t-esc="widget.dropdownTitle"/> <span t-att-class="widget.dropdownSymbol"/> + <span t-att-class="widget.dropdownIcon"/> <t t-esc="widget.dropdownTitle"/> <span t-if="widget.dropdownSymbol" t-att-class="widget.dropdownSymbol"/> </button> - <ul class="dropdown-menu o_dropdown_menu" role="menu"> + <div class="dropdown-menu o_dropdown_menu" role="menu"> <t t-call="DropdownMenu.MenuItems"/> - </ul> + </div> </div> <t t-name="GroupbyMenuGenerator"> - <li t-if="Object.keys(widget.presentedFields).length !== 0 && widget.items.length !== 0" class="o_generator_menu divider"/> - <li t-if="Object.keys(widget.presentedFields).length !== 0" class="o_generator_menu o_add_custom_group "> - <a href="#">Add Custom Group</a> - </li> - <li t-if="widget.generatorMenuIsOpen" class="o_generator_menu"> - <select class="o_input o_group_selector o_add_group"> + <div t-if="Object.keys(widget.presentedFields).length !== 0 && widget.items.length !== 0" class="dropdown-divider o_generator_menu"/> + <button t-if="Object.keys(widget.presentedFields).length !== 0" type="button" class="dropdown-item o_generator_menu o_add_custom_group">Add Custom Group</button> + <div t-if="widget.generatorMenuIsOpen" class="dropdown-item-text o_generator_menu"> + <select class="w-auto o_input o_group_selector o_add_group"> <t t-foreach="widget.presentedFields" t-as="field"> <option t-att-value="field.name"><t t-esc="field.string"/></option> </t> </select> - </li> - <li t-if="widget.generatorMenuIsOpen" class="o_generator_menu"> - <button type="button" class="btn btn-primary btn-sm o_apply_group o_add_group" tabindex="-1">Apply</button> - </li> + </div> + <div t-if="widget.generatorMenuIsOpen" class="dropdown-item-text o_generator_menu"> + <button type="button" class="btn btn-primary o_apply_group o_add_group" tabindex="-1">Apply</button> + </div> </t> <t t-name="FiltersMenuGenerator"> - <li class="divider"/> - <li t-if="Object.keys(widget.fields).length !== 0" class="o_add_custom_filter o_closed_menu"> - <a href="#">Add Custom Filter</a> - </li> - <li class="o_add_filter_menu"> - <button class="btn btn-primary btn-sm o_apply_filter" type="button">Apply</button> - <button class="btn btn-default btn-sm o_add_condition" type="button"> + <div class="dropdown-divider"/> + <button t-if="Object.keys(widget.fields).length !== 0" type="button" class="dropdown-item o_add_custom_filter o_closed_menu">Add Custom Filter</button> + <div class="dropdown-item-text o_add_filter_menu"> + <button class="btn btn-primary o_apply_filter" type="button">Apply</button> + <button class="btn btn-secondary o_add_condition" type="button"> <span class="fa fa-plus-circle"/> Add a condition </button> - </li> + </div> </t> @@ -1144,14 +1135,14 @@ </div> <t t-name="SearchViewMobile"> <div class="o_searchview" role="search" aria-autocomplete="list"> - <button class="o_enable_searchview btn btn-sm fa fa-search"/> + <button class="o_enable_searchview btn fa fa-search"/> <div class="o_mobile_search o_hidden"> <div class="o_mobile_search_header"> - <span class="o_mobile_search_close pull-left mt16 mb16 mr8 ml16"> + <span class="o_mobile_search_close float-left mt16 mb16 mr8 ml16"> <i class="fa fa-arrow-left"/> - <strong class="pull-right ml8">FILTER</strong> + <strong class="float-right ml8">FILTER</strong> </span> - <span class="pull-right o_mobile_search_clear_facets mt16 mr16">CLEAR</span> + <span class="float-right o_mobile_search_clear_facets mt16 mr16">CLEAR</span> </div> <div class="o_searchview_input_container"/> <div class="o_mobile_search_filter o_search_options mb8 mt8 ml16 mr16"/> @@ -1173,15 +1164,20 @@ <t t-esc="widget.model.get('label') + (widget.optionLabel ? (': ' + widget.optionLabel) : '')"/> </span> <t t-name="SearchView.autocomplete"> - <ul class="dropdown-menu o_searchview_autocomplete" role="menu"></ul> + <div class="dropdown-menu o_searchview_autocomplete" role="menu"/> </t> <t t-name="SearchView.filters"> - <li t-foreach="widget.filters" t-as="filter" t-if="!filter.visible || filter.visible()" - t-att-title="filter.attrs.string ? filter.attrs.help : undefined" - t-att-data-index="filter_index"> - <a role="menuitem" href="#"><t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/></a> - </li> + <t t-foreach="widget.filters" t-as="filter"> + <a t-if="!filter.visible || filter.visible()" + href="#" + class="dropdown-item" + t-att-title="filter.attrs.string ? filter.attrs.help : undefined" + t-att-data-index="filter_index" + role="menuitem"> + <t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/> + </a> + </t> </t> <t t-name="SearchView.field"> <label t-att-class="'oe_label' + (attrs.help ? '_help' : '')" @@ -1243,7 +1239,7 @@ </div> </t> <t t-name="SearchView.extended_search.proposition"> - <li role="menuitem" class="o_filter_condition"> + <div role="menuitem" class="dropdown-item-text o_filter_condition"> <span class="o_or_filter">or</span> <span> <select class="o_input o_searchview_extended_prop_field"> @@ -1258,7 +1254,7 @@ </span> <select class="o_input o_searchview_extended_prop_op"/> <span class="o_searchview_extended_prop_value"/> - </li> + </div> </t> <t t-name="SearchView.extended_search.proposition.float"> <input class="o_input" @@ -1276,33 +1272,37 @@ </t> <div t-name="SearchView.FavoriteMenu" class="btn-group o_dropdown"> - <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1" aria-label="Favorites" title="Favorites"> - <span class="fa fa-star"/> Favorites <span t-attf-class="#{widget.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret'}"/> + <button t-attf-class="o_dropdown_toggler_btn btn btn-secondary dropdown-toggle#{widget.isMobile ? ' o-no-caret' : ''}" data-toggle="dropdown" aria-expanded="false" tabindex="-1" aria-label="Favorites" title="Favorites"> + <span class="fa fa-star"/> Favorites <span t-if="widget.isMobile" class="fa fa-chevron-right float-right mt4"/> </button> - <ul class="dropdown-menu o_favorites_menu" role="menu"> - <li class="divider user_filter"/> - <li class="divider shared_filter"/> - <li class="o_save_search o_closed_menu"> - <a role="menuitem" href="#">Save current search</a> - </li> - <li role="menuitem" class="o_save_name"> - <input type="text"></input> - </li> - <li role="menuitem" class="o_save_name"> - <span><div class="o_checkbox"><input type="checkbox"/><span/></div> Use by default</span> - </li> - <li role="menuitem" class="o_save_name"> - <span><div class="o_checkbox"><input type="checkbox"/><span/></div> Share with all users </span><span class="fa fa-users" role="img" aria-label="Users" title="Users"/> - </li> - <li class="o_save_name"> - <button role="menuitem" type="button" class="btn btn-primary btn-sm">Save</button> - </li> - </ul> + <div class="dropdown-menu o_favorites_menu" role="menu"> + <div class="dropdown-divider user_filter"/> + <div class="dropdown-divider shared_filter"/> + <a role="menuitem" href="#" class="dropdown-item o_save_search o_closed_menu">Save current search</a> + <div role="menuitem" class="dropdown-item-text o_save_name"> + <input type="text" class="o_input"></input> + </div> + <div role="menuitem" class="dropdown-item-text o_save_name"> + <div class="custom-control custom-checkbox"> + <input type="checkbox" id="o_fav_menu_use_by_default" class="custom-control-input"/> + <label for="o_fav_menu_use_by_default" class="custom-control-label">Use by default</label> + </div> + </div> + <div role="menuitem" class="dropdown-item-text o_save_name"> + <div class="custom-control custom-checkbox"> + <input type="checkbox" id="o_fav_menu_share_all_users" class="custom-control-input"/> + <label for="o_fav_menu_share_all_users" class="custom-control-label">Share with all users <span class="fa fa-users" role="img" aria-label="Users" title="Users"/></label> + </div> + </div> + <div class="dropdown-item-text o_save_name"> + <button role="menuitem" type="button" class="btn btn-primary">Save</button> + </div> + </div> </div> <div t-name="ExportDialog" class="o_export"> <div class="row"> - <div class="col-md-6"> + <div class="col-lg-6"> <strong>What do you want to do?</strong> <div class="o_import_compat"> <div class="radio"> @@ -1319,7 +1319,7 @@ </div> </div> </div> - <div class="col-md-6"> + <div class="col-lg-6"> <strong>Export Format:</strong> <div class="o_export_format"/> </div> @@ -1331,15 +1331,15 @@ <div class="o_left_field_panel"/> </div> <div class="o_center_panel"> - <button type="button" class="btn btn-sm btn-default o_add_field">Add</button> - <button type="button" class="btn btn-sm btn-default o_remove_field">Remove</button> - <button type="button" class="btn btn-sm btn-default o_remove_all_field">Remove All</button> - <button type="button" class="btn btn-sm btn-default o_move_up">Move Up</button> - <button type="button" class="btn btn-sm btn-default o_move_down">Move Down</button> + <button type="button" class="btn btn-secondary o_add_field">Add</button> + <button type="button" class="btn btn-secondary o_remove_field">Remove</button> + <button type="button" class="btn btn-secondary o_remove_all_field">Remove All</button> + <button type="button" class="btn btn-secondary o_move_up">Move Up</button> + <button type="button" class="btn btn-secondary o_move_down">Move Down</button> </div> <div class="o_right_panel"> <h4> - <a href="#" class="pull-right o_toggle_save_list">Save fields list</a> + <a href="#" class="float-right o_toggle_save_list">Save fields list</a> Fields to export </h4> <div class="o_save_list"/> @@ -1363,7 +1363,7 @@ </t> </t> <t t-name="Export.SaveList"> - <label>Save as:</label> <input type="text"/><button type="button" class="btn btn-sm btn-default">Ok</button> + <label>Save as:</label> <input type="text"/><button type="button" class="btn btn-secondary">Ok</button> </t> <t t-name="Export.SavedList"> <label>Saved exports: </label> @@ -1373,7 +1373,7 @@ <option t-att-value="export.id"><t t-esc="export.name"/></option> </t> </select> - <button type="button" class="btn btn-sm btn-default o_delete_exported_list">Delete</button> + <button type="button" class="btn btn-secondary o_delete_exported_list">Delete</button> </t> <t t-name="Throbber"> @@ -1398,11 +1398,10 @@ <div aria-atomic="true"> <div t-foreach="widget.m2mValues" t-as="m2m_value"> <t t-set="id_for_label" t-value="'o_many2many_checkbox_' + _.uniqueId()"/> - <div class="o_checkbox"> - <input type="checkbox" t-att-id="id_for_label" t-att-data-record-id="JSON.stringify(m2m_value[0])"/> - <span/> + <div class="custom-control custom-checkbox"> + <input type="checkbox" t-att-id="id_for_label" class="custom-control-input" t-att-data-record-id="JSON.stringify(m2m_value[0])"/> + <label t-att-for="id_for_label" class="custom-control-label o_form_label"><t t-esc="m2m_value[1]"/></label> </div> - <label t-att-for="id_for_label" class="o_form_label"><t t-esc="m2m_value[1]"/></label> </div> </div> </t> @@ -1420,14 +1419,14 @@ <span class="o_pager_counter"> <span class="o_pager_value"></span> / <span class="o_pager_limit"></span> </span> - <span class="btn-group btn-group-sm" aria-atomic="true"> + <span class="btn-group" aria-atomic="true"> <!-- accesskeys not wanted in X2Many widgets --> <t t-if="widget.options.withAccessKey"> <t t-set="att_prev" t-value="{'accesskey': 'p'}" /> <t t-set="att_next" t-value="{'accesskey': 'n'}" /> </t> - <button type="button" class="fa fa-chevron-left btn btn-icon o_pager_previous" t-att="att_prev" aria-label="Previous" title="Next" tabindex="-1"/> - <button type="button" class="fa fa-chevron-right btn btn-icon o_pager_next" t-att="att_next" aria-label="Next" title="Next" tabindex="-1"/> + <button type="button" class="fa fa-chevron-left btn btn-secondary o_pager_previous" t-att="att_prev" aria-label="Previous" title="Next" tabindex="-1"/> + <button type="button" class="fa fa-chevron-right btn btn-secondary o_pager_next" t-att="att_next" aria-label="Next" title="Next" tabindex="-1"/> </span> </div> @@ -1457,36 +1456,36 @@ <t t-name="UserMenu"> <li class="o_user_menu"> <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#"> - <img class="img-circle oe_topbar_avatar" t-att-src="_s + '/web/static/src/img/user_menu_avatar.png'" alt="Avatar"/> + <img class="rounded-circle oe_topbar_avatar" t-att-src="_s + '/web/static/src/img/user_menu_avatar.png'" alt="Avatar"/> <span class="oe_topbar_name"/> </a> - <ul class="dropdown-menu" role="menu"> + <div class="dropdown-menu dropdown-menu-right" role="menu"> <t t-call="UserMenu.Actions"/> - </ul> + </div> </li> </t> <t t-name="UserMenu.Actions"> - <li><a role="menuitem" href="#" data-menu="documentation">Documentation</a></li> - <li><a role="menuitem" href="#" data-menu="support">Support</a></li> - <li role="separator" class="divider"/> - <li><a role="menuitem" href="#" data-menu="settings">Preferences</a></li> - <li><a role="menuitem" href="#" data-menu="account">My Odoo.com account</a></li> - <li><a role="menuitem" href="#" data-menu="logout">Log out</a></li> + <a role="menuitem" href="#" data-menu="documentation" class="dropdown-item">Documentation</a> + <a role="menuitem" href="#" data-menu="support" class="dropdown-item">Support</a> + <div role="separator" class="dropdown-divider"/> + <a role="menuitem" href="#" data-menu="settings" class="dropdown-item">Preferences</a> + <a role="menuitem" href="#" data-menu="account" class="dropdown-item">My Odoo.com account</a> + <a role="menuitem" href="#" data-menu="logout" class="dropdown-item">Log out</a> </t> <t t-name="SwitchCompanyMenu"> <li class="o_switch_company_menu"> <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#" aria-label="Dropdown menu" title="Dropdown menu"> - <span t-attf-class="#{widget.isMobile ? 'fa fa-building-o' : 'oe_topbar_name'}"/> <span class="caret"/> + <span t-attf-class="#{widget.isMobile ? 'fa fa-building-o' : 'oe_topbar_name'}"/> </a> - <ul class="dropdown-menu" role="menu"/> + <div class="dropdown-menu dropdown-menu-right" role="menu"/> </li> </t> <t t-name="EnterpriseUpgrade"> <div class="row" role="status"> - <div class="col-xs-6"> + <div class="col-6"> Get this feature and much more with Odoo Enterprise! <ul class="list-unstyled"> <li><i class="fa fa-check"></i> Access to all Enterprise Apps</li> @@ -1497,8 +1496,8 @@ <li><a href="http://www.odoo.com/editions" target="_blank"><i class="fa fa-plus"></i> And more</a></li> </ul> </div> - <div class="col-xs-6"> - <img class="img-responsive" t-att-src='_s + "/web/static/src/img/enterprise_upgrade.jpg"' draggable="false" alt="Upgrade to enterprise"/> + <div class="col-6"> + <img class="img-fluid" t-att-src='_s + "/web/static/src/img/enterprise_upgrade.jpg"' draggable="false" alt="Upgrade to enterprise"/> </div> </div> </t> @@ -1506,7 +1505,7 @@ <t t-name="BaseSetting.Tabs"> <t t-foreach="tabItems" t-as="tab"> <div class="tab" t-attf-data-key="#{tab.key}" role="tab"> - <div class="icon hidden-xs" t-attf-style="background : url('#{imgurl}') no-repeat center;background-size:contain;"/> <span class="app_name"><t t-esc="tab.string"/></span> + <div class="icon d-none d-md-block" t-attf-style="background : url('#{imgurl}') no-repeat center;background-size:contain;"/> <span class="app_name"><t t-esc="tab.string"/></span> </div> </t> </t> @@ -1519,9 +1518,9 @@ </t> <t t-name="AttachDocument"> - <button class="btn btn-sm btn-default o_attachment_button"> + <button class="btn btn-secondary o_attachment_button"> <span class="o_attach_document"><t t-esc="widget.node.attrs.string"/></span> - <span class="hide"> + <span class="d-none"> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileuploadID"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> diff --git a/addons/web/static/src/xml/dialog.xml b/addons/web/static/src/xml/dialog.xml index e55a17f26ef..955deb0e7c8 100644 --- a/addons/web/static/src/xml/dialog.xml +++ b/addons/web/static/src/xml/dialog.xml @@ -7,8 +7,8 @@ <div class="modal-dialog"> <div class="modal-content"> <header class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-label="Close" tabindex="-1">×</button> <h4 class="modal-title"><t t-raw="title"/><span class="o_subtitle text-muted small"><t t-esc="subtitle"/></span></h4> + <button type="button" class="close" data-dismiss="modal" aria-label="Close" tabindex="-1">×</button> </header> <main class="modal-body"/> <footer class="modal-footer"/> diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml index 4b62f52cda8..e95c91e1998 100644 --- a/addons/web/static/src/xml/kanban.xml +++ b/addons/web/static/src/xml/kanban.xml @@ -2,7 +2,7 @@ <t t-name="KanbanView.buttons"> <div> - <button type="button" t-attf-class="btn #{btnClass} btn-sm o-kanban-button-new" accesskey="c"> + <button type="button" t-attf-class="btn #{btnClass} o-kanban-button-new" accesskey="c"> <t t-esc="create_text || _t('Create')"/> </button> </div> @@ -16,18 +16,18 @@ <span t-attf-id="#kanban_header_#{widget.id or widget.db_id}" class="o_column_title"><t t-esc="widget.title"/></span> <span class="o_column_unfold"><i class="fa fa-arrows-h" role="img" aria-label="Unfold" title="Unfold"/></span> <span class="o_kanban_config dropdown"> - <a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-gear" role="img" aria-label="Settings" title="Settings"/></a> - <ul class="dropdown-menu" role="menu"> - <li><a role="menuitem" class="o_kanban_toggle_fold" href="#">Fold</a></li> + <a class="dropdown-toggle o-no-caret" data-toggle="dropdown" href="#"><i class="fa fa-gear" role="img" aria-label="Settings" title="Settings"/></a> + <div class="dropdown-menu" role="menu"> + <a role="menuitem" class="dropdown-item o_kanban_toggle_fold" href="#">Fold</a> <t t-if="widget.grouped_by_m2o"> - <li t-if="widget.editable and widget.id"><a role="menuitem" class="o_column_edit" href="#">Edit Stage</a></li> - <li t-if="widget.deletable and widget.id"><a role="menuitem" class="o_column_delete" href="#">Delete</a></li> + <a t-if="widget.editable and widget.id" role="menuitem" class="dropdown-item o_column_edit" href="#">Edit Stage</a> + <a t-if="widget.deletable and widget.id" role="menuitem" class="dropdown-item o_column_delete" href="#">Delete</a> </t> <t t-if="widget.has_active_field"> - <li><a class="o_column_archive_records" href="#">Archive All</a></li> - <li><a class="o_column_unarchive_records" href="#">Unarchive All</a></li> + <a href="#" class="dropdown-item o_column_archive_records">Archive All</a> + <a href="#" class="dropdown-item o_column_unarchive_records">Unarchive All</a> </t> - </ul> + </div> </span> <span t-if="widget.quick_create" class="o_kanban_quick_add"><i class="fa fa-plus" role="img" aria-label="Quick add" title="Quick add"/></span> </div> @@ -51,15 +51,15 @@ <div class="o_quick_create_unfolded"> <div class="o_kanban_header"> <div class="input-group"> - <input type="text" class="o_input" placeholder="Column title"/> - <span class="input-group-btn"> - <button class="btn btn-sm btn-primary o_kanban_add" type="button">Add</button> + <input type="text" class="form-control o_input" placeholder="Column title"/> + <span class="input-group-append"> + <button class="btn btn-primary o_kanban_add" type="button">Add</button> </span> </div> <t t-if="widget.examples"> <a href="#" role="button" class="btn-link o_kanban_examples">Examples</a> </t> - <span class="o_discard_msg text-muted pull-right">Esc to discard</span> + <span class="o_discard_msg text-muted float-right">Esc to discard</span> </div> <div class="o_kanban_muted_record"/> <div class="o_kanban_muted_record"/> @@ -70,9 +70,9 @@ <t t-name="KanbanView.RecordQuickCreate.buttons"> <div> - <button class="btn btn-sm btn-primary o_kanban_add">Add</button> - <button class="btn btn-sm btn-primary o_kanban_edit">Edit</button> - <button class="btn btn-sm btn-default o_kanban_cancel ml8">Discard</button> + <button class="btn btn-primary o_kanban_add">Add</button> + <button class="btn btn-primary o_kanban_edit">Edit</button> + <button class="btn btn-secondary o_kanban_cancel ml8">Discard</button> </div> </t> @@ -124,10 +124,10 @@ <!-- Note: this dialog isn't responsive, but it is not accessible on mobile --> <div t-name="KanbanView.ExamplesDialog" class="o_kanban_examples_dialog"> <div class="o_kanban_examples_dialog_nav"> - <ul class="nav nav-pills nav-stacked"> + <ul class="nav nav-pills flex-column"> <t t-foreach="examples" t-as="example"> - <li t-att-class="example_index == 0 and 'active' or None"> - <a t-attf-aria-controls="example_#{example_index}" data-toggle="tab" role="tab" t-attf-href="#example_#{example_index}"> <t t-esc="example.name"/> </a> + <li class="nav-item"> + <a t-attf-aria-controls="example_#{example_index}" data-toggle="tab" role="tab" t-attf-href="#example_#{example_index}" t-attf-class="nav-link#{example_index == 0 and ' active' or ''}"> <t t-esc="example.name"/> </a> </li> </t> </ul> @@ -158,7 +158,7 @@ <div class="o_kanban_examples_ghost"> <div class="o_ghost_content"/> <div class="o_ghost_content o_ghost_tag"/> - <img class="pull-right o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/> + <img class="float-right o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/> </div> </t> diff --git a/addons/web/static/src/xml/report.xml b/addons/web/static/src/xml/report.xml index c578add8ce9..49313e8de5a 100644 --- a/addons/web/static/src/xml/report.xml +++ b/addons/web/static/src/xml/report.xml @@ -8,14 +8,14 @@ <!-- Buttons of the Control Panel --> <t t-name="report.client_action.ControlButtons"> <div class="o_report_no_edit_mode"> - <button type="button" class="btn btn-primary btn-sm o_report_print" title="Print">Print</button> + <button type="button" class="btn btn-primary o_report_print" title="Print">Print</button> </div> <div class="o_edit_mode_available"> - <button type="button" class="btn btn-default btn-sm o_report_edit" title="Edit">Edit</button> + <button type="button" class="btn btn-secondary o_report_edit" title="Edit">Edit</button> </div> <div class="o_report_edit_mode"> - <button type="button" class="btn btn-primary btn-sm o_report_save" title="Save">Save</button> - <button type="button" class="btn btn-default btn-sm o_report_discard" title="Discard">Discard</button> + <button type="button" class="btn btn-primary o_report_save" title="Save">Save</button> + <button type="button" class="btn btn-secondary o_report_discard" title="Discard">Discard</button> </div> </t> </template>
\ No newline at end of file diff --git a/addons/web/static/src/xml/web_calendar.xml b/addons/web/static/src/xml/web_calendar.xml index 41f772cd52f..3f32dcbd173 100644 --- a/addons/web/static/src/xml/web_calendar.xml +++ b/addons/web/static/src/xml/web_calendar.xml @@ -4,7 +4,7 @@ <div class="o_calendar_buttons" role="toolbar" aria-label="Calendar toolbar"/> <div class="o_calendar_widget" /> </div> - <div class="o_calendar_sidebar_container hidden-xs"> + <div class="o_calendar_sidebar_container d-none d-md-block"> <i class="o_calendar_sidebar_toggler fa"/> <div class="o_calendar_sidebar"> <div class="o_calendar_mini"/> @@ -21,7 +21,7 @@ <div t-attf-class="o_field_#{name} o_field_type_#{fields[name].type}"> <t t-if="widget.displayFields[name].avatar_field"> <t t-if="!isMobile"><t t-esc="fields[name].string"/>:</t> - <div class="o_calendar_avatars pull-right"> + <div class="o_calendar_avatars float-right"> <t t-foreach="widget.getAvatars(record, name, widget.displayFields[name].avatar_field).slice(0,3)" t-as="image"><t t-raw="image"/></t> <span t-if="record[name].length - 3 > 0">+<t t-esc="record[name].length - 3"/></span> </div> @@ -40,22 +40,29 @@ <h3 t-if="widget.title"><t t-esc="widget.title"/></h3> <div class="o_calendar_filter_items"> <div t-foreach="widget.filters" t-as="filter" t-if="filter.display == null || filter.display" class="o_calendar_filter_item" t-att-data-value="filter.value" t-att-data-id="filter.id"> - <div class="o_checkbox"> - <input type="checkbox" name="selection" t-att-checked="(filter.active ? true : undefined)"/><span/> + <div class="custom-control custom-checkbox"> + <input type="checkbox" + t-attf-id="o_calendar_filter_item_#{filter_index}" + name="selection" + class="custom-control-input" + t-att-checked="(filter.active ? true : undefined)"/> + <label t-attf-for="o_calendar_filter_item_#{filter_index}" + class="custom-control-label"> + <t t-if="filter.value == 'all'"> + <span><i class="fa fa-users fa-fw o_cal_avatar" role="img" aria-label="Avatar" title="Avatar"/></span> + </t> + <t t-if="widget.avatar_field && (filter.value != 'all')"> + <img t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cal_avatar" alt="Avatar"/> + </t> + <t t-set="color" t-value="widget.getColor(filter.color_index)"/> + <span t-if="typeof color === 'number'" t-attf-class="color_filter o_underline_color_#{widget.getColor(filter.color_index)}"><t t-esc="filter.label"/></span> + <span t-elif="color" t-attf-style="border-bottom: 4px solid #{color};"><t t-esc="filter.label"/></span> + <span t-else=""><t t-esc="filter.label"/></span> + </label> </div> - <t t-if="filter.value == 'all'"> - <span><i class="fa fa-users fa-fw o_cal_avatar" role="img" aria-label="Avatar" title="Avatar"/></span> - </t> - <t t-if="widget.avatar_field && (filter.value != 'all')"> - <img t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cal_avatar" alt="Avatar"/> - </t> - <t t-set="color" t-value="widget.getColor(filter.color_index)"/> - <span t-if="typeof color === 'number'" t-attf-class="color_filter o_underline_color_#{widget.getColor(filter.color_index)}"><t t-esc="filter.label"/></span> - <span t-elif="color" t-attf-style="border-bottom: 4px solid #{color};"><t t-esc="filter.label"/></span> - <span t-else=""><t t-esc="filter.label"/></span> <t t-if="filter.id"> <span class="o_remove fa fa-times" title="Remove this favorite from the list" role="img" aria-label="Remove this favorite from the list"/> - </t> + </t> </div> </div> </div> @@ -64,14 +71,14 @@ <t t-name="CalendarView.buttons"> <div class="o_calendar_buttons"> <t t-if="!isMobile"> - <button class="o_calendar_button_prev btn btn-sm btn-primary" aria-label="Previous" title="Previous"><span class="fa fa-arrow-left"/></button> - <button class="o_calendar_button_today btn btn-sm btn-primary">Today</button> - <button class="o_calendar_button_next btn btn-sm btn-primary" aria-label="Next" title="Next"><span class="fa fa-arrow-right"/></button> + <button class="o_calendar_button_prev btn btn-primary" aria-label="Previous" title="Previous"><span class="fa fa-arrow-left"/></button> + <button class="o_calendar_button_today btn btn-primary">Today</button> + <button class="o_calendar_button_next btn btn-primary" aria-label="Next" title="Next"><span class="fa fa-arrow-right"/></button> </t> - <div class="btn-group btn-group-sm"> - <button type="button" class="o_calendar_button_day btn btn-sm btn-default">Day</button> - <button type="button" class="o_calendar_button_week btn btn-sm btn-default">Week</button> - <button type="button" class="o_calendar_button_month btn btn-sm btn-default">Month</button> + <div class="btn-group"> + <button type="button" class="o_calendar_button_day btn btn-secondary">Day</button> + <button type="button" class="o_calendar_button_week btn btn-secondary">Week</button> + <button type="button" class="o_calendar_button_month btn btn-secondary">Month</button> </div> </div> </t> @@ -85,7 +92,7 @@ <main t-name="CalendarView.quick_create" class="o_calendar_quick_create"> <div class="form-group"> - <label for='name' class='control-label'>Summary:</label> + <label for='name' class='col-form-label'>Summary:</label> <input type='text' name='name' class="o_input" t-att-value="widget.dataTemplate.name or None"/> </div> </main> |
