Added sort functionality (visible in settings, bottom left) (#569)

* Added sort functionality (visible in settings, bottom left)

* Fallback to fullName if the sort criteria is not set within the contact; displayName is now the default sort criteria

* Changing display name based on sort order; sorting takes both first and second name in consideration
This commit is contained in:
Jury Verrigni 2017-02-01 12:04:55 +00:00 committed by Alexander Weidinger
parent 9523b407cb
commit 6529a8e9d4
12 changed files with 172 additions and 5 deletions

View File

@ -1,5 +1,5 @@
angular.module('contactsApp')
.controller('contactCtrl', function($route, $routeParams) {
.controller('contactCtrl', function($route, $routeParams, SortByService) {
var ctrl = this;
ctrl.t = {
@ -11,4 +11,29 @@ angular.module('contactsApp')
gid: $routeParams.gid,
uid: ctrl.contact.uid()});
};
ctrl.getName = function() {
// If lastName equals to firstName then none of them is set
if (ctrl.contact.lastName() === ctrl.contact.firstName()) {
return ctrl.contact.displayName();
}
if (SortByService.getSortBy() === 'sortLastName') {
return (
ctrl.contact.lastName() + ', '
+ ctrl.contact.firstName() + ' '
+ ctrl.contact.additionalNames()
).trim();
}
if (SortByService.getSortBy() === 'sortFirstName') {
return (
ctrl.contact.firstName() + ' '
+ ctrl.contact.additionalNames() + ' '
+ ctrl.contact.lastName()
).trim();
}
return ctrl.contact.displayName();
};
});

View File

@ -1,5 +1,5 @@
angular.module('contactsApp')
.controller('contactlistCtrl', function($scope, $filter, $route, $routeParams, ContactService, vCardPropertiesService, SearchService) {
.controller('contactlistCtrl', function($scope, $filter, $route, $routeParams, ContactService, SortByService, vCardPropertiesService, SearchService) {
var ctrl = this;
ctrl.routeParams = $routeParams;
@ -9,6 +9,8 @@ angular.module('contactsApp')
ctrl.show = true;
ctrl.invalid = false;
ctrl.sortBy = SortByService.getSortBy();
ctrl.t = {
emptySearch : t('contacts', 'No search result for {query}', {query: ctrl.searchTerm})
};
@ -21,6 +23,10 @@ angular.module('contactsApp')
return contact.matches(SearchService.getSearchTerm());
};
SortByService.subscribe(function(newValue) {
ctrl.sortBy = newValue;
});
SearchService.registerObserverCallback(function(ev) {
if (ev.event === 'submitSearch') {
var uid = !_.isEmpty(ctrl.contactList) ? ctrl.contactList[0].uid() : undefined;

View File

@ -0,0 +1,16 @@
angular.module('contactsApp')
.controller('sortbyCtrl', function(SortByService) {
var ctrl = this;
var sortText = t('contacts', 'Sort by');
ctrl.sortText = sortText;
var sortList = SortByService.getSortByList();
ctrl.sortList = sortList;
ctrl.defaultOrder = SortByService.getSortBy();
ctrl.updateSortBy = function() {
SortByService.setSortBy(ctrl.defaultOrder);
};
});

View File

@ -0,0 +1,11 @@
angular.module('contactsApp')
.directive('sortby', function() {
return {
priority: 1,
scope: {},
controller: 'sortbyCtrl',
controllerAs: 'ctrl',
bindToController: {},
templateUrl: OC.linkTo('contacts', 'templates/sortBy.html')
};
});

View File

@ -27,10 +27,16 @@ angular.module('contactsApp')
return !reverseOrder ? valueA - valueB : valueB - valueA;
}
if (angular.isArray(valueA)) {
if (valueA[0] === valueB[0]) {
return !reverseOrder ? valueA[1].localeCompare(valueB[1]) : valueB[1].localeCompare(valueA[1]);
}
return !reverseOrder ? valueA[0].localeCompare(valueB[0]) : valueB[0].localeCompare(valueA[0]);
}
return 0;
});
return arrayCopy;
};
}]);

View File

