[IMP] web_editor: optimize selector functions for snippetOptions
Because of cross-browser compatibility concerns, jQuery's selector engine makes using :has selector relatively slow. This is usually acceptable, but in the case of snippet options, some options also need to use :has in their data-target selector, and nested :has selectors' performance degrade exponentially with the level of nesting. Additionaly, jQuery evaluates complex selectors right-to-left, which makes the :not operator quite inefficient. Because of that, this commit removes :has and :not from the conditions that were added at the end of the data-selector, and speeds up the selector by a factor of ~15-40 Lastly, the addDropSelector options was actually unused, and a leftover from the editor revert, as such it has been removed. closes odoo/odoo#50073 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
committed by
qsm-odoo
parent
ee7e75d74b
commit
a814b671ed
@@ -1386,11 +1386,11 @@ var SnippetsMenu = Widget.extend({
|
||||
* See implementation for function details.
|
||||
*
|
||||
* @private
|
||||
* @param {string} include
|
||||
* @param {string} selector
|
||||
* jQuery selector that DOM elements must match to be considered as
|
||||
* potential snippet.
|
||||
* @param {string} exclude
|
||||
* jQuery selector that DOM elements must *not* match the be
|
||||
* jQuery selector that DOM elements must *not* match to be
|
||||
* considered as potential snippet.
|
||||
* @param {string|false} target
|
||||
* jQuery selector that at least one child of a DOM element must
|
||||
@@ -1403,46 +1403,33 @@ var SnippetsMenu = Widget.extend({
|
||||
* considered (@see noCheck), this is true if the DOM elements'
|
||||
* parent must also be in an editable environment to be considered.
|
||||
*/
|
||||
_computeSelectorFunctions: function (include, exclude, target, noCheck, isChildren) {
|
||||
_computeSelectorFunctions: function (selector, exclude, target, noCheck, isChildren) {
|
||||
var self = this;
|
||||
|
||||
// Convert the selector for elements to include into a list
|
||||
var selectorList = _.compact(include.split(/\s*,\s*/));
|
||||
exclude += `${exclude && ', '}.o_snippet_not_selectable`;
|
||||
|
||||
// Convert the selector for elements to exclude into a list
|
||||
var excludeList = _.compact(exclude.split(/\s*,\s*/));
|
||||
excludeList.push('.o_snippet_not_selectable');
|
||||
|
||||
// Prepare the condition that will be added to each subselector for
|
||||
// elements to include: 'not the elements to exclude and only the
|
||||
// editable ones if needed'
|
||||
var selectorConditions = _.map(excludeList, function (exc) {
|
||||
return ':not(' + exc + ')';
|
||||
}).join('');
|
||||
let filterFunc = function () {
|
||||
return !$(this).is(exclude);
|
||||
};
|
||||
if (target) {
|
||||
selectorConditions += ':has(' + target + ')';
|
||||
const oldFilter = filterFunc;
|
||||
filterFunc = function () {
|
||||
return oldFilter.apply(this) && $(this).find(target).length !== 0;
|
||||
};
|
||||
}
|
||||
if (!noCheck) {
|
||||
selectorConditions = (this.options.addDropSelector || '') + selectorConditions;
|
||||
}
|
||||
|
||||
// (Re)join the subselectors
|
||||
var selector = _.map(selectorList, function (s) {
|
||||
return s + selectorConditions;
|
||||
}).join(', ');
|
||||
|
||||
// Prepare the functions
|
||||
var functions = {
|
||||
is: function ($from) {
|
||||
return $from.is(selector);
|
||||
return $from.is(selector) && $from.filter(filterFunc).length !== 0;
|
||||
},
|
||||
};
|
||||
if (noCheck) {
|
||||
functions.closest = function ($from, parentNode) {
|
||||
return $from.closest(selector, parentNode);
|
||||
return $from.closest(selector, parentNode).filter(filterFunc);
|
||||
};
|
||||
functions.all = function ($from) {
|
||||
return $from ? dom.cssFind($from, selector) : $(selector);
|
||||
return ($from ? dom.cssFind($from, selector) : $(selector)).filter(filterFunc);
|
||||
};
|
||||
} else {
|
||||
functions.closest = function ($from, parentNode) {
|
||||
@@ -1456,13 +1443,13 @@ var SnippetsMenu = Widget.extend({
|
||||
node = node.parentNode;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}).filter(filterFunc);
|
||||
};
|
||||
functions.all = isChildren ? function ($from) {
|
||||
return dom.cssFind($from || self.getEditableArea(), selector);
|
||||
return dom.cssFind($from || self.getEditableArea(), selector).filter(filterFunc);
|
||||
} : function ($from) {
|
||||
$from = $from || self.getEditableArea();
|
||||
return $from.filter(selector).add(dom.cssFind($from, selector));
|
||||
return $from.filter(selector).add(dom.cssFind($from, selector)).filter(filterFunc);
|
||||
};
|
||||
}
|
||||
return functions;
|
||||
|
||||
Reference in New Issue
Block a user