openerp-dev-web team mailing list archive
-
openerp-dev-web team
-
Mailing list archive
-
Message #04765
[Merge] lp:~openerp-dev/openobject-client-web/proto61-searchview-niv into lp:~openerp-dev/openobject-client-web/trunk-proto61
Nicolas Vanhoren (OpenERP) has proposed merging lp:~openerp-dev/openobject-client-web/proto61-searchview-niv into lp:~openerp-dev/openobject-client-web/trunk-proto61 with lp:~openerp-dev/openobject-client-web/proto61-searchview-xmo as a prerequisite.
Requested reviews:
Antony Lesuisse (al-openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-client-web/proto61-searchview-niv/+merge/55352
Added custom filters (still needs improvements but the current state is consistent)
--
https://code.launchpad.net/~openerp-dev/openobject-client-web/proto61-searchview-niv/+merge/55352
Your team OpenERP R&D Team is subscribed to branch lp:~openerp-dev/openobject-client-web/proto61-searchview-xmo.
=== modified file 'addons/base/static/openerp/base.html'
--- addons/base/static/openerp/base.html 2011-03-28 09:03:39 +0000
+++ addons/base/static/openerp/base.html 2011-03-29 14:42:53 +0000
@@ -13,7 +13,11 @@
<script type="text/javascript" src="/base/static/LABjs/LAB.js"></script>
<script>
$LAB
+<<<<<<< TREE
.setOptions({UsePreloading:false})
+=======
+ .setOptions({UsePreloading:false})
+>>>>>>> MERGE-SOURCE
.script('/base/static/openerp/js/base.js')
.script('/base/static/qweb/qweb.js')
.script('/base/static/underscore/underscore.js')
=== modified file 'addons/base/static/openerp/base.xml'
--- addons/base/static/openerp/base.xml 2011-03-29 12:50:42 +0000
+++ addons/base/static/openerp/base.xml 2011-03-29 14:42:53 +0000
@@ -341,15 +341,67 @@
<t t-if="filters.length" t-raw="filters.render(defaults)"/>
</div>
</t>
-<t t-name="SearchView.group">
- <div t-att-class="'searchview_group ' + (attrs.expand == '0' ? 'folded' : 'expanded')"
+<t t-name="SearchView.util.expand">
+ <div t-att-class="'searchview_group ' + (expand == '0' ? 'folded' : 'expanded')"
t-att-id="element_id">
- <a t-if="attrs.string" class="searchview_group_string" href="#">
- <t t-esc="attrs.string"/>
+ <a t-if="label" class="searchview_group_string" href="#">
+ <t t-esc="label"/>
</a>
<div class="searchview_group_content">
- <t t-call="SearchView.render_lines"/>
+ <t t-raw="content"/>
</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>
+<t t-name="SearchView.extended_search">
+ <t t-call="SearchView.util.expand">
+ <t t-set="expand" t-value="false"/>
+ <t t-set="label" t-value="'Extended Filters'"/>
+ <t t-set="content">
+ <div class="searchview_extended_groups_list"></div>
+ <button class="searchview_extended_add_group">Add group of conditions</button>
+ </t>
+ </t>
+</t>
+<t t-name="SearchView.extended_search.group">
+ <div t-att-id="element_id">
+ <select class="searchview_extended_group_choice">
+ <option value="all">All</option>
+ <option value="any">Any</option>
+ <option value="none">None</option>
+ </select>
+ <div class="searchview_extended_propositions_list">
+ </div>
+ <button class="searchview_extended_add_proposition">Add condition</button>
+ <button class="searchview_extended_delete_group">Delete this group</button>
+ </div>
+</t>
+<t t-name="SearchView.extended_search.proposition">
+ <div t-att-id="element_id">
+ <select class="searchview_extended_prop_field">
+ <t t-foreach="attrs.fields" t-as="field">
+ <option t-att="{'selected': field === attrs.selected ? 'selected' : null}"
+ t-att-value="field.name">
+ <t t-esc="field.obj.string"/>
+ </option>
+ </t>
+ </select>
+ <select class="searchview_extended_prop_op">
+ </select>
+ <span class="searchview_extended_prop_value">
+ </span>
+ <button class="searchview_extended_delete_prop">Delete this condition</button>
+ </div>
+</t>
+<t t-name="SearchView.extended_search.proposition.char">
+ <input t-att-id="element_id"></input>
+</t>
</templates>
=== modified file 'addons/base/static/openerp/js/base_views.js'
--- addons/base/static/openerp/js/base_views.js 2011-03-29 12:50:42 +0000
+++ addons/base/static/openerp/js/base_views.js 2011-03-29 14:42:53 +0000
@@ -393,6 +393,94 @@
}
});
+/**
+ * Base class for widgets. Handle rendering (based on a QWeb template), identifier
+ * generation, parenting and destruction of the widget.
+ */
+openerp.base.BaseWidget = openerp.base.Controller.extend({
+ /**
+ * The name of the QWeb template that will be used for rendering. Must be redifined
+ * in subclasses or the render() method can not be used.
+ *
+ * @type string
+ */
+ template: null,
+ /**
+ * The prefix used to generate an id automatically. Should be redifined in subclasses.
+ * If it is not defined, the make_id() method must be explicitly called.
+ *
+ * @type string
+ */
+ identifier_prefix: null,
+ /**
+ * Contructor.
+ *
+ * @params {openerp.base.search.BaseWidget} parent The parent widget.
+ */
+ init: function (parent) {
+ this.children = [];
+ this.parent = parent;
+ if(parent != null) {
+ parent.children.push(this);
+ }
+ if(this.identifier_prefix != null) {
+ this.make_id(this.identifier_prefix);
+ }
+ },
+ /**
+ * Sets and returns a globally unique identifier for the widget.
+ *
+ * If a prefix is appended, the identifier will be appended to it.
+ *
+ * @params sections prefix sections, empty/falsy sections will be removed
+ */
+ make_id: function () {
+ this.element_id = _.uniqueId(_.toArray(arguments).join('_'));
+ return this.element_id;
+ },
+ /**
+ * "Starts" the widgets. Called at the end of the rendering, this allows
+ * to get a jQuery object referring to the DOM ($element attribute).
+ */
+ start: function () {
+ this._super();
+ if (this.element_id) {
+ this.$element = $(document.getElementById(
+ this.element_id));
+ }
+ },
+ /**
+ * "Stops" the widgets. Called when the view destroys itself, this
+ * lets the widgets clean up after themselves.
+ */
+ stop: function () {
+ var tmp_children = this.children;
+ this.children = [];
+ _.each(tmp_children, function(x) {
+ x.stop();
+ });
+ if(this.$element != null) {
+ this.$element.remove();
+ }
+ if(this.parent != null) {
+ var _this = this;
+ this.parent.children = _.reject(this.parent.children, function(x) { return x === _this;});
+ this.parent = null;
+ }
+ this._super();
+ },
+ /**
+ * Render the widget. This.template must be defined.
+ * The content of the current object is passed as context to the template.
+ *
+ * @param {object} additional Additional context arguments to pass to the template.
+ */
+ render: function (additional) {
+ return QWeb.render(this.template, _.extend({}, this,
+ additional != null ? additional : {}));
+ }
+});
+
openerp.base.SearchView = openerp.base.Controller.extend({
init: function(session, element_id, dataset, view_id, defaults) {
this._super(session, element_id);
@@ -514,6 +602,11 @@
data.fields_view['arch'].children,
data.fields_view.fields);
+ // for extended search view
+ var ext = new openerp.base.search.ExtendedSearch(null, data.fields_view.fields);
+ lines.push([ext]);
+ this.inputs.push(ext);
+
var render = QWeb.render("SearchView", {
'view': data.fields_view['arch'],
'lines': lines,
@@ -714,6 +807,13 @@
});
}
});
+openerp.base.search.add_expand_listener = function($root) {
+ $root.find('a.searchview_group_string').click(function (e) {
+ $root.toggleClass('folded expanded');
+ e.stopPropagation();
+ e.preventDefault();
+ });
+};
openerp.base.search.Group = openerp.base.search.Widget.extend({
template: 'SearchView.group',
// TODO: contain stuff
@@ -731,14 +831,185 @@
.chain()
.flatten()
.each(function (widget) { widget.start(); });
- var $root = this.$element;
- $root.find('a.searchview_group_string').click(function (e) {
- $root.toggleClass('folded expanded');
- e.stopPropagation();
- e.preventDefault();
- });
+ openerp.base.search.add_expand_listener(this.$element);
}
});
+
+openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
+ template: 'SearchView.extended_search',
+ identifier_prefix: 'extended-search',
+ init: function (parent, fields) {
+ this._super(parent);
+ this.fields = fields;
+ },
+ add_group: function(group) {
+ var group = new openerp.base.search.ExtendedSearchGroup(this, this.fields);
+ var render = group.render({});
+ this.$element.find('.searchview_extended_groups_list').append(render);
+ group.start();
+ },
+ start: function () {
+ this._super();
+ var _this = this;
+ openerp.base.search.add_expand_listener(this.$element);
+ this.add_group();
+ this.$element.find('.searchview_extended_add_group').click(function (e) {
+ _this.add_group();
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ },
+ get_context: function() {
+ return null;
+ },
+ get_domain: function() {
+ if(this.$element.hasClass("folded")) {
+ return null;
+ }
+ var domain = _.reduce(this.children,
+ function(mem, x) { return mem.concat(x.get_domain());}, []);
+ return domain;
+ }
+});
+
+openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
+ template: 'SearchView.extended_search.group',
+ identifier_prefix: 'extended-search-group',
+ init: function (parent, fields) {
+ this._super(parent);
+ this.fields = fields;
+ },
+ add_prop: function() {
+ var prop = new openerp.base.search.ExtendedSearchProposition(this, this.fields);
+ var render = prop.render({});
+ this.$element.find('.searchview_extended_propositions_list').append(render);
+ prop.start();
+ },
+ start: function () {
+ this._super();
+ var _this = this;
+ this.add_prop();
+ this.$element.find('.searchview_extended_add_proposition').click(function (e) {
+ _this.add_prop();
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ var delete_btn = this.$element.find('.searchview_extended_delete_group');
+ delete_btn.click(function (e) {
+ _this.stop();
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ },
+ get_domain: function() {
+ var props = _(this.children).chain().map(function(x) {
+ return x.get_proposition();
+ }).compact().value();
+ var choice = this.$element.find(".searchview_extended_group_choice").val();
+ var op = choice == "all" ? "&" : "|";
+ var domain = [].concat(choice == "none" ? ['!'] : [],
+ _.map(_.range(_.max([0,props.length - 1])), function(x) { return op; }),
+ props);
+ return domain;
+ }
+});
+
+openerp.base.search.extended_filters_types = {
+ char: {
+ operators: [
+ {value: "ilike", text: "contains"},
+ {value: "not like", text: "doesn't contain"},
+ {value: "=", text: "is equal to"},
+ {value: "!=", text: "is not equal to"},
+ {value: ">", text: "greater than"},
+ {value: "<", text: "less than"},
+ {value: ">=", text: "greater or equal than"},
+ {value: "<=", text: "less or equal than"},
+ ],
+ build_component: function(parent) {
+ return new openerp.base.search.ExtendedSearchProposition.Char(parent);
+ }
+ }
+};
+
+openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
+ template: 'SearchView.extended_search.proposition',
+ identifier_prefix: 'extended-search-proposition',
+ init: function (parent, fields) {
+ this._super(parent);
+ this.fields = _(fields).chain()
+ .map(function(val,key) {return {name:key, obj:val};})
+ .sortBy(function(x) {return x.obj.string;}).value();
+ this.attrs = {_: _, fields: this.fields, selected: null};
+ this.value_component = null;
+ },
+ start: function () {
+ this._super();
+ this.set_selected(this.fields.length > 0 ? this.fields[0] : null);
+ var _this = this;
+ this.$element.find(".searchview_extended_prop_field").change(function(e) {
+ _this.changed();
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ var delete_btn = this.$element.find('.searchview_extended_delete_prop');
+ delete_btn.click(function (e) {
+ _this.stop();
+ e.stopPropagation();
+ e.preventDefault();
+ });
+ },
+ changed: function() {
+ var nval = this.$element.find(".searchview_extended_prop_field").val();
+ if(this.attrs.selected == null || nval != this.attrs.selected.name) {
+ this.set_selected(_.detect(this.fields, function(x) {return x.name == nval;}));
+ }
+ },
+ set_selected: function(selected) {
+ var _this = this;
+ if(this.attrs.selected != null) {
+ this.value_component.stop();
+ this.value_component = null;
+ this.$element.find('.searchview_extended_prop_op').html('');
+ }
+ this.attrs.selected = selected;
+ if(selected == null) {
+ return;
+ }
+ var type = selected.obj.type;
+ var extended_filters_types = openerp.base.search.extended_filters_types;
+ type = type in extended_filters_types ? type : "char";
+ _.each(extended_filters_types[type].operators, function(operator) {
+ option = jQuery('<option/>');
+ option.attr('value', operator.value);
+ option.text(operator.text);
+ option.appendTo(_this.$element.find('.searchview_extended_prop_op'));
+ });
+ this.value_component = extended_filters_types[type].build_component(this);
+ var render = this.value_component.render({});
+ this.$element.find('.searchview_extended_prop_value').html(render);
+ this.value_component.start();
+ },
+ get_proposition: function() {
+ if ( this.attrs.selected == null)
+ return null;
+ var field = this.attrs.selected.name;
+ var op = this.$element.find('.searchview_extended_prop_op').val();
+ var value = this.value_component.get_value();
+ return [field, op, value];
+ }
+});
+
+openerp.base.search.ExtendedSearchProposition.Char = openerp.base.BaseWidget.extend({
+ template: 'SearchView.extended_search.proposition.char',
+ identifier_prefix: 'extended-search-proposition-char',
+
+ get_value: function() {
+ var val = this.$element.val();
+ return val;
+ }
+});
+
openerp.base.search.Input = openerp.base.search.Widget.extend({
init: function (view) {
this._super(view);
@@ -1073,6 +1344,8 @@
openerp.base.TreeView = openerp.base.Controller.extend({
});
+
+
openerp.base.Widget = openerp.base.Controller.extend({
// TODO Change this to init: function(view, node) { and use view.session and a new element_id for the super
// it means that widgets are special controllers
=== modified file 'addons/base/static/qweb/qweb.js'
--- addons/base/static/qweb/qweb.js 2011-03-24 12:42:21 +0000
+++ addons/base/static/qweb/qweb.js 2011-03-29 14:42:53 +0000
@@ -182,7 +182,9 @@
g_att[o[0]] = new String(o[1]);
} else if (o.constructor == Object) {
for (var i in o) {
- g_att[i] = new String(o[i]);
+ if(o[i]!=null) {
+ g_att[i] = new String(o[i]);
+ }
}
}
}
Follow ups