summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2014-05-19 14:16:09 +0200
committerGéry Debongnie <ged@odoo.com>2014-05-19 14:16:09 +0200
commit7e6d223e9e6e9ba232c9fa2b1e5629563f5e7a69 (patch)
tree1baa6661734b06bc92808108301dbedb7827f3fc
parent072485799c87d45c460c7aa76fb2f0e7be1b82ef (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.js5
-rw-r--r--addons/mail/static/src/xml/mail.xml1
-rw-r--r--addons/web/static/src/css/base.css5
-rw-r--r--addons/web/static/src/css/base.sass4
-rw-r--r--addons/web/static/src/js/search.js327
-rw-r--r--addons/web/static/src/js/views.js9
-rw-r--r--addons/web/static/src/xml/base.xml6
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"