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