From e478b29c2e40963041abf63c678a7e36d287ad2f Mon Sep 17 00:00:00 2001 From: Alexandre Cloutier Date: Wed, 9 Jul 2014 16:47:13 -0400 Subject: [PATCH 01/12] creating and dragNDrop between calendars in multicolumndayview --- UI/Scheduler/UIxAppointmentActions.m | 32 ++++++- UI/Scheduler/UIxCalDayTable.m | 2 +- UI/Templates/SchedulerUI/UIxCalDayTable.wox | 4 +- UI/WebServerResources/SchedulerUI.js | 77 +++++++++++---- UI/WebServerResources/SchedulerUIDnD.js | 100 ++++++++++++++++---- 5 files changed, 171 insertions(+), 44 deletions(-) diff --git a/UI/Scheduler/UIxAppointmentActions.m b/UI/Scheduler/UIxAppointmentActions.m index db6d55c91..ddfb12b5b 100644 --- a/UI/Scheduler/UIxAppointmentActions.m +++ b/UI/Scheduler/UIxAppointmentActions.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import @@ -52,19 +53,25 @@ WOResponse *response; WORequest *rq; SOGoAppointmentObject *co; + SoSecurityManager *sm; iCalEvent *event; NSCalendarDate *start, *newStart, *end, *newEnd; NSTimeInterval newDuration; SOGoUserDefaults *ud; - NSString *daysDelta, *startDelta, *durationDelta; + NSString *daysDelta, *startDelta, *durationDelta, *calendarID; + NSArray *calendarsID; NSTimeZone *tz; NSException *ex; + SOGoAppointmentFolder *componentCalendar, *previousCalendar; + SOGoAppointmentFolders *user; rq = [context request]; daysDelta = [rq formValueForKey: @"days"]; startDelta = [rq formValueForKey: @"start"]; durationDelta = [rq formValueForKey: @"duration"]; + calendarID = [rq formValueForKey: @"calendarID"]; + if ([daysDelta length] > 0 || [startDelta length] > 0 || [durationDelta length] > 0) { @@ -105,10 +112,31 @@ } if ([event hasRecurrenceRules]) - [event updateRecurrenceRulesUntilDate: end]; + [event updateRecurrenceRulesUntilDate: end]; [event setLastModified: [NSCalendarDate calendarDate]]; ex = [co saveComponent: event]; +/***************************** TODO ******************/ + if (![calendarID isEqualToString:@"0"]) { + user = [[self->context activeUser] calendarsFolderInContext: self->context]; + calendarsID = [calendarID componentsSeparatedByString:@","]; + previousCalendar = [user lookupName:[[calendarsID objectAtIndex:0] stringValue] inContext: self->context acquire: 0]; + componentCalendar = [user lookupName:[[calendarsID objectAtIndex:1] stringValue] inContext: self->context acquire: 0]; + // The event was moved to a different calendar. + sm = [SoSecurityManager sharedSecurityManager]; + if (![sm validatePermission: SoPerm_DeleteObjects + onObject: previousCalendar + inContext: context]) + { + if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles + onObject: componentCalendar + inContext: context]) + ex = [co moveToFolder: componentCalendar]; + } + + + } +/********************************************************/ if (ex) { NSDictionary *jsonResponse; diff --git a/UI/Scheduler/UIxCalDayTable.m b/UI/Scheduler/UIxCalDayTable.m index 799d55f57..7cfde1b1f 100644 --- a/UI/Scheduler/UIxCalDayTable.m +++ b/UI/Scheduler/UIxCalDayTable.m @@ -191,7 +191,7 @@ NSMutableDictionary *calendar; unsigned int count, foldersCount; NSString *folderName, *fDisplayName; - NSNumber *isActive; + BOOL *isActive; co = [self clientObject]; folders = [co subFolders]; diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index 3f488286d..3c4a1c3e4 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -33,7 +33,7 @@
-
+
@@ -75,7 +75,7 @@ -
+
diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index df9c19c4e..44fc3fac1 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -123,28 +123,34 @@ function newEventFromDragging(controller, day, coordinates) { newEvent("event", day, startHm, lengthHm); } -function updateEventFromDragging(controller, eventCells, eventDelta) { - if (eventDelta.dayNumber || eventDelta.start || eventDelta.duration) { - var params = ("days=" + eventDelta.dayNumber - + "&start=" + eventDelta.start * 15 - + "&duration=" + eventDelta.duration * 15); - // log("eventCells: " + eventCells.length); - var eventCell = eventCells[0]; - // log(" time: " + eventCell.recurrenceTime); - // log(" exception: " + eventCell.isException); - - if (eventCell.recurrenceTime && !eventCell.isException) - _editRecurrenceDialog(eventCell, "confirmAdjustment", params); - else { - var urlstr = (ApplicationBaseURL - + "/" + eventCell.calendar + "/" + eventCell.cname); - if (eventCell.recurrenceTime) - urlstr += "/occurence" + eventCell.recurrenceTime; - urlstr += ("/adjust?" + params); - // log(" urlstr: " + urlstr); - triggerAjaxRequest(urlstr, updateEventFromDraggingCallback); - } +function updateEventFromDragging(controller, eventCells, eventDelta, calendarID) { + if (eventDelta.dayNumber || eventDelta.start || eventDelta.duration) { + if (calendarID != 0) + var params = ("calendarID=" + calendarID + + "&days=" + 0 + + "&start=" + eventDelta.start * 15 + + "&duration=" + eventDelta.duration * 15); + else + var params = ("calendarID=" + calendarID + + "&days=" + eventDelta.dayNumber + + "&start=" + eventDelta.start * 15 + + "&duration=" + eventDelta.duration * 15); + // log("eventCells: " + eventCells.length); + var eventCell = eventCells[0]; + // log(" time: " + eventCell.recurrenceTime); + // log(" exception: " + eventCell.isException); + + if (eventCell.recurrenceTime && !eventCell.isException) + _editRecurrenceDialog(eventCell, "confirmAdjustment", params); + else { + var urlstr = (ApplicationBaseURL + "/" + eventCell.calendar + "/" + eventCell.cname); + if (eventCell.recurrenceTime) + urlstr += "/occurence" + eventCell.recurrenceTime; + urlstr += ("/adjust?" + params); + // log(" urlstr: " + urlstr); + triggerAjaxRequest(urlstr, updateEventFromDraggingCallback); } + } } function performEventAdjustment(folder, event, recurrence, params) { @@ -2293,6 +2299,22 @@ function calendarDisplayCallback(http) { if (currentView == "monthview") days[i].observe("scroll", onBodyClickHandler); } + else if (currentView == "multicolumndayview") { + var calendarHeader = $("calendarHeader"); + var headerCalendarsLabels = calendarHeader.select("DIV.calendarLabels DIV.calendarsToDisplay"); + var headerDays = calendarHeader.select("DIV.days DIV.day"); + for (var i = 0; i < days.length; i++) { + headerDays[i].hour = "allday"; + headerCalendarsLabels[i].observe("mousedown", listRowMouseDownHandler); + headerDays[i].observe("click", onCalendarSelectDay); + headerDays[i].observe("dblclick", onClickableCellsDblClick); + days[i].observe("click", onCalendarSelectDay); + + var clickableCells = days[i].select("DIV.clickableHourCell"); + for (var j = 0; j < clickableCells.length; j++) + clickableCells[j].observe("dblclick", onClickableCellsDblClick); + } + } else { var calendarHeader = $("calendarHeader"); var headerDaysLabels = calendarHeader.select("DIV.dayLabels DIV.day"); @@ -2706,6 +2728,19 @@ function onCalendarSelectDay(event) { var target = Event.findElement(event); var div = target.up('div'); + + // Select the calendar associated with the day clicked + if (currentView == "multicolumndayview") { + if (target.getAttribute("calendar")) + var calendar = "[id='/" + target.getAttribute("calendar") + "']"; + else + var calendar = "[id='/" + target.up("[calendar]").getAttribute("calendar") + "']"; + var list = $("calendarList"); + var selectedCalendar = list.down(calendar); + + onRowClick(event, selectedCalendar); + } + if (div && !div.hasClassName('event') && !div.hasClassName('eventInside') && !div.hasClassName('text') && !div.hasClassName('gradient')) { // Target is not an event -- unselect all events. listOfSelection = $("eventsList"); diff --git a/UI/WebServerResources/SchedulerUIDnD.js b/UI/WebServerResources/SchedulerUIDnD.js index 1e8d18eef..ee33b7048 100644 --- a/UI/WebServerResources/SchedulerUIDnD.js +++ b/UI/WebServerResources/SchedulerUIDnD.js @@ -8,6 +8,7 @@ var SOGoEventDragDayLength = 24 * 4; /* quarters */ var SOGoEventDragHandleSize = 8; /* handles for dragging mode */ var SOGoEventDragHorizontalOffset = 3; var SOGoEventDragVerticalOffset = 3; +var calendarID = [], activeCalendars = [];; /* singleton */ var _sogoEventDragUtilities = null; @@ -217,27 +218,31 @@ SOGoEventDragEventCoordinates.prototype = { }, initFromEventCellMultiDay: function(eventCell) { - var classNames = eventCell.className.split(" "); - for (var i = 0; - (this.start == -1 || this.duration == -1) - && i < classNames.length; - i++) { - var className = classNames[i]; + var classNames = eventCell.className.split(" "); + for (var i = 0; (this.start == -1 || this.duration == -1) && i < classNames.length; i++) { + var className = classNames[i]; if (className.startsWith("starts")) { - this.start = parseInt(className.substr(6)); + this.start = parseInt(className.substr(6)); } else if (className.startsWith("lasts")) { this.duration = parseInt(className.substr(5)); } } var dayNumber = -1; + var dayNode = eventCell.parentNode.parentNode; - var classNames = dayNode.className.split(" "); - for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { + if (currentView == "multicolumndayview") { + calendarID[0] = dayNode.getAttribute("calendar"); + var dayNumber = this._updateMulticolumnViewDayNumber(calendarID); + } + else { + var classNames = dayNode.className.split(" "); + for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("day") && className.length > 3) { dayNumber = parseInt(className.substr(3)); } + } } this.dayNumber = dayNumber; }, @@ -246,13 +251,19 @@ SOGoEventDragEventCoordinates.prototype = { this.duration = SOGoEventDragDayLength; var dayNode = eventCell.parentNode; - var classNames = dayNode.className.split(" "); - var dayNumber = -1; - for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { + if (currentView == "multicolumndayview") { + calendarID[0] = dayNode.getAttribute("calendar"); + var dayNumber = this._updateMulticolumnViewDayNumber(calendarID); + } + else { + var classNames = dayNode.className.split(" "); + var dayNumber = -1; + for (var i = 0; dayNumber == -1 && i < classNames.length; i++) { var className = classNames[i]; if (className.startsWith("day") && className.length > 3) { dayNumber = parseInt(className.substr(3)); } + } } this.dayNumber = dayNumber; }, @@ -294,8 +305,8 @@ SOGoEventDragEventCoordinates.prototype = { current.setEventType(this.eventType); current.initFromEventCell(eventCells[i]); if (this.dayNumber == -1 || current.dayNumber < this.dayNumber) { - this.dayNumber = current.dayNumber; - this.start = current.start; + this.dayNumber = current.dayNumber; + this.start = current.start; } this.duration += current.duration; } @@ -321,6 +332,20 @@ SOGoEventDragEventCoordinates.prototype = { return "" + hours + ":" + mins; }, + + _updateMulticolumnViewDayNumber: function(calendarID) { + var calendarList = $("calendarList").getElementsByTagName("li"); + for (var j = 0; j < calendarList.length ; j++) { + if ($("calendarList").getElementsByTagName("li")[j].down().checked) { + activeCalendars.push($("calendarList").getElementsByTagName("li")[j].getAttribute("id").substr(1)); + } + } + for (var k = 0; k < activeCalendars.length; k++) { + if (activeCalendars[k] == calendarID[0]) { + return k; + } + } + }, getStartTime: function() { return this._quartersToHM(this.start); @@ -515,12 +540,32 @@ SOGoEventDragGhostController.prototype = { } } }, - + + _updateMulticolumnViewDayNumber_SEDGC: function() { + var calendarID_SEDGC = this.folderClass.substr(14); + var calendarList = $("calendarList").getElementsByTagName("li"); + var activeCalendars = []; + for (var j = 0; j < calendarList.length ; j++) { + if ($("calendarList").getElementsByTagName("li")[j].down().checked) { + activeCalendars.push($("calendarList").getElementsByTagName("li")[j].getAttribute("id").substr(1)); + } + } + for (var k = 0; k < activeCalendars.length; k++) { + if (activeCalendars[k] == calendarID_SEDGC) { + this.currentCoordinates.dayNumber = k; + break; + } + } + }, + _updateCoordinates: function SEDGC__updateCoordinates() { var delta = this.currentPointerCoordinates .getDelta(this.originalPointerCoordinates); var deltaQuarters = delta.x * SOGoEventDragDayLength + delta.y; - this.currentCoordinates.dayNumber = this.originalCoordinates.dayNumber; + if (currentView == "multicolumndayview") + this._updateMulticolumnViewDayNumber_SEDGC(); + else + this.currentCoordinates.dayNumber = this.originalCoordinates.dayNumber; // log("dragMode: " + this.dragMode); if (this.dragMode == "move-event") { @@ -565,6 +610,10 @@ SOGoEventDragGhostController.prototype = { var deltaDays = Math.floor(this.currentCoordinates.start / SOGoEventDragDayLength); this.currentCoordinates.start -= deltaDays * SOGoEventDragDayLength; + + // This dayNumber needs to be updated with the calendar number. + if (currentView == "multicolumndayview") + this._updateMulticolumnViewDayNumber_SEDGC(); this.currentCoordinates.dayNumber += deltaDays; } }, @@ -1036,9 +1085,17 @@ SOGoEventDragController.prototype = { this.ghostController.initWithCoordinates(coordinates); if (!this.eventCells) { + if (currentView == "multicolumndayview") { + if (target.getAttribute("calendar")) + var folderID = target.getAttribute("calendar"); + else + var folderID = target.up("[calendar]").getAttribute("calendar"); + } + else { var folder = getSelectedFolder(); var folderID = folder.readAttribute("id").substr(1); - this.ghostController.setFolderClass("calendarFolder" + folderID); + } + this.ghostController.setFolderClass("calendarFolder" + folderID); } this.ghostController.setDragMode(this._determineDragMode()); this.ghostController.setPointerHandler(this.pointerHandler); @@ -1311,7 +1368,14 @@ SOGoEventDragController.prototype = { .currentCoordinates .getDelta(this.ghostController .originalCoordinates); - this.updateDropCallback(this, this.eventCells, delta); + if (currentView == "multicolumndayview" && delta.dayNumber != 0) { + var position = activeCalendars.indexOf(calendarID[0]); + position += delta.dayNumber; + calendarID[1] = activeCalendars[position]; + this.updateDropCallback(this, this.eventCells, delta, calendarID); + } + else + this.updateDropCallback(this, this.eventCells, delta, 0); } else { var eventContainerNodes = utilities.getEventContainerNodes(); var dayNode = eventContainerNodes[this.ghostController From ccf181bcf95a8bebf6c4ab9bdb66c151548cc00d Mon Sep 17 00:00:00 2001 From: Alexandre Cloutier Date: Thu, 10 Jul 2014 13:34:47 -0400 Subject: [PATCH 02/12] applied comments and fix repeated events dragNdrop between calendars --- UI/Scheduler/UIxAppointmentActions.m | 37 ++++++++++++++-------------- UI/WebServerResources/SchedulerUI.js | 4 +-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/UI/Scheduler/UIxAppointmentActions.m b/UI/Scheduler/UIxAppointmentActions.m index ddfb12b5b..2d7eb90a2 100644 --- a/UI/Scheduler/UIxAppointmentActions.m +++ b/UI/Scheduler/UIxAppointmentActions.m @@ -62,8 +62,8 @@ NSArray *calendarsID; NSTimeZone *tz; NSException *ex; - SOGoAppointmentFolder *componentCalendar, *previousCalendar; - SOGoAppointmentFolders *user; + SOGoAppointmentFolder *targetCalendar, *sourceCalendar; + SOGoAppointmentFolders *folders; rq = [context request]; @@ -116,27 +116,26 @@ [event setLastModified: [NSCalendarDate calendarDate]]; ex = [co saveComponent: event]; -/***************************** TODO ******************/ - if (![calendarID isEqualToString:@"0"]) { - user = [[self->context activeUser] calendarsFolderInContext: self->context]; - calendarsID = [calendarID componentsSeparatedByString:@","]; - previousCalendar = [user lookupName:[[calendarsID objectAtIndex:0] stringValue] inContext: self->context acquire: 0]; - componentCalendar = [user lookupName:[[calendarsID objectAtIndex:1] stringValue] inContext: self->context acquire: 0]; - // The event was moved to a different calendar. - sm = [SoSecurityManager sharedSecurityManager]; - if (![sm validatePermission: SoPerm_DeleteObjects - onObject: previousCalendar - inContext: context]) + if (![calendarID isEqualToString:@"0"]) { - if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles - onObject: componentCalendar + folders = [[self->context activeUser] calendarsFolderInContext: self->context]; + calendarsID = [calendarID componentsSeparatedByString:@","]; + sourceCalendar = [folders lookupName:[[calendarsID objectAtIndex:0] stringValue] inContext: self->context acquire: 0]; + targetCalendar = [folders lookupName:[[calendarsID objectAtIndex:1] stringValue] inContext: self->context acquire: 0]; + // The event was moved to a different calendar. + sm = [SoSecurityManager sharedSecurityManager]; + if (![sm validatePermission: SoPerm_DeleteObjects + onObject: sourceCalendar inContext: context]) - ex = [co moveToFolder: componentCalendar]; - } + { + if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles + onObject: targetCalendar + inContext: context]) + ex = [co moveToFolder: targetCalendar]; + } - } -/********************************************************/ + } if (ex) { NSDictionary *jsonResponse; diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index 44fc3fac1..2df837244 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -144,7 +144,7 @@ function updateEventFromDragging(controller, eventCells, eventDelta, calendarID) _editRecurrenceDialog(eventCell, "confirmAdjustment", params); else { var urlstr = (ApplicationBaseURL + "/" + eventCell.calendar + "/" + eventCell.cname); - if (eventCell.recurrenceTime) + if (eventCell.recurrenceTime && (calendarID[0] == calendarID[1])) urlstr += "/occurence" + eventCell.recurrenceTime; urlstr += ("/adjust?" + params); // log(" urlstr: " + urlstr); @@ -155,7 +155,7 @@ function updateEventFromDragging(controller, eventCells, eventDelta, calendarID) function performEventAdjustment(folder, event, recurrence, params) { var urlstr = ApplicationBaseURL + "/" + folder + "/" + event; - if (recurrence) + if (recurrence && (calendarID[0] == calendarID[1])) urlstr += "/" + recurrence; urlstr += "/adjust" + generateQueryString(params); triggerAjaxRequest(urlstr, updateEventFromDraggingCallback); From 6dddb5c98ce402268205eaa4fc7eec3068380f9f Mon Sep 17 00:00:00 2001 From: Alexandre Cloutier Date: Fri, 11 Jul 2014 17:04:06 -0400 Subject: [PATCH 03/12] dragNdrop from the events table to the calendars list --- UI/Templates/SchedulerUI/UIxCalMainView.wox | 2 +- UI/WebServerResources/SchedulerUI.js | 94 ++++++++++++++++++++- UI/WebServerResources/UIxOccurenceDialog.js | 3 +- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/UI/Templates/SchedulerUI/UIxCalMainView.wox b/UI/Templates/SchedulerUI/UIxCalMainView.wox index 1d40f4fc3..0a6ff09ff 100644 --- a/UI/Templates/SchedulerUI/UIxCalMainView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMainView.wox @@ -9,7 +9,7 @@ className="UIxPageFrame" const:userDefaultsKeys="SOGoCalendarCategoriesColors,SOGoDefaultCalendar" const:userSettingsKeys="Calendar,ShowCompletedTasks" - const:jsFiles="SchedulerUIDnD.js" + const:jsFiles="SchedulerUIDnD.js,jquery-ui.js" title="title">