From 7512f5d512afb446f80d26087048a5ea9de0fe67 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 16 Jul 2008 02:12:18 +0000 Subject: [PATCH] Monotone-Parent: 95b1c285d67a034685e2ef30e56e10e7c253438d Monotone-Revision: 2609687767884b123c1ff765253fde7c75ef81b3 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-07-16T02:12:18 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 18 + .../Appointments/SOGoAppointmentFolder.m | 5 +- UI/Scheduler/GNUmakefile | 1 + UI/Scheduler/NSDictionary+Scheduler.h | 29 + UI/Scheduler/NSDictionary+Scheduler.m | 35 ++ UI/Scheduler/UIxCalListingActions.h | 1 + UI/Scheduler/UIxCalListingActions.m | 435 +++++++++++-- UI/Scheduler/product.plist | 5 + UI/Templates/SchedulerUI/UIxCalDayTable.wox | 14 - UI/Templates/SchedulerUI/UIxCalMonthView.wox | 84 +-- UI/WebServerResources/SchedulerUI.js | 595 ++++++++---------- 11 files changed, 756 insertions(+), 466 deletions(-) create mode 100644 UI/Scheduler/NSDictionary+Scheduler.h create mode 100644 UI/Scheduler/NSDictionary+Scheduler.m diff --git a/ChangeLog b/ChangeLog index 6156ad7ea..706e4ce80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-07-15 Wolfgang Sourdeau + + * UI/Scheduler/NSDictionary+Scheduler.m: new category module that + implement helper methods for the Scheduler module. + ([NSDictionary -compareEventByStart:otherEvent]): new method that + compares event block dictionaries based on their value for + "start". + + * UI/Scheduler/UIxCalListingActions.m ([UIxCalListingActions + -eventsBlocksAction]): new web method that returns the list of + events as well as the precomputed blocks of events, whether "all + day" or not. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder + -fetchCoreInfosFrom:_startDateto:_endDatetitle:titlecomponent:_componentadditionalFilters:filters]): + requests "c_iscycle". + 2008-07-14 Wolfgang Sourdeau * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 3b68efb8f..5131dc99a 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1399,7 +1399,6 @@ static Class sogoAppointmentFolderKlass = Nil; - (NSString *) davCalendarOrder { - NSArray *siblings; unsigned int order; order = [[container subFolders] indexOfObject: self]; @@ -1409,8 +1408,6 @@ static Class sogoAppointmentFolderKlass = Nil; - (NSException *) setDavCalendarOrder: (NSString *) newColor { - NSException *error; - return nil; } @@ -2218,7 +2215,7 @@ static Class sogoAppointmentFolderKlass = Nil; @"c_classification", @"c_isallday", @"c_isopaque", @"c_participants", @"c_partmails", @"c_partstates", @"c_sequence", @"c_priority", - @"c_cycleinfo", nil]; + @"c_cycleinfo", @"c_iscycle", nil]; return [self fetchFields: infos from: _startDate to: _endDate title: title component: _component diff --git a/UI/Scheduler/GNUmakefile b/UI/Scheduler/GNUmakefile index 464c33c80..796a7e016 100644 --- a/UI/Scheduler/GNUmakefile +++ b/UI/Scheduler/GNUmakefile @@ -11,6 +11,7 @@ SchedulerUI_LANGUAGES = Dutch English French German Italian Spanish SchedulerUI_OBJC_FILES = \ SchedulerUIProduct.m \ NSArray+Scheduler.m \ + NSDictionary+Scheduler.m \ \ UIxCalMainView.m \ UIxCalendarProperties.m \ diff --git a/UI/Scheduler/NSDictionary+Scheduler.h b/UI/Scheduler/NSDictionary+Scheduler.h new file mode 100644 index 000000000..c48aaa5b9 --- /dev/null +++ b/UI/Scheduler/NSDictionary+Scheduler.h @@ -0,0 +1,29 @@ +/* NSDictionary+Scheduler.h - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import + +@interface NSDictionary (SOGoEventComparison) + +- (NSComparisonResult) compareEventByStart: (NSDictionary *) otherEvent; + +@end diff --git a/UI/Scheduler/NSDictionary+Scheduler.m b/UI/Scheduler/NSDictionary+Scheduler.m new file mode 100644 index 000000000..97479748d --- /dev/null +++ b/UI/Scheduler/NSDictionary+Scheduler.m @@ -0,0 +1,35 @@ +/* NSDictionary+Scheduler.m - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import + +#import "NSDictionary+Scheduler.h" + +@implementation NSDictionary (SOGoEventComparison) + +- (NSComparisonResult) compareEventByStart: (NSDictionary *) otherEvent +{ + return [[self objectForKey: @"start"] + compare: [otherEvent objectForKey: @"start"]]; +} + +@end diff --git a/UI/Scheduler/UIxCalListingActions.h b/UI/Scheduler/UIxCalListingActions.h index 99f4ee0e6..b6fd1f20a 100644 --- a/UI/Scheduler/UIxCalListingActions.h +++ b/UI/Scheduler/UIxCalListingActions.h @@ -42,6 +42,7 @@ NSCalendarDate *endDate; NSString *title; NSString *userLogin; + BOOL dayBasedView; WORequest *request; SOGoDateFormatter *dateFormatter; NSTimeZone *userTimeZone; diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index 2d0056870..6f743a1d9 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -49,8 +49,34 @@ #import "UIxCalListingActions.h" +static NSArray *eventsFields = nil; +static NSArray *tasksFields = nil; + +#define dayLength 86400 +#define quarterLength 900 + @implementation UIxCalListingActions ++ (void) initialize +{ + if (!eventsFields) + { + eventsFields = [NSArray arrayWithObjects: @"c_name", @"c_folder", + @"c_status", @"c_title", @"c_startdate", + @"c_enddate", @"c_location", @"c_isallday", + @"c_classification", @"c_partmails", + @"c_partstates", @"c_owner", @"c_iscycle", nil]; + [eventsFields retain]; + } + if (!tasksFields) + { + tasksFields = [NSArray arrayWithObjects: @"c_name", @"c_folder", + @"c_status", @"c_title", @"c_enddate", + @"c_classification", nil]; + [tasksFields retain]; + } +} + - (id) initWithRequest: (WORequest *) newRequest { SOGoUser *user; @@ -64,6 +90,7 @@ user = [[self context] activeUser]; dateFormatter = [user dateFormatterInContext: context]; ASSIGN (userTimeZone, [user timeZone]); + dayBasedView = NO; } return self; @@ -161,7 +188,7 @@ userTZ = [user timeZone]; param = [request formValueForKey: @"filterpopup"]; - if ([param length] > 0) + if ([param length]) { [self _setupDatesWithPopup: param andUserTZ: userTZ]; title = [request formValueForKey: @"search"]; @@ -175,7 +202,7 @@ inTimeZone: userTZ] beginOfDay]; else startDate = nil; - + param = [request formValueForKey: @"ed"]; if ([param length] > 0) endDate = [[NSCalendarDate dateFromShortDateString: param @@ -183,6 +210,9 @@ inTimeZone: userTZ] endOfDay]; else endDate = nil; + + param = [request formValueForKey: @"view"]; + dayBasedView = ![param isEqualToString: @"monthview"]; } } @@ -291,27 +321,9 @@ return formattedDate; } -- (NSString *) _adjustedDateForSeconds: (unsigned int) seconds - forAllDay: (BOOL) forAllDay -{ - NSCalendarDate *date; - unsigned int newSeconds, offset; - - date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds]; - [date setTimeZone: userTimeZone]; - - offset = [userTimeZone secondsFromGMTForDate: date]; - if (forAllDay) - newSeconds = seconds + [userTimeZone secondsFromGMT] - offset; - else - newSeconds = seconds + offset; - - return [NSString stringWithFormat: @"%u", newSeconds]; -} - - (WOResponse *) eventsListAction { - NSArray *fields, *oldEvent, *participants, *states; + NSArray *oldEvent, *participants, *states; NSEnumerator *events; NSMutableArray *newEvents, *newEvent; unsigned int interval, i; @@ -322,27 +334,16 @@ [self _setupContext]; newEvents = [NSMutableArray array]; - fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status", - @"c_title", @"c_startdate", @"c_enddate", @"c_location", - @"c_isallday", @"c_classification", @"c_partmails", @"c_partstates", - @"c_owner", nil]; - events = [[self _fetchFields: fields + events = [[self _fetchFields: eventsFields forComponentOfType: @"vevent"] objectEnumerator]; - oldEvent = [events nextObject]; - while (oldEvent) + while ((oldEvent = [events nextObject])) { newEvent = [NSMutableArray arrayWithArray: oldEvent]; isAllDay = [[oldEvent objectAtIndex: 7] boolValue]; interval = [[oldEvent objectAtIndex: 4] intValue]; - [newEvent replaceObjectAtIndex: 4 - withObject: [self _adjustedDateForSeconds: interval - forAllDay: isAllDay]]; [newEvent addObject: [self _formattedDateForSeconds: interval forAllDay: isAllDay]]; interval = [[oldEvent objectAtIndex: 5] intValue]; - [newEvent replaceObjectAtIndex: 5 - withObject: [self _adjustedDateForSeconds: interval - forAllDay: isAllDay]]; [newEvent addObject: [self _formattedDateForSeconds: interval forAllDay: isAllDay]]; @@ -380,8 +381,6 @@ [newEvent removeObjectAtIndex: 10]; [newEvents addObject: newEvent]; - - oldEvent = [events nextObject]; } sort = [[context request] formValueForKey: @"sort"]; @@ -393,7 +392,7 @@ [newEvents sortUsingSelector: @selector (compareEventsLocationAscending:)]; else [newEvents sortUsingSelector: @selector (compareEventsStartDateAscending:)]; - + ascending = [[context request] formValueForKey: @"asc"]; if (![ascending boolValue]) [newEvents reverseArray]; @@ -401,6 +400,361 @@ return [self _responseWithData: newEvents]; } +static inline void +_feedBlockWithDayBasedData(NSMutableDictionary *block, unsigned int start, + unsigned int end, unsigned int dayStart) +{ + unsigned int delta, quarterStart, length; + + quarterStart = (start - dayStart) / quarterLength; + delta = end - dayStart; + if ((delta % quarterLength)) + delta += quarterLength; + length = (delta / quarterLength) - quarterStart; + if (!length) + length = 1; + [block setObject: [NSNumber numberWithUnsignedInt: quarterStart] + forKey: @"start"]; + [block setObject: [NSNumber numberWithUnsignedInt: length] + forKey: @"length"]; +} + +static inline void +_feedBlockWithMonthBasedData(NSMutableDictionary *block, unsigned int start, + NSTimeZone *userTimeZone, + SOGoDateFormatter *dateFormatter) +{ + NSCalendarDate *eventStartDate; + NSString *startHour; + + eventStartDate = [NSCalendarDate dateWithTimeIntervalSince1970: start]; + [eventStartDate setTimeZone: userTimeZone]; + startHour = [dateFormatter formattedTime: eventStartDate]; + [block setObject: startHour forKey: @"starthour"]; + [block setObject: [NSNumber numberWithUnsignedInt: start] + forKey: @"start"]; +} + +- (NSMutableDictionary *) _eventBlockWithStart: (unsigned int) start + end: (unsigned int) end + cname: (NSString *) cName + onDay: (unsigned int) dayStart + recurrence: (BOOL) recurrence +{ + NSMutableDictionary *block; + + block = [NSMutableDictionary dictionary]; + + if (dayBasedView) + _feedBlockWithDayBasedData (block, start, end, dayStart); + else + _feedBlockWithMonthBasedData (block, start, userTimeZone, dateFormatter); + [block setObject: cName forKey: @"cname"]; + if (recurrence) + [block setObject: @"1" forKey: @"recurrence"]; + + return block; +} + +- (void) _fillBlocks: (NSArray *) blocks + withEvent: (NSArray *) event +{ + unsigned int currentDayStart, startSecs, endsSecs, currentStart, eventStart, + eventEnd, offset; + NSMutableArray *currentDay; + NSMutableDictionary *eventBlock; + NSString *eventCName; + BOOL recurrence; + + startSecs = (unsigned int) [startDate timeIntervalSince1970]; + endsSecs = (unsigned int) [endDate timeIntervalSince1970]; + eventStart = [[event objectAtIndex: 4] unsignedIntValue]; + eventEnd = [[event objectAtIndex: 5] unsignedIntValue]; + + recurrence = [[event objectAtIndex: 12] boolValue]; + + currentStart = eventStart; + if (currentStart < startSecs) + { + currentStart = startSecs; + offset = 0; + } + else + offset = ((currentStart - startSecs) + / dayLength); + currentDay = [blocks objectAtIndex: offset]; + currentDayStart = startSecs + dayLength * offset; + + if (eventEnd > endsSecs) + eventEnd = endsSecs; + + eventCName = [event objectAtIndex: 0]; + while (currentStart + dayLength < eventEnd) + { + eventBlock = [self _eventBlockWithStart: currentStart + end: currentDayStart + 86399 + cname: eventCName + onDay: currentDayStart + recurrence: recurrence]; + [currentDay addObject: eventBlock]; + currentDayStart += dayLength; + currentStart = currentDayStart; + offset++; + currentDay = [blocks objectAtIndex: offset]; + } + eventBlock = [self _eventBlockWithStart: currentStart + end: eventEnd + cname: eventCName + onDay: currentDayStart + recurrence: recurrence]; + [currentDay addObject: eventBlock]; +} + +- (void) _prepareEventBlocks: (NSMutableArray **) blocks + withAllDays: (NSMutableArray **) allDayBlocks +{ + unsigned int count, nbrDays; + int seconds; + + seconds = [endDate timeIntervalSinceDate: startDate]; + if (seconds > 0) + { + nbrDays = 1 + (unsigned int) (seconds / dayLength); + *blocks = [NSMutableArray arrayWithCapacity: nbrDays]; + *allDayBlocks = [NSMutableArray arrayWithCapacity: nbrDays]; + for (count = 0; count < nbrDays; count++) + { + [*blocks addObject: [NSMutableArray array]]; + [*allDayBlocks addObject: [NSMutableArray array]]; + } + } + else + { + *blocks = nil; + *allDayBlocks = nil; + } +} + +- (NSArray *) _horizontalBlocks: (NSMutableArray *) day +{ + NSMutableArray *quarters[96]; + NSMutableArray *currentBlock, *blocks; + NSDictionary *currentEvent; + unsigned int count, max, qCount, qMax, qOffset; + + blocks = [NSMutableArray array]; + + bzero (quarters, 96 * sizeof (NSMutableArray *)); + + max = [day count]; + for (count = 0; count < max; count++) + { + currentEvent = [day objectAtIndex: count]; + qMax = [[currentEvent objectForKey: @"length"] unsignedIntValue]; + qOffset = [[currentEvent objectForKey: @"start"] unsignedIntValue]; + for (qCount = 0; qCount < qMax; qCount++) + { + currentBlock = quarters[qCount + qOffset]; + if (!currentBlock) + { + currentBlock = [NSMutableArray array]; + quarters[qCount + qOffset] = currentBlock; + [blocks addObject: currentBlock]; + } + [currentBlock addObject: currentEvent]; + } + } + + return blocks; +} + +static inline unsigned int +_computeMaxBlockSiblings (NSArray *block) +{ + unsigned int count, max, maxSiblings, siblings; + NSNumber *nbrEvents; + + max = [block count]; + maxSiblings = max; + for (count = 0; count < max; count++) + { + nbrEvents = [[block objectAtIndex: count] objectForKey: @"siblings"]; + if (nbrEvents) + { + siblings = [nbrEvents unsignedIntValue]; + if (siblings > maxSiblings) + maxSiblings = siblings; + } + } + + return maxSiblings; +} + +static inline void +_propagateBlockSiblings (NSArray *block, NSNumber *maxSiblings) +{ + unsigned int count, max; + NSMutableDictionary *event; + NSNumber *realSiblings; + + max = [block count]; + realSiblings = [NSNumber numberWithUnsignedInt: max]; + for (count = 0; count < max; count++) + { + event = [block objectAtIndex: count]; + [event setObject: maxSiblings forKey: @"siblings"]; + [event setObject: realSiblings forKey: @"realSiblings"]; + } +} + +/* this requires two vertical passes */ +static inline void +_computeBlocksSiblings (NSArray *blocks) +{ + NSArray *currentBlock; + unsigned int count, max, maxSiblings; + + max = [blocks count]; + for (count = 0; count < max; count++) + { + currentBlock = [blocks objectAtIndex: count]; + maxSiblings = _computeMaxBlockSiblings (currentBlock); + _propagateBlockSiblings (currentBlock, + [NSNumber numberWithUnsignedInt: maxSiblings]); + } +} + +static inline void +_computeBlockPosition (NSArray *block) +{ + unsigned int count, max, j, siblings; + NSNumber *position; + NSMutableDictionary *event; + NSMutableDictionary **positions; + + max = [block count]; + event = [block objectAtIndex: 0]; + siblings = [[event objectForKey: @"siblings"] unsignedIntValue]; + positions = calloc (siblings, sizeof (NSMutableDictionary *)); + + for (count = 0; count < max; count++) + { + event = [block objectAtIndex: count]; + position = [event objectForKey: @"position"]; + if (position) + *(positions + [position unsignedIntValue]) = event; + else + { + j = 0; + while (j < max && *(positions + j)) + j++; + *(positions + j) = event; + [event setObject: [NSNumber numberWithUnsignedInt: j] + forKey: @"position"]; + } + } + + free (positions); +} + +// static inline void +// _addBlockMultipliers (NSArray *block, NSMutableDictionary **positions) +// { +// unsigned int count, max, limit, multiplier; +// NSMutableDictionary *currentEvent, *event; + +// max = [block count]; +// event = [block objectAtIndex: 0]; +// limit = [[event objectForKey: @"siblings"] unsignedIntValue]; + +// if (max < limit) +// { +// currentEvent = nil; +// for (count = 0; count < limit; count++) +// { +// multiplier = 1; +// event = positions[count]; +// if ([[event objectForKey: @"realSiblings"] unsignedIntValue] +// < limit) +// { +// if (event) +// { +// if (currentEvent && multiplier > 1) +// [currentEvent setObject: [NSNumber numberWithUnsignedInt: multiplier] +// forKey: @"multiplier"]; +// currentEvent = event; +// multiplier = 1; +// } +// else +// multiplier++; +// } +// } +// } +// } + +static inline void +_computeBlocksPosition (NSArray *blocks) +{ + NSArray *block; + unsigned int count, max; +// NSMutableDictionary **positions; + + max = [blocks count]; + for (count = 0; count < max; count++) + { + block = [blocks objectAtIndex: count]; + _computeBlockPosition (block); +// _addBlockMultipliers (block, positions); +// free (positions); + } +} + +- (void) _addBlocksWidth: (NSMutableArray *) day +{ + NSArray *blocks; + + blocks = [self _horizontalBlocks: day]; + _computeBlocksSiblings (blocks); + _computeBlocksSiblings (blocks); + _computeBlocksPosition (blocks); + /* ... _computeBlocksMultiplier() ... */ +} + +- (WOResponse *) eventsBlocksAction +{ + int count, max; + NSArray *events, *event, *eventsBlocks; + NSMutableArray *allDayBlocks, *blocks, *currentDay; + + [self _setupContext]; + + [self _prepareEventBlocks: &blocks withAllDays: &allDayBlocks]; + events = [self _fetchFields: eventsFields + forComponentOfType: @"vevent"]; + eventsBlocks + = [NSArray arrayWithObjects: events, allDayBlocks, blocks, nil]; + max = [events count]; + for (count = 0; count < max; count++) + { + event = [events objectAtIndex: count]; + if (dayBasedView && [[event objectAtIndex: 7] boolValue]) + [self _fillBlocks: allDayBlocks withEvent: event]; + else + [self _fillBlocks: blocks withEvent: event]; + } + + max = [blocks count]; + for (count = 0; count < max; count++) + { + currentDay = [blocks objectAtIndex: count]; + [currentDay sortUsingSelector: @selector (compareEventByStart:)]; + [self _addBlocksWidth: currentDay]; + } + + return [self _responseWithData: eventsBlocks]; +// timeIntervalSinceDate: +} + - (NSString *) _getStatusClassForStatusCode: (int) statusCode andEndDateStamp: (unsigned int) endDateStamp { @@ -438,7 +792,7 @@ NSEnumerator *tasks; NSMutableArray *filteredTasks, *filteredTask; BOOL showCompleted; - NSArray *fields, *task; + NSArray *task; int statusCode; unsigned int endDateStamp; NSString *statusFlag; @@ -447,10 +801,7 @@ [self _setupContext]; - fields = [NSArray arrayWithObjects: @"c_name", @"c_folder", @"c_status", - @"c_title", @"c_enddate", @"c_classification", nil]; - - tasks = [[self _fetchFields: fields + tasks = [[self _fetchFields: tasksFields forComponentOfType: @"vtodo"] objectEnumerator]; showCompleted = [[request formValueForKey: @"show-completed"] intValue]; diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index 502718871..b703b1489 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -59,6 +59,11 @@ actionClass = "UIxCalListingActions"; actionName = "eventsList"; }; + eventsblocks = { + protectedBy = "View"; + actionClass = "UIxCalListingActions"; + actionName = "eventsBlocks"; + }; taskslist = { protectedBy = "View"; actionClass = "UIxCalListingActions"; diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index 9a08afe82..78d466c4b 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -42,20 +42,6 @@ var:day="currentTableDay.shortDateString" var:hour="currentAppointmentHour"> - diff --git a/UI/Templates/SchedulerUI/UIxCalMonthView.wox b/UI/Templates/SchedulerUI/UIxCalMonthView.wox index bbed4037a..f15c35425 100644 --- a/UI/Templates/SchedulerUI/UIxCalMonthView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMonthView.wox @@ -47,89 +47,15 @@ >
- -
-
- -
+
- - - - - - diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index e0f56aafb..fcfc9e9fe 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -10,16 +10,19 @@ var showCompletedTasks = 0; var currentDay = ''; var currentView = "weekview"; -var cachedDateSelectors = new Array(); +var cachedDateSelectors = []; var contactSelectorAction = 'calendars-contacts'; -var eventsToDelete = new Array(); -var calendarsOfEventsToDelete = new Array(); +var eventsToDelete = []; +var calendarsOfEventsToDelete = []; var usersRightsWindowHeight = 250; var usersRightsWindowWidth = 502; +var eventsBlocks; +var calendarEvents = null; + function newEvent(sender, type) { var day = $(sender).readAttribute("day"); if (!day) @@ -34,7 +37,7 @@ function newEvent(sender, type) { folderID = "/personal"; } var urlstr = ApplicationBaseURL + folderID + "/new" + type; - var params = new Array(); + var params = []; if (day) params.push("day=" + day); if (hour) @@ -67,7 +70,7 @@ function onMenuNewTaskClick(event) { } function _editEventId(id, calendar) { - var urlstr = ApplicationBaseURL + "/" + calendar + "/" + id + "/edit"; + var urlstr = ApplicationBaseURL + calendar + "/" + id + "/edit"; var targetname = "SOGo_edit_" + id; var win = window.open(urlstr, "_blank", "width=490,height=470,resizable=0"); @@ -100,7 +103,7 @@ function editEvent() { function _batchDeleteEvents() { var events = eventsToDelete.shift(); var calendar = calendarsOfEventsToDelete.shift(); - var urlstr = (ApplicationBaseURL + "/" + calendar + var urlstr = (ApplicationBaseURL + calendar + "/batchDelete?ids=" + events.join('/')); document.deleteEventAjaxRequest = triggerAjaxRequest(urlstr, deleteEventCallback, @@ -123,13 +126,13 @@ function deleteEvent() { document.deleteEventAjaxRequest.aborted = true; document.deleteEventAjaxRequest.abort(); } - var sortedNodes = new Array(); - var calendars = new Array(); + var sortedNodes = []; + var calendars = []; for (var i = 0; i < nodes.length; i++) { var calendar = nodes[i].calendar; if (!sortedNodes[calendar]) { - sortedNodes[calendar] = new Array(); + sortedNodes[calendar] = []; calendars.push(calendar); } sortedNodes[calendar].push(nodes[i].cname); @@ -228,19 +231,41 @@ function deleteEventCallback(http) { _batchDeleteEvents(); else { document.deleteEventAjaxRequest = null; - if (isTask) - refreshTasks(); - else { - refreshEvents(); - changeCalendarDisplay(); - } } + if (isTask) + deleteTasksFromViews(nodes); + else + deleteEventsFromViews(nodes) } else log ("deleteEventCallback Ajax error"); } } +function deleteTasksFromViews(tasks) { +} + +function deleteEventsFromViews(events) { + if (calendarEvents) { + for (var i = 0; i < events.length; i++) { + var cname = events[i]; + var event = calendarEvents[cname]; + if (event) { + if (event.siblings) { + for (var j = 0; j < event.siblings.length; j++) { + var eventDiv = event.siblings[j]; + eventDiv.parentNode.removeChild(eventDiv); + } + } + delete calendarEvents[cname] + } + var row = $(cname); + if (row) + row.parentNode.removeChild(row); + } + } +} + function editDoubleClickedEvent(event) { _editEventId(this.cname, this.calendar); @@ -364,12 +389,12 @@ function eventsListCallback(http) { td = $(document.createElement("td")); row.appendChild(td); td.observe("mousedown", listRowMouseDownHandler, true); - td.appendChild(document.createTextNode(data[i][10])); + td.appendChild(document.createTextNode(data[i][11])); td = $(document.createElement("td")); row.appendChild(td); td.observe("mousedown", listRowMouseDownHandler, true); - td.appendChild(document.createTextNode(data[i][11])); + td.appendChild(document.createTextNode(data[i][12])); td = $(document.createElement("td")); row.appendChild(td); @@ -603,10 +628,8 @@ function scrollDayView(scrollEvent) { var divs; // Select event in calendar view - if (scrollEvent) { - divs = $$("div#calendarContent div." + eventClass(scrollEvent)); - selectCalendarEvent(divs[0]); - } + if (scrollEvent) + selectCalendarEvent(scrollEvent); // Don't scroll if in month view if (currentView == "monthview") @@ -614,22 +637,23 @@ function scrollDayView(scrollEvent) { var offset = 0; var daysView = $("daysView"); - var hours = - $(daysView.childNodesWithTag("div")[0]).childNodesWithTag("div"); + var hours = $(daysView.childNodesWithTag("div")[0]) + .childNodesWithTag("div"); - if (scrollEvent) { - divs = $$("div#calendarContent div." + eventClass(scrollEvent)); - var classes = $w(divs[0].className); - for (var i = 0; i < classes.length; i++) { - if (classes[i].startsWith("starts")) { - var starts = Math.floor(parseInt(classes[i].substr(6)) / 4); - offset = hours[starts].offsetTop; - } + // Scroll to 8 AM by default + offset = hours[8].offsetTop; + + if (scrollEvent && calendarEvents) { + var event = calendarEvents[scrollEvent]; + if (event) { + var classes = $w(event.siblings[0].className); + for (var i = 0; i < classes.length; i++) + if (classes[i].startsWith("starts")) { + var starts = Math.floor(parseInt(classes[i].substr(6)) / 4); + offset = hours[starts].offsetTop; + } } } - else - // Scroll to 8 AM - offset = hours[8].offsetTop; daysView.scrollTop = offset - 5; } @@ -684,7 +708,8 @@ function refreshCalendarEvents(scrollEvent) { document.refreshCalendarEventsAjaxRequest.aborted = true; document.refreshCalendarEventsAjaxRequest.abort(); } - var url = ApplicationBaseURL + "eventslist?sd=" + sd + "&ed=" + ed; + var url = (ApplicationBaseURL + "eventsblocks?sd=" + sd + "&ed=" + ed + + "&view=" + currentView); document.refreshCalendarEventsAjaxRequest = triggerAjaxRequest(url, refreshCalendarEventsCallback, {"startDate": sd, "endDate": ed, @@ -695,142 +720,13 @@ function refreshCalendarEventsCallback(http) { if (http.readyState == 4 && http.status == 200) { if (http.responseText.length > 0) { - var data = http.responseText.evalJSON(true); - // log("refresh calendar events: " + data.length); - var dateTuples = new Array(); - for (var i = 0; i < data.length; i++) { - var dates = drawCalendarEvent(data[i], - http.callbackData["startDate"], - http.callbackData["endDate"]); - dates.each(function(tuple) { - if (tuple[3] == 0) tuple[3] = 96; - dateTuples.push(tuple); - }); - } - - var c = { - div: 0, - day: 1, - start: 2, - end: 3, - siblingsCount: 4, - siblingsPosition: 5, - siblingsMaxCount: 6 - }; - for (var i = 0; i < dateTuples.length; i++) { - if (dateTuples[i].length < 6) { - dateTuples[i][c.siblingsCount] = 1; - dateTuples[i][c.siblingsPosition] = 0; - } - for (var j = 0; j < dateTuples.length; j++) { - if (j == i) continue; - if (dateTuples[i][c.day] == dateTuples[j][c.day]) { - // Same day - if (dateTuples[j][c.start] > dateTuples[i][c.start] && - dateTuples[j][c.start] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] == dateTuples[i][c.end] && - i < j) { - // Same period - if (dateTuples[j].length < 6) { - dateTuples[j][c.siblingsCount] = 2; - dateTuples[j][c.siblingsPosition] = dateTuples[i][c.siblingsPosition] + 1; - } - else { - dateTuples[j][c.siblingsCount]++; - dateTuples[j][c.siblingsPosition]++; - } - dateTuples[i][c.siblingsCount]++; - } - } - } - } - - // Second loop; adjust total number of siblings for each event - for (var i = 0; i < dateTuples.length; i++) { - //log (i + " " + dateTuples[i].inspect()); - var maxCount = 0; - for (var j = 0; j < dateTuples.length; j++) { - if (j == i) continue; - if (dateTuples[i][c.day] == dateTuples[j][c.day]) { - // Same day - if (dateTuples[j][c.start] > dateTuples[i][c.start] && - dateTuples[j][c.start] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] == dateTuples[i][c.end] && - i < j) { - // Same period - if (dateTuples[j][c.siblingsCount] > maxCount) - maxCount = dateTuples[j][c.siblingsCount]; - } - } - } - if (maxCount > 0) { - dateTuples[i][c.siblingsCount] = maxCount; - dateTuples[i][c.siblingsMaxCount] = maxCount; - } - } - - // Third loop; adjust position and total number of siblings for each event - for (var i = 0; i < dateTuples.length; i++) { - //log (i + " " + dateTuples[i].inspect()); - for (var j = 0; j < dateTuples.length; j++) { - if (j == i) continue; - if (dateTuples[i][c.day] == dateTuples[j][c.day]) { - // Same day - if (dateTuples[j][c.start] > dateTuples[i][c.start] && - dateTuples[j][c.start] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] < dateTuples[i][c.end] || - - dateTuples[j][c.start] == dateTuples[i][c.start] && - dateTuples[j][c.end] == dateTuples[i][c.end] && - i < j) { - // Overlapping period - if (dateTuples[j][c.siblingsPosition] == dateTuples[i][c.siblingsPosition]) { - // Same position - dateTuples[j][c.siblingsPosition]--; // not very clever - } - if (dateTuples[j].length < 7 || - dateTuples[j][c.siblingsMaxCount] < dateTuples[i][c.siblingsMaxCount]) - dateTuples[j][c.siblingsMaxCount] = dateTuples[i][c.siblingsMaxCount]; - } - } - } - if (dateTuples[i].length < 7) - dateTuples[i][c.siblingsMaxCount] = dateTuples[i][c.siblingsCount]; - } - - // Final loop; draw the events - //log ("[div, day, start index, end index, siblings count, siblings position, siblings max count]"); - for (var i = 0; i < dateTuples.length; i++) { - //log (i + " " + dateTuples[i].inspect()); - - var base = dateTuples[i][c.siblingsCount] * dateTuples[i][c.siblingsMaxCount]; - var length = 1; - var maxLength = 1 * dateTuples[i][c.siblingsMaxCount]; - - for (var j = dateTuples[i][c.siblingsCount]; - j < maxLength; - j += dateTuples[i][c.siblingsCount]) { } - - if (j > maxLength) { - j -= dateTuples[i][c.siblingsCount]; - } - - var width = 100 * j / base; - var left = width * dateTuples[i][c.siblingsPosition]; - dateTuples[i][0].setStyle({ width: width + "%", - left: left + "%" }); + var eventsBlocks = http.responseText.evalJSON(true); + calendarEvents = _prepareCalendarEventsCache(eventsBlocks[0]); + if (currentView == "monthview") + _drawMonthCalendarEvents(eventsBlocks[2]); + else { + _drawCalendarAllDaysEvents(eventsBlocks[1]); + _drawCalendarEvents(eventsBlocks[2]); } } scrollDayView(http.callbackData["scrollEvent"]); @@ -839,133 +735,42 @@ function refreshCalendarEventsCallback(http) { log("AJAX error when refreshing calendar events"); } -function drawCalendarEvent(eventData, sd, ed) { - var dateTuples = new Array(); +function _prepareCalendarEventsCache(events) { + var cache = {}; -// log ("drawCalendarEvent..."); - var viewStartDate = sd.asDate(); - var viewEndDate = ed.asDate(); + for (var i = 0; i < events.length; i++) { + cache[events[i][0]] = events[i]; + } - var startDate = new Date(); - startDate.setTime(eventData[4] * 1000); - var endDate = new Date(); - endDate.setTime(eventData[5] * 1000); + return cache; +} -// log ("s: " + startDate + "; e: " + endDate); - - var days = startDate.daysUpTo(endDate); - - var title; - if (currentView == "monthview" - && (eventData[7] == 0)) - title = startDate.getDisplayHoursString() + " " + eventData[3]; - else - title = eventData[3]; - -// log("title: " + title); -// log("viewS: " + viewStartDate); - var startHour = null; - var endHour = null; - - var siblings = new Array(); - for (var i = 0; i < days.length; i++) - if (days[i].earlierDate(viewStartDate) == viewStartDate - && days[i].laterDate(viewEndDate) == viewEndDate) { - var starts; - -// log("day: " + days[i]); - if (i == 0) { - var quarters = (startDate.getUTCHours() * 4 - + Math.floor(startDate.getUTCMinutes() / 15)); - starts = quarters; - startHour = startDate.getDisplayHoursString(); - endHour = endDate.getDisplayHoursString(); - } - else - starts = 0; - - var ends; - var lasts; - if (i == days.length - 1) { - var quarters = (endDate.getUTCHours() * 4 - + Math.ceil(endDate.getUTCMinutes() / 15)); - ends = quarters; - } - else - ends = 96; - lasts = ends - starts; - if (!lasts) - lasts = 1; - - var eventDiv = newEventDIV(eventData[0], eventData[1], starts, lasts, - null, null, title); - siblings.push(eventDiv); - eventDiv.siblings = siblings; - if (eventData[9].length > 0) - eventDiv.addClassName(eventData[9]); // event owner status - //eventDiv.setStyle({ width: '50%' }); - if (currentView != "monthview" && - eventData[7] == 0) // not "all day" - dateTuples.push(new Array(eventDiv, days[i].getDayString(), starts, ends)); - var dayString = days[i].getDayString(); - // log("day: " + dayString); - var parentDiv = null; - if (currentView == "monthview") { - var dayDivs = $("monthDaysView").childNodesWithTag("div"); - var j = 0; - while (!parentDiv && j < dayDivs.length) { - if (dayDivs[j].getAttribute("day") == dayString) - parentDiv = dayDivs[j]; - else - j++; - } - } - else { - if (eventData[7] == 0) { - var daysView = $("daysView"); - var eventsDiv = $(daysView).childNodesWithTag("div")[1]; - var dayDivs = $(eventsDiv).childNodesWithTag("div"); - var j = 0; - while (!parentDiv && j < dayDivs.length) { - if (dayDivs[j].getAttribute("day") == dayString) - parentDiv = dayDivs[j].childNodesWithTag("div")[0]; - else - j++; - } - } - else { - var header = $("calendarHeader"); - var daysDiv = $(header).childNodesWithTag("div")[1]; - var dayDivs = $(daysDiv).childNodesWithTag("div"); - var j = 0; - while (!parentDiv && j < dayDivs.length) { - if (dayDivs[j].getAttribute("day") == dayString) - parentDiv = dayDivs[j]; - else - j++; - } - } - } - if (parentDiv) - parentDiv.appendChild(eventDiv); +function _drawCalendarAllDaysEvents(events) { + var daysView = $("calendarHeader"); + var subdivs = daysView.childNodesWithTag("div"); + var days = subdivs[1].childNodesWithTag("div"); + for (var i = 0; i < events.length; i++) { + var parentDiv = days[i]; + for (var j = 0; j < events[i].length; j++) { + var eventRep = events[i][j]; + var eventDiv = newAllDayEventDIV(eventRep); + parentDiv.appendChild(eventDiv); } - - return dateTuples; + } } -function eventClass(cname) { - return escape(cname.replace(".", "-")); -} - -function newEventDIV(cname, calendar, starts, lasts, - startHour, endHour, title) { +function newAllDayEventDIV(eventRep) { +// cname, calendar, starts, lasts, +// startHour, endHour, title) { var eventDiv = document.createElement("div"); - eventDiv.cname = escape(cname); - eventDiv.calendar = calendar; + var event = calendarEvents[eventRep.cname]; + if (!event.siblings) + event.siblings = []; + eventDiv.event = event; + eventDiv.cname = event[0]; + eventDiv.calendar = event[1]; + $(eventDiv).addClassName("event"); - $(eventDiv).addClassName(eventClass(cname)); - $(eventDiv).addClassName("starts" + starts); - $(eventDiv).addClassName("lasts" + lasts); for (var i = 1; i < 5; i++) { var shadowDiv = document.createElement("div"); eventDiv.appendChild(shadowDiv); @@ -975,7 +780,7 @@ function newEventDIV(cname, calendar, starts, lasts, var innerDiv = document.createElement("div"); eventDiv.appendChild(innerDiv); $(innerDiv).addClassName("eventInside"); - $(innerDiv).addClassName("calendarFolder" + calendar); + $(innerDiv).addClassName("calendarFolder" + event[1]); var gradientDiv = document.createElement("div"); innerDiv.appendChild(gradientDiv); @@ -987,20 +792,151 @@ function newEventDIV(cname, calendar, starts, lasts, var textDiv = document.createElement("div"); innerDiv.appendChild(textDiv); $(textDiv).addClassName("text"); - if (startHour) { - var headerSpan = document.createElement("span"); - textDiv.appendChild(headerSpan); - $(headerSpan).addClassName("eventHeader"); - headerSpan.appendChild(document.createTextNode(startHour + " - " - + endHour)); - textDiv.appendChild(document.createElement("br")); - } - textDiv.appendChild(document.createTextNode(title)); + textDiv.appendChild(document.createTextNode(event[3])); eventDiv.observe("mousedown", listRowMouseDownHandler); eventDiv.observe("click", onCalendarSelectEvent); eventDiv.observe("dblclick", editDoubleClickedEvent); + event.siblings.push(eventDiv); + + return eventDiv; +} + +function _drawCalendarEvents(events) { + var daysView = $("daysView"); + var subdivs = daysView.childNodesWithTag("div"); + var days = subdivs[1].childNodesWithTag("div"); + for (var i = 0; i < events.length; i++) { + var parentDiv = days[i].childNodesWithTag("div")[0]; + for (var j = 0; j < events[i].length; j++) { + var eventRep = events[i][j]; + var eventDiv = newEventDIV(eventRep); + parentDiv.appendChild(eventDiv); + } + } +} + +function newEventDIV(eventRep) { +// cname, calendar, starts, lasts, +// startHour, endHour, title) { + var eventDiv = document.createElement("div"); + var event = calendarEvents[eventRep.cname]; + if (!event.siblings) + event.siblings = []; + eventDiv.event = event; + eventDiv.cname = event[0]; + eventDiv.calendar = event[1]; + + $(eventDiv).addClassName("event"); +// $(eventDiv).addClassName(eventClass(cname)); + $(eventDiv).addClassName("starts" + eventRep.start); + $(eventDiv).addClassName("lasts" + eventRep.length); + for (var i = 1; i < 5; i++) { + var shadowDiv = document.createElement("div"); + eventDiv.appendChild(shadowDiv); + $(shadowDiv).addClassName("shadow"); + $(shadowDiv).addClassName("shadow" + i); + } + var innerDiv = document.createElement("div"); + eventDiv.appendChild(innerDiv); + $(innerDiv).addClassName("eventInside"); + $(innerDiv).addClassName("calendarFolder" + event[1]); + + var gradientDiv = document.createElement("div"); + innerDiv.appendChild(gradientDiv); + $(gradientDiv).addClassName("gradient"); + var gradientImg = document.createElement("img"); + gradientDiv.appendChild(gradientImg); + gradientImg.src = ResourcesURL + "/event-gradient.png"; + + var textDiv = document.createElement("div"); + innerDiv.appendChild(textDiv); + $(textDiv).addClassName("text"); +// if (startHour) { +// var headerSpan = document.createElement("span"); +// textDiv.appendChild(headerSpan); +// $(headerSpan).addClassName("eventHeader"); +// headerSpan.appendChild(document.createTextNode(startHour + " - " +// + endHour)); +// textDiv.appendChild(document.createElement("br")); +// } + textDiv.appendChild(document.createTextNode(event[3])); + + var pc = 100 / eventRep.siblings; + eventDiv.style.width = pc + "%"; + var left = eventRep.position * pc; + eventDiv.style.left = left + "%"; + + eventDiv.observe("mousedown", listRowMouseDownHandler); + eventDiv.observe("click", onCalendarSelectEvent); + eventDiv.observe("dblclick", editDoubleClickedEvent); + + event.siblings.push(eventDiv); + + return eventDiv; +} + +function _drawMonthCalendarEvents(events) { + var daysView = $("monthDaysView"); + var days = daysView.childNodesWithTag("div"); + for (var i = 0; i < days.length; i++) { + var parentDiv = days[i]; + for (var j = 0; j < events[i].length; j++) { + var eventRep = events[i][j]; + var eventDiv = newMonthEventDIV(eventRep); + parentDiv.appendChild(eventDiv); + } + } +} + +function newMonthEventDIV(eventRep) { +// cname, calendar, starts, lasts, +// startHour, endHour, title) { + var eventDiv = document.createElement("div"); + var event = calendarEvents[eventRep.cname]; + if (!event.siblings) + event.siblings = []; + eventDiv.event = event; + eventDiv.cname = event[0]; + eventDiv.calendar = event[1]; + + $(eventDiv).addClassName("event"); + for (var i = 1; i < 5; i++) { + var shadowDiv = document.createElement("div"); + eventDiv.appendChild(shadowDiv); + $(shadowDiv).addClassName("shadow"); + $(shadowDiv).addClassName("shadow" + i); + } + var innerDiv = document.createElement("div"); + eventDiv.appendChild(innerDiv); + $(innerDiv).addClassName("eventInside"); + $(innerDiv).addClassName("calendarFolder" + event[1]); + + var gradientDiv = document.createElement("div"); + innerDiv.appendChild(gradientDiv); + $(gradientDiv).addClassName("gradient"); + var gradientImg = document.createElement("img"); + gradientDiv.appendChild(gradientImg); + gradientImg.src = ResourcesURL + "/event-gradient.png"; + + var textDiv = document.createElement("div"); + innerDiv.appendChild(textDiv); + $(textDiv).addClassName("textw"); + + var eventText; + if (event[7]) + eventText = event[3]; + else + eventText = eventRep.starthour + " - " + event[3]; + textDiv.appendChild(document.createTextNode(eventText)); + + eventDiv.observe("mousedown", listRowMouseDownHandler); + eventDiv.observe("click", onCalendarSelectEvent); + eventDiv.observe("dblclick", editDoubleClickedEvent); + + event.siblings.push(eventDiv); + return eventDiv; } @@ -1021,7 +957,7 @@ function calendarDisplayCallback(http) { contentView = $("calendarContent"); else contentView = $("daysView"); - + refreshCalendarEvents(http.callbackData.scrollEvent); var days = document.getElementsByClassName("day", contentView); @@ -1270,22 +1206,30 @@ function onYearMenuItemClick(event) { changeDateSelectorDisplay(year + month + "01", true); } -function selectCalendarEvent(div) { +function selectCalendarEvent(cname) { // Select event in calendar view if (selectedCalendarCell) for (var i = 0; i < selectedCalendarCell.length; i++) selectedCalendarCell[i].deselect(); - for (var i = 0; i < div.siblings.length; i++) - div.siblings[i].selectElement(); - - selectedCalendarCell = div.siblings; + if (calendarEvents) { + var event = calendarEvents[cname]; +// if (event) { +// if (event[12]) +// log("recurrence; date=" + event[4]); +// } + if (event && event.siblings) { + for (var i = 0; i < event.siblings.length; i++) + event.siblings[i].selectElement(); + selectedCalendarCell = event.siblings; + } + } } function onCalendarSelectEvent() { var list = $("eventsList"); - selectCalendarEvent(this); + selectCalendarEvent(this.cname); // Select event in events list $(list.tBodies[0]).deselectAll(); @@ -1298,11 +1242,7 @@ function onCalendarSelectEvent() { } function onCalendarSelectDay(event) { - var day; - if (currentView == "multicolumndayview") - day = this.getAttribute("day"); - else - day = this.getAttribute("day"); + var day = this.getAttribute("day"); var needRefresh = (listFilter == 'view_selectedday' && day != currentDay); @@ -1322,22 +1262,23 @@ function onCalendarSelectDay(event) { } function changeWeekCalendarDisplayOfSelectedDay(node) { - var days = document.getElementsByClassName("day", node.parentNode); + var daysView = $("daysView"); + var daysDiv = daysView.childNodesWithTag("div"); + var days = daysDiv[1].childNodesWithTag("div"); var headerDiv = $("calendarHeader").childNodesWithTag("div")[1]; - var headerDays = document.getElementsByClassName("day", headerDiv); + var headerDays = $(headerDiv).childNodesWithTag("div"); - // log ("days: " + days.length + "; headerDays: " + headerDays.length); - for (var i = 0; i < days.length; i++) - if (days[i] != node) { - // log("unselect day : " + i); - headerDays[i].removeClassName("selectedDay"); - days[i].removeClassName("selectedDay"); - } - else { - // log("selected day : " + i); + for (var i = 0; i < days.length; i++) { + if (days[i] == node + || headerDays[i] == node) { headerDays[i].addClassName("selectedDay"); days[i].addClassName("selectedDay"); } + else { + headerDays[i].removeClassName("selectedDay"); + days[i].removeClassName("selectedDay"); + } + } } function findMonthCalendarSelectedCell(daysContainer) { @@ -1400,7 +1341,7 @@ function updateTaskStatus(event) { } function updateCalendarStatus(event) { - var list = new Array(); + var list = []; var newStatus = (this.checked ? 1 : 0); if (isSafari() && !isSafari3()) { @@ -1525,12 +1466,12 @@ function onCalendarsMenuPrepareVisibility() { function getMenus() { var menus = {}; - var dateMenu = new Array(); + var dateMenu = []; for (var i = 0; i < 12; i++) dateMenu.push(onMonthMenuItemClick); menus["monthListMenu"] = dateMenu; - dateMenu = new Array(); + dateMenu = []; for (var i = 0; i < 11; i++) dateMenu.push(onYearMenuItemClick); menus["yearListMenu"] = dateMenu; @@ -1830,7 +1771,7 @@ function initDateSelectorEvents() { arrow.observe("click", onDateSelectorGotoMonth); arrow = $("leftArrow"); arrow.observe("click", onDateSelectorGotoMonth); - + var menuButton = $("monthLabel"); menuButton.observe("click", popupMonthMenu); menuButton = $("yearLabel");