1 /*---------------------------------------------------------
3 *---------------------------------------------------------*/
5 openerp.web.view_tree = function(instance) {
6 var QWeb = instance.web.qweb,
7 _lt = instance.web._lt;
9 instance.web.views.add('tree', 'instance.web.TreeView');
10 instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeView# */{
11 display_name: _lt('Tree'),
13 * Indicates that this view is not searchable, and thus that no search
14 * view should be displayed (if there is one active).
18 * Genuine tree view (the one displayed as a tree, not the list)
20 * @constructs instance.web.TreeView
21 * @extends instance.web.View
28 init: function(parent, dataset, view_id, options) {
30 this.dataset = dataset;
31 this.model = dataset.model;
32 this.view_id = view_id;
36 this.options = _.extend({}, this.defaults, options || {});
38 _.bindAll(this, 'color_for');
42 return this.rpc("/web/treeview/load", {
44 view_id: this.view_id,
46 toolbar: this.view_manager ? !!this.view_manager.sidebar : false,
47 context: this.dataset.get_context()
51 * Returns the list of fields needed to correctly read objects.
53 * Gathers the names of all fields in fields_view_get, and adds the
54 * field_parent (children_field in the tree view) if it's not already one
55 * of the fields to fetch
57 * @returns {Array} an array of fields which can be provided to DataSet.read_slice and others
59 fields_list: function () {
60 var fields = _.keys(this.fields);
61 if (!_(fields).contains(this.children_field)) {
62 fields.push(this.children_field);
66 on_loaded: function (fields_view) {
68 var has_toolbar = !!fields_view.arch.attrs.toolbar;
69 // field name in OpenERP is kinda stupid: this is the name of the field
70 // holding the ids to the children of the current node, why call it
72 this.children_field = fields_view['field_parent'];
73 this.fields_view = fields_view;
74 _(this.fields_view.arch.children).each(function (field) {
75 if (field.attrs.modifiers) {
76 field.attrs.modifiers = JSON.parse(field.attrs.modifiers);
79 this.fields = fields_view.fields;
80 this.hook_row_click();
81 this.$element.html(QWeb.render('TreeView', {
82 'title': this.fields_view.arch.attrs.string,
83 'fields_view': this.fields_view.arch.children,
84 'fields': this.fields,
85 'toolbar': has_toolbar
87 this.$element.addClass(this.fields_view.arch.attrs['class']);
89 this.dataset.read_slice(this.fields_list()).then(function(records) {
91 // WARNING: will do a second read on the same ids, but only on
92 // first load so not very important
93 self.getdata(null, _(records).pluck('id'));
97 var $select = self.$element.find('select')
99 var $option = $(this).find(':selected');
100 self.getdata($option.val(), $option.data('children'));
102 _(records).each(function (record) {
103 self.records[record.id] = record;
107 .data('children', record[self.children_field])
111 if (!_.isEmpty(records)) {
116 // TODO store open nodes in url ?...
117 this.do_push_state({});
119 if (!this.fields_view.arch.attrs.colors) {
122 this.colors = _(this.fields_view.arch.attrs.colors.split(';')).chain()
124 .map(function(color_pair) {
125 var pair = color_pair.split(':'),
128 return [color, py.parse(py.tokenize(expr)), expr];
132 * Returns the color for the provided record in the current view (from the
133 * ``@colors`` attribute)
135 * @param {Object} record record for the current row
136 * @returns {String} CSS color declaration
138 color_for: function (record) {
139 if (!this.colors) { return ''; }
140 var context = _.extend({}, record, {
141 uid: this.session.uid,
142 current_date: new Date().toString('yyyy-MM-dd')
143 // TODO: time, datetime, relativedelta
145 for(var i=0, len=this.colors.length; i<len; ++i) {
146 var pair = this.colors[i],
148 expression = pair[1];
149 if (py.evaluate(expression, context).toJSON()) {
150 return 'color: ' + color + ';';
152 // TODO: handle evaluation errors
157 * Sets up opening a row
159 hook_row_click: function () {
161 this.$element.delegate('.treeview-td span, .treeview-tr span', 'click', function (e) {
162 e.stopImmediatePropagation();
163 self.activate($(this).closest('tr').data('id'));
166 this.$element.delegate('.treeview-tr', 'click', function () {
169 record_id = $this.data('id'),
170 record = self.records[record_id],
171 children_ids = record[self.children_field];
173 _(children_ids).each(function(childid) {
174 if (self.$element.find('#treerow_' + childid).length) {
175 if (self.$element.find('#treerow_' + childid).is(':hidden')) {
182 if (is_loaded === 0) {
183 if (!$this.parent().hasClass('oe_open')) {
184 self.getdata(record_id, children_ids);
187 self.showcontent(record_id, is_loaded < 0);
191 // get child data of selected value
192 getdata: function (id, children_ids) {
195 self.dataset.read_ids(children_ids, this.fields_list()).then(function(records) {
196 _(records).each(function (record) {
197 self.records[record.id] = record;
200 var $curr_node = self.$element.find('#treerow_' + id);
201 var children_rows = QWeb.render('TreeView.rows', {
203 'children_field': self.children_field,
204 'fields_view': self.fields_view.arch.children,
205 'fields': self.fields,
206 'level': $curr_node.data('level') || 0,
207 'render': instance.web.format_value,
208 'color_for': self.color_for
211 if ($curr_node.length) {
212 $curr_node.addClass('oe_open');
213 $curr_node.after(children_rows);
215 self.$element.find('tbody').html(children_rows);
220 // Get details in listview
221 activate: function(id) {
223 var local_context = {
224 active_model: self.dataset.model,
227 return this.rpc('/web/treeview/action', {
229 model: this.dataset.model,
230 context: new instance.web.CompoundContext(
231 this.dataset.get_context(), local_context)
232 }).pipe(function (actions) {
233 if (!actions.length) { return; }
234 var action = actions[0][2];
235 var c = new instance.web.CompoundContext(local_context);
236 if (action.context) {
237 c.add(action.context);
239 return self.rpc('/web/session/eval_domain_and_context', {
240 contexts: [c], domains: []
241 }).pipe(function (res) {
242 action.context = res.context;
243 return self.do_action(action);
248 // show & hide the contents
249 showcontent: function (record_id, show) {
250 this.$element.find('#treerow_' + record_id)
251 .toggleClass('oe_open', show);
253 _(this.records[record_id][this.children_field]).each(function (child_id) {
254 var $child_row = this.$element.find('#treerow_' + child_id);
255 if ($child_row.hasClass('oe_open')) {
256 this.showcontent(child_id, false);
258 $child_row.toggle(show);
262 do_show: function () {
263 this.$element.show();
266 do_hide: function () {
267 this.$element.hide();