suneditor 3.0.0-beta.2 → 3.0.0-beta.20
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/CONTRIBUTING.md +186 -184
- package/LICENSE +21 -21
- package/README.md +157 -180
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +126 -123
- package/src/assets/design/color.css +131 -121
- package/src/assets/design/index.css +3 -3
- package/src/assets/design/size.css +37 -35
- package/src/assets/design/typography.css +37 -37
- package/src/assets/icons/defaultIcons.js +247 -232
- package/src/assets/suneditor-contents.css +779 -778
- package/src/assets/suneditor.css +43 -35
- package/src/core/base/eventHandlers/handler_toolbar.js +135 -135
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +56 -56
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +115 -113
- package/src/core/base/eventHandlers/handler_ww_key_input.js +1200 -1200
- package/src/core/base/eventHandlers/handler_ww_mouse.js +194 -194
- package/src/core/base/eventManager.js +1550 -1484
- package/src/core/base/history.js +355 -355
- package/src/core/class/char.js +163 -162
- package/src/core/class/component.js +856 -842
- package/src/core/class/format.js +3433 -3422
- package/src/core/class/html.js +1927 -1890
- package/src/core/class/menu.js +357 -346
- package/src/core/class/nodeTransform.js +424 -424
- package/src/core/class/offset.js +858 -891
- package/src/core/class/selection.js +710 -620
- package/src/core/class/shortcuts.js +98 -98
- package/src/core/class/toolbar.js +438 -430
- package/src/core/class/ui.js +424 -422
- package/src/core/class/viewer.js +750 -750
- package/src/core/editor.js +1810 -1708
- package/src/core/section/actives.js +268 -241
- package/src/core/section/constructor.js +1348 -1661
- package/src/core/section/context.js +102 -102
- package/src/core/section/documentType.js +582 -561
- package/src/core/section/options.js +367 -0
- package/src/core/util/instanceCheck.js +59 -0
- package/src/editorInjector/_classes.js +36 -36
- package/src/editorInjector/_core.js +92 -92
- package/src/editorInjector/index.js +75 -75
- package/src/events.js +634 -622
- package/src/helper/clipboard.js +59 -59
- package/src/helper/converter.js +586 -564
- package/src/helper/dom/domCheck.js +304 -304
- package/src/helper/dom/domQuery.js +677 -669
- package/src/helper/dom/domUtils.js +618 -557
- package/src/helper/dom/index.js +12 -12
- package/src/helper/env.js +249 -240
- package/src/helper/index.js +25 -25
- package/src/helper/keyCodeMap.js +183 -183
- package/src/helper/numbers.js +72 -72
- package/src/helper/unicode.js +47 -47
- package/src/langs/ckb.js +231 -231
- package/src/langs/cs.js +231 -231
- package/src/langs/da.js +231 -231
- package/src/langs/de.js +231 -231
- package/src/langs/en.js +230 -230
- package/src/langs/es.js +231 -231
- package/src/langs/fa.js +231 -231
- package/src/langs/fr.js +231 -231
- package/src/langs/he.js +231 -231
- package/src/langs/hu.js +230 -230
- package/src/langs/index.js +28 -28
- package/src/langs/it.js +231 -231
- package/src/langs/ja.js +230 -230
- package/src/langs/km.js +230 -230
- package/src/langs/ko.js +230 -230
- package/src/langs/lv.js +231 -231
- package/src/langs/nl.js +231 -231
- package/src/langs/pl.js +231 -231
- package/src/langs/pt_br.js +231 -231
- package/src/langs/ro.js +231 -231
- package/src/langs/ru.js +231 -231
- package/src/langs/se.js +231 -231
- package/src/langs/tr.js +231 -231
- package/src/langs/uk.js +231 -231
- package/src/langs/ur.js +231 -231
- package/src/langs/zh_cn.js +231 -231
- package/src/modules/ApiManager.js +191 -191
- package/src/modules/Browser.js +669 -667
- package/src/modules/ColorPicker.js +364 -362
- package/src/modules/Controller.js +474 -454
- package/src/modules/Figure.js +1620 -1617
- package/src/modules/FileManager.js +359 -359
- package/src/modules/HueSlider.js +577 -565
- package/src/modules/Modal.js +346 -346
- package/src/modules/ModalAnchorEditor.js +643 -643
- package/src/modules/SelectMenu.js +549 -549
- package/src/modules/_DragHandle.js +17 -17
- package/src/modules/index.js +14 -14
- package/src/plugins/browser/audioGallery.js +83 -83
- package/src/plugins/browser/fileBrowser.js +103 -103
- package/src/plugins/browser/fileGallery.js +83 -83
- package/src/plugins/browser/imageGallery.js +81 -81
- package/src/plugins/browser/videoGallery.js +103 -103
- package/src/plugins/command/blockquote.js +61 -60
- package/src/plugins/command/exportPDF.js +134 -134
- package/src/plugins/command/fileUpload.js +456 -456
- package/src/plugins/command/list_bulleted.js +149 -148
- package/src/plugins/command/list_numbered.js +152 -151
- package/src/plugins/dropdown/align.js +157 -155
- package/src/plugins/dropdown/backgroundColor.js +108 -104
- package/src/plugins/dropdown/font.js +141 -137
- package/src/plugins/dropdown/fontColor.js +109 -105
- package/src/plugins/dropdown/formatBlock.js +170 -178
- package/src/plugins/dropdown/hr.js +152 -152
- package/src/plugins/dropdown/layout.js +83 -83
- package/src/plugins/dropdown/lineHeight.js +131 -130
- package/src/plugins/dropdown/list.js +123 -122
- package/src/plugins/dropdown/paragraphStyle.js +138 -138
- package/src/plugins/dropdown/table.js +4110 -4000
- package/src/plugins/dropdown/template.js +83 -83
- package/src/plugins/dropdown/textStyle.js +149 -149
- package/src/plugins/field/mention.js +242 -242
- package/src/plugins/index.js +120 -120
- package/src/plugins/input/fontSize.js +414 -410
- package/src/plugins/input/pageNavigator.js +71 -70
- package/src/plugins/modal/audio.js +677 -677
- package/src/plugins/modal/drawing.js +537 -531
- package/src/plugins/modal/embed.js +886 -886
- package/src/plugins/modal/image.js +1377 -1376
- package/src/plugins/modal/link.js +248 -240
- package/src/plugins/modal/math.js +563 -563
- package/src/plugins/modal/video.js +1226 -1226
- package/src/plugins/popup/anchor.js +224 -222
- package/src/suneditor.js +114 -107
- package/src/themes/dark.css +132 -122
- package/src/typedef.js +132 -130
- package/types/assets/icons/defaultIcons.d.ts +8 -0
- package/types/core/base/eventManager.d.ts +29 -4
- package/types/core/class/char.d.ts +2 -1
- package/types/core/class/component.d.ts +1 -2
- package/types/core/class/format.d.ts +8 -1
- package/types/core/class/html.d.ts +8 -0
- package/types/core/class/menu.d.ts +8 -0
- package/types/core/class/offset.d.ts +24 -26
- package/types/core/class/selection.d.ts +2 -0
- package/types/core/class/toolbar.d.ts +6 -0
- package/types/core/class/ui.d.ts +1 -1
- package/types/core/editor.d.ts +34 -12
- package/types/core/section/constructor.d.ts +5 -638
- package/types/core/section/documentType.d.ts +12 -2
- package/types/core/section/options.d.ts +740 -0
- package/types/core/util/instanceCheck.d.ts +50 -0
- package/types/editorInjector/_core.d.ts +5 -5
- package/types/editorInjector/index.d.ts +2 -2
- package/types/events.d.ts +2 -0
- package/types/helper/converter.d.ts +9 -0
- package/types/helper/dom/domQuery.d.ts +5 -5
- package/types/helper/dom/domUtils.d.ts +8 -0
- package/types/helper/env.d.ts +6 -1
- package/types/helper/index.d.ts +4 -1
- package/types/index.d.ts +122 -120
- package/types/langs/_Lang.d.ts +194 -194
- package/types/modules/ColorPicker.d.ts +5 -1
- package/types/modules/Controller.d.ts +8 -4
- package/types/modules/Figure.d.ts +2 -1
- package/types/modules/HueSlider.d.ts +4 -1
- package/types/modules/SelectMenu.d.ts +1 -1
- package/types/plugins/command/blockquote.d.ts +1 -0
- package/types/plugins/command/list_bulleted.d.ts +1 -0
- package/types/plugins/command/list_numbered.d.ts +1 -0
- package/types/plugins/dropdown/align.d.ts +1 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +1 -0
- package/types/plugins/dropdown/font.d.ts +1 -0
- package/types/plugins/dropdown/fontColor.d.ts +1 -0
- package/types/plugins/dropdown/formatBlock.d.ts +3 -2
- package/types/plugins/dropdown/lineHeight.d.ts +1 -0
- package/types/plugins/dropdown/list.d.ts +1 -0
- package/types/plugins/dropdown/table.d.ts +6 -0
- package/types/plugins/input/fontSize.d.ts +1 -0
- package/types/plugins/modal/drawing.d.ts +4 -0
- package/types/plugins/modal/link.d.ts +32 -15
- package/types/suneditor.d.ts +13 -9
- package/types/typedef.d.ts +8 -0
package/src/core/base/history.js
CHANGED
|
@@ -1,355 +1,355 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview history stack closure
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { _w } from '../../helper/env';
|
|
6
|
-
import { getNodeFromPath, getNodePath } from '../../helper/dom/domQuery';
|
|
7
|
-
import { numbers } from '../../helper';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @description History stack closure
|
|
11
|
-
* @param {__se__EditorCore} editor - The root editor instance
|
|
12
|
-
*/
|
|
13
|
-
export default function History(editor) {
|
|
14
|
-
const frameRoots = editor.frameRoots;
|
|
15
|
-
let delayTime = editor.options.get('historyStackDelayTime');
|
|
16
|
-
let pushDelay = null;
|
|
17
|
-
let stackIndex, stack, rootStack, rootInitContents;
|
|
18
|
-
let waiting = false;
|
|
19
|
-
let waitingTime = null;
|
|
20
|
-
|
|
21
|
-
function change(fc, index, isSetFocus) {
|
|
22
|
-
if (isSetFocus && editor.status.hasFocus) editor.eventManager.applyTagEffect();
|
|
23
|
-
editor.history.resetButtons(fc.get('key'), index);
|
|
24
|
-
|
|
25
|
-
// user event
|
|
26
|
-
editor.triggerEvent('onChange', { frameContext: fc, data: fc.get('wysiwyg').innerHTML });
|
|
27
|
-
if (editor.context.get('toolbar.main').style.display === 'block') editor.toolbar._showBalloon();
|
|
28
|
-
else if (editor.isSubBalloon && editor.context.get('toolbar.sub.main').style.display === 'block') editor.subToolbar._showBalloon();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function setContentFromStack(increase) {
|
|
32
|
-
const prevKey = stack[stackIndex];
|
|
33
|
-
const prevRoot = rootStack[prevKey];
|
|
34
|
-
const fc = editor.frameContext;
|
|
35
|
-
|
|
36
|
-
stackIndex += increase;
|
|
37
|
-
const rootKey = increase < 0 && prevKey !== stack[stackIndex] && prevRoot.index > 0 ? prevKey : stack[stackIndex];
|
|
38
|
-
const root = rootStack[rootKey];
|
|
39
|
-
root.index += increase;
|
|
40
|
-
|
|
41
|
-
const item = root.value[root.index];
|
|
42
|
-
frameRoots.get(rootKey).get('wysiwyg').innerHTML = item.content;
|
|
43
|
-
|
|
44
|
-
if (prevKey !== rootKey && increase < 0 && stackIndex === 1) {
|
|
45
|
-
stackIndex = 0;
|
|
46
|
-
} else if (prevKey !== rootKey && increase > 0 && root.index === 1) {
|
|
47
|
-
stackIndex++;
|
|
48
|
-
} else if ((increase < 0 && root.index < 1) || (increase > 0 && root.index > root.value.length)) {
|
|
49
|
-
stackIndex += increase;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let focusKey = rootKey;
|
|
53
|
-
let focusItem = item;
|
|
54
|
-
if (increase < 0 && stackIndex > 0 && root.index === 0) {
|
|
55
|
-
const nextKey = stack[stackIndex + increase];
|
|
56
|
-
if (nextKey !== rootKey) {
|
|
57
|
-
const nextRoot = rootStack[nextKey];
|
|
58
|
-
focusKey = nextKey;
|
|
59
|
-
focusItem = nextRoot.value[nextRoot.index];
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
editor.changeFrameContext(focusKey);
|
|
64
|
-
editor.selection.setRange(getNodeFromPath(focusItem.s.path, focusItem.frame), focusItem.s.offset, getNodeFromPath(focusItem.e.path, focusItem.frame), focusItem.e.offset);
|
|
65
|
-
editor.focus();
|
|
66
|
-
|
|
67
|
-
if (stackIndex < 0) stackIndex = 0;
|
|
68
|
-
else if (stackIndex >= stack.length) stackIndex = stack.length - 1;
|
|
69
|
-
|
|
70
|
-
editor.ui._offCurrentController();
|
|
71
|
-
editor._checkComponents(false);
|
|
72
|
-
editor.char.display();
|
|
73
|
-
editor._resourcesStateChange(fc);
|
|
74
|
-
|
|
75
|
-
// document type
|
|
76
|
-
if (fc.has('documentType-use-header')) {
|
|
77
|
-
fc.get('documentType').reHeader();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// onChange
|
|
81
|
-
change(fc, root.index, true);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function setStack(content, range, rootKey, increase) {
|
|
85
|
-
let s, e;
|
|
86
|
-
if (!range) {
|
|
87
|
-
s = { path: [0, 0], offset: [0, 0] };
|
|
88
|
-
e = { path: 0, offset: 0 };
|
|
89
|
-
} else {
|
|
90
|
-
s = {
|
|
91
|
-
path: getNodePath(range.startContainer, null, null),
|
|
92
|
-
offset: range.startOffset
|
|
93
|
-
};
|
|
94
|
-
e = {
|
|
95
|
-
path: getNodePath(range.endContainer, null, null),
|
|
96
|
-
offset: range.endOffset
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// set root stack
|
|
101
|
-
stackIndex += increase;
|
|
102
|
-
stack[stackIndex] = rootKey;
|
|
103
|
-
const root = rootStack[rootKey];
|
|
104
|
-
root.index += increase;
|
|
105
|
-
root.value[root.index] = {
|
|
106
|
-
content: content,
|
|
107
|
-
s: s,
|
|
108
|
-
e: e,
|
|
109
|
-
frame: frameRoots.get(rootKey).get('wysiwyg')
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function resetRoot(rootKey) {
|
|
114
|
-
stackIndex++;
|
|
115
|
-
stack[stackIndex] = rootKey;
|
|
116
|
-
const root = rootStack[rootKey];
|
|
117
|
-
root.index = 0;
|
|
118
|
-
root.value[0] = {
|
|
119
|
-
content: rootInitContents[rootKey],
|
|
120
|
-
s: { path: [0, 0], offset: [0, 0] },
|
|
121
|
-
e: { path: 0, offset: 0 },
|
|
122
|
-
frame: frameRoots.get(rootKey).get('wysiwyg')
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function initRoot(rootKey) {
|
|
127
|
-
rootStack[rootKey] = { value: [], index: -1 };
|
|
128
|
-
rootInitContents[rootKey] = frameRoots.get(rootKey).get('wysiwyg').innerHTML;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function refreshRoots(root) {
|
|
132
|
-
const deleteRoot = [];
|
|
133
|
-
for (let i = stackIndex + 1, len = stack.length; i < len; i++) {
|
|
134
|
-
if (deleteRoot.includes(stack[i])) continue;
|
|
135
|
-
deleteRoot.push(stack[i]);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
stack = stack.slice(0, stackIndex + 1);
|
|
139
|
-
root.value.splice(stackIndex + 1);
|
|
140
|
-
editor.applyCommandTargets('redo', (e) => {
|
|
141
|
-
e.disabled = true;
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
for (let i = 0, len = deleteRoot.length; i < len; i++) {
|
|
145
|
-
if (!stack.includes(deleteRoot[i])) initRoot(deleteRoot[i]);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function pushStack(rootKey, range) {
|
|
150
|
-
editor._checkComponents(false);
|
|
151
|
-
|
|
152
|
-
const fc = frameRoots.get(rootKey);
|
|
153
|
-
const current = fc.get('wysiwyg').innerHTML;
|
|
154
|
-
const root = rootStack[rootKey];
|
|
155
|
-
if (!current || (root.value[root.index] && current === root.value[root.index].content)) return;
|
|
156
|
-
if (stack.length > stackIndex + 1) refreshRoots(root);
|
|
157
|
-
if (root.value.length === 0) resetRoot(rootKey);
|
|
158
|
-
|
|
159
|
-
setStack(current, range, rootKey, 1);
|
|
160
|
-
|
|
161
|
-
if (stackIndex === 1) {
|
|
162
|
-
editor.applyCommandTargets('undo', (e) => {
|
|
163
|
-
e.disabled = false;
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
editor.char.display();
|
|
168
|
-
change(fc, root.index, false);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
/**
|
|
173
|
-
* @description Saving the current status to the history object stack
|
|
174
|
-
* - If "delay" is true, it will be saved after (options.get('historyStackDelayTime') || 400) milliseconds.
|
|
175
|
-
* - If the function is called again with the "delay" argument true before it is saved, the delay time is renewed.
|
|
176
|
-
* - You can specify the delay time by sending a number.
|
|
177
|
-
* @param {boolean|number} delay If true, add stack without delay time.
|
|
178
|
-
* @param {*=} [rootKey] The key of the root frame to save history for.
|
|
179
|
-
*/
|
|
180
|
-
push(delay, rootKey) {
|
|
181
|
-
if (waiting) return;
|
|
182
|
-
|
|
183
|
-
rootKey = rootKey || editor.status.rootKey;
|
|
184
|
-
const range = editor.status._range;
|
|
185
|
-
|
|
186
|
-
_w.setTimeout(editor._resourcesStateChange.bind(editor, frameRoots.get(rootKey)), 0);
|
|
187
|
-
const time = typeof delay === 'number' ? (delay > 0 ? delay : 0) : !delay ? 0 : delayTime;
|
|
188
|
-
|
|
189
|
-
if (!time || pushDelay) {
|
|
190
|
-
_w.clearTimeout(pushDelay);
|
|
191
|
-
if (!time) {
|
|
192
|
-
pushStack(rootKey, range);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
pushDelay = _w.setTimeout(() => {
|
|
198
|
-
_w.clearTimeout(pushDelay);
|
|
199
|
-
pushDelay = null;
|
|
200
|
-
pushStack(rootKey, range);
|
|
201
|
-
}, time);
|
|
202
|
-
},
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* @description Immediately saves the current state to the history stack if a delayed save is pending.
|
|
206
|
-
* @param {*} rootKey The key of the root frame.
|
|
207
|
-
* @param {Range} range The selection range object.
|
|
208
|
-
*/
|
|
209
|
-
check(rootKey, range) {
|
|
210
|
-
if (pushDelay) {
|
|
211
|
-
_w.clearTimeout(pushDelay);
|
|
212
|
-
pushDelay = null;
|
|
213
|
-
pushStack(rootKey, range);
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @description Undo function that restores the previous state from the history stack.
|
|
219
|
-
*/
|
|
220
|
-
undo() {
|
|
221
|
-
if (stackIndex > 0) {
|
|
222
|
-
setContentFromStack(-1);
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* @description Redo function that re-applies a previously undone state from the history stack.
|
|
228
|
-
*/
|
|
229
|
-
redo() {
|
|
230
|
-
if (stack.length - 1 > stackIndex) {
|
|
231
|
-
setContentFromStack(1);
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* @description Overwrites the current state in the history stack with the latest content.
|
|
237
|
-
* @param {string=} [rootKey] The key of the root frame to overwrite.
|
|
238
|
-
*/
|
|
239
|
-
overwrite(rootKey) {
|
|
240
|
-
setStack(frameRoots.get(rootKey || editor.status.rootKey).get('wysiwyg').innerHTML, null, editor.status.rootKey, 0);
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* @description Pauses the history stack, preventing new entries from being added for up to 5 seconds.
|
|
245
|
-
*/
|
|
246
|
-
pause() {
|
|
247
|
-
waiting = true;
|
|
248
|
-
|
|
249
|
-
if (waitingTime) {
|
|
250
|
-
_w.clearTimeout(waitingTime);
|
|
251
|
-
waitingTime = null;
|
|
252
|
-
}
|
|
253
|
-
waitingTime = _w.setTimeout(() => {
|
|
254
|
-
waiting = false;
|
|
255
|
-
}, 5000);
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @description Resumes history tracking by allowing new entries to be added to the stack.
|
|
260
|
-
*/
|
|
261
|
-
resume() {
|
|
262
|
-
if (waitingTime) {
|
|
263
|
-
_w.clearTimeout(waitingTime);
|
|
264
|
-
waitingTime = null;
|
|
265
|
-
}
|
|
266
|
-
waiting = false;
|
|
267
|
-
},
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* @description Resets the history stack and disables related UI buttons.
|
|
271
|
-
*/
|
|
272
|
-
reset() {
|
|
273
|
-
editor.applyCommandTargets('undo', (e) => (e.disabled = true));
|
|
274
|
-
editor.applyCommandTargets('redo', (e) => (e.disabled = true));
|
|
275
|
-
editor.applyCommandTargets('save', (e) => (e.disabled = true));
|
|
276
|
-
|
|
277
|
-
editor.applyFrameRoots((e) => e.set('historyIndex', -1));
|
|
278
|
-
editor.applyFrameRoots((e) => e.set('isChanged', false));
|
|
279
|
-
|
|
280
|
-
stackIndex = -1;
|
|
281
|
-
stack = [];
|
|
282
|
-
rootStack = {};
|
|
283
|
-
rootInitContents = {};
|
|
284
|
-
waiting = false;
|
|
285
|
-
|
|
286
|
-
const rootKeys = editor.rootKeys;
|
|
287
|
-
for (let i = 0, len = rootKeys.length; i < len; i++) {
|
|
288
|
-
initRoot(rootKeys[i]);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* @description Updates the state of history-related buttons (undo, redo, save) based on the current history stack.
|
|
294
|
-
* @param {*} rootKey The key of the root frame.
|
|
295
|
-
* @param {number} [index] The index of the current history state.
|
|
296
|
-
*/
|
|
297
|
-
resetButtons(rootKey, index) {
|
|
298
|
-
const isReset = !numbers.is(index);
|
|
299
|
-
const root = rootStack[rootKey === undefined ? stack[stackIndex] : rootKey];
|
|
300
|
-
index = !isReset ? index : root.index;
|
|
301
|
-
const target = editor.frameRoots.get(rootKey);
|
|
302
|
-
const rootLen = root.value.length - 1;
|
|
303
|
-
|
|
304
|
-
editor.applyCommandTargets('undo', (e) => {
|
|
305
|
-
if (index > 0 && index <= rootLen) e.disabled = false;
|
|
306
|
-
else e.disabled = true;
|
|
307
|
-
});
|
|
308
|
-
editor.applyCommandTargets('redo', (e) => {
|
|
309
|
-
if (index > -1 && index < rootLen) e.disabled = false;
|
|
310
|
-
else e.disabled = true;
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const savedIndex = target.get('savedIndex');
|
|
314
|
-
const historyIndex = target.get('historyIndex');
|
|
315
|
-
const isChanged = savedIndex > -1 ? savedIndex !== index : isReset ? root.index > 0 : index > 0 && historyIndex !== index;
|
|
316
|
-
|
|
317
|
-
target.set('historyIndex', index);
|
|
318
|
-
target.set('isChanged', isChanged);
|
|
319
|
-
editor.applyCommandTargets('save', (e) => {
|
|
320
|
-
if (isChanged) e.disabled = false;
|
|
321
|
-
else e.disabled = true;
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
editor.triggerEvent('onResetButtons', { rootKey });
|
|
325
|
-
},
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* @description Returns the root stack containing the history of each frame.
|
|
329
|
-
* @returns {{content: string, s: {path: number|number[], offset: number|number[]}, e: {path: number|number[], offset: number|number[]}, frame: HTMLElement}} The root stack object.
|
|
330
|
-
* - content: content html string
|
|
331
|
-
* - s: depth info of the "start" range
|
|
332
|
-
* - e: depth info of the "end" range
|
|
333
|
-
* - frame: wysiwyg editable element.
|
|
334
|
-
*/
|
|
335
|
-
getRootStack() {
|
|
336
|
-
return rootStack;
|
|
337
|
-
},
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* @description Resets the delay time for saving history.
|
|
341
|
-
* @param {number} ms The new delay time in milliseconds.
|
|
342
|
-
*/
|
|
343
|
-
resetDelayTime(ms) {
|
|
344
|
-
delayTime = ms;
|
|
345
|
-
},
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* @description Clears the entire history stack and cancels any pending save operations.
|
|
349
|
-
*/
|
|
350
|
-
destroy() {
|
|
351
|
-
if (pushDelay) _w.clearTimeout(pushDelay);
|
|
352
|
-
stackIndex = stack = rootStack = rootInitContents = null;
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview history stack closure
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { _w } from '../../helper/env';
|
|
6
|
+
import { getNodeFromPath, getNodePath } from '../../helper/dom/domQuery';
|
|
7
|
+
import { numbers } from '../../helper';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @description History stack closure
|
|
11
|
+
* @param {__se__EditorCore} editor - The root editor instance
|
|
12
|
+
*/
|
|
13
|
+
export default function History(editor) {
|
|
14
|
+
const frameRoots = editor.frameRoots;
|
|
15
|
+
let delayTime = editor.options.get('historyStackDelayTime');
|
|
16
|
+
let pushDelay = null;
|
|
17
|
+
let stackIndex, stack, rootStack, rootInitContents;
|
|
18
|
+
let waiting = false;
|
|
19
|
+
let waitingTime = null;
|
|
20
|
+
|
|
21
|
+
function change(fc, index, isSetFocus) {
|
|
22
|
+
if (isSetFocus && editor.status.hasFocus) editor.eventManager.applyTagEffect();
|
|
23
|
+
editor.history.resetButtons(fc.get('key'), index);
|
|
24
|
+
|
|
25
|
+
// user event
|
|
26
|
+
editor.triggerEvent('onChange', { frameContext: fc, data: fc.get('wysiwyg').innerHTML });
|
|
27
|
+
if (editor.context.get('toolbar.main').style.display === 'block') editor.toolbar._showBalloon();
|
|
28
|
+
else if (editor.isSubBalloon && editor.context.get('toolbar.sub.main').style.display === 'block') editor.subToolbar._showBalloon();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function setContentFromStack(increase) {
|
|
32
|
+
const prevKey = stack[stackIndex];
|
|
33
|
+
const prevRoot = rootStack[prevKey];
|
|
34
|
+
const fc = editor.frameContext;
|
|
35
|
+
|
|
36
|
+
stackIndex += increase;
|
|
37
|
+
const rootKey = increase < 0 && prevKey !== stack[stackIndex] && prevRoot.index > 0 ? prevKey : stack[stackIndex];
|
|
38
|
+
const root = rootStack[rootKey];
|
|
39
|
+
root.index += increase;
|
|
40
|
+
|
|
41
|
+
const item = root.value[root.index];
|
|
42
|
+
frameRoots.get(rootKey).get('wysiwyg').innerHTML = item.content;
|
|
43
|
+
|
|
44
|
+
if (prevKey !== rootKey && increase < 0 && stackIndex === 1) {
|
|
45
|
+
stackIndex = 0;
|
|
46
|
+
} else if (prevKey !== rootKey && increase > 0 && root.index === 1) {
|
|
47
|
+
stackIndex++;
|
|
48
|
+
} else if ((increase < 0 && root.index < 1) || (increase > 0 && root.index > root.value.length)) {
|
|
49
|
+
stackIndex += increase;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let focusKey = rootKey;
|
|
53
|
+
let focusItem = item;
|
|
54
|
+
if (increase < 0 && stackIndex > 0 && root.index === 0) {
|
|
55
|
+
const nextKey = stack[stackIndex + increase];
|
|
56
|
+
if (nextKey !== rootKey) {
|
|
57
|
+
const nextRoot = rootStack[nextKey];
|
|
58
|
+
focusKey = nextKey;
|
|
59
|
+
focusItem = nextRoot.value[nextRoot.index];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
editor.changeFrameContext(focusKey);
|
|
64
|
+
editor.selection.setRange(getNodeFromPath(focusItem.s.path, focusItem.frame), focusItem.s.offset, getNodeFromPath(focusItem.e.path, focusItem.frame), focusItem.e.offset);
|
|
65
|
+
editor.focus();
|
|
66
|
+
|
|
67
|
+
if (stackIndex < 0) stackIndex = 0;
|
|
68
|
+
else if (stackIndex >= stack.length) stackIndex = stack.length - 1;
|
|
69
|
+
|
|
70
|
+
editor.ui._offCurrentController();
|
|
71
|
+
editor._checkComponents(false);
|
|
72
|
+
editor.char.display();
|
|
73
|
+
editor._resourcesStateChange(fc);
|
|
74
|
+
|
|
75
|
+
// document type
|
|
76
|
+
if (fc.has('documentType-use-header')) {
|
|
77
|
+
fc.get('documentType').reHeader();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// onChange
|
|
81
|
+
change(fc, root.index, true);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function setStack(content, range, rootKey, increase) {
|
|
85
|
+
let s, e;
|
|
86
|
+
if (!range) {
|
|
87
|
+
s = { path: [0, 0], offset: [0, 0] };
|
|
88
|
+
e = { path: 0, offset: 0 };
|
|
89
|
+
} else {
|
|
90
|
+
s = {
|
|
91
|
+
path: getNodePath(range.startContainer, null, null),
|
|
92
|
+
offset: range.startOffset
|
|
93
|
+
};
|
|
94
|
+
e = {
|
|
95
|
+
path: getNodePath(range.endContainer, null, null),
|
|
96
|
+
offset: range.endOffset
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// set root stack
|
|
101
|
+
stackIndex += increase;
|
|
102
|
+
stack[stackIndex] = rootKey;
|
|
103
|
+
const root = rootStack[rootKey];
|
|
104
|
+
root.index += increase;
|
|
105
|
+
root.value[root.index] = {
|
|
106
|
+
content: content,
|
|
107
|
+
s: s,
|
|
108
|
+
e: e,
|
|
109
|
+
frame: frameRoots.get(rootKey).get('wysiwyg')
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resetRoot(rootKey) {
|
|
114
|
+
stackIndex++;
|
|
115
|
+
stack[stackIndex] = rootKey;
|
|
116
|
+
const root = rootStack[rootKey];
|
|
117
|
+
root.index = 0;
|
|
118
|
+
root.value[0] = {
|
|
119
|
+
content: rootInitContents[rootKey],
|
|
120
|
+
s: { path: [0, 0], offset: [0, 0] },
|
|
121
|
+
e: { path: 0, offset: 0 },
|
|
122
|
+
frame: frameRoots.get(rootKey).get('wysiwyg')
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function initRoot(rootKey) {
|
|
127
|
+
rootStack[rootKey] = { value: [], index: -1 };
|
|
128
|
+
rootInitContents[rootKey] = frameRoots.get(rootKey).get('wysiwyg').innerHTML;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function refreshRoots(root) {
|
|
132
|
+
const deleteRoot = [];
|
|
133
|
+
for (let i = stackIndex + 1, len = stack.length; i < len; i++) {
|
|
134
|
+
if (deleteRoot.includes(stack[i])) continue;
|
|
135
|
+
deleteRoot.push(stack[i]);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
stack = stack.slice(0, stackIndex + 1);
|
|
139
|
+
root.value.splice(stackIndex + 1);
|
|
140
|
+
editor.applyCommandTargets('redo', (e) => {
|
|
141
|
+
e.disabled = true;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
for (let i = 0, len = deleteRoot.length; i < len; i++) {
|
|
145
|
+
if (!stack.includes(deleteRoot[i])) initRoot(deleteRoot[i]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function pushStack(rootKey, range) {
|
|
150
|
+
editor._checkComponents(false);
|
|
151
|
+
|
|
152
|
+
const fc = frameRoots.get(rootKey);
|
|
153
|
+
const current = fc.get('wysiwyg').innerHTML;
|
|
154
|
+
const root = rootStack[rootKey];
|
|
155
|
+
if (!current || (root.value[root.index] && current === root.value[root.index].content)) return;
|
|
156
|
+
if (stack.length > stackIndex + 1) refreshRoots(root);
|
|
157
|
+
if (root.value.length === 0) resetRoot(rootKey);
|
|
158
|
+
|
|
159
|
+
setStack(current, range, rootKey, 1);
|
|
160
|
+
|
|
161
|
+
if (stackIndex === 1) {
|
|
162
|
+
editor.applyCommandTargets('undo', (e) => {
|
|
163
|
+
e.disabled = false;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
editor.char.display();
|
|
168
|
+
change(fc, root.index, false);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
/**
|
|
173
|
+
* @description Saving the current status to the history object stack
|
|
174
|
+
* - If "delay" is true, it will be saved after (options.get('historyStackDelayTime') || 400) milliseconds.
|
|
175
|
+
* - If the function is called again with the "delay" argument true before it is saved, the delay time is renewed.
|
|
176
|
+
* - You can specify the delay time by sending a number.
|
|
177
|
+
* @param {boolean|number} delay If true, add stack without delay time.
|
|
178
|
+
* @param {*=} [rootKey] The key of the root frame to save history for.
|
|
179
|
+
*/
|
|
180
|
+
push(delay, rootKey) {
|
|
181
|
+
if (waiting) return;
|
|
182
|
+
|
|
183
|
+
rootKey = rootKey || rootKey === null ? rootKey : editor.status.rootKey;
|
|
184
|
+
const range = editor.status._range;
|
|
185
|
+
|
|
186
|
+
_w.setTimeout(editor._resourcesStateChange.bind(editor, frameRoots.get(rootKey)), 0);
|
|
187
|
+
const time = typeof delay === 'number' ? (delay > 0 ? delay : 0) : !delay ? 0 : delayTime;
|
|
188
|
+
|
|
189
|
+
if (!time || pushDelay) {
|
|
190
|
+
_w.clearTimeout(pushDelay);
|
|
191
|
+
if (!time) {
|
|
192
|
+
pushStack(rootKey, range);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
pushDelay = _w.setTimeout(() => {
|
|
198
|
+
_w.clearTimeout(pushDelay);
|
|
199
|
+
pushDelay = null;
|
|
200
|
+
pushStack(rootKey, range);
|
|
201
|
+
}, time);
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @description Immediately saves the current state to the history stack if a delayed save is pending.
|
|
206
|
+
* @param {*} rootKey The key of the root frame.
|
|
207
|
+
* @param {Range} range The selection range object.
|
|
208
|
+
*/
|
|
209
|
+
check(rootKey, range) {
|
|
210
|
+
if (pushDelay) {
|
|
211
|
+
_w.clearTimeout(pushDelay);
|
|
212
|
+
pushDelay = null;
|
|
213
|
+
pushStack(rootKey, range);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @description Undo function that restores the previous state from the history stack.
|
|
219
|
+
*/
|
|
220
|
+
undo() {
|
|
221
|
+
if (stackIndex > 0) {
|
|
222
|
+
setContentFromStack(-1);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @description Redo function that re-applies a previously undone state from the history stack.
|
|
228
|
+
*/
|
|
229
|
+
redo() {
|
|
230
|
+
if (stack.length - 1 > stackIndex) {
|
|
231
|
+
setContentFromStack(1);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @description Overwrites the current state in the history stack with the latest content.
|
|
237
|
+
* @param {string=} [rootKey] The key of the root frame to overwrite.
|
|
238
|
+
*/
|
|
239
|
+
overwrite(rootKey) {
|
|
240
|
+
setStack(frameRoots.get(rootKey || editor.status.rootKey).get('wysiwyg').innerHTML, null, editor.status.rootKey, 0);
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @description Pauses the history stack, preventing new entries from being added for up to 5 seconds.
|
|
245
|
+
*/
|
|
246
|
+
pause() {
|
|
247
|
+
waiting = true;
|
|
248
|
+
|
|
249
|
+
if (waitingTime) {
|
|
250
|
+
_w.clearTimeout(waitingTime);
|
|
251
|
+
waitingTime = null;
|
|
252
|
+
}
|
|
253
|
+
waitingTime = _w.setTimeout(() => {
|
|
254
|
+
waiting = false;
|
|
255
|
+
}, 5000);
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* @description Resumes history tracking by allowing new entries to be added to the stack.
|
|
260
|
+
*/
|
|
261
|
+
resume() {
|
|
262
|
+
if (waitingTime) {
|
|
263
|
+
_w.clearTimeout(waitingTime);
|
|
264
|
+
waitingTime = null;
|
|
265
|
+
}
|
|
266
|
+
waiting = false;
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @description Resets the history stack and disables related UI buttons.
|
|
271
|
+
*/
|
|
272
|
+
reset() {
|
|
273
|
+
editor.applyCommandTargets('undo', (e) => (e.disabled = true));
|
|
274
|
+
editor.applyCommandTargets('redo', (e) => (e.disabled = true));
|
|
275
|
+
editor.applyCommandTargets('save', (e) => (e.disabled = true));
|
|
276
|
+
|
|
277
|
+
editor.applyFrameRoots((e) => e.set('historyIndex', -1));
|
|
278
|
+
editor.applyFrameRoots((e) => e.set('isChanged', false));
|
|
279
|
+
|
|
280
|
+
stackIndex = -1;
|
|
281
|
+
stack = [];
|
|
282
|
+
rootStack = {};
|
|
283
|
+
rootInitContents = {};
|
|
284
|
+
waiting = false;
|
|
285
|
+
|
|
286
|
+
const rootKeys = editor.rootKeys;
|
|
287
|
+
for (let i = 0, len = rootKeys.length; i < len; i++) {
|
|
288
|
+
initRoot(rootKeys[i]);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @description Updates the state of history-related buttons (undo, redo, save) based on the current history stack.
|
|
294
|
+
* @param {*} rootKey The key of the root frame.
|
|
295
|
+
* @param {number} [index] The index of the current history state.
|
|
296
|
+
*/
|
|
297
|
+
resetButtons(rootKey, index) {
|
|
298
|
+
const isReset = !numbers.is(index);
|
|
299
|
+
const root = rootStack[rootKey === undefined ? stack[stackIndex] : rootKey];
|
|
300
|
+
index = !isReset ? index : root.index;
|
|
301
|
+
const target = editor.frameRoots.get(rootKey);
|
|
302
|
+
const rootLen = root.value.length - 1;
|
|
303
|
+
|
|
304
|
+
editor.applyCommandTargets('undo', (e) => {
|
|
305
|
+
if (index > 0 && index <= rootLen) e.disabled = false;
|
|
306
|
+
else e.disabled = true;
|
|
307
|
+
});
|
|
308
|
+
editor.applyCommandTargets('redo', (e) => {
|
|
309
|
+
if (index > -1 && index < rootLen) e.disabled = false;
|
|
310
|
+
else e.disabled = true;
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const savedIndex = target.get('savedIndex');
|
|
314
|
+
const historyIndex = target.get('historyIndex');
|
|
315
|
+
const isChanged = savedIndex > -1 ? savedIndex !== index : isReset ? root.index > 0 : index > 0 && historyIndex !== index;
|
|
316
|
+
|
|
317
|
+
target.set('historyIndex', index);
|
|
318
|
+
target.set('isChanged', isChanged);
|
|
319
|
+
editor.applyCommandTargets('save', (e) => {
|
|
320
|
+
if (isChanged) e.disabled = false;
|
|
321
|
+
else e.disabled = true;
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
editor.triggerEvent('onResetButtons', { rootKey });
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @description Returns the root stack containing the history of each frame.
|
|
329
|
+
* @returns {{content: string, s: {path: number|number[], offset: number|number[]}, e: {path: number|number[], offset: number|number[]}, frame: HTMLElement}} The root stack object.
|
|
330
|
+
* - content: content html string
|
|
331
|
+
* - s: depth info of the "start" range
|
|
332
|
+
* - e: depth info of the "end" range
|
|
333
|
+
* - frame: wysiwyg editable element.
|
|
334
|
+
*/
|
|
335
|
+
getRootStack() {
|
|
336
|
+
return rootStack;
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @description Resets the delay time for saving history.
|
|
341
|
+
* @param {number} ms The new delay time in milliseconds.
|
|
342
|
+
*/
|
|
343
|
+
resetDelayTime(ms) {
|
|
344
|
+
delayTime = ms;
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @description Clears the entire history stack and cancels any pending save operations.
|
|
349
|
+
*/
|
|
350
|
+
destroy() {
|
|
351
|
+
if (pushDelay) _w.clearTimeout(pushDelay);
|
|
352
|
+
stackIndex = stack = rootStack = rootInitContents = null;
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
}
|