diff options
| author | Géry Debongnie <ged@odoo.com> | 2014-05-19 14:16:09 +0200 |
|---|---|---|
| committer | Géry Debongnie <ged@odoo.com> | 2014-05-19 14:16:09 +0200 |
| commit | 7e6d223e9e6e9ba232c9fa2b1e5629563f5e7a69 (patch) | |
| tree | 1baa6661734b06bc92808108301dbedb7827f3fc | |
| parent | 072485799c87d45c460c7aa76fb2f0e7be1b82ef (diff) | |
[IMP] work on inline search view in web client
incomplete work. So far, the search view widget has been split in
two widgets: SearchView and SearchViewDrawer. The SearchViewDrawer
has been inserted inline, and some preliminary work has been done
to improve the layout.
| -rw-r--r-- | addons/mail/static/src/js/mail.js | 5 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/mail.xml | 1 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.css | 5 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 327 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 9 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 6 |
7 files changed, 198 insertions, 159 deletions
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 99a7751e15e..9cf33203a45 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1888,7 +1888,10 @@ openerp.mail = function (session) { var self = this; var ds_msg = new session.web.DataSetSearch(this, 'mail.message'); this.searchview = new session.web.SearchView(this, ds_msg, false, defaults || {}, false); - this.searchview.appendTo(this.$('.oe_view_manager_view_search')) + this.searchview_drawer = new session.web.SearchViewDrawer(this, this.searchview); + + $.when(this.searchview.appendTo(this.$('.oe_view_manager_view_search')), + this.searchview_drawer.appendTo(this.$('.oe_searchview_drawer_container'))) .then(function () { self.searchview.on('search_data', self, self.do_searchview_search); }); if (this.searchview.has_defaults) { this.searchview.ready.then(this.searchview.do_search); diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index ec7b0fa2911..77aeef0b5b9 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -191,6 +191,7 @@ </tr> </tbody> </table> + <div class="oe_searchview_drawer_container"/> <div class="oe_mail-placeholder"></div> <aside class="oe_mail_wall_aside"></aside> </div> diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index f02dc3c7fd7..03066c171b4 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "utf-8"; +@charset "UTF-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); @@ -1776,6 +1776,9 @@ margin: 0 0 0 4px; padding: 0; } +.openerp .oe_searchview_drawer_container { + border-bottom: 1px solid #afafb6; +} .openerp .oe_view_nocontent { padding: 15px; margin-top: 0; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index c15c90abb7a..e1296924629 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -1280,7 +1280,7 @@ $sheet-padding: 16px &.oe_searchview_open_drawer .oe_searchview_drawer display: block - + .oe_searchview_drawer cursor: default position: absolute @@ -1458,6 +1458,8 @@ $sheet-padding: 16px margin: 0 0 0 4px padding: 0 + .oe_searchview_drawer_container + border-bottom: 1px solid $tag-border // }}} // Views Common {{{ diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 832faa4ca62..88cf7531fec 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -340,7 +340,8 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }, 'click .oe_searchview_unfold_drawer': function (e) { e.stopImmediatePropagation(); - this.$el.toggleClass('oe_searchview_open_drawer'); + if (this.searchview_drawer) + this.searchview_drawer.toggle(); }, 'keydown .oe_searchview_input, .oe_searchview_facet': function (e) { switch(e.which) { @@ -383,14 +384,13 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea this.defaults = defaults || {}; this.has_defaults = !_.isEmpty(this.defaults); - this.inputs = []; - this.controls = []; - this.headless = this.options.hidden && !this.has_defaults; this.input_subviews = []; this.ready = $.Deferred(); + this.drawer_ready = $.Deferred(); + this.fields_view_get = $.Deferred(); }, start: function() { var self = this; @@ -416,20 +416,20 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }); this.alive($.when(load_view)).then(function (r) { + self.fields_view_get.resolve(r); return self.search_view_loaded(r); }).fail(function () { self.ready.reject.apply(null, arguments); }); } - instance.web.bus.on('click', this, function(ev) { - if ($(ev.target).parents('.oe_searchview').length === 0) { - self.$el.removeClass('oe_searchview_open_drawer'); - } - }); - return $.when(p, this.ready); }, + + set_drawer: function (drawer) { + this.searchview_drawer = drawer; + }, + show: function () { this.$el.show(); }, @@ -463,14 +463,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }, /** - * Sets up thingie where all the mess is put? - */ - select_for_drawer: function () { - return _(this.inputs).filter(function (input) { - return input.in_drawer(); - }); - }, - /** * Sets up search view's view-wide auto-completion widget */ setup_global_completion: function () { @@ -630,87 +622,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }); }, - /** - * Builds a list of widget rows (each row is an array of widgets) - * - * @param {Array} items a list of nodes to convert to widgets - * @param {Object} fields a mapping of field names to (ORM) field attributes - * @param {Object} [group] group to put the new controls in - */ - make_widgets: function (items, fields, group) { - if (!group) { - group = new instance.web.search.Group( - this, 'q', {attrs: {string: _t("Filters")}}); - } - var self = this; - var filters = []; - _.each(items, function (item) { - if (filters.length && item.tag !== 'filter') { - group.push(new instance.web.search.FilterGroup(filters, group)); - filters = []; - } - - switch (item.tag) { - case 'separator': case 'newline': - break; - case 'filter': - filters.push(new instance.web.search.Filter(item, group)); - break; - case 'group': - self.make_widgets(item.children, fields, - new instance.web.search.Group(group, 'w', item)); - break; - case 'field': - var field = this.make_field( - item, fields[item['attrs'].name], group); - group.push(field); - // filters - self.make_widgets(item.children, fields, group); - break; - } - }, this); - - if (filters.length) { - group.push(new instance.web.search.FilterGroup(filters, this)); - } - }, - /** - * Creates a field for the provided field descriptor item (which comes - * from fields_view_get) - * - * @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, parent) { - // M2O combined with selection widget is pointless and broken in search views, - // but has been used in the past for unsupported hacks -> ignore it - if (field.type === "many2one" && item.attrs.widget === "selection"){ - item.attrs.widget = undefined; - } - var obj = instance.web.search.fields.get_any( [item.attrs.widget, field.type]); - if(obj) { - return new (obj) (item, field, parent || this); - } else { - console.group('Unknown field type ' + field.type); - console.error('View node', item); - console.info('View field', field); - console.info('In view', this); - console.groupEnd(); - return null; - } - }, - - add_common_inputs: function() { - // add Filters to this.inputs, need view.controls filled - (new instance.web.search.Filters(this)); - // add custom filters to this.inputs - this.custom_filters = new instance.web.search.CustomFilters(this); - // add Advanced to this.inputs - (new instance.web.search.Advanced(this)); - }, - search_view_loaded: function(data) { var self = this; this.fields_view = data; @@ -720,41 +631,28 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea "Got non-search view after asking for a search view: type %s, arch root %s", data.type, data.arch.tag)); } - this.make_widgets( - data['arch'].children, - data.fields); - - this.add_common_inputs(); - - // build drawer - var drawer_started = $.when.apply( - null, _(this.select_for_drawer()).invoke( - 'appendTo', this.$('.oe_searchview_drawer'))); - - - // load defaults - var defaults_fetched = $.when.apply(null, _(this.inputs).invoke( - 'facet_for_defaults', this.defaults)) - .then(this.proxy('setup_default_query')); - return $.when(drawer_started, defaults_fetched) + return this.drawer_ready + .then(this.proxy('setup_default_query')) .then(function () { self.trigger("search_view_loaded", data); self.ready.resolve(); }); }, setup_default_query: function () { + this.ready.resolve(); + return; // Hacky implementation of CustomFilters#facet_for_defaults ensure // CustomFilters will be ready (and CustomFilters#filters will be // correctly filled) by the time this method executes. - var custom_filters = this.custom_filters.filters; + var custom_filters = this.searchview_drawer.custom_filters.filters; if (!this.options.disable_custom_filters && !_(custom_filters).isEmpty()) { // Check for any is_default custom filter var personal_filter = _(custom_filters).find(function (filter) { return filter.user_id && filter.is_default; }); if (personal_filter) { - this.custom_filters.toggle_filter(personal_filter, true); + this.searchview_drawer.custom_filters.toggle_filter(personal_filter, true); return; } @@ -762,7 +660,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea return !filter.user_id && filter.is_default; }); if (global_filter) { - this.custom_filters.toggle_filter(global_filter, true); + this.searchview_drawer.custom_filters.toggle_filter(global_filter, true); return; } } @@ -875,6 +773,146 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea } }); +instance.web.SearchViewDrawer = instance.web.Widget.extend({ + template: "SearchViewDrawer", + + init: function(parent, searchview) { + this._super(parent); + this.searchview = searchview; + this.searchview.set_drawer(this); + this.ready = searchview.drawer_ready; + this.controls = []; + this.inputs = []; + }, + + toggle: function () { + this.$el.toggle(); + }, + + start: function() { + var filters_ready = this.searchview.fields_view_get + .then(this.proxy('prepare_filters')); + return $.when(this._super(), filters_ready) + .then(this.proxy('notify_searchview')); + }, + prepare_filters: function (data) { + this.make_widgets( + data['arch'].children, + data.fields); + + this.add_common_inputs(); + + // build drawer + var drawer_started = $.when.apply( + null, _(this.select_for_drawer()).invoke( + 'appendTo', this.$el)); + + + // load defaults + // var defaults_fetched = $.when.apply(null, _(this.inputs).invoke( + // 'facet_for_defaults', this.defaults)) + // .then(this.proxy('setup_default_query')); + + + }, + notify_searchview: function () { + this.searchview.drawer_ready.resolve(); + + // with args... + // this.searchview.drawer_ready.resolve(); + }, + /** + * Sets up thingie where all the mess is put? + */ + select_for_drawer: function () { + return _(this.inputs).filter(function (input) { + return input.in_drawer(); + }); + }, + + /** + * Builds a list of widget rows (each row is an array of widgets) + * + * @param {Array} items a list of nodes to convert to widgets + * @param {Object} fields a mapping of field names to (ORM) field attributes + * @param {Object} [group] group to put the new controls in + */ + make_widgets: function (items, fields, group) { + if (!group) { + group = new instance.web.search.Group( + this, 'q', {attrs: {string: _t("Filters")}}); + } + var self = this; + var filters = []; + _.each(items, function (item) { + if (filters.length && item.tag !== 'filter') { + group.push(new instance.web.search.FilterGroup(filters, group)); + filters = []; + } + + switch (item.tag) { + case 'separator': case 'newline': + break; + case 'filter': + filters.push(new instance.web.search.Filter(item, group)); + break; + case 'group': + self.make_widgets(item.children, fields, + new instance.web.search.Group(group, 'w', item)); + break; + case 'field': + var field = this.make_field( + item, fields[item['attrs'].name], group); + group.push(field); + // filters + self.make_widgets(item.children, fields, group); + break; + } + }, this); + + if (filters.length) { + group.push(new instance.web.search.FilterGroup(filters, this)); + } + }, + /** + * Creates a field for the provided field descriptor item (which comes + * from fields_view_get) + * + * @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, parent) { + // M2O combined with selection widget is pointless and broken in search views, + // but has been used in the past for unsupported hacks -> ignore it + if (field.type === "many2one" && item.attrs.widget === "selection"){ + item.attrs.widget = undefined; + } + var obj = instance.web.search.fields.get_any( [item.attrs.widget, field.type]); + if(obj) { + return new (obj) (item, field, parent || this); + } else { + console.group('Unknown field type ' + field.type); + console.error('View node', item); + console.info('View field', field); + console.info('In view', this); + console.groupEnd(); + return null; + } + }, + + add_common_inputs: function() { + // add Filters to this.inputs, need view.controls filled + (new instance.web.search.Filters(this)); + // add custom filters to this.inputs + this.custom_filters = new instance.web.search.CustomFilters(this); + // add Advanced to this.inputs + (new instance.web.search.Advanced(this)); + }, + +}); + /** * Registry of search fields, called by :js:class:`instance.web.SearchView` to * find and instantiate its field widgets. @@ -932,9 +970,10 @@ instance.web.search.Widget = instance.web.Widget.extend( /** @lends instance.web this._super(parent); var ancestor = parent; do { - this.view = ancestor; - } while (!(ancestor instanceof instance.web.SearchView) + this.drawer = ancestor; + } while (!(ancestor instanceof instance.web.SearchViewDrawer) && (ancestor = (ancestor.getParent && ancestor.getParent()))); + this.view = this.drawer.searchview; } }); @@ -956,7 +995,7 @@ instance.web.search.Group = instance.web.search.Widget.extend({ this.name = attrs.string; this.children = []; - this.view.controls.push(this); + this.drawer.controls.push(this); }, push: function (input) { this.children.push(input); @@ -977,7 +1016,7 @@ instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instan init: function (parent) { this._super(parent); this.load_attrs({}); - this.view.inputs.push(this); + this.drawer.inputs.push(this); }, /** * Fetch auto-completion values for the widget. @@ -1814,22 +1853,13 @@ instance.web.search.Filters = instance.web.search.Input.extend({ _in_drawer: true, start: function () { var self = this; - var running_count = 0; - // get total filters count var is_group = function (i) { return i instanceof instance.web.search.FilterGroup; }; - var visible_filters = _(this.view.controls).chain().reject(function (group) { + var visible_filters = _(this.drawer.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 = visible_filters.map(function (group) { + var groups = visible_filters.map(function (group) { var filters = _(group.children).filter(is_group); return { name: _.str.sprintf("<span class='oe_i'>%s</span> %s", @@ -1840,27 +1870,16 @@ instance.web.search.Filters = instance.web.search.Input.extend({ }; }).value(); - while (col2.length) { - // col1 + group should be smaller than col2 + group - if ((running_count + col2[0].length) <= (filters_count - running_count)) { - running_count += col2[0].length; - col1.push(col2.shift()); - } else { - break; - } - } + var $dl = $('<dl class="dl-horizontal">').appendTo(this.$el); - return $.when( - this.render_column(col1, $('<div>').appendTo(this.$el)), - this.render_column(col2, $('<div>').appendTo(this.$el))); - }, - render_column: function (column, $el) { - return $.when.apply(null, _(column).map(function (group) { - $('<h3>').html(group.name).appendTo($el); - return $.when.apply(null, - _(group.filters).invoke('appendTo', $el)); - })); - } + var rendered_lines = _.map(groups, function (group) { + $('<dt>').html(group.name).appendTo($dl); + var $dd = $('<dd>').appendTo($dl); + return $.when.apply(null, _(group.filters).invoke('appendTo', $dd)); + }); + + return $.when.apply(this, rendered_lines); + }, }); instance.web.search.Advanced = instance.web.search.Input.extend({ diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 753d52d497a..f954ebd9ad5 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -553,6 +553,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ this.model = dataset ? dataset.model : undefined; this.dataset = dataset; this.searchview = null; + this.searchview_drawer = null; this.active_view = null; this.views_src = _.map(views, function(x) { if (x instanceof Array) { @@ -800,14 +801,20 @@ instance.web.ViewManager = instance.web.Widget.extend({ if (this.searchview) { this.searchview.destroy(); } + if (this.searchview_drawer) { + this.searchview_drawer.destroy(); + } + var options = { hidden: this.flags.search_view === false, disable_custom_filters: this.flags.search_disable_custom_filters, }; this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, options); + this.searchview_drawer = new instance.web.SearchViewDrawer(this, this.searchview); this.searchview.on('search_data', self, this.do_searchview_search); - return this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search")); + return $.when(this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search")), + this.searchview_drawer.appendTo(this.$(".oe_searchview_drawer_container"))); }, do_searchview_search: function(domains, contexts, groupbys) { var self = this, diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index f801e6c7c71..22e344f2b3d 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -520,6 +520,8 @@ </tr> </table> + <div class="oe_searchview_drawer_container"/> + <div class="oe_view_manager_body"> <t t-foreach="widget.views_src" t-as="view"> <div t-attf-class="oe_view_manager_view_#{view.view_type}"/> @@ -1555,11 +1557,13 @@ <div class="oe_searchview_facets"/> <div class="oe_searchview_clear"/> <div class="oe_searchview_unfold_drawer" title="Advanced Search..."/> - <div class="oe_searchview_drawer"/> <button type="button" class="oe_searchview_search" title="Search Again">Search</button> </div> +<div t-name="SearchViewDrawer" class="oe_searchview_drawer" style="display:none;"> +</div> + <div t-name="SearchView.InputView" class="oe_searchview_input" contenteditable="true" |
