]> err.no Git - scalable-opengroupware.org/blob - UI/WebServerResources/SchedulerUI.js
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1071 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / WebServerResources / SchedulerUI.js
1 /* JavaScript for SOGoCalendar */
2
3 var sortOrder = '';
4 var sortKey = '';
5 var listFilter = 'view_today';
6
7 var listOfSelection = null;
8 var selectedCalendarCell;
9
10 var showCompletedTasks = 0;
11
12 var currentDay = '';
13 var currentView = "dayview";
14
15 var cachedDateSelectors = new Array();
16
17 var contactSelectorAction = 'calendars-contacts';
18
19 var eventsToDelete = new Array();
20 var ownersOfEventsToDelete = new Array();
21
22 var usersRightsWindowHeight = 250;
23 var usersRightsWindowWidth = 502;
24
25 function newEvent(sender, type) {
26    var day = sender.getAttribute("day");
27    if (!day)
28       day = currentDay;
29
30    var user = UserLogin;
31    if (sender.parentNode.getAttribute("id") != "toolbar"
32        && currentView == "multicolumndayview" && type == "event")
33       user = sender.parentNode.parentNode.getAttribute("user");
34
35    var hour = sender.getAttribute("hour");
36    var urlstr = UserFolderURL + "../" + user + "/Calendar/new" + type;
37    var params = new Array();
38    if (day)
39       params.push("day=" + day);
40    if (hour)
41       params.push("hm=" + hour);
42    if (params.length > 0)
43       urlstr += "?" + params.join("&");
44    
45    window.open(urlstr, "", "width=490,height=470,resizable=0");
46    
47    return false; /* stop following the link */
48 }
49
50 function onMenuNewEventClick(event) {
51    newEvent(this, "event");
52 }
53
54 function onMenuNewTaskClick(event) {
55    newEvent(this, "task");
56 }
57
58 function _editEventId(id, owner) {
59   var urlBase;
60   if (owner)
61     urlBase = UserFolderURL + "../" + owner + "/";
62   urlBase += "Calendar/"
63
64   var urlstr = urlBase + id + "/edit";
65
66   var win = window.open(urlstr, "SOGo_edit_" + id,
67                         "width=490,height=470,resizable=0");
68   win.focus();
69 }
70
71 function editEvent() {
72   if (listOfSelection) {
73     var nodes = listOfSelection.getSelectedRows();
74
75     for (var i = 0; i < nodes.length; i++)
76       _editEventId(nodes[i].getAttribute("id"),
77                    nodes[i].getAttribute("owner"));
78   } else if (selectedCalendarCell) {
79       _editEventId(selectedCalendarCell.getAttribute("aptCName"),
80                    selectedCalendarCell.getAttribute("owner"));
81   }
82
83   return false; /* stop following the link */
84 }
85
86 function _batchDeleteEvents() {
87   var events = eventsToDelete.shift();
88   var owner = ownersOfEventsToDelete.shift();
89   var urlstr = (UserFolderURL + "../" + owner + "/Calendar/batchDelete?ids="
90                 + events.join('/'));
91   document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
92                                                        deleteEventCallback,
93                                                        events);
94 }
95
96 function deleteEvent() {
97   if (listOfSelection) {
98     var nodes = listOfSelection.getSelectedRows();
99
100     if (nodes.length > 0) {
101       var label = "";
102       if (listOfSelection == $("tasksList"))
103         label = labels["taskDeleteConfirmation"].decodeEntities();
104       else
105         label = labels["appointmentDeleteConfirmation"].decodeEntities();
106       
107       if (confirm(label)) {
108         if (document.deleteEventAjaxRequest) {
109           document.deleteEventAjaxRequest.aborted = true;
110           document.deleteEventAjaxRequest.abort();
111         }
112         var sortedNodes = new Array();
113         var owners = new Array();
114
115         for (var i = 0; i < nodes.length; i++) {
116           var owner = nodes[i].getAttribute("owner");
117           if (!sortedNodes[owner]) {
118               sortedNodes[owner] = new Array();
119               owners.push(owner);
120           }
121           sortedNodes[owner].push(nodes[i].getAttribute("id"));
122         }
123         for (var i = 0; i < owners.length; i++) {
124           ownersOfEventsToDelete.push(owners[i]);
125           eventsToDelete.push(sortedNodes[owners[i]]);
126         }
127         _batchDeleteEvents();
128       }
129     }
130   }
131   else if (selectedCalendarCell) {
132      var label = labels["appointmentDeleteConfirmation"].decodeEntities();
133      if (confirm(label)) {
134         if (document.deleteEventAjaxRequest) {
135            document.deleteEventAjaxRequest.aborted = true;
136            document.deleteEventAjaxRequest.abort();
137         }
138         eventsToDelete.push([selectedCalendarCell.getAttribute("aptCName")]);
139         ownersOfEventsToDelete.push(selectedCalendarCell.getAttribute("owner"));
140         _batchDeleteEvents();
141      }
142   }
143   else
144     window.alert("no selection");
145
146   return false;
147 }
148
149 function modifyEvent(sender, modification) {
150   var currentLocation = '' + window.location;
151   var arr = currentLocation.split("/");
152   arr[arr.length-1] = modification;
153
154   document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
155                                                        modifyEventCallback,
156                                                        modification);
157
158   return false;
159 }
160
161 function closeInvitationWindow() {
162   var closeDiv = document.createElement("div");
163   closeDiv.addClassName("javascriptPopupBackground");
164   var closePseudoWin = document.createElement("div");
165   closePseudoWin.addClassName("javascriptMessagePseudoWindow");
166   closePseudoWin.style.top = "0px;";
167   closePseudoWin.style.left = "0px;";
168   closePseudoWin.style.right = "0px;";
169   closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"].decodeEntities()));
170   document.body.appendChild(closeDiv);
171   document.body.appendChild(closePseudoWin);
172 }
173
174 function modifyEventCallback(http) {
175   if (http.readyState == 4) {
176     if (http.status == 200) {
177       log("closing window...?");
178       if (queryParameters["mail-invitation"] == "yes")
179         closeInvitationWindow();
180       else {
181         window.opener.setTimeout("refreshAppointmentsAndDisplay();", 100);
182         window.setTimeout("window.close();", 100);
183       }
184     }
185     else {
186       log("showing alert...");
187       window.alert(labels["eventPartStatModificationError"]);
188     }
189     document.modifyEventAjaxRequest = null;
190   }
191 }
192
193 function deleteEventCallback(http) {
194   if (http.readyState == 4
195       && http.status == 200) {
196     var nodes = http.callbackData;
197     for (var i = 0; i < nodes.length; i++) {
198       var node = $(nodes[i]);
199       if (node)
200         node.parentNode.removeChild(node);
201     }
202     if (eventsToDelete.length)
203       _batchDeleteEvents();
204     else {
205       document.deleteEventAjaxRequest = null;
206       refreshAppointments();
207       refreshTasks();
208       changeCalendarDisplay();
209     }
210   }
211   else
212     log ("ajax fuckage");
213 }
214
215 function editDoubleClickedEvent(node) {
216   _editEventId(node.getAttribute("id"),
217                node.getAttribute("owner"));
218   
219   return false;
220 }
221
222 function onSelectAll() {
223   var list = $("appointmentsList");
224   list.selectRowsMatchingClass("appointmentRow");
225
226   return false;
227 }
228
229 function displayAppointment(event) {
230   _editEventId(this.getAttribute("aptCName"),
231                this.getAttribute("owner"));
232
233   preventDefault(event);
234   event.stopPropagation();
235   event.cancelBubble = true;
236   event.returnValue = false;
237 }
238
239 function onDaySelect(node) {
240   var day = node.getAttribute("day");
241   var needRefresh = (listFilter == 'view_selectedday'
242                      && day != currentDay);
243
244   var td = node.getParentWithTagName("td");
245   var table = td.getParentWithTagName("table");
246
247 //   log ("table.selected: " + table.selected);
248
249   if (document.selectedDate)
250     document.selectedDate.deselect();
251
252   td.select();
253   document.selectedDate = td;
254
255   changeCalendarDisplay( { "day": day } );
256   if (needRefresh)
257     refreshAppointments();
258
259   return false;
260 }
261
262 function onDateSelectorGotoMonth(node) {
263   var day = node.getAttribute("date");
264
265   changeDateSelectorDisplay(day, true);
266
267   return false;
268 }
269
270 function onCalendarGotoDay(node) {
271   var day = node.getAttribute("date");
272
273   changeDateSelectorDisplay(day);
274   changeCalendarDisplay( { "day": day } );
275
276   return false;
277 }
278
279 function gotoToday() {
280   changeDateSelectorDisplay('');
281   changeCalendarDisplay();
282
283   return false;
284 }
285
286 function setDateSelectorContent(content) {
287   var div = $("dateSelectorView");
288
289   div.innerHTML = content;
290   if (currentDay.length > 0)
291     restoreCurrentDaySelection(div);
292 }
293
294 function dateSelectorCallback(http) {
295   if (http.readyState == 4
296       && http.status == 200) {
297     document.dateSelectorAjaxRequest = null;
298     var content = http.responseText;
299     setDateSelectorContent(content);
300     cachedDateSelectors[http.callbackData] = content;
301   }
302   else
303     log ("ajax fuckage");
304 }
305
306 function appointmentsListCallback(http) {
307   var div = $("appointmentsListView");
308
309   if (http.readyState == 4
310       && http.status == 200) {
311     document.appointmentsListAjaxRequest = null;
312     div.innerHTML = http.responseText;
313     var params = parseQueryParameters(http.callbackData);
314     sortKey = params["sort"];
315     sortOrder = params["desc"];
316     var list = $("appointmentsList");
317     Event.observe(list, "selectionchange", onAppointmentsSelectionChange.bindAsEventListener(list), true);
318     configureSortableTableHeaders();
319   }
320   else
321     log ("ajax fuckage");
322 }
323
324 function tasksListCallback(http) {
325   var div = $("tasksListView");
326
327   if (http.readyState == 4
328       && http.status == 200) {
329     document.tasksListAjaxRequest = null;
330     var list = $("tasksList");
331     var scroll = list.scrollTop;
332     div.innerHTML = http.responseText;
333     list = $("tasksList");
334     Event.observe(list, "selectionchange", onTasksSelectionChange.bindAsEventListener(list), true);
335     list.scrollTop = scroll;
336     if (http.callbackData) {
337       var selectedNodesId = http.callbackData;
338       for (var i = 0; i < selectedNodesId.length; i++)
339         $(selectedNodesId[i]).select();
340     }
341   }
342   else
343     log ("ajax fuckage");
344 }
345
346 function restoreCurrentDaySelection(div) {
347   var elements = div.getElementsByTagName("a");
348   var day = null;
349   var i = 9;
350   while (!day && i < elements.length)
351     {
352       day = elements[i].getAttribute("day");
353       i++;
354     }
355
356   if (day
357       && day.substr(0, 6) == currentDay.substr(0, 6)) {
358       for (i = 0; i < elements.length; i++) {
359         day = elements[i].getAttribute("day");
360         if (day && day == currentDay) {
361           var td = elements[i].getParentWithTagName("td");
362           if (document.selectedDate)
363             document.selectedDate.deselect();
364           td.select();
365           document.selectedDate = td;
366         }
367       }
368     }
369 }
370
371 function changeDateSelectorDisplay(day, keepCurrentDay) {
372   var url = ApplicationBaseURL + "dateselector";
373   if (day)
374     url += "?day=" + day;
375
376   if (day != currentDay) {
377     if (!keepCurrentDay)
378       currentDay = day;
379
380     var month = day.substr(0, 6);
381     if (cachedDateSelectors[month]) {
382 //       log ("restoring cached selector for month: " + month);
383       setDateSelectorContent(cachedDateSelectors[month]);
384     }
385     else {
386 //       log ("loading selector for month: " + month);
387       if (document.dateSelectorAjaxRequest) {
388         document.dateSelectorAjaxRequest.aborted = true;
389         document.dateSelectorAjaxRequest.abort();
390       }
391       document.dateSelectorAjaxRequest
392         = triggerAjaxRequest(url,
393                              dateSelectorCallback,
394                              month);
395     }
396   }
397 }
398
399 function changeCalendarDisplay(time, newView) {
400   var url = ApplicationBaseURL + ((newView) ? newView : currentView);
401
402   selectedCalendarCell = null;
403
404   var day = null;
405   var hour = null;
406   if (time) {
407     day = time['day'];
408     hour = time['hour'];
409   }
410
411   if (!day)
412     day = currentDay;
413   if (day)
414     url += "?day=" + day;
415
416 //   if (newView)
417 //     log ("switching to view: " + newView);
418 //   log ("changeCalendarDisplay: " + url);
419
420   if (document.dayDisplayAjaxRequest) {
421 //     log ("aborting day ajaxrq");
422     document.dayDisplayAjaxRequest.aborted = true;
423     document.dayDisplayAjaxRequest.abort();
424   }
425   document.dayDisplayAjaxRequest = triggerAjaxRequest(url,
426                                                       calendarDisplayCallback,
427                                                       { "view": newView,
428                                                         "day": day,
429                                                         "hour": hour });
430
431   return false;
432 }
433
434 function _ensureView(view) {
435   if (currentView != view)
436     changeCalendarDisplay(null, view);
437
438   return false;
439 }
440
441 function onDayOverview() {
442   return _ensureView("dayview");
443 }
444
445 function onMulticolumnDayOverview() {
446   return _ensureView("multicolumndayview");
447 }
448
449 function onWeekOverview() {
450   return _ensureView("weekview");
451 }
452
453 function onMonthOverview() {
454   return _ensureView("monthview");
455 }
456
457 function scrollDayView(hour) {
458   var rowNumber;
459   if (hour) {
460     if (hour.length == 3)
461       rowNumber = parseInt(hour.substr(0, 1));
462     else {
463       if (hour.substr(0, 1) == "0")
464         rowNumber = parseInt(hour.substr(1, 1));
465       else
466         rowNumber = parseInt(hour.substr(0, 2));
467     }
468   } else
469     rowNumber = 8;
470
471   var daysView = $("daysView");
472   var hours = $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div");
473   if (hours.length > 0)
474     daysView.parentNode.scrollTop = hours[rowNumber + 1].offsetTop;
475 }
476
477 function onClickableCellsDblClick(event) {
478   newEvent(this, 'event');
479
480   event.cancelBubble = true;
481   event.returnValue = false;
482 }
483
484 function calendarDisplayCallback(http) {
485   var div = $("calendarView");
486
487   //log ("calendarDisplayCallback: " + div);
488   if (http.readyState == 4
489       && http.status == 200) {
490     document.dayDisplayAjaxRequest = null;
491     div.innerHTML = http.responseText;
492     if (http.callbackData["view"])
493       currentView = http.callbackData["view"];
494     if (http.callbackData["day"])
495       currentDay = http.callbackData["day"];
496     var hour = null;
497     if (http.callbackData["hour"])
498       hour = http.callbackData["hour"];
499     var contentView;
500     if (currentView == "monthview")
501       contentView = $("calendarContent");
502     else {
503       scrollDayView(hour);
504       contentView = $("daysView");
505     }
506     var appointments = document.getElementsByClassName("appointment", contentView);
507     for (var i = 0; i < appointments.length; i++) {
508       Event.observe(appointments[i], "mousedown",  listRowMouseDownHandler);
509       Event.observe(appointments[i], "click",  onCalendarSelectAppointment.bindAsEventListener(appointments[i]));
510       Event.observe(appointments[i], "dblclick", displayAppointment.bindAsEventListener(appointments[i]));
511     }
512     var days = document.getElementsByClassName("day", contentView);
513     if (currentView == "monthview")
514       for (var i = 0; i < days.length; i++) {
515         Event.observe(days[i], "click",  onCalendarSelectDay.bindAsEventListener(days[i]));
516         Event.observe(days[i], "dblclick",  onClickableCellsDblClick.bindAsEventListener(days[i]));
517       }
518     else
519       for (var i = 0; i < days.length; i++) {
520         Event.observe(days[i], "click",  onCalendarSelectDay.bindAsEventListener(days[i]));
521         var clickableCells = document.getElementsByClassName("clickableHourCell",
522                                                              days[i]);
523         for (var j = 0; j < clickableCells.length; j++)
524           Event.observe(clickableCells[j], "dblclick", onClickableCellsDblClick.bindAsEventListener(clickableCells[j]));
525       }
526 //     log("cbtest1");
527   }
528   else
529     log ("ajax fuckage");
530 }
531
532 function assignCalendar(name) {
533    if (typeof(skycalendar) != "undefined") {
534       var node = $(name);
535       
536       node.calendar = new skycalendar(node);
537       node.calendar.setCalendarPage(ResourcesURL + "/skycalendar.html");
538       var dateFormat = node.getAttribute("dateFormat");
539       if (dateFormat)
540          node.calendar.setDateFormat(dateFormat);
541    }
542 }
543
544 function popupCalendar(node) {
545    var nodeId = node.getAttribute("inputId");
546    var input = $(nodeId);
547    input.calendar.popup();
548
549    return false;
550 }
551
552 function onAppointmentContextMenu(event, element) {
553   var topNode = $("appointmentsList");
554 //   log(topNode);
555
556   var menu = $("appointmentsListMenu");
557
558   Event.observe(menu, "hideMenu",  onAppointmentContextMenuHide);
559   popupMenu(event, "appointmentsListMenu", element);
560
561   var topNode = $("appointmentsList");
562   var selectedNodes = topNode.getSelectedRows();
563   topNode.menuSelectedRows = selectedNodes;
564   for (var i = 0; i < selectedNodes.length; i++)
565     selectedNodes[i].deselect();
566
567   topNode.menuSelectedEntry = element;
568   element.select();
569 }
570
571 function onAppointmentContextMenuHide(event) {
572   var topNode = $("appointmentsList");
573
574   if (topNode.menuSelectedEntry) {
575     topNode.menuSelectedEntry.deselect();
576     topNode.menuSelectedEntry = null;
577   }
578   if (topNode.menuSelectedRows) {
579     var nodeIds = topNode.menuSelectedRows;
580     for (var i = 0; i < nodeIds.length; i++) {
581       var node = $(nodeIds[i]);
582       node.select();
583     }
584     topNode.menuSelectedRows = null;
585   }
586 }
587
588 function onAppointmentsSelectionChange() {
589   listOfSelection = this;
590   this.removeClassName("_unfocused");
591   $("tasksList").addClassName("_unfocused");
592 }
593
594 function onTasksSelectionChange() {
595   listOfSelection = this;
596   this.removeClassName("_unfocused");
597   $("appointmentsList").addClassName("_unfocused");
598 }
599
600 function _loadAppointmentHref(href) {
601   if (document.appointmentsListAjaxRequest) {
602     document.appointmentsListAjaxRequest.aborted = true;
603     document.appointmentsListAjaxRequest.abort();
604   }
605   var url = ApplicationBaseURL + href;
606   document.appointmentsListAjaxRequest
607     = triggerAjaxRequest(url, appointmentsListCallback, href);
608
609   return false;
610 }
611
612 function _loadTasksHref(href) {
613   if (document.tasksListAjaxRequest) {
614     document.tasksListAjaxRequest.aborted = true;
615     document.tasksListAjaxRequest.abort();
616   }
617   url = ApplicationBaseURL + href;
618
619   var selectedIds = $("tasksList").getSelectedNodesId();
620   document.tasksListAjaxRequest
621     = triggerAjaxRequest(url, tasksListCallback, selectedIds);
622
623   return false;
624 }
625
626 function onHeaderClick(event) {
627 //   log("onHeaderClick: " + this.link);
628   _loadAppointmentHref(this.link);
629
630   preventDefault(event);
631 }
632
633 function refreshAppointments() {
634   return _loadAppointmentHref("aptlist?desc=" + sortOrder
635                               + "&sort=" + sortKey
636                               + "&day=" + currentDay
637                               + "&filterpopup=" + listFilter);
638 }
639
640 function refreshTasks() {
641   return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
642 }
643
644 function refreshAppointmentsAndDisplay() {
645   refreshAppointments();
646   changeCalendarDisplay();
647 }
648
649 function onListFilterChange() {
650   var node = $("filterpopup");
651
652   listFilter = node.value;
653 //   log ("listFilter = " + listFilter);
654
655   return refreshAppointments();
656 }
657
658 function onAppointmentClick(event) {
659   var target = getTarget(event);
660   var node = target.getParentWithTagName("tr");
661   var day = node.getAttribute("day");
662   var hour = node.getAttribute("hour");
663
664   changeCalendarDisplay( { "day": day, "hour": hour} );
665   changeDateSelectorDisplay(day);
666
667   return onRowClick(event);
668 }
669
670 function selectMonthInMenu(menu, month) {
671   var entries = menu.childNodes[1].childNodesWithTag("LI");
672   for (i = 0; i < entries.length; i++) {
673     var entry = entries[i];
674     var entryMonth = entry.getAttribute("month");
675     if (entryMonth == month)
676       entry.addClassName("currentMonth");
677     else
678       entry.removeClassName("currentMonth");
679   }
680 }
681
682 function selectYearInMenu(menu, month) {
683   var entries = menu.childNodes[1].childNodes;
684   for (i = 0; i < entries.length; i++) {
685     var entry = entries[i];
686     if (entry instanceof HTMLLIElement) {
687       var entryMonth = entry.innerHTML;
688       if (entryMonth == month)
689         entry.addClassName("currentMonth");
690       else
691         entry.removeClassName("currentMonth");
692     }
693   }
694 }
695
696 function popupMonthMenu(event, menuId) {
697   var node = event.target;
698
699   if (event.button == 0) {
700     event.cancelBubble = true;
701     event.returnValue = false;
702
703     if (document.currentPopupMenu)
704       hideMenu(event, document.currentPopupMenu);
705
706     var popup = $(menuId);
707     var id = node.getAttribute("id");
708     if (id == "monthLabel")
709       selectMonthInMenu(popup, node.getAttribute("month"));
710     else
711       selectYearInMenu(popup, node.innerHTML);
712
713     var diff = (popup.offsetWidth - node.offsetWidth) /2;
714
715     popup.style.top = (node.offsetTop + 95) + "px";
716     popup.style.left = (node.offsetLeft - diff) + "px";
717     popup.style.visibility = "visible";
718
719     bodyOnClick = "" + document.body.getAttribute("onclick");
720     document.body.setAttribute("onclick", "onBodyClick('" + menuId + "');");
721     document.currentPopupMenu = popup;
722   }
723 }
724
725 function onMonthMenuItemClick(event) {
726   var month = '' + this.getAttribute("month");
727   var year = '' + $("yearLabel").innerHTML;
728
729   changeDateSelectorDisplay(year + month + "01", true);
730
731 //   event.cancelBubble();
732 }
733
734 function onYearMenuItemClick(event) {
735   var month = '' + $("monthLabel").getAttribute("month");;
736   var year = '' + this.innerHTML;
737
738   changeDateSelectorDisplay(year + month + "01", true);
739 }
740
741 function onSearchFormSubmit() {
742   log ("search not implemented");
743
744   return false;
745 }
746
747 function onCalendarSelectAppointment() {
748   var list = $("appointmentsList");
749   list.deselectAll();
750
751   var aptCName = this.getAttribute("aptCName");
752   if (selectedCalendarCell)
753     selectedCalendarCell.deselect();
754   this.select();
755   selectedCalendarCell = this;
756   var row = $(aptCName);
757   if (row) {
758     var div = row.parentNode.parentNode.parentNode;
759     div.scrollTop = row.offsetTop - (div.offsetHeight / 2);
760     row.select();
761   }
762 }
763
764 function onCalendarSelectDay(event) {
765   var day;
766   if (currentView == "multicolumndayview")
767      day = this.parentNode.getAttribute("day");
768   else
769      day = this.getAttribute("day");
770   var needRefresh = (listFilter == 'view_selectedday'
771                      && day != currentDay);
772
773   if (currentView == 'weekview')
774     changeWeekCalendarDisplayOfSelectedDay(this);
775   else if (currentView == 'monthview')
776     changeMonthCalendarDisplayOfSelectedDay(this);
777   changeDateSelectorDisplay(day);
778
779   if (listOfSelection) {
780     listOfSelection.addClassName("_unfocused");
781     listOfSelection = null;
782   }
783
784   if (needRefresh)
785     refreshAppointments();
786 }
787
788 function changeWeekCalendarDisplayOfSelectedDay(node) {
789   var days = document.getElementsByClassName("day", node.parentNode);
790
791   for (var i = 0; i < days.length; i++)
792     if (days[i] != node)
793       days[i].removeClassName("selectedDay");
794
795   node.addClassName("selectedDay");
796 }
797
798 function findMonthCalendarSelectedCell(daysContainer) {
799    var found = false;
800    var i = 0;
801
802    while (!found && i < daysContainer.childNodes.length) {
803       var currentNode = daysContainer.childNodes[i];
804       if (currentNode instanceof HTMLDivElement
805           && currentNode.hasClassName("selectedDay")) {
806          daysContainer.selectedCell = currentNode;
807          found = true;
808       }
809       else
810          i++;
811    }
812 }
813
814 function changeMonthCalendarDisplayOfSelectedDay(node) {
815    var daysContainer = node.parentNode;
816    if (!daysContainer.selectedCell)
817       findMonthCalendarSelectedCell(daysContainer);
818    
819    if (daysContainer.selectedCell)
820       daysContainer.selectedCell.removeClassName("selectedDay");
821    daysContainer.selectedCell = node;
822    node.addClassName("selectedDay");
823 }
824
825 function onShowCompletedTasks(node) {
826   showCompletedTasks = (node.checked ? 1 : 0);
827
828   return refreshTasks();
829 }
830
831 function updateTaskStatus(node) {
832   var taskId = node.parentNode.getAttribute("id");
833   var taskOwner = node.parentNode.getAttribute("owner");
834   var newStatus = (node.checked ? 1 : 0);
835 //   log ("update task status: " + taskId);
836
837   var http = createHTTPClient();
838
839   url = (UserFolderURL + "../" + taskOwner + "/Calendar/"
840          + taskId + "/changeStatus?status=" + newStatus);
841
842   if (http) {
843 //     log ("url: " + url);
844     // TODO: add parameter to signal that we are only interested in OK
845     http.url = url;
846     http.open("GET", url, false /* not async */);
847     http.send("");
848     if (http.status == 200)
849       refreshTasks();
850   } else
851     log ("no http client?");
852
853   return false;
854 }
855
856 function updateCalendarStatus(event) {
857   var list = new Array();
858
859   var nodes = $("calendarList").childNodesWithTag("li");
860   for (var i = 0; i < nodes.length; i++) {
861     var input = $(nodes[i]).childNodesWithTag("input")[0];
862     if (input.checked) {
863        var folderId = nodes[i].getAttribute("id");
864        var elems = folderId.split(":");
865        if (elems.length > 1)
866           list.push(elems[0]);
867        else
868           list.push(UserLogin);
869     }
870   }
871
872   if (!list.length) {
873      list.push(UserLogin);
874      nodes[0].childNodesWithTag("input")[0].checked = true;
875   }
876 //   ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
877 //                      + list.join(",") + "/Calendar/");
878
879   if (event) {
880      var folderID = this.parentNode.getAttribute("id");
881      var urlstr = URLForFolderID(folderID);
882      if (this.checked)
883         urlstr += "/activateFolder";
884      else
885         urlstr += "/deactivateFolder";
886      triggerAjaxRequest(urlstr, calendarStatusCallback, folderID);
887   }
888   else {
889      updateCalendarsList();
890      refreshAppointments();
891      refreshTasks();
892      changeCalendarDisplay();
893   }
894
895   return false;
896 }
897
898 function calendarStatusCallback(http) {
899    if (http.readyState == 4) {
900       if (http.status == 204) {
901          refreshAppointments();
902          refreshTasks();
903          changeCalendarDisplay();
904       }
905       else {
906          var folder = $(http.callbackData);
907          var input = folder.childNodesWithTag("input")[0];
908          input.checked = (!input.checked);
909       }
910    }
911 }
912
913 function calendarEntryCallback(http) {
914    var disabled = true;
915
916    if (http.readyState == 4) {
917       if (http.status == 200)
918          disabled = (http.responseText == "0");
919       var entry = $(http.callbackData);
920       var input = entry.childNodesWithTag("input")[0];
921       input.disabled = disabled;
922       if (disabled) {
923          input.checked = false;
924          $(entry).addClassName("denied");
925       }
926       else
927          $(entry).removeClassName("denied");
928    }
929 }
930
931 function updateCalendarsList(method) {
932   var list = $("calendarList").childNodesWithTag("li");
933   for (var i = 0; i < list.length; i++) {
934      var folderID = list[i].getAttribute("id");
935      var url = URLForFolderID(folderID) + "/canAccessContent";
936      triggerAjaxRequest(url, calendarEntryCallback, folderID);
937   }
938 }
939
940 function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
941   var uids = $("uixselector-calendarsList-uidList");
942 //   log("addContact");
943   if (contactId)
944     {
945       var re = new RegExp("(^|,)" + contactId + "($|,)");
946
947       if (!re.test(uids.value))
948         {
949           if (uids.value.length > 0)
950             uids.value += ',' + contactId;
951           else
952             uids.value = contactId;
953           var names = $("calendarList");
954           var listElems = names.childNodesWithTag("li");
955           var colorDef = indexColor(listElems.length);
956           names.appendChild(userCalendarEntry(contactId, colorDef));
957
958         }
959     }
960
961   return false;
962 }
963
964 function validateBrowseURL(input) {
965   var button = $("browseURLBtn");
966
967   if (input.value.length) {
968     if (!button.enabled)
969       enableAnchor(button);
970   } else if (!button.disabled)
971     disableAnchor(button);
972 }
973
974 function browseURL(anchor, event) {
975   if (event.button == 0) {
976     var input = $("url");
977     var url = input.value;
978     if (url.length)
979       window.open(url, '_blank');
980   }
981
982   return false;
983 }
984
985 function getMenus() {
986    var menus = {};
987
988    var dateMenu = new Array();
989    for (var i = 0; i < 12; i++)
990       dateMenu.push(onMonthMenuItemClick);
991    menus["monthListMenu"] = dateMenu;
992
993    dateMenu = new Array();
994    for (var i = 0; i < 11; i++)
995       dateMenu.push(onYearMenuItemClick);
996    menus["yearListMenu"] = dateMenu;
997
998    menus["appointmentsListMenu"] = new Array(onMenuNewEventClick, "-",
999                                              onMenuNewTaskClick,
1000                                              editEvent, deleteEvent, "-",
1001                                              onSelectAll, "-",
1002                                              null, null);
1003    menus["calendarsMenu"] = new Array(null, null, "-", null, null, "-",
1004                                       null, "-", onMenuSharing);
1005    menus["searchMenu"] = new Array(setSearchCriteria);
1006
1007    return menus;
1008 }
1009
1010 function onMenuSharing(event) {
1011   var folders = $("calendarList");
1012   var selected = folders.getSelectedNodes()[0];
1013   /* FIXME: activation of the context menu should preferable select the entry
1014                above which the event has occured */
1015   if (selected) {
1016      var folderID = selected.getAttribute("id");
1017      var urlstr = URLForFolderID(folderID) + "/acls";
1018
1019      openAclWindow(urlstr);
1020   }
1021 }
1022
1023 function configureDragHandles() {
1024   var handle = $("verticalDragHandle");
1025   if (handle) {
1026     handle.addInterface(SOGoDragHandlesInterface);
1027     handle.leftBlock=$("leftPanel");
1028     handle.rightBlock=$("rightPanel");
1029   }
1030
1031   handle = $("rightDragHandle");
1032   if (handle) {
1033     handle.addInterface(SOGoDragHandlesInterface);
1034     handle.upperBlock=$("appointmentsListView");
1035     handle.lowerBlock=$("calendarView");
1036   }
1037 }
1038
1039 function initCalendarSelector() {
1040   var selector = $("calendarSelector");
1041   updateCalendarStatus();
1042   selector.changeNotification = updateCalendarsList;
1043
1044   var list = $("calendarList").childNodesWithTag("li");
1045   for (var i = 0; i < list.length; i++) {
1046     var input = list[i].childNodesWithTag("input")[0];
1047     Event.observe(input, "change", updateCalendarStatus.bindAsEventListener(input));
1048     Event.observe(list[i], "mousedown", listRowMouseDownHandler);
1049     Event.observe(list[i], "click", onRowClick);
1050   }
1051
1052   var links = $("calendarSelectorButtons").childNodesWithTag("a");
1053   Event.observe(links[0], "click",  onCalendarAdd);
1054   Event.observe(links[1], "click",  onCalendarRemove);
1055 }
1056
1057 function onCalendarAdd(event) {
1058    openUserFolderSelector(onFolderSubscribeCB, "calendar");
1059
1060    preventDefault(event);
1061 }
1062
1063 function appendCalendar(folderName, folder) {
1064    var calendarList = $("calendarList");
1065    var lis = calendarList.childNodesWithTag("li");
1066    var color = indexColor(lis.length);
1067    log ("color: " + color);
1068    var li = document.createElement("li");
1069    li.setAttribute("id", folder);
1070    Event.observe(li, "mousedown",  listRowMouseDownHandler);
1071    Event.observe(li, "click",  onRowClick);
1072    var checkBox = document.createElement("input");
1073    checkBox.addClassName("checkBox");
1074    checkBox.type = "checkbox";
1075    Event.observe(checkBox, "change",  updateCalendarStatus);
1076    li.appendChild(checkBox);
1077    li.appendChild(document.createTextNode(" "));
1078    var colorBox = document.createElement("div");
1079    colorBox.appendChild(document.createTextNode("OO"));
1080    colorBox.addClassName("colorBox");
1081    if (color) {
1082      colorBox.setStyle({ color: color,
1083                          backgroundColor: color });
1084    }
1085    li.appendChild(colorBox);
1086    li.appendChild(document.createTextNode(" " + folderName));
1087
1088    calendarList.appendChild(li);
1089
1090    var contactId = folder.split(":")[0];
1091    var styles = document.getElementsByTagName("style");
1092
1093    var url = URLForFolderID(folder) + "/canAccessContent";
1094    triggerAjaxRequest(url, calendarEntryCallback, folder);
1095
1096    styles[0].innerHTML += ('.ownerIs' + contactId + ' {'
1097                            + ' background-color: '
1098                            + color
1099                            + ' !important; }');
1100 }
1101
1102 function onFolderSubscribeCB(folderData) {
1103    var folder = $(folderData["folder"]);
1104    if (!folder)
1105       appendCalendar(folderData["folderName"], folderData["folder"]);
1106 }
1107
1108 function onFolderUnsubscribeCB(folderId) {
1109    var node = $(folderId);
1110    node.parentNode.removeChild(node);
1111 }
1112
1113 function onCalendarRemove(event) {
1114   var nodes = $("calendarList").getSelectedNodes();
1115   if (nodes.length > 0) { 
1116      nodes[0].deselect();
1117      var folderId = nodes[0].getAttribute("id");
1118      var folderIdElements = folderId.split(":");
1119      if (folderIdElements.length > 1) {
1120         unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
1121      }
1122   }
1123
1124   preventDefault(event);
1125 }
1126
1127 function configureSearchField() {
1128    var searchValue = $("searchValue");
1129
1130    Event.observe(searchValue, "mousedown",  onSearchMouseDown.bindAsEventListener(searchValue));
1131    Event.observe(searchValue, "click",  popupSearchMenu.bindAsEventListener(searchValue));
1132    Event.observe(searchValue, "blur",  onSearchBlur.bindAsEventListener(searchValue));
1133    Event.observe(searchValue, "focus",  onSearchFocus.bindAsEventListener(searchValue));
1134    Event.observe(searchValue, "keydown",  onSearchKeyDown.bindAsEventListener(searchValue));
1135 }
1136
1137 function initCalendars() {
1138    if (!document.body.hasClassName("popup")) {
1139       initCalendarSelector();
1140       configureSearchField();
1141       var selector = $("calendarSelector");
1142       if (selector)
1143          selector.attachMenu("calendarsMenu");
1144    }
1145 }
1146
1147 addEvent(window, 'load', initCalendars);