@babylonjs/shared-ui-components 7.25.1 → 7.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/historyStack.d.ts +9 -2
- package/historyStack.js +49 -34
- package/historyStack.js.map +1 -1
- package/package.json +1 -1
package/historyStack.d.ts
CHANGED
@@ -3,8 +3,9 @@ import type { IDisposable } from "@babylonjs/core/scene.js";
|
|
3
3
|
* Class handling undo / redo operations
|
4
4
|
*/
|
5
5
|
export declare class HistoryStack implements IDisposable {
|
6
|
-
private
|
6
|
+
private _historyStack;
|
7
7
|
private _redoStack;
|
8
|
+
private _activeData;
|
8
9
|
private readonly _maxHistoryLength;
|
9
10
|
private _locked;
|
10
11
|
private _dataProvider;
|
@@ -15,13 +16,19 @@ export declare class HistoryStack implements IDisposable {
|
|
15
16
|
* @param applyUpdate defines the code to execute when undo/redo operation is required
|
16
17
|
*/
|
17
18
|
constructor(dataProvider: () => any, applyUpdate: (data: any) => void);
|
19
|
+
/**
|
20
|
+
* Process key event to handle undo / redo
|
21
|
+
* @param evt defines the keyboard event to process
|
22
|
+
* @returns true if the event was processed
|
23
|
+
*/
|
24
|
+
processKeyEvent(evt: KeyboardEvent): boolean;
|
18
25
|
/**
|
19
26
|
* Resets the stack
|
20
27
|
*/
|
21
28
|
reset(): void;
|
22
29
|
private _generateJSONDiff;
|
23
30
|
private _applyJSONDiff;
|
24
|
-
private
|
31
|
+
private _copy;
|
25
32
|
/**
|
26
33
|
* Stores the current state
|
27
34
|
*/
|
package/historyStack.js
CHANGED
@@ -8,19 +8,42 @@ export class HistoryStack {
|
|
8
8
|
* @param applyUpdate defines the code to execute when undo/redo operation is required
|
9
9
|
*/
|
10
10
|
constructor(dataProvider, applyUpdate) {
|
11
|
-
this.
|
11
|
+
this._historyStack = [];
|
12
12
|
this._redoStack = [];
|
13
|
-
this._maxHistoryLength =
|
13
|
+
this._maxHistoryLength = 256;
|
14
14
|
this._locked = false;
|
15
15
|
this._dataProvider = dataProvider;
|
16
16
|
this._applyUpdate = applyUpdate;
|
17
17
|
}
|
18
|
+
/**
|
19
|
+
* Process key event to handle undo / redo
|
20
|
+
* @param evt defines the keyboard event to process
|
21
|
+
* @returns true if the event was processed
|
22
|
+
*/
|
23
|
+
processKeyEvent(evt) {
|
24
|
+
if (evt.ctrlKey || evt.metaKey) {
|
25
|
+
if (evt.key === "z" || evt.key === "Z") {
|
26
|
+
if (evt.shiftKey) {
|
27
|
+
this.redo();
|
28
|
+
return true;
|
29
|
+
}
|
30
|
+
this.undo();
|
31
|
+
return true;
|
32
|
+
}
|
33
|
+
if (evt.key === "y" || evt.key === "Y") {
|
34
|
+
this.redo();
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return false;
|
39
|
+
}
|
18
40
|
/**
|
19
41
|
* Resets the stack
|
20
42
|
*/
|
21
43
|
reset() {
|
22
|
-
this.
|
44
|
+
this._historyStack = [];
|
23
45
|
this._redoStack = [];
|
46
|
+
this._activeData = null;
|
24
47
|
this.store();
|
25
48
|
}
|
26
49
|
_generateJSONDiff(obj1, obj2) {
|
@@ -105,12 +128,8 @@ export class HistoryStack {
|
|
105
128
|
}
|
106
129
|
return result;
|
107
130
|
}
|
108
|
-
|
109
|
-
|
110
|
-
for (let index = 1; index < this._history.length; index++) {
|
111
|
-
newState = this._applyJSONDiff(newState, JSON.parse(this._history[index]));
|
112
|
-
}
|
113
|
-
return newState;
|
131
|
+
_copy(source) {
|
132
|
+
return JSON.parse(JSON.stringify(source));
|
114
133
|
}
|
115
134
|
/**
|
116
135
|
* Stores the current state
|
@@ -119,23 +138,17 @@ export class HistoryStack {
|
|
119
138
|
if (this._locked) {
|
120
139
|
return;
|
121
140
|
}
|
122
|
-
const data = this._dataProvider();
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
if (JSON.stringify(previousState) === dataString) {
|
141
|
+
const data = this._copy(this._dataProvider());
|
142
|
+
if (this._activeData) {
|
143
|
+
const diff = this._generateJSONDiff(data, this._activeData);
|
144
|
+
if (!diff) {
|
127
145
|
return;
|
128
146
|
}
|
129
|
-
|
130
|
-
if (diff) {
|
131
|
-
this._history.push(JSON.stringify(diff));
|
132
|
-
}
|
133
|
-
}
|
134
|
-
else {
|
135
|
-
this._history.push(dataString);
|
147
|
+
this._historyStack.push(JSON.stringify(diff));
|
136
148
|
}
|
137
|
-
|
138
|
-
|
149
|
+
this._activeData = data;
|
150
|
+
if (this._historyStack.length > this._maxHistoryLength) {
|
151
|
+
this._historyStack.shift();
|
139
152
|
}
|
140
153
|
this._redoStack.length = 0;
|
141
154
|
}
|
@@ -143,35 +156,37 @@ export class HistoryStack {
|
|
143
156
|
* Undo the latest operation
|
144
157
|
*/
|
145
158
|
undo() {
|
146
|
-
if (this.
|
159
|
+
if (!this._historyStack.length) {
|
147
160
|
return;
|
148
161
|
}
|
149
162
|
this._locked = true;
|
150
|
-
const
|
151
|
-
this.
|
152
|
-
|
153
|
-
this._applyUpdate(newState);
|
163
|
+
const diff = this._historyStack.pop();
|
164
|
+
const newState = this._applyJSONDiff(this._activeData, JSON.parse(diff));
|
165
|
+
this._redoStack.push(JSON.stringify(this._generateJSONDiff(newState, this._activeData)));
|
166
|
+
this._applyUpdate(this._copy(newState));
|
167
|
+
this._activeData = newState;
|
154
168
|
this._locked = false;
|
155
169
|
}
|
156
170
|
/**
|
157
171
|
* Redo the latest undo operation
|
158
172
|
*/
|
159
173
|
redo() {
|
160
|
-
if (this._redoStack.length
|
174
|
+
if (!this._redoStack.length) {
|
161
175
|
return;
|
162
176
|
}
|
163
177
|
this._locked = true;
|
164
|
-
const
|
165
|
-
this.
|
166
|
-
|
167
|
-
this._applyUpdate(newState);
|
178
|
+
const diff = this._redoStack.pop();
|
179
|
+
const newState = this._applyJSONDiff(this._activeData, JSON.parse(diff));
|
180
|
+
this._historyStack.push(JSON.stringify(this._generateJSONDiff(newState, this._activeData)));
|
181
|
+
this._applyUpdate(this._copy(newState));
|
182
|
+
this._activeData = newState;
|
168
183
|
this._locked = false;
|
169
184
|
}
|
170
185
|
/**
|
171
186
|
* Disposes the stack
|
172
187
|
*/
|
173
188
|
dispose() {
|
174
|
-
this.
|
189
|
+
this._historyStack = [];
|
175
190
|
this._redoStack = [];
|
176
191
|
}
|
177
192
|
}
|
package/historyStack.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"historyStack.js","sourceRoot":"","sources":["../../../dev/sharedUiComponents/src/historyStack.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,YAAY;IAQrB;;;;OAIG;IACH,YAAY,YAAuB,EAAE,WAAgC;QAZ7D,aAAQ,GAAa,EAAE,CAAC;QACxB,eAAU,GAAa,EAAE,CAAC;QACjB,sBAAiB,GAAG,EAAE,CAAC;QAChC,YAAO,GAAG,KAAK,CAAC;QAUpB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IACpC,CAAC;IAED;;OAEG;IACI,KAAK;QACR,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAEO,iBAAiB,CAAC,IAAS,EAAE,IAAS;QAC1C,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACpC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;YACxF,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE;gBACrC,OAAO,KAAK,CAAC;aAChB;YACD,OAAO,IAAI,CAAC;SACf;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YAC5C,MAAM,IAAI,GAAG,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,UAAU,GAAG,KAAK,CAAC;YAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;gBAChC,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3D,IAAI,SAAS,KAAK,SAAS,EAAE;oBACzB,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;oBACpB,UAAU,GAAG,IAAI,CAAC;iBACrB;aACJ;YAED,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;SACxC;QAED,MAAM,IAAI,GAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnE,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;YACpB,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE;gBAChB,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;gBACtB,UAAU,GAAG,IAAI,CAAC;aACrB;iBAAM,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE;gBACvB,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,oBAAoB;gBACvC,UAAU,GAAG,IAAI,CAAC;aACrB;iBAAM;gBACH,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAChE,IAAI,UAAU,KAAK,SAAS,EAAE;oBAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;oBACvB,UAAU,GAAG,IAAI,CAAC;iBACrB;aACJ;SACJ;QAED,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACzC,CAAC;IAEO,cAAc,CAAC,IAAS,EAAE,IAAS;QACvC,IAAI,IAAI,KAAK,SAAS,EAAE;YACpB,OAAO,IAAI,CAAC;SACf;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;YAC3D,OAAO,IAAI,CAAC;SACf;QAED,MAAM,MAAM,GAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAElD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE;gBACzD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE;oBACrC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;iBACvB;qBAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE;oBAC1B,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;iBACrD;aACJ;SACJ;aAAM;YACH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;gBACpB,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE;oBAChB,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;iBAC3B;aACJ;YACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;gBACpB,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE;oBACrB,oCAAoC;iBACvC;qBAAM,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;oBAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;iBAC3D;qBAAM;oBACH,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;iBAC3B;aACJ;SACJ;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,aAAa;QACjB,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;YACvD,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC9E;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;OAEG;IACI,KAAK;QACR,IAAI,IAAI,CAAC,OAAO,EAAE;YACd,OAAO;SACV;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YAC1B,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3C,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,UAAU,EAAE;gBAC9C,OAAO;aACV;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACzD,IAAI,IAAI,EAAE;gBACN,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;aAC5C;SACJ;aAAM;YACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAClC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE;YAC/C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SAC9B;QAED,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACI,IAAI;QACP,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YAC1B,OAAO;SACV;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAG,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAEtC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;OAEG;IACI,IAAI;QACP,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE;YAC5B,OAAO;SACV;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAG,CAAC;QACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE5B,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACtC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAE5B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;OAEG;IACI,OAAO;QACV,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;IACzB,CAAC;CACJ","sourcesContent":["import type { IDisposable } from \"core/scene\";\r\n\r\n/**\r\n * Class handling undo / redo operations\r\n */\r\nexport class HistoryStack implements IDisposable {\r\n private _history: string[] = [];\r\n private _redoStack: string[] = [];\r\n private readonly _maxHistoryLength = 64;\r\n private _locked = false;\r\n private _dataProvider: () => any;\r\n private _applyUpdate: (data: any) => void;\r\n\r\n /**\r\n * Constructor\r\n * @param dataProvider defines the data provider function\r\n * @param applyUpdate defines the code to execute when undo/redo operation is required\r\n */\r\n constructor(dataProvider: () => any, applyUpdate: (data: any) => void) {\r\n this._dataProvider = dataProvider;\r\n this._applyUpdate = applyUpdate;\r\n }\r\n\r\n /**\r\n * Resets the stack\r\n */\r\n public reset() {\r\n this._history = [];\r\n this._redoStack = [];\r\n this.store();\r\n }\r\n\r\n private _generateJSONDiff(obj1: any, obj2: any): any {\r\n if (obj1 === obj2) return undefined;\r\n if (obj1 === null || obj2 === null || typeof obj1 !== \"object\" || typeof obj2 !== \"object\") {\r\n if (obj1 !== obj2 && obj2 === undefined) {\r\n return \"@d@\";\r\n }\r\n return obj2;\r\n }\r\n\r\n if (Array.isArray(obj1) && Array.isArray(obj2)) {\r\n const diff = [];\r\n const maxLength = Math.max(obj1.length, obj2.length);\r\n let hasChanges = false;\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const localDiff = this._generateJSONDiff(obj1[i], obj2[i]);\r\n if (localDiff !== undefined) {\r\n diff[i] = localDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n\r\n return hasChanges ? diff : undefined;\r\n }\r\n\r\n const diff: any = {};\r\n const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);\r\n let hasChanges = false;\r\n\r\n for (const key of keys) {\r\n if (!(key in obj1)) {\r\n diff[key] = obj2[key];\r\n hasChanges = true;\r\n } else if (!(key in obj2)) {\r\n diff[key] = \"@d@\"; // Mark for deletion\r\n hasChanges = true;\r\n } else {\r\n const nestedDiff = this._generateJSONDiff(obj1[key], obj2[key]);\r\n if (nestedDiff !== undefined) {\r\n diff[key] = nestedDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n }\r\n\r\n return hasChanges ? diff : undefined;\r\n }\r\n\r\n private _applyJSONDiff(obj1: any, diff: any) {\r\n if (diff === undefined) {\r\n return obj1;\r\n }\r\n if (typeof diff !== \"object\" || diff === null || obj1 == null) {\r\n return diff;\r\n }\r\n\r\n const result: any = Array.isArray(obj1) ? [] : {};\r\n\r\n if (Array.isArray(diff)) {\r\n for (let i = 0; i < Math.max(obj1.length, diff.length); i++) {\r\n if (diff[i] === null && i < obj1.length) {\r\n result[i] = obj1[i];\r\n } else if (diff[i] !== \"@d@\") {\r\n result[i] = this._applyJSONDiff(obj1[i], diff[i]);\r\n }\r\n }\r\n } else {\r\n for (const key in obj1) {\r\n if (!(key in diff)) {\r\n result[key] = obj1[key];\r\n }\r\n }\r\n for (const key in diff) {\r\n if (diff[key] === \"@d@\") {\r\n // Skip this key (it's been deleted)\r\n } else if (typeof diff[key] === \"object\" && diff[key] !== null) {\r\n result[key] = this._applyJSONDiff(obj1[key], diff[key]);\r\n } else {\r\n result[key] = diff[key];\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private _rebuildState() {\r\n let newState = JSON.parse(this._history[0]);\r\n for (let index = 1; index < this._history.length; index++) {\r\n newState = this._applyJSONDiff(newState, JSON.parse(this._history[index]));\r\n }\r\n\r\n return newState;\r\n }\r\n\r\n /**\r\n * Stores the current state\r\n */\r\n public store() {\r\n if (this._locked) {\r\n return;\r\n }\r\n\r\n const data = this._dataProvider();\r\n const dataString = JSON.stringify(data);\r\n\r\n if (this._history.length > 0) {\r\n const previousState = this._rebuildState();\r\n if (JSON.stringify(previousState) === dataString) {\r\n return;\r\n }\r\n const diff = this._generateJSONDiff(previousState, data);\r\n if (diff) {\r\n this._history.push(JSON.stringify(diff));\r\n }\r\n } else {\r\n this._history.push(dataString);\r\n }\r\n\r\n if (this._history.length > this._maxHistoryLength) {\r\n this._history.splice(0, 1);\r\n }\r\n\r\n this._redoStack.length = 0;\r\n }\r\n\r\n /**\r\n * Undo the latest operation\r\n */\r\n public undo() {\r\n if (this._history.length < 2) {\r\n return;\r\n }\r\n\r\n this._locked = true;\r\n const current = this._history.pop()!;\r\n this._redoStack.push(current);\r\n\r\n const newState = this._rebuildState();\r\n\r\n this._applyUpdate(newState);\r\n\r\n this._locked = false;\r\n }\r\n\r\n /**\r\n * Redo the latest undo operation\r\n */\r\n public redo() {\r\n if (this._redoStack.length < 1) {\r\n return;\r\n }\r\n\r\n this._locked = true;\r\n const current = this._redoStack.pop()!;\r\n this._history.push(current);\r\n\r\n const newState = this._rebuildState();\r\n this._applyUpdate(newState);\r\n\r\n this._locked = false;\r\n }\r\n\r\n /**\r\n * Disposes the stack\r\n */\r\n public dispose() {\r\n this._history = [];\r\n this._redoStack = [];\r\n }\r\n}\r\n"]}
|
1
|
+
{"version":3,"file":"historyStack.js","sourceRoot":"","sources":["../../../dev/sharedUiComponents/src/historyStack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IDisposable } from \"core/scene\";\r\n\r\n/**\r\n * Class handling undo / redo operations\r\n */\r\nexport class HistoryStack implements IDisposable {\r\n private _historyStack: string[] = [];\r\n private _redoStack: string[] = [];\r\n private _activeData: any;\r\n private readonly _maxHistoryLength = 256;\r\n private _locked = false;\r\n private _dataProvider: () => any;\r\n private _applyUpdate: (data: any) => void;\r\n\r\n /**\r\n * Constructor\r\n * @param dataProvider defines the data provider function\r\n * @param applyUpdate defines the code to execute when undo/redo operation is required\r\n */\r\n constructor(dataProvider: () => any, applyUpdate: (data: any) => void) {\r\n this._dataProvider = dataProvider;\r\n this._applyUpdate = applyUpdate;\r\n }\r\n\r\n /**\r\n * Process key event to handle undo / redo\r\n * @param evt defines the keyboard event to process\r\n * @returns true if the event was processed\r\n */\r\n processKeyEvent(evt: KeyboardEvent): boolean {\r\n if (evt.ctrlKey || evt.metaKey) {\r\n if (evt.key === \"z\" || evt.key === \"Z\") {\r\n if (evt.shiftKey) {\r\n this.redo();\r\n return true;\r\n }\r\n\r\n this.undo();\r\n return true;\r\n }\r\n if (evt.key === \"y\" || evt.key === \"Y\") {\r\n this.redo();\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Resets the stack\r\n */\r\n public reset() {\r\n this._historyStack = [];\r\n this._redoStack = [];\r\n this._activeData = null;\r\n this.store();\r\n }\r\n\r\n private _generateJSONDiff(obj1: any, obj2: any): any {\r\n if (obj1 === obj2) return undefined;\r\n if (obj1 === null || obj2 === null || typeof obj1 !== \"object\" || typeof obj2 !== \"object\") {\r\n if (obj1 !== obj2 && obj2 === undefined) {\r\n return \"@d@\";\r\n }\r\n return obj2;\r\n }\r\n\r\n if (Array.isArray(obj1) && Array.isArray(obj2)) {\r\n const diff = [];\r\n const maxLength = Math.max(obj1.length, obj2.length);\r\n let hasChanges = false;\r\n\r\n for (let i = 0; i < maxLength; i++) {\r\n const localDiff = this._generateJSONDiff(obj1[i], obj2[i]);\r\n if (localDiff !== undefined) {\r\n diff[i] = localDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n\r\n return hasChanges ? diff : undefined;\r\n }\r\n\r\n const diff: any = {};\r\n const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);\r\n let hasChanges = false;\r\n\r\n for (const key of keys) {\r\n if (!(key in obj1)) {\r\n diff[key] = obj2[key];\r\n hasChanges = true;\r\n } else if (!(key in obj2)) {\r\n diff[key] = \"@d@\"; // Mark for deletion\r\n hasChanges = true;\r\n } else {\r\n const nestedDiff = this._generateJSONDiff(obj1[key], obj2[key]);\r\n if (nestedDiff !== undefined) {\r\n diff[key] = nestedDiff;\r\n hasChanges = true;\r\n }\r\n }\r\n }\r\n\r\n return hasChanges ? diff : undefined;\r\n }\r\n\r\n private _applyJSONDiff(obj1: any, diff: any) {\r\n if (diff === undefined) {\r\n return obj1;\r\n }\r\n if (typeof diff !== \"object\" || diff === null || obj1 == null) {\r\n return diff;\r\n }\r\n\r\n const result: any = Array.isArray(obj1) ? [] : {};\r\n\r\n if (Array.isArray(diff)) {\r\n for (let i = 0; i < Math.max(obj1.length, diff.length); i++) {\r\n if (diff[i] === null && i < obj1.length) {\r\n result[i] = obj1[i];\r\n } else if (diff[i] !== \"@d@\") {\r\n result[i] = this._applyJSONDiff(obj1[i], diff[i]);\r\n }\r\n }\r\n } else {\r\n for (const key in obj1) {\r\n if (!(key in diff)) {\r\n result[key] = obj1[key];\r\n }\r\n }\r\n for (const key in diff) {\r\n if (diff[key] === \"@d@\") {\r\n // Skip this key (it's been deleted)\r\n } else if (typeof diff[key] === \"object\" && diff[key] !== null) {\r\n result[key] = this._applyJSONDiff(obj1[key], diff[key]);\r\n } else {\r\n result[key] = diff[key];\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private _copy(source: any) {\r\n return JSON.parse(JSON.stringify(source));\r\n }\r\n\r\n /**\r\n * Stores the current state\r\n */\r\n public store() {\r\n if (this._locked) {\r\n return;\r\n }\r\n\r\n const data = this._copy(this._dataProvider());\r\n\r\n if (this._activeData) {\r\n const diff = this._generateJSONDiff(data, this._activeData);\r\n if (!diff) {\r\n return;\r\n }\r\n this._historyStack.push(JSON.stringify(diff));\r\n }\r\n\r\n this._activeData = data;\r\n\r\n if (this._historyStack.length > this._maxHistoryLength) {\r\n this._historyStack.shift();\r\n }\r\n\r\n this._redoStack.length = 0;\r\n }\r\n\r\n /**\r\n * Undo the latest operation\r\n */\r\n public undo() {\r\n if (!this._historyStack.length) {\r\n return;\r\n }\r\n\r\n this._locked = true;\r\n const diff = this._historyStack.pop()!;\r\n\r\n const newState = this._applyJSONDiff(this._activeData, JSON.parse(diff));\r\n this._redoStack.push(JSON.stringify(this._generateJSONDiff(newState, this._activeData)));\r\n\r\n this._applyUpdate(this._copy(newState));\r\n this._activeData = newState;\r\n\r\n this._locked = false;\r\n }\r\n\r\n /**\r\n * Redo the latest undo operation\r\n */\r\n public redo() {\r\n if (!this._redoStack.length) {\r\n return;\r\n }\r\n\r\n this._locked = true;\r\n const diff = this._redoStack.pop()!;\r\n\r\n const newState = this._applyJSONDiff(this._activeData, JSON.parse(diff));\r\n this._historyStack.push(JSON.stringify(this._generateJSONDiff(newState, this._activeData)));\r\n\r\n this._applyUpdate(this._copy(newState));\r\n this._activeData = newState;\r\n\r\n this._locked = false;\r\n }\r\n\r\n /**\r\n * Disposes the stack\r\n */\r\n public dispose() {\r\n this._historyStack = [];\r\n this._redoStack = [];\r\n }\r\n}\r\n"]}
|