[ADD] get a bunch of widgets to display (though not quite correctly... todo: fix...
[odoo/odoo.git] / addons / base_dashboard / static / src / js / dashboard.js
1 openerp.base_dashboard = function(openerp) {
2
3 QWeb.add_template('/base_dashboard/static/src/xml/base_dashboard.xml');
4
5 openerp.base.form.DashBoard = openerp.base.form.Widget.extend({
6     init: function(view, node) {
7         this._super(view, node);
8         this.template = 'DashBoard';
9         this.actions_attrs = {};
10     },
11     start: function() {
12         var self = this;
13         this._super.apply(this, arguments);
14
15         this.$element.find('.oe-dashboard-column').sortable({
16             connectWith: '.oe-dashboard-column',
17             handle: '.oe-dashboard-action-header',
18             scroll: false
19         }).disableSelection().bind('sortstop', self.do_save_dashboard);
20
21         // Events
22         this.$element.find('.oe-dashboard-link-undo').click(this.on_undo);
23         this.$element.find('.oe-dashboard-link-reset').click(this.on_reset);
24         this.$element.find('.oe-dashboard-link-add_widget').click(this.on_add_widget);
25         this.$element.find('.oe-dashboard-link-change_layout').click(this.on_change_layout);
26         this.$element.find('.oe-dashboard-column .oe-dashboard-fold').click(this.on_fold_action);
27         this.$element.find('.oe-dashboard-column .ui-icon-closethick').click(this.on_close_action);
28
29         this.actions_attrs = {};
30         // Init actions
31         _.each(this.node.children, function(column) {
32             _.each(column.children, function(action) {
33                 delete(action.attrs.width);
34                 delete(action.attrs.height);
35                 delete(action.attrs.colspan);
36                 self.actions_attrs[action.attrs.name] = action.attrs;
37                 self.rpc('/base/action/load', {
38                     action_id: parseInt(action.attrs.name, 10)
39                 }, self.on_load_action);
40             });
41         });
42
43         this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename);
44     },
45     on_undo: function() {
46         this.rpc('/base/view/undo_custom', {
47             view_id: this.view.fields_view.view_id
48         }, this.do_reload);
49     },
50     on_reset: function() {
51         this.rpc('/base/view/undo_custom', {
52             view_id: this.view.fields_view.view_id,
53             reset: true
54         }, this.do_reload);
55     },
56     on_add_widget: function() {
57         var self = this;
58         var action = {
59             res_model : 'ir.actions.actions',
60             views : [[false, 'list']],
61             type : 'ir.actions.act_window',
62             limit : 80,
63             auto_search : true,
64             flags : {
65                 sidebar : false,
66                 views_switcher : false,
67                 action_buttons : false
68             }
69         };
70         // TODO: create a Dialog controller which optionally takes an action
71         // Should set width & height automatically and take buttons & views callback
72         var dialog_id = _.uniqueId('act_window_dialog');
73         var action_manager = new openerp.base.ActionManager(this.session, dialog_id);
74         var $dialog = $('<div id=' + dialog_id + '>').dialog({
75                             modal : true,
76                             title : 'Actions',
77                             width : 800,
78                             height : 600,
79                             buttons : {
80                                 Cancel : function() {
81                                     $(this).dialog('destroy');
82                                 },
83                                 Add : function() {
84                                     self.do_add_widget(action_manager);
85                                     $(this).dialog('destroy');
86                                 }
87                             }
88                         });
89         action_manager.start();
90         action_manager.do_action(action);
91         // TODO: should bind ListView#select_record in order to catch record clicking
92     },
93     do_add_widget : function(action_manager) {
94         var self = this,
95             actions = action_manager.viewmanager.views.list.controller.groups.get_selection().ids,
96             results = [],
97             qdict = { view : this.view };
98         // TODO: should load multiple actions at once
99         _.each(actions, function(aid) {
100             self.rpc('/base/action/load', {
101                 action_id: aid
102             }, function(result) {
103                 self.actions_attrs[aid] = {
104                     name: aid,
105                     string: _.trim(result.result.name)
106                 }
107                 qdict.action = {
108                     attrs : self.actions_attrs[aid]
109                 }
110                 self.$element.find('.oe-dashboard-column:first').prepend(QWeb.render('DashBoard.action', qdict));
111                 self.do_save_dashboard();
112                 self.on_load_action(result)
113             });
114         });
115     },
116     on_rename : function(e) {
117         var self = this,
118             id = parseInt($(e.currentTarget).parents('.oe-dashboard-action:first').attr('data-id'), 10),
119             $header = $(e.currentTarget).parents('.oe-dashboard-action-header:first'),
120             $rename = $header.find('a.oe-dashboard-action-rename').hide(),
121             $title = $header.find('span.oe-dashboard-action-title').hide(),
122             $input = $header.find('input[name=title]');
123         $input.val($title.text()).show().focus().bind('keydown', function(e) {
124             if (e.which == 13 || e.which == 27) {
125                 if (e.which == 13) { //enter
126                     var val = $input.val();
127                     if (!val) {
128                         return false;
129                     }
130                     $title.text(val);
131                     self.actions_attrs[id].string = val;
132                     self.do_save_dashboard();
133                 }
134                 $input.unbind('keydown').hide();
135                 $rename.show();
136                 $title.show();
137             }
138         });
139     },
140     on_change_layout: function() {
141         var self = this;
142         var qdict = {
143             current_layout : this.$element.find('.oe-dashboard').attr('data-layout')
144         };
145         var $dialog = $('<div>').dialog({
146                             modal: true,
147                             title: 'Edit Layout',
148                             width: 'auto',
149                             height: 'auto'
150                         }).html(QWeb.render('DashBoard.layouts', qdict));
151         $dialog.find('li').click(function() {
152             var layout = $(this).attr('data-layout');
153             $dialog.dialog('destroy');
154             self.do_change_layout(layout);
155         });
156     },
157     do_change_layout: function(new_layout) {
158         var $dashboard = this.$element.find('.oe-dashboard');
159         var current_layout = $dashboard.attr('data-layout');
160         if (current_layout != new_layout) {
161             var clayout = current_layout.split('-').length,
162                 nlayout = new_layout.split('-').length,
163                 column_diff = clayout - nlayout;
164             if (column_diff > 0) {
165                 var $last_column = $();
166                 $dashboard.find('.oe-dashboard-column').each(function(k, v) {
167                     if (k >= nlayout) {
168                         $(v).find('.oe-dashboard-action').appendTo($last_column);
169                     } else {
170                         $last_column = $(v);
171                     }
172                 });
173             }
174             $dashboard.toggleClass('oe-dashboard-layout_' + current_layout + ' oe-dashboard-layout_' + new_layout);
175             $dashboard.attr('data-layout', new_layout);
176             this.do_save_dashboard();
177         }
178     },
179     on_fold_action: function(e) {
180         var $e = $(e.currentTarget),
181             $action = $e.parents('.oe-dashboard-action:first'),
182             id = parseInt($action.attr('data-id'), 10);
183         if ($e.is('.ui-icon-minusthick')) {
184             this.actions_attrs[id].fold = '1';
185         } else {
186             delete(this.actions_attrs[id].fold);
187         }
188         $e.toggleClass('ui-icon-minusthick ui-icon-plusthick');
189         $action.find('.oe-dashboard-action-content').toggle();
190         this.do_save_dashboard();
191     },
192     on_close_action: function(e) {
193         $(e.currentTarget).parents('.oe-dashboard-action:first').remove();
194         this.do_save_dashboard();
195     },
196     do_save_dashboard: function() {
197         var self = this;
198         var board = {
199                 form_title : this.view.fields_view.arch.attrs.string,
200                 style : this.$element.find('.oe-dashboard').attr('data-layout'),
201                 columns : []
202             };
203         this.$element.find('.oe-dashboard-column').each(function() {
204             var actions = [];
205             $(this).find('.oe-dashboard-action').each(function() {
206                 var action_id = $(this).attr('data-id');
207                 actions.push(self.actions_attrs[action_id]);
208             });
209             board.columns.push(actions);
210         });
211         var arch = QWeb.render('DashBoard.xml', board);
212         this.rpc('/base/view/add_custom', {
213             view_id: this.view.fields_view.view_id,
214             arch: arch
215         }, function() {
216             self.$element.find('.oe-dashboard-link-undo, .oe-dashboard-link-reset').show();
217         });
218     },
219     on_load_action: function(result) {
220         var action = result.result;
221         action.flags = {
222             search_view : false,
223             sidebar : false,
224             views_switcher : false,
225             action_buttons : false,
226             pager: false
227         };
228         new openerp.base.ActionManager(
229                 this.session, this.view.element_id + '_action_' + action.id)
230             .do_action(action);
231     },
232     render: function() {
233         // We should start with three columns available
234         for (var i = this.node.children.length; i < 3; i++) {
235             this.node.children.push({
236                 tag: 'column',
237                 attrs: {},
238                 children: []
239             });
240         }
241         return QWeb.render(this.template, this);
242     },
243     do_reload: function() {
244         this.view.view_manager.stop();
245         this.view.view_manager.start();
246     }
247 });
248 openerp.base.form.DashBoardLegacy = openerp.base.form.DashBoard.extend({
249     render: function() {
250         if (this.node.tag == 'hpaned') {
251             this.node.attrs.style = '1-1';
252         } else if (this.node.tag == 'vpaned') {
253             this.node.attrs.style = '1';
254         }
255         this.node.tag = 'board';
256         _.each(this.node.children, function(child) {
257             if (child.tag.indexOf('child') == 0) {
258                 child.tag = 'column';
259                 var actions = [], first_child = child.children[0];
260                 if (first_child && first_child.tag == 'vpaned') {
261                     _.each(first_child.children, function(subchild) {
262                         actions.push.apply(actions, subchild.children);
263                     });
264                     child.children = actions;
265                 }
266             }
267         });
268         return this._super(this, arguments);
269     }
270 });
271
272 openerp.base.form.widgets.add('hpaned', 'openerp.base.form.DashBoardLegacy');
273 openerp.base.form.widgets.add('vpaned', 'openerp.base.form.DashBoardLegacy');
274 openerp.base.form.widgets.add('board', 'openerp.base.form.DashBoard');
275
276 openerp.base.client_actions.add(
277     'board.config.overview', 'openerp.base_dashboard.ConfigOverview'
278 );
279 if (!openerp.base_dashboard) {
280     openerp.base_dashboard = {};
281 }
282 openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
283     init: function (parent_or_session, element_id) {
284         this._super(parent_or_session, element_id);
285         this.dataset = new openerp.base.DataSetSearch(
286                 this.session, 'ir.actions.todo');
287     },
288     start: function () {
289         this.dataset.read_slice(['state', 'action_id'], undefined, undefined,
290                         this.on_records_loaded);
291     },
292     on_records_loaded: function (records) {
293         var       self = this,
294           done_records = _(records).filter(function (record) {
295                                 return record.state === 'done';}),
296             done_ratio = done_records.length / records.length;
297         this.$element.html(QWeb.render('ConfigOverview', {
298             completion: done_ratio * 100,
299             todos: _(records).map(function (record) {
300                 return {
301                     action: record.action_id[0],
302                     name: record.action_id[1],
303                     state: record.state,
304                     done: record.state === 'done',
305                     skipped: record.state === 'skip',
306                     to_do: (record.state !== 'done' && record.state !== 'skip')
307                 }
308             })
309         }));
310         var $progress = this.$element.find('div.oe-config-progress');
311         $progress.progressbar({value: $progress.data('completion')});
312
313         // allow for executing to-do and skipped action
314         this.$element.find('div.oe-dashboard-config-overview ul')
315                 .delegate('li.ui-state-error', 'click', function () {
316             self.execute_action({
317                 type: 'action',
318                 name: $(this).data('action')
319             }, self.dataset,
320             new openerp.base.ActionManager(self.session, self.element_id),
321             null, null, function () {
322                 // after action popup closed, refresh configuration thingie
323                 self.start();
324             });
325         });
326     }
327 });
328
329 openerp.base.client_actions.add(
330     'board.home.applications', 'openerp.base_dashboard.ApplicationTiles');
331 openerp.base_dashboard.ApplicationTiles = openerp.base.View.extend({
332     init: function (parent_or_session, element_id) {
333         this._super(parent_or_session, element_id);
334         this.dataset = new openerp.base.DataSetSearch(
335                 this.session, 'ir.ui.menu', null, [['parent_id', '=', false]]);
336     },
337     start: function () {
338         var self = this;
339         this.dataset.read_slice(
340             ['name', 'web_icon_data', 'web_icon_hover_data'],
341             null, null, function (applications) {
342                 // Create a matrix of 3*x applications
343                 var rows = [];
344                 while (applications.length) {
345                     rows.push(applications.splice(0, 3));
346                 }
347                 self.$element
348                     .append(QWeb.render(
349                         'ApplicationTiles', {rows: rows}))
350                     .find('.oe-dashboard-home-tile')
351                         .click(function () {
352                             var $this = $(this);
353                             $this.closest('.openerp')
354                                  .find('.menu a[data-menu=' + $this.data('menuid') + ']')
355                                  .click();});
356         });
357     }
358 });
359 openerp.base.client_actions.add(
360     'board.home.widgets', 'openerp.base_dashboard.Widgets');
361 openerp.base_dashboard.Widgets = openerp.base.View.extend({
362     init: function (parent_or_session, element_id) {
363         this._super(parent_or_session, element_id);
364         this.user_widgets = new openerp.base.DataSetSearch(
365                 this.session, 'res.widget.user', null,
366                 ['|', ['user_id', '=', false],
367                       ['user_id', '=', this.session.uid]]);
368         this.widgets = new openerp.base.DataSetSearch(this.session, 'res.widget');
369     },
370     start: function () {
371         this.user_widgets.read_slice(['widget_id', 'user_id'], null, null,
372             this.on_widgets_list_loaded);
373     },
374     on_widgets_list_loaded: function (user_widgets) {
375         var self = this;
376         var widget_user = {};
377         _(user_widgets).each(function (widget) {
378             widget['widget_id'] = widget['widget_id'][0];
379             widget_user[widget['widget_id']] = {
380                 removable: widget['user_id'] !== false,
381                 user_widget_id: widget['id']
382             };
383         });
384         this.widgets.read_ids(_(user_widgets).pluck('widget_id'), [], function (widgets) {
385             _(widgets).each(function (widget) {
386                 _.extend(widget, widget_user[widget['id']]);
387             });
388             var root = self.$element[0];
389             root.innerHTML = QWeb.render('HomeWidgets', {
390                 widgets: widgets
391             });
392
393             self.process_widgets_scripts(0, root.getElementsByTagName('script'));
394         })
395     },
396     process_widgets_scripts: function (index, nodes) {
397         if (nodes.length <= index) {
398             return;
399         }
400         var old_write = window.document.write,
401                  self = this,
402                script = nodes[index],
403              deferred = $.Deferred().then(function () {
404                             window.document.write = old_write; }),
405          continuation = function () {
406              $.when(self.process_widgets_scripts(index+1, nodes)).then(
407                      deferred.resolve());
408          };
409         window.document.write = function (s) {
410             $(script).closest('.oe-dashboard-home-widgets-widget')
411                 .children('div')
412                 .append(s);
413         };
414
415         if (!script.src) {
416             new Function(script.firstChild.nodeValue)();
417             setTimeout(continuation);
418         } else {
419             $LAB.script(script.src).wait(continuation);
420         }
421         return deferred;
422     }
423 });
424 };