[FIX] implement forgotten @invisible handling on search view fields
bzr revid: xmo@openerp.com-20130304152047-8xaczg9qdx6ug2p1
This commit is contained in:
commit
b921444d6f
|
@ -107,6 +107,12 @@ formatted differently). If an input *may* fetch multiple completion
|
|||
items, it *should* prefix those with a section title using its own
|
||||
name. This has no technical consequence but is clearer for users.
|
||||
|
||||
.. note::
|
||||
|
||||
If a field is :js:func:`invisible
|
||||
<openerp.web.search.Input.visible>`, its completion function will
|
||||
*not* be called.
|
||||
|
||||
Providing drawer/supplementary UI
|
||||
+++++++++++++++++++++++++++++++++
|
||||
|
||||
|
@ -145,6 +151,11 @@ started only once (per view).
|
|||
dynamically collects, lays out and renders filters? =>
|
||||
exercises drawer thingies
|
||||
|
||||
.. note::
|
||||
|
||||
An :js:func:`invisible <openerp.web.search.Input.visible>` input
|
||||
will not be inserted into the drawer.
|
||||
|
||||
Converting from facet objects
|
||||
+++++++++++++++++++++++++++++
|
||||
|
||||
|
|
|
@ -359,7 +359,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
this.has_defaults = !_.isEmpty(this.defaults);
|
||||
|
||||
this.inputs = [];
|
||||
this.controls = {};
|
||||
this.controls = [];
|
||||
|
||||
this.headless = this.options.hidden && !this.has_defaults;
|
||||
|
||||
|
@ -499,6 +499,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
*/
|
||||
complete_global_search: function (req, resp) {
|
||||
$.when.apply(null, _(this.inputs).chain()
|
||||
.filter(function (input) { return input.visible(); })
|
||||
.invoke('complete', req.term)
|
||||
.value()).then(function () {
|
||||
resp(_(_(arguments).compact()).flatten(true));
|
||||
|
@ -587,18 +588,18 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
*
|
||||
* @param {Array} items a list of nodes to convert to widgets
|
||||
* @param {Object} fields a mapping of field names to (ORM) field attributes
|
||||
* @param {String} [group_name] name of the group to put the new controls in
|
||||
* @param {Object} [group] group to put the new controls in
|
||||
*/
|
||||
make_widgets: function (items, fields, group_name) {
|
||||
group_name = group_name || null;
|
||||
if (!(group_name in this.controls)) {
|
||||
this.controls[group_name] = [];
|
||||
make_widgets: function (items, fields, group) {
|
||||
if (!group) {
|
||||
group = new instance.web.search.Group(
|
||||
this, 'q', {attrs: {string: _t("Filters")}});
|
||||
}
|
||||
var self = this, group = this.controls[group_name];
|
||||
var self = this;
|
||||
var filters = [];
|
||||
_.each(items, function (item) {
|
||||
if (filters.length && item.tag !== 'filter') {
|
||||
group.push(new instance.web.search.FilterGroup(filters, this));
|
||||
group.push(new instance.web.search.FilterGroup(filters, group));
|
||||
filters = [];
|
||||
}
|
||||
|
||||
|
@ -606,15 +607,18 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
case 'separator': case 'newline':
|
||||
break;
|
||||
case 'filter':
|
||||
filters.push(new instance.web.search.Filter(item, this));
|
||||
filters.push(new instance.web.search.Filter(item, group));
|
||||
break;
|
||||
case 'group':
|
||||
self.make_widgets(item.children, fields, item.attrs.string);
|
||||
self.make_widgets(item.children, fields,
|
||||
new instance.web.search.Group(group, 'w', item));
|
||||
break;
|
||||
case 'field':
|
||||
group.push(this.make_field(item, fields[item['attrs'].name]));
|
||||
var field = this.make_field(
|
||||
item, fields[item['attrs'].name], group);
|
||||
group.push(field);
|
||||
// filters
|
||||
self.make_widgets(item.children, fields, group_name);
|
||||
self.make_widgets(item.children, fields, group);
|
||||
break;
|
||||
}
|
||||
}, this);
|
||||
|
@ -629,12 +633,13 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
|
|||
*
|
||||
* @param {Object} item fields_view_get node for the field
|
||||
* @param {Object} field fields_get result for the field
|
||||
* @param {Object} [parent]
|
||||
* @returns instance.web.search.Field
|
||||
*/
|
||||
make_field: function (item, field) {
|
||||
make_field: function (item, field, parent) {
|
||||
var obj = instance.web.search.fields.get_any( [item.attrs.widget, field.type]);
|
||||
if(obj) {
|
||||
return new (obj) (item, field, this);
|
||||
return new (obj) (item, field, parent || this);
|
||||
} else {
|
||||
console.group('Unknown field type ' + field.type);
|
||||
console.error('View node', item);
|
||||
|
@ -869,13 +874,18 @@ instance.web.search.Widget = instance.web.Widget.extend( /** @lends instance.web
|
|||
* @constructs instance.web.search.Widget
|
||||
* @extends instance.web.Widget
|
||||
*
|
||||
* @param view the ancestor view of this widget
|
||||
* @param parent parent of this widget
|
||||
*/
|
||||
init: function (view) {
|
||||
this._super(view);
|
||||
this.view = view;
|
||||
init: function (parent) {
|
||||
this._super(parent);
|
||||
var ancestor = parent;
|
||||
do {
|
||||
this.view = ancestor;
|
||||
} while (!(ancestor instanceof instance.web.SearchView)
|
||||
&& (ancestor = (ancestor.getParent && ancestor.getParent())));
|
||||
}
|
||||
});
|
||||
|
||||
instance.web.search.add_expand_listener = function($root) {
|
||||
$root.find('a.searchview_group_string').click(function (e) {
|
||||
$root.toggleClass('folded expanded');
|
||||
|
@ -884,13 +894,24 @@ instance.web.search.add_expand_listener = function($root) {
|
|||
});
|
||||
};
|
||||
instance.web.search.Group = instance.web.search.Widget.extend({
|
||||
template: 'SearchView.group',
|
||||
init: function (view_section, view, fields) {
|
||||
this._super(view);
|
||||
this.attrs = view_section.attrs;
|
||||
this.lines = view.make_widgets(
|
||||
view_section.children, fields);
|
||||
}
|
||||
init: function (parent, icon, node) {
|
||||
this._super(parent);
|
||||
var attrs = node.attrs;
|
||||
this.modifiers = attrs.modifiers =
|
||||
attrs.modifiers ? JSON.parse(attrs.modifiers) : {};
|
||||
this.attrs = attrs;
|
||||
this.icon = icon;
|
||||
this.name = attrs.string;
|
||||
this.children = [];
|
||||
|
||||
this.view.controls.push(this);
|
||||
},
|
||||
push: function (input) {
|
||||
this.children.push(input);
|
||||
},
|
||||
visible: function () {
|
||||
return !this.modifiers.invisible;
|
||||
},
|
||||
});
|
||||
|
||||
instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instance.web.search.Input# */{
|
||||
|
@ -899,12 +920,12 @@ instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instan
|
|||
* @constructs instance.web.search.Input
|
||||
* @extends instance.web.search.Widget
|
||||
*
|
||||
* @param view
|
||||
* @param parent
|
||||
*/
|
||||
init: function (view) {
|
||||
this._super(view);
|
||||
init: function (parent) {
|
||||
this._super(parent);
|
||||
this.load_attrs({});
|
||||
this.view.inputs.push(this);
|
||||
this.style = undefined;
|
||||
},
|
||||
/**
|
||||
* Fetch auto-completion values for the widget.
|
||||
|
@ -952,15 +973,30 @@ instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instan
|
|||
"get_domain not implemented for widget " + this.attrs.type);
|
||||
},
|
||||
load_attrs: function (attrs) {
|
||||
if (attrs.modifiers) {
|
||||
attrs.modifiers = JSON.parse(attrs.modifiers);
|
||||
attrs.invisible = attrs.modifiers.invisible || false;
|
||||
if (attrs.invisible) {
|
||||
this.style = 'display: none;'
|
||||
attrs.modifiers = attrs.modifiers ? JSON.parse(attrs.modifiers) : {};
|
||||
this.attrs = attrs;
|
||||
},
|
||||
/**
|
||||
* Returns whether the input is "visible". The default behavior is to
|
||||
* query the ``modifiers.invisible`` flag on the input's description or
|
||||
* view node.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
visible: function () {
|
||||
if (this.attrs.modifiers.invisible) {
|
||||
return false;
|
||||
}
|
||||
var parent = this;
|
||||
while ((parent = parent.getParent()) &&
|
||||
( (parent instanceof instance.web.search.Group)
|
||||
|| (parent instanceof instance.web.search.Input))) {
|
||||
if (!parent.visible()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.attrs = attrs;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends instance.web.search.FilterGroup# */{
|
||||
template: 'SearchView.filters',
|
||||
|
@ -974,17 +1010,17 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
* @extends instance.web.search.Input
|
||||
*
|
||||
* @param {Array<instance.web.search.Filter>} filters elements of the group
|
||||
* @param {instance.web.SearchView} view view in which the filters are contained
|
||||
* @param {instance.web.SearchView} parent parent in which the filters are contained
|
||||
*/
|
||||
init: function (filters, view) {
|
||||
init: function (filters, parent) {
|
||||
// If all filters are group_by and we're not initializing a GroupbyGroup,
|
||||
// create a GroupbyGroup instead of the current FilterGroup
|
||||
if (!(this instanceof instance.web.search.GroupbyGroup) &&
|
||||
_(filters).all(function (f) {
|
||||
return f.attrs.context && f.attrs.context.group_by; })) {
|
||||
return new instance.web.search.GroupbyGroup(filters, view);
|
||||
return new instance.web.search.GroupbyGroup(filters, parent);
|
||||
}
|
||||
this._super(view);
|
||||
this._super(parent);
|
||||
this.filters = filters;
|
||||
this.view.query.on('add remove change reset', this.proxy('search_change'));
|
||||
},
|
||||
|
@ -1103,6 +1139,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
var self = this;
|
||||
item = item.toLowerCase();
|
||||
var facet_values = _(this.filters).chain()
|
||||
.filter(function (filter) { return filter.visible(); })
|
||||
.filter(function (filter) {
|
||||
var at = {
|
||||
string: filter.attrs.string || '',
|
||||
|
@ -1129,8 +1166,8 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
|
|||
instance.web.search.GroupbyGroup = instance.web.search.FilterGroup.extend({
|
||||
icon: 'w',
|
||||
completion_label: _lt("Group by: %s"),
|
||||
init: function (filters, view) {
|
||||
this._super(filters, view);
|
||||
init: function (filters, parent) {
|
||||
this._super(filters, parent);
|
||||
// Not flanders: facet unicity is handled through the
|
||||
// (category, field) pair of facet attributes. This is all well and
|
||||
// good for regular filter groups where a group matches a facet, but for
|
||||
|
@ -1138,8 +1175,8 @@ instance.web.search.GroupbyGroup = instance.web.search.FilterGroup.extend({
|
|||
// view which proxies to the first GroupbyGroup, so it can be used
|
||||
// for every GroupbyGroup and still provides the various methods needed
|
||||
// by the search view. Use weirdo name to avoid risks of conflicts
|
||||
if (!this.getParent()._s_groupby) {
|
||||
this.getParent()._s_groupby = {
|
||||
if (!this.view._s_groupby) {
|
||||
this.view._s_groupby = {
|
||||
help: "See GroupbyGroup#init",
|
||||
get_context: this.proxy('get_context'),
|
||||
get_domain: this.proxy('get_domain'),
|
||||
|
@ -1148,7 +1185,7 @@ instance.web.search.GroupbyGroup = instance.web.search.FilterGroup.extend({
|
|||
}
|
||||
},
|
||||
match_facet: function (facet) {
|
||||
return facet.get('field') === this.getParent()._s_groupby;
|
||||
return facet.get('field') === this.view._s_groupby;
|
||||
},
|
||||
make_facet: function (values) {
|
||||
return {
|
||||
|
@ -1173,10 +1210,10 @@ instance.web.search.Filter = instance.web.search.Input.extend(/** @lends instanc
|
|||
* @extends instance.web.search.Input
|
||||
*
|
||||
* @param node
|
||||
* @param view
|
||||
* @param parent
|
||||
*/
|
||||
init: function (node, view) {
|
||||
this._super(view);
|
||||
init: function (node, parent) {
|
||||
this._super(parent);
|
||||
this.load_attrs(node.attrs);
|
||||
},
|
||||
facet_for: function () { return $.when(null); },
|
||||
|
@ -1192,10 +1229,10 @@ instance.web.search.Field = instance.web.search.Input.extend( /** @lends instanc
|
|||
*
|
||||
* @param view_section
|
||||
* @param field
|
||||
* @param view
|
||||
* @param parent
|
||||
*/
|
||||
init: function (view_section, field, view) {
|
||||
this._super(view);
|
||||
init: function (view_section, field, parent) {
|
||||
this._super(parent);
|
||||
this.load_attrs(_.extend({}, field, view_section.attrs));
|
||||
},
|
||||
facet_for: function (value) {
|
||||
|
@ -1235,7 +1272,7 @@ instance.web.search.Field = instance.web.search.Input.extend( /** @lends instanc
|
|||
*
|
||||
* @param {String} name the field's name
|
||||
* @param {String} operator the field's operator (either attribute-specified or default operator for the field
|
||||
* @param {Number|String} value parsed value for the field
|
||||
* @param {Number|String} facet parsed value for the field
|
||||
* @returns {Array<Array>} domain to include in the resulting search
|
||||
*/
|
||||
make_domain: function (name, operator, facet) {
|
||||
|
@ -1467,8 +1504,8 @@ instance.web.search.DateTimeField = instance.web.search.DateField.extend(/** @le
|
|||
});
|
||||
instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
|
||||
default_operator: {},
|
||||
init: function (view_section, field, view) {
|
||||
this._super(view_section, field, view);
|
||||
init: function (view_section, field, parent) {
|
||||
this._super(view_section, field, parent);
|
||||
this.model = new instance.web.Model(this.attrs.relation);
|
||||
},
|
||||
complete: function (needle) {
|
||||
|
@ -1716,22 +1753,28 @@ instance.web.search.Filters = instance.web.search.Input.extend({
|
|||
var running_count = 0;
|
||||
// get total filters count
|
||||
var is_group = function (i) { return i instanceof instance.web.search.FilterGroup; };
|
||||
var filters_count = _(this.view.controls).chain()
|
||||
var visible_filters = _(this.view.controls).chain().reject(function (group) {
|
||||
return _(_(group.children).filter(is_group)).isEmpty()
|
||||
|| group.modifiers.invisible;
|
||||
});
|
||||
var filters_count = visible_filters
|
||||
.pluck('children')
|
||||
.flatten()
|
||||
.filter(is_group)
|
||||
.map(function (i) { return i.filters.length; })
|
||||
.sum()
|
||||
.value();
|
||||
|
||||
var col1 = [], col2 = _(this.view.controls).map(function (inputs, group) {
|
||||
var filters = _(inputs).filter(is_group);
|
||||
return {
|
||||
name: group === 'null' ? "<span class='oe_i'>q</span> " + _t("Filters") : "<span class='oe_i'>w</span> " + group,
|
||||
filters: filters,
|
||||
length: _(filters).chain().map(function (i) {
|
||||
return i.filters.length; }).sum().value()
|
||||
};
|
||||
});
|
||||
var col1 = [], col2 = visible_filters.map(function (group) {
|
||||
var filters = _(group.children).filter(is_group);
|
||||
return {
|
||||
name: _.str.sprintf("<span class='oe_i'>%s</span> %s",
|
||||
group.icon, group.name),
|
||||
filters: filters,
|
||||
length: _(filters).chain().map(function (i) {
|
||||
return i.filters.length; }).sum().value()
|
||||
};
|
||||
}).value();
|
||||
|
||||
while (col2.length) {
|
||||
// col1 + group should be smaller than col2 + group
|
||||
|
|
|
@ -1496,7 +1496,7 @@
|
|||
<t t-esc="attrs.string"/>
|
||||
</button>
|
||||
<ul t-name="SearchView.filters">
|
||||
<li t-foreach="widget.filters" t-as="filter"
|
||||
<li t-foreach="widget.filters" t-as="filter" t-if="filter.visible()"
|
||||
t-att-title="filter.attrs.string ? filter.attrs.help : undefined">
|
||||
<t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/>
|
||||
</li>
|
||||
|
@ -1584,15 +1584,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.group">
|
||||
<t t-call="SearchView.util.expand">
|
||||
<t t-set="expand" t-value="attrs.expand"/>
|
||||
<t t-set="label" t-value="attrs.string"/>
|
||||
<t t-set="content">
|
||||
<t t-call="SearchView.render_lines"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
<div t-name="SearchView.Filters" class="oe_searchview_filters oe_searchview_section">
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
openerp.testing.section('query', {
|
||||
openerp.testing.section('search.query', {
|
||||
dependencies: ['web.search']
|
||||
}, function (test) {
|
||||
test('Adding a facet to the query creates a facet and a value', function (instance) {
|
||||
|
@ -180,7 +180,7 @@ var makeSearchView = function (instance, dummy_widget_attributes, defaults) {
|
|||
});
|
||||
return view;
|
||||
};
|
||||
openerp.testing.section('defaults', {
|
||||
openerp.testing.section('search.defaults', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
|
@ -362,7 +362,7 @@ openerp.testing.section('defaults', {
|
|||
"should not accept multiple default values");
|
||||
})
|
||||
});
|
||||
openerp.testing.section('completions', {
|
||||
openerp.testing.section('search.completions', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -615,7 +615,7 @@ openerp.testing.section('completions', {
|
|||
return f.complete("bob");
|
||||
});
|
||||
});
|
||||
openerp.testing.section('search-serialization', {
|
||||
openerp.testing.section('search.serialization', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -922,7 +922,7 @@ openerp.testing.section('search-serialization', {
|
|||
return $.when(t1, t2);
|
||||
});
|
||||
});
|
||||
openerp.testing.section('removal', {
|
||||
openerp.testing.section('search.removal', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -945,7 +945,7 @@ openerp.testing.section('removal', {
|
|||
});
|
||||
});
|
||||
});
|
||||
openerp.testing.section('drawer', {
|
||||
openerp.testing.section('search.drawer', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -961,7 +961,7 @@ openerp.testing.section('drawer', {
|
|||
});
|
||||
});
|
||||
});
|
||||
openerp.testing.section('filters', {
|
||||
openerp.testing.section('search.filters', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
|
@ -1046,7 +1046,7 @@ openerp.testing.section('filters', {
|
|||
});
|
||||
});
|
||||
});
|
||||
openerp.testing.section('saved_filters', {
|
||||
openerp.testing.section('search.filters.saved', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -1150,7 +1150,7 @@ openerp.testing.section('saved_filters', {
|
|||
});
|
||||
});
|
||||
});
|
||||
openerp.testing.section('advanced', {
|
||||
openerp.testing.section('search.advanced', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
|
@ -1231,3 +1231,159 @@ openerp.testing.section('advanced', {
|
|||
});
|
||||
// TODO: UI tests?
|
||||
});
|
||||
openerp.testing.section('search.invisible', {
|
||||
dependencies: ['web.search'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
}, function (test) {
|
||||
var registerTestField = function (instance, methods) {
|
||||
instance.web.search.fields.add('test', 'instance.testing.TestWidget');
|
||||
instance.testing = {
|
||||
TestWidget: instance.web.search.Field.extend(methods),
|
||||
};
|
||||
};
|
||||
var makeView = function (instance, mock, fields, arch, defaults) {
|
||||
mock('ir.filters:get_filters', function () { return []; });
|
||||
mock('test.model:fields_get', function () { return fields; });
|
||||
mock('test.model:fields_view_get', function () {
|
||||
return { type: 'search', fields: fields, arch: arch };
|
||||
});
|
||||
var ds = new instance.web.DataSet(null, 'test.model');
|
||||
return new instance.web.SearchView(null, ds, false, defaults);
|
||||
};
|
||||
// Invisible fields should not auto-complete
|
||||
test('invisible-field-no-autocomplete', {asserts: 1}, function (instance, $fix, mock) {
|
||||
registerTestField(instance, {
|
||||
complete: function () {
|
||||
return $.when([{label: this.attrs.string}]);
|
||||
},
|
||||
});
|
||||
var view = makeView(instance, mock, {
|
||||
field0: {type: 'test', string: 'Field 0'},
|
||||
field1: {type: 'test', string: 'Field 1'},
|
||||
}, ['<search>',
|
||||
'<field name="field0"/>',
|
||||
'<field name="field1" modifiers="{"invisible": true}"/>',
|
||||
'</search>'].join());
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
var done = $.Deferred();
|
||||
view.complete_global_search({term: 'test'}, function (comps) {
|
||||
done.resolve(comps);
|
||||
});
|
||||
return done;
|
||||
}).then(function (completions) {
|
||||
deepEqual(completions, [{label: 'Field 0'}],
|
||||
"should only complete the visible field");
|
||||
});
|
||||
});
|
||||
// Invisible filters should not appear in the drawer
|
||||
test('invisible-filter-no-drawer', {asserts: 4}, function (instance, $fix, mock) {
|
||||
var view = makeView(instance, mock, {}, [
|
||||
'<search>',
|
||||
'<filter string="filter 0"/>',
|
||||
'<filter string="filter 1" modifiers="{"invisible": true}"/>',
|
||||
'</search>'].join());
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
var $fs = $fix.find('.oe_searchview_filters ul');
|
||||
strictEqual($fs.children().length,
|
||||
1,
|
||||
"should only display one filter");
|
||||
strictEqual(_.str.trim($fs.children().text()),
|
||||
"filter 0",
|
||||
"should only display filter 0");
|
||||
var done = $.Deferred();
|
||||
view.complete_global_search({term: 'filter'}, function (comps) {
|
||||
done.resolve();
|
||||
strictEqual(comps.length, 1, "should only complete visible filter");
|
||||
strictEqual(comps[0].label, "Filter on: filter 0",
|
||||
"should complete filter 0");
|
||||
});
|
||||
return done;
|
||||
});
|
||||
});
|
||||
// Invisible filter groups should not appear in the drawer
|
||||
// Group invisibility should be inherited by children
|
||||
test('group-invisibility', {asserts: 6}, function (instance, $fix, mock) {
|
||||
registerTestField(instance, {
|
||||
complete: function () {
|
||||
return $.when([{label: this.attrs.string}]);
|
||||
},
|
||||
});
|
||||
var view = makeView(instance, mock, {
|
||||
field0: {type: 'test', string: 'Field 0'},
|
||||
field1: {type: 'test', string: 'Field 1'},
|
||||
}, [
|
||||
'<search>',
|
||||
'<group string="Visibles">',
|
||||
'<field name="field0"/>',
|
||||
'<filter string="Filter 0"/>',
|
||||
'</group>',
|
||||
'<group string="Invisibles" modifiers="{"invisible": true}">',
|
||||
'<field name="field1"/>',
|
||||
'<filter string="Filter 1"/>',
|
||||
'</group>',
|
||||
'</search>'
|
||||
].join(''));
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
strictEqual($fix.find('.oe_searchview_filters h3').length,
|
||||
1,
|
||||
"should only display one group");
|
||||
strictEqual($fix.find('.oe_searchview_filters h3').text(),
|
||||
'w Visibles',
|
||||
"should only display the Visibles group (and its icon char)");
|
||||
|
||||
var $fs = $fix.find('.oe_searchview_filters ul');
|
||||
strictEqual($fs.children().length, 1,
|
||||
"should only have one filter in the drawer");
|
||||
strictEqual(_.str.trim($fs.text()), "Filter 0",
|
||||
"should have filter 0 as sole filter");
|
||||
|
||||
var done = $.Deferred();
|
||||
view.complete_global_search({term: 'filter'}, function (compls) {
|
||||
done.resolve();
|
||||
strictEqual(compls.length, 2,
|
||||
"should have 2 completions");
|
||||
deepEqual(_.pluck(compls, 'label'),
|
||||
['Field 0', 'Filter on: Filter 0'],
|
||||
"should complete on field 0 and filter 0");
|
||||
});
|
||||
return done;
|
||||
});
|
||||
});
|
||||
// Default on invisible fields should still work, for fields and filters both
|
||||
test('invisible-defaults', {asserts: 1}, function (instance, $fix, mock) {
|
||||
var view = makeView(instance, mock, {
|
||||
field: {type: 'char', string: "Field"},
|
||||
field2: {type: 'char', string: "Field 2"},
|
||||
}, [
|
||||
'<search>',
|
||||
'<field name="field2"/>',
|
||||
'<filter name="filter2" string="Filter"',
|
||||
' domain="[[\'qwa\', \'=\', 42]]"/>',
|
||||
'<group string="Invisibles" modifiers="{"invisible": true}">',
|
||||
'<field name="field"/>',
|
||||
'<filter name="filter" string="Filter"',
|
||||
' domain="[[\'whee\', \'=\', \'42\']]"/>',
|
||||
'</group>',
|
||||
'</search>'
|
||||
].join(''), {field: "foo", filter: true});
|
||||
|
||||
return view.appendTo($fix)
|
||||
.then(function () {
|
||||
deepEqual(view.build_search_data(), {
|
||||
errors: [],
|
||||
groupbys: [],
|
||||
contexts: [],
|
||||
domains: [
|
||||
// Generated from field
|
||||
[['field', 'ilike', 'foo']],
|
||||
// generated from filter
|
||||
"[['whee', '=', '42']]"
|
||||
],
|
||||
}, "should yield invisible fields selected by defaults");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue