@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
JavaScript
/**-----------------------------------------------------------------------------------------
* 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']
}] } });