diff --git a/web_responsive/static/src/css/web_responsive.scss b/web_responsive/static/src/css/web_responsive.scss index 4ff2cb32c..0c5b162d2 100644 --- a/web_responsive/static/src/css/web_responsive.scss +++ b/web_responsive/static/src/css/web_responsive.scss @@ -42,8 +42,7 @@ $chatter_zone_width: 35%; } .o_menu_sections, - .o_menu_systray, - { + .o_menu_systray { padding: 0; } } @@ -56,8 +55,7 @@ $chatter_zone_width: 35%; // Hide big things .o_menu_brand, .o_menu_sections, - .oe_topbar_name, - { + .oe_topbar_name { display: none; } @@ -85,8 +83,7 @@ $chatter_zone_width: 35%; > li, .o_menu_entry_lvl_1, - .o_menu_header_lvl_1, - { + .o_menu_header_lvl_1 { // Homogeneous background color background-color: $dropdown-bg; color: $dropdown-link-color; @@ -137,7 +134,6 @@ $chatter_zone_width: 35%; // Iconized full screen apps menu .o_menu_apps { - .search-input:focus { border-color: $o-brand-primary; } @@ -238,8 +234,7 @@ html .o_web_client .o_action_manager .o_action { .o_cp_buttons, .o_cp_left, .o_cp_right, - .o_cp_searchview, - { + .o_cp_searchview { flex: 1 1 100%; @include media-breakpoint-up(md) { flex-basis: 50%; @@ -251,8 +246,7 @@ html .o_web_client .o_action_manager .o_action { } .o_cp_searchview, - .o_cp_right, - { + .o_cp_right { flex-basis: 10%; } @@ -276,7 +270,7 @@ html .o_web_client .o_action_manager .o_action { padding-right: 0; } - &:nth-last-of-type(1n+3) { + &:nth-last-of-type(1n + 3) { display: none; } @@ -333,7 +327,8 @@ html .o_web_client .o_action_manager .o_action { } // Normal views -.o_content, .modal-content { +.o_content, +.modal-content { max-width: 100%; // Form views @@ -380,14 +375,13 @@ html .o_web_client .o_action_manager .o_action { .oe_button_box { .o_dropdown_more { button:last-child { - border-right: 1px solid gray('400'); + border-right: 1px solid gray("400"); } } } // Avoid overflow on forms with title and/or button box - .oe_title, - { + .oe_title { max-width: 100%; } @@ -442,8 +436,7 @@ html .o_web_client .o_action_manager .o_action { // Full width in form sheets .o_form_sheet, - .oe_chatter, - { + .oe_chatter { min-width: auto; max-width: 98%; } @@ -460,7 +453,7 @@ html .o_web_client .o_action_manager .o_action { // Display send button on small screens .o_thread_composer { - padding-left: $o-mail-thread-avatar-size*0.5; + padding-left: $o-mail-thread-avatar-size * 0.5; .o_composer_button_send { display: initial !important; // Forced in core @@ -508,7 +501,7 @@ html .o_web_client .o_action_manager .o_action { } .o_chatter { - border-left: 1px solid gray('400'); + border-left: 1px solid gray("400"); flex: 0 0 $chatter_zone_width; max-width: initial; min-width: initial; @@ -544,10 +537,11 @@ html .o_web_client .o_action_manager .o_action { // Sticky Header & Footer in List View .o_list_view { - .table-responsive { + .table-responsive { .o_list_table { // th & td are here for compatibility with chrome - thead, thead tr:nth-child(1) th { + thead, + thead tr:nth-child(1) th { position: sticky; top: 0; z-index: 1; @@ -555,7 +549,8 @@ html .o_web_client .o_action_manager .o_action { thead tr:nth-child(1) th { background-color: $o-list-footer-bg-color; } - tfoot, tfoot tr:nth-child(1) td { + tfoot, + tfoot tr:nth-child(1) td { position: sticky; bottom: 0; } @@ -568,7 +563,7 @@ html .o_web_client .o_action_manager .o_action { // Waiting Cursor .oe_wait { - cursor: progress; + cursor: progress; } // Document Viewer @@ -585,10 +580,12 @@ html .o_web_client .o_action_manager .o_action { right: 0; /* Show/Hide control buttons (next, prev, etc..) */ - &:hover .arrow, &:hover .o_viewer_toolbar { + &:hover .arrow, + &:hover .o_viewer_toolbar { display: flex; } - .arrow, .o_viewer_toolbar { + .arrow, + .o_viewer_toolbar { display: none; } @@ -611,7 +608,8 @@ html .o_web_client .o_action_manager .o_action { } } @include media-breakpoint-down(lg) { - .o_minimize_btn, .o_maximize_btn { + .o_minimize_btn, + .o_maximize_btn { display: none; } } @@ -619,7 +617,8 @@ html .o_web_client .o_action_manager .o_action { } /* Max/Min buttons only are usefull in sided mode */ .o_web_client:not(.o_chatter_position_sided) { - .o_minimize_btn, .o_maximize_btn { + .o_minimize_btn, + .o_maximize_btn { display: none; } } diff --git a/web_responsive/static/src/js/web_responsive.js b/web_responsive/static/src/js/web_responsive.js index 6285d1282..aa9a1de35 100644 --- a/web_responsive/static/src/js/web_responsive.js +++ b/web_responsive/static/src/js/web_responsive.js @@ -1,28 +1,28 @@ /* Copyright 2018 Tecnativa - Jairo Llopis * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ -odoo.define('web_responsive', function (require) { - 'use strict'; +odoo.define("web_responsive", function(require) { + "use strict"; - const ActionManager = require('web.ActionManager'); + const ActionManager = require("web.ActionManager"); const AbstractWebClient = require("web.AbstractWebClient"); const AppsMenu = require("web.AppsMenu"); - const BasicController = require('web.BasicController'); + const BasicController = require("web.BasicController"); const config = require("web.config"); const core = require("web.core"); - const FormRenderer = require('web.FormRenderer'); + const FormRenderer = require("web.FormRenderer"); const Menu = require("web.Menu"); - const RelationalFields = require('web.relational_fields'); - const Chatter = require('mail.Chatter'); - const ListRenderer = require('web.ListRenderer'); - const DocumentViewer = require('mail.DocumentViewer'); + const RelationalFields = require("web.relational_fields"); + const Chatter = require("mail.Chatter"); + const ListRenderer = require("web.ListRenderer"); + const DocumentViewer = require("mail.DocumentViewer"); /* * Helper function to know if are waiting * */ - function isWaiting () { - return $('.oe_wait').length !== 0; + function isWaiting() { + return $(".oe_wait").length !== 0; } /** @@ -70,7 +70,7 @@ odoo.define('web_responsive', function (require) { * } * ``` */ - function findNames (memo, menu) { + function findNames(memo, menu) { if (menu.action) { var key = menu.parent_id ? menu.parent_id[1] + "/" : ""; memo[key + menu.name] = menu; @@ -82,33 +82,31 @@ odoo.define('web_responsive', function (require) { } AppsMenu.include({ - events: _.extend({ - "keydown .search-input input": "_searchResultsNavigate", - "input .search-input input": "_searchMenusSchedule", - "click .o-menu-search-result": "_searchResultChosen", - "shown.bs.dropdown": "_searchFocus", - "hidden.bs.dropdown": "_searchReset", - "hide.bs.dropdown": "_hideAppsMenu", - }, AppsMenu.prototype.events), + events: _.extend( + { + "keydown .search-input input": "_searchResultsNavigate", + "input .search-input input": "_searchMenusSchedule", + "click .o-menu-search-result": "_searchResultChosen", + "shown.bs.dropdown": "_searchFocus", + "hidden.bs.dropdown": "_searchReset", + "hide.bs.dropdown": "_hideAppsMenu", + }, + AppsMenu.prototype.events + ), /** * Rescue some menu data stripped out in original method. * * @override */ - init: function (parent, menuData) { + init: function(parent, menuData) { this._super.apply(this, arguments); // Keep base64 icon for main menus - for (let n in this._apps) { - this._apps[n].web_icon_data = - menuData.children[n].web_icon_data; + for (const n in this._apps) { + this._apps[n].web_icon_data = menuData.children[n].web_icon_data; } // Store menu data in a format searchable by fuzzy.js - this._searchableMenus = _.reduce( - menuData.children, - findNames, - {} - ); + this._searchableMenus = _.reduce(menuData.children, findNames, {}); // Search only after timeout, for fast typers this._search_def = false; }, @@ -116,7 +114,7 @@ odoo.define('web_responsive', function (require) { /** * @override */ - start: function () { + start: function() { this.$search_container = this.$(".search-container"); this.$search_input = this.$(".search-input input"); this.$search_results = this.$(".search-results"); @@ -128,7 +126,7 @@ odoo.define('web_responsive', function (require) { * * @override */ - _onAppsMenuItemClicked: function (ev) { + _onAppsMenuItemClicked: function(ev) { this._super.apply(this, arguments); ev.preventDefault(); }, @@ -142,17 +140,20 @@ odoo.define('web_responsive', function (require) { * @returns {Object} * Menu definition, plus extra needed keys. */ - _menuInfo: function (key) { + _menuInfo: function(key) { const original = this._searchableMenus[key]; - return _.extend({ - action_id: parseInt(original.action.split(',')[1], 10), - }, original); + return _.extend( + { + action_id: parseInt(original.action.split(",")[1], 10), + }, + original + ); }, /** * Autofocus on search field on big screens. */ - _searchFocus: function () { + _searchFocus: function() { if (!config.device.isMobile) { this.$search_input.focus(); } @@ -161,7 +162,7 @@ odoo.define('web_responsive', function (require) { /** * Reset search input and results */ - _searchReset: function () { + _searchReset: function() { this.$search_container.removeClass("has-results"); this.$search_results.empty(); this.$search_input.val(""); @@ -170,8 +171,8 @@ odoo.define('web_responsive', function (require) { /** * Schedule a search on current menu items. */ - _searchMenusSchedule: function () { - this._search_def = new Promise((resolve) => { + _searchMenusSchedule: function() { + this._search_def = new Promise(resolve => { setTimeout(resolve, 50); }); this._search_def.then(this._searchMenus.bind(this)); @@ -180,33 +181,23 @@ odoo.define('web_responsive', function (require) { /** * Search among available menu items, and render that search. */ - _searchMenus: function () { + _searchMenus: function() { const query = this.$search_input.val(); if (query === "") { this.$search_container.removeClass("has-results"); this.$search_results.empty(); return; } - var results = fuzzy.filter( - query, - _.keys(this._searchableMenus), - { - pre: "", - post: "", - } - ); - this.$search_container.toggleClass( - "has-results", - Boolean(results.length) - ); + var results = fuzzy.filter(query, _.keys(this._searchableMenus), { + pre: "", + post: "", + }); + this.$search_container.toggleClass("has-results", Boolean(results.length)); this.$search_results.html( - core.qweb.render( - "web_responsive.MenuSearchResults", - { - results: results, - widget: this, - } - ) + core.qweb.render("web_responsive.MenuSearchResults", { + results: results, + widget: this, + }) ); }, @@ -215,7 +206,7 @@ odoo.define('web_responsive', function (require) { * * @param {jQuery.Event} event */ - _searchResultChosen: function (event) { + _searchResultChosen: function(event) { event.preventDefault(); event.stopPropagation(); const $result = $(event.currentTarget), @@ -229,7 +220,7 @@ odoo.define('web_responsive', function (require) { previous_menu_id: data.parentId, }); // Find app that owns the chosen menu - const app = _.find(this._apps, function (_app) { + const app = _.find(this._apps, function(_app) { return text.indexOf(_app.name + suffix) === 0; }); // Update navbar menus @@ -241,7 +232,7 @@ odoo.define('web_responsive', function (require) { * * @param {jQuery.Event} event */ - _searchResultsNavigate: function (event) { + _searchResultsNavigate: function(event) { // Find current results and active element (1st by default) const all = this.$search_results.find(".o-menu-search-result"), pre_focused = all.filter(".active") || $(all[0]); @@ -257,20 +248,20 @@ odoo.define('web_responsive', function (require) { key = event.shiftKey ? "ArrowUp" : "ArrowDown"; } switch (key) { - // Pressing enter is the same as clicking on the active element - case "Enter": - pre_focused.click(); - break; - // Navigate up or down - case "ArrowUp": - offset--; - break; - case "ArrowDown": - offset++; - break; - default: - // Other keys are useless in this event - return; + // Pressing enter is the same as clicking on the active element + case "Enter": + pre_focused.click(); + break; + // Navigate up or down + case "ArrowUp": + offset--; + break; + case "ArrowDown": + offset++; + break; + default: + // Other keys are useless in this event + return; } // Allow looping on results if (offset < 0) { @@ -290,44 +281,45 @@ odoo.define('web_responsive', function (require) { }, /* - * Control if AppDrawer can be closed - */ - _hideAppsMenu: function () { - return !isWaiting() && !this.$('input').is(':focus'); + * Control if AppDrawer can be closed + */ + _hideAppsMenu: function() { + return !isWaiting() && !this.$("input").is(":focus"); }, }); BasicController.include({ - /** * Close the AppDrawer if the data set is dirty and a discard dialog * is opened * * @override */ - canBeDiscarded: function (recordID) { + canBeDiscarded: function(recordID) { if (this.model.isDirty(recordID || this.handle)) { - $('.o_menu_apps .dropdown:has(.dropdown-menu.show) > a') - .dropdown('toggle'); - $('.o_menu_sections li.show .dropdown-toggle') - .dropdown('toggle'); + $(".o_menu_apps .dropdown:has(.dropdown-menu.show) > a").dropdown( + "toggle" + ); + $(".o_menu_sections li.show .dropdown-toggle").dropdown("toggle"); } return this._super.apply(this, arguments); }, }); Menu.include({ - events: _.extend({ - // Clicking a hamburger menu item should close the hamburger - "click .o_menu_sections [role=menuitem]": "_hideMobileSubmenus", - // Opening any dropdown in the navbar should hide the hamburger - "show.bs.dropdown .o_menu_systray, .o_menu_apps": - "_hideMobileSubmenus", - // Prevent close section menu - "hide.bs.dropdown .o_menu_sections": "_hideMenuSection", - }, Menu.prototype.events), + events: _.extend( + { + // Clicking a hamburger menu item should close the hamburger + "click .o_menu_sections [role=menuitem]": "_hideMobileSubmenus", + // Opening any dropdown in the navbar should hide the hamburger + "show.bs.dropdown .o_menu_systray, .o_menu_apps": "_hideMobileSubmenus", + // Prevent close section menu + "hide.bs.dropdown .o_menu_sections": "_hideMenuSection", + }, + Menu.prototype.events + ), - start: function () { + start: function() { this.$menu_toggle = this.$(".o-menu-toggle"); return this._super.apply(this, arguments); }, @@ -335,7 +327,7 @@ odoo.define('web_responsive', function (require) { /** * Hide menus for current app if you're in mobile */ - _hideMobileSubmenus: function () { + _hideMobileSubmenus: function() { if ( this.$menu_toggle.is(":visible") && this.$section_placeholder.is(":visible") && @@ -350,7 +342,7 @@ odoo.define('web_responsive', function (require) { * * @returns {Boolean} */ - _hideMenuSection: function () { + _hideMenuSection: function() { return !isWaiting(); }, @@ -359,7 +351,7 @@ odoo.define('web_responsive', function (require) { * * @override */ - _updateMenuBrand: function () { + _updateMenuBrand: function() { if (!config.device.isMobile) { return this._super.apply(this, arguments); } @@ -370,7 +362,7 @@ odoo.define('web_responsive', function (require) { * * @override */ - _onMouseOverMenu: function () { + _onMouseOverMenu: function() { if (!isWaiting()) { this._super.apply(this, arguments); } @@ -378,16 +370,15 @@ odoo.define('web_responsive', function (require) { }); RelationalFields.FieldStatus.include({ - /** * Fold all on mobiles. * * @override */ - _setState: function () { + _setState: function() { this._super.apply(this, arguments); if (config.device.isMobile) { - _.map(this.status_information, (value) => { + _.map(this.status_information, value => { value.fold = true; }); } @@ -396,19 +387,20 @@ odoo.define('web_responsive', function (require) { // Sticky Column Selector ListRenderer.include({ - _renderView: function () { + _renderView: function() { const self = this; return this._super.apply(this, arguments).then(() => { const $col_selector = self.$el.find( - '.o_optional_columns_dropdown_toggle'); + ".o_optional_columns_dropdown_toggle" + ); if ($col_selector.length !== 0) { - const $th = self.$el.find('thead>tr:first>th:last'); + const $th = self.$el.find("thead>tr:first>th:last"); $col_selector.appendTo($th); } }); }, - _onToggleOptionalColumnDropdown: function (ev) { + _onToggleOptionalColumnDropdown: function(ev) { // FIXME: For some strange reason the 'stopPropagation' call // in the main method don't work. Invoking here the same method // does the expected behavior... O_O! @@ -421,13 +413,12 @@ odoo.define('web_responsive', function (require) { // Responsive view "action" buttons FormRenderer.include({ - /** * In mobiles, put all statusbar buttons in a dropdown. * * @override */ - _renderHeaderButtons: function () { + _renderHeaderButtons: function() { const $buttons = this._super.apply(this, arguments); if ( !config.device.isMobile || @@ -438,9 +429,9 @@ odoo.define('web_responsive', function (require) { // $buttons must be appended by JS because all events are bound $buttons.addClass("dropdown-menu"); - const $dropdown = $(core.qweb.render( - 'web_responsive.MenuStatusbarButtons' - )); + const $dropdown = $( + core.qweb.render("web_responsive.MenuStatusbarButtons") + ); $buttons.addClass("dropdown-menu").appendTo($dropdown); return $dropdown; }, @@ -448,10 +439,12 @@ odoo.define('web_responsive', function (require) { // Chatter Hide Composer Chatter.include({ - _openComposer: function (options) { - if (this._composer && - options.isLog === this._composer.options.isLog && - this._composer.$el.is(':visible')) { + _openComposer: function(options) { + if ( + this._composer && + options.isLog === this._composer.options.isLog && + this._composer.$el.is(":visible") + ) { this._closeComposer(false); } else { this._super.apply(this, arguments); @@ -461,37 +454,43 @@ odoo.define('web_responsive', function (require) { // Hide AppDrawer or Menu when the action has been completed ActionManager.include({ - /** - * Because the menu aren't closed when click, this method - * searchs for the menu with the action executed to close it. - * To avoid delays in pages with a lot of DOM nodes we make - * 'sub-groups' with 'querySelector' to improve the performance. - * - * @param {action} action - * The executed action - */ - _hideMenusByAction: function (action) { - const uniq_sel = '[data-action-id='+action.id+']'; + * Because the menu aren't closed when click, this method + * searchs for the menu with the action executed to close it. + * To avoid delays in pages with a lot of DOM nodes we make + * 'sub-groups' with 'querySelector' to improve the performance. + * + * @param {action} action + * The executed action + */ + _hideMenusByAction: function(action) { + const uniq_sel = "[data-action-id=" + action.id + "]"; // Need close AppDrawer? - const menu_apps_dropdown = document.querySelector( - '.o_menu_apps .dropdown'); - $(menu_apps_dropdown).has('.dropdown-menu.show') - .has(uniq_sel).find('> a').dropdown('toggle'); + const menu_apps_dropdown = document.querySelector(".o_menu_apps .dropdown"); + $(menu_apps_dropdown) + .has(".dropdown-menu.show") + .has(uniq_sel) + .find("> a") + .dropdown("toggle"); // Need close Sections Menu? - const menu_sections = document.querySelector( - '.o_menu_sections li.show'); - $(menu_sections).has(uniq_sel).find('.dropdown-toggle') - .dropdown('toggle'); + const menu_sections = document.querySelector(".o_menu_sections li.show"); + $(menu_sections) + .has(uniq_sel) + .find(".dropdown-toggle") + .dropdown("toggle"); // Need close Mobile? const menu_sections_mobile = document.querySelector( - '.o_menu_sections.show'); - $(menu_sections_mobile).has(uniq_sel).hide(); + ".o_menu_sections.show" + ); + $(menu_sections_mobile) + .has(uniq_sel) + .hide(); }, - _handleAction: function (action) { - return this._super.apply(this, arguments).finally( - $.proxy(this, '_hideMenusByAction', action)); + _handleAction: function(action) { + return this._super + .apply(this, arguments) + .finally($.proxy(this, "_hideMenusByAction", action)); }, }); @@ -508,7 +507,6 @@ odoo.define('web_responsive', function (require) { * enable this behavior. */ var KeyboardNavigationShiftAltMixin = { - /** * Alter the key event to require pressing Shift. * @@ -526,7 +524,7 @@ odoo.define('web_responsive', function (require) { * @returns {keyEvent} * Altered event object */ - _shiftPressed: function (keyEvent) { + _shiftPressed: function(keyEvent) { const alt = keyEvent.altKey || keyEvent.key === "Alt", newEvent = _.extend({}, keyEvent), shift = keyEvent.shiftKey || keyEvent.key === "Shift"; @@ -540,11 +538,11 @@ odoo.define('web_responsive', function (require) { return newEvent; }, - _onKeyDown: function (keyDownEvent) { + _onKeyDown: function(keyDownEvent) { return this._super(this._shiftPressed(keyDownEvent)); }, - _onKeyUp: function (keyUpEvent) { + _onKeyUp: function(keyUpEvent) { return this._super(this._shiftPressed(keyUpEvent)); }, }; @@ -559,38 +557,38 @@ odoo.define('web_responsive', function (require) { // this.$el is active, but now the modal have buttons that can obtain // the focus. For this reason we now listen core events, that are // dispatched every time. - events: _.extend(_.omit(DocumentViewer.prototype.events, [ - 'keydown', - 'keyup', - ]), { - 'click .o_maximize_btn': '_onClickMaximize', - 'click .o_minimize_btn': '_onClickMinimize', - 'shown.bs.modal': '_onShownModal', - }), + events: _.extend( + _.omit(DocumentViewer.prototype.events, ["keydown", "keyup"]), + { + "click .o_maximize_btn": "_onClickMaximize", + "click .o_minimize_btn": "_onClickMinimize", + "shown.bs.modal": "_onShownModal", + } + ), - start: function () { - core.bus.on('keydown', this, this._onKeydown); - core.bus.on('keyup', this, this._onKeyUp); + start: function() { + core.bus.on("keydown", this, this._onKeydown); + core.bus.on("keyup", this, this._onKeyUp); return this._super.apply(this, arguments); }, - destroy: function () { - core.bus.off('keydown', this, this._onKeydown); - core.bus.off('keyup', this, this._onKeyUp); + destroy: function() { + core.bus.off("keydown", this, this._onKeydown); + core.bus.off("keyup", this, this._onKeyUp); this._super.apply(this, arguments); }, - _onShownModal: function () { + _onShownModal: function() { // Disable auto-focus to allow to use controls in edit mode. // This only affects the active modal. // More info: https://stackoverflow.com/a/14795256 - $(document).off('focusin.modal'); + $(document).off("focusin.modal"); }, - _onClickMaximize: function () { - this.$el.removeClass('o_responsive_document_viewer'); + _onClickMaximize: function() { + this.$el.removeClass("o_responsive_document_viewer"); }, - _onClickMinimize: function () { - this.$el.addClass('o_responsive_document_viewer'); + _onClickMinimize: function() { + this.$el.addClass("o_responsive_document_viewer"); }, }); }); diff --git a/web_responsive/static/src/xml/apps.xml b/web_responsive/static/src/xml/apps.xml index ccde2bec4..ae9595e02 100644 --- a/web_responsive/static/src/xml/apps.xml +++ b/web_responsive/static/src/xml/apps.xml @@ -1,17 +1,18 @@ - + - diff --git a/web_responsive/static/src/xml/document_viewer.xml b/web_responsive/static/src/xml/document_viewer.xml index ea1fe33b2..9339dcbad 100644 --- a/web_responsive/static/src/xml/document_viewer.xml +++ b/web_responsive/static/src/xml/document_viewer.xml @@ -1,11 +1,12 @@ - + -