UNPKG

@anglr/grid

Version:
275 lines 11 kB
import { Component, ChangeDetectionStrategy, ElementRef, Inject, Optional, forwardRef, resolveForwardRef, signal, inject, computed, Injector } from '@angular/core'; import { toObservable } from '@angular/core/rxjs-interop'; import { CommonModule } from '@angular/common'; import { MatDialog } from '@angular/material/dialog'; import { PERMANENT_STORAGE, LocalizePipe } from '@anglr/common'; import { GRID_PLUGIN_INSTANCES, METADATA_SELECTOR_OPTIONS } from '@anglr/grid'; import { extend } from '@jscrpt/common/extend'; import { skip } from 'rxjs'; import { VerticalDragNDropSelectionComponent } from '../../../components'; import * as i0 from "@angular/core"; import * as i1 from "@angular/material/dialog"; import * as i2 from "@angular/common"; /** * Default options for dialog metadata selector */ const defaultOptions = { storageName: null, dialogCompnentOptions: { dragDisabled: false, }, cssClasses: { btnElement: 'btn btn-primary', btnIconElement: 'fas fa-list grid-margin-right-extra-small', dialogComponentClasses: { titleElement: 'metadata-columns-title', resetMetadataIconElement: 'fas fa-rotate-right', columnsContainer: 'metadata-columns', columnElement: 'metadata-column', dragIndicationElement: 'fas fa-bars' } }, texts: { btnShowSelection: 'column selection', dialogComponentTexts: { selectionTitle: 'columns' } }, showButtonVisible: true, dialogComponent: forwardRef(() => VerticalDragNDropSelectionComponent), }; /** * Component for rendering dialog metadata selector */ export class DialogMetadataSelectorComponent { /** * @inheritdoc */ get options() { return this.optionsValue(); } set options(options) { this.optionsValue.update(opts => extend(true, opts, options)); } /** * @inheritdoc */ get metadata() { return this.metadataValue; } //######################### constructor ######################### constructor(storage, dialog, options) { this.storage = storage; this.dialog = dialog; /** * Metadata for dialog component */ this.metadataForDialogComponent = computed(() => { return { ...this.allMetadata(), columns: this.columnsForSelection(), }; }); /** * Instance of injector used for DI */ this.injector = inject(Injector); /** * Indication whether gahterer has been initialized */ this.gathererInitialized = false; /** * All metadata that are available */ this.allMetadata = signal(null); /** * Array of visiblity flags for columns originaly obtained from metadata selector */ this.originalColumnsVisibility = []; /** * Columns for selection that are currently */ this.columnsForSelection = signal([]); //######################### public properties - implementation of DialogMetadataSelector ######################### /** * @inheritdoc */ this.gridPlugins = inject(GRID_PLUGIN_INSTANCES, { optional: true }); /** * @inheritdoc */ this.pluginElement = inject((ElementRef)); this.optionsValue = signal(extend(true, {}, defaultOptions, options)); this.metadataValue = computed(() => { return { ...this.allMetadata(), columns: this.columnsForSelection().filter(itm => itm.visible), }; }); } //######################### public methods - implementation of OnDestroy ######################### /** * Called when component is destroyed */ ngOnDestroy() { this.metadataChangedSubscription?.unsubscribe(); this.metadataChangedSubscription = null; } //######################### public methods - implementation of DialogMetadataSelector ######################### /** * @inheritdoc */ show() { if (!this.dialogComponent) { return; } this.dialog.open(this.dialogComponent, { data: { metadata: this.metadataForDialogComponent, setMetadata: metadata => { this.saveToStorage(); this.columnsForSelection.set([...metadata.columns]); }, resetMetadata: () => { this.resetMetadata(); }, cssClasses: this.options.cssClasses.dialogComponentClasses, texts: this.options.texts.dialogComponentTexts, options: this.options.dialogCompnentOptions, } }); } /** * @inheritdoc */ resetMetadata() { if (this.options.storageName) { this.storage.remove(this.options.storageName); } //reset visiblity of all columns const allMetadata = this.metadataGatherer?.metadata(); if (!allMetadata) { this.allMetadata.set(null); this.initMetadata(); return; } for (let x = 0; x < allMetadata.columns.length; x++) { const col = allMetadata.columns[x]; col.visible = this.originalColumnsVisibility[x] ?? false; } this.allMetadata.set({ ...allMetadata }); this.initMetadata(); } /** * @inheritdoc */ setMetadataGatherer(gatherer) { if (this.metadataGatherer != gatherer) { this.gathererInitialized = false; } this.metadataGatherer = gatherer; } /** * @inheritdoc */ initialize(force) { this.dialogComponent = resolveForwardRef(this.options.dialogComponent); if (force || !this.gathererInitialized) { if (!this.metadataGatherer) { throw new Error('DialogMetadataSelectorComponent: missing metadata gatherer!'); } const initMetadataFn = (allMetadata) => { this.originalColumnsVisibility = allMetadata?.columns.map(itm => itm.visible) ?? []; this.allMetadata.set(allMetadata); this.initMetadata(); }; this.metadataChangedSubscription?.unsubscribe(); this.metadataChangedSubscription = toObservable(this.metadataGatherer.metadata, { injector: this.injector }) .pipe(skip(1)) .subscribe(initMetadataFn); initMetadataFn(this.metadataGatherer.metadata()); this.gathererInitialized = true; } } /** * @inheritdoc */ initOptions() { } /** * @inheritdoc */ invalidateVisuals() { } //######################### protected methods ######################### /** * Initialize metadata */ initMetadata() { const storageState = this.loadFromStorage(); const allMetadata = this.allMetadata(); if (storageState) { allMetadata?.columns.forEach(meta => { if (!meta.id) { throw new Error('Missing id for column to be stored in storage!'); } meta.visible = !!storageState[meta.id]?.visible; }); this.columnsForSelection.set(Object.keys(storageState) .map(id => allMetadata?.columns.find(itm => itm.id == id)) .filter(itm => !!itm) .concat(allMetadata?.columns.filter(meta => !storageState[meta.id ?? 0]) ?? [])); } else { this.columnsForSelection.set([...(allMetadata?.columns ?? [])]); } } /** * Saves current state to storage */ saveToStorage() { if (!this.options.storageName) { return; } const state = {}; this.columnsForSelection().forEach(meta => { if (!meta.id) { throw new Error('Missing id for column to be stored in storage!'); } state[meta.id] = { visible: meta.visible, id: meta.id, title: meta.title, }; }); this.storage.set(this.options.storageName, state); } /** * Gets stored storage state */ loadFromStorage() { if (!this.options.storageName) { return null; } return this.storage.get(this.options.storageName); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.0", ngImport: i0, type: DialogMetadataSelectorComponent, deps: [{ token: PERMANENT_STORAGE }, { token: i1.MatDialog }, { token: METADATA_SELECTOR_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.0", type: DialogMetadataSelectorComponent, isStandalone: true, selector: "ng-dialog-metadata-selector", ngImport: i0, template: "@if(optionsValue().showButtonVisible)\r\n{\r\n <div>\r\n <button type=\"button\" (click)=\"show()\" [ngClass]=\"optionsValue().cssClasses.btnElement\">\r\n <span [ngClass]=\"optionsValue().cssClasses.btnIconElement\"></span>\r\n <span>{{optionsValue().texts.btnShowSelection | localize}}</span>\r\n </button>\r\n </div>\r\n}", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: LocalizePipe, name: "localize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.0", ngImport: i0, type: DialogMetadataSelectorComponent, decorators: [{ type: Component, args: [{ selector: 'ng-dialog-metadata-selector', imports: [ CommonModule, LocalizePipe, ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if(optionsValue().showButtonVisible)\r\n{\r\n <div>\r\n <button type=\"button\" (click)=\"show()\" [ngClass]=\"optionsValue().cssClasses.btnElement\">\r\n <span [ngClass]=\"optionsValue().cssClasses.btnIconElement\"></span>\r\n <span>{{optionsValue().texts.btnShowSelection | localize}}</span>\r\n </button>\r\n </div>\r\n}" }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [PERMANENT_STORAGE] }] }, { type: i1.MatDialog }, { type: undefined, decorators: [{ type: Inject, args: [METADATA_SELECTOR_OPTIONS] }, { type: Optional }] }] }); //# sourceMappingURL=dialogMetadataSelector.component.js.map