UNPKG

@sparser/au2-data-grid

Version:
280 lines 14.4 kB
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; import { ILogger, resolve, } from '@aurelia/kernel'; import { bindable, CustomElement, CustomElementDefinition, IHydrationContext, INode, BindingMode, ISignaler, } from '@aurelia/runtime-html'; import { ItemSelectionMode, } from './content-model.js'; import template from './data-grid.html'; import { DefaultGridHeader, } from './grid-header.js'; import { Column, GridStateModel, } from './grid-state.js'; import { SortDirection, } from './sorting-options.js'; import { GridContent, GridHeaders, } from './template-controllers.js'; const ascPattern = /^asc$|^ascending$/i; const descPattern = /^desc$|^descending$/i; const stateLookup = new Map(); /** * Default implementation of the data-grid. */ let DataGrid = (() => { let _model_decorators; let _model_initializers = []; let _model_extraInitializers = []; let _state_decorators; let _state_initializers = []; let _state_extraInitializers = []; let _itemClicked_decorators; let _itemClicked_initializers = []; let _itemClicked_extraInitializers = []; let _hiddenColumns_decorators; let _hiddenColumns_initializers = []; let _hiddenColumns_extraInitializers = []; return class DataGrid { static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; _model_decorators = [bindable]; _state_decorators = [bindable]; _itemClicked_decorators = [bindable]; _hiddenColumns_decorators = [bindable({ mode: BindingMode.oneTime })]; __esDecorate(null, null, _model_decorators, { kind: "field", name: "model", static: false, private: false, access: { has: obj => "model" in obj, get: obj => obj.model, set: (obj, value) => { obj.model = value; } }, metadata: _metadata }, _model_initializers, _model_extraInitializers); __esDecorate(null, null, _state_decorators, { kind: "field", name: "state", static: false, private: false, access: { has: obj => "state" in obj, get: obj => obj.state, set: (obj, value) => { obj.state = value; } }, metadata: _metadata }, _state_initializers, _state_extraInitializers); __esDecorate(null, null, _itemClicked_decorators, { kind: "field", name: "itemClicked", static: false, private: false, access: { has: obj => "itemClicked" in obj, get: obj => obj.itemClicked, set: (obj, value) => { obj.itemClicked = value; } }, metadata: _metadata }, _itemClicked_initializers, _itemClicked_extraInitializers); __esDecorate(null, null, _hiddenColumns_decorators, { kind: "field", name: "hiddenColumns", static: false, private: false, access: { has: obj => "hiddenColumns" in obj, get: obj => obj.hiddenColumns, set: (obj, value) => { obj.hiddenColumns = value; } }, metadata: _metadata }, _hiddenColumns_initializers, _hiddenColumns_extraInitializers); if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); } static id = 0; /** * The content model (data). */ model = __runInitializers(this, _model_initializers, void 0); /** * Any bound state is read only once in the binding stage. * Any 'incoming' changes from the consumer side thereafter is disregarded. * In the post-binding phase this property is treated as a write-only property to provide the consumer side with any changes in the exportable grid state. */ state = (__runInitializers(this, _model_extraInitializers), __runInitializers(this, _state_initializers, void 0)); /** * Callback when a item is * - clicked with the 'None' selection mode, or * - double-clicked with 'Single' or 'Multiple' selection mode. */ itemClicked = (__runInitializers(this, _state_extraInitializers), __runInitializers(this, _itemClicked_initializers, void 0)); /** * This is a one-time bindable array of string columnIds that needs to be hidden from the current instance of the grid. */ hiddenColumns = (__runInitializers(this, _itemClicked_extraInitializers), __runInitializers(this, _hiddenColumns_initializers, [])); stateModel = __runInitializers(this, _hiddenColumns_extraInitializers); $controller; // This is set by the controller after this instance is constructed containerEl; lastClickedRow = null; selectionUpdateSignal = ''; hydrationContext = resolve(IHydrationContext); node = resolve(INode); signaler = resolve(ISignaler); logger = resolve(ILogger).scopeTo('DataGrid'); created(controller) { const instanceIdStr = this.node.dataset.instanceId; const instanceId = Number(instanceIdStr); if (!Number.isInteger(instanceId)) throw new Error(`Invalid data grid instanceId: ${instanceIdStr}; expected integer.`); this.selectionUpdateSignal = `update-selection-${instanceIdStr}`; const state = stateLookup.get(Number(instanceId)); if (state === undefined) throw new Error(`Cannot find the model for the instance #${instanceIdStr}`); this.stateModel = state; const container = this.hydrationContext .controller .container .createChild({ inheritParentResources: true }) .register(controller.definition.dependencies); state.createViewFactories(container); this.node.style.setProperty('--num-columns', state.columns.length.toString()); } binding() { const stateModel = this.stateModel; const state = this.state; if (state != null) { stateModel.applyState(state); } stateModel.hideColumns(this.hiddenColumns); const sortingOptions = stateModel.initializeActiveSortOptions(); if (sortingOptions !== null) { this.model.applySorting(sortingOptions); } stateModel.addSubscriber(this); } attaching() { this.adjustColumnWidth(); } unbinding() { this.stateModel.removeSubscriber(this); } exportState() { try { return this.state = this.stateModel.export(); } catch (e) { this.logger.warn(e.message); } } handleGridStateChange(type, newValue, _oldValue) { switch (type) { case 1 /* ChangeType.Sort */: this.model.applySorting(newValue); break; case 3 /* ChangeType.Width */: case 2 /* ChangeType.Order */: this.adjustColumnWidth(); break; } this.exportState(); } adjustColumnWidth() { const columns = this.stateModel.columns; const fallback = columns.some(c => c.widthPx != null) ? 'auto' : '1fr'; this.containerEl.style.gridTemplateColumns = columns.map(c => `minmax(0px, ${c.widthPx ?? fallback})`).join(' '); } handleDblClick(item, index) { getSelection()?.empty(); this.itemClicked?.({ item, index }); this.lastClickedRow = index; } handleClick(event, item, index) { getSelection()?.empty(); const model = this.model; switch (model.selectionMode) { case ItemSelectionMode.None: this.itemClicked?.({ item, index }); break; case ItemSelectionMode.Single: model.selectItem(item); break; case ItemSelectionMode.Multiple: if (event.shiftKey) { const lastClickedRow = this.lastClickedRow; if (lastClickedRow !== null) { model.selectRange(lastClickedRow, index); } else { model.selectItem(item); } } else if (event.ctrlKey) { model.toggleSelection(item); } else { model.clearSelections(); model.selectItem(item); } break; } this.lastClickedRow = index; this.signaler.dispatchSignal(this.selectionUpdateSignal); } static processContent(content, platform) { const columns = content.querySelectorAll('grid-column'); const numColumns = columns.length; const state = new GridStateModel(); const doc = platform.document; for (let i = 0; i < numColumns; i++) { const col = columns[i]; // extract metadata let isExportable = true; const property = col.getAttribute('property'); const id = col.getAttribute('id') ?? property ?? (isExportable = false, Column.generateId()); const directionRaw = col.getAttribute('sort-direction'); let direction = null; if (directionRaw !== null) { if (ascPattern.test(directionRaw)) { direction = SortDirection.Ascending; } else if (descPattern.test(directionRaw)) { direction = SortDirection.Descending; } } const isResizable = !col.hasAttribute('non-resizable'); let width = null; if (isResizable) { width = col.getAttribute('width'); width = width === null || Number.isNaN(width) ? null : `${width}px`; } // extract header let container = doc.createElement('grid-header'); container.setAttribute('state.bind', ''); const header = col.querySelector('header'); const headerContent = header?.childNodes; const projection = doc.createElement('template'); projection.setAttribute('au-slot', 'default'); projection.content.append(...(headerContent !== undefined ? Array.from(headerContent) : [doc.createTextNode(`Column ${i + 1}`)])); container.append(projection); const headerDfn = CustomElementDefinition.create({ name: CustomElement.generateName(), template: container }); header?.remove(); // extract content container = doc.createElement('div'); container.setAttribute('role', 'cell'); container.append(...Array.from(col.childNodes)); const contentDfn = CustomElementDefinition.create({ name: CustomElement.generateName(), template: container }); void new Column(state, id, property, isExportable, direction, isResizable, width, headerDfn, contentDfn); col.remove(); } const id = ++this.id; stateLookup.set(id, state); content.setAttribute('data-instance-id', id.toString()); } }; })(); export { DataGrid }; // eslint-disable-next-line @typescript-eslint/naming-convention export const DefaultDataGrid = defineDataGridCustomElement(DefaultGridHeader); /** * Creates data-grid custom element registration. * @param {CustomElementType<THeader>} header The grid-header custom element registration. * @returns {CustomElementType<Constructable<DataGrid>>} Data grid custom element registration. * @template THeader */ export function defineDataGridCustomElement(header) { return CustomElement.define({ name: 'data-grid', template, dependencies: [ // TCs GridHeaders, GridContent, //CEs header, ] }, DataGrid); } //# sourceMappingURL=data-grid.js.map