[ADD] start of widgets-based search view, break search itself (for now) and get the same result as before I broke everything layout-wise (woohoo)

bzr revid: xmo@openerp.com-20110324124653-kn5c69ytuieu68gn
This commit is contained in:
Xavier Morel 2011-03-24 13:46:53 +01:00
parent d4ee05255c
commit a8f877e6f0
3 changed files with 193 additions and 124 deletions

View File

@ -348,6 +348,7 @@ body.openerp {
}
.openerp .filter_label_group {
padding-right: 0.4em;
white-space: nowrap;
}
.openerp .filter_label_group button:first-child {
border-left: 1px solid #666;

View File

@ -276,86 +276,51 @@
</button>
</t>
<t t-name="SearchView">
<h3 class="title"><t t-esc="fields_view.arch.attrs['string']"/></h3>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<t t-call="SearchView.node">
<t t-set="node" t-value="fields_view.arch"/>
<t t-set="previous_node_type"></t>
</t>
</tr>
</table>
<h3 class="title"><t t-esc="view.attrs['string']"/></h3>
<t t-call="SearchView.render_lines"/>
<div style="text-align:right;">
<input id="search" type="button" value="Search"/>
<input type="button" value="Clear"/>
</div>
</t>
<t t-name="SearchView.node" t-trim="inner">
<t t-if="node.tag == 'filter'">
<t t-if="previous_node_type != 'filter'">
&lt;td nowrap="true" valign="bottom" class="filter_label_group"&gt;
</t>
<button type="button" t-att-title="node.attrs.help" t-att-class="node.attrs.string ? 'filter_label' : 'filter_icon'">
<img t-if="node.attrs.icon" t-att-src="'/base/static/openerp/img/icons/' + node.attrs.icon + '.png'" width="16" height="16"/>
<br t-if="node.attrs.icon and node.attrs.string"/>
<t t-esc="node.attrs.string"/>
</button>
<t t-if="next_node_type != 'filter'">
&lt;/td&gt;
</t>
</t>
<t t-if="node.tag == 'separator'">
<!-- nothing in search view ? -->
</t>
<t t-if="node.tag == 'newline'">
<!-- TODO: check qweb support for cdata -->
&lt;/tr&gt;
&lt;/table&gt;
&lt;table border="0" cellspacing="0" cellpadding="0"&gt;
&lt;tr&gt;
</t>
<t t-if="node.tag == 'field'">
<t t-set="orm" t-value="fields_view.fields[node.attrs.name] || {}"/>
<td>
<label style="display: block" t-att-title="orm.help || node.attrs.help">
<t t-esc="orm.string || node.attrs.string || node.attrs.name"/>
<span t-if="orm.help || node.attrs.help">(?)</span>
</label>
<div>
<input type="text" t-att-name="node.attrs.name"/>
</div>
</td>
</t>
<t t-if="node.tag == 'group'">
<!-- if group is called without a <newline/> before, the table should be closed.
I think we'll need preprocessing, all those escaped tables are too ugly -->
<td>
<div t-att-class="'searchview_group ' + (node.attrs.expand == '0' ? 'folded' : 'expanded')">
<a class="searchview_group_string" href="#" onclick="$(this).parent().toggleClass('folded expanded')"><t t-esc="node.attrs.string"/></a>
<div class="searchview_group_content">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<t t-call="SearchView.recurse"/>
</tr>
</table>
</div>
</div>
</td>
&lt;/tr&gt;
&lt;/table&gt;
&lt;table border="0" cellspacing="0" cellpadding="0"&gt;
&lt;tr&gt;
</t>
<t t-if="node.children and node.tag != 'newline' and node.tag != 'group'">
<t t-call="SearchView.recurse"/>
</t>
<t t-name="SearchView.render_lines">
<table border="0" cellspacing="0" cellpadding="0"
t-foreach="lines" t-as="line">
<tr>
<td t-foreach="line" t-as="widget">
<t t-raw="widget.render(defaults)"/>
</td>
</tr>
</table>
</t>
<t t-name="SearchView.recurse" t-trim="inner">
<t t-foreach="node.children" t-as="node">
<t t-call="SearchView.node">
<t t-set="previous_node_type" t-value="node_all[node_index - 1] ? node_all[node_index - 1].tag : ''"/>
<t t-set="next_node_type" t-value="node_all[node_index + 1] ? node_all[node_index + 1].tag : ''"/>
</t>
</t>
<button t-name="SearchView.filter" type="button"
t-att-title="attrs.help"
t-att-class="attrs.string ? 'filter_label' : 'filter_icon'">
<img t-if="attrs.icon" t-att-src="'/base/static/openerp/img/icons/' + attrs.icon + '.png'" width="16" height="16"/>
<br t-if="attrs.icon and attrs.string"/>
<t t-esc="attrs.string"/>
</button>
<div t-name="SearchView.filters" class="filter_label_group"
><t t-foreach="filters" t-as="filter"
><t t-raw="filter.render(defaults)"/></t
></div>
<t t-name="SearchView.field">
<label style="display: block" t-att-title="attrs.help">
<t t-esc="attrs.string || attrs.name"/>
<span t-if="attrs.help">(?)</span>
</label>
<div>
<input type="text" t-att-name="attrs.name"/>
</div>
</t>
<t t-name="SearchView.group">
<div t-att-class="'searchview_group ' + (attrs.expand == '0' ? 'folded' : 'expanded')">
<a class="searchview_group_string" href="#" onclick="$(this).parent().toggleClass('folded expanded')"><t t-esc="attrs.string"/></a>
<div class="searchview_group_content">
<t t-call="SearchView.render_lines"/>
</div>
</div>
</t>
</templates>

View File

@ -371,63 +371,166 @@ openerp.base.SearchView = openerp.base.Controller.extend({
//this.log('Starting SearchView '+this.model+this.view_id)
this.rpc("/base/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
},
/**
* 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
*/
make_widgets: function (items, fields) {
var rows = [],
row = [];
rows.push(row);
var filters = [];
_.each(items, function (item) {
if (filters.length && item.tag !== 'filter') {
row.push(
new openerp.base.search.FilterGroup(
filters, this));
filters = [];
}
if (item.tag === 'newline') {
row = [];
rows.push(row);
} else if (item.tag === 'filter') {
filters.push(
new openerp.base.search.Filter(
item, this));
} else if (item.tag === 'separator') {
// a separator is a no-op
} else {
if (item.tag === 'group') {
// TODO: group and field should be fetched from registries, maybe even filters
row.push(
new openerp.base.search.Group(
item, this, fields));
} else if (item.tag === 'field') {
row.push(
this.make_field(
item, fields[item['attrs'].name]));
}
}
}, this);
return rows;
},
/**
*
*/
make_field: function (item, field) {
// TODO: should fetch from an actual registry
// TODO: register fields in self?
switch (field.type) {
case 'char':
return new openerp.base.search.CharField(
item, field, this);
case 'float':
return new openerp.base.search.FloatField(
item, field, this);
case 'datetime':
return new openerp.base.search.DateTimeField(
item, field, this);
case 'one2many':
return new openerp.base.search.OneToManyField(
item, field, this);
case 'many2one':
return new openerp.base.search.ManyToOneField(
item, field, this);
default:
console.group('Unknown field type ' + field.type);
console.error('View node', item);
console.info('View field', field);
console.info('In view', this);
console.groupEnd();
}
},
on_loaded: function(data) {
this.fields_view = data.fields_view;
this.log(this.fields_view);
this.input_ids = {};
this.$element.html(QWeb.render("SearchView", {"fields_view": this.fields_view}));
this.$element.find("#search").bind('click',this.on_search);
// TODO bind click event on all button
// TODO we don't do many2one yet, but in the future bind a many2one controller on them
this.log(this.$element.find("#search"));
},
register_input: function(node) {
// self should be passed in the qweb dict to do:
// <input t-add-id="self.register_input(node)"/>
var lines = this.make_widgets(
data.fields_view['arch'].children,
data.fields_view.fields);
// generate id
var id = this.element_id + "_" + this.input_index++;
// TODO construct a nice object
// save it in our registry
this.input_ids[id] = {
node: node,
type: "filter",
domain: "",
context: "",
disabled: false
};
// TODO: get default values
var default_values = {};
return id;
var render = QWeb.render("SearchView", {
'view': data.fields_view['arch'],
'lines': lines,
'defaults': default_values
});
this.$element.html(render);
// TODO: setup events
},
on_click: function() {
// event catched on a button
// flip the disabled flag
// adjust the css class
},
on_search: function() {
this.log("on_search");
// collect all non disabled domains definitions, AND them
// evaluate as python expression
// save the result in this.domain
this.dataset.fetch();
},
on_clear: function() {
}
on_search: function () {}
});
openerp.base.SearchViewInput = openerp.base.Controller.extend({
// TODO not sure should we create a controller for every input ?
// of we just keep a simple dict for each input in
// openerp.base.SearchView#input_ids
// and use if when we get an event depending on the type
// i think it's less bloated to avoid useless controllers
// but i think for many2one a controller would be nice
// so simple dict for simple inputs
// an controller for many2one ?
openerp.base.search = {};
openerp.base.search.Widget = openerp.base.Controller.extend({
template: null,
init: function (view) {
this.view = view;
},
render: function (defaults) {
return QWeb.render(
this.template, _.extend(this, {
defaults: defaults
}));
}
// TODO: rendering
// TODO: validation
});
openerp.base.search.Filter = openerp.base.search.Widget.extend({
template: 'SearchView.filter',
// TODO: force rendering
init: function (node, view) {
this._super(view);
this.attrs = node.attrs;
}
});
openerp.base.search.FilterGroup = openerp.base.search.Widget.extend({
template: 'SearchView.filters',
init: function (filters, view) {
this._super(view);
this.filters = filters;
}
});
openerp.base.search.Group = openerp.base.search.Widget.extend({
template: 'SearchView.group',
// TODO: contain stuff
// TODO: @expand
init: function (view_section, view, fields) {
this._super(view);
this.attrs = view_section.attrs;
this.lines = view.make_widgets(
view_section.children, fields);
}
});
openerp.base.search.Field = openerp.base.search.Widget.extend({
template: 'SearchView.field',
// TODO: set default values
// TODO: get context, domain
// TODO: holds Filters
init: function (view_section, field, view) {
this._super(view);
this.attrs = _.extend({}, field, view_section.attrs);
}
});
openerp.base.search.CharField = openerp.base.search.Field.extend({
// TODO: .size
});
openerp.base.search.FloatField = openerp.base.search.Field.extend({
// TODO: .digits (a, b)
});
openerp.base.search.DateTimeField = openerp.base.search.Field.extend({
});
openerp.base.search.OneToManyField = openerp.base.search.Field.extend({
// TODO: .relation, .context, .domain
});
openerp.base.search.ManyToOneField = openerp.base.search.Field.extend({
// TODO: @widget
// TODO: .relation, .selection, .context, .domain
});
openerp.base.FormView = openerp.base.Controller.extend({
init: function(session, element_id, dataset, view_id) {