1 /*---------------------------------------------------------
3 *---------------------------------------------------------*/
5 openerp.web_calendar = function(openerp) {
6 var _t = openerp.web._t;
7 var QWeb = openerp.web.qweb;
8 openerp.web.views.add('calendar', 'openerp.web_calendar.CalendarView');
9 openerp.web_calendar.CalendarView = openerp.web.View.extend({
11 init: function(parent, dataset, view_id, options) {
13 this.set_default_options(options);
14 this.dataset = dataset;
15 this.model = dataset.model;
16 this.fields_view = {};
17 this.view_id = view_id;
18 this.has_been_loaded = $.Deferred();
19 this.creating_event_id = null;
20 this.dataset_events = [];
21 this.form_dialog = new openerp.web_calendar.CalendarFormDialog(this, {}, this.options.action_views_ids.form, dataset);
22 this.form_dialog.start();
23 this.COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
24 '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
25 '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
26 '#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900' ];
28 this.last_search = [];
32 return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type":"calendar", 'toolbar': true}, this.on_loaded);
38 on_loaded: function(data) {
39 this.fields_view = data;
40 this.calendar_fields = {};
41 this.ids = this.dataset.ids;
42 this.color_values = [];
43 this.info_fields = [];
45 this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
46 this.view_id = this.fields_view.view_id;
48 // mode, one of month, week or day
49 this.mode = this.fields_view.arch.attrs.mode;
51 // date_start is mandatory, date_delay and date_stop are optional
52 this.date_start = this.fields_view.arch.attrs.date_start;
53 this.date_delay = this.fields_view.arch.attrs.date_delay;
54 this.date_stop = this.fields_view.arch.attrs.date_stop;
56 this.colors = this.fields_view.arch.attrs.colors;
57 this.day_length = this.fields_view.arch.attrs.day_length || 8;
58 this.color_field = this.fields_view.arch.attrs.color;
59 this.fields = this.fields_view.fields;
61 if (!this.date_start) {
62 throw new Error("Calendar view has not defined 'date_start' attribute.");
66 this.calendar_fields.date_start = {'name': this.date_start, 'kind': this.fields[this.date_start].type};
68 if (this.date_delay) {
69 if (this.fields[this.date_delay].type != 'float') {
70 throw new Error("Calendar view has a 'date_delay' type != float");
72 this.calendar_fields.date_delay = {'name': this.date_delay, 'kind': this.fields[this.date_delay].type};
75 this.calendar_fields.date_stop = {'name': this.date_stop, 'kind': this.fields[this.date_stop].type};
78 for (var fld = 0; fld < this.fields_view.arch.children.length; fld++) {
79 this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
81 this.$element.html(QWeb.render("CalendarView", {"fields_view": this.fields_view}));
83 if (this.options.sidebar && this.options.sidebar_id) {
84 this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
86 this.sidebar.navigator = new openerp.web_calendar.SidebarNavigator(this.sidebar, this);
87 this.sidebar.responsible = new openerp.web_calendar.SidebarResponsible(this.sidebar, this);
88 this.sidebar.add_toolbar(this.fields_view.toolbar);
89 this.set_common_sidebar_sections(this.sidebar);
90 this.sidebar.do_unfold();
91 this.sidebar.do_fold.add_last(this.refresh_scheduler);
92 this.sidebar.do_unfold.add_last(this.refresh_scheduler);
93 this.sidebar.do_toggle.add_last(this.refresh_scheduler);
96 this.init_scheduler();
97 this.has_been_loaded.resolve();
99 init_scheduler: function() {
101 scheduler.clearAll();
102 if (this.fields[this.date_start]['type'] == 'time') {
103 scheduler.config.xml_date = "%H:%M:%S";
105 scheduler.config.xml_date = "%Y-%m-%d %H:%i";
107 scheduler.config.api_date = "%Y-%m-%d %H:%i";
108 scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
109 scheduler.config.start_on_monday = true;
110 scheduler.config.time_step = 30;
111 scheduler.config.scroll_hour = 8;
112 scheduler.config.drag_resize = true;
113 scheduler.config.drag_create = true;
114 scheduler.config.mark_now = true;
115 scheduler.config.day_date = '%l %j';
117 scheduler.init('openerp_scheduler', null, this.mode || 'month');
119 // Remove hard coded style attributes from dhtmlx scheduler
120 this.$element.find(".dhx_cal_navline div").removeAttr('style');
122 scheduler.detachAllEvents();
123 scheduler.attachEvent('onEventAdded', this.do_create_event);
124 scheduler.attachEvent('onEventDeleted', this.do_delete_event);
125 scheduler.attachEvent('onEventChanged', this.do_save_event);
126 scheduler.attachEvent('onClick', this.do_edit_event);
127 scheduler.attachEvent('onLightbox', this.do_edit_event);
129 scheduler.attachEvent('onViewChange', function(mode, date) {
130 self.$element.removeClass('oe_cal_day oe_cal_week oe_cal_month').addClass('oe_cal_' + mode);
133 if (this.options.sidebar) {
134 this.mini_calendar = scheduler.renderCalendar({
135 container: this.sidebar.navigator.element_id,
137 date: scheduler._date,
138 handler: function(date, calendar) {
139 scheduler.setCurrentView(date, 'day');
144 refresh_scheduler: function() {
145 scheduler.setCurrentView(scheduler._date);
147 refresh_minical: function() {
148 if (this.options.sidebar) {
149 scheduler.updateCalendar(this.mini_calendar);
152 reload_event: function(id) {
153 this.dataset.read_ids([id], _.keys(this.fields), this.on_events_loaded);
155 get_color: function(key) {
156 if (this.color_map[key]) {
157 return this.color_map[key];
159 var index = _.keys(this.color_map).length % this.COLOR_PALETTE.length;
160 var color = this.COLOR_PALETTE[index];
161 this.color_map[key] = color;
164 on_events_loaded: function(events, fn_filter, no_filter_reload) {
167 //To parse Events we have to convert date Format
170 for (var e = 0; e < events.length; e++) {
172 if (!evt[this.date_start]) {
176 if (this.color_field) {
177 var filter = evt[this.color_field];
179 var filter_value = (typeof filter === 'object') ? filter[0] : filter;
180 if (typeof(fn_filter) === 'function' && !fn_filter(filter_value)) {
185 label: (typeof filter === 'object') ? filter[1] : filter,
186 color: this.get_color(filter_value)
188 if (!sidebar_items[filter_value]) {
189 sidebar_items[filter_value] = filter_item;
191 evt.color = filter_item.color;
192 evt.textColor = '#ffffff';
196 if (this.fields[this.date_start]['type'] == 'date') {
197 evt[this.date_start] = openerp.web.auto_str_to_date(evt[this.date_start]).set({hour: 9}).toString('yyyy-MM-dd HH:mm:ss');
199 if (this.date_stop && evt[this.date_stop] && this.fields[this.date_stop]['type'] == 'date') {
200 evt[this.date_stop] = openerp.web.auto_str_to_date(evt[this.date_stop]).set({hour: 17}).toString('yyyy-MM-dd HH:mm:ss');
202 res_events.push(this.convert_event(evt));
204 scheduler.parse(res_events, 'json');
205 this.refresh_scheduler();
206 this.refresh_minical();
207 if (!no_filter_reload && this.options.sidebar) {
208 this.sidebar.responsible.on_events_loaded(sidebar_items);
211 convert_event: function(evt) {
212 var date_start = openerp.web.str_to_datetime(evt[this.date_start]),
213 date_stop = this.date_stop ? openerp.web.str_to_datetime(evt[this.date_stop]) : null,
214 date_delay = evt[this.date_delay] || 1.0,
216 res_description = [];
218 if (this.info_fields) {
219 var fld = evt[this.info_fields[0]];
220 res_text = (typeof fld == 'object') ? fld[fld.length -1] : res_text = fld;
222 var sliced_info_fields = this.info_fields.slice(1);
223 for (var sl_fld in sliced_info_fields) {
224 var slc_fld = evt[sliced_info_fields[sl_fld]];
225 if (typeof slc_fld == 'object') {
226 res_description.push(slc_fld[slc_fld.length - 1]);
227 } else if (slc_fld) {
228 res_description.push(slc_fld);
232 if (!date_stop && date_delay) {
233 date_stop = date_start.clone().addHours(date_delay);
236 'start_date': date_start.toString('yyyy-MM-dd HH:mm:ss'),
237 'end_date': date_stop.toString('yyyy-MM-dd HH:mm:ss'),
240 'title': res_description.join()
246 r.textColor = evt.textColor;
250 do_create_event: function(event_id, event_obj) {
252 data = this.get_event_data(event_obj);
253 this.dataset.create(data, function(r) {
255 self.dataset.ids.push(id);
256 scheduler.changeEventId(event_id, id);
257 self.refresh_minical();
258 }, function(r, event) {
259 event.preventDefault();
260 self.do_create_event_with_formdialog(event_id, event_obj);
263 do_create_event_with_formdialog: function(event_id, event_obj) {
265 event_obj = scheduler.getEvent(event_id);
268 data = this.get_event_data(event_obj),
269 form = self.form_dialog.form,
270 fields_to_fetch = _(form.fields_view.fields).keys();
271 this.dataset.index = null;
272 self.creating_event_id = event_id;
273 this.form_dialog.form.do_show().then(function() {
274 form.show_invalid = false;
275 _.each(['date_start', 'date_stop', 'date_delay'], function(field) {
276 var field_name = self[field];
278 field = form.fields[field_name];
279 field.set_value(data[field_name]);
281 form.do_onchange(field);
284 form.show_invalid = true;
285 self.form_dialog.open();
288 do_save_event: function(event_id, event_obj) {
290 data = this.get_event_data(event_obj),
291 index = this.dataset.get_id_index(event_id);
293 event_id = this.dataset.ids[index];
294 this.dataset.write(event_id, data, {}, function() {
295 self.refresh_minical();
299 do_delete_event: function(event_id, event_obj) {
300 // dhtmlx sends this event even when it does not exist in openerp.
301 // Eg: use cancel in dhtmlx new event dialog
303 index = this.dataset.get_id_index(event_id);
304 if (index !== null) {
305 this.dataset.unlink(event_id, function() {
306 self.refresh_minical();
310 do_edit_event: function(event_id) {
312 var index = this.dataset.get_id_index(event_id);
313 if (index !== null) {
314 this.dataset.index = index;
315 this.do_switch_view('page');
316 } else if (scheduler.getState().mode === 'month') {
317 var event_obj = scheduler.getEvent(event_id);
318 if (event_obj._length === 1) {
319 event_obj['start_date'].addHours(8);
320 event_obj['end_date'] = new Date(event_obj['start_date']);
321 event_obj['end_date'].addHours(1);
323 this.do_create_event_with_formdialog(event_id, event_obj);
325 // Theorically, returning false should prevent the lightbox to open.
326 // It works, but then the scheduler is in a buggy state where drag'n drop
327 // related internal Event won't be fired anymore.
328 // I tried scheduler.editStop(event_id); but doesn't work either
329 // After losing one hour on this, here's a quick and very dirty fix :
330 $(".dhx_cancel_btn").click();
333 get_event_data: function(event_obj) {
337 data[this.date_start] = openerp.web.datetime_to_str(event_obj.start_date);
338 if (this.date_stop) {
339 data[this.date_stop] = openerp.web.datetime_to_str(event_obj.end_date);
341 if (this.date_delay) {
342 var diff_seconds = Math.round((event_obj.end_date.getTime() - event_obj.start_date.getTime()) / 1000);
343 data[this.date_delay] = diff_seconds / 3600;
347 do_search: function(domain, context, group_by) {
350 this.do_search.apply(this, this.last_search);
352 this.last_search = [domain, context, group_by];
354 scheduler.clearAll();
355 $.when(this.has_been_loaded).then(function() {
356 self.dataset.read_slice(_.keys(self.fields), {
359 }, function(events) {
360 self.dataset_events = events;
361 self.on_events_loaded(events);
365 do_show: function () {
367 $.when(this.has_been_loaded).then(function() {
368 self.$element.show();
370 self.sidebar.$element.show();
374 do_hide: function () {
375 this.$element.hide();
377 this.sidebar.$element.hide();
380 get_selected_ids: function() {
381 // no way to select a record anyway
386 openerp.web_calendar.CalendarFormDialog = openerp.web.Dialog.extend({
387 init: function(view, options, view_id, dataset) {
388 this._super(view, options);
389 this.dataset = dataset;
390 this.view_id = view_id;
395 this.form = new openerp.web.FormView(this, this.dataset, this.view_id, {
399 this.form.appendTo(this.$element);
400 this.form.on_created.add_last(this.on_form_dialog_saved);
401 this.form.on_saved.add_last(this.on_form_dialog_saved);
403 on_form_dialog_saved: function() {
404 var id = this.dataset.ids[this.dataset.index];
405 if (this.view.creating_event_id) {
406 scheduler.changeEventId(this.view.creating_event_id, id);
407 this.view.creating_event_id = null;
409 this.view.reload_event(id);
412 on_close: function() {
413 if (this.view.creating_event_id) {
414 scheduler.deleteEvent(this.view.creating_event_id);
415 this.view.creating_event_id = null;
420 openerp.web_calendar.SidebarResponsible = openerp.web.Widget.extend({
421 init: function(parent, view) {
422 var $section = parent.add_section(_t('Responsible'), 'responsible');
423 this.$div = $('<div></div>');
424 $section.append(this.$div);
425 this._super(parent, $section.attr('id'));
427 this.$element.delegate('input:checkbox', 'change', this.on_filter_click);
429 on_events_loaded: function(filters) {
430 this.$div.html(QWeb.render('CalendarView.sidebar.responsible', { filters: filters }));
432 on_filter_click: function(e) {
433 var responsibles = [],
435 this.$element.find('div.oe_calendar_responsible input:checked').each(function() {
436 responsibles.push($(this).val());
438 scheduler.clearAll();
439 if (responsibles.length) {
440 this.view.on_events_loaded(this.view.dataset_events, function(filter_value) {
441 return _.indexOf(responsibles, filter_value.toString()) > -1;
444 this.view.on_events_loaded(this.view.dataset_events, false, true);
449 openerp.web_calendar.SidebarNavigator = openerp.web.Widget.extend({
450 init: function(parent, view) {
451 var $section = parent.add_section(_t('Navigator'), 'navigator');
452 this._super(parent, $section.attr('id'));
455 on_events_loaded: function(events) {
460 // DEBUG_RPC:rpc.request:('execute', 'addons-dsh-l10n_us', 1, '*', ('ir.filters', 'get_filters', u'res.partner'))
461 // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: