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