suneditor 3.0.0-beta.26 → 3.0.0-beta.28

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.
Files changed (135) hide show
  1. package/dist/suneditor.min.css +1 -1
  2. package/dist/suneditor.min.js +1 -1
  3. package/package.json +77 -39
  4. package/src/core/{section → base}/actives.js +1 -1
  5. package/src/core/class/component.js +2 -0
  6. package/src/core/class/format.js +44 -2435
  7. package/src/core/class/html.js +5 -4
  8. package/src/core/class/inline.js +1853 -0
  9. package/src/core/class/listFormat.js +582 -0
  10. package/src/core/class/nodeTransform.js +1 -3
  11. package/src/core/class/selection.js +4 -2
  12. package/src/core/class/ui.js +1 -1
  13. package/src/core/class/viewer.js +4 -4
  14. package/src/core/config/options.js +37 -18
  15. package/src/core/editor.js +43 -29
  16. package/src/core/event/actions/index.js +229 -0
  17. package/src/core/event/effects/common.registry.js +60 -0
  18. package/src/core/event/effects/keydown.registry.js +551 -0
  19. package/src/core/event/effects/ruleHelpers.js +145 -0
  20. package/src/core/{base → event}/eventManager.js +8 -124
  21. package/src/core/event/executor.js +21 -0
  22. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +1 -1
  23. package/src/core/event/handlers/handler_ww_input.js +77 -0
  24. package/src/core/event/handlers/handler_ww_key.js +228 -0
  25. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
  26. package/src/core/event/ports.js +211 -0
  27. package/src/core/event/reducers/keydown.reducer.js +89 -0
  28. package/src/core/event/rules/keydown.rule.arrow.js +54 -0
  29. package/src/core/event/rules/keydown.rule.backspace.js +202 -0
  30. package/src/core/event/rules/keydown.rule.delete.js +126 -0
  31. package/src/core/event/rules/keydown.rule.enter.js +144 -0
  32. package/src/core/event/rules/keydown.rule.tab.js +29 -0
  33. package/src/core/section/constructor.js +57 -23
  34. package/src/editorInjector/_classes.js +4 -0
  35. package/src/editorInjector/index.js +4 -0
  36. package/src/helper/clipboard.js +0 -1
  37. package/src/helper/converter.js +6 -7
  38. package/src/helper/dom/domCheck.js +1 -1
  39. package/src/helper/dom/domQuery.js +1 -1
  40. package/src/helper/dom/domUtils.js +2 -2
  41. package/src/helper/dom/index.js +4 -0
  42. package/src/helper/env.js +1 -6
  43. package/src/helper/keyCodeMap.js +0 -1
  44. package/src/langs/ckb.js +1 -1
  45. package/src/langs/cs.js +1 -1
  46. package/src/langs/da.js +1 -1
  47. package/src/langs/de.js +1 -1
  48. package/src/langs/en.js +1 -1
  49. package/src/langs/es.js +1 -1
  50. package/src/langs/fa.js +1 -1
  51. package/src/langs/fr.js +1 -1
  52. package/src/langs/he.js +1 -1
  53. package/src/langs/hu.js +1 -1
  54. package/src/langs/it.js +1 -1
  55. package/src/langs/ja.js +1 -1
  56. package/src/langs/km.js +1 -1
  57. package/src/langs/ko.js +1 -1
  58. package/src/langs/lv.js +1 -1
  59. package/src/langs/nl.js +1 -1
  60. package/src/langs/pl.js +1 -1
  61. package/src/langs/pt_br.js +1 -1
  62. package/src/langs/ro.js +1 -1
  63. package/src/langs/ru.js +1 -1
  64. package/src/langs/se.js +1 -1
  65. package/src/langs/tr.js +1 -1
  66. package/src/langs/uk.js +1 -1
  67. package/src/langs/ur.js +1 -1
  68. package/src/langs/zh_cn.js +1 -1
  69. package/src/modules/ApiManager.js +5 -0
  70. package/src/modules/Figure.js +4 -10
  71. package/src/modules/HueSlider.js +18 -4
  72. package/src/modules/SelectMenu.js +1 -1
  73. package/src/plugins/command/fileUpload.js +1 -1
  74. package/src/plugins/command/list_bulleted.js +1 -1
  75. package/src/plugins/command/list_numbered.js +1 -1
  76. package/src/plugins/dropdown/backgroundColor.js +2 -2
  77. package/src/plugins/dropdown/font.js +2 -2
  78. package/src/plugins/dropdown/fontColor.js +2 -2
  79. package/src/plugins/dropdown/list.js +1 -1
  80. package/src/plugins/dropdown/table.js +1 -3
  81. package/src/plugins/dropdown/textStyle.js +1 -1
  82. package/src/plugins/field/mention.js +2 -2
  83. package/src/plugins/input/fontSize.js +9 -9
  84. package/src/plugins/modal/audio.js +5 -5
  85. package/src/plugins/modal/embed.js +5 -5
  86. package/src/plugins/modal/image.js +7 -7
  87. package/src/plugins/modal/link.js +23 -8
  88. package/src/plugins/modal/video.js +5 -5
  89. package/src/suneditor.js +9 -34
  90. package/src/typedef.js +15 -9
  91. package/types/core/class/format.d.ts +2 -352
  92. package/types/core/class/html.d.ts +2 -2
  93. package/types/core/class/inline.d.ts +263 -0
  94. package/types/core/class/listFormat.d.ts +135 -0
  95. package/types/core/config/options.d.ts +52 -78
  96. package/types/core/editor.d.ts +22 -12
  97. package/types/core/event/actions/index.d.ts +47 -0
  98. package/types/core/event/effects/common.registry.d.ts +50 -0
  99. package/types/core/event/effects/keydown.registry.d.ts +73 -0
  100. package/types/core/event/effects/ruleHelpers.d.ts +31 -0
  101. package/types/core/{base → event}/eventManager.d.ts +0 -42
  102. package/types/core/event/executor.d.ts +6 -0
  103. package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
  104. package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -33
  105. package/types/core/event/ports.d.ts +255 -0
  106. package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
  107. package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
  108. package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
  109. package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
  110. package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
  111. package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
  112. package/types/core/section/constructor.d.ts +165 -39
  113. package/types/editorInjector/_classes.d.ts +4 -0
  114. package/types/editorInjector/index.d.ts +4 -0
  115. package/types/helper/converter.d.ts +4 -20
  116. package/types/helper/dom/index.d.ts +86 -1
  117. package/types/index.d.ts +11 -121
  118. package/types/langs/index.d.ts +2 -2
  119. package/types/modules/HueSlider.d.ts +12 -0
  120. package/types/modules/index.d.ts +3 -3
  121. package/types/plugins/index.d.ts +38 -38
  122. package/types/plugins/modal/link.d.ts +6 -4
  123. package/types/suneditor.d.ts +18 -19
  124. package/types/typedef.d.ts +6 -2
  125. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1267
  126. package/types/core/section/context.d.ts +0 -67
  127. package/types/core/section/options.d.ts +0 -1022
  128. package/types/langs/_Lang.d.ts +0 -194
  129. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
  130. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +0 -0
  131. /package/types/core/{section → base}/actives.d.ts +0 -0
  132. /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
  133. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
  134. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
  135. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.d.ts +0 -0
