1 | import { isPlainObject } from 'is-plain-object';
|
2 | import { Operation, Editor, Transforms, Path } from 'slate';
|
3 |
|
4 |
|
5 | var History = {
|
6 | |
7 |
|
8 |
|
9 | isHistory(value) {
|
10 | return isPlainObject(value) && Array.isArray(value.redos) && Array.isArray(value.undos) && (value.redos.length === 0 || Operation.isOperationList(value.redos[0].operations)) && (value.undos.length === 0 || Operation.isOperationList(value.undos[0].operations));
|
11 | }
|
12 | };
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var HISTORY = new WeakMap();
|
18 | var SAVING = new WeakMap();
|
19 | var MERGING = new WeakMap();
|
20 |
|
21 | var HistoryEditor = {
|
22 | |
23 |
|
24 |
|
25 | isHistoryEditor(value) {
|
26 | return History.isHistory(value.history) && Editor.isEditor(value);
|
27 | },
|
28 | |
29 |
|
30 |
|
31 | isMerging(editor) {
|
32 | return MERGING.get(editor);
|
33 | },
|
34 | |
35 |
|
36 |
|
37 | isSaving(editor) {
|
38 | return SAVING.get(editor);
|
39 | },
|
40 | |
41 |
|
42 |
|
43 | redo(editor) {
|
44 | editor.redo();
|
45 | },
|
46 | |
47 |
|
48 |
|
49 | undo(editor) {
|
50 | editor.undo();
|
51 | },
|
52 | |
53 |
|
54 |
|
55 |
|
56 | withoutMerging(editor, fn) {
|
57 | var prev = HistoryEditor.isMerging(editor);
|
58 | MERGING.set(editor, false);
|
59 | fn();
|
60 | MERGING.set(editor, prev);
|
61 | },
|
62 | |
63 |
|
64 |
|
65 |
|
66 | withoutSaving(editor, fn) {
|
67 | var prev = HistoryEditor.isSaving(editor);
|
68 | SAVING.set(editor, false);
|
69 | fn();
|
70 | SAVING.set(editor, prev);
|
71 | }
|
72 | };
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | var withHistory = editor => {
|
84 | var e = editor;
|
85 | var {
|
86 | apply
|
87 | } = e;
|
88 | e.history = {
|
89 | undos: [],
|
90 | redos: []
|
91 | };
|
92 | e.redo = () => {
|
93 | var {
|
94 | history
|
95 | } = e;
|
96 | var {
|
97 | redos
|
98 | } = history;
|
99 | if (redos.length > 0) {
|
100 | var batch = redos[redos.length - 1];
|
101 | if (batch.selectionBefore) {
|
102 | Transforms.setSelection(e, batch.selectionBefore);
|
103 | }
|
104 | HistoryEditor.withoutSaving(e, () => {
|
105 | Editor.withoutNormalizing(e, () => {
|
106 | for (var op of batch.operations) {
|
107 | e.apply(op);
|
108 | }
|
109 | });
|
110 | });
|
111 | history.redos.pop();
|
112 | e.writeHistory('undos', batch);
|
113 | }
|
114 | };
|
115 | e.undo = () => {
|
116 | var {
|
117 | history
|
118 | } = e;
|
119 | var {
|
120 | undos
|
121 | } = history;
|
122 | if (undos.length > 0) {
|
123 | var batch = undos[undos.length - 1];
|
124 | HistoryEditor.withoutSaving(e, () => {
|
125 | Editor.withoutNormalizing(e, () => {
|
126 | var inverseOps = batch.operations.map(Operation.inverse).reverse();
|
127 | for (var op of inverseOps) {
|
128 | e.apply(op);
|
129 | }
|
130 | if (batch.selectionBefore) {
|
131 | Transforms.setSelection(e, batch.selectionBefore);
|
132 | }
|
133 | });
|
134 | });
|
135 | e.writeHistory('redos', batch);
|
136 | history.undos.pop();
|
137 | }
|
138 | };
|
139 | e.apply = op => {
|
140 | var {
|
141 | operations,
|
142 | history
|
143 | } = e;
|
144 | var {
|
145 | undos
|
146 | } = history;
|
147 | var lastBatch = undos[undos.length - 1];
|
148 | var lastOp = lastBatch && lastBatch.operations[lastBatch.operations.length - 1];
|
149 | var save = HistoryEditor.isSaving(e);
|
150 | var merge = HistoryEditor.isMerging(e);
|
151 | if (save == null) {
|
152 | save = shouldSave(op);
|
153 | }
|
154 | if (save) {
|
155 | if (merge == null) {
|
156 | if (lastBatch == null) {
|
157 | merge = false;
|
158 | } else if (operations.length !== 0) {
|
159 | merge = true;
|
160 | } else {
|
161 | merge = shouldMerge(op, lastOp);
|
162 | }
|
163 | }
|
164 | if (lastBatch && merge) {
|
165 | lastBatch.operations.push(op);
|
166 | } else {
|
167 | var batch = {
|
168 | operations: [op],
|
169 | selectionBefore: e.selection
|
170 | };
|
171 | e.writeHistory('undos', batch);
|
172 | }
|
173 | while (undos.length > 100) {
|
174 | undos.shift();
|
175 | }
|
176 | history.redos = [];
|
177 | }
|
178 | apply(op);
|
179 | };
|
180 | e.writeHistory = (stack, batch) => {
|
181 | e.history[stack].push(batch);
|
182 | };
|
183 | return e;
|
184 | };
|
185 |
|
186 |
|
187 |
|
188 | var shouldMerge = (op, prev) => {
|
189 | if (prev && op.type === 'insert_text' && prev.type === 'insert_text' && op.offset === prev.offset + prev.text.length && Path.equals(op.path, prev.path)) {
|
190 | return true;
|
191 | }
|
192 | if (prev && op.type === 'remove_text' && prev.type === 'remove_text' && op.offset + op.text.length === prev.offset && Path.equals(op.path, prev.path)) {
|
193 | return true;
|
194 | }
|
195 | return false;
|
196 | };
|
197 |
|
198 |
|
199 |
|
200 | var shouldSave = (op, prev) => {
|
201 | if (op.type === 'set_selection') {
|
202 | return false;
|
203 | }
|
204 | return true;
|
205 | };
|
206 |
|
207 | export { HISTORY, History, HistoryEditor, MERGING, SAVING, withHistory };
|
208 |
|