From 45bc5a53680f0e0d844a072c565b13cfbf6152b6 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 29 Sep 2015 14:08:05 -0400 Subject: [PATCH] Multicolumn day view Restored multicolumn day view from v2. Month view as also been improved. --- UI/Scheduler/UIxCalDayTable.m | 14 +- UI/Scheduler/UIxCalListingActions.m | 27 ++- UI/Templates/SchedulerUI/UIxCalDayTable.wox | 160 +++++++----------- UI/Templates/SchedulerUI/UIxCalDayView.wox | 7 + UI/Templates/SchedulerUI/UIxCalMonthView.wox | 21 ++- .../SchedulerUI/UIxCalMulticolumnDayView.wox | 78 ++++----- UI/Templates/SchedulerUI/UIxCalWeekView.wox | 7 + .../js/Scheduler/CalendarController.js | 14 +- .../js/Scheduler/Component.service.js | 106 +++++++----- .../js/Scheduler/Scheduler.app.js | 35 +++- .../scss/views/SchedulerUI.scss | 43 ++++- 11 files changed, 285 insertions(+), 227 deletions(-) diff --git a/UI/Scheduler/UIxCalDayTable.m b/UI/Scheduler/UIxCalDayTable.m index 08c3dceac..737b51959 100644 --- a/UI/Scheduler/UIxCalDayTable.m +++ b/UI/Scheduler/UIxCalDayTable.m @@ -303,7 +303,7 @@ isLastOrFirstDay = NO; calendarFormat = @"%b"; - if ([currentView isEqualToString:@"dayview"]) + if ([currentView hasSuffix: @"dayview"]) { isLastOrFirstDay = YES; calendarFormat = @"%B"; @@ -456,22 +456,18 @@ unsigned int currentDayNbr, realDayOfWeek; classes = [NSMutableString string]; - if ([currentView isEqualToString:@"multicolumndayview"]) - [classes appendFormat:@"day dayColumn"]; - else { - currentDayNbr = [daysToDisplay indexOfObject: currentTableDay]; - realDayOfWeek = [currentTableDay dayOfWeek]; + currentDayNbr = [daysToDisplay indexOfObject: currentTableDay]; + realDayOfWeek = [currentTableDay dayOfWeek]; - [classes appendFormat: @"day day%d", currentDayNbr]; + [classes appendFormat: @"day day%d", currentDayNbr]; - if (numberOfDays > 1) + if (numberOfDays > 1) { if (realDayOfWeek == 0 || realDayOfWeek == 6) [classes appendString: @" weekEndDay"]; if ([currentTableDay isToday]) [classes appendString: @" dayOfToday"]; } - } return classes; } diff --git a/UI/Scheduler/UIxCalListingActions.m b/UI/Scheduler/UIxCalListingActions.m index 9975a8be6..d45dc8c8f 100644 --- a/UI/Scheduler/UIxCalListingActions.m +++ b/UI/Scheduler/UIxCalListingActions.m @@ -1225,7 +1225,7 @@ _computeBlocksPosition (NSArray *blocks) SOGoAppointmentFolder *folder; NSMutableArray *selectedCalendars; NSArray *folders; - NSString *fUID; + NSString *fUID, *fName; NSNumber *isActive; unsigned int count, foldersCount; @@ -1239,7 +1239,11 @@ _computeBlocksPosition (NSArray *blocks) isActive = [NSNumber numberWithBool: [folder isActive]]; if ([isActive intValue] != 0) { fUID = [folder nameInContainer]; - [selectedCalendars addObject: fUID]; + fName = [folder displayName]; + [selectedCalendars addObject: [NSDictionary dictionaryWithObjectsAndKeys: + fUID, @"id", + fName, @"name", + nil]]; } } return selectedCalendars; @@ -1297,9 +1301,10 @@ _computeBlocksPosition (NSArray *blocks) { int count, max; NSArray *events, *event, *calendars; - NSDictionary *eventsBlocks; - NSMutableArray *allDayBlocks, *blocks, *currentDay, *eventsByCalendars, *eventsForCalendar; + NSDictionary *eventsBlocks, *calendar; + NSMutableArray *allDayBlocks, *blocks, *currentDay, *eventsForCalendar, *eventsByCalendars; NSNumber *eventNbr; + NSString *calendarName, *calendarId; BOOL isAllDay; int i, j; @@ -1313,16 +1318,21 @@ _computeBlocksPosition (NSArray *blocks) eventsByCalendars = [NSMutableArray arrayWithCapacity:[calendars count]]; for (i = 0; i < [calendars count]; i++) // For each calendar { + calendar = [calendars objectAtIndex:i]; + calendarName =[calendar objectForKey: @"name"]; + calendarId = [calendar objectForKey: @"id"]; eventsForCalendar = [NSMutableArray array]; [self _prepareEventBlocks: &blocks withAllDays: &allDayBlocks]; for (j = 0; j < [events count]; j++) { - if ([[[events objectAtIndex:j] objectAtIndex:eventFolderIndex] isEqualToString:[calendars objectAtIndex:i]]) { + if ([[[events objectAtIndex:j] objectAtIndex:eventFolderIndex] isEqualToString: calendarId]) { // Event is in current calendar [eventsForCalendar addObject: [events objectAtIndex:j]]; } } eventsBlocks = [NSDictionary dictionaryWithObjectsAndKeys: - eventsFields, @"eventsFields", + calendarId , @"id", + calendarName, @"calendarName", + eventsFields, @"eventsFields", eventsForCalendar, @"events", allDayBlocks, @"allDayBlocks", blocks, @"blocks", nil]; @@ -1344,8 +1354,7 @@ _computeBlocksPosition (NSArray *blocks) [currentDay sortUsingSelector: @selector (compareEventByStart:)]; [self _addBlocksWidth: currentDay]; } - - [eventsByCalendars insertObject:eventsBlocks atIndex:i]; + [eventsByCalendars addObject: eventsBlocks]; } return [self _responseWithData: eventsByCalendars]; } @@ -1381,7 +1390,7 @@ _computeBlocksPosition (NSArray *blocks) [currentDay sortUsingSelector: @selector (compareEventByStart:)]; [self _addBlocksWidth: currentDay]; } - return [self _responseWithData: eventsBlocks]; + return [self _responseWithData: [NSArray arrayWithObject: eventsBlocks]]; } } diff --git a/UI/Templates/SchedulerUI/UIxCalDayTable.wox b/UI/Templates/SchedulerUI/UIxCalDayTable.wox index 47d0ace4d..a7445071a 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayTable.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayTable.wox @@ -8,66 +8,44 @@ xmlns:label="OGo:label"> - - + +
+ +
+ + +
+ +
+
+ +
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
+
+ -
- -
- -
-
-
- - -
- -
-
- -
-
-
- - +
- - -
-
-
-
-
- - - - -
- -
- - -
- -
-
- -
-
-
-
- - - -
-
- -
-
-
-
-
-
+
+ {{view.calendar.name}} +
@@ -75,9 +53,13 @@
-
+
@@ -101,46 +83,28 @@
- - - - -
-
- -
- - - -
-
+ +
+
+ +
+ + +
-
-
- - - - - - -
-
- -
- - - -
-
- -
-
+ +
-
-
+
+
+
diff --git a/UI/Templates/SchedulerUI/UIxCalDayView.wox b/UI/Templates/SchedulerUI/UIxCalDayView.wox index 02f52d6ce..6a2027ec3 100644 --- a/UI/Templates/SchedulerUI/UIxCalDayView.wox +++ b/UI/Templates/SchedulerUI/UIxCalDayView.wox @@ -22,12 +22,19 @@ today + view_day view_week view_module + view_array
diff --git a/UI/Templates/SchedulerUI/UIxCalMonthView.wox b/UI/Templates/SchedulerUI/UIxCalMonthView.wox index 3a4521916..477972898 100644 --- a/UI/Templates/SchedulerUI/UIxCalMonthView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMonthView.wox @@ -28,6 +28,13 @@ view_week + view_module + view_array
@@ -44,27 +51,31 @@
+ md-row-height="1:1" + md-gutter="0"> + var:id="currentDayId" + >
-
+
+ +
diff --git a/UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox b/UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox index 862a0026b..c888c920b 100644 --- a/UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox +++ b/UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox @@ -1,56 +1,46 @@ - + - diff --git a/UI/WebServerResources/js/Scheduler/CalendarController.js b/UI/WebServerResources/js/Scheduler/CalendarController.js index 435c716bb..b0273e6e3 100644 --- a/UI/WebServerResources/js/Scheduler/CalendarController.js +++ b/UI/WebServerResources/js/Scheduler/CalendarController.js @@ -10,15 +10,19 @@ function CalendarController($scope, $state, $stateParams, $timeout, $interval, $log, focus, Calendar, Component, stateEventsBlocks) { var vm = this; - vm.blocks = stateEventsBlocks.blocks; - vm.allDayBlocks = stateEventsBlocks.allDayBlocks; + vm.views = stateEventsBlocks; vm.changeView = changeView; // Refresh current view when the list of calendars is modified $scope.$on('calendars:list', function() { + // See stateEventsBlocks in Scheduler.app.js Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function(data) { - vm.blocks = data.blocks; - vm.allDayBlocks = data.allDayBlocks; + vm.views = data; + _.forEach(vm.views, function(view) { + if (view.id) { + view.calendar = new Calendar({ id: view.id, name: view.calendarName }); + } + }); }); }); @@ -28,7 +32,7 @@ $state.go('calendars.view', { view: $stateParams.view, day: date }); } } - + angular .module('SOGo.SchedulerUI') .controller('CalendarController', CalendarController); diff --git a/UI/WebServerResources/js/Scheduler/Component.service.js b/UI/WebServerResources/js/Scheduler/Component.service.js index 87d694faa..70eec8645 100644 --- a/UI/WebServerResources/js/Scheduler/Component.service.js +++ b/UI/WebServerResources/js/Scheduler/Component.service.js @@ -240,6 +240,10 @@ viewAction = 'dayView'; startDate = endDate = date; } + else if (view == 'multicolumnday') { + viewAction = 'multicolumndayView'; + startDate = endDate = date; + } else if (view == 'week') { viewAction = 'weekView'; startDate = date.beginOfWeek(); @@ -264,65 +268,79 @@ /** * @function $eventsBlocks * @desc Events blocks for a specific view and period - * @param {string} view - Either 'day' or 'week' + * @param {string} view - Either 'day', 'multicolumnday', 'week' or 'month' * @param {Date} startDate - period's start date * @param {Date} endDate - period's end date * @returns a promise of a collection of objects describing the events blocks */ Component.$eventsBlocks = function(view, startDate, endDate) { - var params, futureComponentData, i, + var params, futureComponentData, i, dates = [], deferred = Component.$q.defer(); params = { view: view.toLowerCase(), sd: startDate.getDayString(), ed: endDate.getDayString() }; Component.$log.debug('eventsblocks ' + JSON.stringify(params, undefined, 2)); futureComponentData = this.$$resource.fetch(null, 'eventsblocks', params); - futureComponentData.then(function(data) { + futureComponentData.then(function(views) { + var reduceComponent, associateComponent; + + reduceComponent = function(objects, eventData, i) { + var componentData = _.object(this.eventsFields, eventData), + start = new Date(componentData.c_startdate * 1000); + componentData.hour = start.getHourString(); + objects.push(new Component(componentData)); + return objects; + }; + + associateComponent = function(block) { + block.component = this[block.nbr]; + }; + + Component.$views = []; Component.$timeout(function() { - var components = [], blocks = {}, allDayBlocks = {}, dates = []; + _.forEach(views, function(data) { + var components = [], blocks = {}, allDayBlocks = {}, viewData; - // Instantiate Component objects - _.reduce(data.events, function(objects, eventData, i) { - var componentData = _.object(data.eventsFields, eventData), - start = new Date(componentData.c_startdate * 1000); - componentData.hour = start.getHourString(); - objects.push(new Component(componentData)); - return objects; - }, components); + // Instantiate Component objects + _.reduce(data.events, reduceComponent, components, data); - // Associate Component objects to blocks positions - _.each(_.flatten(data.blocks), function(block) { - block.component = components[block.nbr]; + // Associate Component objects to blocks positions + _.forEach(_.flatten(data.blocks), associateComponent, components); + + // Associate Component objects to all-day blocks positions + _.each(_.flatten(data.allDayBlocks), associateComponent, components); + + // Build array of dates + if (dates.length === 0) + for (i = 0; i < data.blocks.length; i++) { + dates.push(startDate.getDayString()); + startDate.addDays(1); + } + + // Convert array of blocks to object with days as keys + for (i = 0; i < data.blocks.length; i++) { + blocks[dates[i]] = data.blocks[i]; + } + + // Convert array of all-day blocks to object with days as keys + for (i = 0; i < data.allDayBlocks.length; i++) { + allDayBlocks[dates[i]] = data.allDayBlocks[i]; + } + + Component.$log.debug('blocks ready (' + _.flatten(data.blocks).length + ')'); + Component.$log.debug('all day blocks ready (' + _.flatten(data.allDayBlocks).length + ')'); + + // Save the blocks to the object model + viewData = { blocks: blocks, allDayBlocks: allDayBlocks }; + if (data.id && data.calendarName) { + // The multicolumnday view also includes calendar information + viewData.id = data.id; + viewData.calendarName = data.calendarName; + } + Component.$views.push(viewData); }); - // Associate Component objects to all-day blocks positions - _.each(_.flatten(data.allDayBlocks), function(allDayBlock) { - allDayBlock.component = components[allDayBlock.nbr]; - }); - - // Build array of dates - for (i = 0; i < data.blocks.length; i++) { - dates.push(startDate.getDayString()); - startDate.addDays(1); - } - - // Convert array of blocks to object with days as keys - for (i = 0; i < data.blocks.length; i++) { - blocks[dates[i]] = data.blocks[i]; - } - - // Convert array of all-day blocks to object with days as keys - for (i = 0; i < data.allDayBlocks.length; i++) { - allDayBlocks[dates[i]] = data.allDayBlocks[i]; - } - - Component.$log.debug('blocks ready (' + _.flatten(data.blocks).length + ')'); - Component.$log.debug('all day blocks ready (' + _.flatten(data.allDayBlocks).length + ')'); - - // Save the blocks to the object model - Component.$blocks = blocks; - Component.$allDayBlocks = allDayBlocks; - - deferred.resolve({ blocks: blocks, allDayBlocks: allDayBlocks }); + Component.$log.debug(JSON.stringify(Component.$views, undefined, 2)); + deferred.resolve(Component.$views); }); }, deferred.reject); diff --git a/UI/WebServerResources/js/Scheduler/Scheduler.app.js b/UI/WebServerResources/js/Scheduler/Scheduler.app.js index f5ee4860c..b25fe0e7f 100644 --- a/UI/WebServerResources/js/Scheduler/Scheduler.app.js +++ b/UI/WebServerResources/js/Scheduler/Scheduler.app.js @@ -28,7 +28,7 @@ } }) .state('calendars.view', { - url: '/{view:(?:day|week|month)}/:day', + url: '/{view:(?:day|week|month|multicolumnday)}/:day', sticky: true, deepStateRedirect: true, views: { @@ -36,7 +36,8 @@ templateUrl: function($stateParams) { // UI/Templates/SchedulerUI/UIxCalDayView.wox or // UI/Templates/SchedulerUI/UIxCalWeekView.wox or - // UI/Templates/SchedulerUI/UIxCalMonthView.wox + // UI/Templates/SchedulerUI/UIxCalMonthView.wox or + // UI/Templates/SchedulerUI/UIxCalMulticolumnDayView.wox return $stateParams.view + 'view?day=' + $stateParams.day; }, controller: 'CalendarController', @@ -53,6 +54,11 @@ var now = new Date(); return '/calendar/day/' + now.getDayString(); }); + $urlRouterProvider.when('/calendar/multicolumnday', function() { + // If no date is specified, show today + var now = new Date(); + return '/calendar/multicolumnday/' + now.getDayString(); + }); $urlRouterProvider.when('/calendar/week', function() { // If no date is specified, show today's week var now = new Date(); @@ -80,18 +86,31 @@ /** * @ngInject */ - stateEventsBlocks.$inject = ['$stateParams', 'Component']; - function stateEventsBlocks($stateParams, Component) { - return Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()); + stateEventsBlocks.$inject = ['$stateParams', 'Component', 'Calendar', ]; + function stateEventsBlocks($stateParams, Component, Calendar) { + // See CalendarController.js + return Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()) + .then(function(views) { + _.forEach(views, function(view) { + if (view.id) { + view.calendar = new Calendar({ id: view.id, name: view.calendarName }); + } + }); + return views; + }); } /** * @ngInject */ - runBlock.$inject = ['$rootScope', '$location', 'Preferences']; - function runBlock($rootScope, $location, Preferences) { + runBlock.$inject = ['$rootScope', '$log', '$location', 'Preferences']; + function runBlock($rootScope, $log, $location, Preferences) { + $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { + $log.error(error); + $state.go('calendar'); + }); $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) { - console.error(event, current, previous, rejection); + $log.error(event, current, previous, rejection); }); if ($location.url().length === 0) { // Restore user's last view diff --git a/UI/WebServerResources/scss/views/SchedulerUI.scss b/UI/WebServerResources/scss/views/SchedulerUI.scss index 92151d33e..846134ff8 100644 --- a/UI/WebServerResources/scss/views/SchedulerUI.scss +++ b/UI/WebServerResources/scss/views/SchedulerUI.scss @@ -8,6 +8,7 @@ $scrollbar_width: 16px; * - SchedulerUI/UIxCalWeekView.wox * - SchedulerUI/UIxCalDayTable.wox * - SchedulerUI/UIxCalMonthView.wox + * - SchedulerUI/UIxCalMulticolumnDayView.wox */ [ui-view=calendars] { @@ -57,7 +58,7 @@ $scrollbar_width: 16px; // The days labels appear in the toolbar md-toolbar { - &.daysView { + &.daysView, &.monthView { overflow: hidden; z-index: $z-index-toolbar - 1; .days { @@ -70,7 +71,7 @@ $scrollbar_width: 16px; } } } - &[sg-view=dayview] { + &[sg-view$=dayview] { .dayLabels { .day { display: flex; @@ -123,9 +124,10 @@ $scrollbar_width: 16px; text-overflow: ellipsis; white-space: nowrap; font-size: $sg-font-size-2; + padding: 2px; + min-height: $sg-font-size-2 + 4px; //font-weight: $sg-font-light; overflow: hidden; - padding: 2px; } // The left column of hours @@ -161,7 +163,7 @@ $scrollbar_width: 16px; .sg-event { font-size: $sg-font-size-2; &, md-icon { - color: #fff; + color: #fff !important; // Overwrite dynamic CSS theme } .material-icons { font-size: $sg-font-size-2; @@ -191,10 +193,41 @@ $scrollbar_width: 16px; } } + // Multicolumn day cell that contains the calendar name + .multicolumnDay { + font-size: $subhead-font-size-base; + font-weight: $sg-font-light; + overflow: hidden; + max-height: $subhead-font-size-base * 3; + padding-left: 2px; + margin-right: 2px; + } + .monthView { md-grid-tile { - border: 1px solid sg-color($sogoPaper, 300); + //border: 1px solid sg-color($sogoPaper, 300); + border-right: 1px solid rgb(242, 242, 242); + border-bottom: 1px solid rgb(242, 242, 242); overflow: auto; + &.dayOfAnotherMonth { + background-color: rgb(250, 250, 250); + //border-color: #ddd; + .sg-calendar-tile-header { + color: rgb(221, 221, 221) !important; // Overwrite dynamic CSS theme + } + } + &.dayOfToday { + .sg-calendar-tile-header { + border-radius: 50%; + color: #fff; + display: inline; + font-weight: 600; + margin-right: auto; + } + } + } + md-content { + background-color: transparent; // See the grid tile background color } .sg-event { position: relative;