1 /* JavaScript for SOGoCalendar */
5 var listFilter = 'view_today';
7 var listOfSelection = null;
8 var selectedCalendarCell;
9 var calendarColorIndex = null;
11 var showCompletedTasks = 0;
14 var currentView = "weekview";
16 var cachedDateSelectors = new Array();
18 var contactSelectorAction = 'calendars-contacts';
20 var eventsToDelete = new Array();
21 var calendarsOfEventsToDelete = new Array();
23 var usersRightsWindowHeight = 250;
24 var usersRightsWindowWidth = 502;
26 function newEvent(sender, type) {
27 var day = sender.readAttribute("day");
30 var hour = sender.readAttribute("hour");
31 var folder = getSelectedFolder();
32 var folderID = folder.readAttribute("id");
33 var roles = folder.readAttribute("roles");
35 roles = roles.split(",")
36 if ($(roles).indexOf("PublicModifier") < 0)
37 folderID = "/personal";
39 var urlstr = ApplicationBaseURL + folderID + "/new" + type;
40 var params = new Array();
42 params.push("day=" + day);
44 params.push("hm=" + hour);
45 if (params.length > 0)
46 urlstr += "?" + params.join("&");
47 window.open(urlstr, "", "width=490,height=470,resizable=0");
49 return false; /* stop following the link */
52 function getSelectedFolder() {
54 var list = $("calendarList");
55 var nodes = list.getSelectedRows();
59 folder = list.down("li");
64 function onMenuNewEventClick(event) {
65 newEvent(this, "event");
68 function onMenuNewTaskClick(event) {
69 newEvent(this, "task");
72 function _editEventId(id, calendar) {
73 var urlstr = ApplicationBaseURL + "/" + calendar + "/" + id + "/edit";
74 var targetname = "SOGo_edit_" + id;
75 var win = window.open(urlstr, "_blank",
76 "width=490,height=470,resizable=0");
80 function editEvent() {
81 if (listOfSelection) {
82 var nodes = listOfSelection.getSelectedRows();
84 for (var i = 0; i < nodes.length; i++)
85 _editEventId(nodes[i].getAttribute("id"),
87 } else if (selectedCalendarCell) {
88 _editEventId(selectedCalendarCell[0].cname,
89 selectedCalendarCell[0].calendar);
92 return false; /* stop following the link */
95 function _batchDeleteEvents() {
96 var events = eventsToDelete.shift();
97 var calendar = calendarsOfEventsToDelete.shift();
98 var urlstr = (ApplicationBaseURL + "/" + calendar
99 + "/batchDelete?ids=" + events.join('/'));
100 document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
105 function deleteEvent() {
106 if (listOfSelection) {
107 var nodes = listOfSelection.getSelectedRows();
109 if (nodes.length > 0) {
111 if (listOfSelection == $("tasksList"))
112 label = labels["taskDeleteConfirmation"];
114 label = labels["eventDeleteConfirmation"];
116 if (confirm(label)) {
117 if (document.deleteEventAjaxRequest) {
118 document.deleteEventAjaxRequest.aborted = true;
119 document.deleteEventAjaxRequest.abort();
121 var sortedNodes = new Array();
122 var calendars = new Array();
124 for (var i = 0; i < nodes.length; i++) {
125 var calendar = nodes[i].calendar;
126 if (!sortedNodes[calendar]) {
127 sortedNodes[calendar] = new Array();
128 calendars.push(calendar);
130 sortedNodes[calendar].push(nodes[i].cname);
132 for (var i = 0; i < calendars.length; i++) {
133 calendarsOfEventsToDelete.push(calendars[i]);
134 eventsToDelete.push(sortedNodes[calendars[i]]);
136 _batchDeleteEvents();
140 else if (selectedCalendarCell) {
141 var label = labels["eventDeleteConfirmation"];
142 if (confirm(label)) {
143 if (document.deleteEventAjaxRequest) {
144 document.deleteEventAjaxRequest.aborted = true;
145 document.deleteEventAjaxRequest.abort();
147 eventsToDelete.push([selectedCalendarCell[0].cname]);
148 calendarsOfEventsToDelete.push(selectedCalendarCell[0].calendar);
149 _batchDeleteEvents();
153 window.alert("no selection");
158 function modifyEvent(sender, modification) {
159 var currentLocation = '' + window.location;
160 var arr = currentLocation.split("/");
161 arr[arr.length-1] = modification;
163 document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
170 function closeInvitationWindow() {
171 var closeDiv = document.createElement("div");
172 document.body.appendChild(closeDiv);
173 closeDiv.addClassName("javascriptPopupBackground");
175 var closePseudoWin = document.createElement("div");
176 document.body.appendChild(closePseudoWin);
177 closePseudoWin.addClassName("javascriptMessagePseudoTopWindow");
178 closePseudoWin.style.top = "0px;";
179 closePseudoWin.style.left = "0px;";
180 closePseudoWin.style.right = "0px;";
181 closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
183 var calLink = document.createElement("a");
184 closePseudoWin.appendChild(calLink);
185 calLink.href = ApplicationBaseURL;
186 calLink.appendChild(document.createTextNode(labels["Calendar"].toLowerCase()));
189 function modifyEventCallback(http) {
190 if (http.readyState == 4) {
191 if (http.status == 200) {
192 var mailInvitation = queryParameters["mail-invitation"];
193 if (mailInvitation && mailInvitation.toLowerCase() == "yes")
194 closeInvitationWindow();
196 window.opener.setTimeout("refreshEventsAndDisplay();", 100);
197 window.setTimeout("window.close();", 100);
201 // log("showing alert...");
202 window.alert(labels["eventPartStatModificationError"]);
204 document.modifyEventAjaxRequest = null;
208 function deleteEventCallback(http) {
209 if (http.readyState == 4) {
210 if (isHttpStatus204(http.status)) {
211 var nodes = http.callbackData;
212 for (var i = 0; i < nodes.length; i++) {
213 var node = $(nodes[i]);
215 node.parentNode.removeChild(node);
217 if (eventsToDelete.length)
218 _batchDeleteEvents();
220 document.deleteEventAjaxRequest = null;
223 changeCalendarDisplay();
227 log ("deleteEventCallback Ajax error");
231 function editDoubleClickedEvent(event) {
232 _editEventId(this.cname, this.calendar);
234 preventDefault(event);
235 event.cancelBubble = true;
238 function onSelectAll() {
239 var list = $("eventsList");
240 list.selectRowsMatchingClass("eventRow");
245 function onDaySelect(node) {
246 var day = node.getAttribute('day');
247 var needRefresh = (listFilter == 'view_selectedday'
248 && day != currentDay);
250 var td = $(node).getParentWithTagName("td");
251 var table = $(td).getParentWithTagName("table");
253 // log ("table.selected: " + table.selected);
255 if (document.selectedDate)
256 document.selectedDate.deselect();
259 document.selectedDate = td;
261 changeCalendarDisplay( { "day": day } );
268 function onDateSelectorGotoMonth(event) {
269 var day = this.getAttribute("date");
271 changeDateSelectorDisplay(day, true);
276 function onCalendarGotoDay(node) {
277 var day = node.getAttribute("date");
279 changeDateSelectorDisplay(day);
280 changeCalendarDisplay( { "day": day } );
285 function gotoToday() {
286 changeDateSelectorDisplay('');
287 changeCalendarDisplay();
292 function setDateSelectorContent(content) {
293 var div = $("dateSelectorView");
295 div.innerHTML = content;
296 if (currentDay.length > 0)
297 restoreCurrentDaySelection(div);
299 initDateSelectorEvents();
302 function dateSelectorCallback(http) {
303 if (http.readyState == 4
304 && http.status == 200) {
305 document.dateSelectorAjaxRequest = null;
306 var content = http.responseText;
307 setDateSelectorContent(content);
308 cachedDateSelectors[http.callbackData] = content;
311 log ("dateSelectorCallback Ajax error");
314 function eventsListCallback(http) {
315 if (http.readyState == 4
316 && http.status == 200) {
317 var div = $("eventsListView");
319 document.eventsListAjaxRequest = null;
320 var table = $("eventsList");
321 var params = parseQueryParameters(http.callbackData);
322 sortKey = params["sort"];
323 sortOrder = params["desc"];
324 lastClickedRow = -1; // from generic.js
326 if (http.responseText.length > 0) {
327 var data = http.responseText.evalJSON(true);
328 for (var i = 0; i < data.length; i++) {
329 var row = document.createElement("tr");
330 table.tBodies[0].appendChild(row);
331 $(row).addClassName("eventRow");
332 row.setAttribute("id", escape(data[i][0]));
333 row.cname = escape(data[i][0]);
334 row.calendar = data[i][1];
336 var startDate = new Date();
337 startDate.setTime(data[i][4] * 1000);
338 row.day = startDate.getDayString();
339 row.hour = startDate.getHourString();
340 Event.observe(row, "click",
341 onEventClick.bindAsEventListener(row));
342 Event.observe(row, "dblclick",
343 editDoubleClickedEvent.bindAsEventListener(row));
344 Event.observe(row, "contextmenu",
345 onEventContextMenu.bindAsEventListener(row));
347 var td = document.createElement("td");
349 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
350 td.appendChild(document.createTextNode(data[i][3]));
352 td = document.createElement("td");
354 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
355 td.appendChild(document.createTextNode(data[i][9]));
357 td = document.createElement("td");
359 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
360 td.appendChild(document.createTextNode(data[i][10]));
362 td = document.createElement("td");
364 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
365 td.appendChild(document.createTextNode(data[i][6]));
370 log ("eventsListCallback Ajax error");
373 function tasksListCallback(http) {
374 var div = $("tasksListView");
376 if (http.readyState == 4
377 && http.status == 200) {
378 document.tasksListAjaxRequest = null;
379 var list = $("tasksList");
381 if (http.responseText.length > 0) {
382 var data = http.responseText.evalJSON(true);
384 for (var i = 0; i < data.length; i++) {
385 //log(i + " = " + data[i][3]);
386 var listItem = document.createElement("li");
387 list.appendChild(listItem);
388 Event.observe(listItem, "mousedown", listRowMouseDownHandler);
389 Event.observe(listItem, "click", onRowClick);
390 Event.observe(listItem, "dblclick",
391 editDoubleClickedEvent.bindAsEventListener(listItem));
392 listItem.setAttribute("id", data[i][0]);
393 $(listItem).addClassName(data[i][5]);
394 listItem.calendar = data[i][1];
395 $(listItem).addClassName("calendarFolder" + data[i][1]);
396 listItem.cname = escape(data[i][0]);
397 var input = document.createElement("input");
398 input.setAttribute("type", "checkbox");
399 listItem.appendChild(input);
400 Event.observe(input, "click", updateTaskStatus.bindAsEventListener(input), true);
401 input.setAttribute("value", "1");
403 input.setAttribute("checked", "checked");
404 $(input).addClassName("checkBox");
405 listItem.appendChild(document.createTextNode(data[i][3]));
408 list.scrollTop = list.previousScroll;
410 if (http.callbackData) {
411 var selectedNodesId = http.callbackData;
412 for (var i = 0; i < selectedNodesId.length; i++) {
413 // log(selectedNodesId[i] + " (" + i + ") is selected");
414 $(selectedNodesId[i]).select();
418 log ("tasksListCallback: no data");
422 log ("tasksListCallback Ajax error");
425 function restoreCurrentDaySelection(div) {
426 var elements = $(div).getElementsByTagName("a");
429 while (!day && i < elements.length)
431 day = elements[i].day;
436 && day.substr(0, 6) == currentDay.substr(0, 6)) {
437 for (i = 0; i < elements.length; i++) {
438 day = elements[i].day;
439 if (day && day == currentDay) {
440 var td = $(elements[i]).getParentWithTagName("td");
441 if (document.selectedDate)
442 document.selectedDate.deselect();
444 document.selectedDate = td;
450 function changeDateSelectorDisplay(day, keepCurrentDay) {
451 var url = ApplicationBaseURL + "dateselector";
453 url += "?day=" + day;
455 if (day != currentDay) {
459 var month = day.substr(0, 6);
460 if (cachedDateSelectors[month]) {
461 // log ("restoring cached selector for month: " + month);
462 setDateSelectorContent(cachedDateSelectors[month]);
465 // log ("loading selector for month: " + month);
466 if (document.dateSelectorAjaxRequest) {
467 document.dateSelectorAjaxRequest.aborted = true;
468 document.dateSelectorAjaxRequest.abort();
470 document.dateSelectorAjaxRequest
471 = triggerAjaxRequest(url,
472 dateSelectorCallback,
478 function changeCalendarDisplay(data, newView) {
479 var url = ApplicationBaseURL + ((newView) ? newView : currentView);
481 var scrollEvent = null;
485 scrollEvent = data['scrollEvent'];
493 var divs = $$('div.day[day='+day+']');
495 // Don't reload the view if the event is present in current view
497 // Deselect previous day
498 var selectedDivs = $$('div.day.selectedDay');
499 selectedDivs.each(function(div) {
500 div.removeClassName('selectedDay');
504 divs.each(function(div) {
505 div.addClassName('selectedDay');
508 // Deselect day in date selector
509 if (document.selectedDate)
510 document.selectedDate.deselect();
512 // Select day in date selector
513 var selectedLink = $$('table#dateSelectorTable a[day='+day+']');
514 if (selectedLink.length > 0) {
515 selectedCell = selectedLink[0].up(1);
516 selectedCell.select();
517 document.selectedDate = selectedCell;
521 scrollDayView(scrollEvent);
526 url += "?day=" + day;
529 // log ("switching to view: " + newView);
530 // log ("changeCalendarDisplay: " + url);
532 selectedCalendarCell = null;
534 if (document.dayDisplayAjaxRequest) {
535 // log ("aborting day ajaxrq");
536 document.dayDisplayAjaxRequest.aborted = true;
537 document.dayDisplayAjaxRequest.abort();
539 document.dayDisplayAjaxRequest
540 = triggerAjaxRequest(url, calendarDisplayCallback,
543 "scrollEvent": scrollEvent });
548 function _ensureView(view) {
549 if (currentView != view)
550 changeCalendarDisplay(null, view);
555 function onDayOverview() {
556 return _ensureView("dayview");
559 function onMulticolumnDayOverview() {
560 return _ensureView("multicolumndayview");
563 function onWeekOverview() {
564 return _ensureView("weekview");
567 function onMonthOverview() {
568 return _ensureView("monthview");
571 function scrollDayView(scrollEvent) {
574 // Select event in calendar view
576 divs = $$("div#calendarContent div." + eventClass(scrollEvent));
577 selectCalendarEvent(divs[0]);
580 // Don't scroll if in month view
581 if (currentView == "monthview")
585 var daysView = $("daysView");
587 $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div");
590 divs = $$("div#calendarContent div." + eventClass(scrollEvent));
591 var classes = $w(divs[0].className);
592 for (var i = 0; i < classes.length; i++) {
593 if (classes[i].startsWith("starts")) {
594 var starts = Math.floor(parseInt(classes[i].substr(6)) / 4);
595 offset = hours[starts].offsetTop;
601 offset = hours[8].offsetTop;
603 daysView.scrollTop = offset - 5;
606 function onClickableCellsDblClick(event) {
607 newEvent(this, 'event');
609 event.cancelBubble = true;
610 event.returnValue = false;
613 function refreshCalendarEvents(scrollEvent) {
614 var todayDate = new Date();
617 if (currentView == "dayview") {
621 sd = todayDate.getDayString();
624 else if (currentView == "weekview") {
627 startDate = currentDay.asDate();
629 startDate = todayDate;
630 startDate = startDate.beginOfWeek();
631 sd = startDate.getDayString();
632 var endDate = new Date();
633 endDate.setTime(startDate.getTime());
635 ed = endDate.getDayString();
640 monthDate = currentDay.asDate();
642 monthDate = todayDate;
643 monthDate.setDate(1);
644 sd = monthDate.beginOfWeek().getDayString();
646 var lastMonthDate = new Date();
647 lastMonthDate.setTime(monthDate.getTime());
648 lastMonthDate.setMonth(monthDate.getMonth() + 1);
649 lastMonthDate.addDays(-1);
650 ed = lastMonthDate.endOfWeek().getDayString();
652 if (document.refreshCalendarEventsAjaxRequest) {
653 document.refreshCalendarEventsAjaxRequest.aborted = true;
654 document.refreshCalendarEventsAjaxRequest.abort();
656 var url = ApplicationBaseURL + "eventslist?sd=" + sd + "&ed=" + ed;
657 document.refreshCalendarEventsAjaxRequest
658 = triggerAjaxRequest(url, refreshCalendarEventsCallback,
659 {"startDate": sd, "endDate": ed,
660 "scrollEvent": scrollEvent});
663 function refreshCalendarEventsCallback(http) {
664 if (http.readyState == 4
665 && http.status == 200) {
667 if (http.responseText.length > 0) {
668 var data = http.responseText.evalJSON(true);
669 // log("refresh calendar events: " + data.length);
670 for (var i = 0; i < data.length; i++)
671 drawCalendarEvent(data[i],
672 http.callbackData["startDate"],
673 http.callbackData["endDate"]);
675 scrollDayView(http.callbackData["scrollEvent"]);
678 log("AJAX error when refreshing calendar events");
681 function drawCalendarEvent(eventData, sd, ed) {
682 var viewStartDate = sd.asDate();
683 var viewEndDate = ed.asDate();
685 var startDate = new Date();
686 startDate.setTime(eventData[4] * 1000);
687 var endDate = new Date();
688 endDate.setTime(eventData[5] * 1000);
690 // log ("s: " + startDate + "; e: " + endDate);
692 var days = startDate.daysUpTo(endDate);
695 if (currentView == "monthview"
696 && (eventData[7] == 0))
697 title = startDate.getDisplayHoursString() + " " + eventData[3];
699 title = eventData[3];
701 // log("title: " + title);
702 // log("viewS: " + viewStartDate);
703 var startHour = null;
706 var siblings = new Array();
707 for (var i = 0; i < days.length; i++)
708 if (days[i].earlierDate(viewStartDate) == viewStartDate
709 && days[i].laterDate(viewEndDate) == viewEndDate) {
712 // log("day: " + days[i]);
714 var quarters = (startDate.getUTCHours() * 4
715 + Math.floor(startDate.getUTCMinutes() / 15));
717 startHour = startDate.getDisplayHoursString();
718 endHour = endDate.getDisplayHoursString();
725 if (i == days.length - 1) {
726 var quarters = (endDate.getUTCHours() * 4
727 + Math.ceil(endDate.getUTCMinutes() / 15));
732 lasts = ends - starts;
736 var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
738 siblings.push(eventDiv);
739 eventDiv.siblings = siblings;
740 var dayString = days[i].getDayString();
741 // log("day: " + dayString);
742 var parentDiv = null;
743 if (currentView == "monthview") {
744 var dayDivs = $("monthDaysView").childNodesWithTag("div");
746 while (!parentDiv && j < dayDivs.length) {
747 if (dayDivs[j].getAttribute("day") == dayString)
748 parentDiv = dayDivs[j];
754 if (eventData[7] == 0) {
755 var daysView = $("daysView");
756 var eventsDiv = $(daysView).childNodesWithTag("div")[1];
757 var dayDivs = $(eventsDiv).childNodesWithTag("div");
759 while (!parentDiv && j < dayDivs.length) {
760 if (dayDivs[j].getAttribute("day") == dayString)
761 parentDiv = dayDivs[j].childNodesWithTag("div")[0];
767 var header = $("calendarHeader");
768 var daysDiv = $(header).childNodesWithTag("div")[1];
769 var dayDivs = $(daysDiv).childNodesWithTag("div");
771 while (!parentDiv && j < dayDivs.length) {
772 if (dayDivs[j].getAttribute("day") == dayString)
773 parentDiv = dayDivs[j];
780 parentDiv.appendChild(eventDiv);
784 function eventClass(cname) {
785 return escape(cname.replace(".", "-"));
789 function newEventDIV(cname, calendar, starts, lasts,
790 startHour, endHour, title) {
791 var eventDiv = document.createElement("div");
792 eventDiv.cname = escape(cname);
793 eventDiv.calendar = calendar;
794 $(eventDiv).addClassName("event");
795 $(eventDiv).addClassName(eventClass(cname));
796 $(eventDiv).addClassName("starts" + starts);
797 $(eventDiv).addClassName("lasts" + lasts);
798 for (var i = 1; i < 5; i++) {
799 var shadowDiv = document.createElement("div");
800 eventDiv.appendChild(shadowDiv);
801 $(shadowDiv).addClassName("shadow");
802 $(shadowDiv).addClassName("shadow" + i);
804 var innerDiv = document.createElement("div");
805 eventDiv.appendChild(innerDiv);
806 $(innerDiv).addClassName("eventInside");
807 $(innerDiv).addClassName("calendarFolder" + calendar);
809 var gradientDiv = document.createElement("div");
810 innerDiv.appendChild(gradientDiv);
811 $(gradientDiv).addClassName("gradient");
812 var gradientImg = document.createElement("img");
813 gradientDiv.appendChild(gradientImg);
814 gradientImg.src = ResourcesURL + "/event-gradient.png";
816 var textDiv = document.createElement("div");
817 innerDiv.appendChild(textDiv);
818 $(textDiv).addClassName("text");
820 var headerSpan = document.createElement("span");
821 textDiv.appendChild(headerSpan);
822 $(headerSpan).addClassName("eventHeader");
823 headerSpan.appendChild(document.createTextNode(startHour + " - "
825 textDiv.appendChild(document.createElement("br"));
827 textDiv.appendChild(document.createTextNode(title));
829 Event.observe(eventDiv, "mousedown", listRowMouseDownHandler);
830 Event.observe(eventDiv, "click",
831 onCalendarSelectEvent.bindAsEventListener(eventDiv));
832 Event.observe(eventDiv, "dblclick",
833 editDoubleClickedEvent.bindAsEventListener(eventDiv));
838 function calendarDisplayCallback(http) {
839 var div = $("calendarView");
841 if (http.readyState == 4
842 && http.status == 200) {
843 document.dayDisplayAjaxRequest = null;
844 div.update(http.responseText);
845 if (http.callbackData["view"])
846 currentView = http.callbackData["view"];
847 if (http.callbackData["day"])
848 currentDay = http.callbackData["day"];
851 if (currentView == "monthview")
852 contentView = $("calendarContent");
854 contentView = $("daysView");
856 refreshCalendarEvents(http.callbackData.scrollEvent);
858 var days = document.getElementsByClassName("day", contentView);
859 if (currentView == "monthview")
860 for (var i = 0; i < days.length; i++) {
861 Event.observe(days[i], "click",
862 onCalendarSelectDay.bindAsEventListener(days[i]));
863 Event.observe(days[i], "dblclick",
864 onClickableCellsDblClick.bindAsEventListener(days[i]));
867 var headerDivs = $("calendarHeader").childNodesWithTag("div");
868 var headerDaysLabels = document.getElementsByClassName("day", headerDivs[0]);
869 var headerDays = document.getElementsByClassName("day", headerDivs[1]);
870 for (var i = 0; i < days.length; i++) {
871 headerDays[i].hour = "allday";
872 Event.observe(headerDaysLabels[i], "mousedown", listRowMouseDownHandler);
873 Event.observe(headerDays[i], "click",
874 onCalendarSelectDay.bindAsEventListener(days[i]));
875 Event.observe(headerDays[i], "dblclick",
876 onClickableCellsDblClick.bindAsEventListener(headerDays[i]));
877 Event.observe(days[i], "click",
878 onCalendarSelectDay.bindAsEventListener(days[i]));
879 var clickableCells = document.getElementsByClassName("clickableHourCell",
881 for (var j = 0; j < clickableCells.length; j++)
882 Event.observe(clickableCells[j], "dblclick",
883 onClickableCellsDblClick.bindAsEventListener(clickableCells[j]));
888 log ("calendarDisplayCallback Ajax error (" + http.readyState + "/" + http.status + ")");
891 function assignCalendar(name) {
892 if (typeof(skycalendar) != "undefined") {
895 node.calendar = new skycalendar(node);
896 node.calendar.setCalendarPage(ResourcesURL + "/skycalendar.html");
897 var dateFormat = node.getAttribute("dateFormat");
899 node.calendar.setDateFormat(dateFormat);
903 function popupCalendar(node) {
904 var nodeId = $(node).readAttribute("inputId");
905 var input = $(nodeId);
906 input.calendar.popup();
911 function onEventContextMenu(event) {
912 var topNode = $("eventsList");
915 var menu = $("eventsListMenu");
917 Event.observe(menu, "hideMenu", onEventContextMenuHide);
918 popupMenu(event, "eventsListMenu", this);
920 var topNode = $("eventsList");
921 var selectedNodes = topNode.getSelectedRows();
922 topNode.menuSelectedRows = selectedNodes;
923 for (var i = 0; i < selectedNodes.length; i++)
924 selectedNodes[i].deselect();
926 topNode.menuSelectedEntry = this;
930 function onEventContextMenuHide(event) {
931 var topNode = $("eventsList");
933 if (topNode.menuSelectedEntry) {
934 topNode.menuSelectedEntry.deselect();
935 topNode.menuSelectedEntry = null;
937 if (topNode.menuSelectedRows) {
938 var nodeIds = topNode.menuSelectedRows;
939 for (var i = 0; i < nodeIds.length; i++) {
940 var node = $(nodeIds[i]);
943 topNode.menuSelectedRows = null;
947 function onEventsSelectionChange() {
948 listOfSelection = this;
949 this.removeClassName("_unfocused");
950 $("tasksList").addClassName("_unfocused");
953 function onTasksSelectionChange() {
954 listOfSelection = this;
955 this.removeClassName("_unfocused");
956 $("eventsList").addClassName("_unfocused");
959 function _loadEventHref(href) {
960 if (document.eventsListAjaxRequest) {
961 document.eventsListAjaxRequest.aborted = true;
962 document.eventsListAjaxRequest.abort();
964 var url = ApplicationBaseURL + "/" + href;
965 document.eventsListAjaxRequest
966 = triggerAjaxRequest(url, eventsListCallback, href);
968 var table = $("eventsList").tBodies[0];
969 while (table.rows.length > 0)
970 table.removeChild(table.rows[0]);
975 function _loadTasksHref(href) {
976 if (document.tasksListAjaxRequest) {
977 document.tasksListAjaxRequest.aborted = true;
978 document.tasksListAjaxRequest.abort();
980 url = ApplicationBaseURL + href;
982 var tasksList = $("tasksList");
985 selectedIds = tasksList.getSelectedNodesId();
988 document.tasksListAjaxRequest
989 = triggerAjaxRequest(url, tasksListCallback, selectedIds);
991 tasksList.previousScroll = tasksList.scrollTop;
992 while (tasksList.childNodes.length)
993 tasksList.removeChild(tasksList.childNodes[0]);
998 function onHeaderClick(event) {
999 //log("onHeaderClick: " + this.link);
1000 //_loadEventHref(this.link);
1002 preventDefault(event);
1005 function refreshCurrentFolder() {
1009 function refreshEvents() {
1011 var value = search["value"];
1012 if (value && value.length)
1013 titleSearch = "&search=" + value;
1017 return _loadEventHref("eventslist?desc=" + sortOrder
1018 + "&sort=" + sortKey
1019 + "&day=" + currentDay
1021 + "&filterpopup=" + listFilter);
1024 function refreshTasks() {
1025 return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
1028 function refreshEventsAndDisplay() {
1030 changeCalendarDisplay();
1033 function onListFilterChange() {
1034 var node = $("filterpopup");
1036 listFilter = node.value;
1037 // log ("listFilter = " + listFilter);
1039 return refreshEvents();
1042 function onEventClick(event) {
1043 changeCalendarDisplay( { "day": this.day,
1044 "scrollEvent": this.getAttribute("id") } );
1045 changeDateSelectorDisplay(this.day);
1047 return onRowClick(event);
1050 function selectMonthInMenu(menu, month) {
1051 var entries = menu.childNodes[1].childNodesWithTag("LI");
1052 for (i = 0; i < entries.length; i++) {
1053 var entry = entries[i];
1054 var entryMonth = entry.getAttribute("month");
1055 if (entryMonth == month)
1056 entry.addClassName("currentMonth");
1058 entry.removeClassName("currentMonth");
1062 function selectYearInMenu(menu, month) {
1063 var entries = menu.childNodes[1].childNodes;
1064 for (i = 0; i < entries.length; i++) {
1065 var entry = entries[i];
1066 if (entry.tagName == "LI") {
1067 var entryMonth = entry.innerHTML;
1068 if (entryMonth == month)
1069 entry.addClassName("currentMonth");
1071 entry.removeClassName("currentMonth");
1076 function popupMonthMenu(event) {
1077 if (event.button == 0) {
1078 var id = this.getAttribute("id");
1079 if (id == "monthLabel")
1080 menuId = "monthListMenu";
1082 menuId = "yearListMenu";
1084 var popup = $(menuId);
1085 if (id == "monthLabel")
1086 selectMonthInMenu(popup, this.getAttribute("month"));
1088 selectYearInMenu(popup, this.innerHTML);
1090 popupToolbarMenu(this, menuId);
1095 function onMonthMenuItemClick(event) {
1096 var month = '' + this.getAttribute("month");
1097 var year = '' + $("yearLabel").innerHTML;
1099 changeDateSelectorDisplay(year + month + "01", true);
1102 function onYearMenuItemClick(event) {
1103 var month = '' + $("monthLabel").getAttribute("month");;
1104 var year = '' + this.innerHTML;
1106 changeDateSelectorDisplay(year + month + "01", true);
1109 function selectCalendarEvent(div) {
1110 // Select event in calendar view
1111 if (selectedCalendarCell)
1112 for (var i = 0; i < selectedCalendarCell.length; i++)
1113 selectedCalendarCell[i].deselect();
1115 for (var i = 0; i < div.siblings.length; i++)
1116 div.siblings[i].select();
1118 selectedCalendarCell = div.siblings;
1121 function onCalendarSelectEvent() {
1122 var list = $("eventsList");
1124 selectCalendarEvent(this);
1126 // Select event in events list
1127 $(list.tBodies[0]).deselectAll();
1128 var row = $(this.cname);
1130 var div = row.parentNode.parentNode.parentNode;
1131 div.scrollTop = row.offsetTop - (div.offsetHeight / 2);
1136 function onCalendarSelectDay(event) {
1138 if (currentView == "multicolumndayview")
1139 day = this.getAttribute("day");
1141 day = this.getAttribute("day");
1142 var needRefresh = (listFilter == 'view_selectedday'
1143 && day != currentDay);
1145 if (currentView == 'weekview')
1146 changeWeekCalendarDisplayOfSelectedDay(this);
1147 else if (currentView == 'monthview')
1148 changeMonthCalendarDisplayOfSelectedDay(this);
1149 changeDateSelectorDisplay(day);
1151 if (listOfSelection) {
1152 listOfSelection.addClassName("_unfocused");
1153 listOfSelection = null;
1160 function changeWeekCalendarDisplayOfSelectedDay(node) {
1161 var days = document.getElementsByClassName("day", node.parentNode);
1162 var headerDiv = $("calendarHeader").childNodesWithTag("div")[1];
1163 var headerDays = document.getElementsByClassName("day", headerDiv);
1165 // log ("days: " + days.length + "; headerDays: " + headerDays.length);
1166 for (var i = 0; i < days.length; i++)
1167 if (days[i] != node) {
1168 // log("unselect day : " + i);
1169 headerDays[i].removeClassName("selectedDay");
1170 days[i].removeClassName("selectedDay");
1173 // log("selected day : " + i);
1174 headerDays[i].addClassName("selectedDay");
1175 days[i].addClassName("selectedDay");
1179 function findMonthCalendarSelectedCell(daysContainer) {
1183 while (!found && i < daysContainer.childNodes.length) {
1184 var currentNode = daysContainer.childNodes[i];
1185 if (currentNode.tagName == 'DIV'
1186 && currentNode.hasClassName("selectedDay")) {
1187 daysContainer.selectedCell = currentNode;
1195 function changeMonthCalendarDisplayOfSelectedDay(node) {
1196 var daysContainer = node.parentNode;
1197 if (!daysContainer.selectedCell)
1198 findMonthCalendarSelectedCell(daysContainer);
1200 if (daysContainer.selectedCell)
1201 daysContainer.selectedCell.removeClassName("selectedDay");
1202 daysContainer.selectedCell = node;
1203 node.addClassName("selectedDay");
1206 function onShowCompletedTasks(event) {
1207 showCompletedTasks = (this.checked ? 1 : 0);
1209 return refreshTasks();
1212 function updateTaskStatus(event) {
1213 var taskId = this.parentNode.getAttribute("id");
1214 var newStatus = (this.checked ? 1 : 0);
1215 var http = createHTTPClient();
1217 if (isSafari() && !isSafari3()) {
1218 newStatus = (newStatus ? 0 : 1);
1221 url = (ApplicationBaseURL + this.parentNode.calendar
1222 + "/" + taskId + "/changeStatus?status=" + newStatus);
1225 // TODO: add parameter to signal that we are only interested in OK
1226 http.open("POST", url, false /* not async */);
1229 if (isHttpStatus204(http.status))
1232 log ("no http client?");
1237 function updateCalendarStatus(event) {
1238 var list = new Array();
1239 var newStatus = (this.checked ? 1 : 0);
1241 if (isSafari() && !isSafari3()) {
1242 newStatus = (newStatus ? 0 : 1);
1243 this.checked = newStatus;
1246 var nodes = $("calendarList").childNodesWithTag("li");
1247 for (var i = 0; i < nodes.length; i++) {
1248 var input = $(nodes[i]).childNodesWithTag("input")[0];
1249 if (input.checked) {
1250 var folderId = nodes[i].getAttribute("id");
1251 var elems = folderId.split(":");
1252 if (elems.length > 1)
1253 list.push(elems[0]);
1255 list.push(UserLogin);
1259 // if (!list.length) {
1260 // list.push(UserLogin);
1261 // nodes[0].childNodesWithTag("input")[0].checked = true;
1264 // ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
1265 // + list.join(",") + "/Calendar/");
1268 var folderID = this.parentNode.getAttribute("id");
1269 var urlstr = URLForFolderID(folderID);
1271 urlstr += "/activateFolder";
1273 urlstr += "/deactivateFolder";
1274 //log("updateCalendarStatus: ajax request = " + urlstr + ", folderID = " + folderID);
1275 triggerAjaxRequest(urlstr, calendarStatusCallback, folderID);
1278 updateCalendarsList();
1281 changeCalendarDisplay();
1287 function calendarStatusCallback(http) {
1288 if (http.readyState == 4) {
1289 if (isHttpStatus204(http.status)) {
1292 changeCalendarDisplay();
1295 var folder = $(http.callbackData);
1296 var input = folder.childNodesWithTag("input")[0];
1297 input.checked = (!input.checked);
1301 log("calendarStatusCallback Ajax error");
1304 function calendarEntryCallback(http) {
1305 if (http.readyState == 4) {
1306 var denied = !isHttpStatus204(http.status);
1307 var entry = $(http.callbackData);
1309 entry.addClassName("denied");
1311 entry.removeClassName("denied");
1315 function updateCalendarsList(method) {
1316 var list = $("calendarList").childNodesWithTag("li");
1317 for (var i = 0; i < list.length; i++) {
1318 var folderID = list[i].getAttribute("id");
1319 var url = URLForFolderID(folderID) + "/canAccessContent";
1320 triggerAjaxRequest(url, calendarEntryCallback, folderID);
1324 function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
1325 var uids = $("uixselector-calendarsList-uidList");
1326 // log("addContact");
1329 var re = new RegExp("(^|,)" + contactId + "($|,)");
1331 if (!re.test(uids.value))
1333 if (uids.value.length > 0)
1334 uids.value += ',' + contactId;
1336 uids.value = contactId;
1337 var names = $("calendarList");
1338 var listElems = names.childNodesWithTag("li");
1339 var colorDef = indexColor(listElems.length);
1340 names.appendChild(userCalendarEntry(contactId, colorDef));
1348 function validateBrowseURL(input) {
1349 var button = $("browseURLBtn");
1351 if (input.value.length) {
1352 if (!button.enabled)
1353 enableAnchor(button);
1354 } else if (!button.disabled)
1355 disableAnchor(button);
1358 function browseURL(anchor, event) {
1359 if (event.button == 0) {
1360 var input = $("url");
1361 var url = input.value;
1363 window.open(url, '_blank');
1369 function onCalendarsMenuPrepareVisibility() {
1370 var folders = $("calendarList");
1371 var selected = folders.getSelectedNodes();
1373 if (selected.length > 0) {
1374 var folderOwner = selected[0].getAttribute("owner");
1375 var sharingOption = $(this).down("ul").childElements().last();
1376 // Disable the "Sharing" option when calendar is not owned by user
1377 if (folderOwner == UserLogin || IsSuperUser)
1378 sharingOption.removeClassName("disabled");
1380 sharingOption.addClassName("disabled");
1384 function getMenus() {
1387 var dateMenu = new Array();
1388 for (var i = 0; i < 12; i++)
1389 dateMenu.push(onMonthMenuItemClick);
1390 menus["monthListMenu"] = dateMenu;
1392 dateMenu = new Array();
1393 for (var i = 0; i < 11; i++)
1394 dateMenu.push(onYearMenuItemClick);
1395 menus["yearListMenu"] = dateMenu;
1397 menus["eventsListMenu"] = new Array(onMenuNewEventClick, "-",
1399 editEvent, deleteEvent, "-",
1402 menus["calendarsMenu"] = new Array(onMenuModify,
1404 onCalendarNew, onCalendarRemove,
1405 "-", null, null, "-",
1406 null, "-", onMenuSharing);
1407 menus["searchMenu"] = new Array(setSearchCriteria);
1409 var calendarsMenu = $("calendarsMenu");
1411 calendarsMenu.prepareVisibility = onCalendarsMenuPrepareVisibility;
1416 function onMenuSharing(event) {
1417 if ($(this).hasClassName("disabled"))
1420 var folders = $("calendarList");
1421 var selected = folders.getSelectedNodes()[0];
1422 /* FIXME: activation of the context menu should preferably select the entry
1423 above which the event has occured */
1425 var folderID = selected.getAttribute("id");
1426 var urlstr = URLForFolderID(folderID) + "/acls";
1428 openAclWindow(urlstr);
1432 function configureDragHandles() {
1433 var handle = $("verticalDragHandle");
1435 handle.addInterface(SOGoDragHandlesInterface);
1436 handle.leftBlock=$("leftPanel");
1437 handle.rightBlock=$("rightPanel");
1440 handle = $("rightDragHandle");
1442 handle.addInterface(SOGoDragHandlesInterface);
1443 handle.upperBlock=$("eventsListView");
1444 handle.lowerBlock=$("calendarView");
1448 function initCalendarSelector() {
1449 var selector = $("calendarSelector");
1450 updateCalendarStatus();
1451 selector.changeNotification = updateCalendarsList;
1453 var list = $("calendarList");
1454 list.multiselect = true;
1455 var items = list.childNodesWithTag("li");
1456 for (var i = 0; i < items.length; i++) {
1457 var input = items[i].childNodesWithTag("input")[0];
1458 Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
1459 Event.observe(items[i], "mousedown", listRowMouseDownHandler);
1460 Event.observe(items[i], "selectstart", listRowMouseDownHandler);
1461 Event.observe(items[i], "click", onRowClick);
1464 var links = $("calendarSelectorButtons").childNodesWithTag("a");
1465 Event.observe(links[0], "click", onCalendarNew);
1466 Event.observe(links[1], "click", onCalendarAdd);
1467 Event.observe(links[2], "click", onCalendarRemove);
1470 function onMenuModify(event) {
1471 var folders = $("calendarList");
1472 var selected = folders.getSelectedNodes()[0];
1474 if (UserLogin == selected.getAttribute("owner")) {
1475 var node = selected.childNodes[selected.childNodes.length - 1];
1476 var currentName = node.nodeValue.trim();
1477 var newName = window.prompt(labels["Name of the Calendar"],
1479 if (newName && newName.length > 0
1480 && newName != currentName) {
1481 var url = (URLForFolderID(selected.getAttribute("id"))
1482 + "/renameFolder?name=" + escape(newName.utf8encode()));
1483 triggerAjaxRequest(url, folderRenameCallback,
1484 {node: node, name: " " + newName});
1487 window.alert(clabels["Unable to rename that folder!"]);
1490 function folderRenameCallback(http) {
1491 if (http.readyState == 4) {
1492 if (isHttpStatus204(http.status)) {
1493 var dict = http.callbackData;
1494 dict["node"].nodeValue = dict["name"];
1499 function onCalendarNew(event) {
1500 createFolder(window.prompt(labels["Name of the Calendar"]),
1502 preventDefault(event);
1505 function onCalendarAdd(event) {
1506 openUserFolderSelector(onFolderSubscribeCB, "calendar");
1507 preventDefault(event);
1510 function appendCalendar(folderName, folderPath) {
1514 owner = getSubscribedFolderOwner(folderPath);
1515 folderPath = accessToSubscribedFolder(folderPath);
1518 folderPath = "/" + folderName;
1523 //log ("append name: " + folderName + "; path: " + folderPath + "; owner: " + owner);
1526 window.alert(clabels["You have already subscribed to that folder!"]);
1528 var calendarList = $("calendarList");
1529 var lis = calendarList.childNodesWithTag("li");
1530 var li = document.createElement("li");
1532 // Add the calendar to the proper place
1533 var previousOwner = null;
1534 for (var i = 0; i < lis.length; i++) {
1535 var currentFolderName = lis[i].lastChild.nodeValue.strip();
1536 var currentOwner = lis[i].readAttribute('owner');
1537 if (currentOwner == owner) {
1538 previousOwner = currentOwner;
1539 if (currentFolderName > folderName)
1542 else if (previousOwner ||
1543 (currentOwner != UserLogin && currentOwner > owner))
1546 if (i != lis.length) // User is subscribed to other calendars of the same owner
1547 calendarList.insertBefore(li, lis[i]);
1549 calendarList.appendChild(li);
1551 li.setAttribute("id", folderPath);
1552 li.setAttribute("owner", owner);
1554 // Generate new color
1555 if (calendarColorIndex == null)
1556 calendarColorIndex = lis.length;
1557 calendarColorIndex++;
1558 var colorTable = [1, 1, 1];
1560 var currentValue = calendarColorIndex;
1562 while (currentValue) {
1563 if (currentValue & 1)
1564 colorTable[index]++;
1570 colorTable[0] = parseInt(255 / colorTable[0]) - 1;
1571 colorTable[1] = parseInt(255 / colorTable[1]) - 1;
1572 colorTable[2] = parseInt(255 / colorTable[2]) - 1;
1575 + colorTable[2].toString(16)
1576 + colorTable[1].toString(16)
1577 + colorTable[0].toString(16);
1578 //log ("color = " + color);
1580 var checkBox = document.createElement("input");
1581 checkBox.setAttribute("type", "checkbox");
1582 li.appendChild(checkBox);
1583 li.appendChild(document.createTextNode(" "));
1584 $(checkBox).addClassName("checkBox");
1586 var colorBox = document.createElement("div");
1587 li.appendChild(colorBox);
1588 li.appendChild(document.createTextNode(folderName));
1589 colorBox.appendChild(document.createTextNode("OO"));
1591 $(colorBox).addClassName("colorBox");
1592 $(colorBox).addClassName('calendarFolder' + folderPath.substr(1));
1594 // Register events (doesn't work with Safari)
1595 Event.observe(li, "mousedown", listRowMouseDownHandler);
1596 Event.observe(li, "selectstart", listRowMouseDownHandler);
1597 Event.observe(li, "click", onRowClick);
1598 Event.observe(checkBox, "click",
1599 updateCalendarStatus.bindAsEventListener(checkBox));
1601 var url = URLForFolderID(folderPath) + "/canAccessContent";
1602 triggerAjaxRequest(url, calendarEntryCallback, folderPath);
1604 // Update CSS for events color
1605 if (!document.styleSheets) return;
1607 var styleElement = document.createElement("style");
1608 styleElement.type = "text/css";
1610 '.calendarFolder' + folderPath.substr(1),
1611 'div.colorBox.calendarFolder' + folderPath.substr(1)
1614 ' { background-color: ' + color + ' !important; }',
1615 ' { color: ' + color + ' !important; }'
1617 for (var i = 0; i < rules.length; i++)
1618 if (styleElement.styleSheet && styleElement.styleSheet.addRule)
1619 styleElement.styleSheet.addRule(selectors[i], rules[i]); // IE
1621 styleElement.appendChild(document.createTextNode(selectors[i] + rules[i])); // Mozilla _+ Safari
1622 document.getElementsByTagName("head")[0].appendChild(styleElement);
1626 function onFolderSubscribeCB(folderData) {
1627 var folder = $(folderData["folder"]);
1629 appendCalendar(folderData["folderName"], folderData["folder"]);
1632 function onFolderUnsubscribeCB(folderId) {
1633 var node = $(folderId);
1634 node.parentNode.removeChild(node);
1635 if (removeFolderRequestCount == 0) {
1638 changeCalendarDisplay();
1642 function onCalendarRemove(event) {
1643 if (removeFolderRequestCount == 0) {
1644 var nodes = $("calendarList").getSelectedNodes();
1645 for (var i = 0; i < nodes.length; i++) {
1646 nodes[i].deselect();
1647 var folderId = nodes[i].getAttribute("id");
1648 var folderIdElements = folderId.split("_");
1649 if (folderIdElements.length > 1) {
1650 unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
1653 deletePersonalCalendar(folderIdElements[0]);
1657 preventDefault(event);
1660 function deletePersonalCalendar(folderElement) {
1661 var folderId = folderElement.substr(1);
1663 = labels["Are you sure you want to delete the calendar \"%{0}\"?"].formatted($(folderElement).lastChild.nodeValue.strip());
1664 if (window.confirm(label)) {
1665 removeFolderRequestCount++;
1666 var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
1667 triggerAjaxRequest(url, deletePersonalCalendarCallback, folderId);
1671 function deletePersonalCalendarCallback(http) {
1672 if (http.readyState == 4) {
1673 if (isHttpStatus204(http.status)) {
1674 var ul = $("calendarList");
1675 var children = ul.childNodesWithTag("li");
1678 while (!done && i < children.length) {
1679 var currentFolderId = children[i].getAttribute("id").substr(1);
1680 if (currentFolderId == http.callbackData) {
1681 ul.removeChild(children[i]);
1687 removeFolderRequestCount--;
1688 if (removeFolderRequestCount == 0) {
1691 changeCalendarDisplay();
1696 log ("ajax problem 5: " + http.status);
1699 function configureLists() {
1700 var list = $("tasksList");
1701 list.multiselect = true;
1702 Event.observe(list, "mousedown",
1703 onTasksSelectionChange.bindAsEventListener(list));
1705 var input = $("showHideCompletedTasks");
1706 Event.observe(input, "click",
1707 onShowCompletedTasks.bindAsEventListener(input));
1709 list = $("eventsList");
1710 list.multiselect = true;
1711 //configureSortableTableHeaders(list);
1712 TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
1713 Event.observe(list, "mousedown",
1714 onEventsSelectionChange.bindAsEventListener(list));
1715 var div = list.parentNode;
1716 Event.observe(div, "contextmenu",
1717 onEventContextMenu.bindAsEventListener(div));
1720 function initDateSelectorEvents() {
1721 var arrow = $("rightArrow");
1722 Event.observe(arrow, "click",
1723 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1724 arrow = $("leftArrow");
1725 Event.observe(arrow, "click",
1726 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1728 var menuButton = $("monthLabel");
1729 Event.observe(menuButton, "click",
1730 popupMonthMenu.bindAsEventListener(menuButton));
1731 menuButton = $("yearLabel");
1732 Event.observe(menuButton, "click",
1733 popupMonthMenu.bindAsEventListener(menuButton));
1736 function initCalendars() {
1737 if (!document.body.hasClassName("popup")) {
1738 initDateSelectorEvents();
1739 initCalendarSelector();
1740 configureSearchField();
1742 var selector = $("calendarSelector");
1744 selector.attachMenu("calendarsMenu");
1748 FastInit.addOnLoad(initCalendars);