[REF] web: search panel goes ESNext
This commit is contained in:
@@ -6,18 +6,20 @@ odoo.define('web.SearchPanel', function (require) {
|
||||
* filter/manage data easily.
|
||||
*/
|
||||
|
||||
var core = require('web.core');
|
||||
var Domain = require('web.Domain');
|
||||
var pyUtils = require('web.py_utils');
|
||||
var viewUtils = require('web.viewUtils');
|
||||
var Widget = require('web.Widget');
|
||||
const core = require('web.core');
|
||||
const Domain = require('web.Domain');
|
||||
const pyUtils = require('web.py_utils');
|
||||
const { sortBy } = require('web.utils');
|
||||
const viewUtils = require('web.viewUtils');
|
||||
const Widget = require('web.Widget');
|
||||
|
||||
var qweb = core.qweb;
|
||||
const qweb = core.qweb;
|
||||
|
||||
// defaultViewTypes is the list of view types for which the searchpanel is
|
||||
// present by default (if not explicitly stated in the 'view_types' attribute
|
||||
// in the arch)
|
||||
var defaultViewTypes = ['kanban', 'tree'];
|
||||
const defaultViewTypes = ['kanban', 'tree'];
|
||||
let nextSectionId = 1;
|
||||
|
||||
const SEARCH_PANEL_LIMIT = 200;
|
||||
|
||||
@@ -30,19 +32,16 @@ const SEARCH_PANEL_LIMIT = 200;
|
||||
* @returns {Object}
|
||||
*/
|
||||
function _processSearchPanelNode(node, fields) {
|
||||
var sections = {};
|
||||
const sections = {};
|
||||
node.children.forEach((childNode, index) => {
|
||||
if (childNode.tag !== 'field') {
|
||||
if (childNode.tag !== 'field' || childNode.attrs.invisible === "1") {
|
||||
return;
|
||||
}
|
||||
if (childNode.attrs.invisible === "1") {
|
||||
return;
|
||||
}
|
||||
var fieldName = childNode.attrs.name;
|
||||
var type = childNode.attrs.select === 'multi' ? 'filter' : 'category';
|
||||
const fieldName = childNode.attrs.name;
|
||||
const type = childNode.attrs.select === 'multi' ? 'filter' : 'category';
|
||||
|
||||
var sectionId = _.uniqueId('section_');
|
||||
var section = {
|
||||
const sectionId = `section_${nextSectionId++}`;
|
||||
const section = {
|
||||
color: childNode.attrs.color,
|
||||
description: childNode.attrs.string || fields[fieldName].string,
|
||||
fieldName: fieldName,
|
||||
@@ -64,7 +63,7 @@ function _processSearchPanelNode(node, fields) {
|
||||
return sections;
|
||||
}
|
||||
|
||||
var SearchPanel = Widget.extend({
|
||||
const SearchPanel = Widget.extend({
|
||||
className: 'o_search_panel',
|
||||
events: {
|
||||
'click .o_search_panel_category_value header': '_onCategoryValueClicked',
|
||||
@@ -75,7 +74,7 @@ var SearchPanel = Widget.extend({
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @constructor
|
||||
* @param {Object} params
|
||||
* @param {Object} [params.defaultValues={}] the value(s) to activate by
|
||||
* default, for each filter and category
|
||||
@@ -90,22 +89,21 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Object} [params.state] state exported by another searchpanel
|
||||
* instance
|
||||
*/
|
||||
init: function (parent, params) {
|
||||
this._super.apply(this, arguments);
|
||||
init(parent, params) {
|
||||
this._super(...arguments);
|
||||
|
||||
this.categories = _.pick(params.sections, function (section) {
|
||||
return section.type === 'category';
|
||||
});
|
||||
this.filters = _.pick(params.sections, function (section) {
|
||||
return section.type === 'filter';
|
||||
});
|
||||
this.categories = {};
|
||||
this.filters = {};
|
||||
for (const section of Object.values(params.sections)) {
|
||||
const key = section.type === 'category' ? 'categories' : 'filters';
|
||||
this[key][section.id] = section;
|
||||
}
|
||||
|
||||
this.initialState = params.state;
|
||||
this.scrollTop = this.initialState && this.initialState.scrollTop || null;
|
||||
this.defaultValues = params.defaultValues || {};
|
||||
if (params.defaultNoFilter) {
|
||||
Object.keys(this.categories).forEach((categoryId) => {
|
||||
var fieldName = this.categories[categoryId].fieldName;
|
||||
Object.values(this.categories).forEach(({ fieldName }) => {
|
||||
this.defaultValues[fieldName] = this.defaultValues[fieldName] || false;
|
||||
});
|
||||
}
|
||||
@@ -118,38 +116,37 @@ var SearchPanel = Widget.extend({
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
willStart: function () {
|
||||
var self = this;
|
||||
var loadCategoriesProm;
|
||||
async willStart() {
|
||||
const _super = this._super;
|
||||
if (this.initialState) {
|
||||
this.filters = this.initialState.filters;
|
||||
this.categories = this.initialState.categories;
|
||||
} else {
|
||||
loadCategoriesProm = this._fetchCategories().then(function () {
|
||||
return self._fetchFilters().then(self._applyDefaultFilterValues.bind(self));
|
||||
});
|
||||
await this._fetchCategories();
|
||||
await this._fetchFilters();
|
||||
await this._applyDefaultFilterValues();
|
||||
}
|
||||
return Promise.all([loadCategoriesProm, this._super.apply(this, arguments)]);
|
||||
return _super.call(this, ...arguments);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
start() {
|
||||
this._render();
|
||||
return this._super.apply(this, arguments);
|
||||
return this._super(...arguments);
|
||||
},
|
||||
/**
|
||||
* Called each time the searchPanel is attached into the DOM.
|
||||
*/
|
||||
on_attach_callback: function () {
|
||||
on_attach_callback() {
|
||||
if (this.scrollTop !== null) {
|
||||
this.el.scrollTop = this.scrollTop;
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a given search view arch to extract the searchpanel information
|
||||
@@ -163,44 +160,40 @@ var SearchPanel = Widget.extend({
|
||||
* or may not instantiate a SearchPanel.
|
||||
*
|
||||
* @static
|
||||
* @params {Object} viewInfo the viewInfo of a search view
|
||||
* @params {string} viewInfo.arch
|
||||
* @params {Object} viewInfo.fields
|
||||
* @params {string} viewType the type of the current view (e.g. 'kanban')
|
||||
* @returns {Object|undefined}
|
||||
* @param {Object} viewInfo the viewInfo of a search view
|
||||
* @param {string} viewInfo.arch
|
||||
* @param {Object} viewInfo.fields
|
||||
* @param {string} viewType the type of the current view (e.g. 'kanban')
|
||||
* @returns {Object}
|
||||
*/
|
||||
computeSearchPanelParams: function (arch, fields, viewType) {
|
||||
var searchPanelSections;
|
||||
var classes;
|
||||
computeSearchPanelParams(arch, fields, viewType) {
|
||||
const searchPanelParams = {};
|
||||
if (arch && fields) {
|
||||
viewType = viewType === 'list' ? 'tree' : viewType;
|
||||
arch = viewUtils.parseArch(arch);
|
||||
const searchPanelNode = arch.children.find(child => child.tag === 'searchpanel');
|
||||
const parsedArch = viewUtils.parseArch(arch);
|
||||
const searchPanelNode = parsedArch.children.find(child => child.tag === 'searchpanel');
|
||||
if (searchPanelNode) {
|
||||
var attrs = searchPanelNode.attrs;
|
||||
var viewTypes = defaultViewTypes;
|
||||
const { attrs } = searchPanelNode;
|
||||
const type = viewType === 'list' ? 'tree' : viewType;
|
||||
let viewTypes = defaultViewTypes;
|
||||
if (attrs.view_types) {
|
||||
viewTypes = attrs.view_types.split(',');
|
||||
}
|
||||
if (attrs.class) {
|
||||
classes = attrs.class.split(' ');
|
||||
searchPanelParams.classes = attrs.class.split(' ');
|
||||
}
|
||||
if (viewTypes.includes(viewType)) {
|
||||
searchPanelSections = _processSearchPanelNode(searchPanelNode, fields);
|
||||
if (viewTypes.includes(type)) {
|
||||
searchPanelParams.sections = _processSearchPanelNode(searchPanelNode, fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
sections: searchPanelSections,
|
||||
classes: classes,
|
||||
};
|
||||
return searchPanelParams;
|
||||
},
|
||||
/**
|
||||
* Export the current state (categories and filters) of the searchpanel.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
exportState: function () {
|
||||
exportState() {
|
||||
return {
|
||||
categories: this.categories,
|
||||
filters: this.filters,
|
||||
@@ -211,7 +204,7 @@ var SearchPanel = Widget.extend({
|
||||
* @returns {Array[]} the current searchPanel domain based on active
|
||||
* categories and checked filters
|
||||
*/
|
||||
getDomain: function () {
|
||||
getDomain() {
|
||||
return this._getCategoryDomain().concat(this._getFilterDomain());
|
||||
},
|
||||
/**
|
||||
@@ -221,7 +214,7 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Object} state.filters.
|
||||
* @param {Object} state.categories
|
||||
*/
|
||||
importState: function (state) {
|
||||
importState(state) {
|
||||
this.categories = state.categories || this.categories;
|
||||
this.filters = state.filters || this.filters;
|
||||
this.scrollTop = state.scrollTop;
|
||||
@@ -236,22 +229,21 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Array[]} params.viewDomain domain coming from view
|
||||
* @returns {Promise}
|
||||
*/
|
||||
update: function (params) {
|
||||
async update(params) {
|
||||
const currentDomain = JSON.stringify([...this.searchDomain, ...this.viewDomain]);
|
||||
const newDomain = JSON.stringify([...params.searchDomain, ...params.viewDomain]);
|
||||
var filtersProm;
|
||||
if (this.needReload || (currentDomain !== newDomain)) {
|
||||
this.needReload = false;
|
||||
this.searchDomain = params.searchDomain;
|
||||
this.viewDomain = params.viewDomain;
|
||||
filtersProm = this._fetchFilters();
|
||||
await this._fetchFilters();
|
||||
}
|
||||
return Promise.resolve(filtersProm).then(this._render.bind(this));
|
||||
return this._render();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set active values for each filter (coming from context). This needs to be
|
||||
@@ -259,19 +251,15 @@ var SearchPanel = Widget.extend({
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_applyDefaultFilterValues: function () {
|
||||
var self = this;
|
||||
Object.keys(this.filters).forEach(function (filterId) {
|
||||
var filter = self.filters[filterId];
|
||||
var defaultValues = self.defaultValues[filter.fieldName] || [];
|
||||
defaultValues.forEach(function (value) {
|
||||
_applyDefaultFilterValues() {
|
||||
Object.values(this.filters).forEach(filter => {
|
||||
const defaultValues = this.defaultValues[filter.fieldName] || [];
|
||||
defaultValues.forEach(value => {
|
||||
if (filter.values[value]) {
|
||||
filter.values[value].checked = true;
|
||||
}
|
||||
});
|
||||
Object.keys(filter.groups || []).forEach(function (groupId) {
|
||||
self._updateFilterGroupState(filter.groups[groupId]);
|
||||
});
|
||||
Object.values(filter.groups || []).forEach(this._updateFilterGroupState);
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -279,9 +267,8 @@ var SearchPanel = Widget.extend({
|
||||
* @param {string} categoryId
|
||||
* @param {Object[]} values
|
||||
*/
|
||||
_createCategoryTree: function (categoryId, values) {
|
||||
var category = this.categories[categoryId];
|
||||
|
||||
_createCategoryTree(categoryId, values) {
|
||||
const category = this.categories[categoryId];
|
||||
let parentField = category.parentField;
|
||||
if (values.length === SEARCH_PANEL_LIMIT) {
|
||||
category.limitAttained = true;
|
||||
@@ -292,36 +279,36 @@ var SearchPanel = Widget.extend({
|
||||
}
|
||||
|
||||
category.values = {};
|
||||
_.each(values, function (value) {
|
||||
category.values[value.id] = _.extend({}, value, {
|
||||
values.forEach(value => {
|
||||
category.values[value.id] = Object.assign({}, value, {
|
||||
childrenIds: [],
|
||||
folded: true,
|
||||
parentId: value[parentField] && value[parentField][0] || false,
|
||||
});
|
||||
});
|
||||
_.map(values, function (value) {
|
||||
var value = category.values[value.id];
|
||||
var parentCategoryId = value.parentId;
|
||||
values.forEach(value => {
|
||||
const { parentId: parentCategoryId } = category.values[value.id];
|
||||
if (parentCategoryId && parentCategoryId in category.values) {
|
||||
category.values[parentCategoryId].childrenIds.push(value.id);
|
||||
}
|
||||
});
|
||||
category.rootIds = _.filter(_.map(values, function (value) {
|
||||
return value.id;
|
||||
}), function (valueId) {
|
||||
var value = category.values[valueId];
|
||||
return value.parentId === false;
|
||||
});
|
||||
category.rootIds = [];
|
||||
for (const value of values) {
|
||||
const { parentId } = category.values[value.id];
|
||||
if (!parentId) {
|
||||
category.rootIds.push(value.id);
|
||||
}
|
||||
}
|
||||
|
||||
// set active value
|
||||
var validValues = _.pluck(category.values, 'id').concat([false]);
|
||||
var value = this._getCategoryDefaultValue(category, validValues);
|
||||
category.activeValueId = _.contains(validValues, value) ? value : false;
|
||||
const validValues = [...Object.values(category.values).map(v => v.id), false];
|
||||
const value = this._getCategoryDefaultValue(category, validValues);
|
||||
category.activeValueId = validValues.includes(value) ? value : false;
|
||||
|
||||
// unfold ancestor values of active value to make it is visible
|
||||
if (category.activeValueId) {
|
||||
var parentValueIds = this._getAncestorValueIds(category, category.activeValueId);
|
||||
parentValueIds.forEach(function (parentValue) {
|
||||
const parentValueIds = this._getAncestorValueIds(category, category.activeValueId);
|
||||
parentValueIds.forEach(parentValue => {
|
||||
category.values[parentValue].folded = false;
|
||||
});
|
||||
}
|
||||
@@ -331,25 +318,25 @@ var SearchPanel = Widget.extend({
|
||||
* @param {string} filterId
|
||||
* @param {Object[]} values
|
||||
*/
|
||||
_createFilterTree: function (filterId, values) {
|
||||
var filter = this.filters[filterId];
|
||||
_createFilterTree(filterId, values) {
|
||||
const filter = this.filters[filterId];
|
||||
|
||||
if (values.length === SEARCH_PANEL_LIMIT) {
|
||||
filter.limitAttained = true;
|
||||
}
|
||||
|
||||
// restore checked property
|
||||
values.forEach(function (value) {
|
||||
var oldValue = filter.values && filter.values[value.id];
|
||||
values.forEach(value => {
|
||||
const oldValue = filter.values && filter.values[value.id];
|
||||
value.checked = oldValue && oldValue.checked || false;
|
||||
});
|
||||
|
||||
filter.values = {};
|
||||
var groupIds = [];
|
||||
const groupIds = [];
|
||||
if (filter.groupBy) {
|
||||
var groups = {};
|
||||
values.forEach(function (value) {
|
||||
var groupId = JSON.stringify(value.group_id);
|
||||
const groups = {};
|
||||
values.forEach(value => {
|
||||
const groupId = JSON.stringify(value.group_id);
|
||||
if (!groups[groupId]) {
|
||||
if (groupId !== 'false') {
|
||||
groupIds.push(groupId);
|
||||
@@ -365,7 +352,7 @@ var SearchPanel = Widget.extend({
|
||||
sortedValueIds: [],
|
||||
};
|
||||
// restore former checked and folded state
|
||||
var oldGroup = filter.groups && filter.groups[groupId];
|
||||
const oldGroup = filter.groups && filter.groups[groupId];
|
||||
groups[groupId].state = oldGroup && oldGroup.state || false;
|
||||
groups[groupId].folded = oldGroup && oldGroup.folded || false;
|
||||
}
|
||||
@@ -373,19 +360,17 @@ var SearchPanel = Widget.extend({
|
||||
groups[groupId].sortedValueIds.push(value.id);
|
||||
});
|
||||
filter.groups = groups;
|
||||
filter.sortedGroupIds = _.sortBy(groupIds, function (groupId) {
|
||||
return groups[groupId].sequence || groups[groupId].name;
|
||||
});
|
||||
Object.keys(filter.groups).forEach(function (groupId) {
|
||||
filter.values = _.extend(filter.values, filter.groups[groupId].values);
|
||||
filter.sortedGroupIds = sortBy(groupIds,
|
||||
id => groups[id].sequence || groups[id].name
|
||||
);
|
||||
Object.values(filter.groups).forEach(group => {
|
||||
Object.assign(filter.values, group.values);
|
||||
});
|
||||
} else {
|
||||
values.forEach(function (value) {
|
||||
values.forEach(value => {
|
||||
filter.values[value.id] = value;
|
||||
});
|
||||
filter.sortedValueIds = values.map(function (value) {
|
||||
return value.id;
|
||||
});
|
||||
filter.sortedValueIds = values.map(value => value.id);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -394,31 +379,31 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @returns {Promise} resolved when all categories have been fetched
|
||||
*/
|
||||
_fetchCategories: function () {
|
||||
var self = this;
|
||||
var proms = Object.keys(this.categories).map(function (categoryId) {
|
||||
var category = self.categories[categoryId];
|
||||
var field = self.fields[category.fieldName];
|
||||
var categoriesProm;
|
||||
_fetchCategories() {
|
||||
const proms = [];
|
||||
let prom;
|
||||
for (const category of Object.values(this.categories)) {
|
||||
const field = this.fields[category.fieldName];
|
||||
if (field.type === 'selection') {
|
||||
var values = field.selection.map(function (value) {
|
||||
return {id: value[0], display_name: value[1]};
|
||||
const values = field.selection.map(value => {
|
||||
return { id: value[0], display_name: value[1] };
|
||||
});
|
||||
categoriesProm = Promise.resolve(values);
|
||||
prom = Promise.resolve(values);
|
||||
} else {
|
||||
categoriesProm = self._rpc({
|
||||
prom = this._rpc({
|
||||
method: 'search_panel_select_range',
|
||||
model: self.model,
|
||||
model: this.model,
|
||||
args: [category.fieldName],
|
||||
}).then(function (result) {
|
||||
}).then(result => {
|
||||
category.parentField = result.parent_field;
|
||||
return result.values;
|
||||
});
|
||||
}
|
||||
return categoriesProm.then(function (values) {
|
||||
self._createCategoryTree(categoryId, values);
|
||||
prom.then(values => {
|
||||
this._createCategoryTree(category.id, values);
|
||||
});
|
||||
});
|
||||
proms.push(prom);
|
||||
}
|
||||
return Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
@@ -428,20 +413,18 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @returns {Promise} resolved when all filters have been fetched
|
||||
*/
|
||||
_fetchFilters: function () {
|
||||
var self = this;
|
||||
var evalContext = {};
|
||||
Object.keys(this.categories).forEach(function (categoryId) {
|
||||
var category = self.categories[categoryId];
|
||||
_fetchFilters() {
|
||||
const evalContext = {};
|
||||
for (const category of Object.values(this.categories)) {
|
||||
evalContext[category.fieldName] = category.activeValueId;
|
||||
});
|
||||
var categoryDomain = this._getCategoryDomain();
|
||||
var filterDomain = this._getFilterDomain();
|
||||
var proms = Object.keys(this.filters).map(function (filterId) {
|
||||
var filter = self.filters[filterId];
|
||||
return self._rpc({
|
||||
}
|
||||
const categoryDomain = this._getCategoryDomain();
|
||||
const filterDomain = this._getFilterDomain();
|
||||
const proms = [];
|
||||
for (const filter of Object.values(this.filters)) {
|
||||
const prom = this._rpc({
|
||||
method: 'search_panel_select_multi_range',
|
||||
model: self.model,
|
||||
model: this.model,
|
||||
args: [filter.fieldName],
|
||||
kwargs: {
|
||||
category_domain: categoryDomain,
|
||||
@@ -449,12 +432,11 @@ var SearchPanel = Widget.extend({
|
||||
disable_counters: filter.disableCounters,
|
||||
filter_domain: filterDomain,
|
||||
group_by: filter.groupBy || false,
|
||||
search_domain: [...self.searchDomain, ...self.viewDomain],
|
||||
search_domain: [...this.searchDomain, ...this.viewDomain],
|
||||
},
|
||||
}).then(function (values) {
|
||||
self._createFilterTree(filterId, values);
|
||||
});
|
||||
});
|
||||
}).then(values => { this._createFilterTree(filter.id, values); });
|
||||
proms.push(prom);
|
||||
}
|
||||
return Promise.all(proms);
|
||||
},
|
||||
/**
|
||||
@@ -463,13 +445,13 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Array} validValues
|
||||
* @returns id of the default item of the category or false
|
||||
*/
|
||||
_getCategoryDefaultValue: function (category, validValues) {
|
||||
_getCategoryDefaultValue(category, validValues) {
|
||||
// set active value from context
|
||||
var value = this.defaultValues[category.fieldName];
|
||||
const value = this.defaultValues[category.fieldName];
|
||||
// if not set in context, or set to an unknown value, set active value
|
||||
// from localStorage
|
||||
if (!_.contains(validValues, value)) {
|
||||
var storageKey = this._getLocalStorageKey(category);
|
||||
if (!validValues.includes(value)) {
|
||||
const storageKey = this._getLocalStorageKey(category);
|
||||
return this.call('local_storage', 'getItem', storageKey);
|
||||
}
|
||||
return value;
|
||||
@@ -480,20 +462,16 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @returns {Array[]}
|
||||
*/
|
||||
_getCategoryDomain: function () {
|
||||
var self = this;
|
||||
|
||||
function categoryToDomain(domain, categoryId) {
|
||||
var category = self.categories[categoryId];
|
||||
_getCategoryDomain() {
|
||||
const domain = [];
|
||||
for (const category of Object.values(this.categories)) {
|
||||
if (category.activeValueId) {
|
||||
var field = self.fields[category.fieldName];
|
||||
var op = (field.type === 'many2one' && category.parentField) ? 'child_of' : '=';
|
||||
const field = this.fields[category.fieldName];
|
||||
const op = (field.type === 'many2one' && category.parentField) ? 'child_of' : '=';
|
||||
domain.push([category.fieldName, op, category.activeValueId]);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
return Object.keys(this.categories).reduce(categoryToDomain, []);
|
||||
return domain;
|
||||
},
|
||||
/**
|
||||
* Compute and return the domain based on the current checked filters.
|
||||
@@ -504,40 +482,36 @@ var SearchPanel = Widget.extend({
|
||||
* a group (and grouped using an 'OR').
|
||||
*
|
||||
* @private
|
||||
* @param {string} filterId
|
||||
* @returns {Array[]}
|
||||
*/
|
||||
_getFilterDomain: function () {
|
||||
var self = this;
|
||||
_getFilterDomain(filterId) {
|
||||
const domain = [];
|
||||
|
||||
function getCheckedValueIds(values) {
|
||||
return Object.keys(values).reduce(function (checkedValues, valueId) {
|
||||
if (values[valueId].checked) {
|
||||
checkedValues.push(values[valueId].id);
|
||||
}
|
||||
return checkedValues;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function filterToDomain(domain, filterId) {
|
||||
var filter = self.filters[filterId];
|
||||
if (filter.groups) {
|
||||
Object.keys(filter.groups).forEach(function (groupId) {
|
||||
var group = filter.groups[groupId];
|
||||
var checkedValues = getCheckedValueIds(group.values);
|
||||
if (checkedValues.length) {
|
||||
domain.push([filter.fieldName, 'in', checkedValues]);
|
||||
}
|
||||
});
|
||||
} else if (filter.values) {
|
||||
var checkedValues = getCheckedValueIds(filter.values);
|
||||
if (checkedValues.length) {
|
||||
domain.push([filter.fieldName, 'in', checkedValues]);
|
||||
}
|
||||
function addCondition(fieldName, checkedValues) {
|
||||
if (checkedValues.length) {
|
||||
const ids = checkedValues.map(v => v.id);
|
||||
domain.push([fieldName, 'in', ids]);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
return Object.keys(this.filters).reduce(filterToDomain, []);
|
||||
for (const filter of Object.values(this.filters)) {
|
||||
if (filter.id === filterId) {
|
||||
continue;
|
||||
}
|
||||
const { fieldName } = filter;
|
||||
let checkedValues;
|
||||
if (filter.groups) {
|
||||
for (const group of Object.values(filter.groups)) {
|
||||
checkedValues = Object.values(group.values).filter(v => v.checked);
|
||||
addCondition(fieldName, checkedValues);
|
||||
}
|
||||
} else if (filter.values) {
|
||||
checkedValues = Object.values(filter.values).filter(v => v.checked);
|
||||
addCondition(fieldName, checkedValues);
|
||||
}
|
||||
}
|
||||
return domain;
|
||||
},
|
||||
/**
|
||||
* The active id of each category is stored in the localStorage, s.t. it
|
||||
@@ -547,7 +521,7 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Object} category
|
||||
* @returns {string}
|
||||
*/
|
||||
_getLocalStorageKey: function (category) {
|
||||
_getLocalStorageKey(category) {
|
||||
return 'searchpanel_' + this.model + '_' + category.fieldName;
|
||||
},
|
||||
/**
|
||||
@@ -557,9 +531,8 @@ var SearchPanel = Widget.extend({
|
||||
* @returns {integer[]} list of ids of the ancestors of the given value in
|
||||
* the given category
|
||||
*/
|
||||
_getAncestorValueIds: function (category, categoryValueId) {
|
||||
var categoryValue = category.values[categoryValueId];
|
||||
var parentId = categoryValue.parentId;
|
||||
_getAncestorValueIds(category, categoryValueId) {
|
||||
const { parentId } = category.values[categoryValueId];
|
||||
if (parentId) {
|
||||
return [parentId].concat(this._getAncestorValueIds(category, parentId));
|
||||
}
|
||||
@@ -575,7 +548,7 @@ var SearchPanel = Widget.extend({
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_notifyDomainUpdated: function () {
|
||||
_notifyDomainUpdated() {
|
||||
this.needReload = true;
|
||||
this.trigger_up('search_panel_domain_updated', {
|
||||
domain: this.getDomain(),
|
||||
@@ -584,27 +557,20 @@ var SearchPanel = Widget.extend({
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_render: function () {
|
||||
var self = this;
|
||||
_render() {
|
||||
this.$el.empty();
|
||||
|
||||
// sort categories and filters according to their index
|
||||
var categories = Object.keys(this.categories).map(function (categoryId) {
|
||||
return self.categories[categoryId];
|
||||
});
|
||||
var filters = Object.keys(this.filters).map(function (filterId) {
|
||||
return self.filters[filterId];
|
||||
});
|
||||
var sections = categories.concat(filters).sort(function (s1, s2) {
|
||||
return s1.index - s2.index;
|
||||
});
|
||||
const categories = Object.values(this.categories);
|
||||
const filters = Object.values(this.filters);
|
||||
const sections = categories.concat(filters).sort((s1, s2) => s1.index - s2.index);
|
||||
|
||||
sections.forEach(function (section) {
|
||||
sections.forEach(section => {
|
||||
if (Object.keys(section.values).length) {
|
||||
if (section.type === 'category') {
|
||||
self.$el.append(self._renderCategory(section));
|
||||
this.$el.append(this._renderCategory(section));
|
||||
} else {
|
||||
self.$el.append(self._renderFilter(section));
|
||||
this.$el.append(this._renderFilter(section));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -614,30 +580,29 @@ var SearchPanel = Widget.extend({
|
||||
* @param {Object} category
|
||||
* @returns {string}
|
||||
*/
|
||||
_renderCategory: function (category) {
|
||||
return qweb.render('SearchPanel.Category', {category: category});
|
||||
_renderCategory(category) {
|
||||
return qweb.render('SearchPanel.Category', { category });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} filter
|
||||
* @returns {jQuery}
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
_renderFilter: function (filter) {
|
||||
var $filter = $(qweb.render('SearchPanel.Filter', {filter: filter}));
|
||||
_renderFilter(filter) {
|
||||
const filterElement = $(qweb.render('SearchPanel.Filter', { filter }))[0];
|
||||
|
||||
// set group inputs in indeterminate state when necessary
|
||||
Object.keys(filter.groups || {}).forEach(function (groupId) {
|
||||
var state = filter.groups[groupId].state;
|
||||
Object.keys(filter.groups || {}).forEach(groupId => {
|
||||
const group = filter.groups[groupId];
|
||||
const { state } = group;
|
||||
// group 'false' is not displayed
|
||||
if (groupId !== 'false' && state === 'indeterminate') {
|
||||
$filter
|
||||
.find('.o_search_panel_filter_group[data-group-id=' + groupId + '] input')
|
||||
.get(0)
|
||||
.indeterminate = true;
|
||||
const sel = `.o_search_panel_filter_group[data-group-id="${groupId}"] input`;
|
||||
filterElement.querySelector(sel).indeterminate = true;
|
||||
}
|
||||
});
|
||||
|
||||
return $filter;
|
||||
return filterElement;
|
||||
},
|
||||
/**
|
||||
* Updates the state property of a given filter's group according to the
|
||||
@@ -646,37 +611,38 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @param {Object} group
|
||||
*/
|
||||
_updateFilterGroupState: function (group) {
|
||||
var valuePartition = _.partition(Object.keys(group.values), function (valueId) {
|
||||
return group.values[valueId].checked;
|
||||
});
|
||||
if (valuePartition[0].length && valuePartition[1].length) {
|
||||
group.state = 'indeterminate';
|
||||
} else if (valuePartition[0].length) {
|
||||
group.state = 'checked';
|
||||
_updateFilterGroupState(group) {
|
||||
if (Object.values(group.values).some(v => v.checked)) {
|
||||
if (Object.values(group.values).some(v => !v.checked)) {
|
||||
group.state = 'indeterminate';
|
||||
} else {
|
||||
group.state = 'checked';
|
||||
}
|
||||
} else {
|
||||
group.state = 'unchecked';
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onCategoryValueClicked: function (ev) {
|
||||
_onCategoryValueClicked(ev) {
|
||||
ev.stopPropagation();
|
||||
var $item = $(ev.currentTarget).closest('.o_search_panel_category_value');
|
||||
var category = this.categories[$item.data('categoryId')];
|
||||
var valueId = $item.data('id') || false;
|
||||
const item = ev.currentTarget.closest('.o_search_panel_category_value');
|
||||
const category = this.categories[item.dataset.categoryId];
|
||||
const valueId = !isNaN(item.dataset.id) ?
|
||||
Number(item.dataset.id) :
|
||||
item.dataset.id || false;
|
||||
category.activeValueId = valueId;
|
||||
if (category.values[valueId]) {
|
||||
category.values[valueId].folded = !category.values[valueId].folded;
|
||||
}
|
||||
var storageKey = this._getLocalStorageKey(category);
|
||||
const storageKey = this._getLocalStorageKey(category);
|
||||
this.call('local_storage', 'setItem', storageKey, valueId);
|
||||
this._notifyDomainUpdated();
|
||||
},
|
||||
@@ -684,15 +650,14 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onFilterGroupChanged: function (ev) {
|
||||
_onFilterGroupChanged(ev) {
|
||||
ev.stopPropagation();
|
||||
var $item = $(ev.target).closest('.o_search_panel_filter_group');
|
||||
var filter = this.filters[$item.data('filterId')];
|
||||
var groupId = $item.data('groupId');
|
||||
var group = filter.groups[groupId];
|
||||
const item = ev.target.closest('.o_search_panel_filter_group');
|
||||
const filter = this.filters[item.dataset.filterId];
|
||||
const group = filter.groups[item.dataset.groupId];
|
||||
group.state = group.state === 'checked' ? 'unchecked' : 'checked';
|
||||
Object.keys(group.values).forEach(function (valueId) {
|
||||
group.values[valueId].checked = group.state === 'checked';
|
||||
Object.values(group.values).forEach(value => {
|
||||
value.checked = group.state === 'checked';
|
||||
});
|
||||
this._notifyDomainUpdated();
|
||||
},
|
||||
@@ -700,14 +665,14 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onFilterValueChanged: function (ev) {
|
||||
_onFilterValueChanged(ev) {
|
||||
ev.stopPropagation();
|
||||
var $item = $(ev.target).closest('.o_search_panel_filter_value');
|
||||
var valueId = $item.data('valueId');
|
||||
var filter = this.filters[$item.data('filterId')];
|
||||
var value = filter.values[valueId];
|
||||
const item = ev.target.closest('.o_search_panel_filter_value');
|
||||
const filter = this.filters[item.dataset.filterId];
|
||||
const value = filter.values[item.dataset.valueId];
|
||||
value.checked = !value.checked;
|
||||
var group = filter.groups && filter.groups[value.group_id];
|
||||
const groupId = JSON.stringify(value.group_id);
|
||||
const group = filter.groups && filter.groups[groupId];
|
||||
if (group) {
|
||||
this._updateFilterGroupState(group);
|
||||
}
|
||||
@@ -717,12 +682,12 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onToggleFoldCategory: function (ev) {
|
||||
_onToggleFoldCategory(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var $item = $(ev.currentTarget).closest('.o_search_panel_category_value');
|
||||
var category = this.categories[$item.data('categoryId')];
|
||||
var valueId = $item.data('id');
|
||||
const item = ev.currentTarget.closest('.o_search_panel_category_value');
|
||||
const category = this.categories[item.dataset.categoryId];
|
||||
const valueId = item.dataset.id;
|
||||
category.values[valueId].folded = !category.values[valueId].folded;
|
||||
this._render();
|
||||
},
|
||||
@@ -730,12 +695,12 @@ var SearchPanel = Widget.extend({
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onToggleFoldFilterGroup: function (ev) {
|
||||
_onToggleFoldFilterGroup(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var $item = $(ev.currentTarget).closest('.o_search_panel_filter_group');
|
||||
var filter = this.filters[$item.data('filterId')];
|
||||
var groupId = $item.data('groupId');
|
||||
const item = ev.currentTarget.closest('.o_search_panel_filter_group');
|
||||
const filter = this.filters[item.dataset.filterId];
|
||||
const groupId = item.dataset.groupId;
|
||||
filter.groups[groupId].folded = !filter.groups[groupId].folded;
|
||||
this._render();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user