diff --git a/addons/hr_attendance/static/src/js/attendance.js b/addons/hr_attendance/static/src/js/attendance.js index 692fdc33f50..3ec2ca4709f 100644 --- a/addons/hr_attendance/static/src/js/attendance.js +++ b/addons/hr_attendance/static/src/js/attendance.js @@ -69,25 +69,11 @@ openerp.hr_attendance = function (instance) { }, }); - instance.web.UserMenu.include({ - do_update: function () { - this._super(); - var self = this; - this.update_promise.done(function () { - if (!_.isUndefined(self.attendanceslider)) { - return; - } - // check current user is an employee - var Users = new instance.web.Model('res.users'); - Users.call('has_group', ['base.group_user']).done(function(is_employee) { - if (is_employee) { - self.attendanceslider = new instance.hr_attendance.AttendanceSlider(self); - self.attendanceslider.prependTo(instance.webclient.$('.oe_systray')); - } else { - self.attendanceslider = null; - } - }); - }); - }, - }); + // Put the AttendanceSlider widget in the systray menu if the user is an employee + var Users = new instance.web.Model('res.users'); + Users.call('has_group', ['base.group_user']).done(function(is_employee) { + if (is_employee) { + instance.web.SystrayItems.push(instance.hr_attendance.AttendanceSlider); + } + }) }; diff --git a/addons/im_chat/static/src/js/im_chat.js b/addons/im_chat/static/src/js/im_chat.js index 3ffbbb6ee07..4929fad2050 100644 --- a/addons/im_chat/static/src/js/im_chat.js +++ b/addons/im_chat/static/src/js/im_chat.js @@ -601,31 +601,29 @@ events: { "click": "clicked", }, + start: function() { + // Create the InstantMessaging widget and put it in the DOM + var im = new openerp.im_chat.InstantMessaging(self); + openerp.im_chat.single = im; + im.appendTo(openerp.client.$el); + // Bind the click action to the ImTopButton + this.on("clicked", im, im.switch_display); + return this._super(); + }, clicked: function(ev) { ev.preventDefault(); this.trigger("clicked"); }, }); - if(openerp.web && openerp.web.UserMenu) { - openerp.web.UserMenu.include({ - do_update: function(){ - var self = this; - var Users = new openerp.web.Model('res.users'); - Users.call('has_group', ['base.group_user']).done(function(is_employee) { - if (is_employee) { - self.update_promise.then(function() { - var im = new openerp.im_chat.InstantMessaging(self); - openerp.im_chat.single = im; - im.appendTo(openerp.client.$el); - var button = new openerp.im_chat.ImTopButton(this); - button.on("clicked", im, im.switch_display); - button.appendTo(window.$('.oe_systray')); - }); - } - }); - return this._super.apply(this, arguments); - }, + // Guard: only for the backend + if (openerp.web && openerp.web.Model) { + // Put the ImTopButton widget in the systray menu if the user is an employee + var Users = new openerp.web.Model('res.users'); + Users.call('has_group', ['base.group_user']).done(function(is_employee) { + if (is_employee) { + openerp.web.SystrayItems.push(openerp.im_chat.ImTopButton); + } }); } diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index d99fd5d2f15..59c1eaecd89 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -2077,14 +2077,6 @@ openerp.mail = function (session) { }, }); - session.web.UserMenu.include({ - do_update: function(){ - var self = this; - this._super.apply(this, arguments); - this.update_promise.then(function() { - var mail_button = new session.web.ComposeMessageTopButton(); - mail_button.appendTo(session.webclient.$el.find('.oe_systray')); - }); - }, - }); + // Put the ComposeMessageTopButton widget in the systray menu + session.web.SystrayItems.push(session.web.ComposeMessageTopButton); }; diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 17f07c9cbb9..9c74a3d0c85 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -30,7 +30,7 @@ } #oe_main_menu_navbar .oe_topbar_avatar { max-height: 18px; - width: auto; + width: 18px; } #oe_main_menu_navbar.navbar { diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index f36f25b5181..157fb03d71a 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -153,7 +153,7 @@ $sheet-padding: 16px font-size: 13px .oe_topbar_avatar max-height: 18px - width: auto + width: 18px #oe_main_menu_navbar.navbar margin-bottom: 0px diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index d6dc9382910..5155f106796 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -756,12 +756,39 @@ instance.web.ChangePassword = instance.web.Widget.extend({ }); instance.web.client_actions.add("change_password", "instance.web.ChangePassword"); +instance.web.SystrayItems = []; +instance.web.SystrayMenu = instance.web.Widget.extend({ + /** + * This widget renders the systray menu. It creates and renders widgets + * pushed in instance.web.SystrayItems. + */ + init: function(parent) { + this._super(parent); + this.items = []; + this.load = $.Deferred(); + }, + start: function() { + var self = this; + self._super.apply(this, arguments); + self.load_items(); + return $.when.apply($, self.items).done(function () { + self.load.resolve(); + }); + }, + load_items: function() { + var self = this; + _.each(instance.web.SystrayItems, function(widgetCls) { + var cur_systray_item = new widgetCls(self); + self.items.push(cur_systray_item.appendTo(self.$el)); + }); + }, +}); + instance.web.Menu = instance.web.Widget.extend({ init: function() { var self = this; this._super.apply(this, arguments); this.is_bound = $.Deferred(); - this.maximum_visible_links = 'auto'; // # of menu to show. 0 = do not crop, 'auto' = algo this.data = {data:{children:[]}}; this.on("menu_bound", this, function() { // launch the fetch of needaction counters, asynchronous @@ -791,10 +818,9 @@ instance.web.Menu = instance.web.Widget.extend({ self.open_menu(self.current_menu); } this.trigger('menu_bound'); - var lazyreflow = _.debounce(this.reflow.bind(this), 200); instance.web.bus.on('resize', this, function() { - if (parseInt(self.$el.parent().css('width')) <= 768 ) { + if ($(window).width() < 768 ) { lazyreflow('all_outside'); } else { lazyreflow(); @@ -829,9 +855,8 @@ instance.web.Menu = instance.web.Widget.extend({ * 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 set to - * 'all_inside', all the items are hidden under the more item. If not set, only the - * overflowing items are hidden. + * @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; @@ -843,32 +868,33 @@ instance.web.Menu = instance.web.Widget.extend({ // '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() { - // In all inside mode, we do not compute to know if we must hide the items, we hide them all - if (behavior === 'all_inside') { - return false; - } 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; + if ($(this).width() >= remaining_space) { + return false; // the current item will be appended in more_container } - $(this).show(); + $(this).show(); // show the current item in menu bar }); $more.append($toplevel_items.filter(':hidden').show()); - $more_container.toggle(!!$more.children().length || behavior === 'all_inside'); + $more_container.toggle(!!$more.children().length); // Hide toplevel item if there is only one - var $toplevel = this.$el.children("li:visible"); - if ($toplevel.length === 1 && behavior != 'all_inside') { + var $toplevel = self.$el.children("li:visible"); + if ($toplevel.length === 1) { $toplevel.hide(); } }, @@ -1014,7 +1040,6 @@ instance.web.UserMenu = instance.web.Widget.extend({ }, start: function() { var self = this; - this._super.apply(this, arguments); this.$el.on('click', '.dropdown-menu li a[data-menu]', function(ev) { ev.preventDefault(); var f = self['on_menu_' + $(this).data('menu')]; @@ -1023,6 +1048,7 @@ instance.web.UserMenu = instance.web.Widget.extend({ } }); this.$el.parent().show() + return this._super.apply(this, arguments); }, do_update: function () { var self = this; @@ -1286,15 +1312,24 @@ instance.web.WebClient = instance.web.Client.extend({ this.$('.oe_logo img').click(function(ev) { self.on_logo_click(ev); }); + // Create the user menu (rendered client-side) + self.user_menu = new instance.web.UserMenu(self); + var user_menu_loaded = self.user_menu.appendTo(this.$el.parents().find('.oe_user_menu_placeholder')); + self.user_menu.on('user_logout', self, self.on_logout); + self.user_menu.do_update(); + // Create the systray menu (rendered server-side) + self.systray_menu = new instance.web.SystrayMenu(self); + self.systray_menu.setElement(this.$el.parents().find('.oe_systray')); + var systray_menu_loaded = self.systray_menu.start(); + // Create and render the menu once both systray and user menus are rendered + // to prevent overflows while loading // Menu is rendered server-side thus we don't want the widget to create any dom self.menu = new instance.web.Menu(self); self.menu.setElement(this.$el.parents().find('.oe_application_menu_placeholder')); - self.menu.start(); self.menu.on('menu_click', this, this.on_menu_action); - self.user_menu = new instance.web.UserMenu(self); - self.user_menu.appendTo(this.$el.parents().find('.oe_user_menu_placeholder')); - self.user_menu.on('user_logout', self, self.on_logout); - self.user_menu.do_update(); + $.when(systray_menu_loaded, user_menu_loaded).done(function() { + self.menu.start(); + }); self.bind_hashchange(); self.set_title(); self.check_timezone(); diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index ca87deb85d9..80f42335c13 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -142,7 +142,7 @@