UNPKG

@progress/kendo-angular-grid

Version:

Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.

179 lines (178 loc) 7.68 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Directive, EventEmitter, Input, Output } from '@angular/core'; import { UndoRedoStack } from './undo-redo.stack'; import { GridComponent } from '../grid.component'; import { UndoRedoEvent } from './grid-state.models'; import { Subscription } from 'rxjs'; import { EditService } from '../editing/edit.service'; import { filter, tap } from 'rxjs/operators'; import { UndoRedoService } from './undo-redo.service'; import { hasObservers } from '@progress/kendo-angular-common'; import { ChangeNotificationService } from '../data/change-notification.service'; import * as i0 from "@angular/core"; import * as i1 from "../grid.component"; import * as i2 from "../editing/edit.service"; import * as i3 from "./undo-redo.service"; import * as i4 from "../data/change-notification.service"; export class UndoRedoDirective { host; editService; undoRedoService; changeNotification; /** * Determines the maximum number of actions to keep in the undo-redo stack. * @default 10 */ maxStoredStates = 10; /** * Fires when undo action is performed. Exposes the state of the grid that will be applied. */ onUndo = new EventEmitter(); /** * Fires when undo action is performed. Exposes the state of the grid that will be applied. */ onRedo = new EventEmitter(); /** * Returns an array of all undo-redo actions that are currently in the stack. */ get undoRedoItems() { return this.stack.toArray(); } stack; subs = new Subscription(); addToState = true; constructor(host, editService, undoRedoService, changeNotification) { this.host = host; this.editService = editService; this.undoRedoService = undoRedoService; this.changeNotification = changeNotification; this.host.undoRedoService = this.undoRedoService; } ngOnInit() { this.stack = new UndoRedoStack(this.maxStoredStates); this.stack.add({ originalEvent: { skip: this.host.skip, take: this.host.pageSize, sort: this.host.sort, filter: this.host.filter, group: this.host.group }, gridState: structuredClone(this.host.currentState) }); this.subs = this.host.gridStateChange.subscribe((state) => { if (this.addToState) { this.stack.add({ originalEvent: { skip: state.skip, take: state.take, sort: state.sort, filter: state.filter, group: state.group }, gridState: structuredClone(state) }); } let stackEndPointReached; if (this.stack.canUndo) { stackEndPointReached = this.stack.canRedo ? false : 'end'; } else { stackEndPointReached = 'start'; } this.undoRedoService.stackEndReached.next(stackEndPointReached); }); this.subs.add(this.editService.changes .pipe(filter(event => event.action === 'save' || event.action === 'remove'), tap(event => this.undoRedoService.originalEvent = event)) .subscribe(event => { this.stack.add({ originalEvent: event, gridState: structuredClone(this.host.currentState) }); this.addToState = false; this.host.gridStateChange.emit(this.stack.current.gridState); this.addToState = true; this.updateUndoRedoDisabled(); })); this.subs.add(this.changeNotification.changes.subscribe(() => this.stack.current.gridState = this.host.currentState)); ['Undo', 'Redo'].forEach((action) => { this.subs.add(this.undoRedoService[`on${action}`].subscribe(() => { if (!this.stack[`can${action}`]) { return; } this.stack[`${action.toLowerCase()}`](); if (hasObservers(this[`on${action}`])) { const event = new UndoRedoEvent(this.stack.current); this[`on${action}`].emit(event); if (event.isDefaultPrevented()) { return; } } this.updateUndoRedoDisabled(); this.host.loadState(this.stack.current.gridState); })); }); this.subs.add(this.undoRedoService.setState.subscribe((state) => this.stack.add({ originalEvent: 'dataChange', gridState: state }))); } ngOnDestroy() { this.stack.clear(); this.stack = null; this.subs.unsubscribe(); } /** * Re-applies the last action, reverted by the `undo` method. */ redo() { if (this.stack.canRedo) { this.stack.redo(); this.host.loadState(this.stack.current.gridState); if (!this.stack.canRedo) { this.undoRedoService.stackEndReached.next('end'); } } } /** * Reverts the last user action. */ undo() { if (this.stack.canUndo) { this.stack.undo(); this.host.loadState(this.stack.current.gridState); if (!this.stack.canUndo) { this.undoRedoService.stackEndReached.next('start'); } } } updateUndoRedoDisabled() { if (!this.stack.canRedo) { this.undoRedoService.stackEndReached.next('end'); return; } if (!this.stack.canUndo) { this.undoRedoService.stackEndReached.next('start'); return; } this.undoRedoService.stackEndReached.next(false); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, deps: [{ token: i1.GridComponent }, { token: i2.EditService }, { token: i3.UndoRedoService }, { token: i4.ChangeNotificationService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: UndoRedoDirective, isStandalone: true, selector: "[kendoGridUndoRedo]", inputs: { maxStoredStates: "maxStoredStates" }, outputs: { onUndo: "undo", onRedo: "redo" }, providers: [UndoRedoService], exportAs: ["kendoGridUndoRedo"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoGridUndoRedo]', standalone: true, exportAs: 'kendoGridUndoRedo', providers: [UndoRedoService] }] }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i2.EditService }, { type: i3.UndoRedoService }, { type: i4.ChangeNotificationService }]; }, propDecorators: { maxStoredStates: [{ type: Input }], onUndo: [{ type: Output, args: ['undo'] }], onRedo: [{ type: Output, args: ['redo'] }] } });