From 991f1d25a4943554fc7d018180387dcce73928ac Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Mon, 26 Aug 2019 16:38:00 -0400 Subject: [PATCH] (js) Improve attendees editor performance --- .../SchedulerUI/UIxAttendeesEditor.wox | 55 ++------- .../js/Scheduler/Attendees.service.js | 3 + .../js/Scheduler/sgFreebusy.directive.js | 58 +++++++++ .../js/Scheduler/sgFreebusyDay.directive.js | 116 ++++++++++++++++++ 4 files changed, 190 insertions(+), 42 deletions(-) create mode 100644 UI/WebServerResources/js/Scheduler/sgFreebusy.directive.js create mode 100644 UI/WebServerResources/js/Scheduler/sgFreebusyDay.directive.js diff --git a/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox b/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox index 48f2122dc..65e94f4d3 100644 --- a/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox +++ b/UI/Templates/SchedulerUI/UIxAttendeesEditor.wox @@ -43,11 +43,11 @@ person person
-
{{editor.component.organizer.name}}
-
{{editor.component.organizer.email}}
+
{{::editor.component.organizer.name}}
+
{{::editor.component.organizer.email}}
@@ -78,7 +78,7 @@ - + - -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
+ - -
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
+
diff --git a/UI/WebServerResources/js/Scheduler/Attendees.service.js b/UI/WebServerResources/js/Scheduler/Attendees.service.js index 1e9fe5701..04a6a73b5 100644 --- a/UI/WebServerResources/js/Scheduler/Attendees.service.js +++ b/UI/WebServerResources/js/Scheduler/Attendees.service.js @@ -23,6 +23,7 @@ this.slotEndTimeLimit.setMinutes(0); this.slotEndTimeLimit.setHours(Attendees.dayEndHour); this.$days = []; + this.$futureFreebusyData = {}; this.updateFreeBusyCoverage(); this.updateFreeBusy(); } @@ -432,6 +433,8 @@ promise = Attendees.$q.when(); } + this.$futureFreebusyData[attendee.uid] = promise; + return promise; } }; diff --git a/UI/WebServerResources/js/Scheduler/sgFreebusy.directive.js b/UI/WebServerResources/js/Scheduler/sgFreebusy.directive.js new file mode 100644 index 000000000..2a655fc5e --- /dev/null +++ b/UI/WebServerResources/js/Scheduler/sgFreebusy.directive.js @@ -0,0 +1,58 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +(function() { + + /** + * sgFreebusy - A directive that watches some attributes of a component. Any child component + * should depends on this directive and extend the 'onUpdate' method instead of creating new + * independent watchers. + * @memberof SOGo.SchedulerUI + */ + function sgFreebusy() { + return { + restrict: 'C', + scope: {}, + bindToController: { + component: '=sgComponent' + }, + controller: sgFreebusyController + }; + } + + /** + * @ngInject + */ + sgFreebusyController.$inject = ['$scope', '$element', '$q']; + function sgFreebusyController($scope, $element, $q) { + var $ctrl = this; + + this.$onInit = function () { + var watchedAttrs = ['start', 'end', 'attendees']; + + $scope.$watch( + function() { + return $ctrl.component? [ _.pick($ctrl.component, watchedAttrs) ] : null; + }, + function(newId, oldId) { + if ($ctrl.component) { + // Component has changed + $q.all(_.values($ctrl.component.$attendees.$futureFreebusyData)).then(function() { + $ctrl.onUpdate(); + }); + } + }, + true // compare for object equality + ); + }; + + + this.onUpdate = function () { + // console.debug('dates or attendees changed -- refresh freebusy'); + }; + } + + + angular + .module('SOGo.SchedulerUI') + .directive('sgFreebusy', sgFreebusy); +})(); diff --git a/UI/WebServerResources/js/Scheduler/sgFreebusyDay.directive.js b/UI/WebServerResources/js/Scheduler/sgFreebusyDay.directive.js new file mode 100644 index 000000000..cf9393b16 --- /dev/null +++ b/UI/WebServerResources/js/Scheduler/sgFreebusyDay.directive.js @@ -0,0 +1,116 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +(function() { + + /* + * sgFreebusyDay - A representation of the freebusy data for an attendee for one day. + * @memberof SOGo.SchedulerUI + * @restrict element + * @param {string} sgDay - the day string + * @param {object} sgAttendees - the Attendees object instance of the component + * @param {object} sgAttendee - the object representing the attendee + * + * @example: + + + */ + function sgFreebusyDay() { + return { + restrict: 'E', + require: '^^sgFreebusy', + bindToController: { + day: '=sgDay', + attendees: '=sgAttendees', + attendee: '=sgAttendee' + }, + replace: true, + template: function(tElement, tAttrs) { + var template = [ + '' + ]; + for (var hour = 0; hour < 24; hour++) { + template.push('
'); + for (var quarter = 0; quarter < 4; quarter++) { + template.push('
'); + template.push('
'); + template.push('
'); + } + template.push('
'); + } + template.push(' '); + template.push('
'); + + return template.join(''); + }, + link: postLink, + controller: sgFreebusyDayController, + controllerAs: '$ctrl' + }; + + function postLink(scope, element, attrs, parentController) { + scope.parentController = parentController; + } + } + + /** + * @ngInject + */ + sgFreebusyDayController.$inject = ['$scope', '$element']; + function sgFreebusyDayController($scope, $element) { + var $ctrl = this; + + this.$postLink = function () { + var hours = [], quarters = [], busys = [], parentControllerOnUpdate; + + this.parentController = $scope.parentController; + parentControllerOnUpdate = this.parentController.onUpdate; + + _.forEach($element.find('div'), function(div) { + if (div.className.startsWith('hour')) hours.push(div); + else if (div.className.startsWith('quarter')) quarters.push(div); + else if (div.className.startsWith('busy')) busys.push(div); + }); + + this.parentController.onUpdate = function () { + var freebusys = $ctrl.attendee.freebusy[$ctrl.day]; + + if (!$ctrl.attendee.uid) { + _.forEach(hours, function(div) { + div.classList.add('sg-no-freebusy'); + }); + } + + for (var hour = 0; hour < 24; hour++) { + for (var quarter = 0; quarter < 4; quarter++) { + var index = hour * 4 + quarter; + if ($ctrl.coversFreebusy(hour, quarter)) { + quarters[index].classList.add('event'); + } else { + quarters[index].classList.remove('event'); + } + if (freebusys[hour][quarter]) { + busys[index].classList.remove('ng-hide'); + } else { + busys[index].classList.add('ng-hide'); + } + } + } + + // Call original method on parent controller + angular.bind($ctrl.parentController, parentControllerOnUpdate)(); + }; + }; + + this.coversFreebusy = function (hour, quarter) { + return $ctrl.attendees.coversFreeBusy($ctrl.day, hour, quarter); + }; + } + + angular + .module('SOGo.SchedulerUI') + .directive('sgFreebusyDay', sgFreebusyDay); +})();