]> err.no Git - scalable-opengroupware.org/blob - UI/WebServerResources/SchedulerUI.js
361c0708dd8a4a8d6d0e2927f50180a342344ee2
[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 = "weekview";
14
15 var cachedDateSelectors = new Array();
16
17 var contactSelectorAction = 'calendars-contacts';
18
19 var eventsToDelete = new Array();
20 var calendarsOfEventsToDelete = new Array();
21
22 var usersRightsWindowHeight = 250;
23 var usersRightsWindowWidth = 502;
24
25 function newEvent(sender, type) {
26    var day = sender.day;
27    if (!day)
28       day = currentDay;
29
30    var hour = sender.hour;
31    if (!hour)
32       hour = sender.getAttribute("hour");
33    var folderID = getSelectedFolder();
34    var urlstr = ApplicationBaseURL + folderID + "/new" + type;
35    var params = new Array();
36    if (day)
37       params.push("day=" + day);
38    if (hour)
39       params.push("hm=" + hour);
40    if (params.length > 0)
41       urlstr += "?" + params.join("&");
42    
43    window.open(urlstr, "", "width=490,height=470,resizable=0");
44    
45    return false; /* stop following the link */
46 }
47
48 function getSelectedFolder() {
49   var folder;
50
51   var nodes = $("calendarList").getSelectedRows();
52   if (nodes.length > 0)
53     folder = nodes[0].getAttribute("id");
54   else
55     folder = "/personal";
56
57   return folder;
58 }
59
60 function onMenuNewEventClick(event) {
61    newEvent(this, "event");
62 }
63
64 function onMenuNewTaskClick(event) {
65    newEvent(this, "task");
66 }
67
68 function _editEventId(id, calendar) {
69   var urlstr = ApplicationBaseURL + "/" + calendar + "/" + id + "/edit";
70   var targetname = "SOGo_edit_" + id;
71   var win = window.open(urlstr, "_blank",
72                         "width=490,height=470,resizable=0");
73   win.focus();
74 }
75
76 function editEvent() {
77   if (listOfSelection) {
78     var nodes = listOfSelection.getSelectedRows();
79
80     for (var i = 0; i < nodes.length; i++)
81       _editEventId(nodes[i].getAttribute("id"),
82                    nodes[i].calendar);
83   } else if (selectedCalendarCell) {
84       _editEventId(selectedCalendarCell[0].cname,
85                    selectedCalendarCell[0].calendar);
86   }
87
88   return false; /* stop following the link */
89 }
90
91 function _batchDeleteEvents() {
92   var events = eventsToDelete.shift();
93   var calendar = calendarsOfEventsToDelete.shift();
94   var urlstr = (ApplicationBaseURL + "/" + calendar
95                 + "/batchDelete?ids=" + events.join('/'));
96   document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
97                                                        deleteEventCallback,
98                                                        events);
99 }
100
101 function deleteEvent() {
102   if (listOfSelection) {
103     var nodes = listOfSelection.getSelectedRows();
104
105     if (nodes.length > 0) {
106       var label = "";
107       if (listOfSelection == $("tasksList"))
108         label = labels["taskDeleteConfirmation"];
109       else
110         label = labels["eventDeleteConfirmation"];
111       
112       if (confirm(label)) {
113         if (document.deleteEventAjaxRequest) {
114           document.deleteEventAjaxRequest.aborted = true;
115           document.deleteEventAjaxRequest.abort();
116         }
117         var sortedNodes = new Array();
118         var calendars = new Array();
119
120         for (var i = 0; i < nodes.length; i++) {
121           var calendar = nodes[i].calendar;
122           if (!sortedNodes[calendar]) {
123             sortedNodes[calendar] = new Array();
124             calendars.push(calendar);
125           }
126           sortedNodes[calendar].push(nodes[i].cname);
127         }
128         for (var i = 0; i < calendars.length; i++) {
129           calendarsOfEventsToDelete.push(calendars[i]);
130           eventsToDelete.push(sortedNodes[calendars[i]]);
131         }
132         _batchDeleteEvents();
133       }
134     }
135   }
136   else if (selectedCalendarCell) {
137      var label = labels["eventDeleteConfirmation"];
138      if (confirm(label)) {
139         if (document.deleteEventAjaxRequest) {
140            document.deleteEventAjaxRequest.aborted = true;
141            document.deleteEventAjaxRequest.abort();
142         }
143         eventsToDelete.push([selectedCalendarCell[0].cname]);
144         calendarsOfEventsToDelete.push(selectedCalendarCell[0].calendar);
145         _batchDeleteEvents();
146      }
147   }
148   else
149     window.alert("no selection");
150
151   return false;
152 }
153
154 function modifyEvent(sender, modification) {
155   var currentLocation = '' + window.location;
156   var arr = currentLocation.split("/");
157   arr[arr.length-1] = modification;
158
159   document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
160                                                        modifyEventCallback,
161                                                        modification);
162
163   return false;
164 }
165
166 function closeInvitationWindow() {
167   var closeDiv = document.createElement("div");
168   document.body.appendChild(closeDiv);
169   closeDiv.addClassName("javascriptPopupBackground");
170
171   var closePseudoWin = document.createElement("div");
172   document.body.appendChild(closePseudoWin);
173   closePseudoWin.addClassName("javascriptMessagePseudoTopWindow");
174   closePseudoWin.style.top = "0px;";
175   closePseudoWin.style.left = "0px;";
176   closePseudoWin.style.right = "0px;";
177   closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
178
179   var calLink = document.createElement("a");
180   closePseudoWin.appendChild(calLink);
181   calLink.href = ApplicationBaseURL;
182   calLink.appendChild(document.createTextNode(labels["Calendar"].toLowerCase()));
183 }
184
185 function modifyEventCallback(http) {
186   if (http.readyState == 4) {
187     if (http.status == 200) {
188       var mailInvitation = queryParameters["mail-invitation"];
189       if (mailInvitation && mailInvitation.toLowerCase() == "yes")
190         closeInvitationWindow();
191       else {
192         window.opener.setTimeout("refreshEventsAndDisplay();", 100);
193         window.setTimeout("window.close();", 100);
194       }
195     }
196     else {
197 //       log("showing alert...");
198       window.alert(labels["eventPartStatModificationError"]);
199     }
200     document.modifyEventAjaxRequest = null;
201   }
202 }
203
204 function deleteEventCallback(http) {
205   if (http.readyState == 4) {
206     if (isHttpStatus204(http.status)) {
207       var nodes = http.callbackData;
208       for (var i = 0; i < nodes.length; i++) {
209         var node = $(nodes[i]);
210         if (node)
211           node.parentNode.removeChild(node);
212       }
213       if (eventsToDelete.length)
214         _batchDeleteEvents();
215       else {
216         document.deleteEventAjaxRequest = null;
217         refreshEvents();
218         refreshTasks();
219         changeCalendarDisplay();
220       }
221     }
222     else
223       log ("deleteEventCallback Ajax error");
224   }
225 }
226
227 function editDoubleClickedEvent(event) {
228   _editEventId(this.cname, this.calendar);
229
230   preventDefault(event);
231   event.cancelBubble = true;
232 }
233
234 function onSelectAll() {
235   var list = $("eventsList");
236   list.selectRowsMatchingClass("eventRow");
237
238   return false;
239 }
240
241 function onDaySelect(node) {
242   var day = node.getAttribute('day');
243   var needRefresh = (listFilter == 'view_selectedday'
244                      && day != currentDay);
245
246   var td = $(node).getParentWithTagName("td");
247   var table = $(td).getParentWithTagName("table");
248
249 //   log ("table.selected: " + table.selected);
250
251   if (document.selectedDate)
252     document.selectedDate.deselect();
253
254   td.select();
255   document.selectedDate = td;
256
257   changeCalendarDisplay( { "day": day } );
258   if (needRefresh)
259     refreshEvents();
260
261   return false;
262 }
263
264 function onDateSelectorGotoMonth(event) {
265    var day = this.getAttribute("date");
266
267    changeDateSelectorDisplay(day, true);
268
269    Event.stop(event);
270 }
271
272 function onCalendarGotoDay(node) {
273    var day = node.getAttribute("date");
274    
275    changeDateSelectorDisplay(day);
276    changeCalendarDisplay( { "day": day } );
277   
278    return false;
279 }
280
281 function gotoToday() {
282   changeDateSelectorDisplay('');
283   changeCalendarDisplay();
284
285   return false;
286 }
287
288 function setDateSelectorContent(content) {
289   var div = $("dateSelectorView");
290
291   div.innerHTML = content;
292   if (currentDay.length > 0)
293     restoreCurrentDaySelection(div);
294
295   initDateSelectorEvents();
296 }
297
298 function dateSelectorCallback(http) {
299   if (http.readyState == 4
300       && http.status == 200) {
301      document.dateSelectorAjaxRequest = null;
302      var content = http.responseText;
303      setDateSelectorContent(content);
304      cachedDateSelectors[http.callbackData] = content;
305   }
306   else
307     log ("dateSelectorCallback Ajax error");
308 }
309
310 function eventsListCallback(http) {
311   if (http.readyState == 4
312       && http.status == 200) {
313      var div = $("eventsListView");
314
315     document.eventsListAjaxRequest = null;
316     var table = $("eventsList");
317     var params = parseQueryParameters(http.callbackData);
318     sortKey = params["sort"];
319     sortOrder = params["desc"];
320     lastClickedRow = -1; // from generic.js
321
322     if (http.responseText.length > 0) {
323       var data = http.responseText.evalJSON(true);
324       for (var i = 0; i < data.length; i++) {
325         var row = document.createElement("tr");
326         table.tBodies[0].appendChild(row);
327         $(row).addClassName("eventRow");
328         row.setAttribute("id", escape(data[i][0]));
329         row.cname = escape(data[i][0]);
330         row.calendar = data[i][1];
331
332         var startDate = new Date();
333         startDate.setTime(data[i][4] * 1000);
334         row.day = startDate.getDayString();
335         row.hour = startDate.getHourString();
336         Event.observe(row, "click",
337                       onEventClick.bindAsEventListener(row));
338         Event.observe(row, "dblclick",
339                       editDoubleClickedEvent.bindAsEventListener(row));
340         Event.observe(row, "contextmenu",
341                       onEventContextMenu.bindAsEventListener(row));
342       
343         var td = document.createElement("td");
344         row.appendChild(td);
345         Event.observe(td, "mousedown", listRowMouseDownHandler, true);
346         td.appendChild(document.createTextNode(data[i][3]));
347
348         td = document.createElement("td");
349         row.appendChild(td);
350         Event.observe(td, "mousedown", listRowMouseDownHandler, true);
351         td.appendChild(document.createTextNode(data[i][8]));
352
353         td = document.createElement("td");
354         row.appendChild(td);
355         Event.observe(td, "mousedown", listRowMouseDownHandler, true);
356         td.appendChild(document.createTextNode(data[i][9]));
357       
358         td = document.createElement("td");
359         row.appendChild(td);
360         Event.observe(td, "mousedown", listRowMouseDownHandler, true);
361         td.appendChild(document.createTextNode(data[i][6]));
362       }
363     }
364   }
365   else
366     log ("eventsListCallback Ajax error");
367 }
368
369 function tasksListCallback(http) {
370   var div = $("tasksListView");
371
372   if (http.readyState == 4
373       && http.status == 200) {
374     document.tasksListAjaxRequest = null;
375     var list = $("tasksList");
376  
377     if (http.responseText.length > 0) {
378       var data = http.responseText.evalJSON(true);
379
380       for (var i = 0; i < data.length; i++) {
381         //log(i + " = " + data[i][3]);
382         var listItem = document.createElement("li");
383         list.appendChild(listItem);
384         Event.observe(listItem, "mousedown", listRowMouseDownHandler);
385         Event.observe(listItem, "click", onRowClick);
386         Event.observe(listItem, "dblclick", editDoubleClickedEvent.bindAsEventListener(listItem));
387         listItem.setAttribute("id", data[i][0]);
388         $(listItem).addClassName(data[i][5]);
389         listItem.calendar = data[i][1];
390         $(listItem).addClassName("calendarFolder" + data[i][1]);
391         listItem.cname = escape(data[i][0]);
392         var input = document.createElement("input");
393         input.setAttribute("type", "checkbox");
394         listItem.appendChild(input);
395         Event.observe(input, "click", updateTaskStatus.bindAsEventListener(input), true);
396         input.setAttribute("value", "1");
397         if (data[i][2] == 1)
398           input.setAttribute("checked", "checked");
399         $(input).addClassName("checkBox");
400         listItem.appendChild(document.createTextNode(data[i][3]));
401       }
402
403       list.scrollTop = list.previousScroll;
404
405       if (http.callbackData) {
406         var selectedNodesId = http.callbackData;
407         for (var i = 0; i < selectedNodesId.length; i++) {
408           //    log(selectedNodesId[i] + " (" + i + ") is selected");
409           $(selectedNodesId[i]).select();
410         }
411       }
412       else
413         log ("tasksListCallback: no data");
414     }
415   }
416   else
417     log ("tasksListCallback Ajax error");
418 }
419
420 function restoreCurrentDaySelection(div) {
421   var elements = $(div).getElementsByTagName("a");
422   var day = null;
423   var i = 9;
424   while (!day && i < elements.length)
425     {
426       day = elements[i].day;
427       i++;
428     }
429
430   if (day
431       && day.substr(0, 6) == currentDay.substr(0, 6)) {
432       for (i = 0; i < elements.length; i++) {
433         day = elements[i].day;
434         if (day && day == currentDay) {
435           var td = $(elements[i]).getParentWithTagName("td");
436           if (document.selectedDate)
437             document.selectedDate.deselect();
438           $(td).select();
439           document.selectedDate = td;
440         }
441       }
442     }
443 }
444
445 function changeDateSelectorDisplay(day, keepCurrentDay) {
446   var url = ApplicationBaseURL + "/dateselector";
447   if (day)
448     url += "?day=" + day;
449
450   if (day != currentDay) {
451     if (!keepCurrentDay)
452       currentDay = day;
453
454     var month = day.substr(0, 6);
455     if (cachedDateSelectors[month]) {
456 //       log ("restoring cached selector for month: " + month);
457       setDateSelectorContent(cachedDateSelectors[month]);
458     }
459     else {
460 //       log ("loading selector for month: " + month);
461       if (document.dateSelectorAjaxRequest) {
462         document.dateSelectorAjaxRequest.aborted = true;
463         document.dateSelectorAjaxRequest.abort();
464       }
465       document.dateSelectorAjaxRequest
466         = triggerAjaxRequest(url,
467                              dateSelectorCallback,
468                              month);
469     }
470   }
471 }
472
473 function changeCalendarDisplay(time, newView) {
474   var url = ApplicationBaseURL + "/" + ((newView) ? newView : currentView);
475
476   selectedCalendarCell = null;
477
478   var day = null;
479   var hour = null;
480   if (time) {
481     day = time['day'];
482     hour = time['hour'];
483   }
484
485   if (!day)
486     day = currentDay;
487   if (day)
488     url += "?day=" + day;
489
490 //   if (newView)
491 //     log ("switching to view: " + newView);
492 //   log ("changeCalendarDisplay: " + url);
493
494   if (document.dayDisplayAjaxRequest) {
495 //     log ("aborting day ajaxrq");
496     document.dayDisplayAjaxRequest.aborted = true;
497     document.dayDisplayAjaxRequest.abort();
498   }
499   document.dayDisplayAjaxRequest
500      = triggerAjaxRequest(url, calendarDisplayCallback,
501                           { "view": newView, "day": day, "hour": hour });
502
503   return false;
504 }
505
506 function _ensureView(view) {
507   if (currentView != view)
508     changeCalendarDisplay(null, view);
509
510   return false;
511 }
512
513 function onDayOverview() {
514   return _ensureView("dayview");
515 }
516
517 function onMulticolumnDayOverview() {
518   return _ensureView("multicolumndayview");
519 }
520
521 function onWeekOverview() {
522   return _ensureView("weekview");
523 }
524
525 function onMonthOverview() {
526   return _ensureView("monthview");
527 }
528
529 function scrollDayView(hour) {
530   var rowNumber;
531   if (hour) {
532     if (hour.length == 3)
533       rowNumber = parseInt(hour.substr(0, 1));
534     else {
535       if (hour.substr(0, 1) == "0")
536         rowNumber = parseInt(hour.substr(1, 1));
537       else
538         rowNumber = parseInt(hour.substr(0, 2));
539     }
540   } else
541     rowNumber = 8;
542
543   var daysView = $("daysView");
544   var hours =
545      $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div");
546   if (hours.length > 0)
547     daysView.scrollTop = hours[rowNumber].offsetTop;
548 }
549
550 function onClickableCellsDblClick(event) {
551   newEvent(this, 'event');
552
553   event.cancelBubble = true;
554   event.returnValue = false;
555 }
556
557 function refreshCalendarEvents() {
558    var todayDate = new Date();
559    var sd;
560    var ed;
561    if (currentView == "dayview") {
562       if (currentDay)
563          sd = currentDay;
564       else
565          sd = todayDate.getDayString();
566       ed = sd;
567    }
568    else if (currentView == "weekview") {
569       var startDate;
570       if (currentDay)
571          startDate = currentDay.asDate();
572       else
573          startDate = todayDate;
574       startDate = startDate.beginOfWeek();
575       sd = startDate.getDayString();
576       var endDate = new Date();
577       endDate.setTime(startDate.getTime());
578       endDate.addDays(6);
579       ed = endDate.getDayString();
580    }
581    else {
582       var monthDate;
583       if (currentDay)
584          monthDate = currentDay.asDate();
585       else
586          monthDate = todayDate;
587       monthDate.setDate(1);
588       sd = monthDate.beginOfWeek().getDayString();
589
590       var lastMonthDate = new Date();
591       lastMonthDate.setTime(monthDate.getTime());
592       lastMonthDate.setMonth(monthDate.getMonth() + 1);
593       lastMonthDate.addDays(-1);
594       ed = lastMonthDate.endOfWeek().getDayString();
595    }
596    if (document.refreshCalendarEventsAjaxRequest) {
597       document.refreshCalendarEventsAjaxRequest.aborted = true;
598       document.refreshCalendarEventsAjaxRequest.abort();
599    }
600    var url = ApplicationBaseURL + "/eventslist?sd=" + sd + "&ed=" + ed;
601    document.refreshCalendarEventsAjaxRequest
602       = triggerAjaxRequest(url, refreshCalendarEventsCallback,
603                            {"startDate": sd, "endDate": ed});
604 }
605
606 function refreshCalendarEventsCallback(http) {
607   if (http.readyState == 4
608       && http.status == 200) {
609
610     if (http.responseText.length > 0) {
611       var data = http.responseText.evalJSON(true);
612 //      log("refresh calendar events: " + data.length);
613       for (var i = 0; i < data.length; i++)
614         drawCalendarEvent(data[i],
615                           http.callbackData["startDate"],
616                           http.callbackData["endDate"]);
617     }
618   }
619   else
620      log("AJAX error when refreshing calendar events");
621 }
622
623 function drawCalendarEvent(eventData, sd, ed) {
624    var viewStartDate = sd.asDate();
625    var viewEndDate = ed.asDate();
626
627    var startDate = new Date();
628    startDate.setTime(eventData[4] * 1000);
629    var endDate = new Date();
630    endDate.setTime(eventData[5] * 1000);
631
632 //    log ("s: " + startDate + "; e: " + endDate);
633
634    var days = startDate.daysUpTo(endDate);
635
636    var divs = new Array();
637
638    var title;
639    if (currentView == "monthview"
640        && (eventData[7] == 0))
641       title = startDate.getDisplayHoursString() + " " + eventData[3];
642    else
643       title = eventData[3];
644
645 //    log("title: " + title); 
646 //    log("viewS: " + viewStartDate);
647    var startHour = null;
648    var endHour = null;
649
650    var siblings = new Array();
651    for (var i = 0; i < days.length; i++)
652       if (days[i].earlierDate(viewStartDate) == viewStartDate
653           && days[i].laterDate(viewEndDate) == viewEndDate) {
654          var starts;
655
656 //       log("day: " + days[i]);
657          if (i == 0) {
658             var quarters = (startDate.getUTCHours() * 4
659                             + Math.floor(startDate.getUTCMinutes() / 15));
660             starts = quarters;
661             startHour = startDate.getDisplayHoursString();
662             endHour = endDate.getDisplayHoursString();
663          }
664          else
665             starts = 0;
666          
667          var ends;
668          var lasts;
669          if (i == days.length - 1) {
670             var quarters = (endDate.getUTCHours() * 4
671                             + Math.ceil(endDate.getUTCMinutes() / 15));
672             ends = quarters;
673          }
674          else
675             ends = 96;
676          lasts = ends - starts;
677          if (!lasts)
678             lasts = 1;
679
680          var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
681                                     null, null, title);
682          siblings.push(eventDiv);
683          eventDiv.siblings = siblings;
684          var dayString = days[i].getDayString();
685 //       log("day: " + dayString);
686          var parentDiv = null;
687          if (currentView == "monthview") {
688             var dayDivs = $("monthDaysView").childNodesWithTag("div");
689             var j = 0; 
690             while (!parentDiv && j < dayDivs.length) {
691                if (dayDivs[j].getAttribute("day") == dayString)
692                   parentDiv = dayDivs[j];
693                else
694                   j++;
695             }
696          }
697          else {
698             if (eventData[7] == 0) {
699                var daysView = $("daysView");
700                var eventsDiv = $(daysView).childNodesWithTag("div")[1];
701                var dayDivs = $(eventsDiv).childNodesWithTag("div");
702                var j = 0; 
703                while (!parentDiv && j < dayDivs.length) {
704                   if (dayDivs[j].getAttribute("day") == dayString)
705                      parentDiv = dayDivs[j].childNodesWithTag("div")[0];
706                   else
707                      j++;
708                }
709             }
710             else {
711                var header = $("calendarHeader");
712                var daysDiv = $(header).childNodesWithTag("div")[1];
713                var dayDivs = $(daysDiv).childNodesWithTag("div");
714                var j = 0; 
715                while (!parentDiv && j < dayDivs.length) {
716                   if (dayDivs[j].getAttribute("day") == dayString)
717                      parentDiv = dayDivs[j];
718                   else
719                      j++;
720                }
721             }
722          }
723          if (parentDiv)
724             parentDiv.appendChild(eventDiv);
725       }
726 }
727
728 function newEventDIV(cname, calendar, starts, lasts,
729                      startHour, endHour, title) {
730    var eventDiv = document.createElement("div");
731    eventDiv.cname = escape(cname);
732    eventDiv.calendar = calendar;
733    $(eventDiv).addClassName("event");
734    $(eventDiv).addClassName("starts" + starts);
735    $(eventDiv).addClassName("lasts" + lasts);
736    for (var i = 1; i < 5; i++) {
737       var shadowDiv = document.createElement("div");
738       eventDiv.appendChild(shadowDiv);
739       $(shadowDiv).addClassName("shadow");
740       $(shadowDiv).addClassName("shadow" + i);
741    }
742    var innerDiv = document.createElement("div");
743    eventDiv.appendChild(innerDiv);
744    $(innerDiv).addClassName("eventInside");
745    $(innerDiv).addClassName("calendarFolder" + calendar);
746
747    var gradientDiv = document.createElement("div");
748    innerDiv.appendChild(gradientDiv);
749    $(gradientDiv).addClassName("gradient");
750    var gradientImg = document.createElement("img");
751    gradientDiv.appendChild(gradientImg);
752    gradientImg.src = ResourcesURL + "/event-gradient.png";
753
754    var textDiv = document.createElement("div");
755    innerDiv.appendChild(textDiv);
756    $(textDiv).addClassName("text");
757    if (startHour) {
758       var headerSpan = document.createElement("span");
759       textDiv.appendChild(headerSpan);
760       $(headerSpan).addClassName("eventHeader");
761       headerSpan.appendChild(document.createTextNode(startHour + " - "
762                                                      + endHour));
763       textDiv.appendChild(document.createElement("br"));
764    }
765    textDiv.appendChild(document.createTextNode(title));
766
767    Event.observe(eventDiv, "mousedown", listRowMouseDownHandler);
768    Event.observe(eventDiv, "click",
769                  onCalendarSelectEvent.bindAsEventListener(eventDiv));
770    Event.observe(eventDiv, "dblclick",
771                  editDoubleClickedEvent.bindAsEventListener(eventDiv));
772
773    return eventDiv;
774 }
775
776 function calendarDisplayCallback(http) {
777   var div = $("calendarView");
778
779   if (http.readyState == 4
780       && http.status == 200) {
781     document.dayDisplayAjaxRequest = null;
782     div.update(http.responseText);
783     if (http.callbackData["view"])
784       currentView = http.callbackData["view"];
785     if (http.callbackData["day"])
786       currentDay = http.callbackData["day"];
787
788     var hour = null;
789     if (http.callbackData["hour"])
790       hour = http.callbackData["hour"];
791     var contentView;
792     if (currentView == "monthview")
793       contentView = $("calendarContent");
794     else {
795       scrollDayView(hour);
796       contentView = $("daysView");
797     }
798     refreshCalendarEvents();
799     var days = document.getElementsByClassName("day", contentView);
800     if (currentView == "monthview")
801       for (var i = 0; i < days.length; i++) {
802         Event.observe(days[i], "click",  onCalendarSelectDay.bindAsEventListener(days[i]));
803         Event.observe(days[i], "dblclick",  onClickableCellsDblClick.bindAsEventListener(days[i]));
804       }
805     else {
806        var headerDivs = $("calendarHeader").childNodesWithTag("div"); 
807        var headerDaysLabels = document.getElementsByClassName("day", headerDivs[0]);
808        var headerDays = document.getElementsByClassName("day", headerDivs[1]);
809        for (var i = 0; i < days.length; i++) {
810           headerDays[i].hour = "allday";
811           Event.observe(headerDaysLabels[i], "mousedown", listRowMouseDownHandler);
812           Event.observe(headerDays[i], "click",
813                         onCalendarSelectDay.bindAsEventListener(days[i]));
814           Event.observe(headerDays[i], "dblclick",
815                         onClickableCellsDblClick.bindAsEventListener(headerDays[i]));
816           Event.observe(days[i], "click",
817                         onCalendarSelectDay.bindAsEventListener(days[i]));
818           var clickableCells = document.getElementsByClassName("clickableHourCell",
819                                                                days[i]);
820           for (var j = 0; j < clickableCells.length; j++)
821              Event.observe(clickableCells[j], "dblclick",
822                            onClickableCellsDblClick.bindAsEventListener(clickableCells[j]));
823        }
824     }
825   }
826   else
827     log ("calendarDisplayCallback Ajax error (" + http.readyState + "/" + http.status + ")");
828 }
829
830 function assignCalendar(name) {
831   if (typeof(skycalendar) != "undefined") {
832     var node = $(name);
833       
834     node.calendar = new skycalendar(node);
835     node.calendar.setCalendarPage(ResourcesURL + "/skycalendar.html");
836     var dateFormat = node.getAttribute("dateFormat");
837     if (dateFormat)
838       node.calendar.setDateFormat(dateFormat);
839   }
840 }
841
842 function popupCalendar(node) {
843    var nodeId = node.getAttribute("inputId");
844    var input = $(nodeId);
845    input.calendar.popup();
846
847    return false;
848 }
849
850 function onEventContextMenu(event) {
851   var topNode = $("eventsList");
852 //   log(topNode);
853
854   var menu = $("eventsListMenu");
855
856   Event.observe(menu, "hideMenu",  onEventContextMenuHide);
857   popupMenu(event, "eventsListMenu", this);
858
859   var topNode = $("eventsList");
860   var selectedNodes = topNode.getSelectedRows();
861   topNode.menuSelectedRows = selectedNodes;
862   for (var i = 0; i < selectedNodes.length; i++)
863     selectedNodes[i].deselect();
864
865   topNode.menuSelectedEntry = this;
866   this.select();
867 }
868
869 function onEventContextMenuHide(event) {
870   var topNode = $("eventsList");
871
872   if (topNode.menuSelectedEntry) {
873     topNode.menuSelectedEntry.deselect();
874     topNode.menuSelectedEntry = null;
875   }
876   if (topNode.menuSelectedRows) {
877     var nodeIds = topNode.menuSelectedRows;
878     for (var i = 0; i < nodeIds.length; i++) {
879       var node = $(nodeIds[i]);
880       node.select();
881     }
882     topNode.menuSelectedRows = null;
883   }
884 }
885
886 function onEventsSelectionChange() {
887   listOfSelection = this;
888   this.removeClassName("_unfocused");
889   $("tasksList").addClassName("_unfocused");
890 }
891
892 function onTasksSelectionChange() {
893   listOfSelection = this;
894   this.removeClassName("_unfocused");
895   $("eventsList").addClassName("_unfocused");
896 }
897
898 function _loadEventHref(href) {
899   if (document.eventsListAjaxRequest) {
900     document.eventsListAjaxRequest.aborted = true;
901     document.eventsListAjaxRequest.abort();
902   }
903   var url = ApplicationBaseURL + "/" + href;
904   document.eventsListAjaxRequest
905     = triggerAjaxRequest(url, eventsListCallback, href);
906
907   var table = $("eventsList").tBodies[0];
908   while (table.rows.length > 0)
909      table.removeChild(table.rows[0]);
910
911   return false;
912 }
913
914 function _loadTasksHref(href) {
915   if (document.tasksListAjaxRequest) {
916     document.tasksListAjaxRequest.aborted = true;
917     document.tasksListAjaxRequest.abort();
918   }
919   url = ApplicationBaseURL + "/" + href;
920
921   var tasksList = $("tasksList");
922   var selectedIds;
923   if (tasksList)
924      selectedIds = tasksList.getSelectedNodesId();
925   else
926      selectedIds = null;
927   document.tasksListAjaxRequest
928     = triggerAjaxRequest(url, tasksListCallback, selectedIds);
929
930   tasksList.previousScroll = tasksList.scrollTop;
931   while (tasksList.childNodes.length)
932      tasksList.removeChild(tasksList.childNodes[0]);
933
934   return true;
935 }
936
937 function onHeaderClick(event) {
938   //log("onHeaderClick: " + this.link);
939   //_loadEventHref(this.link);
940
941   preventDefault(event);
942 }
943
944 function refreshEvents() {
945    return _loadEventHref("eventslist?desc=" + sortOrder
946                          + "&sort=" + sortKey
947                          + "&day=" + currentDay
948                          + "&filterpopup=" + listFilter);
949 }
950
951 function refreshTasks() {
952   return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
953 }
954
955 function refreshEventsAndDisplay() {
956   refreshEvents();
957   changeCalendarDisplay();
958 }
959
960 function onListFilterChange() {
961   var node = $("filterpopup");
962
963   listFilter = node.value;
964 //   log ("listFilter = " + listFilter);
965
966   return refreshEvents();
967 }
968
969 function onEventClick(event) { log ("onEventClick");
970   var day = this.day;
971   var hour = this.hour;
972
973   changeCalendarDisplay( { "day": day, "hour": hour} );
974   changeDateSelectorDisplay(day);
975
976   return onRowClick(event);
977 }
978
979 function selectMonthInMenu(menu, month) {
980    var entries = menu.childNodes[1].childNodesWithTag("LI");
981    for (i = 0; i < entries.length; i++) {
982       var entry = entries[i];
983       var entryMonth = entry.getAttribute("month");
984       if (entryMonth == month)
985          entry.addClassName("currentMonth");
986       else
987          entry.removeClassName("currentMonth");
988    }
989 }
990
991 function selectYearInMenu(menu, month) {
992   var entries = menu.childNodes[1].childNodes;
993   for (i = 0; i < entries.length; i++) {
994     var entry = entries[i];
995     if (entry.tagName == "LI") {
996       var entryMonth = entry.innerHTML;
997       if (entryMonth == month)
998         entry.addClassName("currentMonth");
999       else
1000         entry.removeClassName("currentMonth");
1001     }
1002   }
1003 }
1004
1005 function popupMonthMenu(event) {
1006   if (event.button == 0) {
1007     var id = this.getAttribute("id");
1008     if (id == "monthLabel")
1009        menuId = "monthListMenu";
1010     else
1011        menuId = "yearListMenu";
1012
1013     var popup = $(menuId);
1014     if (id == "monthLabel")
1015       selectMonthInMenu(popup, this.getAttribute("month"));
1016     else
1017       selectYearInMenu(popup, this.innerHTML);
1018
1019     popupToolbarMenu(this, menuId);
1020     Event.stop(event);
1021   }
1022 }
1023
1024 function onMonthMenuItemClick(event) {
1025   var month = '' + this.getAttribute("month");
1026   var year = '' + $("yearLabel").innerHTML;
1027
1028   changeDateSelectorDisplay(year + month + "01", true);
1029 }
1030
1031 function onYearMenuItemClick(event) {
1032   var month = '' + $("monthLabel").getAttribute("month");;
1033   var year = '' + this.innerHTML;
1034
1035   changeDateSelectorDisplay(year + month + "01", true);
1036 }
1037
1038 function onSearchFormSubmit() {
1039   log ("search not implemented");
1040
1041   return false;
1042 }
1043
1044 function onCalendarSelectEvent() {
1045   var list = $("eventsList");
1046   $(list.tBodies[0]).deselectAll();
1047
1048   if (selectedCalendarCell)
1049      for (var i = 0; i < selectedCalendarCell.length; i++)
1050         selectedCalendarCell[i].deselect();
1051
1052   for (var i = 0; i < this.siblings.length; i++)
1053      this.siblings[i].select();
1054   selectedCalendarCell = this.siblings;
1055   var row = $(this.cname);
1056   if (row) {
1057     var div = row.parentNode.parentNode.parentNode;
1058     div.scrollTop = row.offsetTop - (div.offsetHeight / 2);
1059     row.select();
1060   }
1061 }
1062
1063 function onCalendarSelectDay(event) {
1064   var day;
1065   if (currentView == "multicolumndayview")
1066      day = this.getAttribute("day");
1067   else
1068      day = this.getAttribute("day");
1069   var needRefresh = (listFilter == 'view_selectedday'
1070                      && day != currentDay);
1071
1072   if (currentView == 'weekview')
1073     changeWeekCalendarDisplayOfSelectedDay(this);
1074   else if (currentView == 'monthview')
1075     changeMonthCalendarDisplayOfSelectedDay(this);
1076   changeDateSelectorDisplay(day);
1077
1078   if (listOfSelection) {
1079     listOfSelection.addClassName("_unfocused");
1080     listOfSelection = null;
1081   }
1082
1083   if (needRefresh)
1084     refreshEvents();
1085 }
1086
1087 function changeWeekCalendarDisplayOfSelectedDay(node) {
1088   var days = document.getElementsByClassName("day", node.parentNode);
1089   var headerDiv = $("calendarHeader").childNodesWithTag("div")[1];
1090   var headerDays = document.getElementsByClassName("day", headerDiv);
1091
1092 //   log ("days: " + days.length + "; headerDays: " + headerDays.length);
1093   for (var i = 0; i < days.length; i++)
1094      if (days[i] != node) {
1095 //      log("unselect day : " + i);
1096         headerDays[i].removeClassName("selectedDay");
1097         days[i].removeClassName("selectedDay");
1098      }
1099      else {
1100 //      log("selected day : " + i);
1101         headerDays[i].addClassName("selectedDay");
1102         days[i].addClassName("selectedDay");
1103      }
1104 }
1105
1106 function findMonthCalendarSelectedCell(daysContainer) {
1107    var found = false;
1108    var i = 0;
1109
1110    while (!found && i < daysContainer.childNodes.length) {
1111       var currentNode = daysContainer.childNodes[i];
1112       if (currentNode.tagName == 'DIV'
1113           && currentNode.hasClassName("selectedDay")) {
1114          daysContainer.selectedCell = currentNode;
1115          found = true;
1116       }
1117       else
1118          i++;
1119    }
1120 }
1121
1122 function changeMonthCalendarDisplayOfSelectedDay(node) {
1123    var daysContainer = node.parentNode;
1124    if (!daysContainer.selectedCell)
1125       findMonthCalendarSelectedCell(daysContainer);
1126    
1127    if (daysContainer.selectedCell)
1128       daysContainer.selectedCell.removeClassName("selectedDay");
1129    daysContainer.selectedCell = node;
1130    node.addClassName("selectedDay");
1131 }
1132
1133 function onShowCompletedTasks(event) {
1134    showCompletedTasks = (this.checked ? 1 : 0);
1135
1136    return refreshTasks();
1137 }
1138
1139 function updateTaskStatus(event) {
1140   var taskId = this.parentNode.getAttribute("id");
1141   var newStatus = (this.checked ? 1 : 0);
1142   var http = createHTTPClient();
1143
1144   if (isSafari() && !isSafari3()) {
1145     newStatus = (newStatus ? 0 : 1);
1146   }
1147   
1148   url = (ApplicationBaseURL + "/" + this.parentNode.calendar
1149          + "/" + taskId + "/changeStatus?status=" + newStatus);
1150
1151   if (http) {
1152     // TODO: add parameter to signal that we are only interested in OK
1153     http.open("POST", url, false /* not async */);
1154     http.url = url;
1155     http.send("");
1156     if (http.status == 200)
1157       refreshTasks();
1158   } else
1159     log ("no http client?");
1160
1161   return false;
1162 }
1163
1164 function updateCalendarStatus(event) {
1165   var list = new Array();
1166   var newStatus = (this.checked ? 1 : 0);
1167   
1168   if (isSafari() && !isSafari3()) {
1169     newStatus = (newStatus ? 0 : 1);
1170     this.checked = newStatus;
1171   }
1172
1173   var nodes = $("calendarList").childNodesWithTag("li");
1174   for (var i = 0; i < nodes.length; i++) {
1175     var input = $(nodes[i]).childNodesWithTag("input")[0];
1176     if (input.checked) {
1177        var folderId = nodes[i].getAttribute("id");
1178        var elems = folderId.split(":");
1179        if (elems.length > 1)
1180           list.push(elems[0]);
1181        else
1182           list.push(UserLogin);
1183     }
1184   }
1185
1186 //   if (!list.length) {
1187 //      list.push(UserLogin);
1188 //      nodes[0].childNodesWithTag("input")[0].checked = true;
1189 //   }
1190
1191 //   ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
1192 //                      + list.join(",") + "/Calendar/");
1193
1194   if (event) {
1195      var folderID = this.parentNode.getAttribute("id");
1196      var urlstr = URLForFolderID(folderID);
1197      if (newStatus)
1198        urlstr += "/activateFolder";
1199      else
1200        urlstr += "/deactivateFolder";
1201      //log("updateCalendarStatus: ajax request = " + urlstr + ", folderID = " + folderID);
1202      triggerAjaxRequest(urlstr, calendarStatusCallback, folderID);
1203   }
1204   else {
1205      updateCalendarsList();
1206      refreshEvents();
1207      refreshTasks();
1208      changeCalendarDisplay();
1209   }
1210
1211   return false;
1212 }
1213
1214 function calendarStatusCallback(http) {
1215   if (http.readyState == 4) {
1216     if (isHttpStatus204(http.status)) {
1217       refreshEvents();
1218       refreshTasks();
1219       changeCalendarDisplay();
1220     }
1221     else {
1222       var folder = $(http.callbackData);
1223       var input = folder.childNodesWithTag("input")[0];
1224       input.checked = (!input.checked);
1225     }
1226   }
1227   else
1228     log("calendarStatusCallback Ajax error");
1229 }
1230
1231 function calendarEntryCallback(http) {
1232    if (http.readyState == 4) {
1233       var denied = !isHttpStatus204(http.status);
1234       var entry = $(http.callbackData);
1235       if (denied)
1236          entry.addClassName("denied");
1237       else
1238          entry.removeClassName("denied");
1239    }
1240 }
1241
1242 function updateCalendarsList(method) {
1243   var list = $("calendarList").childNodesWithTag("li");
1244   for (var i = 0; i < list.length; i++) {
1245      var folderID = list[i].getAttribute("id");
1246      var url = URLForFolderID(folderID) + "/canAccessContent";
1247      triggerAjaxRequest(url, calendarEntryCallback, folderID);
1248   }
1249 }
1250
1251 function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
1252   var uids = $("uixselector-calendarsList-uidList");
1253 //   log("addContact");
1254   if (contactId)
1255     {
1256       var re = new RegExp("(^|,)" + contactId + "($|,)");
1257
1258       if (!re.test(uids.value))
1259         {
1260           if (uids.value.length > 0)
1261             uids.value += ',' + contactId;
1262           else
1263             uids.value = contactId;
1264           var names = $("calendarList");
1265           var listElems = names.childNodesWithTag("li");
1266           var colorDef = indexColor(listElems.length);
1267           names.appendChild(userCalendarEntry(contactId, colorDef));
1268
1269         }
1270     }
1271
1272   return false;
1273 }
1274
1275 function validateBrowseURL(input) {
1276   var button = $("browseURLBtn");
1277
1278   if (input.value.length) {
1279     if (!button.enabled)
1280       enableAnchor(button);
1281   } else if (!button.disabled)
1282     disableAnchor(button);
1283 }
1284
1285 function browseURL(anchor, event) {
1286   if (event.button == 0) {
1287     var input = $("url");
1288     var url = input.value;
1289     if (url.length)
1290       window.open(url, '_blank');
1291   }
1292
1293   return false;
1294 }
1295
1296 function getMenus() {
1297    var menus = {};
1298
1299    var dateMenu = new Array();
1300    for (var i = 0; i < 12; i++)
1301       dateMenu.push(onMonthMenuItemClick);
1302    menus["monthListMenu"] = dateMenu;
1303
1304    dateMenu = new Array();
1305    for (var i = 0; i < 11; i++)
1306       dateMenu.push(onYearMenuItemClick);
1307    menus["yearListMenu"] = dateMenu;
1308
1309    menus["eventsListMenu"] = new Array(onMenuNewEventClick, "-",
1310                                        onMenuNewTaskClick,
1311                                        editEvent, deleteEvent, "-",
1312                                        onSelectAll, "-",
1313                                        null, null);
1314    menus["calendarsMenu"] = new Array(onMenuModify,
1315                                       "-",
1316                                       onCalendarNew, onCalendarRemove,
1317                                       "-", null, null, "-",
1318                                       null, "-", onMenuSharing);
1319    menus["searchMenu"] = new Array(setSearchCriteria);
1320
1321    return menus;
1322 }
1323
1324 function onMenuSharing(event) {
1325   var folders = $("calendarList");
1326   var selected = folders.getSelectedNodes()[0];
1327   /* FIXME: activation of the context menu should preferable select the entry
1328                above which the event has occured */
1329   if (selected) {
1330      var folderID = selected.getAttribute("id");
1331      var urlstr = URLForFolderID(folderID) + "/acls";
1332
1333      openAclWindow(urlstr);
1334   }
1335 }
1336
1337 function configureDragHandles() {
1338   var handle = $("verticalDragHandle");
1339   if (handle) {
1340     handle.addInterface(SOGoDragHandlesInterface);
1341     handle.leftBlock=$("leftPanel");
1342     handle.rightBlock=$("rightPanel");
1343   }
1344
1345   handle = $("rightDragHandle");
1346   if (handle) {
1347     handle.addInterface(SOGoDragHandlesInterface);
1348     handle.upperBlock=$("eventsListView");
1349     handle.lowerBlock=$("calendarView");
1350   }
1351 }
1352
1353 function initCalendarSelector() {
1354   var selector = $("calendarSelector");
1355   updateCalendarStatus();
1356   selector.changeNotification = updateCalendarsList;
1357
1358   var list = $("calendarList");
1359   list.multiselect = true;
1360   var items = list.childNodesWithTag("li");
1361   for (var i = 0; i < items.length; i++) {
1362     var input = items[i].childNodesWithTag("input")[0];
1363     Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
1364     Event.observe(items[i], "mousedown", listRowMouseDownHandler);
1365     Event.observe(items[i], "selectstart", listRowMouseDownHandler);
1366     Event.observe(items[i], "click", onRowClick);
1367   }
1368
1369   var links = $("calendarSelectorButtons").childNodesWithTag("a");
1370   Event.observe(links[0], "click",  onCalendarNew);
1371   Event.observe(links[1], "click",  onCalendarAdd);
1372   Event.observe(links[2], "click",  onCalendarRemove);
1373 }
1374
1375 function onMenuModify(event) {
1376   var folders = $("calendarList");
1377   var selected = folders.getSelectedNodes()[0];
1378
1379   if (UserLogin == selected.getAttribute("owner")) {
1380     var node = selected.childNodes[4];
1381     var currentName = node.nodeValue.trim();
1382     var newName = window.prompt(labels["Name of the Calendar"],
1383                                 currentName);
1384     if (newName && newName.length > 0
1385         && newName != currentName) {
1386       var url = (URLForFolderID(selected.getAttribute("id"))
1387                  + "/renameFolder?name=" + escape(newName.utf8encode()));
1388       triggerAjaxRequest(url, folderRenameCallback,
1389                          {node: node, name: " " + newName});
1390     }
1391   } else
1392     window.alert(clabels["Unable to rename that folder!"]);
1393 }
1394
1395 function folderRenameCallback(http) {
1396   if (http.readyState == 4) {
1397     if (isHttpStatus204(http.status)) {
1398       var dict = http.callbackData;
1399       dict["node"].nodeValue = dict["name"];
1400     }
1401   }
1402 }
1403
1404 function onCalendarNew(event) {
1405   createFolder(window.prompt(labels["Name of the Calendar"]),
1406                appendCalendar);
1407   preventDefault(event);
1408 }
1409
1410 function onCalendarAdd(event) {
1411   openUserFolderSelector(onFolderSubscribeCB, "calendar");
1412   preventDefault(event);
1413 }
1414
1415 function appendCalendar(folderName, folderPath) {
1416   var owner;
1417
1418   if (folderPath) {
1419     owner = getSubscribedFolderOwner(folderPath);
1420     folderPath = accessToSubscribedFolder(folderPath);
1421   }
1422   else
1423     folderPath = "/" + folderName;
1424
1425   if (!owner)
1426     owner = UserLogin;
1427
1428   //log ("append name: " + folderName + "; path: " + folderPath + "; owner: " + owner);
1429
1430   if ($(folderPath))
1431     window.alert(clabels["You have already subscribed to that folder!"]);
1432   else {
1433     var calendarList = $("calendarList");
1434     var lis = calendarList.childNodesWithTag("li");
1435     var color = indexColor(lis.length + 100);
1436     //log ("color: " + color);
1437
1438     var li = document.createElement("li");
1439     
1440     // Add the calendar to the proper place
1441     var previousOwner = null;
1442     for (var i = 1; i < lis.length; i++) {
1443       var currentFolderName = lis[i].lastChild.nodeValue.strip();
1444       var currentOwner = lis[i].readAttribute('owner');
1445       if (currentOwner == owner) {
1446         previousOwner = currentOwner;
1447         if (currentFolderName > folderName)
1448           break;
1449       }
1450       else if (previousOwner || 
1451                (currentOwner != UserLogin && currentOwner > owner))
1452         break;
1453     }
1454     if (i != lis.length) // User is subscribed to other calendars of the same owner
1455       calendarList.insertBefore(li, lis[i]);
1456     else 
1457       calendarList.appendChild(li);
1458     
1459     li.setAttribute("id", folderPath);
1460     li.setAttribute("owner", owner);
1461
1462     var checkBox = document.createElement("input");
1463     checkBox.setAttribute("type", "checkbox");
1464     li.appendChild(checkBox);
1465     li.appendChild(document.createTextNode(" "));
1466     $(checkBox).addClassName("checkBox");
1467
1468     var colorBox = document.createElement("div");
1469     li.appendChild(colorBox);
1470     li.appendChild(document.createTextNode(folderName));
1471     colorBox.appendChild(document.createTextNode("OO"));
1472
1473     $(colorBox).addClassName("colorBox");
1474     $(colorBox).addClassName('calendarFolder' + folderPath.substr(1));
1475
1476     // Register events (doesn't work with Safari)
1477     Event.observe(li, "mousedown",  listRowMouseDownHandler);
1478     Event.observe(li, "selectstart", listRowMouseDownHandler);
1479     Event.observe(li, "click",  onRowClick);
1480     Event.observe(checkBox, "click",
1481                   updateCalendarStatus.bindAsEventListener(checkBox));
1482
1483     var url = URLForFolderID(folderPath) + "/canAccessContent";
1484     triggerAjaxRequest(url, calendarEntryCallback, folderPath);
1485     
1486     // Update CSS for events color
1487     if (!document.styleSheets) return;
1488     var theRules = new Array();
1489     var lastSheet = document.styleSheets[document.styleSheets.length - 1];
1490     if (lastSheet.insertRule) { // Mozilla
1491       lastSheet.insertRule('.calendarFolder' + folderPath.substr(1) + ' {'
1492                            + ' background-color: '
1493                            + color
1494                            + ' !important; }', 0);
1495       lastSheet.insertRule('div.colorBox.calendarFolder' + folderPath.substr(1) + ' {'
1496                            + ' color: '
1497                            + color
1498                            + ' !important; }', 0);
1499     }
1500     else { // IE
1501       lastSheet.addRule('.calendarFolder' + folderPath.substr(1),
1502                         ' background-color: '
1503                         + color
1504                         + ' !important; }');
1505       lastSheet.addRule('div.colorBox.calendarFolder' + folderPath.substr(1),
1506                         ' color: '
1507                         + color
1508                         + ' !important; }');
1509     }
1510   }
1511 }
1512
1513 function onFolderSubscribeCB(folderData) {
1514   var folder = $(folderData["folder"]);
1515    if (!folder)
1516      appendCalendar(folderData["folderName"], folderData["folder"]);
1517 }
1518
1519 function onFolderUnsubscribeCB(folderId) {
1520   var node = $(folderId);
1521   node.parentNode.removeChild(node);
1522   if (removeFolderRequestCount == 0) {
1523     refreshEvents();
1524     refreshTasks();
1525     changeCalendarDisplay();
1526   }
1527 }
1528
1529 function onCalendarRemove(event) {
1530   if (removeFolderRequestCount == 0) {
1531     var nodes = $("calendarList").getSelectedNodes();
1532     for (var i = 0; i < nodes.length; i++) {
1533       nodes[i].deselect();
1534       var folderId = nodes[i].getAttribute("id");
1535       var folderIdElements = folderId.split("_");
1536       if (folderIdElements.length > 1) {
1537         unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
1538       }
1539       else
1540         deletePersonalCalendar(folderIdElements[0]);
1541     }
1542   }
1543   
1544   preventDefault(event);
1545 }
1546
1547 function deletePersonalCalendar(folderElement) {
1548   var folderId = folderElement.substr(1);
1549   var label
1550     = labels["Are you sure you want to delete the calendar \"%{0}\"?"].formatted($(folderElement).lastChild.nodeValue.strip());
1551   if (window.confirm(label)) {
1552     removeFolderRequestCount++;
1553     var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
1554     triggerAjaxRequest(url, deletePersonalCalendarCallback, folderId);
1555   }
1556 }
1557
1558 function deletePersonalCalendarCallback(http) {
1559   if (http.readyState == 4) {
1560     if (isHttpStatus204(http.status)) {
1561       var ul = $("calendarList");
1562       var children = ul.childNodesWithTag("li");
1563       var i = 0;
1564       var done = false;
1565       while (!done && i < children.length) {
1566         var currentFolderId = children[i].getAttribute("id").substr(1);
1567         if (currentFolderId == http.callbackData) {
1568           ul.removeChild(children[i]);
1569           done = true;
1570         }
1571         else
1572           i++;
1573       }
1574       removeFolderRequestCount--;
1575       if (removeFolderRequestCount == 0) {
1576         refreshEvents();
1577         refreshTasks();
1578         changeCalendarDisplay();
1579       }
1580     }
1581   }
1582   else
1583     log ("ajax problem 5: " + http.status);
1584 }
1585
1586 function configureLists() {
1587    var list = $("tasksList");
1588    list.multiselect = true;
1589    Event.observe(list, "mousedown",
1590                  onTasksSelectionChange.bindAsEventListener(list));
1591
1592    var input = $("showHideCompletedTasks");
1593    Event.observe(input, "click",
1594                  onShowCompletedTasks.bindAsEventListener(input));
1595
1596    list = $("eventsList");
1597    list.multiselect = true;
1598    //configureSortableTableHeaders(list);
1599    TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
1600    Event.observe(list, "mousedown",
1601                  onEventsSelectionChange.bindAsEventListener(list));
1602    var div = list.parentNode;
1603    Event.observe(div, "contextmenu",
1604                  onEventContextMenu.bindAsEventListener(div));
1605 }
1606
1607 function initDateSelectorEvents() {
1608    var arrow = $("rightArrow");
1609    Event.observe(arrow, "click",
1610                  onDateSelectorGotoMonth.bindAsEventListener(arrow));
1611    arrow = $("leftArrow");
1612    Event.observe(arrow, "click",
1613                  onDateSelectorGotoMonth.bindAsEventListener(arrow));
1614    
1615    var menuButton = $("monthLabel");
1616    Event.observe(menuButton, "click",
1617                  popupMonthMenu.bindAsEventListener(menuButton));
1618    menuButton = $("yearLabel");
1619    Event.observe(menuButton, "click",
1620                  popupMonthMenu.bindAsEventListener(menuButton));
1621 }
1622
1623 function initCalendars() {
1624    if (!document.body.hasClassName("popup")) {
1625       initDateSelectorEvents();
1626       initCalendarSelector();
1627       configureSearchField();
1628       configureLists();
1629       var selector = $("calendarSelector");
1630       if (selector)
1631          selector.attachMenu("calendarsMenu");
1632    }
1633 }
1634
1635 addEvent(window, 'load', initCalendars);