diff --git a/addons/web/static/src/js/chrome/menu.js b/addons/web/static/src/js/chrome/menu.js
index 6f2815b670a..3c3530d49e9 100644
--- a/addons/web/static/src/js/chrome/menu.js
+++ b/addons/web/static/src/js/chrome/menu.js
@@ -69,6 +69,7 @@ var Menu = Widget.extend({
// Systray Menu
this.systray_menu = new SystrayMenu(this);
var systrayMenuProm = this.systray_menu.attachTo(this.$('.o_menu_systray')).then(function() {
+ self.systray_menu.on_attach_callback(); // At this point, we know we are in the DOM
dom.initAutoMoreMenu(self.$section_placeholder, {
maxWidth: function () {
return self.$el.width() - (self.$menu_apps.outerWidth(true) + self.$menu_brand_placeholder.outerWidth(true) + self.systray_menu.$el.outerWidth(true));
diff --git a/addons/web/static/src/js/chrome/systray_menu.js b/addons/web/static/src/js/chrome/systray_menu.js
index cb292a9b90f..0e25f2566de 100644
--- a/addons/web/static/src/js/chrome/systray_menu.js
+++ b/addons/web/static/src/js/chrome/systray_menu.js
@@ -39,6 +39,11 @@ var SystrayMenu = Widget.extend({
return Promise.all(proms);
});
},
+ on_attach_callback() {
+ this.widgets
+ .filter(widget => widget.on_attach_callback)
+ .forEach(widget => widget.on_attach_callback());
+ },
/**
* Add the instanciated items, using the object located in this.wisgets
*/
diff --git a/addons/web/static/tests/chrome/menu_tests.js b/addons/web/static/tests/chrome/menu_tests.js
new file mode 100644
index 00000000000..c7ce40b16c2
--- /dev/null
+++ b/addons/web/static/tests/chrome/menu_tests.js
@@ -0,0 +1,47 @@
+odoo.define('web.menu_tests', function (require) {
+ "use strict";
+
+ const testUtils = require('web.test_utils');
+ const Menu = require('web.Menu');
+ const SystrayMenu = require('web.SystrayMenu');
+ const Widget = require('web.Widget');
+
+
+ QUnit.module('chrome', {}, function () {
+ QUnit.module('Menu');
+
+ QUnit.test('Systray on_attach_callback is called', async function (assert) {
+ assert.expect(4);
+
+ const parent = testUtils.createParent({});
+
+ // Add some widgets to the systray
+ const Widget1 = Widget.extend({
+ on_attach_callback: () => assert.step('on_attach_callback widget1')
+ });
+ const Widget2 = Widget.extend({
+ on_attach_callback: () => assert.step('on_attach_callback widget2')
+ });
+ SystrayMenu.Items = [Widget1, Widget2]
+
+ testUtils.mock.patch(SystrayMenu, {
+ on_attach_callback: function () {
+ assert.step('on_attach_callback systray');
+ this._super(...arguments);
+ }
+ });
+
+ const menu = new Menu(parent, {children: []});
+ await menu.appendTo($('#qunit-fixture'));
+
+ assert.verifySteps([
+ 'on_attach_callback systray',
+ 'on_attach_callback widget1',
+ 'on_attach_callback widget2',
+ ]);
+ testUtils.mock.unpatch(SystrayMenu);
+ parent.destroy();
+ });
+ });
+
+});
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 39513722b99..62ebfb2d6da 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -723,6 +723,7 @@
+