@@ -0,0 +1,211 @@
1
+ import { isMobile } from '../../helper/env';
2
+
3
+ /**
4
+ * @typedef {import('./eventManager').EventManagerThis} EventManagerInstanceType
5
+ */
6
+
7
+ /**
8
+ * @typedef {import('../class/selection').default} Selection
9
+ * @typedef {import('../class/format').default} Format
10
+ * @typedef {import('../class/listFormat').default} ListFormat
11
+ * @typedef {import('../class/component').default} Component
12
+ * @typedef {import('../class/html').default} Html
13
+ * @typedef {import('../class/nodeTransform').default} NodeTransform
14
+ * @typedef {import('../class/char').default} Char
15
+ * @typedef {import('../class/menu').default} Menu
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} SelectionPorts
20
+ * @property {(...args: Parameters<Selection['getRange']>) => ReturnType<Selection['getRange']>} getRange
21
+ * @property {(...args: Parameters<Selection['getNode']>) => ReturnType<Selection['getNode']>} getNode
22
+ * @property {(...args: Parameters<Selection['setRange']>) => ReturnType<Selection['setRange']>} setRange
23
+ * @property {(...args: Parameters<Selection['get']>) => ReturnType<Selection['get']>} get
24
+ */
25
+
26
+ /**
27
+ * @typedef {Object} FormatPorts
28
+ * @property {(...args: Parameters<Format['isLine']>) => ReturnType<Format['isLine']>} isLine
29
+ * @property {(...args: Parameters<Format['getLine']>) => ReturnType<Format['getLine']>} getLine
30
+ * @property {(...args: Parameters<Format['getLines']>) => ReturnType<Format['getLines']>} getLines
31
+ * @property {(...args: Parameters<Format['getBrLine']>) => ReturnType<Format['getBrLine']>} getBrLine
32
+ * @property {(...args: Parameters<Format['getBlock']>) => ReturnType<Format['getBlock']>} getBlock
33
+ * @property {(...args: Parameters<Format['isNormalLine']>) => ReturnType<Format['isNormalLine']>} isNormalLine
34
+ * @property {(...args: Parameters<Format['isBrLine']>) => ReturnType<Format['isBrLine']>} isBrLine
35
+ * @property {(...args: Parameters<Format['isClosureBrLine']>) => ReturnType<Format['isClosureBrLine']>} isClosureBrLine
36
+ * @property {(...args: Parameters<Format['isClosureBlock']>) => ReturnType<Format['isClosureBlock']>} isClosureBlock
37
+ * @property {(...args: Parameters<Format['isEdgeLine']>) => ReturnType<Format['isEdgeLine']>} isEdgeLine
38
+ * @property {(...args: Parameters<Format['removeBlock']>) => ReturnType<Format['removeBlock']>} removeBlock
39
+ * @property {(...args: Parameters<Format['addLine']>) => ReturnType<Format['addLine']>} addLine
40
+ */
41
+
42
+ /**
43
+ * @typedef {Object} ListFormatPorts
44
+ * @property {(...args: Parameters<ListFormat['applyNested']>) => ReturnType<ListFormat['applyNested']>} applyNested
45
+ */
46
+
47
+ /**
48
+ * @typedef {Object} ComponentPorts
49
+ * @property {(...args: Parameters<Component['deselect']>) => ReturnType<Component['deselect']>} deselect
50
+ * @property {(...args: Parameters<Component['is']>) => ReturnType<Component['is']>} is
51
+ * @property {(...args: Parameters<Component['get']>) => ReturnType<Component['get']>} get
52
+ * @property {(...args: Parameters<Component['select']>) => ReturnType<Component['select']>} select
53
+ */
54
+
55
+ /**
56
+ * @typedef {Object} HtmlPorts
57
+ * @property {(...args: Parameters<Html['remove']>) => ReturnType<Html['remove']>} remove
58
+ * @property {(...args: Parameters<Html['insert']>) => ReturnType<Html['insert']>} insert
59
+ * @property {(...args: Parameters<Html['insertNode']>) => ReturnType<Html['insertNode']>} insertNode
60
+ */
61
+
62
+ /**
63
+ * @typedef {Object} NodeTransformPorts
64
+ * @property {(...args: Parameters<NodeTransform['removeAllParents']>) => ReturnType<NodeTransform['removeAllParents']>} removeAllParents
65
+ * @property {(...args: Parameters<NodeTransform['split']>) => ReturnType<NodeTransform['split']>} split
66
+ */
67
+
68
+ /**
69
+ * @typedef {Object} CharPorts
70
+ * @property {(...args: Parameters<Char['check']>) => ReturnType<Char['check']>} check
71
+ */
72
+
73
+ /**
74
+ * @typedef {Object} MenuPorts
75
+ * @property {(...args: Parameters<Menu['dropdownOff']>) => ReturnType<Menu['dropdownOff']>} dropdownOff
76
+ */
77
+
78
+ /**
79
+ * @description Create ports for event reducers
80
+ * @param {EventManagerInstanceType} inst - EventManager instance
81
+ * @param {Object} param1 - Additional parameters
82
+ * @param {*} param1._styleNodes - Style nodes reference object
83
+ */
84
+ export function makePorts(inst, { _styleNodes }) {
85
+ const { selection, format, listFormat, component, html, nodeTransform, history, char, menu } = inst;
86
+
87
+ return {
88
+ // editor
89
+ editor: {
90
+ _nativeFocus: () => inst.editor._nativeFocus(),
91
+ blur: () => inst.editor.blur()
92
+ },
93
+
94
+ // === class ===
95
+ selection: {
96
+ getRange: () => selection.getRange(),
97
+ getNode: () => selection.getNode(),
98
+ setRange: (se, so, ec, eo) => selection.setRange(se, so, ec, eo),
99
+ get: () => selection.get()
100
+ },
101
+
102
+ format: {
103
+ isLine: (n) => format.isLine(n),
104
+ getLine: (n, p) => format.getLine(n, p),
105
+ getLines: (v) => format.getLines(v),
106
+ getBrLine: (n, p) => format.getBrLine(n, p),
107
+ getBlock: (n, p) => format.getBlock(n, p),
108
+ isNormalLine: (n) => format.isNormalLine(n),
109
+ isBrLine: (n) => format.isBrLine(n),
110
+ isClosureBrLine: (n) => format.isClosureBrLine(n),
111
+ isClosureBlock: (n) => format.isClosureBlock(n),
112
+ isEdgeLine: (node, offset, dir) => format.isEdgeLine(node, offset, dir),
113
+ removeBlock: (n, p) => format.removeBlock(n, p),
114
+ addLine: (el, nextOrTag) => format.addLine(el, nextOrTag)
115
+ },
116
+
117
+ listFormat: {
118
+ applyNested: (cells, shift) => listFormat.applyNested(cells, shift)
119
+ },
120
+
121
+ component: {
122
+ deselect: () => component.deselect(),
123
+ is: (n) => component.is(n),
124
+ get: (n) => component.get(n),
125
+ select: (t, p) => component.select(t, p)
126
+ },
127
+
128
+ html: {
129
+ remove: () => html.remove(),
130
+ insert: (h, p) => html.insert(h, p),
131
+ insertNode: (n, p) => html.insertNode(n, p)
132
+ },
133
+
134
+ history: {
135
+ push: (hard) => history.push(!!hard)
136
+ },
137
+
138
+ nodeTransform: {
139
+ removeAllParents: (s, n, p) => nodeTransform.removeAllParents(s, n, p),
140
+ split: (n, o, d) => nodeTransform.split(n, o, d)
141
+ },
142
+
143
+ char: {
144
+ check: (content) => char.check(content)
145
+ },
146
+
147
+ menu: {
148
+ dropdownOff: () => menu.dropdownOff()
149
+ },
150
+
151
+ // === inst(eventManager) commands ===
152
+ setDefaultLine: (tag) => inst._setDefaultLine(tag),
153
+ hideToolbar: () => inst._hideToolbar(),
154
+ hideToolbar_sub: () => inst._hideToolbar_sub(),
155
+ styleNodeCache: () => (_styleNodes.value = inst.__cacheStyleNodes),
156
+ formatAttrsTempCache: (attrs) => (inst._formatAttrsTemp = attrs),
157
+ setOnShortcutKey: (v) => (inst._onShortcutKey = v),
158
+
159
+ // === enter event specific ===
160
+ /**
161
+ * @description Scrolls the editor view to the caret position after pressing Enter. (Ignored on mobile devices)
162
+ * @param {Range} range Range object
163
+ */
164
+ enterScrollTo(range) {
165
+ inst.editor._iframeAutoHeight(inst.frameContext);
166
+
167
+ // scroll to
168
+ if (isMobile && inst.scrollparents.length > 0) return;
169
+ inst.selection.scrollTo(range, { behavior: 'auto', block: 'nearest', inline: 'nearest' });
170
+ },
171
+ /**
172
+ * @description Prevents the default behavior of the Enter key and refocuses the editor.
173
+ * @param {Event} e The keyboard event
174
+ */
175
+ enterPrevent(e) {
176
+ e.preventDefault();
177
+ if (!isMobile) return;
178
+
179
+ inst.__focusTemp.focus({ preventScroll: true });
180
+ inst.frameContext.get('wysiwyg').focus({ preventScroll: true });
181
+ }
182
+ };
183
+ }
184
+
185
+ /**
186
+ * @typedef {Object} EventReducerPorts
187
+ *
188
+ * @property {Object} editor
189
+ * @property {() => void} editor._nativeFocus
190
+ * @property {() => void} editor.blur
191
+ * @property {SelectionPorts} selection
192
+ * @property {FormatPorts} format
193
+ * @property {ListFormatPorts} listFormat
194
+ * @property {ComponentPorts} component
195
+ * @property {HtmlPorts} html
196
+ * @property {Object} history
197
+ * @property {(hard: boolean) => void} history.push
198
+ * @property {NodeTransformPorts} nodeTransform
199
+ * @property {CharPorts} char
200
+ * @property {MenuPorts} menu
201
+ *
202
+ * @property {(tag: string) => void} setDefaultLine
203
+ * @property {() => void} hideToolbar
204
+ * @property {() => void} hideToolbar_sub
205
+ * @property {() => void} styleNodeCache
206
+ * @property {(attrs: Object<string, *>) => void} formatAttrsTempCache
207
+ * @property {(v: boolean) => void} setOnShortcutKey
208
+ *
209
+ * @property {(e: Event) => void} enterPrevent
210
+ * @property {(range: Range) => void} enterScrollTo
211
+ */
@@ -0,0 +1,89 @@
1
+ import { env, dom, keyCodeMap } from '../../../helper';
2
+
3
+ import { reduceBackspaceDown } from '../rules/keydown.rule.backspace';
4
+ import { reduceDeleteDown } from '../rules/keydown.rule.delete';
5
+ import { reduceEnterDown } from '../rules/keydown.rule.enter';
6
+ import { reduceTabDown } from '../rules/keydown.rule.tab';
7
+ import { reduceArrowDown } from '../rules/keydown.rule.arrow';
8
+ import { A } from '../actions';
9
+
10
+ const { isOSX_IOS } = env;
11
+
12
+ /**
13
+ * @typedef {Object} KeydownReducerCtx - Keydown Reducer Context object
14
+ * @property {KeyboardEvent} ctx.e - The keyboard event
15
+ * @property {__se__FrameContext} ctx.fc - Frame context object
16
+ * @property {__se__EditorStatus} ctx.status - Editor status object
17
+ * @property {__se__BaseOptions} ctx.options - Options object
18
+ * @property {__se__FrameOptions} ctx.frameOptions - Frame options object
19
+ * @property {Range} ctx.range - Current selection range
20
+ * @property {HTMLElement|Text} ctx.selectionNode - Current selection node
21
+ * @property {HTMLElement} ctx.formatEl - Current format element
22
+ * @property {string} ctx.keyCode - Key code
23
+ * @property {boolean} ctx.ctrl - Whether the ctrl key is pressed
24
+ * @property {boolean} ctx.alt - Whether the alt key is pressed
25
+ * @property {boolean} ctx.shift - Whether the shift key is pressed
26
+ */
27
+
28
+ /**
29
+ * @description Keydown event reducer
30
+ * @param {__se__EventPorts} ports - Ports for interacting with editor
31
+ * @param {KeydownReducerCtx} ctx - Context object
32
+ * @returns {Promise<__se__EventActions>} Action list
33
+ */
34
+ export async function reduceKeydown(ports, ctx) {
35
+ const actions = [];
36
+
37
+ switch (ctx.keyCode) {
38
+ case 'Backspace' /** backspace key */: {
39
+ if (reduceBackspaceDown(actions, ports, ctx) === false) {
40
+ return actions;
41
+ }
42
+ break;
43
+ }
44
+ case 'Delete' /** delete key */: {
45
+ if (reduceDeleteDown(actions, ports, ctx) === false) {
46
+ return actions;
47
+ }
48
+ break;
49
+ }
50
+ case 'Tab' /** tab key */: {
51
+ if (reduceTabDown(actions, ports, ctx) === false) {
52
+ return actions;
53
+ }
54
+ break;
55
+ }
56
+ case 'Enter' /** enter key */: {
57
+ if (reduceEnterDown(actions, ports, ctx) === false) {
58
+ return actions;
59
+ }
60
+ break;
61
+ }
62
+ }
63
+
64
+ // ZWS, nbsp, documentType
65
+ const { fc, keyCode, shift, alt, ctrl, range } = ctx;
66
+
67
+ if (shift && (isOSX_IOS ? alt : ctrl) && keyCodeMap.isSpace(keyCode)) {
68
+ actions.push(A.preventStop());
69
+ actions.push(A.keydownInputInsertNbsp());
70
+ return actions;
71
+ }
72
+
73
+ const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
74
+ if (!ctrl && !alt && !selectRange && !keyCodeMap.isNonTextKey(keyCode) && dom.check.isBreak(range.commonAncestorContainer)) {
75
+ actions.push(A.keydownInputInsertZWS());
76
+ return actions;
77
+ }
78
+
79
+ // document type
80
+ if (fc.has('documentType_use_header') && selectRange && !ctrl && !alt && !shift && !keyCodeMap.isDirectionKey(keyCode)) {
81
+ actions.push(A.documentTypeRefreshHeader());
82
+ return actions;
83
+ }
84
+
85
+ // Arrow key - select component action
86
+ reduceArrowDown(actions, ports, ctx);
87
+
88
+ return actions;
89
+ }
@@ -0,0 +1,54 @@
1
+ import { dom } from '../../../helper';
2
+ import { A } from '../actions';
3
+
4
+ /**
5
+ * @this {void}
6
+ * @description Arrow key down rule
7
+ * @param {__se__EventActions} actions - Action list
8
+ * @param {__se__EventPorts} ports - Ports for interacting with editor
9
+ * @param {__se__EventKeydownCtx} ctx - Context object
10
+ */
11
+ export function reduceArrowDown(actions, ports, ctx) {
12
+ const { component } = ports;
13
+ const { formatEl, range, selectionNode, keyCode } = ctx;
14
+
15
+ // next component
16
+ let cmponentInfo = null;
17
+ switch (keyCode) {
18
+ case 'ArrowUp' /** up key */:
19
+ if (component.is(formatEl.previousElementSibling)) {
20
+ cmponentInfo = component.get(formatEl.previousElementSibling);
21
+ }
22
+ break;
23
+ case 'ArrowLeft' /** left key */:
24
+ if (dom.check.isEdgePoint(selectionNode, range.startOffset, 'front')) {
25
+ const prevEl = selectionNode.previousElementSibling || dom.query.getPreviousDeepestNode(selectionNode);
26
+ if (prevEl) {
27
+ if (component.is(prevEl)) cmponentInfo = component.get(prevEl);
28
+ } else if (component.is(formatEl.previousElementSibling)) {
29
+ cmponentInfo = component.get(formatEl.previousElementSibling);
30
+ }
31
+ }
32
+ break;
33
+ case 'ArrowDown' /** down key */:
34
+ if (component.is(formatEl.nextElementSibling)) {
35
+ cmponentInfo = component.get(formatEl.nextElementSibling);
36
+ }
37
+ break;
38
+ case 'ArrowRight' /** right key */:
39
+ if (dom.check.isEdgePoint(selectionNode, range.endOffset, 'end')) {
40
+ const nextEl = selectionNode.nextElementSibling || dom.query.getNextDeepestNode(selectionNode);
41
+ if (nextEl) {
42
+ if (component.is(nextEl)) cmponentInfo = component.get(nextEl);
43
+ } else if (component.is(formatEl.nextElementSibling)) {
44
+ cmponentInfo = component.get(formatEl.nextElementSibling);
45
+ }
46
+ }
47
+ break;
48
+ }
49
+
50
+ if (cmponentInfo && !cmponentInfo.options?.isInputComponent) {
51
+ actions.push(A.prevent());
52
+ actions.push(A.selectComponentFallback(cmponentInfo));
53
+ }
54
+ }
@@ -0,0 +1,202 @@
1
+ import { dom } from '../../../helper';
2
+ import { cleanRemovedTags, hardDelete, isUneditableNode, setDefaultLine } from '../effects/ruleHelpers';
3
+ import { A } from '../actions';
4
+
5
+ /**
6
+ * @this {void}
7
+ * @description Backspace key down rule
8
+ * @param {__se__EventActions} actions - Action list
9
+ * @param {__se__EventPorts} ports - Ports for interacting with editor
10
+ * @param {__se__EventKeydownCtx} ctx - Context object
11
+ * @returns {boolean} Return false to stop the processing
12
+ */
13
+ export function reduceBackspaceDown(actions, ports, ctx) {
14
+ const { format, component } = ports;
15
+ const { fc, options, range, selectionNode } = ctx;
16
+ let { formatEl } = ctx;
17
+
18
+ const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
19
+
20
+ actions.push(A.componentDeselect());
21
+ actions.push(A.cacheStyleNode());
22
+
23
+ if (selectRange && hardDelete(ports)) {
24
+ actions.push(A.preventStop());
25
+ return true;
26
+ }
27
+
28
+ if (!format.isNormalLine(formatEl) && !format.isBrLine(formatEl) && !fc.get('wysiwyg').firstElementChild && !component.is(selectionNode) && setDefaultLine(ports, options.get('defaultLine')) !== null) {
29
+ actions.push(A.preventStop());
30
+ return false;
31
+ }
32
+
33
+ // line delete
34
+ if (
35
+ format.isLine(formatEl) &&
36
+ selectRange &&
37
+ dom.check.isEdgePoint(range.startContainer, range.startOffset, 'front') &&
38
+ (!range.startContainer.previousSibling || dom.check.isZeroWidth(range.startContainer.previousSibling)) &&
39
+ format.getLine(range.startContainer) !== format.getLine(range.endContainer) &&
40
+ (format.isLine(formatEl.previousElementSibling) || dom.check.isListCell(formatEl))
41
+ ) {
42
+ actions.push(A.preventStop());
43
+ actions.push(A.delFormatRemoveAndMove(range.startContainer, formatEl));
44
+ actions.push(A.historyPush(true));
45
+ return false;
46
+ }
47
+
48
+ // closure, default
49
+ if (
50
+ !selectRange &&
51
+ !formatEl.previousElementSibling &&
52
+ range.startOffset === 0 &&
53
+ !selectionNode.previousSibling &&
54
+ !dom.check.isListCell(formatEl) &&
55
+ format.isLine(formatEl) &&
56
+ (!format.isBrLine(formatEl) || format.isClosureBrLine(formatEl))
57
+ ) {
58
+ // closure range
59
+ if (format.isClosureBlock(formatEl.parentNode)) {
60
+ actions.push(A.preventStop());
61
+ return false;
62
+ }
63
+
64
+ // maintain default format
65
+ if (dom.check.isWysiwygFrame(formatEl.parentNode) && formatEl.childNodes.length <= 1 && (!formatEl.firstChild || dom.check.isZeroWidth(formatEl.textContent))) {
66
+ actions.push(A.preventStop());
67
+ actions.push(A.backspaceFormatMaintain(formatEl));
68
+ }
69
+
70
+ actions.push(A.editorNativeFocus());
71
+ return false;
72
+ }
73
+
74
+ // clean remove tag
75
+ const startCon = range.startContainer;
76
+ if (formatEl && !formatEl.previousElementSibling && range.startOffset === 0 && startCon.nodeType === 3 && dom.check.isZeroWidth(startCon)) {
77
+ if (cleanRemovedTags(ports, startCon, formatEl) === true) return true;
78
+ }
79
+
80
+ // line component
81
+ if (!selectRange && formatEl && (range.startOffset === 0 || selectionNode === formatEl)) {
82
+ const sel =
83
+ selectionNode === formatEl
84
+ ? isUneditableNode(ports, range, true)
85
+ : dom.check.isElement(selectionNode.previousSibling)
86
+ ? selectionNode.previousSibling
87
+ : dom.check.isEdgePoint(range.startContainer, range.startOffset)
88
+ ? dom.query.getPreviousDeepestNode(range.startContainer)
89
+ : null;
90
+ if (component.is(sel)) {
91
+ const fileComponentInfo = component.get(sel);
92
+ if (fileComponentInfo) {
93
+ actions.push(A.preventStop());
94
+ actions.push(A.backspaceComponentSelect(selectionNode, range, fileComponentInfo));
95
+ return true;
96
+ }
97
+ }
98
+ }
99
+
100
+ // tag[contenteditable='false']
101
+ if (isUneditableNode(ports, range, true)) {
102
+ actions.push(A.preventStop());
103
+ return true;
104
+ }
105
+
106
+ // format attributes
107
+ if (!selectRange && format.isEdgeLine(range.startContainer, range.startOffset, 'front')) {
108
+ if (format.isLine(formatEl.previousElementSibling)) {
109
+ actions.push(A.cacheFormatAttrsTemp(formatEl.previousElementSibling.attributes));
110
+ }
111
+ }
112
+
113
+ // nested list
114
+ formatEl = format.getLine(range.startContainer, null);
115
+ const rangeEl = format.getBlock(formatEl, null);
116
+ const commonCon = range.commonAncestorContainer;
117
+ if (rangeEl && formatEl && !dom.check.isTableCell(rangeEl) && !/^FIGCAPTION$/i.test(rangeEl.nodeName)) {
118
+ if (
119
+ dom.check.isListCell(formatEl) &&
120
+ dom.check.isList(rangeEl) &&
121
+ (dom.check.isListCell(rangeEl.parentElement) || formatEl.previousElementSibling) &&
122
+ (selectionNode === formatEl || (selectionNode.nodeType === 3 && (!selectionNode.previousSibling || dom.check.isList(selectionNode.previousSibling)))) &&
123
+ (format.getLine(range.startContainer, null) !== format.getLine(range.endContainer, null) ? rangeEl.contains(range.startContainer) : range.startOffset === 0 && range.collapsed)
124
+ ) {
125
+ if (range.startContainer !== range.endContainer) {
126
+ actions.push(A.prevent());
127
+ actions.push(A.backspaceListRemoveNested(range));
128
+ actions.push(A.historyPush(true));
129
+ } else {
130
+ let prev = formatEl.previousElementSibling || rangeEl.parentElement;
131
+ if (dom.check.isListCell(prev)) {
132
+ actions.push(A.prevent());
133
+
134
+ let prevLast = prev;
135
+ if (!prev.contains(formatEl) && dom.check.isListCell(prevLast) && dom.check.isList(prevLast.lastElementChild)) {
136
+ prevLast = /** @type {HTMLLIElement} */ (prevLast.lastElementChild.lastElementChild);
137
+ while (dom.check.isListCell(prevLast) && dom.check.isList(prevLast.lastElementChild)) {
138
+ prevLast = /** @type {HTMLLIElement} */ (prevLast.lastElementChild && prevLast.lastElementChild.lastElementChild);
139
+ }
140
+ prev = prevLast;
141
+ }
142
+
143
+ actions.push(A.backspaceListMergePrev(prev, formatEl, rangeEl));
144
+ actions.push(A.historyPush(true));
145
+ }
146
+ }
147
+
148
+ return true;
149
+ }
150
+
151
+ // detach range
152
+ if (!selectRange && range.startOffset === 0) {
153
+ let detach = true;
154
+ let comm = commonCon;
155
+ while (comm && comm !== rangeEl && !dom.check.isWysiwygFrame(comm)) {
156
+ if (comm.previousSibling) {
157
+ if (comm.previousSibling.nodeType === 1 || !dom.check.isZeroWidth(comm.previousSibling.textContent.trim())) {
158
+ detach = false;
159
+ break;
160
+ }
161
+ }
162
+ comm = comm.parentNode;
163
+ }
164
+
165
+ if (detach && rangeEl.parentNode) {
166
+ actions.push(A.prevent());
167
+ actions.push(A.formatRemoveBlock(rangeEl, dom.check.isListCell(formatEl) ? [formatEl] : null, null, false, false));
168
+ actions.push(A.historyPush(true));
169
+ return true;
170
+ }
171
+ }
172
+ }
173
+
174
+ // component
175
+ if (!selectRange && formatEl && (range.startOffset === 0 || (selectionNode === formatEl ? formatEl.childNodes[range.startOffset] : false))) {
176
+ const isList = dom.check.isListCell(formatEl);
177
+ const sel = selectionNode === formatEl ? formatEl.childNodes[range.startOffset] : selectionNode;
178
+ const prev = (isList ? sel : formatEl).previousSibling;
179
+ // select file component
180
+ const ignoreZWS = isList || ((commonCon.nodeType === 3 || dom.check.isBreak(commonCon)) && !commonCon.previousSibling && range.startOffset === 0);
181
+ if (sel && (isList || !sel.previousSibling) && ((commonCon && component.is(commonCon.previousSibling)) || (ignoreZWS && component.is(prev)))) {
182
+ const fileComponentInfo = component.get(prev);
183
+ if (fileComponentInfo) {
184
+ actions.push(A.preventStop());
185
+ actions.push(A.backspaceComponentRemove(isList, sel, formatEl, fileComponentInfo));
186
+ } else if (component.is(prev)) {
187
+ actions.push(A.preventStop());
188
+ actions.push(A.domUtilsRemoveItem(prev));
189
+ }
190
+ return true;
191
+ }
192
+
193
+ // delete nonEditable
194
+ if (sel && dom.check.isNonEditable(sel.previousSibling)) {
195
+ actions.push(A.preventStop());
196
+ actions.push(A.domUtilsRemoveItem(sel.previousSibling));
197
+ return true;
198
+ }
199
+ }
200
+
201
+ return true;
202
+ }
@@ -0,0 +1,126 @@
1
+ import { dom } from '../../../helper';
2
+ import { hardDelete, isUneditableNode } from '../effects/ruleHelpers';
3
+ import { A } from '../actions';
4
+
5
+ /**
6
+ * @this {void}
7
+ * @description Delete key down rule
8
+ * @param {__se__EventActions} actions - Action list
9
+ * @param {__se__EventPorts} ports - Ports for interacting with editor
10
+ * @param {__se__EventKeydownCtx} ctx - Context object
11
+ * @returns {boolean} Return false to stop the processing
12
+ */
13
+ export function reduceDeleteDown(actions, ports, ctx) {
14
+ const { format, component } = ports;
15
+ const { range, selectionNode } = ctx;
16
+ let { formatEl } = ctx;
17
+
18
+ const selectRange = !range.collapsed || range.startContainer !== range.endContainer;
19
+
20
+ actions.push(A.componentDeselect());
21
+ actions.push(A.cacheStyleNode());
22
+
23
+ if (selectRange && hardDelete(ports)) {
24
+ actions.push(A.preventStop());
25
+ return true;
26
+ }
27
+
28
+ if (!selectRange && format.isEdgeLine(range.endContainer, range.endOffset, 'end') && !formatEl.nextSibling) {
29
+ actions.push(A.preventStop());
30
+ return false;
31
+ }
32
+
33
+ // line delete
34
+ if (
35
+ format.isLine(formatEl) &&
36
+ selectRange &&
37
+ dom.check.isEdgePoint(range.endContainer, range.endOffset, 'end') &&
38
+ (!range.endContainer.nextSibling || dom.check.isZeroWidth(range.endContainer.nextSibling)) &&
39
+ format.getLine(range.startContainer) !== format.getLine(range.endContainer) &&
40
+ (format.isLine(formatEl.nextElementSibling) || dom.check.isListCell(formatEl))
41
+ ) {
42
+ actions.push(A.preventStop());
43
+ actions.push(A.delFormatRemoveAndMove(range.endContainer, formatEl));
44
+ actions.push(A.historyPush(true));
45
+ return false;
46
+ }
47
+
48
+ // line component
49
+ if (!selectRange && formatEl && (range.endOffset === range.endContainer.textContent.length || selectionNode === formatEl)) {
50
+ const sel =
51
+ selectionNode === formatEl
52
+ ? isUneditableNode(ports, range, false)
53
+ : dom.check.isElement(selectionNode.nextSibling)
54
+ ? selectionNode.nextSibling
55
+ : dom.check.isEdgePoint(range.endContainer, range.endOffset)
56
+ ? dom.query.getNextDeepestNode(range.endContainer, null)
57
+ : null;
58
+ if (component.is(sel)) {
59
+ const fileComponentInfo = component.get(sel);
60
+ if (fileComponentInfo) {
61
+ actions.push(A.preventStop());
62
+ actions.push(A.deleteComponentSelect(formatEl, fileComponentInfo));
63
+ return true;
64
+ }
65
+ }
66
+ }
67
+
68
+ // tag[contenteditable='false']
69
+ if (isUneditableNode(ports, range, false)) {
70
+ actions.push(A.preventStop());
71
+ return true;
72
+ }
73
+
74
+ // component
75
+ if (
76
+ (format.isLine(selectionNode) || selectionNode.nextSibling === null || (dom.check.isZeroWidth(selectionNode.nextSibling) && selectionNode.nextSibling.nextSibling === null)) &&
77
+ range.startOffset === selectionNode.textContent.length
78
+ ) {
79
+ const nextEl = formatEl.nextElementSibling;
80
+ if (!nextEl) return true;
81
+
82
+ if (component.is(nextEl)) {
83
+ actions.push(A.prevent());
84
+ actions.push(A.deleteComponentSelectNext(formatEl, nextEl));
85
+ return true;
86
+ }
87
+ }
88
+
89
+ if (!selectRange && (dom.check.isEdgePoint(range.endContainer, range.endOffset) || (selectionNode === formatEl ? formatEl.childNodes[range.startOffset] : false))) {
90
+ const sel = selectionNode === formatEl ? formatEl.childNodes[range.startOffset] || selectionNode : selectionNode;
91
+ // delete nonEditable
92
+ if (sel && dom.check.isNonEditable(sel.nextSibling)) {
93
+ actions.push(A.preventStop());
94
+ actions.push(A.domUtilsRemoveItem(sel.nextSibling));
95
+ return true;
96
+ } else if (component.is(sel)) {
97
+ actions.push(A.preventStop());
98
+ actions.push(A.domUtilsRemoveItem(sel));
99
+ return true;
100
+ }
101
+ }
102
+
103
+ // format attributes
104
+ if (!selectRange && format.isEdgeLine(range.endContainer, range.endOffset, 'end')) {
105
+ if (format.isLine(formatEl.nextElementSibling)) {
106
+ actions.push(A.cacheFormatAttrsTemp(formatEl.attributes));
107
+ }
108
+ }
109
+
110
+ // nested list
111
+ formatEl = format.getLine(range.startContainer, null);
112
+ const rangeEl = format.getBlock(formatEl, null);
113
+ if (
114
+ dom.check.isListCell(formatEl) &&
115
+ dom.check.isList(rangeEl) &&
116
+ (selectionNode === formatEl ||
117
+ (selectionNode.nodeType === 3 &&
118
+ (!selectionNode.nextSibling || dom.check.isList(selectionNode.nextSibling)) &&
119
+ (format.getLine(range.startContainer, null) !== format.getLine(range.endContainer, null) ? rangeEl.contains(range.endContainer) : range.endOffset === selectionNode.textContent.length && range.collapsed)))
120
+ ) {
121
+ actions.push(A.deleteListRemoveNested(range, formatEl, rangeEl));
122
+ return true;
123
+ }
124
+
125
+ return true;
126
+ }