[IMP] web: add more filtering and sorting options on ModelFieldSelector

A new `filter` option has been added to filter fields with an optional function.
A new `order` option has been added to sort displayed fields.

The `followRelations` options have also been extended to take a function.
This commit is contained in:
Christophe Matthieu
2018-08-13 17:09:28 +02:00
parent e082ee38e8
commit 061175e598
3 changed files with 51 additions and 12 deletions
@@ -53,7 +53,11 @@ var ModelFieldSelector = Widget.extend({
* @param {string} model - the model name (e.g. "res.partner")
* @param {string[]} chain - list of the initial field chain parts
* @param {Object} [options] - some key-value options
* @param {string} [options.order='string']
* an ordering key for displayed fields
* @param {boolean} [options.readonly=true] - true if should be readonly
* @param {function} [options.filter]
* a function to filter the fetched fields
* @param {Object} [options.filters]
* some key-value options to filter the fetched fields
* @param {boolean} [options.filters.searchable=true]
@@ -62,7 +66,7 @@ var ModelFieldSelector = Widget.extend({
* the list of fields info to use when no relation has
* been followed (null indicates the widget has to request
* the fields itself)
* @param {boolean} [options.followRelations=true]
* @param {boolean|function} [options.followRelations=true]
* true if can follow relation when building the chain
* @param {boolean} [options.debugMode=false]
* true if the widget is in debug mode, false otherwise
@@ -73,9 +77,11 @@ var ModelFieldSelector = Widget.extend({
this.model = model;
this.chain = chain;
this.options = _.extend({
order: 'string',
readonly: true,
filters: {},
fields: null,
filter: function () {return true;},
followRelations: true,
debugMode: false,
}, options || {});
@@ -83,6 +89,12 @@ var ModelFieldSelector = Widget.extend({
searchable: true,
}, this.options.filters);
if (typeof this.options.followRelations !== 'function') {
this.options.followRelations = this.options.followRelations ?
function () {return true;} :
function () {return false;};
}
this.pages = [];
this.dirty = false;
@@ -192,6 +204,7 @@ var ModelFieldSelector = Widget.extend({
* non-technical names
*/
_getModelFieldsFromCache: function (model, filters) {
var self = this;
var def = modelFieldsCache.cacheDefs[model];
if (!def) {
def = modelFieldsCache.cacheDefs[model] = this._rpc({
@@ -204,12 +217,12 @@ var ModelFieldSelector = Widget.extend({
context: this.getSession().user_context,
})
.then((function (fields) {
modelFieldsCache.cache[model] = sortFields(fields, model);
modelFieldsCache.cache[model] = sortFields(fields, model, self.options.order);
}).bind(this));
}
return def.then((function () {
return _.filter(modelFieldsCache.cache[model], function (f) {
return !filters.searchable || f.searchable;
return (!filters.searchable || f.searchable) && self.options.filter(f);
});
}).bind(this));
},
@@ -299,7 +312,7 @@ var ModelFieldSelector = Widget.extend({
_pushPageData: function (model) {
var def;
if (this.model === model && this.options.fields) {
def = $.when(sortFields(this.options.fields, model));
def = $.when(sortFields(this.options.fields, model, this.options.order));
} else {
def = this._getModelFieldsFromCache(model, this.options.filters);
}
@@ -345,7 +358,7 @@ var ModelFieldSelector = Widget.extend({
}
this.$(".o_field_selector_popover_header .o_field_selector_title").text(title);
this.$(".o_field_selector_page").replaceWith(core.qweb.render(this.template + ".page", {
lines: page,
lines: _.filter(page, this.options.filter),
followRelations: this.options.followRelations,
debug: this.options.debugMode,
}));
@@ -544,16 +557,18 @@ return ModelFieldSelector;
* contain additional keys "model" and "name" with the field
* name)
*/
function sortFields(fields, model) {
return _.chain(fields)
function sortFields(fields, model, order) {
var array = _.chain(fields)
.pairs()
.sortBy(function (p) { return p[1].string; })
.map(function (p) {
.sortBy(function (p) { return p[1].string; });
if (order !== 'string') {
array = array.sortBy(function (p) {return p[1][order]; });
}
return array.map(function (p) {
return _.extend({
name: p[0],
model: model,
}, p[1]);
})
.value();
}).value();
}
});
+1 -1
View File
@@ -771,7 +771,7 @@
</t>
<ul t-name="ModelFieldSelector.page" class="o_field_selector_page">
<t t-foreach="lines" t-as="line">
<t t-set="relationToFollow" t-value="followRelations &amp;&amp; line.relation"/>
<t t-set="relationToFollow" t-value="followRelations(line) &amp;&amp; line.relation"/>
<li t-attf-class="o_field_selector_item #{relationToFollow and 'o_field_selector_next_page' or 'o_field_selector_select_button'}#{line_index == 0 and ' active' or ''}"
t-att-data-name="line.name">
<t t-esc="line.string"/>
@@ -167,6 +167,30 @@ QUnit.module('ModelFieldSelector', {
}).join(" -> ");
}
});
QUnit.test("use the filter option", function (assert) {
assert.expect(2);
var $target = $("#qunit-fixture");
// Create the field selector and its mock environment
var fieldSelector = new ModelFieldSelector(null, "partner", [], {
readonly: false,
filter: function (field) {
return field.type === 'many2one';
},
});
testUtils.addMockEnvironment(fieldSelector, {data: this.data});
fieldSelector.appendTo($target);
fieldSelector.$el.trigger('focusin');
var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
var $lis = $fieldSelectorPopover.find("li");
assert.strictEqual($lis.length, 1, "there should only be one element");
assert.strictEqual($lis.text().trim(), "Product", "the available field should be the many2one");
fieldSelector.destroy();
});
});
});
});