[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:
parent
d4ee05255c
commit
a8f877e6f0
|
@ -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;
|
||||
|
|
|
@ -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'">
|
||||
<td nowrap="true" valign="bottom" class="filter_label_group">
|
||||
</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'">
|
||||
</td>
|
||||
</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 -->
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
</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>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
</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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue