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