Repository URL to install this package:
|
Version:
1.0.0-next.10 ▾
|
/**
* @license
* FOURBURNER CONFIDENTIAL
* Unpublished Copyright (C) 2021 FourBurner Technologies, Inc. All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of FOURBURNER TECHNOLOGIES,
* INC. The intellectual and technical concepts contained herein are proprietary to FOURBURNER
* TECHNOLOGIES, INC. and may be covered by U.S. and Foreign Patents, patents in process, and are
* protected by trade secret or copyright law. Dissemination of this information or reproduction of
* this material is strictly forbidden unless prior written permission is obtained from FOURBURNER
* TECHNOLOGIES, INC. Access to the source code contained herein is hereby forbidden to anyone
* except current FOURBURNER TECHNOLOGIES, INC. employees, managers or contractors who have executed
* Confidentiality and Non-disclosure agreements explicitly covering such access.
*
* The copyright notice above does not evidence any actual or intended publication or disclosure of
* this source code, which includes information that is confidential and/or proprietary, and is a
* trade secret, of FOURBURNER TECHNOLOGIES, INC. ANY REPRODUCTION, MODIFICATION, DISTRIBUTION,
* PUBLIC PERFORMANCE, OR PUBLIC DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS
* WRITTEN CONSENT OF FOURBURNER TECHNOLOGIES, INC. IS STRICTLY PROHIBITED, AND IN VIOLATION OF
* APPLICABLE LAWS AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE AND/OR
* RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE, DISCLOSE OR DISTRIBUTE ITS
* CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING THAT IT MAY DESCRIBE, IN WHOLE OR IN PART.
*/
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
import {
Directive,
EventEmitter,
Inject,
InjectionToken,
Input,
OnChanges,
OnDestroy,
OnInit,
Optional,
Output,
} from '@angular/core';
import {
CanDisable,
HasInitialized,
mixinDisabled,
mixinInitialized,
ngDevMode
} from '@twnd/ux/core';
import {Subject} from 'rxjs';
import {SortDirection} from './sort.direction';
import {
getSortDuplicateSortableIdError,
getSortHeaderMissingIdError,
getSortInvalidDirectionError,
} from './sort.errors';
/** Interface for a directive that holds sorting state consumed by `TWNDSortHeader`. */
export interface TWNDSortable {
/** The id of the column being sorted. */
id: string;
/** Starting sort direction. */
start: 'asc'|'desc';
/** Whether to disable clearing the sorting state. */
disableClear: boolean;
}
/** The current sort state. */
export interface Sort {
/** The id of the column being sorted. */
active: string;
/** The sort direction. */
direction: SortDirection;
}
/** Default options for `twnd-sort`. */
export interface TWNDSortDefaultOptions {
/** Whether to disable clearing the sorting state. */
disableClear?: boolean;
}
/** Injection token to be used to override the default options for `twnd-sort`. */
export const TWND_SORT_DEFAULT_OPTIONS = new InjectionToken<TWNDSortDefaultOptions>(
'TWND_SORT_DEFAULT_OPTIONS',
);
// Boilerplate for applying mixins to TWNDSort.
/** @docs-private */
const _TWNDSortBase = mixinInitialized(mixinDisabled(class {}));
/** Container for TWNDSortables to manage the sort state and provide default sort parameters. */
@Directive({
selector : '[twndSort]',
exportAs : 'twndSort',
host : {'class' : 'twnd-sort'},
inputs : [ 'disabled: twndSortDisabled' ],
})
export class TWNDSort extends _TWNDSortBase implements CanDisable, HasInitialized, OnChanges,
OnDestroy, OnInit
{
/** Collection of all registered sortables that this directive manages. */
sortables = new Map<string, TWNDSortable>();
/** Used to notify any child components listening to state changes. */
readonly _stateChanges = new Subject<void>();
/** The id of the most recently sorted TWNDSortable. */
@Input('twndSortActive') active: string;
/**
* The direction to set when an TWNDSortable is initially sorted.
* May be overriden by the TWNDSortable's sort start.
*/
@Input('twndSortStart') start: 'asc'|'desc' = 'asc';
/** The sort direction of the currently active TWNDSortable. */
@Input('twndSortDirection') get direction(): SortDirection
{
return this._direction;
}
set direction(direction: SortDirection)
{
if (direction && direction !== 'asc' && direction !== 'desc' &&
(typeof ngDevMode === 'undefined' || ngDevMode)) {
throw getSortInvalidDirectionError(direction);
}
this._direction = direction;
}
private _direction: SortDirection = '';
/**
* Whether to disable the user from clearing the sort by finishing the sort direction cycle.
* May be overriden by the TWNDSortable's disable clear input.
*/
@Input('twndSortDisableClear') get disableClear(): boolean
{
return this._disableClear;
}
set disableClear(v: BooleanInput)
{
this._disableClear = coerceBooleanProperty(v);
}
private _disableClear: boolean;
/** Event emitted when the user changes either the active sort or sort direction. */
@Output('twndSortChange') readonly sortChange: EventEmitter<Sort> = new EventEmitter<Sort>();
constructor(
@Optional() @Inject(TWND_SORT_DEFAULT_OPTIONS) private _defaultOptions?: TWNDSortDefaultOptions,
)
{
super();
}
/**
* Register function to be used by the contained TWNDSortables. Adds the TWNDSortable to the
* collection of TWNDSortables.
*/
register(sortable: TWNDSortable): void
{
if (typeof ngDevMode === 'undefined' || ngDevMode) {
if (!sortable.id) {
throw getSortHeaderMissingIdError();
}
if (this.sortables.has(sortable.id)) {
throw getSortDuplicateSortableIdError(sortable.id);
}
}
this.sortables.set(sortable.id, sortable);
}
/**
* Unregister function to be used by the contained TWNDSortables. Removes the TWNDSortable from
* the collection of contained TWNDSortables.
*/
deregister(sortable: TWNDSortable): void
{
this.sortables.delete(sortable.id);
}
/** Sets the active sort id and determines the new sort direction. */
sort(sortable: TWNDSortable): void
{
if (this.active != sortable.id) {
this.active = sortable.id;
this.direction = sortable.start ? sortable.start : this.start;
} else {
this.direction = this.getNextSortDirection(sortable);
}
this.sortChange.emit({active : this.active, direction : this.direction});
}
/** Returns the next sort direction of the active sortable, checking for potential overrides. */
getNextSortDirection(sortable: TWNDSortable): SortDirection
{
if (!sortable) {
return '';
}
// Get the sort direction cycle with the potential sortable overrides.
const disableClear = sortable?.disableClear ?? this.disableClear ??
!!this._defaultOptions?.disableClear;
let sortDirectionCycle = getSortDirectionCycle(sortable.start || this.start, disableClear);
// Get and return the next direction in the cycle
let nextDirectionIndex = sortDirectionCycle.indexOf(this.direction) + 1;
if (nextDirectionIndex >= sortDirectionCycle.length) {
nextDirectionIndex = 0;
}
return sortDirectionCycle[nextDirectionIndex];
}
ngOnInit()
{
this._markInitialized();
}
ngOnChanges()
{
this._stateChanges.next();
}
ngOnDestroy()
{
this._stateChanges.complete();
}
}
/** Returns the sort direction cycle to use given the provided parameters of order and clear. */
function getSortDirectionCycle(start: 'asc'|'desc', disableClear: boolean): SortDirection[]
{
let sortOrder: SortDirection[] = [ 'asc', 'desc' ];
if (start == 'desc') {
sortOrder.reverse();
}
if (!disableClear) {
sortOrder.push('');
}
return sortOrder;
}