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) {
31 var hour = sender.hour;
33 hour = sender.getAttribute("hour");
34 var folder = getSelectedFolder();
35 var folderID = folder.getAttribute("id");
36 var roles = folder.getAttribute("roles");
38 roles = roles.split(",")
39 if ($(roles).indexOf("PublicModifier") < 0)
40 folderID = "/personal";
42 var urlstr = ApplicationBaseURL + folderID + "/new" + type;
43 var params = new Array();
45 params.push("day=" + day);
47 params.push("hm=" + hour);
48 if (params.length > 0)
49 urlstr += "?" + params.join("&");
51 window.open(urlstr, "", "width=490,height=470,resizable=0");
53 return false; /* stop following the link */
56 function getSelectedFolder() {
58 var list = $("calendarList");
59 var nodes = list.getSelectedRows();
63 folder = list.down("li");
68 function onMenuNewEventClick(event) {
69 newEvent(this, "event");
72 function onMenuNewTaskClick(event) {
73 newEvent(this, "task");
76 function _editEventId(id, calendar) {
77 var urlstr = ApplicationBaseURL + "/" + calendar + "/" + id + "/edit";
78 var targetname = "SOGo_edit_" + id;
79 var win = window.open(urlstr, "_blank",
80 "width=490,height=470,resizable=0");
84 function editEvent() {
85 if (listOfSelection) {
86 var nodes = listOfSelection.getSelectedRows();
88 for (var i = 0; i < nodes.length; i++)
89 _editEventId(nodes[i].getAttribute("id"),
91 } else if (selectedCalendarCell) {
92 _editEventId(selectedCalendarCell[0].cname,
93 selectedCalendarCell[0].calendar);
96 return false; /* stop following the link */
99 function _batchDeleteEvents() {
100 var events = eventsToDelete.shift();
101 var calendar = calendarsOfEventsToDelete.shift();
102 var urlstr = (ApplicationBaseURL + "/" + calendar
103 + "/batchDelete?ids=" + events.join('/'));
104 document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
109 function deleteEvent() {
110 if (listOfSelection) {
111 var nodes = listOfSelection.getSelectedRows();
113 if (nodes.length > 0) {
115 if (listOfSelection == $("tasksList"))
116 label = labels["taskDeleteConfirmation"];
118 label = labels["eventDeleteConfirmation"];
120 if (confirm(label)) {
121 if (document.deleteEventAjaxRequest) {
122 document.deleteEventAjaxRequest.aborted = true;
123 document.deleteEventAjaxRequest.abort();
125 var sortedNodes = new Array();
126 var calendars = new Array();
128 for (var i = 0; i < nodes.length; i++) {
129 var calendar = nodes[i].calendar;
130 if (!sortedNodes[calendar]) {
131 sortedNodes[calendar] = new Array();
132 calendars.push(calendar);
134 sortedNodes[calendar].push(nodes[i].cname);
136 for (var i = 0; i < calendars.length; i++) {
137 calendarsOfEventsToDelete.push(calendars[i]);
138 eventsToDelete.push(sortedNodes[calendars[i]]);
140 _batchDeleteEvents();
144 else if (selectedCalendarCell) {
145 var label = labels["eventDeleteConfirmation"];
146 if (confirm(label)) {
147 if (document.deleteEventAjaxRequest) {
148 document.deleteEventAjaxRequest.aborted = true;
149 document.deleteEventAjaxRequest.abort();
151 eventsToDelete.push([selectedCalendarCell[0].cname]);
152 calendarsOfEventsToDelete.push(selectedCalendarCell[0].calendar);
153 _batchDeleteEvents();
157 window.alert("no selection");
162 function modifyEvent(sender, modification) {
163 var currentLocation = '' + window.location;
164 var arr = currentLocation.split("/");
165 arr[arr.length-1] = modification;
167 document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
174 function closeInvitationWindow() {
175 var closeDiv = document.createElement("div");
176 document.body.appendChild(closeDiv);
177 closeDiv.addClassName("javascriptPopupBackground");
179 var closePseudoWin = document.createElement("div");
180 document.body.appendChild(closePseudoWin);
181 closePseudoWin.addClassName("javascriptMessagePseudoTopWindow");
182 closePseudoWin.style.top = "0px;";
183 closePseudoWin.style.left = "0px;";
184 closePseudoWin.style.right = "0px;";
185 closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
187 var calLink = document.createElement("a");
188 closePseudoWin.appendChild(calLink);
189 calLink.href = ApplicationBaseURL;
190 calLink.appendChild(document.createTextNode(labels["Calendar"].toLowerCase()));
193 function modifyEventCallback(http) {
194 if (http.readyState == 4) {
195 if (http.status == 200) {
196 var mailInvitation = queryParameters["mail-invitation"];
197 if (mailInvitation && mailInvitation.toLowerCase() == "yes")
198 closeInvitationWindow();
200 window.opener.setTimeout("refreshEventsAndDisplay();", 100);
201 window.setTimeout("window.close();", 100);
205 // log("showing alert...");
206 window.alert(labels["eventPartStatModificationError"]);
208 document.modifyEventAjaxRequest = null;
212 function deleteEventCallback(http) {
213 if (http.readyState == 4) {
214 if (isHttpStatus204(http.status)) {
215 var nodes = http.callbackData;
216 for (var i = 0; i < nodes.length; i++) {
217 var node = $(nodes[i]);
219 node.parentNode.removeChild(node);
221 if (eventsToDelete.length)
222 _batchDeleteEvents();
224 document.deleteEventAjaxRequest = null;
227 changeCalendarDisplay();
231 log ("deleteEventCallback Ajax error");
235 function editDoubleClickedEvent(event) {
236 _editEventId(this.cname, this.calendar);
238 preventDefault(event);
239 event.cancelBubble = true;
242 function onSelectAll() {
243 var list = $("eventsList");
244 list.selectRowsMatchingClass("eventRow");
249 function onDaySelect(node) {
250 var day = node.getAttribute('day');
251 var needRefresh = (listFilter == 'view_selectedday'
252 && day != currentDay);
254 var td = $(node).getParentWithTagName("td");
255 var table = $(td).getParentWithTagName("table");
257 // log ("table.selected: " + table.selected);
259 if (document.selectedDate)
260 document.selectedDate.deselect();
263 document.selectedDate = td;
265 changeCalendarDisplay( { "day": day } );
272 function onDateSelectorGotoMonth(event) {
273 var day = this.getAttribute("date");
275 changeDateSelectorDisplay(day, true);
280 function onCalendarGotoDay(node) {
281 var day = node.getAttribute("date");
283 changeDateSelectorDisplay(day);
284 changeCalendarDisplay( { "day": day } );
289 function gotoToday() {
290 changeDateSelectorDisplay('');
291 changeCalendarDisplay();
296 function setDateSelectorContent(content) {
297 var div = $("dateSelectorView");
299 div.innerHTML = content;
300 if (currentDay.length > 0)
301 restoreCurrentDaySelection(div);
303 initDateSelectorEvents();
306 function dateSelectorCallback(http) {
307 if (http.readyState == 4
308 && http.status == 200) {
309 document.dateSelectorAjaxRequest = null;
310 var content = http.responseText;
311 setDateSelectorContent(content);
312 cachedDateSelectors[http.callbackData] = content;
315 log ("dateSelectorCallback Ajax error");
318 function eventsListCallback(http) {
319 if (http.readyState == 4
320 && http.status == 200) {
321 var div = $("eventsListView");
323 document.eventsListAjaxRequest = null;
324 var table = $("eventsList");
325 var params = parseQueryParameters(http.callbackData);
326 sortKey = params["sort"];
327 sortOrder = params["desc"];
328 lastClickedRow = -1; // from generic.js
330 if (http.responseText.length > 0) {
331 var data = http.responseText.evalJSON(true);
332 for (var i = 0; i < data.length; i++) {
333 var row = document.createElement("tr");
334 table.tBodies[0].appendChild(row);
335 $(row).addClassName("eventRow");
336 row.setAttribute("id", escape(data[i][0]));
337 row.cname = escape(data[i][0]);
338 row.calendar = data[i][1];
340 var startDate = new Date();
341 startDate.setTime(data[i][4] * 1000);
342 row.day = startDate.getDayString();
343 row.hour = startDate.getHourString();
344 Event.observe(row, "click",
345 onEventClick.bindAsEventListener(row));
346 Event.observe(row, "dblclick",
347 editDoubleClickedEvent.bindAsEventListener(row));
348 Event.observe(row, "contextmenu",
349 onEventContextMenu.bindAsEventListener(row));
351 var td = document.createElement("td");
353 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
354 td.appendChild(document.createTextNode(data[i][3]));
356 td = document.createElement("td");
358 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
359 td.appendChild(document.createTextNode(data[i][8]));
361 td = document.createElement("td");
363 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
364 td.appendChild(document.createTextNode(data[i][9]));
366 td = document.createElement("td");
368 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
369 td.appendChild(document.createTextNode(data[i][6]));
374 log ("eventsListCallback Ajax error");
377 function tasksListCallback(http) {
378 var div = $("tasksListView");
380 if (http.readyState == 4
381 && http.status == 200) {
382 document.tasksListAjaxRequest = null;
383 var list = $("tasksList");
385 if (http.responseText.length > 0) {
386 var data = http.responseText.evalJSON(true);
388 for (var i = 0; i < data.length; i++) {
389 //log(i + " = " + data[i][3]);
390 var listItem = document.createElement("li");
391 list.appendChild(listItem);
392 Event.observe(listItem, "mousedown", listRowMouseDownHandler);
393 Event.observe(listItem, "click", onRowClick);
394 Event.observe(listItem, "dblclick",
395 editDoubleClickedEvent.bindAsEventListener(listItem));
396 listItem.setAttribute("id", data[i][0]);
397 $(listItem).addClassName(data[i][5]);
398 listItem.calendar = data[i][1];
399 $(listItem).addClassName("calendarFolder" + data[i][1]);
400 listItem.cname = escape(data[i][0]);
401 var input = document.createElement("input");
402 input.setAttribute("type", "checkbox");
403 listItem.appendChild(input);
404 Event.observe(input, "click", updateTaskStatus.bindAsEventListener(input), true);
405 input.setAttribute("value", "1");
407 input.setAttribute("checked", "checked");
408 $(input).addClassName("checkBox");
409 listItem.appendChild(document.createTextNode(data[i][3]));
412 list.scrollTop = list.previousScroll;
414 if (http.callbackData) {
415 var selectedNodesId = http.callbackData;
416 for (var i = 0; i < selectedNodesId.length; i++) {
417 // log(selectedNodesId[i] + " (" + i + ") is selected");
418 $(selectedNodesId[i]).select();
422 log ("tasksListCallback: no data");
426 log ("tasksListCallback Ajax error");
429 function restoreCurrentDaySelection(div) {
430 var elements = $(div).getElementsByTagName("a");
433 while (!day && i < elements.length)
435 day = elements[i].day;
440 && day.substr(0, 6) == currentDay.substr(0, 6)) {
441 for (i = 0; i < elements.length; i++) {
442 day = elements[i].day;
443 if (day && day == currentDay) {
444 var td = $(elements[i]).getParentWithTagName("td");
445 if (document.selectedDate)
446 document.selectedDate.deselect();
448 document.selectedDate = td;
454 function changeDateSelectorDisplay(day, keepCurrentDay) {
455 var url = ApplicationBaseURL + "/dateselector";
457 url += "?day=" + day;
459 if (day != currentDay) {
463 var month = day.substr(0, 6);
464 if (cachedDateSelectors[month]) {
465 // log ("restoring cached selector for month: " + month);
466 setDateSelectorContent(cachedDateSelectors[month]);
469 // log ("loading selector for month: " + month);
470 if (document.dateSelectorAjaxRequest) {
471 document.dateSelectorAjaxRequest.aborted = true;
472 document.dateSelectorAjaxRequest.abort();
474 document.dateSelectorAjaxRequest
475 = triggerAjaxRequest(url,
476 dateSelectorCallback,
482 function changeCalendarDisplay(data, newView) {
483 var url = ApplicationBaseURL + "/" + ((newView) ? newView : currentView);
485 selectedCalendarCell = null;
488 var scrollEvent = null;
491 scrollEvent = data['scrollEvent'];
497 url += "?day=" + day;
500 // log ("switching to view: " + newView);
501 // log ("changeCalendarDisplay: " + url);
503 if (document.dayDisplayAjaxRequest) {
504 // log ("aborting day ajaxrq");
505 document.dayDisplayAjaxRequest.aborted = true;
506 document.dayDisplayAjaxRequest.abort();
508 document.dayDisplayAjaxRequest
509 = triggerAjaxRequest(url, calendarDisplayCallback,
512 "scrollEvent": scrollEvent });
517 function _ensureView(view) {
518 if (currentView != view)
519 changeCalendarDisplay(null, view);
524 function onDayOverview() {
525 return _ensureView("dayview");
528 function onMulticolumnDayOverview() {
529 return _ensureView("multicolumndayview");
532 function onWeekOverview() {
533 return _ensureView("weekview");
536 function onMonthOverview() {
537 return _ensureView("monthview");
540 function scrollDayView(scrollEvent) {
542 var daysView = $("daysView");
544 $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div");
546 if (scrollEvent && scrollEvent.siblings) {
547 var classes = scrollEvent.siblings[0].getAttribute("class").split(" ");
548 for (var i = 0; i < classes.length; i++)
549 if (classes[i].startsWith("starts")) {
550 var starts = Math.floor(parseInt(classes[i].substr(6)) / 4);
551 offset = hours[starts].offsetTop;
555 offset = hours[8].offsetTop;
557 daysView.scrollTop = offset - 5;
560 function onClickableCellsDblClick(event) {
561 newEvent(this, 'event');
563 event.cancelBubble = true;
564 event.returnValue = false;
567 function refreshCalendarEvents() {
568 var todayDate = new Date();
571 if (currentView == "dayview") {
575 sd = todayDate.getDayString();
578 else if (currentView == "weekview") {
581 startDate = currentDay.asDate();
583 startDate = todayDate;
584 startDate = startDate.beginOfWeek();
585 sd = startDate.getDayString();
586 var endDate = new Date();
587 endDate.setTime(startDate.getTime());
589 ed = endDate.getDayString();
594 monthDate = currentDay.asDate();
596 monthDate = todayDate;
597 monthDate.setDate(1);
598 sd = monthDate.beginOfWeek().getDayString();
600 var lastMonthDate = new Date();
601 lastMonthDate.setTime(monthDate.getTime());
602 lastMonthDate.setMonth(monthDate.getMonth() + 1);
603 lastMonthDate.addDays(-1);
604 ed = lastMonthDate.endOfWeek().getDayString();
606 if (document.refreshCalendarEventsAjaxRequest) {
607 document.refreshCalendarEventsAjaxRequest.aborted = true;
608 document.refreshCalendarEventsAjaxRequest.abort();
610 var url = ApplicationBaseURL + "/eventslist?sd=" + sd + "&ed=" + ed;
611 document.refreshCalendarEventsAjaxRequest
612 = triggerAjaxRequest(url, refreshCalendarEventsCallback,
613 {"startDate": sd, "endDate": ed});
616 function refreshCalendarEventsCallback(http) {
617 if (http.readyState == 4
618 && http.status == 200) {
620 if (http.responseText.length > 0) {
621 var data = http.responseText.evalJSON(true);
622 // log("refresh calendar events: " + data.length);
623 for (var i = 0; i < data.length; i++)
624 drawCalendarEvent(data[i],
625 http.callbackData["startDate"],
626 http.callbackData["endDate"]);
630 log("AJAX error when refreshing calendar events");
633 function drawCalendarEvent(eventData, sd, ed) {
634 var viewStartDate = sd.asDate();
635 var viewEndDate = ed.asDate();
637 var startDate = new Date();
638 startDate.setTime(eventData[4] * 1000);
639 var endDate = new Date();
640 endDate.setTime(eventData[5] * 1000);
642 // log ("s: " + startDate + "; e: " + endDate);
644 var days = startDate.daysUpTo(endDate);
647 if (currentView == "monthview"
648 && (eventData[7] == 0))
649 title = startDate.getDisplayHoursString() + " " + eventData[3];
651 title = eventData[3];
653 // log("title: " + title);
654 // log("viewS: " + viewStartDate);
655 var startHour = null;
658 var siblings = new Array();
659 for (var i = 0; i < days.length; i++)
660 if (days[i].earlierDate(viewStartDate) == viewStartDate
661 && days[i].laterDate(viewEndDate) == viewEndDate) {
664 // log("day: " + days[i]);
666 var quarters = (startDate.getUTCHours() * 4
667 + Math.floor(startDate.getUTCMinutes() / 15));
669 startHour = startDate.getDisplayHoursString();
670 endHour = endDate.getDisplayHoursString();
677 if (i == days.length - 1) {
678 var quarters = (endDate.getUTCHours() * 4
679 + Math.ceil(endDate.getUTCMinutes() / 15));
684 lasts = ends - starts;
688 var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
690 siblings.push(eventDiv);
691 eventDiv.siblings = siblings;
692 var dayString = days[i].getDayString();
693 // log("day: " + dayString);
694 var parentDiv = null;
695 if (currentView == "monthview") {
696 var dayDivs = $("monthDaysView").childNodesWithTag("div");
698 while (!parentDiv && j < dayDivs.length) {
699 if (dayDivs[j].getAttribute("day") == dayString)
700 parentDiv = dayDivs[j];
706 if (eventData[7] == 0) {
707 var daysView = $("daysView");
708 var eventsDiv = $(daysView).childNodesWithTag("div")[1];
709 var dayDivs = $(eventsDiv).childNodesWithTag("div");
711 while (!parentDiv && j < dayDivs.length) {
712 if (dayDivs[j].getAttribute("day") == dayString)
713 parentDiv = dayDivs[j].childNodesWithTag("div")[0];
719 var header = $("calendarHeader");
720 var daysDiv = $(header).childNodesWithTag("div")[1];
721 var dayDivs = $(daysDiv).childNodesWithTag("div");
723 while (!parentDiv && j < dayDivs.length) {
724 if (dayDivs[j].getAttribute("day") == dayString)
725 parentDiv = dayDivs[j];
732 parentDiv.appendChild(eventDiv);
735 var eventTR = $(eventData[0]);
737 eventTR.siblings = siblings;
740 function newEventDIV(cname, calendar, starts, lasts,
741 startHour, endHour, title) {
742 var eventDiv = document.createElement("div");
743 eventDiv.cname = escape(cname);
744 eventDiv.calendar = calendar;
745 $(eventDiv).addClassName("event");
746 $(eventDiv).addClassName("starts" + starts);
747 $(eventDiv).addClassName("lasts" + lasts);
748 for (var i = 1; i < 5; i++) {
749 var shadowDiv = document.createElement("div");
750 eventDiv.appendChild(shadowDiv);
751 $(shadowDiv).addClassName("shadow");
752 $(shadowDiv).addClassName("shadow" + i);
754 var innerDiv = document.createElement("div");
755 eventDiv.appendChild(innerDiv);
756 $(innerDiv).addClassName("eventInside");
757 $(innerDiv).addClassName("calendarFolder" + calendar);
759 var gradientDiv = document.createElement("div");
760 innerDiv.appendChild(gradientDiv);
761 $(gradientDiv).addClassName("gradient");
762 var gradientImg = document.createElement("img");
763 gradientDiv.appendChild(gradientImg);
764 gradientImg.src = ResourcesURL + "/event-gradient.png";
766 var textDiv = document.createElement("div");
767 innerDiv.appendChild(textDiv);
768 $(textDiv).addClassName("text");
770 var headerSpan = document.createElement("span");
771 textDiv.appendChild(headerSpan);
772 $(headerSpan).addClassName("eventHeader");
773 headerSpan.appendChild(document.createTextNode(startHour + " - "
775 textDiv.appendChild(document.createElement("br"));
777 textDiv.appendChild(document.createTextNode(title));
779 Event.observe(eventDiv, "mousedown", listRowMouseDownHandler);
780 Event.observe(eventDiv, "click",
781 onCalendarSelectEvent.bindAsEventListener(eventDiv));
782 Event.observe(eventDiv, "dblclick",
783 editDoubleClickedEvent.bindAsEventListener(eventDiv));
788 function calendarDisplayCallback(http) {
789 var div = $("calendarView");
791 if (http.readyState == 4
792 && http.status == 200) {
793 document.dayDisplayAjaxRequest = null;
794 div.update(http.responseText);
795 if (http.callbackData["view"])
796 currentView = http.callbackData["view"];
797 if (http.callbackData["day"])
798 currentDay = http.callbackData["day"];
801 if (currentView == "monthview")
802 contentView = $("calendarContent");
804 var scrollEvent = http.callbackData.scrollEvent;
805 scrollDayView($(scrollEvent));
806 contentView = $("daysView");
808 refreshCalendarEvents();
809 var days = document.getElementsByClassName("day", contentView);
810 if (currentView == "monthview")
811 for (var i = 0; i < days.length; i++) {
812 Event.observe(days[i], "click",
813 onCalendarSelectDay.bindAsEventListener(days[i]));
814 Event.observe(days[i], "dblclick",
815 onClickableCellsDblClick.bindAsEventListener(days[i]));
818 var headerDivs = $("calendarHeader").childNodesWithTag("div");
819 var headerDaysLabels = document.getElementsByClassName("day", headerDivs[0]);
820 var headerDays = document.getElementsByClassName("day", headerDivs[1]);
821 for (var i = 0; i < days.length; i++) {
822 headerDays[i].hour = "allday";
823 Event.observe(headerDaysLabels[i], "mousedown", listRowMouseDownHandler);
824 Event.observe(headerDays[i], "click",
825 onCalendarSelectDay.bindAsEventListener(days[i]));
826 Event.observe(headerDays[i], "dblclick",
827 onClickableCellsDblClick.bindAsEventListener(headerDays[i]));
828 Event.observe(days[i], "click",
829 onCalendarSelectDay.bindAsEventListener(days[i]));
830 var clickableCells = document.getElementsByClassName("clickableHourCell",
832 for (var j = 0; j < clickableCells.length; j++)
833 Event.observe(clickableCells[j], "dblclick",
834 onClickableCellsDblClick.bindAsEventListener(clickableCells[j]));
839 log ("calendarDisplayCallback Ajax error (" + http.readyState + "/" + http.status + ")");
842 function assignCalendar(name) {
843 if (typeof(skycalendar) != "undefined") {
846 node.calendar = new skycalendar(node);
847 node.calendar.setCalendarPage(ResourcesURL + "/skycalendar.html");
848 var dateFormat = node.getAttribute("dateFormat");
850 node.calendar.setDateFormat(dateFormat);
854 function popupCalendar(node) {
855 var nodeId = node.getAttribute("inputId");
856 var input = $(nodeId);
857 input.calendar.popup();
862 function onEventContextMenu(event) {
863 var topNode = $("eventsList");
866 var menu = $("eventsListMenu");
868 Event.observe(menu, "hideMenu", onEventContextMenuHide);
869 popupMenu(event, "eventsListMenu", this);
871 var topNode = $("eventsList");
872 var selectedNodes = topNode.getSelectedRows();
873 topNode.menuSelectedRows = selectedNodes;
874 for (var i = 0; i < selectedNodes.length; i++)
875 selectedNodes[i].deselect();
877 topNode.menuSelectedEntry = this;
881 function onEventContextMenuHide(event) {
882 var topNode = $("eventsList");
884 if (topNode.menuSelectedEntry) {
885 topNode.menuSelectedEntry.deselect();
886 topNode.menuSelectedEntry = null;
888 if (topNode.menuSelectedRows) {
889 var nodeIds = topNode.menuSelectedRows;
890 for (var i = 0; i < nodeIds.length; i++) {
891 var node = $(nodeIds[i]);
894 topNode.menuSelectedRows = null;
898 function onEventsSelectionChange() {
899 listOfSelection = this;
900 this.removeClassName("_unfocused");
901 $("tasksList").addClassName("_unfocused");
904 function onTasksSelectionChange() {
905 listOfSelection = this;
906 this.removeClassName("_unfocused");
907 $("eventsList").addClassName("_unfocused");
910 function _loadEventHref(href) {
911 if (document.eventsListAjaxRequest) {
912 document.eventsListAjaxRequest.aborted = true;
913 document.eventsListAjaxRequest.abort();
915 var url = ApplicationBaseURL + "/" + href;
916 document.eventsListAjaxRequest
917 = triggerAjaxRequest(url, eventsListCallback, href);
919 var table = $("eventsList").tBodies[0];
920 while (table.rows.length > 0)
921 table.removeChild(table.rows[0]);
926 function _loadTasksHref(href) {
927 if (document.tasksListAjaxRequest) {
928 document.tasksListAjaxRequest.aborted = true;
929 document.tasksListAjaxRequest.abort();
931 url = ApplicationBaseURL + "/" + href;
933 var tasksList = $("tasksList");
936 selectedIds = tasksList.getSelectedNodesId();
939 document.tasksListAjaxRequest
940 = triggerAjaxRequest(url, tasksListCallback, selectedIds);
942 tasksList.previousScroll = tasksList.scrollTop;
943 while (tasksList.childNodes.length)
944 tasksList.removeChild(tasksList.childNodes[0]);
949 function onHeaderClick(event) {
950 //log("onHeaderClick: " + this.link);
951 //_loadEventHref(this.link);
953 preventDefault(event);
956 function refreshEvents() {
957 return _loadEventHref("eventslist?desc=" + sortOrder
959 + "&day=" + currentDay
960 + "&filterpopup=" + listFilter);
963 function refreshTasks() {
964 return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
967 function refreshEventsAndDisplay() {
969 changeCalendarDisplay();
972 function onListFilterChange() {
973 var node = $("filterpopup");
975 listFilter = node.value;
976 // log ("listFilter = " + listFilter);
978 return refreshEvents();
981 function onEventClick(event) {
982 changeCalendarDisplay( { "day": this.day,
983 "scrollEvent": this.getAttribute("id") } );
984 changeDateSelectorDisplay(this.day);
986 return onRowClick(event);
989 function selectMonthInMenu(menu, month) {
990 var entries = menu.childNodes[1].childNodesWithTag("LI");
991 for (i = 0; i < entries.length; i++) {
992 var entry = entries[i];
993 var entryMonth = entry.getAttribute("month");
994 if (entryMonth == month)
995 entry.addClassName("currentMonth");
997 entry.removeClassName("currentMonth");
1001 function selectYearInMenu(menu, month) {
1002 var entries = menu.childNodes[1].childNodes;
1003 for (i = 0; i < entries.length; i++) {
1004 var entry = entries[i];
1005 if (entry.tagName == "LI") {
1006 var entryMonth = entry.innerHTML;
1007 if (entryMonth == month)
1008 entry.addClassName("currentMonth");
1010 entry.removeClassName("currentMonth");
1015 function popupMonthMenu(event) {
1016 if (event.button == 0) {
1017 var id = this.getAttribute("id");
1018 if (id == "monthLabel")
1019 menuId = "monthListMenu";
1021 menuId = "yearListMenu";
1023 var popup = $(menuId);
1024 if (id == "monthLabel")
1025 selectMonthInMenu(popup, this.getAttribute("month"));
1027 selectYearInMenu(popup, this.innerHTML);
1029 popupToolbarMenu(this, menuId);
1034 function onMonthMenuItemClick(event) {
1035 var month = '' + this.getAttribute("month");
1036 var year = '' + $("yearLabel").innerHTML;
1038 changeDateSelectorDisplay(year + month + "01", true);
1041 function onYearMenuItemClick(event) {
1042 var month = '' + $("monthLabel").getAttribute("month");;
1043 var year = '' + this.innerHTML;
1045 changeDateSelectorDisplay(year + month + "01", true);
1048 function onSearchFormSubmit() {
1049 log ("search not implemented");
1054 function onCalendarSelectEvent() {
1055 var list = $("eventsList");
1056 $(list.tBodies[0]).deselectAll();
1058 if (selectedCalendarCell)
1059 for (var i = 0; i < selectedCalendarCell.length; i++)
1060 selectedCalendarCell[i].deselect();
1062 for (var i = 0; i < this.siblings.length; i++)
1063 this.siblings[i].select();
1064 selectedCalendarCell = this.siblings;
1065 var row = $(this.cname);
1067 var div = row.parentNode.parentNode.parentNode;
1068 div.scrollTop = row.offsetTop - (div.offsetHeight / 2);
1073 function onCalendarSelectDay(event) {
1075 if (currentView == "multicolumndayview")
1076 day = this.getAttribute("day");
1078 day = this.getAttribute("day");
1079 var needRefresh = (listFilter == 'view_selectedday'
1080 && day != currentDay);
1082 if (currentView == 'weekview')
1083 changeWeekCalendarDisplayOfSelectedDay(this);
1084 else if (currentView == 'monthview')
1085 changeMonthCalendarDisplayOfSelectedDay(this);
1086 changeDateSelectorDisplay(day);
1088 if (listOfSelection) {
1089 listOfSelection.addClassName("_unfocused");
1090 listOfSelection = null;
1097 function changeWeekCalendarDisplayOfSelectedDay(node) {
1098 var days = document.getElementsByClassName("day", node.parentNode);
1099 var headerDiv = $("calendarHeader").childNodesWithTag("div")[1];
1100 var headerDays = document.getElementsByClassName("day", headerDiv);
1102 // log ("days: " + days.length + "; headerDays: " + headerDays.length);
1103 for (var i = 0; i < days.length; i++)
1104 if (days[i] != node) {
1105 // log("unselect day : " + i);
1106 headerDays[i].removeClassName("selectedDay");
1107 days[i].removeClassName("selectedDay");
1110 // log("selected day : " + i);
1111 headerDays[i].addClassName("selectedDay");
1112 days[i].addClassName("selectedDay");
1116 function findMonthCalendarSelectedCell(daysContainer) {
1120 while (!found && i < daysContainer.childNodes.length) {
1121 var currentNode = daysContainer.childNodes[i];
1122 if (currentNode.tagName == 'DIV'
1123 && currentNode.hasClassName("selectedDay")) {
1124 daysContainer.selectedCell = currentNode;
1132 function changeMonthCalendarDisplayOfSelectedDay(node) {
1133 var daysContainer = node.parentNode;
1134 if (!daysContainer.selectedCell)
1135 findMonthCalendarSelectedCell(daysContainer);
1137 if (daysContainer.selectedCell)
1138 daysContainer.selectedCell.removeClassName("selectedDay");
1139 daysContainer.selectedCell = node;
1140 node.addClassName("selectedDay");
1143 function onShowCompletedTasks(event) {
1144 showCompletedTasks = (this.checked ? 1 : 0);
1146 return refreshTasks();
1149 function updateTaskStatus(event) {
1150 var taskId = this.parentNode.getAttribute("id");
1151 var newStatus = (this.checked ? 1 : 0);
1152 var http = createHTTPClient();
1154 if (isSafari() && !isSafari3()) {
1155 newStatus = (newStatus ? 0 : 1);
1158 url = (ApplicationBaseURL + "/" + this.parentNode.calendar
1159 + "/" + taskId + "/changeStatus?status=" + newStatus);
1162 // TODO: add parameter to signal that we are only interested in OK
1163 http.open("POST", url, false /* not async */);
1166 if (http.status == 200)
1169 log ("no http client?");
1174 function updateCalendarStatus(event) {
1175 var list = new Array();
1176 var newStatus = (this.checked ? 1 : 0);
1178 if (isSafari() && !isSafari3()) {
1179 newStatus = (newStatus ? 0 : 1);
1180 this.checked = newStatus;
1183 var nodes = $("calendarList").childNodesWithTag("li");
1184 for (var i = 0; i < nodes.length; i++) {
1185 var input = $(nodes[i]).childNodesWithTag("input")[0];
1186 if (input.checked) {
1187 var folderId = nodes[i].getAttribute("id");
1188 var elems = folderId.split(":");
1189 if (elems.length > 1)
1190 list.push(elems[0]);
1192 list.push(UserLogin);
1196 // if (!list.length) {
1197 // list.push(UserLogin);
1198 // nodes[0].childNodesWithTag("input")[0].checked = true;
1201 // ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
1202 // + list.join(",") + "/Calendar/");
1205 var folderID = this.parentNode.getAttribute("id");
1206 var urlstr = URLForFolderID(folderID);
1208 urlstr += "/activateFolder";
1210 urlstr += "/deactivateFolder";
1211 //log("updateCalendarStatus: ajax request = " + urlstr + ", folderID = " + folderID);
1212 triggerAjaxRequest(urlstr, calendarStatusCallback, folderID);
1215 updateCalendarsList();
1218 changeCalendarDisplay();
1224 function calendarStatusCallback(http) {
1225 if (http.readyState == 4) {
1226 if (isHttpStatus204(http.status)) {
1229 changeCalendarDisplay();
1232 var folder = $(http.callbackData);
1233 var input = folder.childNodesWithTag("input")[0];
1234 input.checked = (!input.checked);
1238 log("calendarStatusCallback Ajax error");
1241 function calendarEntryCallback(http) {
1242 if (http.readyState == 4) {
1243 var denied = !isHttpStatus204(http.status);
1244 var entry = $(http.callbackData);
1246 entry.addClassName("denied");
1248 entry.removeClassName("denied");
1252 function updateCalendarsList(method) {
1253 var list = $("calendarList").childNodesWithTag("li");
1254 for (var i = 0; i < list.length; i++) {
1255 var folderID = list[i].getAttribute("id");
1256 var url = URLForFolderID(folderID) + "/canAccessContent";
1257 triggerAjaxRequest(url, calendarEntryCallback, folderID);
1261 function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
1262 var uids = $("uixselector-calendarsList-uidList");
1263 // log("addContact");
1266 var re = new RegExp("(^|,)" + contactId + "($|,)");
1268 if (!re.test(uids.value))
1270 if (uids.value.length > 0)
1271 uids.value += ',' + contactId;
1273 uids.value = contactId;
1274 var names = $("calendarList");
1275 var listElems = names.childNodesWithTag("li");
1276 var colorDef = indexColor(listElems.length);
1277 names.appendChild(userCalendarEntry(contactId, colorDef));
1285 function validateBrowseURL(input) {
1286 var button = $("browseURLBtn");
1288 if (input.value.length) {
1289 if (!button.enabled)
1290 enableAnchor(button);
1291 } else if (!button.disabled)
1292 disableAnchor(button);
1295 function browseURL(anchor, event) {
1296 if (event.button == 0) {
1297 var input = $("url");
1298 var url = input.value;
1300 window.open(url, '_blank');
1306 function getMenus() {
1309 var dateMenu = new Array();
1310 for (var i = 0; i < 12; i++)
1311 dateMenu.push(onMonthMenuItemClick);
1312 menus["monthListMenu"] = dateMenu;
1314 dateMenu = new Array();
1315 for (var i = 0; i < 11; i++)
1316 dateMenu.push(onYearMenuItemClick);
1317 menus["yearListMenu"] = dateMenu;
1319 menus["eventsListMenu"] = new Array(onMenuNewEventClick, "-",
1321 editEvent, deleteEvent, "-",
1324 menus["calendarsMenu"] = new Array(onMenuModify,
1326 onCalendarNew, onCalendarRemove,
1327 "-", null, null, "-",
1328 null, "-", onMenuSharing);
1329 menus["searchMenu"] = new Array(setSearchCriteria);
1334 function onMenuSharing(event) {
1335 var folders = $("calendarList");
1336 var selected = folders.getSelectedNodes()[0];
1337 /* FIXME: activation of the context menu should preferable select the entry
1338 above which the event has occured */
1340 var folderID = selected.getAttribute("id");
1341 var urlstr = URLForFolderID(folderID) + "/acls";
1343 openAclWindow(urlstr);
1347 function configureDragHandles() {
1348 var handle = $("verticalDragHandle");
1350 handle.addInterface(SOGoDragHandlesInterface);
1351 handle.leftBlock=$("leftPanel");
1352 handle.rightBlock=$("rightPanel");
1355 handle = $("rightDragHandle");
1357 handle.addInterface(SOGoDragHandlesInterface);
1358 handle.upperBlock=$("eventsListView");
1359 handle.lowerBlock=$("calendarView");
1363 function initCalendarSelector() {
1364 var selector = $("calendarSelector");
1365 updateCalendarStatus();
1366 selector.changeNotification = updateCalendarsList;
1368 var list = $("calendarList");
1369 list.multiselect = true;
1370 var items = list.childNodesWithTag("li");
1371 for (var i = 0; i < items.length; i++) {
1372 var input = items[i].childNodesWithTag("input")[0];
1373 Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
1374 Event.observe(items[i], "mousedown", listRowMouseDownHandler);
1375 Event.observe(items[i], "selectstart", listRowMouseDownHandler);
1376 Event.observe(items[i], "click", onRowClick);
1379 var links = $("calendarSelectorButtons").childNodesWithTag("a");
1380 Event.observe(links[0], "click", onCalendarNew);
1381 Event.observe(links[1], "click", onCalendarAdd);
1382 Event.observe(links[2], "click", onCalendarRemove);
1385 function onMenuModify(event) {
1386 var folders = $("calendarList");
1387 var selected = folders.getSelectedNodes()[0];
1389 if (UserLogin == selected.getAttribute("owner")) {
1390 var node = selected.childNodes[4];
1391 var currentName = node.nodeValue.trim();
1392 var newName = window.prompt(labels["Name of the Calendar"],
1394 if (newName && newName.length > 0
1395 && newName != currentName) {
1396 var url = (URLForFolderID(selected.getAttribute("id"))
1397 + "/renameFolder?name=" + escape(newName.utf8encode()));
1398 triggerAjaxRequest(url, folderRenameCallback,
1399 {node: node, name: " " + newName});
1402 window.alert(clabels["Unable to rename that folder!"]);
1405 function folderRenameCallback(http) {
1406 if (http.readyState == 4) {
1407 if (isHttpStatus204(http.status)) {
1408 var dict = http.callbackData;
1409 dict["node"].nodeValue = dict["name"];
1414 function onCalendarNew(event) {
1415 createFolder(window.prompt(labels["Name of the Calendar"]),
1417 preventDefault(event);
1420 function onCalendarAdd(event) {
1421 openUserFolderSelector(onFolderSubscribeCB, "calendar");
1422 preventDefault(event);
1425 function appendCalendar(folderName, folderPath) {
1429 owner = getSubscribedFolderOwner(folderPath);
1430 folderPath = accessToSubscribedFolder(folderPath);
1433 folderPath = "/" + folderName;
1438 //log ("append name: " + folderName + "; path: " + folderPath + "; owner: " + owner);
1441 window.alert(clabels["You have already subscribed to that folder!"]);
1443 var calendarList = $("calendarList");
1444 var lis = calendarList.childNodesWithTag("li");
1445 var li = document.createElement("li");
1447 // Add the calendar to the proper place
1448 var previousOwner = null;
1449 for (var i = 0; i < lis.length; i++) {
1450 var currentFolderName = lis[i].lastChild.nodeValue.strip();
1451 var currentOwner = lis[i].readAttribute('owner');
1452 if (currentOwner == owner) {
1453 previousOwner = currentOwner;
1454 if (currentFolderName > folderName)
1457 else if (previousOwner ||
1458 (currentOwner != UserLogin && currentOwner > owner))
1461 if (i != lis.length) // User is subscribed to other calendars of the same owner
1462 calendarList.insertBefore(li, lis[i]);
1464 calendarList.appendChild(li);
1466 li.setAttribute("id", folderPath);
1467 li.setAttribute("owner", owner);
1469 // Generate new color
1470 if (calendarColorIndex == null)
1471 calendarColorIndex = lis.length;
1472 calendarColorIndex++;
1473 var colorTable = [1, 1, 1];
1475 var currentValue = calendarColorIndex;
1477 while (currentValue) {
1478 if (currentValue & 1)
1479 colorTable[index]++;
1485 colorTable[0] = parseInt(255 / colorTable[0]) - 1;
1486 colorTable[1] = parseInt(255 / colorTable[1]) - 1;
1487 colorTable[2] = parseInt(255 / colorTable[2]) - 1;
1490 + colorTable[2].toString(16)
1491 + colorTable[1].toString(16)
1492 + colorTable[0].toString(16);
1493 //log ("color = " + color);
1495 var checkBox = document.createElement("input");
1496 checkBox.setAttribute("type", "checkbox");
1497 li.appendChild(checkBox);
1498 li.appendChild(document.createTextNode(" "));
1499 $(checkBox).addClassName("checkBox");
1501 var colorBox = document.createElement("div");
1502 li.appendChild(colorBox);
1503 li.appendChild(document.createTextNode(folderName));
1504 colorBox.appendChild(document.createTextNode("OO"));
1506 $(colorBox).addClassName("colorBox");
1507 $(colorBox).addClassName('calendarFolder' + folderPath.substr(1));
1509 // Register events (doesn't work with Safari)
1510 Event.observe(li, "mousedown", listRowMouseDownHandler);
1511 Event.observe(li, "selectstart", listRowMouseDownHandler);
1512 Event.observe(li, "click", onRowClick);
1513 Event.observe(checkBox, "click",
1514 updateCalendarStatus.bindAsEventListener(checkBox));
1516 var url = URLForFolderID(folderPath) + "/canAccessContent";
1517 triggerAjaxRequest(url, calendarEntryCallback, folderPath);
1519 // Update CSS for events color
1520 if (!document.styleSheets) return;
1522 var styleElement = document.createElement("style");
1523 styleElement.type = "text/css";
1525 '.calendarFolder' + folderPath.substr(1),
1526 'div.colorBox.calendarFolder' + folderPath.substr(1)
1529 ' { background-color: ' + color + ' !important; }',
1530 ' { color: ' + color + ' !important; }'
1532 for (var i = 0; i < rules.length; i++)
1533 if (styleElement.styleSheet && styleElement.styleSheet.addRule)
1534 styleElement.styleSheet.addRule(selectors[i], rules[i]); // IE
1536 styleElement.appendChild(document.createTextNode(selectors[i] + rules[i])); // Mozilla _+ Safari
1537 document.getElementsByTagName("head")[0].appendChild(styleElement);
1541 function onFolderSubscribeCB(folderData) {
1542 var folder = $(folderData["folder"]);
1544 appendCalendar(folderData["folderName"], folderData["folder"]);
1547 function onFolderUnsubscribeCB(folderId) {
1548 var node = $(folderId);
1549 node.parentNode.removeChild(node);
1550 if (removeFolderRequestCount == 0) {
1553 changeCalendarDisplay();
1557 function onCalendarRemove(event) {
1558 if (removeFolderRequestCount == 0) {
1559 var nodes = $("calendarList").getSelectedNodes();
1560 for (var i = 0; i < nodes.length; i++) {
1561 nodes[i].deselect();
1562 var folderId = nodes[i].getAttribute("id");
1563 var folderIdElements = folderId.split("_");
1564 if (folderIdElements.length > 1) {
1565 unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
1568 deletePersonalCalendar(folderIdElements[0]);
1572 preventDefault(event);
1575 function deletePersonalCalendar(folderElement) {
1576 var folderId = folderElement.substr(1);
1578 = labels["Are you sure you want to delete the calendar \"%{0}\"?"].formatted($(folderElement).lastChild.nodeValue.strip());
1579 if (window.confirm(label)) {
1580 removeFolderRequestCount++;
1581 var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
1582 triggerAjaxRequest(url, deletePersonalCalendarCallback, folderId);
1586 function deletePersonalCalendarCallback(http) {
1587 if (http.readyState == 4) {
1588 if (isHttpStatus204(http.status)) {
1589 var ul = $("calendarList");
1590 var children = ul.childNodesWithTag("li");
1593 while (!done && i < children.length) {
1594 var currentFolderId = children[i].getAttribute("id").substr(1);
1595 if (currentFolderId == http.callbackData) {
1596 ul.removeChild(children[i]);
1602 removeFolderRequestCount--;
1603 if (removeFolderRequestCount == 0) {
1606 changeCalendarDisplay();
1611 log ("ajax problem 5: " + http.status);
1614 function configureLists() {
1615 var list = $("tasksList");
1616 list.multiselect = true;
1617 Event.observe(list, "mousedown",
1618 onTasksSelectionChange.bindAsEventListener(list));
1620 var input = $("showHideCompletedTasks");
1621 Event.observe(input, "click",
1622 onShowCompletedTasks.bindAsEventListener(input));
1624 list = $("eventsList");
1625 list.multiselect = true;
1626 //configureSortableTableHeaders(list);
1627 TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
1628 Event.observe(list, "mousedown",
1629 onEventsSelectionChange.bindAsEventListener(list));
1630 var div = list.parentNode;
1631 Event.observe(div, "contextmenu",
1632 onEventContextMenu.bindAsEventListener(div));
1635 function initDateSelectorEvents() {
1636 var arrow = $("rightArrow");
1637 Event.observe(arrow, "click",
1638 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1639 arrow = $("leftArrow");
1640 Event.observe(arrow, "click",
1641 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1643 var menuButton = $("monthLabel");
1644 Event.observe(menuButton, "click",
1645 popupMonthMenu.bindAsEventListener(menuButton));
1646 menuButton = $("yearLabel");
1647 Event.observe(menuButton, "click",
1648 popupMonthMenu.bindAsEventListener(menuButton));
1651 function initCalendars() {
1652 if (!document.body.hasClassName("popup")) {
1653 initDateSelectorEvents();
1654 initCalendarSelector();
1655 configureSearchField();
1657 var selector = $("calendarSelector");
1659 selector.attachMenu("calendarsMenu");
1663 addEvent(window, 'load', initCalendars);