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