e24770f3b182648cecd69d233fc9bd0524e57765
[odoo/odoo.git] / addons / board / static / src / js / dashboard.js
1 openerp.board = function(instance) {
2 var QWeb = instance.web.qweb,
3     _t = instance.web._t;
4
5 if (!instance.board) {
6     /** @namespace */
7     instance.board = {};
8 }
9
10 instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
11     events: {
12         'click .oe_dashboard_link_reset': 'on_reset',
13         'click .oe_dashboard_link_change_layout': 'on_change_layout',
14         'click h2.oe_header span.oe_header_txt': function (ev) {
15             if(ev.target === ev.currentTarget)
16                 self.on_header_string($(ev.target).parent());
17         },
18         'click .oe_dashboard_column .oe_fold': 'on_fold_action',
19         'click .oe_dashboard_column .oe_close': 'on_close_action',
20     },
21     init: function(view, node) {
22         this._super(view, node);
23         this.form_template = 'DashBoard';
24         this.actions_attrs = {};
25         this.action_managers = [];
26     },
27     start: function() {
28         var self = this;
29         this._super.apply(this, arguments);
30
31         this.$('.oe_dashboard_column').sortable({
32             connectWith: '.oe_dashboard_column',
33             handle: '.oe_header',
34             scroll: false
35         }).bind('sortstop', self.do_save_dashboard);
36
37         var old_title = this.__parentedParent.get('title');
38         this.__parentedParent.on('load_record', self, function(){
39             self.__parentedParent.set({ 'title': old_title});
40         });
41
42         // Init actions
43         _.each(this.node.children, function(column, column_index) {
44             _.each(column.children, function(action, action_index) {
45                 delete(action.attrs.width);
46                 delete(action.attrs.height);
47                 delete(action.attrs.colspan);
48                 var action_id = _.str.toNumber(action.attrs.name);
49                 if (!_.isNaN(action_id)) {
50                     self.rpc('/web/action/load', {action_id: action_id}).done(function(result) {
51                         self.on_load_action(result, column_index + '_' + action_index, action.attrs);
52                     });
53                 }
54             });
55         });
56     },
57     on_header_string:function(h2){
58         var self = this;
59         var span = h2.find('span:first').hide();
60         var input = h2.find('.oe_header_text').css('visibility','visible');
61         var attr = h2.closest(".oe_action").data('action_attrs');
62         var change_string = function(new_name){
63                 attr['string'] = new_name;
64                 span.text(new_name).show();
65                 input.css('visibility','hidden');
66                 self.do_save_dashboard();
67         }
68         input.unbind()
69         .val(span.text())
70         .change(function(event){
71             change_string($(this).val());
72         })
73         .keyup(function(event){
74             if(event.keyCode == 27){
75                 //esc key to cancel changes
76                 input.css('visibility','hidden');
77                 span.show();
78             }
79         });
80     },
81     on_reset: function() {
82         this.rpc('/web/view/undo_custom', {
83             view_id: this.view.fields_view.view_id,
84             reset: true
85         }).done(this.do_reload);
86     },
87     on_change_layout: function() {
88         var self = this;
89         var qdict = {
90             current_layout : this.$el.find('.oe_dashboard').attr('data-layout')
91         };
92         var $dialog = new instance.web.Dialog(this, {
93                             title: _t("Edit Layout"),
94                         }, QWeb.render('DashBoard.layouts', qdict)).open();
95         $dialog.$el.find('li').click(function() {
96             var layout = $(this).attr('data-layout');
97             self.do_change_layout(layout);
98             $dialog.$dialog_box.modal('hide'); 
99         });
100     },
101     do_change_layout: function(new_layout) {
102         var $dashboard = this.$el.find('.oe_dashboard');
103         var current_layout = $dashboard.attr('data-layout');
104         if (current_layout != new_layout) {
105             var clayout = current_layout.split('-').length,
106                 nlayout = new_layout.split('-').length,
107                 column_diff = clayout - nlayout;
108             if (column_diff > 0) {
109                 var $last_column = $();
110                 $dashboard.find('.oe_dashboard_column').each(function(k, v) {
111                     if (k >= nlayout) {
112                         $(v).find('.oe_action').appendTo($last_column);
113                     } else {
114                         $last_column = $(v);
115                     }
116                 });
117             }
118             $dashboard.toggleClass('oe_dashboard_layout_' + current_layout + ' oe_dashboard_layout_' + new_layout);
119             $dashboard.attr('data-layout', new_layout);
120             this.do_save_dashboard();
121         }
122     },
123     on_fold_action: function(e) {
124         var $e = $(e.currentTarget),
125             $action = $e.parents('.oe_action:first'),
126             id = parseInt($action.attr('data-id'), 10);
127         if ($e.is('.oe_minimize')) {
128             $action.data('action_attrs').fold = '1';
129         } else {
130             delete($action.data('action_attrs').fold);
131         }
132         $e.toggleClass('oe_minimize oe_maximize');
133         $action.find('.oe_content').toggle();
134         this.do_save_dashboard();
135     },
136     on_close_action: function(e) {
137         if (confirm(_t("Are you sure you want to remove this item ?"))) {
138             $(e.currentTarget).parents('.oe_action:first').remove();
139             this.do_save_dashboard();
140         }
141     },
142     do_save_dashboard: function() {
143         var self = this;
144         var board = {
145                 form_title : this.view.fields_view.arch.attrs.string,
146                 style : this.$el.find('.oe_dashboard').attr('data-layout'),
147                 columns : []
148             };
149         this.$el.find('.oe_dashboard_column').each(function() {
150             var actions = [];
151             $(this).find('.oe_action').each(function() {
152                 var action_id = $(this).attr('data-id'),
153                     new_attrs = _.clone($(this).data('action_attrs'));
154                 if (new_attrs.domain) {
155                     new_attrs.domain = new_attrs.domain_string;
156                     delete(new_attrs.domain_string);
157                 }
158                 if (new_attrs.context) {
159                     new_attrs.context = new_attrs.context_string;
160                     delete(new_attrs.context_string);
161                 }
162                 actions.push(new_attrs);
163             });
164             board.columns.push(actions);
165         });
166         var arch = QWeb.render('DashBoard.xml', board);
167         this.rpc('/web/view/add_custom', {
168             view_id: this.view.fields_view.view_id,
169             arch: arch
170         });
171     },
172     on_load_action: function(result, index, action_attrs) {
173         var self = this,
174             action = result,
175             view_mode = action_attrs.view_mode;
176
177         // evaluate action_attrs context and domain
178         action_attrs.context_string = action_attrs.context;
179         action_attrs.context = instance.web.pyeval.eval(
180             'context', action_attrs.context || {});
181         action_attrs.domain_string = action_attrs.domain;
182         action_attrs.domain = instance.web.pyeval.eval(
183             'domain', action_attrs.domain || [], action_attrs.context);
184         if (action_attrs.context['dashboard_merge_domains_contexts'] === false) {
185             // TODO: replace this 6.1 workaround by attribute on <action/>
186             action.context = action_attrs.context || {};
187             action.domain = action_attrs.domain || [];
188         } else {
189             action.context = instance.web.pyeval.eval(
190                 'contexts', [action.context || {}, action_attrs.context]);
191             action.domain = instance.web.pyeval.eval(
192                 'domains', [action_attrs.domain, action.domain || []],
193                 action.context)
194         }
195
196         var action_orig = _.extend({ flags : {} }, action);
197
198         if (view_mode && view_mode != action.view_mode) {
199             action.views = _.map(view_mode.split(','), function(mode) {
200                 mode = mode === 'tree' ? 'list' : mode;
201                 return _(action.views).find(function(view) { return view[1] == mode; })
202                     || [false, mode];
203             });
204         }
205
206         action.flags = {
207             search_view : false,
208             sidebar : false,
209             views_switcher : false,
210             action_buttons : false,
211             pager: false,
212             headless: true,
213             low_profile: true,
214             display_title: false,
215             list: {
216                 selectable: false
217             }
218         };
219         var am = new instance.web.ActionManager(this),
220             // FIXME: ideally the dashboard view shall be refactored like kanban.
221             $action = $('#' + this.view.element_id + '_action_' + index);
222         $action.parent().data('action_attrs', action_attrs);
223         this.action_managers.push(am);
224         am.appendTo($action);
225         am.do_action(action);
226         am.do_action = function (action) {
227             self.do_action(action);
228         };
229         if (am.inner_widget) {
230             var new_form_action = function(id, editable) {
231                 var new_views = [];
232                 _.each(action_orig.views, function(view) {
233                     new_views[view[1] === 'form' ? 'unshift' : 'push'](view);
234                 });
235                 if (!new_views.length || new_views[0][1] !== 'form') {
236                     new_views.unshift([false, 'form']);
237                 }
238                 action_orig.views = new_views;
239                 action_orig.res_id = id;
240                 action_orig.flags = {
241                     form: {
242                         "initial_mode": editable ? "edit" : "view",
243                     }
244                 };
245                 self.do_action(action_orig);
246             };
247             var list = am.inner_widget.views.list;
248             if (list) {
249                 list.created.done(function() {
250                     $(list.controller.groups).off('row_link').on('row_link', function(e, id) {
251                         new_form_action(id);
252                     });
253                 });
254             }
255             var kanban = am.inner_widget.views.kanban;
256             if (kanban) {
257                 kanban.created.done(function() {
258                     kanban.controller.open_record = function(id, editable) {
259                         new_form_action(id, editable);
260                     };
261                 });
262             }
263         }
264     },
265     renderElement: function() {
266         this._super();
267
268         var check = _.detect(this.node.children, function(column, column_index) {
269             return _.detect(column.children,function(element){
270                 return element.tag === "action"? element: false;
271             });
272         });
273         if (!check) {
274             return this.no_result();
275         }
276         // We should start with three columns available
277         for (var i = this.node.children.length; i < 3; i++) {
278             this.node.children.push({
279                 tag: 'column',
280                 attrs: {},
281                 children: []
282             });
283         }
284         var rendered = QWeb.render(this.form_template, this);
285         this.$el.html(rendered);
286     },
287     no_result: function() {
288         if (this.view.options.action.help) {
289             this.$el.append(
290                 $('<div class="oe_view_nocontent">')
291                     .append($('<div>').html(this.view.options.action.help || " "))
292             );
293         }
294     },
295     do_reload: function() {
296         var view_manager = this.view.getParent(),
297             action_manager = view_manager.getParent();
298         this.view.destroy();
299         action_manager.do_action(view_manager.action);
300     }
301 });
302 instance.web.form.DashBoardLegacy = instance.web.form.DashBoard.extend({
303     renderElement: function() {
304         if (this.node.tag == 'hpaned') {
305             this.node.attrs.layout = '2-1';
306         } else if (this.node.tag == 'vpaned') {
307             this.node.attrs.layout = '1';
308         }
309         this.node.tag = 'board';
310         _.each(this.node.children, function(child) {
311             if (child.tag.indexOf('child') == 0) {
312                 child.tag = 'column';
313                 var actions = [], first_child = child.children[0];
314                 if (first_child && first_child.tag == 'vpaned') {
315                     _.each(first_child.children, function(subchild) {
316                         actions.push.apply(actions, subchild.children);
317                     });
318                     child.children = actions;
319                 }
320             }
321         });
322         this._super(this);
323     }
324 });
325
326 instance.web.form.tags.add('hpaned', 'instance.web.form.DashBoardLegacy');
327 instance.web.form.tags.add('vpaned', 'instance.web.form.DashBoardLegacy');
328 instance.web.form.tags.add('board', 'instance.web.form.DashBoard');
329
330
331 instance.web.search.FavoriteMenu.include({
332     prepare_dropdown_menu: function (filters) {
333         var self = this;
334         this._super(filters);
335         this.$('.favorites-menu').append(QWeb.render('SearchView.addtodashboard'));
336         var $add_to_dashboard = this.$('.add-to-dashboard');
337         this.$add_dashboard_btn = $add_to_dashboard.eq(2).find('button');
338         this.$add_dashboard_input = $add_to_dashboard.eq(1).find('input');
339         this.$add_dashboard_link = $add_to_dashboard.first().find('a');
340         var title = this.searchview.getParent().title;
341         this.$add_dashboard_input.val(title);
342         this.$add_dashboard_link.click(function () {
343             self.toggle_dashboard_menu();
344         });
345         this.$add_dashboard_btn.click(this.proxy('add_dashboard'));
346     },
347     toggle_dashboard_menu: function (is_open) {
348         this.$add_dashboard_link
349             .toggleClass('closed-menu', !is_open)
350             .toggleClass('open-menu', is_open);
351         this.$add_dashboard_btn.toggle(is_open);
352         this.$add_dashboard_input.toggle(is_open);
353         if (this.$add_dashboard_link.hasClass('open-menu')) {
354             this.$add_dashboard_input.focus();
355         }
356     },
357     close_menus: function () {
358         this.toggle_dashboard_menu(false);
359         this._super();
360     },
361     add_dashboard: function () {
362         var self = this,
363             view_manager = this.findAncestor(function (a) {
364                 return a instanceof instance.web.ViewManager
365             });
366         if (!view_manager.action) {
367             this.do_warn(_t("Can't find dashboard action"));
368             return;
369         }
370         var searchview = view_manager.searchview,
371             data = searchview.build_search_data(),
372             context = new instance.web.CompoundContext(searchview.dataset.get_context() || []),
373             domain = new instance.web.CompoundDomain(searchview.dataset.get_domain() || []);
374         _.each(data.contexts, context.add, context);
375         _.each(data.domains, domain.add, domain);
376
377         context.add({
378             group_by: instance.web.pyeval.eval('groupbys', data.groupbys || [])
379         });
380         var c = instance.web.pyeval.eval('context', context);
381         for(var k in c) {
382             if (c.hasOwnProperty(k) && /^search_default_/.test(k)) {
383                 delete c[k];
384             }
385         }
386         this.toggle_dashboard_menu(false);
387         c.dashboard_merge_domains_contexts = false;
388         var d = instance.web.pyeval.eval('domain', domain),
389             board = new instance.web.Model('board.board'),
390             name = self.$add_dashboard_input.val();
391         
392         board.call('list', [board.context()])
393             .then(function (board_list) {
394                 return self.rpc('/board/add_to_dashboard', {
395                     menu_id: board_list[0].id,                    
396                     action_id: view_manager.action.id,
397                     context_to_save: c,
398                     domain: d,
399                     view_mode: view_manager.active_view.type,
400                     name: name,
401                 });
402             }).then(function (r) {
403                 if (r) {
404                     self.do_notify(_.str.sprintf(_t("'%s' added to dashboard"), name), '');
405                 } else {
406                     self.do_warn(_t("Could not add filter to dashboard"));
407                 }
408             });
409     },
410 });
411
412 };