5
5
_.str.toBoolElse = function(str, elseValues, trueValues, falseValues) {
6
6
var ret = _.str.toBool(str, trueValues, falseValues);
7
7
if (_.isUndefined(ret)) {
13
13
openerp.web_calendar = function(instance) {
39
39
function isNullOrUndef(value) {
40
return _.isUndefined(value) || _.isNull(value)
40
return _.isUndefined(value) || _.isNull(value);
43
43
instance.web.views.add('calendar', 'instance.web_calendar.CalendarView');
73
72
destroy: function() {
74
73
this.$calendar.fullCalendar('destroy');
75
this.$small_calendar.datepicker('destroy');
74
if (this.$small_calendar){
75
this.$small_calendar.datepicker('destroy');
76
77
this._super.apply(this, arguments);
112
113
this.date_start = attrs.date_start; // Field name of starting date field
113
114
this.date_delay = attrs.date_delay; // duration
114
115
this.date_stop = attrs.date_stop;
115
this.all_day = attrs.all_day;
116
this.attendee_people = attrs.attendee;
116
this.all_day = attrs.all_day;
117
117
this.how_display_event = '';
118
this.attendee_people = attrs.attendee;
119
120
if (!isNullOrUndef(attrs.quick_create_instance)) {
120
self.quick_create_instance = 'instance.' + attrs.quick_create_instance;
121
self.quick_create_instance = 'instance.' + attrs.quick_create_instance;
123
124
//if quick_add = False, we don't allow quick_add
124
125
//if quick_add = not specified in view, we use the default quick_create_instance
125
126
//if quick_add = is NOT False and IS specified in view, we this one for quick_create_instance'
127
this.quick_add_pop = (isNullOrUndef(attrs.quick_add) || _.str.toBoolElse(attrs.quick_add,true) );
128
this.quick_add_pop = (isNullOrUndef(attrs.quick_add) || _.str.toBoolElse(attrs.quick_add,true) );
128
129
if (this.quick_add_pop && !isNullOrUndef(attrs.quick_add)) {
129
self.quick_create_instance = 'instance.' + attrs.quick_add;
130
self.quick_create_instance = 'instance.' + attrs.quick_add;
131
132
// The display format which will be used to display the event where fields are between "[" and "]"
132
133
if (!isNullOrUndef(attrs.display)) {
136
137
// If this field is set ot true, we don't open the event in form view, but in a popup with the view_id passed by this parameter
137
138
if (isNullOrUndef(attrs.event_open_popup) || !_.str.toBoolElse(attrs.event_open_popup,true)) {
138
this.open_popup_action = false;
139
this.open_popup_action = false;
141
142
this.open_popup_action = attrs.event_open_popup;
144
// If this field is set to true, we will use de calendar_friends model as filter and not the color field.
145
this.useContacts = (!isNullOrUndef(attrs.use_contacts) && _.str.toBool(attrs.use_contacts));
146
// If this field is set to true, we will use the calendar_friends model as filter and not the color field.
147
this.useContacts = (!isNullOrUndef(attrs.use_contacts) && _.str.toBool(attrs.use_contacts)) && (!isNullOrUndef(self.options.$sidebar));
147
149
// If this field is set ot true, we don't add itself as an attendee when we use attendee_people to add each attendee icon on an event
148
150
// The color is the color of the attendee, so don't need to show again that it will be present
149
this.colorIsAttendee = (!(isNullOrUndef(attrs.color_is_attendee) || !_.str.toBoolElse(attrs.color_is_attendee,true)));
151
this.colorIsAttendee = (!(isNullOrUndef(attrs.color_is_attendee) || !_.str.toBoolElse(attrs.color_is_attendee, true))) && (!isNullOrUndef(self.options.$sidebar));
155
// if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
156
if (isNullOrUndef(self.options.$sidebar)) {
157
this.useContacts = false;
158
this.colorIsAttendee = false;
159
this.attendee_people = undefined;
152
164
Will be more logic to do it in futur, but see below to stay Retro-compatible
166
178
if (isNullOrUndef(attrs.avatar_model)) {
167
this.avatar_model = null;
179
this.avatar_model = null;
170
182
this.avatar_model = attrs.avatar_model;
173
185
if (isNullOrUndef(attrs.avatar_title)) {
174
this.avatar_title = this.avatar_model;
186
this.avatar_title = this.avatar_model;
177
189
this.avatar_title = attrs.avatar_title;
195
207
.call("check_access_rights", ["create", false])
196
208
.then(function (create_right) {
197
209
self.create_right = create_right;
198
self.init_calendar().then(function() {
210
self.init_calendar().then(function() {
199
211
self.trigger('calendar_view_loaded', fv);
200
212
self.ready.resolve();
231
243
self.proxy('update_record')(event._id, data);
233
245
eventRender: function (event, element, view) {
234
element.find('.fc-event-title').html(event.title);
246
element.find('.fc-event-title').html(event.title);
236
eventAfterRender: function (event, element, view) {
248
eventAfterRender: function (event, element, view) {
237
249
if ((view.name !== 'month') && (((event.end-event.start)/60000)<=30)) {
238
250
//if duration is too small, we see the html code of img
239
251
var current_title = $(element.find('.fc-event-time')).text();
240
var new_title = current_title.substr(0,current_title.indexOf("<img")>0?current_title.indexOf("<img"):current_title.length)
252
var new_title = current_title.substr(0,current_title.indexOf("<img")>0?current_title.indexOf("<img"):current_title.length);
241
253
element.find('.fc-event-time').html(new_title);
244
256
eventClick: function (event) { self.open_event(event._id,event.title); },
245
257
select: function (start_date, end_date, all_day, _js_event, _view) {
294
305
context.$calendar.fullCalendar('changeView','agendaDay');
297
else if (curView.name != "agendaDay" || (curView.name == "agendaDay" && curDate.compareTo(curView.start)==0)) {
308
else if (curView.name != "agendaDay" || (curView.name == "agendaDay" && curDate.compareTo(curView.start)===0)) {
298
309
context.$calendar.fullCalendar('changeView','agendaWeek');
300
311
context.$calendar.fullCalendar('gotoDate', obj.currentYear , obj.currentMonth, obj.currentDay);
304
315
init_calendar: function() {
312
323
this.$small_calendar.datepicker({ onSelect: self.calendarMiniChanged(self) });
314
325
if (this.useContacts) {
315
327
new instance.web.Model("res.users").query(["partner_id"]).filter([["id", "=",this.dataset.context.uid]]).first()
318
330
var sidebar_items = {};
319
331
var filter_value = result.partner_id[0];
320
332
var filter_item = {
326
338
sidebar_items[filter_value] = filter_item ;
329
label: _lt("All calendars"),
341
label: _lt("Everybody's calendars"),
330
342
color: self.get_color(-1),
331
343
avatar_model: self.avatar_model
333
345
sidebar_items[-1] = filter_item ;
346
//Get my coworkers/contacts
335
347
new instance.web.Model("calendar.contacts").query(["partner_id"]).filter([["user_id", "=",self.dataset.context.uid]]).all().then(function(result) {
336
348
_.each(result, function(item) {
337
349
filter_value = item.partner_id[0];
347
359
self.allFilters = sidebar_items;
348
360
self.sidebar.filter.events_loaded(sidebar_items);
349
361
self.sidebar.filter.addUpdateButton();
350
}).done(function () {
351
self.$calendar.fullCalendar('refetchEvents');
362
}).done(function () {
363
self.$calendar.fullCalendar('refetchEvents');
356
368
this.extraSideBar();
486
498
event_data_transform: function(evt) {
489
var date_start = instance.web.auto_str_to_date(evt[this.date_start]),
490
date_stop = this.date_stop ? instance.web.auto_str_to_date(evt[this.date_stop]) : null,
491
date_delay = evt[this.date_delay] || 1.0,
501
var date_delay = evt[this.date_delay] || 1.0,
492
502
all_day = this.all_day ? evt[this.all_day] : false,
493
503
res_computed_text = '',
497
if (this.date_stop && this.fields[this.date_stop].type == 'date') {
508
date_start = instance.web.auto_str_to_date(evt[this.date_start]);
509
date_stop = this.date_stop ? instance.web.auto_str_to_date(evt[this.date_stop]) : null;
512
date_start = instance.web.auto_str_to_date(evt[this.date_start].split(' ')[0],'date');
513
date_stop = this.date_stop ? instance.web.auto_str_to_date(evt[this.date_stop].split(' ')[0],'date').addMinutes(-1) : null;
501
516
if (this.info_fields) {
540
555
var res_text= [];
541
_.each(temp_ret, function(val,key) { res_text.push(val)} );
542
the_title = res_text.join(', ');
556
_.each(temp_ret, function(val,key) { res_text.push(val); });
557
the_title = res_text.join(', ');
544
559
the_title = _.escape(the_title);
551
566
var attendee_showed = 0;
552
567
var attendee_other = '';
554
_.each(temp_ret[this.attendee_people],
555
function (the_attendee_people) {
569
_.each(temp_ret[this.attendee_people],
570
function (the_attendee_people) {
556
571
attendees.push(the_attendee_people);
557
572
attendee_showed += 1;
558
if (attendee_showed<= MAX_ATTENDEES) {
559
if (self.avatar_model != null) {
560
the_title_avatar += '<img title="' + self.all_attendees[the_attendee_people] + '" class="attendee_head" src="/web/binary/image?model=' + self.avatar_model + '&field=image_small&id=' + the_attendee_people + '"></img>';
573
if (attendee_showed<= MAX_ATTENDEES) {
574
if (self.avatar_model !== null) {
575
the_title_avatar += '<img title="' + self.all_attendees[the_attendee_people] + '" class="attendee_head" \
576
src="/web/binary/image?model=' + self.avatar_model + '&field=image_small&id=' + the_attendee_people + '"></img>';
563
579
if (!self.colorIsAttendee || the_attendee_people != temp_ret[self.color_field]) {
564
580
tempColor = (self.all_filters[the_attendee_people] != undefined)
565
581
? self.all_filters[the_attendee_people].color
566
582
: self.all_filters[-1].color;
568
the_title_avatar += '<i class="fa fa-user attendee_head color_'+tempColor+'" title="' + self.all_attendees[the_attendee_people] + '" ></i>'
583
the_title_avatar += '<i class="fa fa-user attendee_head color_'+tempColor+'" title="' + self.all_attendees[the_attendee_people] + '" ></i>';
569
584
}//else don't add myself
573
588
attendee_other += self.all_attendees[the_attendee_people] +", ";
577
592
if (attendee_other.length>2) {
578
the_title_avatar += '<span class="attendee_head" title="' + attendee_other.slice(0, -2) + '">+</span>';
593
the_title_avatar += '<span class="attendee_head" title="' + attendee_other.slice(0, -2) + '">+</span>';
580
595
the_title = the_title_avatar + the_title;
584
599
if (!date_stop && date_delay) {
585
600
date_stop = date_start.clone().addHours(date_delay);
587
602
if (this.fields[this.date_start].type != "date" && all_day) {
588
date_stop.addDays(-1);
603
//date_stop.addDays(-1);
591
606
'start': date_start.toString('yyyy-MM-dd HH:mm:ss'),
600
if (!self.useContacts || self.all_filters[evt[this.color_field]] != undefined) {
615
if (!self.useContacts || self.all_filters[evt[this.color_field]] !== undefined) {
601
616
if (this.color_field && evt[this.color_field]) {
602
617
var color_key = evt[this.color_field];
603
618
if (typeof color_key === "object") {
604
619
color_key = color_key[0];
606
r.className = 'cal_opacity calendar_color_'+ this.get_color(color_key);
621
r.className = 'cal_opacity calendar_color_'+ this.get_color(color_key);
609
624
else { // if form all, get color -1
611
626
r.className = 'cal_opacity calendar_color_'+ self.all_filters[-1].color;
628
642
var event_end = event.end;
629
643
//Bug when we move an all_day event from week or day view, we don't have a dateend or duration...
630
if (event_end == null) {
644
if (event_end === null) {
631
645
event_end = new Date(event.start).addHours(2);
637
651
event_end = new Date(event.start);
639
653
if (this.all_day) {
640
event_end = (new Date(event_end.getTime())).addDays(1);
641
date_start_day = new Date(Date.UTC(event.start.getFullYear(),event.start.getMonth(),event.start.getDate()))
642
date_stop_day = new Date(Date.UTC(event_end.getFullYear(),event_end.getMonth(),event_end.getDate()))
654
event_end = (new Date(event_end.getTime())).addDays(1);
655
date_start_day = new Date(event.start.getFullYear(),event.start.getMonth(),event.start.getDate(),12);
656
date_stop_day = new Date(event_end.getFullYear(),event_end.getMonth(),event_end.getDate(),12);
645
date_start_day = new Date(Date.UTC(event.start.getFullYear(),event.start.getMonth(),event.start.getDate(),7))
646
date_stop_day = new Date(Date.UTC(event_end.getFullYear(),event_end.getMonth(),event_end.getDate(),19))
659
date_start_day = new Date(event.start.getFullYear(),event.start.getMonth(),event.start.getDate(),7);
660
date_stop_day = new Date(event_end.getFullYear(),event_end.getMonth(),event_end.getDate(),19);
648
662
data[this.date_start] = instance.web.parse_value(date_start_day, this.fields[this.date_start]);
649
663
if (this.date_stop) {
650
664
data[this.date_stop] = instance.web.parse_value(date_stop_day, this.fields[this.date_stop]);
656
669
data[this.date_start] = instance.web.parse_value(event.start, this.fields[this.date_start]);
657
670
if (this.date_stop) {
658
671
data[this.date_stop] = instance.web.parse_value(event_end, this.fields[this.date_stop]);
664
676
if (this.all_day) {
665
data[this.all_day] = event.allDay;
677
data[this.all_day] = event.allDay;
668
680
if (this.date_delay) {
674
687
do_search: function(domain, context, _group_by) {
691
self.sidebar.filter.is_loaded = false;
676
694
if (! _.isUndefined(this.event_source)) {
677
695
this.$calendar.fullCalendar('removeEventSource', this.event_source);
684
702
domain: self.get_range_domain(domain, start, end),
685
703
context: context,
686
704
}).done(function(events) {
687
706
if (self.event_source !== current_event_source) {
688
707
console.log("Consecutive ``do_search`` called. Cancelling.");
691
// We should make sure that *2many used in title of event have their extended form [ID, NAME]...
693
events = $.map(events, function (e) {
695
if (self.attendee_people != undefined) { //If we filter on contacts...
696
if (_.intersection(self.selected_filters,e[self.attendee_people]).length || (self.selected_filters.indexOf(-1) > -1)) {
711
if (self.attendee_people !== undefined) {
712
//Else we filter on 'Everybody's Calendar, we don't filter events
713
if (self.selected_filters.indexOf(-1) == -1) {
715
//If we filter on contacts... we keep only events from coworkers
716
events = $.map(events, function (e) {
717
if (_.intersection(self.selected_filters,e[self.attendee_people]).length ) {
703
else { //We adds all events
709
if (!self.useContacts) { // If we use all peoples as filter in sidebars
725
if (!self.useContacts) { // If we use all peoples displayed in the current month as filter in sidebars
710
726
var now_filters = {};
711
727
var filter_value;
714
731
_.each(events, function (e) {
715
732
filter_value = e[self.color_field][0];
727
745
self.allFilters = now_filters;
728
self.sidebar.filter.events_loaded(now_filters);
748
if (!self.sidebar.filter.is_loaded) {
749
self.sidebar.filter.events_loaded(now_filters);
752
events = $.map(events, function (e) {
753
if (_.contains(self.selected_filters,e[self.color_field][0]) ) {
730
760
return self.perform_necessary_name_gets(events).then(callback);
733
763
var all_attendees = [];
735
765
_.each(events, function (e) {
736
all_attendees.push(e[self.attendee_people]);
766
all_attendees.push(e[self.attendee_people]);
739
self.all_attendees = {}
769
self.all_attendees = {};
741
771
all_attendees = _.chain(all_attendees).flatten().uniq().value();
743
if (self.avatar_title != null) {
773
if (self.avatar_title !== null) {
744
774
new instance.web.Model(self.avatar_title).query(["name"]).filter([["id", "in",all_attendees]]).all().then(function(result) {
745
775
_.each(result, function(item) {
746
776
self.all_attendees[item.id] = item.name;
749
779
return self.perform_necessary_name_gets(events).then(callback);
753
783
_.each(all_attendees,function(item){
754
784
self.all_attendees[item] = '';
806
open_event: function(id,title) {
832
open_event: function(id, title) {
808
if (! this.open_popup_action) {
834
if (! this.open_popup_action) {
809
835
var index = this.dataset.get_id_index(id);
810
836
this.dataset.index = index;
811
837
this.do_switch_view('form', null, { mode: "edit" });
817
840
var pop = new instance.web.form.FormOpenPopup(this);
818
console.log(this.open_popup_action, +this.open_popup_action);
819
841
pop.show_element(this.dataset.model, id, this.dataset.get_context(), {
820
842
title: _.str.sprintf(_t("View: %s"),title),
821
843
view_id: +this.open_popup_action,
827
849
var form_controller = pop.view_form;
828
850
form_controller.on("load_record", self, function(){
830
852
button_edit = _.str.sprintf("<button class='oe_button oe_bold editme oe_highlight'><span> %s </span></button>",_t("Edit Event"));
833
pop.$el.closest(".ui-dialog").find(".ui-dialog-buttonpane").prepend(button_delete)
834
pop.$el.closest(".ui-dialog").find(".ui-dialog-buttonpane").prepend(button_edit)
855
pop.$el.closest(".ui-dialog").find(".ui-dialog-buttonpane").prepend(button_delete);
856
pop.$el.closest(".ui-dialog").find(".ui-dialog-buttonpane").prepend(button_edit);
836
858
$('.delme').click(
838
$('.oe_form_button_cancel').trigger('click');
839
self.remove_event(id);
860
$('.oe_form_button_cancel').trigger('click');
861
self.remove_event(id);
842
864
$('.editme').click(
844
$('.oe_form_button_cancel').trigger('click');
846
var index = self.dataset.get_id_index(id);
847
self.dataset.index = index;
866
$('.oe_form_button_cancel').trigger('click');
867
self.dataset.index = self.dataset.get_id_index(id);
848
868
self.do_switch_view('form', null, { mode: "edit" });
862
876
do_show: function() {
900
914
slow_created: function () {
901
915
// refresh all view, because maybe some recurrents item
918
// force filter refresh
919
self.sidebar.filter.is_loaded = false;
903
921
self.$calendar.fullCalendar('refetchEvents');
933
951
template: 'CalendarView.quick_create',
935
953
init: function(parent, dataset, buttons, options, data_template) {
937
955
this.dataset = dataset;
938
956
this._buttons = buttons || false;
939
957
this.options = options;
965
983
if(event.keyCode == 13){
966
984
self.$input.off('keyup', enterHandler);
967
985
if (!self.quick_add()){
968
self.$input.on('keyup', enterHandler);
986
self.$input.on('keyup', enterHandler);
974
992
submit.click(function clickHandler() {
975
993
submit.off('click', clickHandler);
976
994
if (!self.quick_add()){
977
submit.on('click', clickHandler);
995
submit.on('click', clickHandler); }
981
998
this.$el.find(".oe_calendar_quick_create_edit").click(function () {
985
1002
this.$el.find(".oe_calendar_quick_create_close").click(function (ev) {
986
1003
ev.preventDefault();
987
1004
self.trigger('close');
1055
1071
slow_create: function(data) {
1072
//if all day, we could reset time to display 00:00:00
1056
1074
var self = this;
1057
1075
var def = $.Deferred();
1058
1076
var defaults = {};
1059
1078
_.each($.extend({}, this.data_template, data), function(val, field_name) {
1060
1079
defaults['default_' + field_name] = val;
1063
if (defaults['default_allday'] && (defaults['default_date_deadline'] || defaults['default_duration'])) {
1064
delete defaults['default_date_deadline'];
1065
delete defaults['default_duration'];
1068
1082
var pop_infos = self.get_form_popup_infos();
1069
1083
var pop = new instance.web.form.FormOpenPopup(this);
1070
var context = new instance.web.CompoundContext(this.dataset.context, defaults)
1084
var context = new instance.web.CompoundContext(this.dataset.context, defaults);
1071
1085
pop.show_element(this.dataset.model, null, this.dataset.get_context(defaults), {
1072
1086
title: this.get_title(),
1073
1087
disable_multiple_selection: true,
1379
1392
instance.web_calendar.SidebarFilter = instance.web.Widget.extend({
1381
1395
'change input:checkbox': 'filter_click'
1383
1397
init: function(parent, view) {
1384
1398
this._super(parent);
1387
1404
events_loaded: function(filters) {
1388
1405
var self = this;
1406
self.is_loaded=true;
1389
1408
self.selected_filters = [];
1390
1409
self.view.all_filters = filters;
1391
1410
this.$el.html(QWeb.render('CalendarView.sidebar.responsible', { filters: filters }));
1392
this.filter_click(null);
1411
this.filter_click(null);
1394
1414
filter_click: function(e) {
1395
1415
var self = this,
1398
1418
this.$('div.oe_calendar_responsible input:checked').each(function() {
1399
1419
responsibles.push($(this).val());
1401
if (e==null && parseInt($(this).val())<0) {
1421
if (e==null && parseInt($(this).val())<0){
1402
1422
$(this).prop('checked',false);
1405
1426
self.view.selected_filters.push(parseInt($(this).val()));
1408
if (e !== null) { //First intialize
1409
self.view.$calendar.fullCalendar('refetchEvents');
1428
self.view.$calendar.fullCalendar('refetchEvents');
1414
1430
addUpdateButton: function() {
1416
1432
this.$('div.oe_calendar_all_responsibles').append(QWeb.render('CalendarView.sidebar.button_add_contact'));
1417
this.$(".add_contacts_link_btn").on('click', function() {
1418
self.rpc("/web/action/load", {
1419
action_id: "calendar.action_calendar_contacts"
1433
this.$(".add_contacts_link_btn").on('click', function() {
1434
self.rpc("/web/action/load", {
1435
action_id: "calendar.action_calendar_contacts"
1420
1436
}).then( function(result) { return self.do_action(result); });