From ac9bcf853940c058a6cd1bd3fd9c8643a79dbdf9 Mon Sep 17 00:00:00 2001 From: GabrielMeyer Date: Wed, 17 Jul 2019 12:26:13 +0200 Subject: [PATCH] Implements a custom sorting for categories - If the motion-list is sorted by categories, the category is internal sorted by the `category_weight` of the motion - Adds a slot to pass a custom sorting function to the `sort-filter-bar.component` --- .../ui-services/base-sort-list.service.ts | 82 +++++++++---------- .../sort-filter-bar.component.ts | 2 + .../services/motion-sort-list.service.ts | 28 ++++++- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/client/src/app/core/ui-services/base-sort-list.service.ts b/client/src/app/core/ui-services/base-sort-list.service.ts index 39687532d..235fea21e 100644 --- a/client/src/app/core/ui-services/base-sort-list.service.ts +++ b/client/src/app/core/ui-services/base-sort-list.service.ts @@ -20,6 +20,7 @@ export interface OsSortingDefinition { export interface OsSortingOption { property: keyof V; label?: string; + sortFn?: (itemA: V, itemB: V, ascending: boolean, intl?: Intl.Collator) => number; } /** @@ -57,7 +58,7 @@ export abstract class BaseSortListService { /** * The sorting function according to current settings. */ - private sortFn: (a: V, b: V) => number; + public sortFn?: (a: V, b: V, ascending: boolean, intl?: Intl.Collator) => number; /** * Set the current sorting order @@ -201,16 +202,6 @@ export abstract class BaseSortListService { this.store.set('sorting_' + this.name, this.sortDefinition); } - /** - * Sorts an array of data synchronously, using the currently configured sorting - * - * @param data Array of ViewModels - * @returns the data, sorted with the definitions of this service - */ - public sortSync(data: V[]): V[] { - return data.sort(this.sortFn); - } - /** * Helper function to determine false-like values (if they are not boolean) * @param property @@ -246,42 +237,45 @@ export abstract class BaseSortListService { const firstProperty = this.ascending ? itemA[property] : itemB[property]; const secondProperty = this.ascending ? itemB[property] : itemA[property]; - switch (typeof firstProperty) { - case 'boolean': - if (!firstProperty && secondProperty) { - return -1; - } else { - return 1; - } - case 'number': - return firstProperty > secondProperty ? 1 : -1; - case 'string': - if (!!firstProperty && !secondProperty) { - return -1; - } else if (!firstProperty && !!secondProperty) { - return 1; - } else if ((!secondProperty && !secondProperty) || firstProperty === secondProperty) { - return 0; - } else { - return intl.compare(firstProperty, secondProperty); - } - case 'function': - const a = firstProperty(); - const b = secondProperty(); - return intl.compare(a, b); - case 'object': - if (firstProperty instanceof Date) { + if (this.sortFn) { + return this.sortFn(itemA, itemB, this.ascending, intl); + } else { + switch (typeof firstProperty) { + case 'boolean': + if (!firstProperty && secondProperty) { + return -1; + } else { + return 1; + } + case 'number': return firstProperty > secondProperty ? 1 : -1; - } else { - return intl.compare(firstProperty.toString(), secondProperty.toString()); - } - case 'undefined': - return 1; - default: - return -1; + case 'string': + if (!!firstProperty && !secondProperty) { + return -1; + } else if (!firstProperty && !!secondProperty) { + return 1; + } else if ((!secondProperty && !secondProperty) || firstProperty === secondProperty) { + return 0; + } else { + return intl.compare(firstProperty, secondProperty); + } + case 'function': + const a = firstProperty(); + const b = secondProperty(); + return intl.compare(a, b); + case 'object': + if (firstProperty instanceof Date) { + return firstProperty > secondProperty ? 1 : -1; + } else { + return intl.compare(firstProperty.toString(), secondProperty.toString()); + } + case 'undefined': + return 1; + default: + return -1; + } } }); - this.outputSubject.next(this.inputData); } } diff --git a/client/src/app/shared/components/sort-filter-bar/sort-filter-bar.component.ts b/client/src/app/shared/components/sort-filter-bar/sort-filter-bar.component.ts index a3f544122..b30af6975 100644 --- a/client/src/app/shared/components/sort-filter-bar/sort-filter-bar.component.ts +++ b/client/src/app/shared/components/sort-filter-bar/sort-filter-bar.component.ts @@ -134,6 +134,8 @@ export class SortFilterBarComponent { } public set sortOption(option: OsSortingOption) { + // If the option has a custom sorting function + this.sortService.sortFn = option.sortFn || null; this.sortService.sortProperty = option.property; } diff --git a/client/src/app/site/motions/services/motion-sort-list.service.ts b/client/src/app/site/motions/services/motion-sort-list.service.ts index c4940ce2d..5122a10d1 100644 --- a/client/src/app/site/motions/services/motion-sort-list.service.ts +++ b/client/src/app/site/motions/services/motion-sort-list.service.ts @@ -34,7 +34,7 @@ export class MotionSortListService extends BaseSortListService { { property: 'identifier' }, { property: 'title' }, { property: 'submitters' }, - { property: 'category' }, + { property: 'category', sortFn: this.categorySortFn }, { property: 'motion_block_id', label: 'Motion block' }, { property: 'state' }, { property: 'creationDate', label: _('Creation date') }, @@ -71,4 +71,30 @@ export class MotionSortListService extends BaseSortListService { sortAscending: true }; } + + /** + * Custom function to sort the categories internal by the `category_weight` of the motion. + * + * @param itemA The first item to sort + * @param itemB The second item to sort + * @param intl The localizer to compare strings + * @param ascending If the sorting should be in ascended or descended order + * + * @returns {number} The result of comparing. + */ + private categorySortFn(itemA: ViewMotion, itemB: ViewMotion, ascending: boolean, intl: Intl.Collator): number { + const property = 'category'; + const subProperty = 'category_weight'; + const firstValue = ascending ? itemA[property] : itemB[property]; + const secondValue = ascending ? itemB[property] : itemA[property]; + + const diff = intl.compare(firstValue.toString(), secondValue.toString()); + if (diff === 0) { + const firstSubValue = ascending ? itemA[subProperty] : itemB[subProperty]; + const secondSubValue = ascending ? itemB[subProperty] : itemA[subProperty]; + return firstSubValue > secondSubValue ? 1 : -1; + } else { + return diff; + } + } }