},
'click .oe_searchview_unfold_drawer': function (e) {
e.stopImmediatePropagation();
- $(e.target).toggleClass('fa-chevron-right')
- .toggleClass('fa-chevron-down');
- localStorage.visible_search_menu = !(localStorage.visible_search_menu === 'true');
+ $(e.target).toggleClass('fa-caret-down fa-caret-up');
+ localStorage.visible_search_menu = (localStorage.visible_search_menu !== 'true');
this.toggle_buttons();
},
'keydown .oe_searchview_input, .oe_searchview_facet': function (e) {
this.search_fields = [];
this.filters = [];
this.groupbys = [];
- this.visible_filters = !!(localStorage.visible_search_menu === 'true');
+ this.visible_filters = (localStorage.visible_search_menu === 'true');
this.input_subviews = []; // for user input in searchbar
this.defaults = defaults || {};
this.headless = this.options.hidden && _.isEmpty(this.defaults);
this.filter_menu = undefined;
this.groupby_menu = undefined;
- this.favorite_menu = undefined
+ this.favorite_menu = undefined;
+ this.action_id = this.options && this.options.action && this.options.action.id;
},
start: function() {
if (this.headless) {
context: this.dataset.get_context(),
});
this.$('.oe_searchview_unfold_drawer')
- .toggleClass('fa-chevron-right', !this.visible_filters)
- .toggleClass('fa-chevron-down', this.visible_filters);
- return $.when(this._super(), this.alive($.when(load_view))
- .then(this.view_loaded.bind(this)));
+ .toggleClass('fa-caret-down', !this.visible_filters)
+ .toggleClass('fa-caret-up', this.visible_filters);
+ return this.alive($.when(this._super(), load_view.then(this.view_loaded.bind(this))));
},
view_loaded: function (r) {
var self = this;
this.fields_view_get = r;
+ this.view_id = this.view_id || r.view_id;
this.prepare_search_inputs();
if (this.$buttons) {
this.groupby_menu = new my.GroupByMenu(this, this.groupbys, fields_def);
this.filter_menu = new my.FilterMenu(this, this.filters, fields_def);
- this.favorite_menu = new my.FavoriteMenu(this, this.query, this.dataset.model);
+ this.favorite_menu = new my.FavoriteMenu(this, this.query, this.dataset.model, this.action_id);
this.filter_menu.appendTo(this.$buttons);
this.groupby_menu.appendTo(this.$buttons);
}
return $.when(custom_filters_ready).then(this.proxy('set_default_filters'));
},
- set_default_filters: function (a, b) {
+ // it should parse the arch field of the view, instantiate the corresponding
+ // filters/fields, and put them in the correct variables:
+ // * this.search_fields is a list of all the fields,
+ // * this.filters: groups of filters
+ // * this.group_by: group_bys
+ prepare_search_inputs: function () {
+ var self = this,
+ arch = this.fields_view_get.arch;
+
+ var filters = [].concat.apply([], _.map(arch.children, function (item) {
+ return item.tag !== 'group' ? eval_item(item) : item.children.map(eval_item);
+ }));
+ function eval_item (item) {
+ var category = 'filters';
+ if (item.attrs.context) {
+ try {
+ var context = instance.web.pyeval.eval('context', item.attrs.context);
+ if (context.group_by) {
+ category = 'group_by';
+ }
+ } catch (e) {}
+ }
+ return {
+ item: item,
+ category: category,
+ }
+ }
+ var current_group = [],
+ current_category = 'filters',
+ categories = {filters: this.filters, group_by: this.groupbys};
+
+ _.each(filters.concat({category:'filters', item: 'separator'}), function (filter) {
+ if (filter.item.tag === 'filter' && filter.category === current_category) {
+ return current_group.push(new my.Filter(filter.item, self));
+ }
+ if (current_group.length) {
+ var group = new my.FilterGroup(current_group, self);
+ categories[current_category].push(group);
+ current_group = [];
+ }
+ if (filter.item.tag === 'field') {
+ var attrs = filter.item.attrs,
+ field = self.fields_view_get.fields[attrs.name],
+ Obj = my.fields.get_any([attrs.widget, field.type]);
+ if (Obj) {
+ self.search_fields.push(new (Obj) (filter.item, field, self));
+ }
+ }
+ if (filter.item.tag === 'filter') {
+ current_group.push(new my.Filter(filter.item, self));
+ }
+ current_category = filter.category;
+ });
+ },
+ set_default_filters: function () {
var self = this,
default_custom_filter = this.$buttons && this.favorite_menu.get_default_filter();
if (default_custom_filter) {
source: this.proxy('complete_global_search'),
select: this.proxy('select_completion'),
delay: 0,
- get_search_string: function () {
- return self.$('div.oe_searchview_input').text();
+ get_search_string: function () {
+ return self.$('div.oe_searchview_input').text();
},
});
this.autocomplete.appendTo(this.$el);
},
childFocused: function () {
this.$el.addClass('active');
+ this.view_id = this.view_id || data.view_id;
},
childBlurred: function () {
- var val = this.$el.val();
- this.$el.val('');
- this.$el.removeClass('active')
- .trigger('blur');
+ this.$el.val('').removeClass('active').trigger('blur');
this.autocomplete.close();
},
/**
renderChangedFacets: function (model, options) {
this.renderFacets(undefined, model, options);
},
- // it should parse the arch field of the view, instantiate the corresponding
- // filters/fields, and put them in the correct variables:
- // * this.search_fields is a list of all the fields,
- // * this.filters: groups of filters
- // * this.group_by: group_bys
- prepare_search_inputs: function () {
- var self = this,
- arch = this.fields_view_get.arch;
-
- var filters = [].concat.apply([], _.map(arch.children, function (item) {
- return item.tag !== 'group' ? eval_item(item) : item.children.map(eval_item);
- }));
- function eval_item (item) {
- var category = 'filters';
- if (item.attrs.context) {
- try {
- var context = instance.web.pyeval.eval('context', item.attrs.context);
- if (context.group_by) {
- category = 'group_by';
- }
- } catch (e) {}
- }
- return {
- item: item,
- category: category,
- }
- }
- var current_group = [],
- current_category = 'filters',
- categories = {filters: this.filters, group_by: this.groupbys};
-
- _.each(filters.concat({category:'filters', item: 'separator'}), function (filter) {
- if (filter.item.tag === 'filter' && filter.category === current_category) {
- return current_group.push(new my.Filter(filter.item, self));
- }
- if (current_group.length) {
- var group = new my.FilterGroup(current_group, self);
- categories[current_category].push(group);
- current_group = [];
- }
- if (filter.item.tag === 'field') {
- var attrs = filter.item.attrs,
- field = self.fields_view_get.fields[attrs.name],
- Obj = my.fields.get_any([attrs.widget, field.type]);
- if (Obj) {
- self.search_fields.push(new (Obj) (filter.item, field, self));
- }
- }
- if (filter.item.tag === 'filter') {
- current_group.push(new my.Filter(filter.item, self));
- }
- current_category = filter.category;
- });
- },
});
/**
*/
visible: function () {
return !this.attrs.modifiers.invisible;
-
- // var parent = this;
- // while ((parent = parent.getParent()) &&
- // ( (parent instanceof instance.web.search.Group)
- // || (parent instanceof instance.web.search.Input))) {
- // if (!parent.visible()) {
- // return false;
- // }
- // }
- // return true;
},
});
instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends instance.web.search.FilterGroup# */{
toggle: function (filter, options) {
this.searchview.query.toggle(this.make_facet([this.make_value(filter)]), options);
},
+ is_visible: function () {
+ return _.some(this.filters, function (filter) {
+ return !filter.attrs.invisible;
+ });
+ },
complete: function (item) {
var self = this;
item = item.toLowerCase();
return instance.web.date_to_str(facetValue.get('value'));
},
complete: function (needle) {
- var d = Date.parse(needle);
- if (!d) { return $.when(null); }
+ var m = moment(needle);
+ if (!m.isValid()) { return $.when(null); }
+ var d = m.toDate();
var date_string = instance.web.format_value(d, this.attrs);
var label = _.str.sprintf(_.str.escapeHTML(
_t("Search %(field)s at: %(value)s")), {
var values = facet.values;
if (_.isEmpty(this.attrs.context) && values.length === 1) {
var c = {};
- c['default_' + this.attrs.name] = values.at(0).get('value');
+ var v = values.at(0);
+ if (v.get('operator') !== 'ilike') {
+ c['default_' + this.attrs.name] = v.get('value');
+ }
return c;
}
return this._super(facet);
this.$apply_filter = this.$('.oe-apply-filter');
this.$add_filter_menu = this.$('.oe-add-filter-menu');
_.each(this.filters, function (group) {
- group.insertBefore(self.$add_filter);
- $('<li>').addClass('divider').insertBefore(self.$add_filter);
+ if (group.is_visible()) {
+ group.insertBefore(self.$add_filter);
+ $('<li class="divider">').insertBefore(self.$add_filter);
+ }
});
this.append_proposition().then(function (prop) {
prop.$el.hide();
});
},
+ update_max_height: function () {
+ var max_height = $(window).height() - this.$menu[0].getBoundingClientRect().top - 10;
+ this.$menu.css('max-height', max_height);
+ },
toggle_custom_filter_menu: function (is_open) {
this.$add_filter
.toggleClass('closed-menu', !is_open)
this.append_proposition();
}
this.$('.oe-filter-condition').toggle(is_open);
+ this.update_max_height();
},
append_proposition: function () {
var self = this;
self.propositions.push(prop);
prop.insertBefore(self.$add_filter_menu);
self.$apply_filter.prop('disabled', false);
+ self.update_max_height();
return prop;
});
},
remove_proposition: function (prop) {
- this.propositions = _.reject(this.propositions, function (p) { return p === prop});
+ this.propositions = _.without(this.propositions, prop);
if (!this.propositions.length) {
this.$apply_filter.prop('disabled', true);
}
prop.destroy();
},
commit_search: function () {
- var self = this,
- filters = _.invoke(this.propositions, 'get_filter'),
+ var filters = _.invoke(this.propositions, 'get_filter'),
filters_widgets = _.map(filters, function (filter) {
- return new my.Filter(filter, self);
- });
- var filter_group = new my.FilterGroup(filters_widgets, this.searchview);
+ return new my.Filter(filter, this);
+ }),
+ filter_group = new my.FilterGroup(filters_widgets, this.searchview),
+ facets = filters_widgets.map(function (filter) {
+ return filter_group.make_facet([filter_group.make_value(filter)]);
+ });
filter_group.insertBefore(this.$add_filter);
- $('<li>').addClass('divider').insertBefore(self.$add_filter);
-
- filters_widgets.forEach(function (filter) {
- self.searchview.query.add(filter_group.make_facet([filter_group.make_value(filter)]), {silent: true});
- });
+ $('<li class="divider">').insertBefore(this.$add_filter);
+ this.searchview.query.add(facets, {silent: true});
this.searchview.query.trigger('reset');
_.invoke(this.propositions, 'destroy');
this.close_menus();
},
},
- init: function (parent, query, target_model) {
+ init: function (parent, query, target_model, action_id) {
this._super.apply(this,arguments);
this.searchview = parent;
this.query = query;
this.model = new instance.web.Model('ir.filters');
this.filters = {};
this.$filters = {};
- var action = instance.client.action_manager.inner_action;
- this.action_id = action && action.id;
+ this.action_id = action_id;
},
start: function () {
var self = this;
this.$save_name = this.$('.oe-save-name');
this.$inputs = this.$save_name.find('input');
this.$divider = this.$('.divider');
-
- var $shared_filter = $(this.$inputs[1]),
- $default_filter = $(this.$inputs[2]);
+ this.$inputs.eq(0).val(this.searchview.getParent().title);
+ var $shared_filter = this.$inputs.eq(1),
+ $default_filter = this.$inputs.eq(2);
$shared_filter.click(function () {$default_filter.prop('checked', false)});
$default_filter.click(function () {$shared_filter.prop('checked', false)});
}
})
.on('reset', this.proxy('clear_selection'));
+ if (!this.action_id) return $.when();
return this.model.call('get_filters', [this.target_model, this.action_id])
.done(this.proxy('prepare_dropdown_menu'));
},
save_favorite: function () {
var self = this,
filter_name = this.$inputs[0].value,
- shared_filter = this.$inputs[1].checked,
- default_filter = this.$inputs[2].checked;
+ default_filter = this.$inputs[1].checked,
+ shared_filter = this.$inputs[2].checked;
if (!filter_name.length){
this.do_warn(_t("Error"), _t("Filter name is required."));
this.$inputs.first().focus();
append_filter: function (filter) {
var self = this,
key = this.key_for(filter),
- $filter,
- warning = _t("This filter is global and will be removed for everybody if you continue.");
+ $filter;
this.$divider.show();
if (key in this.$filters) {
this.$filters[key].addClass(filter.user_id ? 'oe_searchview_custom_private'
: 'oe_searchview_custom_public')
$('<span>')
- .addClass('fa fa-trash-o')
+ .addClass('fa fa-trash-o remove-filter')
.click(function (event) {
event.stopImmediatePropagation();
self.remove_filter(filter, $filter, key);
})
.appendTo($filter);
}
- this.$filters[key].unbind('click').click(function (event) {
- event.stopPropagation();
+ this.$filters[key].unbind('click').click(function () {
self.toggle_filter(filter);
});
},
},
remove_filter: function (filter, $filter, key) {
var self = this;
- var warning = _t("This filter is global and will be removed for everybody if you continue.");
- if (!(filter.user_id || confirm(warning))) {
+ var global_warning = _t("This filter is global and will be removed for everybody if you continue."),
+ warning = _t("Are you sure that you want to remove this filter?");
+ if (!confirm(filter.user_id ? warning : global_warning)) {
return;
}
this.model.call('unlink', [filter.id]).done(function () {
delete self.$filters[key];
delete self.filters[key];
if (_.isEmpty(self.filters)) {
- self.$('li.divider').remove();
+ self.$divider.hide();
}
});
},
ev.preventDefault();
return;
}
+ // ENTER is caugth at KeyUp rather than KeyDown to avoid firing
+ // before all regular keystrokes have been processed
+ if (ev.which === $.ui.keyCode.ENTER) {
+ if (self.current_result && self.get_search_string().length) {
+ self.select_item(ev);
+ }
+ return;
+ }
if (!self.searching) {
self.searching = true;
return;
});
this.$input.on('keydown', function (ev) {
switch (ev.which) {
+ // TAB and direction keys are handled at KeyDown because KeyUp
+ // is not guaranteed to fire.
+ // See e.g. https://github.com/aef-/jquery.masterblaster/issues/13
case $.ui.keyCode.TAB:
- case $.ui.keyCode.ENTER:
if (self.current_result && self.get_search_string().length) {
self.select_item(ev);
}