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");
81 function editEvent() {
82 if (listOfSelection) {
83 var nodes = listOfSelection.getSelectedRows();
85 if (nodes.length == 0) {
86 window.alert(labels["Please select an event or a task."]);
90 for (var i = 0; i < nodes.length; i++)
91 _editEventId(nodes[i].getAttribute("id"),
93 } else if (selectedCalendarCell) {
94 _editEventId(selectedCalendarCell[0].cname,
95 selectedCalendarCell[0].calendar);
97 window.alert(labels["Please select an event or a task."]);
100 return false; /* stop following the link */
103 function _batchDeleteEvents() {
104 var events = eventsToDelete.shift();
105 var calendar = calendarsOfEventsToDelete.shift();
106 var urlstr = (ApplicationBaseURL + "/" + calendar
107 + "/batchDelete?ids=" + events.join('/'));
108 document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr,
113 function deleteEvent() {
114 if (listOfSelection) {
115 var nodes = listOfSelection.getSelectedRows();
117 if (nodes.length > 0) {
119 if (listOfSelection == $("tasksList"))
120 label = labels["taskDeleteConfirmation"];
122 label = labels["eventDeleteConfirmation"];
124 if (confirm(label)) {
125 if (document.deleteEventAjaxRequest) {
126 document.deleteEventAjaxRequest.aborted = true;
127 document.deleteEventAjaxRequest.abort();
129 var sortedNodes = new Array();
130 var calendars = new Array();
132 for (var i = 0; i < nodes.length; i++) {
133 var calendar = nodes[i].calendar;
134 if (!sortedNodes[calendar]) {
135 sortedNodes[calendar] = new Array();
136 calendars.push(calendar);
138 sortedNodes[calendar].push(nodes[i].cname);
140 for (var i = 0; i < calendars.length; i++) {
141 calendarsOfEventsToDelete.push(calendars[i]);
142 eventsToDelete.push(sortedNodes[calendars[i]]);
144 _batchDeleteEvents();
147 window.alert(labels["Please select an event or a task."]);
150 else if (selectedCalendarCell) {
151 var label = labels["eventDeleteConfirmation"];
152 if (confirm(label)) {
153 if (document.deleteEventAjaxRequest) {
154 document.deleteEventAjaxRequest.aborted = true;
155 document.deleteEventAjaxRequest.abort();
157 eventsToDelete.push([selectedCalendarCell[0].cname]);
158 calendarsOfEventsToDelete.push(selectedCalendarCell[0].calendar);
159 _batchDeleteEvents();
163 window.alert(labels["Please select an event or a task."]);
168 function modifyEvent(sender, modification) {
169 var currentLocation = '' + window.location;
170 var arr = currentLocation.split("/");
171 arr[arr.length-1] = modification;
173 document.modifyEventAjaxRequest = triggerAjaxRequest(arr.join("/"),
180 function closeInvitationWindow() {
181 var closeDiv = document.createElement("div");
182 document.body.appendChild(closeDiv);
183 closeDiv.addClassName("javascriptPopupBackground");
185 var closePseudoWin = document.createElement("div");
186 document.body.appendChild(closePseudoWin);
187 closePseudoWin.addClassName("javascriptMessagePseudoTopWindow");
188 closePseudoWin.style.top = "0px;";
189 closePseudoWin.style.left = "0px;";
190 closePseudoWin.style.right = "0px;";
191 closePseudoWin.appendChild(document.createTextNode(labels["closeThisWindowMessage"]));
193 var calLink = document.createElement("a");
194 closePseudoWin.appendChild(calLink);
195 calLink.href = ApplicationBaseURL;
196 calLink.appendChild(document.createTextNode(labels["Calendar"].toLowerCase()));
199 function modifyEventCallback(http) {
200 if (http.readyState == 4) {
201 if (http.status == 200) {
202 var mailInvitation = queryParameters["mail-invitation"];
203 if (mailInvitation && mailInvitation.toLowerCase() == "yes")
204 closeInvitationWindow();
206 window.opener.setTimeout("refreshEventsAndDisplay();", 100);
207 window.setTimeout("window.close();", 100);
211 // log("showing alert...");
212 window.alert(labels["eventPartStatModificationError"]);
214 document.modifyEventAjaxRequest = null;
218 function deleteEventCallback(http) {
219 if (http.readyState == 4) {
220 if (isHttpStatus204(http.status)) {
221 var nodes = http.callbackData;
222 for (var i = 0; i < nodes.length; i++) {
223 var node = $(nodes[i]);
225 node.parentNode.removeChild(node);
227 if (eventsToDelete.length)
228 _batchDeleteEvents();
230 document.deleteEventAjaxRequest = null;
233 changeCalendarDisplay();
237 log ("deleteEventCallback Ajax error");
241 function editDoubleClickedEvent(event) {
242 _editEventId(this.cname, this.calendar);
244 preventDefault(event);
245 event.cancelBubble = true;
248 function onSelectAll() {
249 var list = $("eventsList");
250 list.selectRowsMatchingClass("eventRow");
255 function onDaySelect(node) {
256 var day = node.getAttribute('day');
257 var needRefresh = (listFilter == 'view_selectedday'
258 && day != currentDay);
260 var td = $(node).getParentWithTagName("td");
261 var table = $(td).getParentWithTagName("table");
263 // log ("table.selected: " + table.selected);
265 if (document.selectedDate)
266 document.selectedDate.deselect();
269 document.selectedDate = td;
271 changeCalendarDisplay( { "day": day } );
278 function onDateSelectorGotoMonth(event) {
279 var day = this.getAttribute("date");
281 changeDateSelectorDisplay(day, true);
286 function onCalendarGotoDay(node) {
287 var day = node.getAttribute("date");
289 changeDateSelectorDisplay(day);
290 changeCalendarDisplay( { "day": day } );
295 function gotoToday() {
296 changeDateSelectorDisplay('');
297 changeCalendarDisplay();
302 function setDateSelectorContent(content) {
303 var div = $("dateSelectorView");
305 div.innerHTML = content;
306 if (currentDay.length > 0)
307 restoreCurrentDaySelection(div);
309 initDateSelectorEvents();
312 function dateSelectorCallback(http) {
313 if (http.readyState == 4
314 && http.status == 200) {
315 document.dateSelectorAjaxRequest = null;
316 var content = http.responseText;
317 setDateSelectorContent(content);
318 cachedDateSelectors[http.callbackData] = content;
321 log ("dateSelectorCallback Ajax error");
324 function eventsListCallback(http) {
325 if (http.readyState == 4
326 && http.status == 200) {
327 var div = $("eventsListView");
329 document.eventsListAjaxRequest = null;
330 var table = $("eventsList");
331 var params = parseQueryParameters(http.callbackData);
332 sortKey = params["sort"];
333 sortOrder = params["desc"];
334 lastClickedRow = -1; // from generic.js
336 if (http.responseText.length > 0) {
337 var data = http.responseText.evalJSON(true);
338 for (var i = 0; i < data.length; i++) {
339 var row = document.createElement("tr");
340 table.tBodies[0].appendChild(row);
341 $(row).addClassName("eventRow");
342 row.setAttribute("id", escape(data[i][0]));
343 row.cname = escape(data[i][0]);
344 row.calendar = data[i][1];
346 var startDate = new Date();
347 startDate.setTime(data[i][4] * 1000);
348 row.day = startDate.getDayString();
349 row.hour = startDate.getHourString();
350 Event.observe(row, "mousedown", onRowClick);
351 Event.observe(row, "selectstart", listRowMouseDownHandler);
352 Event.observe(row, "dblclick",
353 editDoubleClickedEvent.bindAsEventListener(row));
354 Event.observe(row, "contextmenu",
355 onEventContextMenu.bindAsEventListener(row));
357 var td = document.createElement("td");
359 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
360 td.appendChild(document.createTextNode(data[i][3]));
362 td = document.createElement("td");
364 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
365 td.appendChild(document.createTextNode(data[i][9]));
367 td = document.createElement("td");
369 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
370 td.appendChild(document.createTextNode(data[i][10]));
372 td = document.createElement("td");
374 Event.observe(td, "mousedown", listRowMouseDownHandler, true);
375 td.appendChild(document.createTextNode(data[i][6]));
380 log ("eventsListCallback Ajax error");
383 function tasksListCallback(http) {
384 var div = $("tasksListView");
386 if (http.readyState == 4
387 && http.status == 200) {
388 document.tasksListAjaxRequest = null;
389 var list = $("tasksList");
391 if (http.responseText.length > 0) {
392 var data = http.responseText.evalJSON(true);
394 for (var i = 0; i < data.length; i++) {
395 var listItem = document.createElement("li");
396 list.appendChild(listItem);
397 Event.observe(listItem, "mousedown", listRowMouseDownHandler);
398 Event.observe(listItem, "click", onRowClick);
399 Event.observe(listItem, "dblclick",
400 editDoubleClickedEvent.bindAsEventListener(listItem));
401 listItem.setAttribute("id", data[i][0]);
402 $(listItem).addClassName(data[i][5]);
403 $(listItem).addClassName(data[i][6]);
404 listItem.calendar = data[i][1];
405 $(listItem).addClassName("calendarFolder" + data[i][1]);
406 listItem.cname = escape(data[i][0]);
407 var input = document.createElement("input");
408 input.setAttribute("type", "checkbox");
409 listItem.appendChild(input);
410 Event.observe(input, "click", updateTaskStatus.bindAsEventListener(input), true);
411 input.setAttribute("value", "1");
413 input.setAttribute("checked", "checked");
414 $(input).addClassName("checkBox");
415 listItem.appendChild(document.createTextNode(data[i][3]));
418 list.scrollTop = list.previousScroll;
420 if (http.callbackData) {
421 var selectedNodesId = http.callbackData;
422 for (var i = 0; i < selectedNodesId.length; i++) {
423 // log(selectedNodesId[i] + " (" + i + ") is selected");
424 $(selectedNodesId[i]).select();
428 log ("tasksListCallback: no data");
432 log ("tasksListCallback Ajax error");
435 function restoreCurrentDaySelection(div) {
436 var elements = $(div).getElementsByTagName("a");
439 while (!day && i < elements.length)
441 day = elements[i].day;
446 && day.substr(0, 6) == currentDay.substr(0, 6)) {
447 for (i = 0; i < elements.length; i++) {
448 day = elements[i].day;
449 if (day && day == currentDay) {
450 var td = $(elements[i]).getParentWithTagName("td");
451 if (document.selectedDate)
452 document.selectedDate.deselect();
454 document.selectedDate = td;
460 function changeDateSelectorDisplay(day, keepCurrentDay) {
461 var url = ApplicationBaseURL + "dateselector";
463 url += "?day=" + day;
465 if (day != currentDay) {
469 var month = day.substr(0, 6);
470 if (cachedDateSelectors[month]) {
471 // log ("restoring cached selector for month: " + month);
472 setDateSelectorContent(cachedDateSelectors[month]);
475 // log ("loading selector for month: " + month);
476 if (document.dateSelectorAjaxRequest) {
477 document.dateSelectorAjaxRequest.aborted = true;
478 document.dateSelectorAjaxRequest.abort();
480 document.dateSelectorAjaxRequest
481 = triggerAjaxRequest(url,
482 dateSelectorCallback,
488 function changeCalendarDisplay(data, newView) {
489 var url = ApplicationBaseURL + ((newView) ? newView : currentView);
491 var scrollEvent = null;
495 scrollEvent = data['scrollEvent'];
503 var divs = $$('div.day[day='+day+']');
505 // Don't reload the view if the event is present in current view
507 // Deselect previous day
508 var selectedDivs = $$('div.day.selectedDay');
509 selectedDivs.each(function(div) {
510 div.removeClassName('selectedDay');
514 divs.each(function(div) {
515 div.addClassName('selectedDay');
518 // Deselect day in date selector
519 if (document.selectedDate)
520 document.selectedDate.deselect();
522 // Select day in date selector
523 var selectedLink = $$('table#dateSelectorTable a[day='+day+']');
524 if (selectedLink.length > 0) {
525 selectedCell = selectedLink[0].up(1);
526 selectedCell.select();
527 document.selectedDate = selectedCell;
531 scrollDayView(scrollEvent);
536 url += "?day=" + day;
539 // log ("switching to view: " + newView);
540 // log ("changeCalendarDisplay: " + url);
542 selectedCalendarCell = null;
544 if (document.dayDisplayAjaxRequest) {
545 // log ("aborting day ajaxrq");
546 document.dayDisplayAjaxRequest.aborted = true;
547 document.dayDisplayAjaxRequest.abort();
549 document.dayDisplayAjaxRequest
550 = triggerAjaxRequest(url, calendarDisplayCallback,
553 "scrollEvent": scrollEvent });
558 function _ensureView(view) {
559 if (currentView != view)
560 changeCalendarDisplay(null, view);
565 function onDayOverview() {
566 return _ensureView("dayview");
569 function onMulticolumnDayOverview() {
570 return _ensureView("multicolumndayview");
573 function onWeekOverview() {
574 return _ensureView("weekview");
577 function onMonthOverview() {
578 return _ensureView("monthview");
581 function scrollDayView(scrollEvent) {
584 // Select event in calendar view
586 divs = $$("div#calendarContent div." + eventClass(scrollEvent));
587 selectCalendarEvent(divs[0]);
590 // Don't scroll if in month view
591 if (currentView == "monthview")
595 var daysView = $("daysView");
597 $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div");
600 divs = $$("div#calendarContent div." + eventClass(scrollEvent));
601 var classes = $w(divs[0].className);
602 for (var i = 0; i < classes.length; i++) {
603 if (classes[i].startsWith("starts")) {
604 var starts = Math.floor(parseInt(classes[i].substr(6)) / 4);
605 offset = hours[starts].offsetTop;
611 offset = hours[8].offsetTop;
613 daysView.scrollTop = offset - 5;
616 function onClickableCellsDblClick(event) {
617 newEvent(this, 'event');
619 event.cancelBubble = true;
620 event.returnValue = false;
623 function refreshCalendarEvents(scrollEvent) {
624 var todayDate = new Date();
627 if (currentView == "dayview") {
631 sd = todayDate.getDayString();
634 else if (currentView == "weekview") {
637 startDate = currentDay.asDate();
639 startDate = todayDate;
640 startDate = startDate.beginOfWeek();
641 sd = startDate.getDayString();
642 var endDate = new Date();
643 endDate.setTime(startDate.getTime());
645 ed = endDate.getDayString();
650 monthDate = currentDay.asDate();
652 monthDate = todayDate;
653 monthDate.setDate(1);
654 sd = monthDate.beginOfWeek().getDayString();
656 var lastMonthDate = new Date();
657 lastMonthDate.setTime(monthDate.getTime());
658 lastMonthDate.setMonth(monthDate.getMonth() + 1);
659 lastMonthDate.addDays(-1);
660 ed = lastMonthDate.endOfWeek().getDayString();
662 if (document.refreshCalendarEventsAjaxRequest) {
663 document.refreshCalendarEventsAjaxRequest.aborted = true;
664 document.refreshCalendarEventsAjaxRequest.abort();
666 var url = ApplicationBaseURL + "eventslist?sd=" + sd + "&ed=" + ed;
667 document.refreshCalendarEventsAjaxRequest
668 = triggerAjaxRequest(url, refreshCalendarEventsCallback,
669 {"startDate": sd, "endDate": ed,
670 "scrollEvent": scrollEvent});
673 function refreshCalendarEventsCallback(http) {
674 if (http.readyState == 4
675 && http.status == 200) {
677 if (http.responseText.length > 0) {
678 var data = http.responseText.evalJSON(true);
679 // log("refresh calendar events: " + data.length);
680 for (var i = 0; i < data.length; i++)
681 drawCalendarEvent(data[i],
682 http.callbackData["startDate"],
683 http.callbackData["endDate"]);
685 scrollDayView(http.callbackData["scrollEvent"]);
688 log("AJAX error when refreshing calendar events");
691 function drawCalendarEvent(eventData, sd, ed) {
692 var viewStartDate = sd.asDate();
693 var viewEndDate = ed.asDate();
695 var startDate = new Date();
696 startDate.setTime(eventData[4] * 1000);
697 var endDate = new Date();
698 endDate.setTime(eventData[5] * 1000);
700 // log ("s: " + startDate + "; e: " + endDate);
702 var days = startDate.daysUpTo(endDate);
705 if (currentView == "monthview"
706 && (eventData[7] == 0))
707 title = startDate.getDisplayHoursString() + " " + eventData[3];
709 title = eventData[3];
711 // log("title: " + title);
712 // log("viewS: " + viewStartDate);
713 var startHour = null;
716 var siblings = new Array();
717 for (var i = 0; i < days.length; i++)
718 if (days[i].earlierDate(viewStartDate) == viewStartDate
719 && days[i].laterDate(viewEndDate) == viewEndDate) {
722 // log("day: " + days[i]);
724 var quarters = (startDate.getUTCHours() * 4
725 + Math.floor(startDate.getUTCMinutes() / 15));
727 startHour = startDate.getDisplayHoursString();
728 endHour = endDate.getDisplayHoursString();
735 if (i == days.length - 1) {
736 var quarters = (endDate.getUTCHours() * 4
737 + Math.ceil(endDate.getUTCMinutes() / 15));
742 lasts = ends - starts;
746 var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts,
748 siblings.push(eventDiv);
749 eventDiv.siblings = siblings;
750 var dayString = days[i].getDayString();
751 // log("day: " + dayString);
752 var parentDiv = null;
753 if (currentView == "monthview") {
754 var dayDivs = $("monthDaysView").childNodesWithTag("div");
756 while (!parentDiv && j < dayDivs.length) {
757 if (dayDivs[j].getAttribute("day") == dayString)
758 parentDiv = dayDivs[j];
764 if (eventData[7] == 0) {
765 var daysView = $("daysView");
766 var eventsDiv = $(daysView).childNodesWithTag("div")[1];
767 var dayDivs = $(eventsDiv).childNodesWithTag("div");
769 while (!parentDiv && j < dayDivs.length) {
770 if (dayDivs[j].getAttribute("day") == dayString)
771 parentDiv = dayDivs[j].childNodesWithTag("div")[0];
777 var header = $("calendarHeader");
778 var daysDiv = $(header).childNodesWithTag("div")[1];
779 var dayDivs = $(daysDiv).childNodesWithTag("div");
781 while (!parentDiv && j < dayDivs.length) {
782 if (dayDivs[j].getAttribute("day") == dayString)
783 parentDiv = dayDivs[j];
790 parentDiv.appendChild(eventDiv);
794 function eventClass(cname) {
795 return escape(cname.replace(".", "-"));
799 function newEventDIV(cname, calendar, starts, lasts,
800 startHour, endHour, title) {
801 var eventDiv = document.createElement("div");
802 eventDiv.cname = escape(cname);
803 eventDiv.calendar = calendar;
804 $(eventDiv).addClassName("event");
805 $(eventDiv).addClassName(eventClass(cname));
806 $(eventDiv).addClassName("starts" + starts);
807 $(eventDiv).addClassName("lasts" + lasts);
808 for (var i = 1; i < 5; i++) {
809 var shadowDiv = document.createElement("div");
810 eventDiv.appendChild(shadowDiv);
811 $(shadowDiv).addClassName("shadow");
812 $(shadowDiv).addClassName("shadow" + i);
814 var innerDiv = document.createElement("div");
815 eventDiv.appendChild(innerDiv);
816 $(innerDiv).addClassName("eventInside");
817 $(innerDiv).addClassName("calendarFolder" + calendar);
819 var gradientDiv = document.createElement("div");
820 innerDiv.appendChild(gradientDiv);
821 $(gradientDiv).addClassName("gradient");
822 var gradientImg = document.createElement("img");
823 gradientDiv.appendChild(gradientImg);
824 gradientImg.src = ResourcesURL + "/event-gradient.png";
826 var textDiv = document.createElement("div");
827 innerDiv.appendChild(textDiv);
828 $(textDiv).addClassName("text");
830 var headerSpan = document.createElement("span");
831 textDiv.appendChild(headerSpan);
832 $(headerSpan).addClassName("eventHeader");
833 headerSpan.appendChild(document.createTextNode(startHour + " - "
835 textDiv.appendChild(document.createElement("br"));
837 textDiv.appendChild(document.createTextNode(title));
839 Event.observe(eventDiv, "mousedown", listRowMouseDownHandler);
840 Event.observe(eventDiv, "click",
841 onCalendarSelectEvent.bindAsEventListener(eventDiv));
842 Event.observe(eventDiv, "dblclick",
843 editDoubleClickedEvent.bindAsEventListener(eventDiv));
848 function calendarDisplayCallback(http) {
849 var div = $("calendarView");
851 if (http.readyState == 4
852 && http.status == 200) {
853 document.dayDisplayAjaxRequest = null;
854 div.update(http.responseText);
855 if (http.callbackData["view"])
856 currentView = http.callbackData["view"];
857 if (http.callbackData["day"])
858 currentDay = http.callbackData["day"];
861 if (currentView == "monthview")
862 contentView = $("calendarContent");
864 contentView = $("daysView");
866 refreshCalendarEvents(http.callbackData.scrollEvent);
868 var days = document.getElementsByClassName("day", contentView);
869 if (currentView == "monthview")
870 for (var i = 0; i < days.length; i++) {
871 Event.observe(days[i], "click",
872 onCalendarSelectDay.bindAsEventListener(days[i]));
873 Event.observe(days[i], "dblclick",
874 onClickableCellsDblClick.bindAsEventListener(days[i]));
877 var headerDivs = $("calendarHeader").childNodesWithTag("div");
878 var headerDaysLabels = document.getElementsByClassName("day", headerDivs[0]);
879 var headerDays = document.getElementsByClassName("day", headerDivs[1]);
880 for (var i = 0; i < days.length; i++) {
881 headerDays[i].hour = "allday";
882 Event.observe(headerDaysLabels[i], "mousedown", listRowMouseDownHandler);
883 Event.observe(headerDays[i], "click",
884 onCalendarSelectDay.bindAsEventListener(days[i]));
885 Event.observe(headerDays[i], "dblclick",
886 onClickableCellsDblClick.bindAsEventListener(headerDays[i]));
887 Event.observe(days[i], "click",
888 onCalendarSelectDay.bindAsEventListener(days[i]));
889 var clickableCells = document.getElementsByClassName("clickableHourCell",
891 for (var j = 0; j < clickableCells.length; j++)
892 Event.observe(clickableCells[j], "dblclick",
893 onClickableCellsDblClick.bindAsEventListener(clickableCells[j]));
898 log ("calendarDisplayCallback Ajax error (" + http.readyState + "/" + http.status + ")");
901 function assignCalendar(name) {
902 if (typeof(skycalendar) != "undefined") {
905 node.calendar = new skycalendar(node);
906 node.calendar.setCalendarPage(ResourcesURL + "/skycalendar.html");
907 var dateFormat = node.getAttribute("dateFormat");
909 node.calendar.setDateFormat(dateFormat);
913 function popupCalendar(node) {
914 var nodeId = $(node).readAttribute("inputId");
915 var input = $(nodeId);
916 input.calendar.popup();
921 function onEventContextMenu(event) {
922 var topNode = $("eventsList");
923 var menu = $("eventsListMenu");
925 Event.observe(menu, "hideMenu", onEventContextMenuHide);
926 popupMenu(event, "eventsListMenu", this);
929 function onEventContextMenuHide(event) {
930 var topNode = $("eventsList");
932 if (topNode.menuSelectedEntry) {
933 topNode.menuSelectedEntry.deselect();
934 topNode.menuSelectedEntry = null;
938 function onEventsSelectionChange() {
939 listOfSelection = this;
940 this.removeClassName("_unfocused");
941 $("tasksList").addClassName("_unfocused");
943 var rows = this.tBodies[0].getSelectedNodes();
944 if (rows.length == 1) {
946 changeCalendarDisplay( { "day": row.day,
947 "scrollEvent": row.getAttribute("id") } );
948 changeDateSelectorDisplay(row.day);
952 function onTasksSelectionChange() {
953 listOfSelection = this;
954 this.removeClassName("_unfocused");
955 $("eventsList").addClassName("_unfocused");
958 function _loadEventHref(href) {
959 if (document.eventsListAjaxRequest) {
960 document.eventsListAjaxRequest.aborted = true;
961 document.eventsListAjaxRequest.abort();
963 var url = ApplicationBaseURL + "/" + href;
964 document.eventsListAjaxRequest
965 = triggerAjaxRequest(url, eventsListCallback, href);
967 var table = $("eventsList").tBodies[0];
968 while (table.rows.length > 0)
969 table.removeChild(table.rows[0]);
974 function _loadTasksHref(href) {
975 if (document.tasksListAjaxRequest) {
976 document.tasksListAjaxRequest.aborted = true;
977 document.tasksListAjaxRequest.abort();
979 url = ApplicationBaseURL + href;
981 var tasksList = $("tasksList");
984 selectedIds = tasksList.getSelectedNodesId();
987 document.tasksListAjaxRequest
988 = triggerAjaxRequest(url, tasksListCallback, selectedIds);
990 tasksList.previousScroll = tasksList.scrollTop;
991 while (tasksList.childNodes.length)
992 tasksList.removeChild(tasksList.childNodes[0]);
997 function onHeaderClick(event) {
998 //log("onHeaderClick: " + this.link);
999 //_loadEventHref(this.link);
1001 preventDefault(event);
1004 function refreshCurrentFolder() {
1008 function refreshEvents() {
1010 var value = search["value"];
1011 if (value && value.length)
1012 titleSearch = "&search=" + value;
1016 return _loadEventHref("eventslist?desc=" + sortOrder
1017 + "&sort=" + sortKey
1018 + "&day=" + currentDay
1020 + "&filterpopup=" + listFilter);
1023 function refreshTasks() {
1024 return _loadTasksHref("taskslist?show-completed=" + showCompletedTasks);
1027 function refreshEventsAndDisplay() {
1029 changeCalendarDisplay();
1032 function onListFilterChange() {
1033 var node = $("filterpopup");
1035 listFilter = node.value;
1036 // log ("listFilter = " + listFilter);
1038 return refreshEvents();
1041 function selectMonthInMenu(menu, month) {
1042 var entries = menu.childNodes[1].childNodesWithTag("LI");
1043 for (i = 0; i < entries.length; i++) {
1044 var entry = entries[i];
1045 var entryMonth = entry.getAttribute("month");
1046 if (entryMonth == month)
1047 entry.addClassName("currentMonth");
1049 entry.removeClassName("currentMonth");
1053 function selectYearInMenu(menu, month) {
1054 var entries = menu.childNodes[1].childNodes;
1055 for (i = 0; i < entries.length; i++) {
1056 var entry = entries[i];
1057 if (entry.tagName == "LI") {
1058 var entryMonth = entry.innerHTML;
1059 if (entryMonth == month)
1060 entry.addClassName("currentMonth");
1062 entry.removeClassName("currentMonth");
1067 function popupMonthMenu(event) {
1068 if (event.button == 0) {
1069 var id = this.getAttribute("id");
1070 if (id == "monthLabel")
1071 menuId = "monthListMenu";
1073 menuId = "yearListMenu";
1075 var popup = $(menuId);
1076 if (id == "monthLabel")
1077 selectMonthInMenu(popup, this.getAttribute("month"));
1079 selectYearInMenu(popup, this.innerHTML);
1081 popupToolbarMenu(this, menuId);
1086 function onMonthMenuItemClick(event) {
1087 var month = '' + this.getAttribute("month");
1088 var year = '' + $("yearLabel").innerHTML;
1090 changeDateSelectorDisplay(year + month + "01", true);
1093 function onYearMenuItemClick(event) {
1094 var month = '' + $("monthLabel").getAttribute("month");;
1095 var year = '' + this.innerHTML;
1097 changeDateSelectorDisplay(year + month + "01", true);
1100 function selectCalendarEvent(div) {
1101 // Select event in calendar view
1102 if (selectedCalendarCell)
1103 for (var i = 0; i < selectedCalendarCell.length; i++)
1104 selectedCalendarCell[i].deselect();
1106 for (var i = 0; i < div.siblings.length; i++)
1107 div.siblings[i].select();
1109 selectedCalendarCell = div.siblings;
1112 function onCalendarSelectEvent() {
1113 var list = $("eventsList");
1115 selectCalendarEvent(this);
1117 // Select event in events list
1118 $(list.tBodies[0]).deselectAll();
1119 var row = $(this.cname);
1121 var div = row.parentNode.parentNode.parentNode;
1122 div.scrollTop = row.offsetTop - (div.offsetHeight / 2);
1127 function onCalendarSelectDay(event) {
1129 if (currentView == "multicolumndayview")
1130 day = this.getAttribute("day");
1132 day = this.getAttribute("day");
1133 var needRefresh = (listFilter == 'view_selectedday'
1134 && day != currentDay);
1136 if (currentView == 'weekview')
1137 changeWeekCalendarDisplayOfSelectedDay(this);
1138 else if (currentView == 'monthview')
1139 changeMonthCalendarDisplayOfSelectedDay(this);
1140 changeDateSelectorDisplay(day);
1142 if (listOfSelection) {
1143 listOfSelection.addClassName("_unfocused");
1144 listOfSelection = null;
1151 function changeWeekCalendarDisplayOfSelectedDay(node) {
1152 var days = document.getElementsByClassName("day", node.parentNode);
1153 var headerDiv = $("calendarHeader").childNodesWithTag("div")[1];
1154 var headerDays = document.getElementsByClassName("day", headerDiv);
1156 // log ("days: " + days.length + "; headerDays: " + headerDays.length);
1157 for (var i = 0; i < days.length; i++)
1158 if (days[i] != node) {
1159 // log("unselect day : " + i);
1160 headerDays[i].removeClassName("selectedDay");
1161 days[i].removeClassName("selectedDay");
1164 // log("selected day : " + i);
1165 headerDays[i].addClassName("selectedDay");
1166 days[i].addClassName("selectedDay");
1170 function findMonthCalendarSelectedCell(daysContainer) {
1174 while (!found && i < daysContainer.childNodes.length) {
1175 var currentNode = daysContainer.childNodes[i];
1176 if (currentNode.tagName == 'DIV'
1177 && currentNode.hasClassName("selectedDay")) {
1178 daysContainer.selectedCell = currentNode;
1186 function changeMonthCalendarDisplayOfSelectedDay(node) {
1187 var daysContainer = node.parentNode;
1188 if (!daysContainer.selectedCell)
1189 findMonthCalendarSelectedCell(daysContainer);
1191 if (daysContainer.selectedCell)
1192 daysContainer.selectedCell.removeClassName("selectedDay");
1193 daysContainer.selectedCell = node;
1194 node.addClassName("selectedDay");
1197 function onShowCompletedTasks(event) {
1198 showCompletedTasks = (this.checked ? 1 : 0);
1200 return refreshTasks();
1203 function updateTaskStatus(event) {
1204 var taskId = this.parentNode.getAttribute("id");
1205 var newStatus = (this.checked ? 1 : 0);
1206 var http = createHTTPClient();
1208 if (isSafari() && !isSafari3()) {
1209 newStatus = (newStatus ? 0 : 1);
1212 url = (ApplicationBaseURL + this.parentNode.calendar
1213 + "/" + taskId + "/changeStatus?status=" + newStatus);
1216 // TODO: add parameter to signal that we are only interested in OK
1217 http.open("POST", url, false /* not async */);
1220 if (isHttpStatus204(http.status))
1223 log ("no http client?");
1228 function updateCalendarStatus(event) {
1229 var list = new Array();
1230 var newStatus = (this.checked ? 1 : 0);
1232 if (isSafari() && !isSafari3()) {
1233 newStatus = (newStatus ? 0 : 1);
1234 this.checked = newStatus;
1237 var nodes = $("calendarList").childNodesWithTag("li");
1238 for (var i = 0; i < nodes.length; i++) {
1239 var input = $(nodes[i]).childNodesWithTag("input")[0];
1240 if (input.checked) {
1241 var folderId = nodes[i].getAttribute("id");
1242 var elems = folderId.split(":");
1243 if (elems.length > 1)
1244 list.push(elems[0]);
1246 list.push(UserLogin);
1250 // if (!list.length) {
1251 // list.push(UserLogin);
1252 // nodes[0].childNodesWithTag("input")[0].checked = true;
1255 // ApplicationBaseURL = (UserFolderURL + "Groups/_custom_"
1256 // + list.join(",") + "/Calendar/");
1259 var folderID = this.parentNode.getAttribute("id");
1260 var urlstr = URLForFolderID(folderID);
1262 urlstr += "/activateFolder";
1264 urlstr += "/deactivateFolder";
1265 //log("updateCalendarStatus: ajax request = " + urlstr + ", folderID = " + folderID);
1266 triggerAjaxRequest(urlstr, calendarStatusCallback, folderID);
1269 updateCalendarsList();
1272 changeCalendarDisplay();
1278 function calendarStatusCallback(http) {
1279 if (http.readyState == 4) {
1280 if (isHttpStatus204(http.status)) {
1283 changeCalendarDisplay();
1286 var folder = $(http.callbackData);
1287 var input = folder.childNodesWithTag("input")[0];
1288 input.checked = (!input.checked);
1292 log("calendarStatusCallback Ajax error");
1295 function calendarEntryCallback(http) {
1296 if (http.readyState == 4) {
1297 var denied = !isHttpStatus204(http.status);
1298 var entry = $(http.callbackData);
1300 entry.addClassName("denied");
1302 entry.removeClassName("denied");
1306 function updateCalendarsList(method) {
1307 var list = $("calendarList").childNodesWithTag("li");
1308 for (var i = 0; i < list.length; i++) {
1309 var folderID = list[i].getAttribute("id");
1310 var url = URLForFolderID(folderID) + "/canAccessContent";
1311 triggerAjaxRequest(url, calendarEntryCallback, folderID);
1315 function addContact(tag, fullContactName, contactId, contactName, contactEmail) {
1316 var uids = $("uixselector-calendarsList-uidList");
1317 // log("addContact");
1320 var re = new RegExp("(^|,)" + contactId + "($|,)");
1322 if (!re.test(uids.value))
1324 if (uids.value.length > 0)
1325 uids.value += ',' + contactId;
1327 uids.value = contactId;
1328 var names = $("calendarList");
1329 var listElems = names.childNodesWithTag("li");
1330 var colorDef = indexColor(listElems.length);
1331 names.appendChild(userCalendarEntry(contactId, colorDef));
1339 function validateBrowseURL(input) {
1340 var button = $("browseURLBtn");
1342 if (input.value.length) {
1343 if (!button.enabled)
1344 enableAnchor(button);
1345 } else if (!button.disabled)
1346 disableAnchor(button);
1349 function browseURL(anchor, event) {
1350 if (event.button == 0) {
1351 var input = $("url");
1352 var url = input.value;
1354 window.open(url, '_blank');
1360 function onCalendarsMenuPrepareVisibility() {
1361 var folders = $("calendarList");
1362 var selected = folders.getSelectedNodes();
1364 if (selected.length > 0) {
1365 var folderOwner = selected[0].getAttribute("owner");
1366 var sharingOption = $(this).down("ul").childElements().last();
1367 // Disable the "Sharing" option when calendar is not owned by user
1368 if (folderOwner == UserLogin || IsSuperUser)
1369 sharingOption.removeClassName("disabled");
1371 sharingOption.addClassName("disabled");
1375 function getMenus() {
1378 var dateMenu = new Array();
1379 for (var i = 0; i < 12; i++)
1380 dateMenu.push(onMonthMenuItemClick);
1381 menus["monthListMenu"] = dateMenu;
1383 dateMenu = new Array();
1384 for (var i = 0; i < 11; i++)
1385 dateMenu.push(onYearMenuItemClick);
1386 menus["yearListMenu"] = dateMenu;
1388 menus["eventsListMenu"] = new Array(onMenuNewEventClick, "-",
1390 editEvent, deleteEvent, "-",
1393 menus["calendarsMenu"] = new Array(onMenuModify,
1395 onCalendarNew, onCalendarRemove,
1396 "-", null, null, "-",
1397 null, "-", onMenuSharing);
1398 menus["searchMenu"] = new Array(setSearchCriteria);
1400 var calendarsMenu = $("calendarsMenu");
1402 calendarsMenu.prepareVisibility = onCalendarsMenuPrepareVisibility;
1407 function onMenuSharing(event) {
1408 if ($(this).hasClassName("disabled"))
1411 var folders = $("calendarList");
1412 var selected = folders.getSelectedNodes()[0];
1413 /* FIXME: activation of the context menu should preferably select the entry
1414 above which the event has occured */
1416 var folderID = selected.getAttribute("id");
1417 var urlstr = URLForFolderID(folderID) + "/acls";
1419 openAclWindow(urlstr);
1423 function configureDragHandles() {
1424 var handle = $("verticalDragHandle");
1426 handle.addInterface(SOGoDragHandlesInterface);
1427 handle.leftBlock=$("leftPanel");
1428 handle.rightBlock=$("rightPanel");
1431 handle = $("rightDragHandle");
1433 handle.addInterface(SOGoDragHandlesInterface);
1434 handle.upperBlock=$("eventsListView");
1435 handle.lowerBlock=$("calendarView");
1439 function initCalendarSelector() {
1440 var selector = $("calendarSelector");
1441 updateCalendarStatus();
1442 selector.changeNotification = updateCalendarsList;
1444 var list = $("calendarList");
1445 list.multiselect = true;
1446 var items = list.childNodesWithTag("li");
1447 for (var i = 0; i < items.length; i++) {
1448 var input = items[i].childNodesWithTag("input")[0];
1449 Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
1450 Event.observe(items[i], "mousedown", listRowMouseDownHandler);
1451 Event.observe(items[i], "selectstart", listRowMouseDownHandler);
1452 Event.observe(items[i], "click", onRowClick);
1455 var links = $("calendarSelectorButtons").childNodesWithTag("a");
1456 Event.observe(links[0], "click", onCalendarNew);
1457 Event.observe(links[1], "click", onCalendarAdd);
1458 Event.observe(links[2], "click", onCalendarRemove);
1461 function onMenuModify(event) {
1462 var folders = $("calendarList");
1463 var selected = folders.getSelectedNodes()[0];
1465 if (UserLogin == selected.getAttribute("owner")) {
1466 var node = selected.childNodes[selected.childNodes.length - 1];
1467 var currentName = node.nodeValue.trim();
1468 var newName = window.prompt(labels["Name of the Calendar"],
1470 if (newName && newName.length > 0
1471 && newName != currentName) {
1472 var url = (URLForFolderID(selected.getAttribute("id"))
1473 + "/renameFolder?name=" + escape(newName.utf8encode()));
1474 triggerAjaxRequest(url, folderRenameCallback,
1475 {node: node, name: " " + newName});
1478 window.alert(clabels["Unable to rename that folder!"]);
1481 function folderRenameCallback(http) {
1482 if (http.readyState == 4) {
1483 if (isHttpStatus204(http.status)) {
1484 var dict = http.callbackData;
1485 dict["node"].nodeValue = dict["name"];
1490 function onCalendarNew(event) {
1491 createFolder(window.prompt(labels["Name of the Calendar"]),
1493 preventDefault(event);
1496 function onCalendarAdd(event) {
1497 openUserFolderSelector(onFolderSubscribeCB, "calendar");
1498 preventDefault(event);
1501 function appendCalendar(folderName, folderPath) {
1505 owner = getSubscribedFolderOwner(folderPath);
1506 folderPath = accessToSubscribedFolder(folderPath);
1509 folderPath = "/" + folderName;
1514 //log ("append name: " + folderName + "; path: " + folderPath + "; owner: " + owner);
1517 window.alert(clabels["You have already subscribed to that folder!"]);
1519 var calendarList = $("calendarList");
1520 var lis = calendarList.childNodesWithTag("li");
1521 var li = document.createElement("li");
1523 // Add the calendar to the proper place
1524 var previousOwner = null;
1525 for (var i = 0; i < lis.length; i++) {
1526 var currentFolderName = lis[i].lastChild.nodeValue.strip();
1527 var currentOwner = lis[i].readAttribute('owner');
1528 if (currentOwner == owner) {
1529 previousOwner = currentOwner;
1530 if (currentFolderName > folderName)
1533 else if (previousOwner ||
1534 (currentOwner != UserLogin && currentOwner > owner))
1537 if (i != lis.length) // User is subscribed to other calendars of the same owner
1538 calendarList.insertBefore(li, lis[i]);
1540 calendarList.appendChild(li);
1542 li.setAttribute("id", folderPath);
1543 li.setAttribute("owner", owner);
1545 // Generate new color
1546 if (calendarColorIndex == null)
1547 calendarColorIndex = lis.length;
1548 calendarColorIndex++;
1549 var colorTable = [1, 1, 1];
1551 var currentValue = calendarColorIndex;
1553 while (currentValue) {
1554 if (currentValue & 1)
1555 colorTable[index]++;
1561 colorTable[0] = parseInt(255 / colorTable[0]) - 1;
1562 colorTable[1] = parseInt(255 / colorTable[1]) - 1;
1563 colorTable[2] = parseInt(255 / colorTable[2]) - 1;
1566 + colorTable[2].toString(16)
1567 + colorTable[1].toString(16)
1568 + colorTable[0].toString(16);
1569 //log ("color = " + color);
1571 var checkBox = document.createElement("input");
1572 checkBox.setAttribute("type", "checkbox");
1573 li.appendChild(checkBox);
1574 li.appendChild(document.createTextNode(" "));
1575 $(checkBox).addClassName("checkBox");
1577 var colorBox = document.createElement("div");
1578 li.appendChild(colorBox);
1579 li.appendChild(document.createTextNode(folderName));
1580 colorBox.appendChild(document.createTextNode("OO"));
1582 $(colorBox).addClassName("colorBox");
1583 $(colorBox).addClassName('calendarFolder' + folderPath.substr(1));
1585 // Register events (doesn't work with Safari)
1586 Event.observe(li, "mousedown", listRowMouseDownHandler);
1587 Event.observe(li, "selectstart", listRowMouseDownHandler);
1588 Event.observe(li, "click", onRowClick);
1589 Event.observe(checkBox, "click",
1590 updateCalendarStatus.bindAsEventListener(checkBox));
1592 var url = URLForFolderID(folderPath) + "/canAccessContent";
1593 triggerAjaxRequest(url, calendarEntryCallback, folderPath);
1595 // Update CSS for events color
1596 if (!document.styleSheets) return;
1598 var styleElement = document.createElement("style");
1599 styleElement.type = "text/css";
1601 '.calendarFolder' + folderPath.substr(1),
1602 'div.colorBox.calendarFolder' + folderPath.substr(1)
1605 ' { background-color: ' + color + ' !important; }',
1606 ' { color: ' + color + ' !important; }'
1608 for (var i = 0; i < rules.length; i++)
1609 if (styleElement.styleSheet && styleElement.styleSheet.addRule)
1610 styleElement.styleSheet.addRule(selectors[i], rules[i]); // IE
1612 styleElement.appendChild(document.createTextNode(selectors[i] + rules[i])); // Mozilla _+ Safari
1613 document.getElementsByTagName("head")[0].appendChild(styleElement);
1617 function onFolderSubscribeCB(folderData) {
1618 var folder = $(folderData["folder"]);
1620 appendCalendar(folderData["folderName"], folderData["folder"]);
1623 function onFolderUnsubscribeCB(folderId) {
1624 var node = $(folderId);
1625 node.parentNode.removeChild(node);
1626 if (removeFolderRequestCount == 0) {
1629 changeCalendarDisplay();
1633 function onCalendarRemove(event) {
1634 if (removeFolderRequestCount == 0) {
1635 var nodes = $("calendarList").getSelectedNodes();
1636 for (var i = 0; i < nodes.length; i++) {
1637 nodes[i].deselect();
1638 var folderId = nodes[i].getAttribute("id");
1639 var folderIdElements = folderId.split("_");
1640 if (folderIdElements.length > 1) {
1641 unsubscribeFromFolder(folderId, onFolderUnsubscribeCB, folderId);
1644 deletePersonalCalendar(folderIdElements[0]);
1648 preventDefault(event);
1651 function deletePersonalCalendar(folderElement) {
1652 var folderId = folderElement.substr(1);
1654 = labels["Are you sure you want to delete the calendar \"%{0}\"?"].formatted($(folderElement).lastChild.nodeValue.strip());
1655 if (window.confirm(label)) {
1656 removeFolderRequestCount++;
1657 var url = ApplicationBaseURL + "/" + folderId + "/deleteFolder";
1658 triggerAjaxRequest(url, deletePersonalCalendarCallback, folderId);
1662 function deletePersonalCalendarCallback(http) {
1663 if (http.readyState == 4) {
1664 if (isHttpStatus204(http.status)) {
1665 var ul = $("calendarList");
1666 var children = ul.childNodesWithTag("li");
1669 while (!done && i < children.length) {
1670 var currentFolderId = children[i].getAttribute("id").substr(1);
1671 if (currentFolderId == http.callbackData) {
1672 ul.removeChild(children[i]);
1678 removeFolderRequestCount--;
1679 if (removeFolderRequestCount == 0) {
1682 changeCalendarDisplay();
1687 log ("ajax problem 5: " + http.status);
1690 function configureLists() {
1691 var list = $("tasksList");
1692 list.multiselect = true;
1693 Event.observe(list, "mousedown",
1694 onTasksSelectionChange.bindAsEventListener(list));
1696 var input = $("showHideCompletedTasks");
1697 Event.observe(input, "click",
1698 onShowCompletedTasks.bindAsEventListener(input));
1700 list = $("eventsList");
1701 list.multiselect = true;
1702 //configureSortableTableHeaders(list);
1703 TableKit.Resizable.init(list, {'trueResize' : true, 'keepWidth' : true});
1704 Event.observe(list, "mousedown",
1705 onEventsSelectionChange.bindAsEventListener(list));
1708 function initDateSelectorEvents() {
1709 var arrow = $("rightArrow");
1710 Event.observe(arrow, "click",
1711 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1712 arrow = $("leftArrow");
1713 Event.observe(arrow, "click",
1714 onDateSelectorGotoMonth.bindAsEventListener(arrow));
1716 var menuButton = $("monthLabel");
1717 Event.observe(menuButton, "click",
1718 popupMonthMenu.bindAsEventListener(menuButton));
1719 menuButton = $("yearLabel");
1720 Event.observe(menuButton, "click",
1721 popupMonthMenu.bindAsEventListener(menuButton));
1724 function initCalendars() {
1725 if (!document.body.hasClassName("popup")) {
1726 initDateSelectorEvents();
1727 initCalendarSelector();
1728 configureSearchField();
1730 var selector = $("calendarSelector");
1732 selector.attachMenu("calendarsMenu");
1736 FastInit.addOnLoad(initCalendars);