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