Skip to content
Browse files

[FIX] web, website: adapt menu loading to jQuery 3

Javascript is responsible of showing the menu, potentially with some
parts regrouped in an extra dropdown, on page load (this is what we
call the "autohide" feature). This was done on both the menu and the
affix menu. It worked on the affix menu because the affix menu widget
was initialized before (by luck: alphabetical order).

Since the jQuery 3 update bb004e3
deferred are always delayed (even if their resolve condition is met on
creation). This made the animations to be initialized in the same order
as before but their 'start' method to be delayed (as the willStart was
delayed). So what happened before was:

1) Find menus to enable affix
2) Enable affix on found menus (duplicate the menus to do that)
3) Find menus to enable autohide
4) Enable autohide on found menus (both the menu and the duplicated one
   were found)

And since jQuery 3:

1) Find menus to enable affix
2) Find menus to enable autohide
3) Enable affix on found menus (duplicate the menus to do that)
4) Enable autohide on found menus (the duplicated one was not found at
   step 2 since it did not exist yet)

In fact, widget starting should never have relied on alphabetical order.
The fix only consists of starting widgets on the duplicated menu once it
is ready. This is what this commit does.

However, doing this revealed another bug: if the widgets are started
only for a DOM portion like a '.a' element, a widget with a multiple
parts selector like a '.a .b' selector will not be considered, as
searching inside a '.a' element will not allow to match elements with
a selector containing a '.a'. This is in fact not really a "bug" but a
limitation, so unless we get problems because of this in stable
versions, we can only "fix" this for the current saas. This is fixed
thanks to `dom.cssFind` which already existed. This commit however
improves it to try making it more efficient.
  • Loading branch information...
qsm-odoo committed Apr 5, 2019
1 parent 8c37747 commit d156b0b07f8541501c146907098944e7f309fc92
@@ -153,10 +153,26 @@ var dom = {
* @param {jQuery} $from - the jQuery element(s) from which to search
* @param {string} selector - the CSS selector to match
* @param {boolean} [addBack=false] - whether or not the $from element
* should be considered in the results
* @returns {jQuery}
cssFind: function ($from, selector) {
return $from.find('*').filter(selector);
cssFind: function ($from, selector, addBack) {
var $results;

var parts = selector.split(' ');
if (parts.length > 1) {
var lastPart = parts[parts.length - 1];
$results = $from.find(lastPart).filter(selector);
} else {
$results = $from.find(selector);

if (addBack && $ {
$results = $results.add($from);

return $results;
* Detaches widgets from the DOM and performs their on_detach_callback()
@@ -2,6 +2,7 @@ odoo.define('web.public.root', function (require) {
'use strict';

var ajax = require('web.ajax');
var dom = require('web.dom');
var ServiceProviderMixin = require('web.ServiceProviderMixin');
var session = require('web.session');
var utils = require('web.utils');
@@ -199,7 +200,7 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {

var defs =, function (PublicWidget) {
var selector = PublicWidget.prototype.selector || '';
var $target = $from.find(selector).addBack(selector);
var $target = dom.cssFind($from, selector, true);

var defs =$target, function (el) {
var widget = new PublicWidget(self, options);
@@ -39,7 +39,11 @@ publicWidget.registry.affixMenu = publicWidget.Widget.extend({
$(window).on('resize.affixMenu scroll.affixMenu', _.throttle(this._onWindowUpdate.bind(this), 200));
setTimeout(this._onWindowUpdate.bind(this), 0); // setTimeout to allow override with advanced stuff... see themes

return def;
return def.then(function () {
self.trigger_up('widgets_start_request', {
$target: self.$headerClone,
* @override

0 comments on commit d156b0b

Please sign in to comment.
You can’t perform that action at this time.