blob: 6e59f21388fe752d1b44dd600a165526e56e8ce4 [file] [log] [blame]
Rushabh Mehtab73fa492012-02-24 15:07:39 +05301// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
2//
3// MIT License (MIT)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21//
22
23pscript.onload_calendar = function(wrapper) {
24 if(!erpnext.calendar) {
25 erpnext.calendar = new Calendar();
26 erpnext.calendar.init(wrapper);
27 rename_observers.push(erpnext.calendar);
28 }
29}
30
31///// CALENDAR
32
33Calendar=function() {
34 this.views=[];
35 this.events = {};
36 this.has_event = {};
37 this.events_by_name = {};
38 this.weekdays = new Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
39}
40
41Calendar.prototype.init=function (parent) {
42
43 this.wrapper = parent;
44 this.body = $('.cal_body').get(0);
45
46 //this.make_head_buttons();
47 //this.make_header();
48 this.view_title = $('.cal_view_title').get(0);
49
50 this.todays_date = new Date();
51 this.selected_date = this.todays_date;
52 this.selected_hour = 8;
53
54 // Create views
55 this.views['Month'] = new Calendar.MonthView(this);
56 this.views['Week'] = new Calendar.WeekView(this);
57 this.views['Day'] = new Calendar.DayView(this);
58
59 // Month view as initial
60 this.cur_view = this.views['Day'];
61 this.views['Day'].show();
62
63}
64
65Calendar.prototype.rename_notify = function(dt, old_name, new_name) {
66 // calendar
67 if(dt = 'Event' && this.has_event[old_name])
68 this.has_event[old_name] = false;
69}
70
71//------------------------------------------------------
72
73Calendar.prototype.show_event = function(ev, cal_ev) {
74 var me = this;
75 if(!this.event_dialog) {
76 var d = new Dialog(400, 400, 'Calendar Event');
77 d.make_body([
78 ['HTML','Heading']
79 ,['Text','Description']
80 ,['Check', 'Public Event']
81 ,['Check', 'Cancel Event']
82 ,['HTML', 'Event Link']
83 ,['Button', 'Save']
84 ])
85
86 // show the event when the dialog opens
87 d.onshow = function() {
88 // heading
89 var c = me.selected_date;
90 var tmp = time_to_ampm(this.ev.event_hour);
91 tmp = tmp[0]+':'+tmp[1]+' '+tmp[2];
92
93 this.widgets['Heading'].innerHTML =
94 '<div style="text-align: center; padding:4px; font-size: 14px">'
95 + erpnext.calendar.weekdays[c.getDay()] + ', ' + c.getDate() + ' ' + month_list_full[c.getMonth()] + ' ' + c.getFullYear()
96 + ' - <b>'+tmp+'</b></div>';
97
98 // set
99 this.widgets['Description'].value = cstr(this.ev.description);
100
101 this.widgets['Public Event'].checked = false;
102 this.widgets['Cancel Event'].checked = false;
103
104 if(this.ev.event_type=='Public')
105 this.widgets['Public Event'].checked = true;
106
107 this.widgets['Event Link'].innerHTML = '';
108
109 // link
110 var div = $a(this.widgets['Event Link'], 'div', 'link_type', {margin:'4px 0px'});
111 div.onclick = function() { me.event_dialog.hide(); loaddoc('Event', me.event_dialog.ev.name); }
112 div.innerHTML = 'View Event details, add or edit participants';
113
114 }
115
116 // event save
117 d.widgets['Save'].onclick = function() {
118 var d = me.event_dialog;
119
120 // save values
121 d.ev.description = d.widgets['Description'].value;
122 if(d.widgets['Cancel Event'].checked) d.ev.event_type='Cancel';
123 else if(d.widgets['Public Event'].checked) d.ev.event_type='Public';
124
125 me.event_dialog.hide();
126
127 // if new event
128 if(d.cal_ev)
129 var cal_ev = d.cal_ev;
130 else
131 var cal_ev = me.set_event(d.ev);
132
133 cal_ev.save();
134 if(me.cur_view)me.cur_view.refresh();
135 }
136 this.event_dialog = d;
137 }
138 this.event_dialog.ev = ev;
139 this.event_dialog.cal_ev = cal_ev ? cal_ev : null;
140 this.event_dialog.show();
141
142}
143
144//------------------------------------------------------
145
146Calendar.prototype.add_event = function() {
147
148 var ev = LocalDB.create('Event');
149 ev = locals['Event'][ev];
150
151 ev.event_date = dateutil.obj_to_str(this.selected_date);
152 ev.event_hour = this.selected_hour+':00';
153 ev.event_type = 'Private';
154
155 this.show_event(ev);
156}
157//------------------------------------------------------
158
159Calendar.prototype.get_month_events = function(call_back) {
160 // ret fn
161 var me = this;
162 var f = function(r, rt) {
163 if(me.cur_view) me.cur_view.refresh();
164 if(call_back)call_back();
165 }
166
167 //load
168 var y=this.selected_date.getFullYear(); var m = this.selected_date.getMonth();
169 if(!this.events[y] || !this.events[y][m]) {
170 $c('webnotes.widgets.event.load_month_events', args = {
171 'month': m + 1,
172 'year' : y},
173 f);
174 }
175}
176//------------------------------------------------------
177
178Calendar.prototype.get_daily_event_list=function(day) {
179 var el = [];
180 var d = day.getDate(); var m = day.getMonth(); var y = day.getFullYear()
181 if(this.events[y] && this.events[y][m] &&
182 this.events[y][m][d]) {
183 var l = this.events[y][m][d]
184 for(var i in l) {
185 for(var j in l[i]) el[el.length] = l[i][j];
186 }
187 return el;
188 }
189 else return [];
190}
191//------------------------------------------------------
192
193Calendar.prototype.set_event = function(ev) {
194 // don't duplicate
195 if(this.events_by_name[ev.name]) {
196 return;
197 }
198
199 var dt = dateutil.str_to_obj(ev.event_date);
200 var m = dt.getMonth();
201 var d = dt.getDate();
202 var y = dt.getFullYear();
203
204 if(!this.events[y]) this.events[y] = [];
205 if(!this.events[y][m]) this.events[y][m] = [];
206 if(!this.events[y][m][d]) this.events[y][m][d] = [];
207 if(!this.events[y][m][d][cint(cint(ev.event_hour))])
208 this.events[y][m][d][cint(ev.event_hour)] = [];
209
210 var cal_ev = new Calendar.CalEvent(ev, this);
211 this.events[y][m][d][cint(ev.event_hour)].push(cal_ev);
212 this.events_by_name[ev.name] = cal_ev;
213 this.has_event[ev.name] = true;
214
215 return cal_ev;
216}
217//------------------------------------------------------
218
219Calendar.prototype.refresh = function(viewtype){//Sets the viewtype of the Calendar and Calls the View class based on the viewtype
220 if(viewtype)
221 this.viewtype = viewtype;
222 // switch view if reqd
223 if(this.cur_view.viewtype!=this.viewtype) {
224 this.cur_view.hide();
225 this.cur_view = this.views[this.viewtype];
226 this.cur_view.in_home = false; // for home page
227 this.cur_view.show();
228 }
229 else{
230 this.cur_view.refresh(this);
231 }
232}
233
234//------------------------------------------------------
235
236Calendar.CalEvent= function(doc, cal) {
237 this.body = document.createElement('div');
238 var v = locals['Event'][doc.name].description;
239 if(v==null)v='';
240 this.body.innerHTML = v;
241
242 this.doc = doc;
243 var me = this;
244
245 this.body.onclick = function() {
246 if(me.doc.name) {
247 cal.show_event(me.doc, me);
248 }
249 }
250}
251
252Calendar.CalEvent.prototype.show = function(vu) {
253
254 var t = this.doc.event_type;
255 this.my_class = 'cal_event cal_event_'+ t;
256
257 if(this.body.parentNode)
258 this.body.parentNode.removeChild(this.body);
259 vu.body.appendChild(this.body);
260
261 // refresh
262 var v = this.doc.description;
263 if(v==null)v='';
264 this.body.innerHTML = v;
265 this.body.className = this.my_class;
266}
267
268Calendar.CalEvent.prototype.save = function() {
269 var me = this;
270 save_doclist('Event', me.doc.name, 'Save', function(r) {
271 me.doc = locals['Event'][r.docname];
272 erpnext.calendar.has_event[r.docname] = true;
273 } );
274}
275// ----------
276
277Calendar.View =function() { this.daystep = 0; this.monthstep = 0; }
278Calendar.View.prototype.init=function(cal) {
279 this.cal = cal;
280 this.body = $a(cal.body, 'div', 'cal_view_body');
281 this.body.style.display = 'none';
282 this.create_table();
283}
284
285
286Calendar.View.prototype.show=function() {
287 this.get_events(); this.refresh(); this.body.style.display = 'block';
288}
289
290Calendar.View.prototype.hide=function() { this.body.style.display = 'none';}
291
292Calendar.View.prototype.next = function() {
293 var s = this.cal.selected_date;
294 this.cal.selected_date = new Date(s.getFullYear(), s.getMonth() + this.monthstep, s.getDate() + this.daystep);
295 this.get_events(); this.refresh();
296}
297
298Calendar.View.prototype.prev = function() {
299 var s = this.cal.selected_date;
300 this.cal.selected_date = new Date(s.getFullYear(), s.getMonth() - this.monthstep, s.getDate() - this.daystep);
301 this.get_events(); this.refresh();
302}
303
304Calendar.View.prototype.get_events = function() {
305 this.cal.get_month_events();
306}
307Calendar.View.prototype.add_unit = function(vu) {
308 this.viewunits[this.viewunits.length] = vu;
309}
310Calendar.View.prototype.refresh_units = function() {
311 // load the events
312 if(locals['Event']) {
313 for(var name in locals['Event']) {
314 this.cal.set_event(locals['Event'][name]);
315 }
316 }
317
318
319 for(var r in this.table.rows) {
320 for(var c in this.table.rows[r].cells) {
321 if(this.table.rows[r].cells[c].viewunit) {
322 this.table.rows[r].cells[c].viewunit.refresh();
323 }
324 }
325 }
326}
327
328// ................. Month View..........................
329Calendar.MonthView = function(cal) { this.init(cal); this.monthstep = 1; this.rows = 5; this.cells = 7; }
330Calendar.MonthView.prototype=new Calendar.View();
331Calendar.MonthView.prototype.create_table = function() {
332
333 // create head
334 this.head_wrapper = $a(this.body, 'div', 'cal_month_head');
335
336 // create headers
337 this.headtable = $a(this.head_wrapper, 'table', 'cal_month_headtable');
338 var r = this.headtable.insertRow(0);
339 for(var j=0;j<7;j++) {
340 var cell = r.insertCell(j);
341 cell.innerHTML = erpnext.calendar.weekdays[j]; $w(cell, (100 / 7) + '%');
342 }
343
344 this.main = $a(this.body, 'div', 'cal_month_body');
345 this.table = $a(this.main, 'table', 'cal_month_table');
346 var me = this;
347
348 // create body
349 for(var i=0;i<5;i++) {
350 var r = this.table.insertRow(i);
351 for(var j=0;j<7;j++) {
352 var cell = r.insertCell(j);
353 cell.viewunit = new Calendar.MonthViewUnit(cell);
354 }
355 }
356}
357
358Calendar.MonthView.prototype.refresh = function() {
359 var c =this.cal.selected_date;
360 var me=this;
361 // fill other days
362
363 var cur_row = 0;
364
365 var cur_month = c.getMonth();
366 var cur_year = c.getFullYear();
367
368 var d = new Date(cur_year, cur_month, 1);
369 var day = 1 - d.getDay();
370
371
372 // set day headers
373 var d = new Date(cur_year, cur_month, day);
374
375 this.cal.view_title.innerHTML = month_list_full[cur_month] + ' ' + cur_year;
376
377 for(var i=0;i<6;i++) {
378 if((i<5) || cur_month==d.getMonth()) { // if this month
379 for(var j=0;j<7;j++) {
380 var cell = this.table.rows[cur_row].cells[j];
381
382 if((i<5) || cur_month==d.getMonth()) { // if this month
383 cell.viewunit.day = d;
384 cell.viewunit.hour = 8;
385 if(cur_month == d.getMonth()) {
386 cell.viewunit.is_disabled = false;
387
388 if(same_day(this.cal.todays_date, d))
389 cell.viewunit.is_today = true;
390 else
391 cell.viewunit.is_today = false;
392
393 } else {
394 cell.viewunit.is_disabled = true;
395 }
396 }
397 // new date
398 day++;
399 d = new Date(cur_year, cur_month, day);
400 }
401 }
402 cur_row++;
403 if(cur_row == 5) {cur_row = 0;} // back to top
404 }
405 this.refresh_units();
406
407}
408 // ................. Daily View..........................
409Calendar.DayView=function(cal){ this.init(cal); this.daystep = 1; }
410Calendar.DayView.prototype=new Calendar.View();
411Calendar.DayView.prototype.create_table = function() {
412
413 // create body
414 this.main = $a(this.body, 'div', 'cal_day_body');
415 this.table = $a(this.main, 'table', 'cal_day_table');
416 var me = this;
417
418 for(var i=0;i<24;i++) {
419 var r = this.table.insertRow(i);
420 for(var j=0;j<2;j++) {
421 var cell = r.insertCell(j);
422 if(j==0) {
423 var tmp = time_to_ampm((i)+':00');
424 cell.innerHTML = tmp[0]+':'+tmp[1]+' '+tmp[2];
425 $w(cell, '10%');
426 } else {
427 cell.viewunit = new Calendar.DayViewUnit(cell);
428 cell.viewunit.hour = i;
429 $w(cell, '90%');
430 if((i>=7)&&(i<=20)) {
431 cell.viewunit.is_daytime = true;
432 }
433 }
434 }
435 }
436 }
437
438Calendar.DayView.prototype.refresh = function() {
439 var c =this.cal.selected_date;
440
441 // fill other days
442 var me=this;
443
444 this.cal.view_title.innerHTML = erpnext.calendar.weekdays[c.getDay()] + ', '
445 + c.getDate() + ' ' + month_list_full[c.getMonth()] + ' ' + c.getFullYear();
446
447 // headers
448 var d = c;
449
450 for(var i=0;i<24;i++) {
451 var cell = this.table.rows[i].cells[1];
452 if(same_day(this.cal.todays_date, d)) cell.viewunit.is_today = true;
453 else cell.viewunit.is_today = false;
454 cell.viewunit.day = d;
455 }
456 this.refresh_units();
457}
458
459// ................. Weekly View..........................
460Calendar.WeekView=function(cal) { this.init(cal); this.daystep = 7; }
461Calendar.WeekView.prototype=new Calendar.View();
462Calendar.WeekView.prototype.create_table = function() {
463
464 // create head
465 this.head_wrapper = $a(this.body, 'div', 'cal_month_head');
466
467 // day headers
468 this.headtable = $a(this.head_wrapper, 'table', 'cal_month_headtable');
469 var r = this.headtable.insertRow(0);
470 for(var j=0;j<8;j++) {
471 var cell = r.insertCell(j);
472 $w(cell, (100 / 8) + '%');
473 }
474
475 // hour header
476
477 // create body
478 this.main = $a(this.body, 'div', 'cal_week_body');
479 this.table = $a(this.main, 'table', 'cal_week_table');
480 var me = this;
481
482 for(var i=0;i<24;i++) {
483 var r = this.table.insertRow(i);
484 for(var j=0;j<8;j++) {
485 var cell = r.insertCell(j);
486 if(j==0) {
487 var tmp = time_to_ampm(i+':00');
488 cell.innerHTML = tmp[0]+':'+tmp[1]+' '+tmp[2];
489
490 $w(cell, '10%');
491 } else {
492 cell.viewunit = new Calendar.WeekViewUnit(cell);
493 cell.viewunit.hour = i;
494 if((i>=7)&&(i<=20)) {
495 cell.viewunit.is_daytime = true;
496 }
497 }
498 }
499 }
500}
501
502Calendar.WeekView.prototype.refresh = function() {
503 var c =this.cal.selected_date;
504 // fill other days
505 var me=this;
506
507 this.cal.view_title.innerHTML = month_list_full[c.getMonth()] + ' ' + c.getFullYear();
508
509 // headers
510 var d = new Date(c.getFullYear(), c.getMonth(), c.getDate() - c.getDay());
511
512 for (var k=1;k<8;k++) {
513 this.headtable.rows[0].cells[k].innerHTML = erpnext.calendar.weekdays[d.getDay()] + ' ' + d.getDate();
514
515 for(var i=0;i<24;i++) {
516 var cell = this.table.rows[i].cells[k];
517 if(same_day(this.cal.todays_date, d))
518 cell.viewunit.is_today = true;
519 else cell.viewunit.is_today = false;
520
521 cell.viewunit.day = d;
522 //cell.viewunit.refresh();
523 }
524 d=new Date(d.getFullYear(),d.getMonth(),d.getDate() + 1);
525
526 }
527
528 this.refresh_units();
529}
530
531//------------------------------------------------------.
532
533Calendar.ViewUnit = function() {}
534Calendar.ViewUnit.prototype.init = function(parent) {
535 parent.style.border = "1px solid #CCC" ;
536 this.body = $a(parent, 'div', this.default_class);
537 this.parent = parent;
538
539 var me = this;
540 this.body.onclick = function() {
541 erpnext.calendar.selected_date = me.day;
542 erpnext.calendar.selected_hour = me.hour;
543
544 if(erpnext.calendar.cur_vu && erpnext.calendar.cur_vu!=me){
545 erpnext.calendar.cur_vu.deselect();
546 me.select();
547 erpnext.calendar.cur_vu = me;
548 }
549 }
550 this.body.ondblclick = function() {
551 erpnext.calendar.add_event();
552 }
553}
554
555Calendar.ViewUnit.prototype.set_header=function(v) {
556 this.header.innerHTML = v;
557}
558
559Calendar.ViewUnit.prototype.set_today = function() {
560 this.is_today = true;
561 this.set_display();
562}
563
564Calendar.ViewUnit.prototype.clear = function() {
565 if(this.header)this.header.innerHTML = '';
566
567 // clear body
568 while(this.body.childNodes.length)
569 this.body.removeChild(this.body.childNodes[0]);
570}
571
572Calendar.ViewUnit.prototype.set_display = function() {
573 var cn = '#FFF';
574
575 // colors
576 var col_tod_sel = '#EEE';
577 var col_tod = '#FFF';
578 var col_sel = '#EEF';
579
580 if(this.is_today) {
581 if(this.selected) cn = col_tod_sel;
582 else cn = col_tod;
583 } else
584 if(this.selected) cn = col_sel;
585
586 if(this.header) {
587 if(this.is_disabled) {
588 this.body.className = this.default_class + ' cal_vu_disabled';
589 this.header.style.color = '#BBB';
590 } else {
591 this.body.className = this.default_class;
592 this.header.style.color = '#000';
593 }
594
595 if(this.day&&this.day.getDay()==0)
596 this.header.style.backgroundColor = '#FEE';
597 else
598 this.header.style.backgroundColor = '';
599 }
600 this.parent.style.backgroundColor = cn;
601}
602
603Calendar.ViewUnit.prototype.is_selected = function() {
604 return (same_day(this.day, erpnext.calendar.selected_date)
605 && this.hour==erpnext.calendar.selected_hour)
606}
607
608Calendar.ViewUnit.prototype.get_event_list = function() {
609 var y = this.day.getFullYear();
610 var m = this.day.getMonth();
611 var d = this.day.getDate();
612 if(erpnext.calendar.events[y] && erpnext.calendar.events[y][m] &&
613 erpnext.calendar.events[y][m][d] &&
614 erpnext.calendar.events[y][m][d][this.hour]) {
615 return erpnext.calendar.events[y][m][d][this.hour];
616 } else
617 return [];
618}
619
620Calendar.ViewUnit.prototype.refresh = function() {
621 this.clear();
622
623 if(this.is_selected()) {
624 if(erpnext.calendar.cur_vu)erpnext.calendar.cur_vu.deselect();
625 this.selected = true;
626 erpnext.calendar.cur_vu = this;
627 }
628 this.set_display();
629 this.el = this.get_event_list();
630 if(this.onrefresh)this.onrefresh();
631
632 for(var i in this.el) {
633 this.el[i].show(this);
634 }
635
636 var me = this;
637}
638
639Calendar.ViewUnit.prototype.select=function() { this.selected = true; this.set_display(); }
640Calendar.ViewUnit.prototype.deselect=function() { this.selected = false; this.set_display(); }
641Calendar.ViewUnit.prototype.setevent=function() { }
642
643Calendar.MonthViewUnit=function(parent) {
644 this.header = $a(parent, 'div' , "cal_month_date");
645 this.default_class = "cal_month_unit";
646
647 this.init(parent);
648
649 this.onrefresh = function() {
650 this.header.innerHTML = this.day.getDate();
651 }
652}
653Calendar.MonthViewUnit.prototype = new Calendar.ViewUnit();
654Calendar.MonthViewUnit.prototype.is_selected = function() {
655 return same_day(this.day, erpnext.calendar.selected_date)
656}
657
658Calendar.MonthViewUnit.prototype.get_event_list = function() {
659 return erpnext.calendar.get_daily_event_list(this.day);
660}
661
662Calendar.DayViewUnit= function(parent) {
663 this.default_class = "cal_day_unit"; this.init(parent);
664}
665Calendar.DayViewUnit.prototype = new Calendar.ViewUnit();
666Calendar.DayViewUnit.prototype.onrefresh = function() {
667 if(this.el.length<3)
668 this.body.style.height = '30px';
669 else this.body.style.height = '';
670}
671
672Calendar.WeekViewUnit=function(parent) {
673 this.default_class = "cal_week_unit"; this.init(parent);
674}
675Calendar.WeekViewUnit.prototype = new Calendar.ViewUnit();
676Calendar.WeekViewUnit.prototype.onrefresh = function() {
677 if(this.el.length<3) this.body.style.height = '30px';
678 else this.body.style.height = '';
679}