UNPKG

@sparser/au2-data-grid

Version:
269 lines 9.85 kB
import { DI, } from '@aurelia/kernel'; import { ViewFactory, } from '@aurelia/runtime-html'; // eslint-disable-next-line @typescript-eslint/naming-convention export const IGridStateModel = DI.createInterface('IGridStateModel'); /** * This aggregates the structural metadata for the grid. * This is meant for internal use. * @internal */ export class GridStateModel { _activeSortOptions = null; /** * @internal */ subscribers = []; /** @internal */ viewFactoriesCreated = false; columns = []; get activeSortOptions() { return this._activeSortOptions; } /** * Exports the grid state. */ export() { return { columns: this.columns.map((c) => c.export()) }; } /** * Applies a previously exported state. * @param {ExportableGridState} state The state to apply. */ applyState(state) { const columns = this.columns; const stateColumns = state.columns; const len = stateColumns.length; for (let i = 0; i < len; i++) { const stateColumn = stateColumns[i]; const colIndex = columns.findIndex(c => c.id === stateColumn.id); if (colIndex === -1) continue; const column = columns[colIndex]; if (!column.tryApplyState(stateColumn) || colIndex === i) continue; // move column columns.splice(colIndex, 1); columns.splice(i, 0, column); } } /** * Marks the hidden columns as per the given column ids. * Note that in absence of a `id` attribute in `grid-column`, the `property` is used as the `id`. * @param {string[]} columnIds The collection of ids of the columns to hide. */ hideColumns(columnIds) { const len = columnIds?.length ?? 0; if (len === 0) return; const columns = this.columns; for (let i = 0; i < len; i++) { const id = columnIds[i]; const col = columns.find(c => c.id === id); if (col === undefined) continue; col.hidden = true; } } /** * Creates the view factories for every column using the given `container`. */ createViewFactories(container) { if (this.viewFactoriesCreated) return; const columns = this.columns; const len = columns.length; for (let i = 0; i < len; i++) { columns[i].createViewFactories(container); } this.viewFactoriesCreated = true; } /** * Initializes the sort options. * To this end the first column with non-null direction is used . */ initializeActiveSortOptions() { const column = this.columns.find(c => c.direction !== null); if (column == null) return null; return this._activeSortOptions = { property: column.property, direction: column.direction, }; } /** * Adds the given `subscriber` to the collection of subscribers. * The subscribers will be notified for state changes. */ addSubscriber(subscriber) { this.subscribers.push(subscriber); } /** * Removes the given `subscriber` from the collection of subscribers. * The subscriber won't be notified for any further state changes. */ removeSubscriber(subscriber) { const subscribers = this.subscribers; const idx = subscribers.findIndex(s => s === subscriber); if (idx === -1) return; subscribers.splice(idx, 1); } notifySubscribers(type, newValue, oldValue) { const subscribers = this.subscribers; const len = subscribers.length; for (let i = 0; i < len; i++) { subscribers[i].handleGridStateChange(type, newValue, oldValue); } } handleChange(type, columnOrId, destination, location) { switch (type) { case 1 /* ChangeType.Sort */: { const oldSortOptions = this._activeSortOptions; const oldProperty = oldSortOptions?.property; const newProperty = columnOrId.property; if (oldProperty !== newProperty) { // this is needed so that change to the old sort column can be propagated to the view. this.columns .find(c => c.property === oldProperty) ?.setDirection(null, false); } const newSortOptions = this._activeSortOptions = { property: newProperty, direction: columnOrId.direction }; this.notifySubscribers(type, newSortOptions, oldSortOptions); return; } case 2 /* ChangeType.Order */: { const columns = this.columns; const sourceIndex = columns.findIndex(c => c.id === columnOrId); const destinationIndex = columns.findIndex(c => c === destination); const diff = destinationIndex - sourceIndex; if (diff === 1 && location === 1 /* OrderChangeDropLocation.Before */ || diff === -1 && location === 2 /* OrderChangeDropLocation.After */) return; let $destinationIndex = destinationIndex; if (sourceIndex < destinationIndex && location === 1 /* OrderChangeDropLocation.Before */) { $destinationIndex--; } else if (sourceIndex > destinationIndex && location === 2 /* OrderChangeDropLocation.After */) { $destinationIndex++; } columns.splice($destinationIndex, 0, columns.splice(sourceIndex, 1)[0]); this.notifySubscribers(type, { fromIndex: sourceIndex, toIndex: destinationIndex, location }, null); return; } case 3 /* ChangeType.Width */: this.notifySubscribers(type); return; default: throw new Error(`Unsupported change type: ${String(type)}.`); } } } /** * This describes the structural metadata of a column. * This is meant for internal use. * @internal */ export class Column { parent; id; property; exportable; isResizable; widthPx; header; content; static id = 0; static generateId() { return `unnamed-column-${++this.id}`; } /** @internal */ _sortable = false; /** @internal */ _direction = null; /** @internal */ _headerViewFactory = null; /** @internal */ _contentViewFactory = null; /** * This is registered from inside the grid-header CE during `binding`. * @internal */ headerElement; hidden = false; constructor(parent, id, property, exportable, direction, isResizable, widthPx, header, content) { this.parent = parent; this.id = id; this.property = property; this.exportable = exportable; this.isResizable = isResizable; this.widthPx = widthPx; this.header = header; this.content = content; if (!id) throw new Error('Cannot instantiate ColumnState; expected non-null, non-undefined, non-empty string for id.'); if (property !== null) { if (property.length === 0) throw new Error('Cannot instantiate ColumnState; expected non-empty property.'); this._sortable = true; } else { direction = null; } this._direction = direction; parent.columns.push(this); } get direction() { return this._direction; } get sortable() { return this._sortable; } get headerViewFactory() { return this._headerViewFactory; } get contentViewFactory() { return this._contentViewFactory; } /** @internal */ setDirection(direction, notifyParent) { if (!this._sortable) throw new Error(`The column '${this.id}' is not sortable.`); this._direction = direction; if (notifyParent) { this.parent.handleChange(1 /* ChangeType.Sort */, this); } } export() { if (!this.exportable) throw new Error(`The column '${this.id}' is not exportable.`); return { id: this.id, property: this.property, direction: this._direction, isResizable: this.isResizable, widthPx: this.widthPx, }; } /** @internal */ tryApplyState(state) { if (this.id !== state.id || this.property !== state.property) return false; this._direction = state.direction; this.widthPx = state.widthPx; return true; } createViewFactories(container) { // invocation is expected once during pre-binding stage if (this._headerViewFactory !== null && this._contentViewFactory !== null) return; this._headerViewFactory = new ViewFactory(container, this.header); this._contentViewFactory = new ViewFactory(container, this.content); } } export var ChangeType; (function (ChangeType) { /** Content sorting is changed. */ ChangeType[ChangeType["Sort"] = 1] = "Sort"; /** Column is reordered. */ ChangeType[ChangeType["Order"] = 2] = "Order"; /** Width of a column is changed. */ ChangeType[ChangeType["Width"] = 3] = "Width"; })(ChangeType || (ChangeType = {})); export var OrderChangeDropLocation; (function (OrderChangeDropLocation) { OrderChangeDropLocation[OrderChangeDropLocation["Before"] = 1] = "Before"; OrderChangeDropLocation[OrderChangeDropLocation["After"] = 2] = "After"; })(OrderChangeDropLocation || (OrderChangeDropLocation = {})); //# sourceMappingURL=grid-state.js.map