suneditor 3.1.4 → 3.2.1
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/dist/suneditor-contents.min.css +1 -1
- package/dist/suneditor.min.css +28 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +2 -1
- package/src/assets/design/color.css +12 -0
- package/src/assets/design/size.css +9 -2
- package/src/assets/icons/defaultIcons.js +96 -47
- package/src/assets/suneditor-contents.css +3 -2
- package/src/assets/suneditor.css +481 -31
- package/src/core/config/contextProvider.js +2 -1
- package/src/core/config/eventManager.js +41 -2
- package/src/core/config/optionProvider.js +23 -2
- package/src/core/editor.js +32 -14
- package/src/core/event/actions/index.js +76 -9
- package/src/core/event/effects/common.registry.js +2 -1
- package/src/core/event/effects/keydown.registry.js +169 -33
- package/src/core/event/effects/ruleHelpers.js +20 -6
- package/src/core/event/eventOrchestrator.js +162 -30
- package/src/core/event/handlers/handler_toolbar.js +4 -2
- package/src/core/event/handlers/handler_ww_dragDrop.js +10 -0
- package/src/core/event/handlers/handler_ww_input.js +84 -2
- package/src/core/event/handlers/handler_ww_key.js +82 -21
- package/src/core/event/handlers/handler_ww_mouse.js +45 -8
- package/src/core/event/ports.js +27 -13
- package/src/core/event/reducers/keydown.reducer.js +33 -5
- package/src/core/event/rules/keydown.rule.arrow.js +12 -2
- package/src/core/event/rules/keydown.rule.backspace.js +110 -15
- package/src/core/event/rules/keydown.rule.delete.js +62 -7
- package/src/core/event/rules/keydown.rule.enter.js +62 -31
- package/src/core/event/support/defaultLineManager.js +9 -2
- package/src/core/event/support/selectionState.js +13 -3
- package/src/core/kernel/coreKernel.js +1 -0
- package/src/core/logic/dom/char.js +13 -3
- package/src/core/logic/dom/format.js +171 -39
- package/src/core/logic/dom/html.js +350 -72
- package/src/core/logic/dom/inline.js +229 -34
- package/src/core/logic/dom/listFormat.js +111 -20
- package/src/core/logic/dom/nodeTransform.js +36 -11
- package/src/core/logic/dom/offset.js +116 -31
- package/src/core/logic/dom/selection.js +147 -29
- package/src/core/logic/panel/blockHandle.js +785 -0
- package/src/core/logic/panel/blockResolver.js +278 -0
- package/src/core/logic/panel/finder.js +16 -6
- package/src/core/logic/panel/menu.js +119 -18
- package/src/core/logic/panel/toolbar.js +75 -19
- package/src/core/logic/panel/viewer.js +76 -20
- package/src/core/logic/shell/_commandExecutor.js +44 -9
- package/src/core/logic/shell/commandDispatcher.js +46 -4
- package/src/core/logic/shell/component.js +102 -25
- package/src/core/logic/shell/focusManager.js +13 -3
- package/src/core/logic/shell/history.js +21 -6
- package/src/core/logic/shell/pluginManager.js +21 -13
- package/src/core/logic/shell/shortcuts.js +9 -1
- package/src/core/logic/shell/ui.js +139 -37
- package/src/core/schema/frameContext.js +34 -3
- package/src/core/schema/options.js +46 -4
- package/src/core/section/constructor.js +537 -106
- package/src/core/section/documentType.js +35 -6
- package/src/helper/converter.js +24 -7
- package/src/helper/dom/domCheck.js +25 -5
- package/src/helper/dom/domQuery.js +2 -1
- package/src/helper/dom/domUtils.js +17 -4
- package/src/helper/env.js +11 -2
- package/src/helper/keyCodeMap.js +6 -2
- package/src/helper/markdown.js +24 -5
- package/src/helper/msOffice.js +9 -2
- package/src/interfaces/plugins.js +1 -1
- package/src/langs/ckb.js +0 -1
- package/src/langs/cs.js +0 -1
- package/src/langs/da.js +0 -1
- package/src/langs/de.js +0 -1
- package/src/langs/en.js +0 -1
- package/src/langs/es.js +0 -1
- package/src/langs/fa.js +0 -1
- package/src/langs/fr.js +0 -1
- package/src/langs/he.js +0 -1
- package/src/langs/hu.js +0 -1
- package/src/langs/index.js +27 -1
- package/src/langs/it.js +0 -1
- package/src/langs/ja.js +0 -1
- package/src/langs/km.js +0 -1
- package/src/langs/ko.js +0 -1
- package/src/langs/lv.js +0 -1
- package/src/langs/nl.js +0 -1
- package/src/langs/pl.js +0 -1
- package/src/langs/pt_br.js +0 -1
- package/src/langs/ro.js +0 -1
- package/src/langs/ru.js +0 -1
- package/src/langs/se.js +0 -1
- package/src/langs/tr.js +0 -1
- package/src/langs/uk.js +0 -1
- package/src/langs/ur.js +0 -1
- package/src/langs/zh_cn.js +0 -1
- package/src/modules/contract/Browser.js +58 -14
- package/src/modules/contract/ColorPicker.js +12 -4
- package/src/modules/contract/Controller.js +37 -7
- package/src/modules/contract/Figure.js +156 -36
- package/src/modules/contract/HueSlider.js +27 -4
- package/src/modules/contract/Modal.js +50 -10
- package/src/modules/manager/FileManager.js +50 -8
- package/src/modules/ui/CommandMenu.js +597 -0
- package/src/modules/ui/ModalAnchorEditor.js +33 -6
- package/src/modules/ui/SelectMenu.js +481 -36
- package/src/modules/ui/index.js +1 -0
- package/src/plugins/browser/audioGallery.js +2 -1
- package/src/plugins/browser/fileBrowser.js +9 -2
- package/src/plugins/browser/fileGallery.js +2 -1
- package/src/plugins/browser/imageGallery.js +18 -3
- package/src/plugins/browser/videoGallery.js +13 -4
- package/src/plugins/command/blockquote.js +6 -1
- package/src/plugins/command/codeBlock.js +43 -5
- package/src/plugins/command/exportPDF.js +20 -4
- package/src/plugins/command/fileUpload.js +46 -11
- package/src/plugins/command/list_bulleted.js +6 -1
- package/src/plugins/command/list_numbered.js +6 -1
- package/src/plugins/dropdown/align.js +21 -33
- package/src/plugins/dropdown/backgroundColor.js +10 -2
- package/src/plugins/dropdown/blockStyle.js +17 -22
- package/src/plugins/dropdown/font.js +34 -34
- package/src/plugins/dropdown/hr.js +15 -43
- package/src/plugins/dropdown/layout.js +10 -27
- package/src/plugins/dropdown/lineHeight.js +10 -33
- package/src/plugins/dropdown/list.js +19 -25
- package/src/plugins/dropdown/paragraphStyle.js +16 -24
- package/src/plugins/dropdown/table/index.js +72 -17
- package/src/plugins/dropdown/table/render/table.html.js +3 -1
- package/src/plugins/dropdown/table/services/table.cell.js +33 -7
- package/src/plugins/dropdown/table/services/table.clipboard.js +5 -1
- package/src/plugins/dropdown/table/services/table.grid.js +40 -9
- package/src/plugins/dropdown/table/services/table.resize.js +55 -11
- package/src/plugins/dropdown/table/services/table.selection.js +27 -7
- package/src/plugins/dropdown/table/services/table.style.js +120 -20
- package/src/plugins/dropdown/template.js +13 -29
- package/src/plugins/dropdown/textStyle.js +22 -35
- package/src/plugins/field/autocomplete.js +8 -4
- package/src/plugins/field/slashCommand.js +297 -0
- package/src/plugins/index.js +3 -0
- package/src/plugins/input/fontSize.js +37 -8
- package/src/plugins/input/pageNavigator.js +7 -1
- package/src/plugins/modal/audio.js +71 -17
- package/src/plugins/modal/drawing.js +41 -11
- package/src/plugins/modal/embed.js +92 -22
- package/src/plugins/modal/image/index.js +114 -28
- package/src/plugins/modal/image/services/image.size.js +9 -2
- package/src/plugins/modal/image/services/image.upload.js +38 -4
- package/src/plugins/modal/link.js +9 -2
- package/src/plugins/modal/math.js +10 -2
- package/src/plugins/modal/video/index.js +112 -26
- package/src/plugins/modal/video/render/video.html.js +4 -1
- package/src/plugins/modal/video/services/video.size.js +15 -4
- package/src/plugins/modal/video/services/video.upload.js +10 -2
- package/src/plugins/popup/anchor.js +14 -2
- package/src/suneditor.js +8 -2
- package/src/themes/cobalt.css +12 -0
- package/src/themes/cream.css +12 -0
- package/src/themes/dark.css +12 -0
- package/src/themes/midnight.css +12 -0
- package/src/typedef.js +32 -21
- package/types/assets/icons/defaultIcons.d.ts +1 -0
- package/types/core/config/contextProvider.d.ts +7 -1
- package/types/core/config/eventManager.d.ts +37 -4
- package/types/core/config/optionProvider.d.ts +5 -1
- package/types/core/event/actions/index.d.ts +44 -6
- package/types/core/event/effects/keydown.registry.d.ts +37 -7
- package/types/core/event/effects/ruleHelpers.d.ts +6 -1
- package/types/core/event/eventOrchestrator.d.ts +13 -3
- package/types/core/event/handlers/handler_ww_clipboard.d.ts +15 -3
- package/types/core/event/handlers/handler_ww_dragDrop.d.ts +14 -2
- package/types/core/event/handlers/handler_ww_input.d.ts +10 -2
- package/types/core/event/handlers/handler_ww_key.d.ts +10 -2
- package/types/core/event/handlers/handler_ww_mouse.d.ts +25 -5
- package/types/core/event/ports.d.ts +11 -4
- package/types/core/event/reducers/keydown.reducer.d.ts +12 -3
- package/types/core/event/rules/keydown.rule.backspace.d.ts +6 -1
- package/types/core/kernel/store.d.ts +4 -1
- package/types/core/logic/dom/format.d.ts +32 -14
- package/types/core/logic/dom/html.d.ts +11 -3
- package/types/core/logic/dom/nodeTransform.d.ts +6 -6
- package/types/core/logic/panel/blockHandle.d.ts +64 -0
- package/types/core/logic/panel/blockResolver.d.ts +50 -0
- package/types/core/logic/panel/menu.d.ts +72 -3
- package/types/core/logic/shell/commandDispatcher.d.ts +8 -0
- package/types/core/logic/shell/component.d.ts +5 -3
- package/types/core/logic/shell/shortcuts.d.ts +10 -1
- package/types/core/logic/shell/ui.d.ts +7 -1
- package/types/core/schema/context.d.ts +7 -1
- package/types/core/schema/frameContext.d.ts +36 -4
- package/types/core/schema/options.d.ts +83 -2
- package/types/core/section/constructor.d.ts +38 -1
- package/types/events.d.ts +208 -32
- package/types/helper/converter.d.ts +4 -2
- package/types/helper/dom/domCheck.d.ts +12 -2
- package/types/helper/dom/domQuery.d.ts +35 -7
- package/types/helper/dom/domUtils.d.ts +4 -1
- package/types/interfaces/plugins.d.ts +2 -2
- package/types/langs/_Lang.d.ts +0 -1
- package/types/modules/contract/ColorPicker.d.ts +2 -2
- package/types/modules/contract/Controller.d.ts +7 -0
- package/types/modules/contract/Figure.d.ts +31 -4
- package/types/modules/ui/CommandMenu.d.ts +262 -0
- package/types/modules/ui/SelectMenu.d.ts +56 -3
- package/types/modules/ui/index.d.ts +1 -0
- package/types/plugins/browser/audioGallery.d.ts +1 -1
- package/types/plugins/browser/fileBrowser.d.ts +1 -1
- package/types/plugins/browser/fileGallery.d.ts +1 -1
- package/types/plugins/browser/imageGallery.d.ts +1 -1
- package/types/plugins/browser/videoGallery.d.ts +1 -1
- package/types/plugins/dropdown/align.d.ts +1 -1
- package/types/plugins/dropdown/blockStyle.d.ts +3 -1
- package/types/plugins/dropdown/table/index.d.ts +4 -1
- package/types/plugins/dropdown/table/services/table.clipboard.d.ts +5 -1
- package/types/plugins/dropdown/table/services/table.grid.d.ts +10 -2
- package/types/plugins/field/autocomplete.d.ts +0 -1
- package/types/plugins/field/slashCommand.d.ts +165 -0
- package/types/plugins/index.d.ts +3 -0
- package/types/plugins/modal/link.d.ts +4 -1
- package/types/typedef.d.ts +48 -23
|
@@ -20,7 +20,12 @@ export default {
|
|
|
20
20
|
if (rInfo.commonCon !== rInfo.container && formatEl.parentElement) {
|
|
21
21
|
if (formatEl.contains(container)) {
|
|
22
22
|
const focusNode = LineDelete_next(formatEl);
|
|
23
|
-
ports.selection.setRange(
|
|
23
|
+
ports.selection.setRange(
|
|
24
|
+
focusNode,
|
|
25
|
+
focusNode.textContent.length,
|
|
26
|
+
focusNode,
|
|
27
|
+
focusNode.textContent.length,
|
|
28
|
+
);
|
|
24
29
|
} else {
|
|
25
30
|
const { focusNode, focusOffset } = LineDelete_prev(formatEl);
|
|
26
31
|
ports.selection.setRange(focusNode, focusOffset, focusNode, focusOffset);
|
|
@@ -64,7 +69,10 @@ export default {
|
|
|
64
69
|
formatEl.removeAttribute(attrs[0].name);
|
|
65
70
|
}
|
|
66
71
|
} else {
|
|
67
|
-
formatEl.parentNode.replaceChild(
|
|
72
|
+
formatEl.parentNode.replaceChild(
|
|
73
|
+
dom.utils.createElement(ctx.options.get('defaultLine'), null, '<br>'),
|
|
74
|
+
formatEl,
|
|
75
|
+
);
|
|
68
76
|
}
|
|
69
77
|
},
|
|
70
78
|
|
|
@@ -72,16 +80,19 @@ export default {
|
|
|
72
80
|
'backspace.component.select': ({ ports }, { selectionNode, range, fileComponentInfo }) => {
|
|
73
81
|
let currentZWS = null;
|
|
74
82
|
if (dom.check.isBreak(selectionNode)) dom.utils.removeItem(selectionNode);
|
|
75
|
-
else if (dom.check.isBreak((currentZWS = range.startContainer.childNodes?.[range.startOffset])))
|
|
83
|
+
else if (dom.check.isBreak((currentZWS = range.startContainer.childNodes?.[range.startOffset])))
|
|
84
|
+
dom.utils.removeItem(currentZWS);
|
|
76
85
|
|
|
77
|
-
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
86
|
+
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
87
|
+
ports.focusManager.blur();
|
|
78
88
|
},
|
|
79
89
|
|
|
80
90
|
/** @action backspaceComponentRemove */
|
|
81
91
|
'backspace.component.remove': ({ ports }, { isList, sel, formatEl, fileComponentInfo }) => {
|
|
82
92
|
if (isList) dom.utils.removeItem(sel);
|
|
83
93
|
if (formatEl.textContent.length === 0) dom.utils.removeItem(formatEl);
|
|
84
|
-
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
94
|
+
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
95
|
+
ports.focusManager.blur();
|
|
85
96
|
},
|
|
86
97
|
|
|
87
98
|
/** @action backspaceListMergePrev */
|
|
@@ -110,7 +121,37 @@ export default {
|
|
|
110
121
|
'backspace.list.removeNested': ({ ports }, { range }) => {
|
|
111
122
|
ports.html.remove();
|
|
112
123
|
if (range.startContainer.nodeType === 3) {
|
|
113
|
-
ports.selection.setRange(
|
|
124
|
+
ports.selection.setRange(
|
|
125
|
+
range.startContainer,
|
|
126
|
+
range.startContainer.textContent.length,
|
|
127
|
+
range.startContainer,
|
|
128
|
+
range.startContainer.textContent.length,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/** @action backspaceEmptyLineMergePrev */
|
|
134
|
+
'backspace.emptyLine.mergePrev': ({ ports }, { formatEl, prev }) => {
|
|
135
|
+
dom.utils.removeItem(formatEl);
|
|
136
|
+
caretToLineEdge(ports, prev, true);
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/** @action backspaceBrLineRowMerge */
|
|
140
|
+
'backspace.brline.rowMerge': ({ ports }, { rowEndBr, rowStartBr }) => {
|
|
141
|
+
const between = rowStartBr.nextSibling;
|
|
142
|
+
if (between !== rowEndBr && between?.nodeType === 3 && dom.check.isZeroWidth(between)) {
|
|
143
|
+
dom.utils.removeItem(between);
|
|
144
|
+
}
|
|
145
|
+
const anchor = rowStartBr.previousSibling;
|
|
146
|
+
dom.utils.removeItem(rowStartBr);
|
|
147
|
+
|
|
148
|
+
if (anchor && anchor.nodeType === 3) {
|
|
149
|
+
ports.selection.setRange(anchor, anchor.textContent.length, anchor, anchor.textContent.length);
|
|
150
|
+
} else if (dom.check.isBreak(anchor)) {
|
|
151
|
+
ports.selection.setRange(rowEndBr, 0, rowEndBr, 0);
|
|
152
|
+
} else {
|
|
153
|
+
const pre = rowEndBr.parentNode;
|
|
154
|
+
ports.selection.setRange(pre, 0, pre, 0);
|
|
114
155
|
}
|
|
115
156
|
},
|
|
116
157
|
|
|
@@ -125,7 +166,8 @@ export default {
|
|
|
125
166
|
dom.utils.removeItem(formatEl);
|
|
126
167
|
}
|
|
127
168
|
|
|
128
|
-
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
169
|
+
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
170
|
+
ports.focusManager.blur();
|
|
129
171
|
},
|
|
130
172
|
|
|
131
173
|
/** @action deleteComponentSelectNext */
|
|
@@ -146,7 +188,8 @@ export default {
|
|
|
146
188
|
const fileComponentInfo = ports.component.get(nextEl);
|
|
147
189
|
if (fileComponentInfo) {
|
|
148
190
|
ctx.e.stopPropagation();
|
|
149
|
-
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
191
|
+
if (ports.component.select(fileComponentInfo.target, fileComponentInfo.pluginName) === false)
|
|
192
|
+
ports.focusManager.blur();
|
|
150
193
|
} else if (ports.component.is(nextEl)) {
|
|
151
194
|
ctx.e.stopPropagation();
|
|
152
195
|
dom.utils.removeItem(nextEl);
|
|
@@ -157,7 +200,11 @@ export default {
|
|
|
157
200
|
'delete.list.removeNested': ({ ports, ctx }, { range, formatEl, rangeEl }) => {
|
|
158
201
|
if (range.startContainer !== range.endContainer) ports.html.remove();
|
|
159
202
|
|
|
160
|
-
const next = /** @type {HTMLElement} */ (
|
|
203
|
+
const next = /** @type {HTMLElement} */ (
|
|
204
|
+
dom.utils.arrayFind(formatEl.children, dom.check.isList) ||
|
|
205
|
+
formatEl.nextElementSibling ||
|
|
206
|
+
rangeEl.parentElement.nextElementSibling
|
|
207
|
+
);
|
|
161
208
|
if (next && (dom.check.isList(next) || dom.utils.arrayFind(next.children, dom.check.isList))) {
|
|
162
209
|
ctx.e.preventDefault();
|
|
163
210
|
|
|
@@ -184,6 +231,27 @@ export default {
|
|
|
184
231
|
}
|
|
185
232
|
},
|
|
186
233
|
|
|
234
|
+
/** @action deleteEmptyLineMergeNext — remove an empty line, move caret to the start of the next line */
|
|
235
|
+
'delete.emptyLine.mergeNext': ({ ports }, { formatEl, next }) => {
|
|
236
|
+
dom.utils.removeItem(formatEl);
|
|
237
|
+
caretToLineEdge(ports, next, false);
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
/** @action deleteBrLineRowMerge — remove an empty row inside a brLine (PRE), pull the next row up */
|
|
241
|
+
'delete.brline.rowMerge': ({ ports }, { rowEndBr }) => {
|
|
242
|
+
let next = rowEndBr.nextSibling;
|
|
243
|
+
if (next?.nodeType === 3 && dom.check.isZeroWidth(next)) next = next.nextSibling; // skip a trailing zero-width
|
|
244
|
+
const pre = rowEndBr.parentNode;
|
|
245
|
+
dom.utils.removeItem(rowEndBr);
|
|
246
|
+
|
|
247
|
+
// caret → start of the pulled-up row
|
|
248
|
+
if (next && (next.nodeType === 3 || dom.check.isBreak(next))) {
|
|
249
|
+
ports.selection.setRange(next, 0, next, 0);
|
|
250
|
+
} else {
|
|
251
|
+
ports.selection.setRange(pre, pre.childNodes.length, pre, pre.childNodes.length);
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
|
|
187
255
|
/** [tab] */
|
|
188
256
|
|
|
189
257
|
/** @action tabFormatIndent */
|
|
@@ -224,8 +292,15 @@ export default {
|
|
|
224
292
|
if (lines.length === 1) {
|
|
225
293
|
let tabSize = ctx.store.get('tabSize') + 1;
|
|
226
294
|
if (ctx.options.get('syncTabIndent')) {
|
|
227
|
-
const baseIndex = dom.query.findTextIndexOnLine(
|
|
228
|
-
|
|
295
|
+
const baseIndex = dom.query.findTextIndexOnLine(
|
|
296
|
+
formatEl,
|
|
297
|
+
range.startContainer,
|
|
298
|
+
range.startOffset,
|
|
299
|
+
(current) => ports.component.is(current),
|
|
300
|
+
);
|
|
301
|
+
const prevTabEndIndex = ports.format.isLine(formatEl.previousElementSibling)
|
|
302
|
+
? dom.query.findTabEndIndex(formatEl.previousElementSibling, baseIndex, 2)
|
|
303
|
+
: 0;
|
|
229
304
|
if (prevTabEndIndex > baseIndex) {
|
|
230
305
|
tabSize = prevTabEndIndex - baseIndex;
|
|
231
306
|
}
|
|
@@ -309,16 +384,10 @@ export default {
|
|
|
309
384
|
},
|
|
310
385
|
|
|
311
386
|
/** @action enterLineAddDefault */
|
|
312
|
-
'enter.line.addDefault': ({ ports
|
|
313
|
-
const newFormat = ports.format.
|
|
387
|
+
'enter.line.addDefault': ({ ports }, { formatEl }) => {
|
|
388
|
+
const newFormat = ports.format.addLineAfter(formatEl);
|
|
314
389
|
const temp = newFormat.firstChild;
|
|
315
|
-
|
|
316
|
-
const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
317
|
-
temp.parentNode.insertBefore(zeroWidth, temp);
|
|
318
|
-
ports.selection.setRange(zeroWidth, 1, zeroWidth, 1);
|
|
319
|
-
} else {
|
|
320
|
-
ports.selection.setRange(temp, 0, temp, 0);
|
|
321
|
-
}
|
|
390
|
+
ports.selection.setRange(temp, 0, temp, 0);
|
|
322
391
|
},
|
|
323
392
|
|
|
324
393
|
/** @action enterListAddItem */
|
|
@@ -359,7 +428,12 @@ export default {
|
|
|
359
428
|
}
|
|
360
429
|
|
|
361
430
|
newEl = dom.utils.createElement(newFormat);
|
|
362
|
-
const edge = ports.format.removeBlock(rangeEl, {
|
|
431
|
+
const edge = ports.format.removeBlock(rangeEl, {
|
|
432
|
+
selectedFormats: [formatEl],
|
|
433
|
+
newBlockElement: null,
|
|
434
|
+
shouldDelete: true,
|
|
435
|
+
skipHistory: true,
|
|
436
|
+
});
|
|
363
437
|
edge.cc.insertBefore(newEl, edge.ec);
|
|
364
438
|
}
|
|
365
439
|
|
|
@@ -380,7 +454,12 @@ export default {
|
|
|
380
454
|
|
|
381
455
|
/** @action enterFormatInsertBrHtml */
|
|
382
456
|
'enter.format.insertBrHtml': ({ ports }, { brBlock, range, wSelection, offset }) => {
|
|
383
|
-
ports.html.insert(
|
|
457
|
+
ports.html.insert(
|
|
458
|
+
range.collapsed && dom.check.isBreak(range.startContainer.childNodes[range.startOffset - 1])
|
|
459
|
+
? '<br>'
|
|
460
|
+
: '<br><br>',
|
|
461
|
+
{ selectInserted: false, skipCharCount: true, skipCleaning: true },
|
|
462
|
+
);
|
|
384
463
|
|
|
385
464
|
let focusNode = wSelection.focusNode;
|
|
386
465
|
const wOffset = wSelection.focusOffset;
|
|
@@ -392,6 +471,34 @@ export default {
|
|
|
392
471
|
ports.setOnShortcutKey(true);
|
|
393
472
|
},
|
|
394
473
|
|
|
474
|
+
/** @action enterBrLineInsert — insert exactly one empty row at the caret inside a normal brLine. */
|
|
475
|
+
'enter.brline.insert': ({ ports }, { range }) => {
|
|
476
|
+
// Restore the caret captured at rule time (enterPrevent may have moved the live selection).
|
|
477
|
+
ports.selection.setRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
|
|
478
|
+
if (!range.collapsed) ports.html.remove();
|
|
479
|
+
|
|
480
|
+
const br = dom.utils.createElement('BR');
|
|
481
|
+
ports.html.insertNode(br, { afterNode: null, skipCharCount: true });
|
|
482
|
+
|
|
483
|
+
if (!br.nextSibling) br.parentNode.appendChild(dom.utils.createElement('BR'));
|
|
484
|
+
const lower = br.nextSibling;
|
|
485
|
+
ports.selection.setRange(lower, 0, lower, 0);
|
|
486
|
+
ports.setOnShortcutKey(true);
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
/** @action enterBrLineExit — consume only the caret's current (last) empty row and add a default line after the brLine. */
|
|
490
|
+
'enter.brline.exit': ({ ports }, { brBlock }) => {
|
|
491
|
+
const last = brBlock.lastChild;
|
|
492
|
+
if (last && (dom.check.isBreak(last) || dom.check.isZeroWidth(last.textContent))) {
|
|
493
|
+
dom.utils.removeItem(last);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const brBlockNext = /** @type {HTMLElement} */ (brBlock).nextElementSibling;
|
|
497
|
+
const newEl = ports.format.addLine(brBlock, ports.format.isLine(brBlockNext) ? brBlockNext : null);
|
|
498
|
+
dom.utils.copyFormatAttributes(newEl, brBlock);
|
|
499
|
+
ports.selection.setRange(newEl, 1, newEl, 1);
|
|
500
|
+
},
|
|
501
|
+
|
|
395
502
|
/** @action enterFormatInsertBrNode */
|
|
396
503
|
'enter.format.insertBrNode': ({ ports }, { wSelection }) => {
|
|
397
504
|
const focusNext = wSelection.focusNode.nextSibling;
|
|
@@ -411,7 +518,10 @@ export default {
|
|
|
411
518
|
},
|
|
412
519
|
|
|
413
520
|
/** @action enterFormatBreakAtEdge */
|
|
414
|
-
'enter.format.breakAtEdge': (
|
|
521
|
+
'enter.format.breakAtEdge': (
|
|
522
|
+
{ ports, ctx },
|
|
523
|
+
{ formatEl, selectionNode, formatStartEdge, formatEndEdge, bidiSwapped },
|
|
524
|
+
) => {
|
|
415
525
|
const focusBR = dom.utils.createElement('BR');
|
|
416
526
|
const newFormat = dom.utils.createElement(formatEl.nodeName, null, focusBR);
|
|
417
527
|
|
|
@@ -429,7 +539,10 @@ export default {
|
|
|
429
539
|
} while (formatEl !== sNode && formatEl.contains(sNode));
|
|
430
540
|
|
|
431
541
|
newFormat.appendChild(child);
|
|
432
|
-
formatEl.parentNode.insertBefore(
|
|
542
|
+
formatEl.parentNode.insertBefore(
|
|
543
|
+
newFormat,
|
|
544
|
+
formatStartEdge && !formatEndEdge ? formatEl : formatEl.nextElementSibling,
|
|
545
|
+
);
|
|
433
546
|
if (formatEndEdge) {
|
|
434
547
|
ports.selection.setRange(focusBR, 1, focusBR, 1);
|
|
435
548
|
} else if (bidiSwapped) {
|
|
@@ -442,13 +555,19 @@ export default {
|
|
|
442
555
|
|
|
443
556
|
/** @action enterFormatBreakWithSelection */
|
|
444
557
|
'enter.format.breakWithSelection': ({ ports, ctx }, { formatEl, range, formatStartEdge, formatEndEdge }) => {
|
|
445
|
-
const isMultiLine =
|
|
558
|
+
const isMultiLine =
|
|
559
|
+
ports.format.getLine(range.startContainer, null) !== ports.format.getLine(range.endContainer, null);
|
|
446
560
|
const newFormat = /** @type {HTMLElement} */ (formatEl.cloneNode(false));
|
|
447
561
|
newFormat.innerHTML = '<br>';
|
|
448
562
|
const commonCon = /** @type {HTMLElement} */ (range.commonAncestorContainer);
|
|
449
563
|
const rcon =
|
|
450
564
|
commonCon === range.startContainer && commonCon === range.endContainer && dom.check.isZeroWidth(commonCon)
|
|
451
|
-
? {
|
|
565
|
+
? {
|
|
566
|
+
container: commonCon,
|
|
567
|
+
offset: range.endOffset,
|
|
568
|
+
prevContainer: commonCon.previousElementSibling,
|
|
569
|
+
commonCon: commonCon,
|
|
570
|
+
}
|
|
452
571
|
: ports.html.remove();
|
|
453
572
|
|
|
454
573
|
let newEl = ports.format.getLine(rcon.container, null);
|
|
@@ -467,26 +586,29 @@ export default {
|
|
|
467
586
|
}
|
|
468
587
|
|
|
469
588
|
const innerRange = ports.format.getBlock(rcon.container);
|
|
470
|
-
newEl = newEl.contains(innerRange)
|
|
589
|
+
newEl = newEl.contains(innerRange)
|
|
590
|
+
? dom.query.getEdgeChild(innerRange, (current) => Boolean(ports.format.getLine(current)), false)
|
|
591
|
+
: newEl;
|
|
471
592
|
if (isMultiLine) {
|
|
472
593
|
if (formatEndEdge && !formatStartEdge) {
|
|
473
|
-
newEl.parentNode.insertBefore(
|
|
594
|
+
newEl.parentNode.insertBefore(
|
|
595
|
+
newFormat,
|
|
596
|
+
!rcon.prevContainer || rcon.container === rcon.prevContainer ? newEl.nextElementSibling : newEl,
|
|
597
|
+
);
|
|
474
598
|
newEl = newFormat;
|
|
475
599
|
offset = 0;
|
|
476
600
|
} else {
|
|
477
601
|
offset = rcon.offset;
|
|
478
602
|
if (formatStartEdge) {
|
|
479
|
-
|
|
603
|
+
newEl.parentNode.insertBefore(newFormat, newEl);
|
|
480
604
|
if (formatEndEdge) {
|
|
481
|
-
newEl = tempEl;
|
|
482
605
|
offset = 0;
|
|
483
606
|
}
|
|
484
607
|
}
|
|
485
608
|
}
|
|
486
609
|
} else {
|
|
487
610
|
if (formatEndEdge && formatStartEdge) {
|
|
488
|
-
newEl.parentNode.insertBefore(newFormat,
|
|
489
|
-
newEl = newFormat;
|
|
611
|
+
newEl.parentNode.insertBefore(newFormat, newEl);
|
|
490
612
|
offset = 0;
|
|
491
613
|
} else if (formatEndEdge) {
|
|
492
614
|
newEl = newEl.parentNode.insertBefore(newFormat, newEl.nextElementSibling);
|
|
@@ -526,7 +648,10 @@ export default {
|
|
|
526
648
|
/** [keydown reducer] */
|
|
527
649
|
/** @action keydownInputInsertNbsp */
|
|
528
650
|
'keydown.input.insertNbsp': ({ ports }) => {
|
|
529
|
-
const nbsp = ports.html.insertNode(dom.utils.createTextNode('\u00a0'), {
|
|
651
|
+
const nbsp = ports.html.insertNode(dom.utils.createTextNode('\u00a0'), {
|
|
652
|
+
afterNode: null,
|
|
653
|
+
skipCharCount: true,
|
|
654
|
+
});
|
|
530
655
|
if (nbsp) {
|
|
531
656
|
ports.selection.setRange(nbsp, nbsp.length, nbsp, nbsp.length);
|
|
532
657
|
}
|
|
@@ -540,6 +665,17 @@ export default {
|
|
|
540
665
|
},
|
|
541
666
|
};
|
|
542
667
|
|
|
668
|
+
/**
|
|
669
|
+
* Place a collapsed caret at the start or end of a line after an empty line is removed.
|
|
670
|
+
* @param {import('../ports').EventReducerPorts} ports - Ports for interacting with editor
|
|
671
|
+
* @param {Element} line - The destination line element
|
|
672
|
+
* @param {boolean} toEnd - true → caret at the line end (backspace), false → line start (delete)
|
|
673
|
+
*/
|
|
674
|
+
function caretToLineEdge(ports, line, toEnd) {
|
|
675
|
+
const offset = toEnd ? line.childNodes.length : 0;
|
|
676
|
+
ports.selection.setRange(line, offset, line, offset);
|
|
677
|
+
}
|
|
678
|
+
|
|
543
679
|
/**
|
|
544
680
|
* @param {HTMLElement} formatEl - Format element
|
|
545
681
|
* @returns {Node}
|
|
@@ -35,8 +35,14 @@ function hardDelete(ports) {
|
|
|
35
35
|
const eCell = ports.format.getBlock(ec);
|
|
36
36
|
const sIsCell = dom.check.isTableCell(sCell);
|
|
37
37
|
const eIsCell = dom.check.isTableCell(eCell);
|
|
38
|
-
if (
|
|
39
|
-
|
|
38
|
+
if (
|
|
39
|
+
((sIsCell && !sCell.previousElementSibling && !sCell.parentElement.previousElementSibling) ||
|
|
40
|
+
(eIsCell && !eCell.nextElementSibling && !eCell.parentElement.nextElementSibling)) &&
|
|
41
|
+
sCell !== eCell
|
|
42
|
+
) {
|
|
43
|
+
const ancestor =
|
|
44
|
+
dom.query.getParentElement(range.commonAncestorContainer, dom.check.isFigure)?.parentElement ||
|
|
45
|
+
range.commonAncestorContainer;
|
|
40
46
|
if (!sIsCell) {
|
|
41
47
|
dom.utils.removeItem(dom.query.getParentElement(eCell, (current) => ancestor === current.parentNode));
|
|
42
48
|
} else if (!eIsCell) {
|
|
@@ -104,11 +110,18 @@ function isUneditableNode(ports, range, isFront) {
|
|
|
104
110
|
|
|
105
111
|
let siblingNode;
|
|
106
112
|
if (isElement) {
|
|
107
|
-
siblingNode = /** @type {HTMLElement} */ (
|
|
113
|
+
siblingNode = /** @type {HTMLElement} */ (
|
|
114
|
+
_isUneditableNode_getSibling(ports, container.childNodes[offset], siblingKey, container)
|
|
115
|
+
);
|
|
108
116
|
return dom.check.isComponentContainer(siblingNode) || dom.check.isNonEditable(siblingNode) ? siblingNode : null;
|
|
109
117
|
} else {
|
|
110
|
-
siblingNode = /** @type {HTMLElement} */ (
|
|
111
|
-
|
|
118
|
+
siblingNode = /** @type {HTMLElement} */ (
|
|
119
|
+
_isUneditableNode_getSibling(ports, container, siblingKey, container)
|
|
120
|
+
);
|
|
121
|
+
return dom.check.isEdgePoint(container, offset, isFront ? 'front' : 'end') &&
|
|
122
|
+
(dom.check.isComponentContainer(siblingNode) || dom.check.isNonEditable(siblingNode))
|
|
123
|
+
? siblingNode
|
|
124
|
+
: null;
|
|
112
125
|
}
|
|
113
126
|
}
|
|
114
127
|
|
|
@@ -128,7 +141,8 @@ function _isUneditableNode_getSibling(ports, selectNode, siblingKey, container)
|
|
|
128
141
|
if (!siblingNode) {
|
|
129
142
|
siblingNode = ports.format.getLine(container);
|
|
130
143
|
siblingNode = siblingNode ? siblingNode[siblingKey] : null;
|
|
131
|
-
if (siblingNode && !ports.component.is(siblingNode))
|
|
144
|
+
if (siblingNode && !ports.component.is(siblingNode))
|
|
145
|
+
siblingNode = siblingKey === 'previousSibling' ? siblingNode.firstChild : siblingNode.lastChild;
|
|
132
146
|
else return null;
|
|
133
147
|
}
|
|
134
148
|
|