(js) Improve attendees editor performance

pull/259/head
Francis Lachapelle 2019-08-26 16:38:00 -04:00
parent 4df69587a2
commit 991f1d25a4
4 changed files with 190 additions and 42 deletions

View File

@ -43,11 +43,11 @@
<md-icon>person</md-icon>
</div>
<sg-avatar-image class="md-avatar"
sg-email="editor.component.organizer.email"
sg-email="::editor.component.organizer.email"
size="40">person</sg-avatar-image>
<div class="sg-tile-content sg-padded--right">
<div class="sg-md-subhead"><div>{{editor.component.organizer.name}}</div></div>
<div class="sg-md-body"><div>{{editor.component.organizer.email}}</div></div>
<div class="sg-md-subhead"><div>{{::editor.component.organizer.name}}</div></div>
<div class="sg-md-body"><div>{{::editor.component.organizer.email}}</div></div>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>
@ -78,7 +78,7 @@
<md-divider><!-- divider --></md-divider>
</md-list-item>
</md-list>
<md-content id="freebusy">
<md-content id="freebusy" class="sg-freebusy" sg-component="editor.component">
<!-- freebusy -->
<md-list class="day"
id="freebusy_day_{{ day.getDayString }}"
@ -93,45 +93,16 @@
</div>
</md-list-item>
<!-- organizer freebusy -->
<md-list-item>
<div class="hour"
ng-class="{'sg-no-freebusy': !editor.component.organizer.uid}"
ng-repeat="hour in ::editor.attendeesEditor.hours">
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 0)}">
<div class="busy" ng-show="editor.component.organizer.freebusy[day.getDayString][hour][0]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 1)}">
<div class="busy" ng-show="editor.component.organizer.freebusy[day.getDayString][hour][1]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 2)}">
<div class="busy" ng-show="editor.component.organizer.freebusy[day.getDayString][hour][2]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 3)}">
<div class="busy" ng-show="editor.component.organizer.freebusy[day.getDayString][hour][3]"><!-- 15 minutes --></div>
</div>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>
<sg-freebusy-day
sg-day="day.getDayString"
sg-attendees="editor.component.$attendees"
sg-attendee="editor.component.organizer"><!-- organizer --></sg-freebusy-day>
<!-- attendees freebusy -->
<md-list-item ng-repeat="currentAttendee in editor.component.attendees track by currentAttendee.email">
<div class="hour"
ng-class="{'sg-no-freebusy': !currentAttendee.uid}"
ng-repeat="hour in ::editor.attendeesEditor.hours">
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 0)}">
<div class="busy" ng-show="currentAttendee.freebusy[day.getDayString][hour][0]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 1)}">
<div class="busy" ng-show="currentAttendee.freebusy[day.getDayString][hour][1]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 2)}">
<div class="busy" ng-show="currentAttendee.freebusy[day.getDayString][hour][2]"><!-- 15 minutes --></div>
</div>
<div class="quarter" ng-class="{event: editor.coversFreeBusy(day.getDayString, hour, 3)}">
<div class="busy" ng-show="currentAttendee.freebusy[day.getDayString][hour][3]"><!-- 15 minutes --></div>
</div>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>
<sg-freebusy-day
ng-repeat="currentAttendee in editor.component.attendees track by currentAttendee.email"
sg-day="day.getDayString"
sg-attendees="editor.component.$attendees"
sg-attendee="currentAttendee"><!-- attendees --></sg-freebusy-day>
</md-list>
</md-content>
</div><!-- row -->

View File

@ -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;
}
};

View File

@ -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);
})();

View File

@ -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:
<sg-freebusy-day
ng-repeat="currentAttendee in component.attendees"
sg-day="day.getDayString"
sg-attendees="component.$attendees"
sg-attendee="currentAttendee" />
*/
function sgFreebusyDay() {
return {
restrict: 'E',
require: '^^sgFreebusy',
bindToController: {
day: '=sgDay',
attendees: '=sgAttendees',
attendee: '=sgAttendee'
},
replace: true,
template: function(tElement, tAttrs) {
var template = [
'<md-list-item>'
];
for (var hour = 0; hour < 24; hour++) {
template.push(' <div class="hour">');
for (var quarter = 0; quarter < 4; quarter++) {
template.push(' <div class="quarter">');
template.push(' <div class="busy ng-hide"></div>');
template.push(' </div>');
}
template.push(' </div>');
}
template.push(' <md-divider><!-- divider --></md-divider>');
template.push('</md-list-item>');
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);
})();