[FIX] web: autocompletion in the new search view
A lot of new features have been implemented in search view but autocompletion was forgotten. This commit fixes many small problems that were introduced: - synchronization of facets created through autocompletion with filters and groupby menus - filters created through autocompletion can be saved
This commit is contained in:
@@ -14,6 +14,8 @@ var _t = core._t;
|
||||
|
||||
var PERIOD_OPTIONS = TimeRangeMenuOptions.PeriodOptions;
|
||||
|
||||
var DEFAULT_PERIOD = 'this_month';
|
||||
|
||||
var FiltersMenu = DropdownMenu.extend({
|
||||
custom_events: {
|
||||
remove_proposition: '_onRemoveProposition',
|
||||
@@ -54,6 +56,7 @@ var FiltersMenu = DropdownMenu.extend({
|
||||
this.isMobile = config.device.isMobile;
|
||||
// determines list of options used by filter of type 'date'
|
||||
this.periodOptions = PERIOD_OPTIONS;
|
||||
this.defaultOptionId = DEFAULT_PERIOD;
|
||||
// determines when the 'Add custom filter' submenu is open
|
||||
this.generatorMenuIsOpen = false;
|
||||
this.propositions = [];
|
||||
@@ -146,9 +149,6 @@ var FiltersMenu = DropdownMenu.extend({
|
||||
if (item.isPeriod) {
|
||||
item.options = this.periodOptions;
|
||||
}
|
||||
// super has to be called here because we need to add options to groupby
|
||||
// before to call it since some keys in a groupby are initialized using
|
||||
// the keys 'options' and 'defaultOptionId'
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,7 @@ var GroupByMenu = DropdownMenu.extend({
|
||||
{description: 'Quarter', optionId: 'quarter', groupId: 1},
|
||||
{description: 'Year', optionId: 'year', groupId: 1},
|
||||
];
|
||||
this.defaultOptionId = DEFAULT_INTERVAL;
|
||||
this.groupableFields = [];
|
||||
_.each(fields, function (field, name) {
|
||||
if (field.sortable && _.contains(GROUPABLE_TYPES, field.type)) {
|
||||
@@ -131,6 +132,7 @@ var GroupByMenu = DropdownMenu.extend({
|
||||
var eventData = _.clone(groupby);
|
||||
this._prepareItem(groupby);
|
||||
if (groupby.hasOptions) {
|
||||
groupby.defaultOptionId = DEFAULT_INTERVAL;
|
||||
groupby.currentOptionId = DEFAULT_INTERVAL;
|
||||
groupby.isDate = true;
|
||||
eventData.optionId = groupby.currentOptionId;
|
||||
|
||||
@@ -128,7 +128,7 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ {
|
||||
__contexts: contexts
|
||||
});
|
||||
},
|
||||
get_groupby: function () { },
|
||||
get_groupby: function () {},
|
||||
/**
|
||||
* Function creating the returned domain for the field, override this
|
||||
* methods in children if you only need to customize the field's domain
|
||||
@@ -143,7 +143,7 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ {
|
||||
make_domain: function (name, operator, facet) {
|
||||
return [[name, operator, this.value_from(facet)]];
|
||||
},
|
||||
get_domain: function (facet) {
|
||||
get_domain: function (facet, noDomainEvaluation) {
|
||||
if (!facet.values.length) { return; }
|
||||
|
||||
var value_to_domain;
|
||||
@@ -166,10 +166,15 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ {
|
||||
};
|
||||
}
|
||||
var domains = facet.values.map(value_to_domain);
|
||||
|
||||
// here 'noDomainEvaluation' means 'string representation'
|
||||
if (noDomainEvaluation) {
|
||||
domains = domains.map(Domain.prototype.arrayToString);
|
||||
return pyUtils.assembleDomains(domains, 'OR');
|
||||
}
|
||||
if (domains.length === 1) {
|
||||
return domains[0];
|
||||
}
|
||||
|
||||
_.each(domains, Domain.prototype.normalizeArray);
|
||||
var ors = _.times(domains.length - 1, _.constant("|"));
|
||||
return ors.concat.apply(ors, domains);
|
||||
|
||||
@@ -380,7 +380,7 @@ var SearchView = Widget.extend({
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.selectedGroupIds = {
|
||||
this.activeItemIds = {
|
||||
groupByCategory: [],
|
||||
filterCategory: []
|
||||
};
|
||||
@@ -627,9 +627,10 @@ var SearchView = Widget.extend({
|
||||
* @param {Object} ui.item selected completion item
|
||||
*/
|
||||
select_completion: function (e, ui) {
|
||||
var facet = ui.item.facet;
|
||||
e.preventDefault();
|
||||
if(ui.item.facet && ui.item.facet.values && ui.item.facet.values.length && String(ui.item.facet.values[0].value).trim() !== "") {
|
||||
this.query.add(ui.item.facet);
|
||||
if(facet && facet.values && facet.values.length && String(facet.values[0].value).trim() !== "") {
|
||||
this.query.add(facet);
|
||||
} else {
|
||||
this.query.trigger('add');
|
||||
}
|
||||
@@ -666,7 +667,7 @@ var SearchView = Widget.extend({
|
||||
_.invoke(this.input_subviews, 'destroy');
|
||||
this.input_subviews = [];
|
||||
|
||||
var selectedGroupIds = {
|
||||
var activeItemIds = {
|
||||
groupByCategory: [],
|
||||
filterCategory: [],
|
||||
};
|
||||
@@ -674,29 +675,31 @@ var SearchView = Widget.extend({
|
||||
this.query.each(function (facet) {
|
||||
var values = facet.get('values');
|
||||
if (facet.attributes.cat === "groupByCategory") {
|
||||
selectedGroupIds.groupByCategory = _.uniq(
|
||||
values.reduce(
|
||||
function (acc, value) {
|
||||
var groupby = value.value;
|
||||
var description = _.findWhere(self.groupbysMapping, {groupby: groupby});
|
||||
if (description) {
|
||||
acc.push(description.groupId);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
activeItemIds.groupByCategory = activeItemIds.groupByCategory.concat(
|
||||
_.uniq(
|
||||
values.reduce(
|
||||
function (acc, value) {
|
||||
var groupby = value.value;
|
||||
var description = _.findWhere(self.groupbysMapping, {groupby: groupby});
|
||||
if (description) {
|
||||
acc.push(description.groupbyId);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (facet.attributes.cat === "filterCategory") {
|
||||
selectedGroupIds.filterCategory = selectedGroupIds.filterCategory.concat(
|
||||
activeItemIds.filterCategory = activeItemIds.filterCategory.concat(
|
||||
_.uniq(
|
||||
values.reduce(
|
||||
function (acc, value) {
|
||||
var filter = value.value;
|
||||
var description = _.findWhere(self.filtersMapping, {filter: filter});
|
||||
if (description) {
|
||||
acc.push(description.groupId);
|
||||
acc.push(description.filterId);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
@@ -729,11 +732,10 @@ var SearchView = Widget.extend({
|
||||
_.last(self.input_subviews).$el.focus();
|
||||
}
|
||||
if (self.groupby_menu) {
|
||||
self._unsetUnusedGroupbys(selectedGroupIds.groupByCategory);
|
||||
self.groupby_menu.updateItemsStatus(activeItemIds.groupByCategory);
|
||||
}
|
||||
if (self.filters_menu) {
|
||||
self._unsetUnusedFilters(selectedGroupIds.filterCategory);
|
||||
}
|
||||
self.filters_menu.updateItemsStatus(activeItemIds.filterCategory); }
|
||||
if (self.timeRangeMenu && !timeRangeMenuIsActive) {
|
||||
self.timeRangeMenu.deactivate();
|
||||
}
|
||||
@@ -903,6 +905,7 @@ var SearchView = Widget.extend({
|
||||
var filterId = _.uniqueId('__filter__');
|
||||
var isPeriod = filter.attrs.isPeriod;
|
||||
var defaultPeriod = filter.attrs.default_period;
|
||||
var isActive = !self.hasFavorites && !!self.search_defaults[filter.attrs.name];
|
||||
filters.push({
|
||||
itemId: filterId,
|
||||
description: filter.attrs.string || filter.attrs.help ||
|
||||
@@ -910,8 +913,8 @@ var SearchView = Widget.extend({
|
||||
domain: filter.attrs.domain,
|
||||
fieldName: filter.attrs.date,
|
||||
isPeriod: isPeriod,
|
||||
currentOptionId: defaultPeriod,
|
||||
isActive: !self.hasFavorites && !!self.search_defaults[filter.attrs.name],
|
||||
defaultOptionId: defaultPeriod,
|
||||
isActive: isActive,
|
||||
groupId: groupId,
|
||||
});
|
||||
self.filtersMapping.push({filterId: filterId, filter: filter, groupId: groupId});
|
||||
@@ -945,14 +948,15 @@ var SearchView = Widget.extend({
|
||||
var fieldName = groupby.attrs.fieldName;
|
||||
var isDate = groupby.attrs.isDate;
|
||||
var defaultInterval = groupby.attrs.defaultInterval || DEFAULT_INTERVAL;
|
||||
var isActive = !self.hasFavorites && !!self.search_defaults[groupby.attrs.name];
|
||||
groupbys.push({
|
||||
itemId: groupbyId,
|
||||
description: groupby.attrs.string || groupby.attrs.help || groupby.attrs.name
|
||||
|| groupby.attrs.fieldName || 'Ω',
|
||||
isDate: isDate,
|
||||
fieldName: fieldName,
|
||||
currentOptionId: defaultInterval,
|
||||
isActive: !self.hasFavorites && !!self.search_defaults[groupby.attrs.name],
|
||||
defaultOptionId: defaultInterval,
|
||||
isActive: isActive,
|
||||
groupId: groupId,
|
||||
});
|
||||
if (isDate) {
|
||||
@@ -990,6 +994,9 @@ var SearchView = Widget.extend({
|
||||
fv.arch = utils.xml_to_json(doc, true);
|
||||
return fv;
|
||||
},
|
||||
/**
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_searchDefaultTimeRange: function () {
|
||||
if (this.timeRanges) {
|
||||
var timeRange = "[]";
|
||||
@@ -1065,50 +1072,6 @@ var SearchView = Widget.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function ask the groupby menu to deactive all groupbys if no
|
||||
* groupby is used.
|
||||
*
|
||||
* @param {string[]]} selectedGroupIds list of group ids to deactivate
|
||||
*/
|
||||
_unsetUnusedGroupbys: function (selectedGroupIds) {
|
||||
var groupIds = this.groupsMapping.reduce(
|
||||
function (acc, triple) {
|
||||
if (triple.category === 'Group By') {
|
||||
acc.push(triple.groupId);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
this.selectedGroupIds.groupByCategory = selectedGroupIds;
|
||||
if (selectedGroupIds.length === 0) {
|
||||
this.groupby_menu.unsetGroups(groupIds);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This function ask the filters menu to deactive all filters with
|
||||
* corresponding groupId in the list selectedGroupIds.
|
||||
*
|
||||
* @private
|
||||
* @param {string[]]} selectedGroupIds
|
||||
*/
|
||||
_unsetUnusedFilters: function (selectedGroupIds) {
|
||||
var groupIds = this.groupsMapping.reduce(
|
||||
function (acc, triple) {
|
||||
if (triple.category === 'Filters') {
|
||||
if (!_.contains(selectedGroupIds, triple.groupId)) {
|
||||
acc.push(triple.groupId);
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
this.selectedGroupIds.filterCategory = selectedGroupIds;
|
||||
this.filters_menu.unsetGroups(groupIds);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -66,14 +66,18 @@ var DropdownMenu = Widget.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Number[]} groupIds
|
||||
* @param {string[]} activeItemIds
|
||||
*/
|
||||
unsetGroups: function (groupIds) {
|
||||
var self = this;
|
||||
_.each(self.items, function (item) {
|
||||
if (_.contains(groupIds, item.groupId)) {
|
||||
updateItemsStatus: function (activeItemIds) {
|
||||
_.each(this.items, function (item) {
|
||||
if (!_.contains(activeItemIds, item.itemId)) {
|
||||
item.isActive = false;
|
||||
item.currentOptionId = false;
|
||||
} else {
|
||||
item.isActive = true;
|
||||
item.currentOptionId = item.hasOptions ?
|
||||
(item.currentOptionId || item.defaultOptionId) :
|
||||
false;
|
||||
}
|
||||
});
|
||||
this._renderMenuItems();
|
||||
@@ -122,7 +126,8 @@ var DropdownMenu = Widget.extend({
|
||||
if (item.options && item.options.length !== 0) {
|
||||
item.options = _.sortBy(item.options, 'groupId');
|
||||
item.hasOptions = true;
|
||||
item.currentOptionId = item.isActive && item.currentOptionId ? item.currentOptionId : false;
|
||||
item.defaultOptionId = item.defaultOptionId || this.defaultOptionId;
|
||||
item.currentOptionId = item.isActive && item.defaultOptionId ? item.defaultOptionId : false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -90,6 +90,20 @@ QUnit.module('Search View', {
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[2, 'list']],
|
||||
search_view_id: [7, 'search'],
|
||||
}, {
|
||||
id: 9,
|
||||
name: 'Partners Action 9',
|
||||
res_model: 'partner',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'pivot']],
|
||||
search_view_id: [5, 'search'],
|
||||
}, {
|
||||
id: 10,
|
||||
name: 'Partners Action 10',
|
||||
res_model: 'partner',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'pivot']],
|
||||
search_view_id: [8, 'search'],
|
||||
}
|
||||
];
|
||||
|
||||
@@ -109,6 +123,12 @@ QUnit.module('Search View', {
|
||||
'<field name="float_field" type="measure"/>' +
|
||||
'</graph>',
|
||||
|
||||
// pivot views
|
||||
'partner,false,pivot': '<pivot>' +
|
||||
'<field name="date_field" type="row" interval="day"/>' +
|
||||
'<field name="float_field" type="measure"/>' +
|
||||
'</pivot>',
|
||||
|
||||
// search views
|
||||
'partner,false,search': '<search>'+
|
||||
'<filter string="candle" name="itsName" context="{\'group_by\': \'foo\'}"/>' +
|
||||
@@ -154,6 +174,15 @@ QUnit.module('Search View', {
|
||||
'<separator/>' +
|
||||
'<filter string="11" name="coolName11" domain="[]"/>' +
|
||||
'</search>',
|
||||
'partner,8,search': '<search>'+
|
||||
'<field name="foo"/>' +
|
||||
'<field name="date_field"/>' +
|
||||
'<field name="birthday"/>' +
|
||||
'<field name="bar"/>' +
|
||||
'<field name="float_field"/>' +
|
||||
'<filter string="Date Field Filter" name="positive" date="date_field"/>' +
|
||||
'<filter string="Date Field Groupby" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' +
|
||||
'</search>',
|
||||
};
|
||||
},
|
||||
}, function () {
|
||||
@@ -319,7 +348,7 @@ QUnit.module('Search View', {
|
||||
assert.strictEqual($('.o_content tr.o_group_header').length, 4);
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('a separator in groupbys does not cause problems', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
@@ -523,5 +552,88 @@ QUnit.module('Search View', {
|
||||
}
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('selection via autocompletion modifies appropriately submenus', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var actionManager = createActionManager({
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
actionManager.doAction(9);
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keypress', {
|
||||
which: 97,
|
||||
}));
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keyup', {
|
||||
which: $.ui.keyCode.ENTER,
|
||||
keyCode: $.ui.keyCode.ENTER,
|
||||
}));
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keypress', {
|
||||
which: 103,
|
||||
}));
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keyup', {
|
||||
which: $.ui.keyCode.ENTER,
|
||||
keyCode: $.ui.keyCode.ENTER,
|
||||
}));
|
||||
|
||||
assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(),
|
||||
"Date Field Filter: This Month",
|
||||
"There should be a filter facet with label 'Date Field Filter: This Month'");
|
||||
assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(1).text().trim(),
|
||||
"Date Field Groupby: Day",
|
||||
"There should be a filter facet with label 'Date Field Groupby: Day'");
|
||||
|
||||
$('button .fa-filter').click();
|
||||
$('.o_filters_menu .o_menu_item').eq(0).click();
|
||||
assert.strictEqual($('.o_filters_menu .o_item_option a.selected').text().trim(), "This Month",
|
||||
"The item 'This Month' should be selected in the filters menu");
|
||||
|
||||
$('button .fa-bars').click();
|
||||
$('.o_group_by_menu .o_menu_item').eq(0).click();
|
||||
assert.strictEqual($('.o_group_by_menu .o_item_option a.selected').text().trim(), "Day",
|
||||
"The item 'Day' should be selected in the groupby menu");
|
||||
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('save filters created via autocompletion works', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var actionManager = createActionManager({
|
||||
actions: this.actions,
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
intercepts: {
|
||||
create_filter: function (ev) {
|
||||
assert.ok(ev.data.filter.domain === "[['foo', 'ilike', 'a']]");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
actionManager.doAction(10);
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keypress', {
|
||||
which: 97,
|
||||
}));
|
||||
|
||||
$('.o_searchview_input').trigger($.Event('keyup', {
|
||||
which: $.ui.keyCode.ENTER,
|
||||
keyCode: $.ui.keyCode.ENTER,
|
||||
}));
|
||||
|
||||
assert.strictEqual($('.o_searchview_input_container .o_facet_values span').text().trim(), "a");
|
||||
|
||||
$('button .fa-star').click();
|
||||
$('.o_favorites_menu a.o_save_search').click();
|
||||
$('.o_favorites_menu div.o_save_name button').click();
|
||||
|
||||
actionManager.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user