@ -31,6 +31,18 @@ angular.module('contactsApp')
}
},
sortFirstName: function() {
return [this.firstName(), this.lastName()];
},
sortLastName: function() {
return [this.lastName(), this.firstName()];
},
sortDisplayName: function() {
return this.displayName();
},
displayName: function() {
var displayName = this.fullName() || this.org() || '';
if(angular.isArray(displayName)) {
@ -49,6 +61,33 @@ angular.module('contactsApp')
},
firstName: function() {
var property = this.getProperty('n');
if (property) {
return property.value[1];
} else {
return this.displayName();
}
},
lastName: function() {
var property = this.getProperty('n');
if (property) {
return property.value[0];
} else {
return this.displayName();
}
},
additionalNames: function() {
var property = this.getProperty('n');
if (property) {
return property.value[2];
} else {
return '';
}
},
fullName: function(value) {
var model = this;
if (angular.isDefined(value)) {

View File

@ -0,0 +1,39 @@
angular.module('contactsApp')
.service('SortByService', function () {
var subscriptions = [];
var sortBy = 'sortDisplayName';
var defaultOrder = window.localStorage.getItem('contacts_default_order');
if (defaultOrder) {
sortBy = defaultOrder;
}
function notifyObservers () {
angular.forEach(subscriptions, function (subscription) {
if (typeof subscription === 'function') {
subscription(sortBy);
}
});
}
return {
subscribe: function (callback) {
subscriptions.push (callback);
},
setSortBy: function (value) {
sortBy = value;
window.localStorage.setItem ('contacts_default_order', value);
notifyObservers ();
},
getSortBy: function () {
return sortBy;
},
getSortByList: function () {
return {
sortDisplayName: t('contacts', 'Display name'),
sortFirstName: t('contacts', 'First name'),
sortLastName: t('contacts', 'Last name')
};
}
};
});

View File

@ -0,0 +1,20 @@
describe('sortbyService', function() {
var $Service;
beforeEach(module('contactsApp'));
beforeEach(inject(function(SortByService){
$Service = SortByService;
}));
it('should return sortDisplayName as default sorting method', function() {
expect($Service.getSortBy()).to.equal('sortDisplayName');
});
it('should store sorting method', function() {
$Service.setSortBy('sortLastName');
expect($Service.getSortBy()).to.equal(
window.localStorage.getItem('contacts_default_order')
);
});
});

View File

@ -3,6 +3,6 @@
<div class="app-content-list-item-icon contact__icon" ng-show="ctrl.contact.photo()===undefined" ng-style="{'background-color': (ctrl.contact.uid() | contactColor) }">{{ ctrl.contact.displayName() | firstCharacter }}</div>
<div class="app-content-list-item-star icon-star" data-starred="false"></div>
<div class="app-content-list-item-failed icon-error" tooltip-placement="auto left" ng-if="ctrl.contact.failedProps.length>0" uib-tooltip="{{ ctrl.t.errorMessage }}"></div>
<div class="app-content-list-item-line-one" ng-class="{'no-line-two':!ctrl.contact.email()}">{{ ctrl.contact.displayName() | newContact }}</div>
<div class="app-content-list-item-line-one" ng-class="{'no-line-two':!ctrl.contact.email()}">{{ ctrl.getName() | newContact }}</div>
<div class="app-content-list-item-line-two">{{ctrl.contact.email()}}</div>
</a>

View File

@ -1,6 +1,6 @@
<div style="height: 90%" class="contacts-list" ng-class="{loading: ctrl.loading, 'mobile-show': ctrl.show}">
<div class="app-content-list-item"
ng-repeat="contact in ctrl.contactList = (ctrl.contacts | contactGroupFilter:ctrl.routeParams.gid | localeOrderBy:'displayName' | filter:query) as filtered track by contact.uid()"
ng-repeat="contact in ctrl.contactList = (ctrl.contacts | contactGroupFilter:ctrl.routeParams.gid | localeOrderBy:ctrl.sortBy | filter:query) as filtered track by contact.uid()"
contact data="contact"
ng-click="setSelected(contact.uid())"
ng-class="{active: contact.uid() === ctrl.getSelectedId()}">

View File

@ -38,6 +38,7 @@ vendor_style('select2/select2');
<div id="app-settings-content">
<addressBookList></addressBookList>
<contactImport></contactImport>
<sortBy></sortBy>
</div>
</div>
</div>

4
templates/sortBy.html Normal file
View File

@ -0,0 +1,4 @@
<label for="contact-import">{{ctrl.sortText}}:</label>
<select ng-change="ctrl.updateSortBy()" ng-model="ctrl.defaultOrder" id="sort-by">
<option ng-repeat="(key, value) in ctrl.sortList" ng-model="ctrl.sortList[key]" ng-selected="ctrl.defaultOrder == key" value="{{key}}">{{value}}</option>
</select>