suneditor 3.0.0-beta.3 → 3.0.0-beta.30

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 (241) hide show
  1. package/CONTRIBUTING.md +8 -8
  2. package/README.md +44 -49
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +95 -53
  6. package/src/assets/design/color.css +2 -2
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +16 -1
  9. package/src/assets/suneditor-contents.css +9 -8
  10. package/src/assets/suneditor.css +29 -26
  11. package/src/core/{section → base}/actives.js +20 -12
  12. package/src/core/base/history.js +4 -4
  13. package/src/core/class/char.js +10 -10
  14. package/src/core/class/component.js +146 -57
  15. package/src/core/class/format.js +94 -2458
  16. package/src/core/class/html.js +187 -129
  17. package/src/core/class/inline.js +1853 -0
  18. package/src/core/class/listFormat.js +582 -0
  19. package/src/core/class/menu.js +14 -3
  20. package/src/core/class/nodeTransform.js +9 -14
  21. package/src/core/class/offset.js +162 -197
  22. package/src/core/class/selection.js +137 -34
  23. package/src/core/class/toolbar.js +73 -52
  24. package/src/core/class/ui.js +11 -11
  25. package/src/core/class/viewer.js +56 -55
  26. package/src/core/config/context.js +122 -0
  27. package/src/core/config/frameContext.js +204 -0
  28. package/src/core/config/options.js +639 -0
  29. package/src/core/editor.js +181 -108
  30. package/src/core/event/actions/index.js +229 -0
  31. package/src/core/event/effects/common.registry.js +60 -0
  32. package/src/core/event/effects/keydown.registry.js +551 -0
  33. package/src/core/event/effects/ruleHelpers.js +145 -0
  34. package/src/core/{base → event}/eventManager.js +119 -201
  35. package/src/core/event/executor.js +21 -0
  36. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +4 -4
  37. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +2 -2
  38. package/src/core/event/handlers/handler_ww_input.js +77 -0
  39. package/src/core/event/handlers/handler_ww_key.js +228 -0
  40. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
  41. package/src/core/event/ports.js +211 -0
  42. package/src/core/event/reducers/keydown.reducer.js +89 -0
  43. package/src/core/event/rules/keydown.rule.arrow.js +54 -0
  44. package/src/core/event/rules/keydown.rule.backspace.js +202 -0
  45. package/src/core/event/rules/keydown.rule.delete.js +126 -0
  46. package/src/core/event/rules/keydown.rule.enter.js +144 -0
  47. package/src/core/event/rules/keydown.rule.tab.js +29 -0
  48. package/src/core/section/constructor.js +79 -388
  49. package/src/core/section/documentType.js +47 -26
  50. package/src/core/util/instanceCheck.js +59 -0
  51. package/src/editorInjector/_classes.js +4 -0
  52. package/src/editorInjector/_core.js +17 -7
  53. package/src/editorInjector/index.js +10 -2
  54. package/src/events.js +6 -0
  55. package/src/helper/clipboard.js +24 -10
  56. package/src/helper/converter.js +17 -12
  57. package/src/helper/dom/domCheck.js +22 -3
  58. package/src/helper/dom/domQuery.js +91 -45
  59. package/src/helper/dom/domUtils.js +93 -19
  60. package/src/helper/dom/index.js +4 -0
  61. package/src/helper/env.js +11 -7
  62. package/src/helper/keyCodeMap.js +4 -3
  63. package/src/langs/ckb.js +1 -1
  64. package/src/langs/cs.js +1 -1
  65. package/src/langs/da.js +1 -1
  66. package/src/langs/de.js +1 -1
  67. package/src/langs/en.js +1 -1
  68. package/src/langs/es.js +1 -1
  69. package/src/langs/fa.js +1 -1
  70. package/src/langs/fr.js +1 -1
  71. package/src/langs/he.js +1 -1
  72. package/src/langs/hu.js +1 -1
  73. package/src/langs/it.js +1 -1
  74. package/src/langs/ja.js +1 -1
  75. package/src/langs/km.js +1 -1
  76. package/src/langs/ko.js +1 -1
  77. package/src/langs/lv.js +1 -1
  78. package/src/langs/nl.js +1 -1
  79. package/src/langs/pl.js +1 -1
  80. package/src/langs/pt_br.js +10 -10
  81. package/src/langs/ro.js +1 -1
  82. package/src/langs/ru.js +1 -1
  83. package/src/langs/se.js +1 -1
  84. package/src/langs/tr.js +1 -1
  85. package/src/langs/uk.js +1 -1
  86. package/src/langs/ur.js +1 -1
  87. package/src/langs/zh_cn.js +1 -1
  88. package/src/modules/ApiManager.js +25 -18
  89. package/src/modules/Browser.js +52 -61
  90. package/src/modules/ColorPicker.js +37 -38
  91. package/src/modules/Controller.js +85 -79
  92. package/src/modules/Figure.js +275 -187
  93. package/src/modules/FileManager.js +86 -92
  94. package/src/modules/HueSlider.js +67 -35
  95. package/src/modules/Modal.js +84 -77
  96. package/src/modules/ModalAnchorEditor.js +62 -79
  97. package/src/modules/SelectMenu.js +89 -86
  98. package/src/plugins/browser/audioGallery.js +9 -5
  99. package/src/plugins/browser/fileBrowser.js +10 -6
  100. package/src/plugins/browser/fileGallery.js +9 -5
  101. package/src/plugins/browser/imageGallery.js +9 -5
  102. package/src/plugins/browser/videoGallery.js +11 -6
  103. package/src/plugins/command/blockquote.js +1 -0
  104. package/src/plugins/command/exportPDF.js +11 -8
  105. package/src/plugins/command/fileUpload.js +41 -29
  106. package/src/plugins/command/list_bulleted.js +2 -1
  107. package/src/plugins/command/list_numbered.js +2 -1
  108. package/src/plugins/dropdown/align.js +8 -2
  109. package/src/plugins/dropdown/backgroundColor.js +19 -11
  110. package/src/plugins/dropdown/font.js +15 -9
  111. package/src/plugins/dropdown/fontColor.js +19 -11
  112. package/src/plugins/dropdown/formatBlock.js +7 -2
  113. package/src/plugins/dropdown/hr.js +7 -3
  114. package/src/plugins/dropdown/layout.js +6 -2
  115. package/src/plugins/dropdown/lineHeight.js +8 -3
  116. package/src/plugins/dropdown/list.js +2 -1
  117. package/src/plugins/dropdown/paragraphStyle.js +15 -11
  118. package/src/plugins/dropdown/{table.js → table/index.js} +514 -362
  119. package/src/plugins/dropdown/template.js +6 -2
  120. package/src/plugins/dropdown/textStyle.js +7 -3
  121. package/src/plugins/field/mention.js +33 -27
  122. package/src/plugins/input/fontSize.js +44 -37
  123. package/src/plugins/input/pageNavigator.js +3 -2
  124. package/src/plugins/modal/audio.js +90 -85
  125. package/src/plugins/modal/drawing.js +58 -66
  126. package/src/plugins/modal/embed.js +193 -180
  127. package/src/plugins/modal/image.js +441 -439
  128. package/src/plugins/modal/link.js +31 -8
  129. package/src/plugins/modal/math.js +23 -22
  130. package/src/plugins/modal/video.js +233 -230
  131. package/src/plugins/popup/anchor.js +24 -18
  132. package/src/suneditor.js +69 -24
  133. package/src/typedef.js +42 -19
  134. package/types/assets/icons/defaultIcons.d.ts +8 -0
  135. package/types/core/class/char.d.ts +1 -1
  136. package/types/core/class/component.d.ts +29 -7
  137. package/types/core/class/format.d.ts +4 -354
  138. package/types/core/class/html.d.ts +13 -4
  139. package/types/core/class/inline.d.ts +263 -0
  140. package/types/core/class/listFormat.d.ts +135 -0
  141. package/types/core/class/menu.d.ts +10 -2
  142. package/types/core/class/offset.d.ts +24 -26
  143. package/types/core/class/selection.d.ts +2 -0
  144. package/types/core/class/toolbar.d.ts +24 -11
  145. package/types/core/class/ui.d.ts +1 -1
  146. package/types/core/class/viewer.d.ts +1 -1
  147. package/types/core/config/context.d.ts +157 -0
  148. package/types/core/config/frameContext.d.ts +367 -0
  149. package/types/core/config/options.d.ts +1119 -0
  150. package/types/core/editor.d.ts +101 -66
  151. package/types/core/event/actions/index.d.ts +47 -0
  152. package/types/core/event/effects/common.registry.d.ts +50 -0
  153. package/types/core/event/effects/keydown.registry.d.ts +73 -0
  154. package/types/core/event/effects/ruleHelpers.d.ts +31 -0
  155. package/types/core/{base → event}/eventManager.d.ts +15 -46
  156. package/types/core/event/executor.d.ts +6 -0
  157. package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
  158. package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -6
  159. package/types/core/event/ports.d.ts +255 -0
  160. package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
  161. package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
  162. package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
  163. package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
  164. package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
  165. package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
  166. package/types/core/section/constructor.d.ts +101 -631
  167. package/types/core/section/documentType.d.ts +14 -4
  168. package/types/core/util/instanceCheck.d.ts +50 -0
  169. package/types/editorInjector/_classes.d.ts +4 -0
  170. package/types/editorInjector/_core.d.ts +17 -7
  171. package/types/editorInjector/index.d.ts +10 -2
  172. package/types/events.d.ts +1 -0
  173. package/types/helper/clipboard.d.ts +2 -2
  174. package/types/helper/converter.d.ts +6 -9
  175. package/types/helper/dom/domCheck.d.ts +7 -0
  176. package/types/helper/dom/domQuery.d.ts +19 -8
  177. package/types/helper/dom/domUtils.d.ts +24 -2
  178. package/types/helper/dom/index.d.ts +86 -1
  179. package/types/helper/env.d.ts +6 -1
  180. package/types/helper/index.d.ts +7 -1
  181. package/types/helper/keyCodeMap.d.ts +3 -3
  182. package/types/index.d.ts +23 -117
  183. package/types/langs/index.d.ts +2 -2
  184. package/types/modules/ApiManager.d.ts +1 -8
  185. package/types/modules/Browser.d.ts +4 -62
  186. package/types/modules/ColorPicker.d.ts +4 -21
  187. package/types/modules/Controller.d.ts +8 -64
  188. package/types/modules/Figure.d.ts +54 -50
  189. package/types/modules/FileManager.d.ts +1 -13
  190. package/types/modules/HueSlider.d.ts +13 -3
  191. package/types/modules/Modal.d.ts +0 -43
  192. package/types/modules/ModalAnchorEditor.d.ts +0 -73
  193. package/types/modules/SelectMenu.d.ts +0 -85
  194. package/types/modules/index.d.ts +3 -3
  195. package/types/plugins/browser/audioGallery.d.ts +29 -18
  196. package/types/plugins/browser/fileBrowser.d.ts +38 -27
  197. package/types/plugins/browser/fileGallery.d.ts +29 -18
  198. package/types/plugins/browser/imageGallery.d.ts +24 -16
  199. package/types/plugins/browser/videoGallery.d.ts +29 -18
  200. package/types/plugins/command/blockquote.d.ts +1 -0
  201. package/types/plugins/command/exportPDF.d.ts +18 -18
  202. package/types/plugins/command/fileUpload.d.ts +65 -45
  203. package/types/plugins/command/list_bulleted.d.ts +1 -0
  204. package/types/plugins/command/list_numbered.d.ts +1 -0
  205. package/types/plugins/dropdown/align.d.ts +13 -8
  206. package/types/plugins/dropdown/backgroundColor.d.ts +30 -19
  207. package/types/plugins/dropdown/font.d.ts +13 -12
  208. package/types/plugins/dropdown/fontColor.d.ts +30 -19
  209. package/types/plugins/dropdown/formatBlock.d.ts +13 -8
  210. package/types/plugins/dropdown/hr.d.ts +15 -11
  211. package/types/plugins/dropdown/layout.d.ts +15 -11
  212. package/types/plugins/dropdown/lineHeight.d.ts +16 -11
  213. package/types/plugins/dropdown/list.d.ts +1 -0
  214. package/types/plugins/dropdown/paragraphStyle.d.ts +31 -27
  215. package/types/plugins/dropdown/table/index.d.ts +582 -0
  216. package/types/plugins/dropdown/table.d.ts +41 -86
  217. package/types/plugins/dropdown/template.d.ts +15 -11
  218. package/types/plugins/dropdown/textStyle.d.ts +19 -11
  219. package/types/plugins/field/mention.d.ts +58 -56
  220. package/types/plugins/index.d.ts +38 -38
  221. package/types/plugins/input/fontSize.d.ts +46 -50
  222. package/types/plugins/modal/audio.d.ts +26 -56
  223. package/types/plugins/modal/drawing.d.ts +0 -85
  224. package/types/plugins/modal/embed.d.ts +15 -79
  225. package/types/plugins/modal/image.d.ts +24 -136
  226. package/types/plugins/modal/link.d.ts +34 -15
  227. package/types/plugins/modal/math.d.ts +0 -16
  228. package/types/plugins/modal/video.d.ts +17 -86
  229. package/types/plugins/popup/anchor.d.ts +1 -8
  230. package/types/suneditor.d.ts +70 -19
  231. package/types/typedef.d.ts +60 -46
  232. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  233. package/src/core/section/context.js +0 -102
  234. package/types/core/section/context.d.ts +0 -45
  235. package/types/langs/_Lang.d.ts +0 -194
  236. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
  237. /package/types/core/{section → base}/actives.d.ts +0 -0
  238. /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
  239. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
  240. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
  241. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.d.ts +0 -0
@@ -0,0 +1,21 @@
1
+ import common from './effects/common.registry';
2
+ import keydown from './effects/keydown.registry';
3
+
4
+ const HALT = 'action.stop';
5
+
6
+ /**
7
+ * @description Execute actions sequentially
8
+ * @param {__se__EventActions} actions - Array of actions to execute
9
+ * @param {*} effContext - Effect context containing ports, ctx, and event
10
+ */
11
+ export async function actionExecutor(actions, effContext) {
12
+ const effects = { ...common, ...keydown };
13
+ for (const a of actions) {
14
+ if (a.t === HALT) return false;
15
+ const eff = effects[a.t];
16
+ if (eff) {
17
+ const r = await eff(effContext, a.p);
18
+ if (r === false) return false;
19
+ }
20
+ }
21
+ }
@@ -15,7 +15,7 @@ export function ButtonsHandler(e) {
15
15
  const eventTarget = dom.query.getEventTarget(e);
16
16
  let target = eventTarget;
17
17
 
18
- if (this.editor.isSubBalloon && !this.context.get('toolbar.sub.main')?.contains(target)) {
18
+ if (this.editor.isSubBalloon && !this.context.get('toolbar_sub_main')?.contains(target)) {
19
19
  this._hideToolbar_sub();
20
20
  }
21
21
 
@@ -23,7 +23,7 @@ export function ButtonsHandler(e) {
23
23
 
24
24
  if (isInput) {
25
25
  this.editor._preventBlur = false;
26
- } else if (!this.editor.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
26
+ } else if (!this.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
27
27
  this.editor.focus();
28
28
  }
29
29
 
@@ -82,7 +82,7 @@ export function ButtonsHandler(e) {
82
82
 
83
83
  this.__removeInput();
84
84
  return;
85
- } else if (!this.editor.frameContext.get('isCodeView')) {
85
+ } else if (!this.frameContext.get('isCodeView')) {
86
86
  if (isMobile) {
87
87
  this.editor._preventBlur = true;
88
88
  } else {
@@ -113,7 +113,7 @@ export function OnClick_menuTray(e) {
113
113
  let k = '';
114
114
  while (t && !/se-menu-tray/.test(t.className) && !k) {
115
115
  t = t.parentElement;
116
- k = t.getAttribute('data-key');
116
+ k = t?.getAttribute('data-key');
117
117
  }
118
118
  if (!k) return;
119
119
 
@@ -27,7 +27,7 @@ export function OnDragOver_wysiwyg(fc, dragCursor, _iframeTopArea, _innerToolbar
27
27
  const _offset = { y: 0, x: 0 };
28
28
  if (_iframeTopArea) {
29
29
  const iframeOffset = this.offset.getGlobal(_iframeTopArea);
30
- const toolbarH = _innerToolbar ? this.context.get('toolbar.main').offsetHeight : 0;
30
+ const toolbarH = _innerToolbar ? this.context.get('toolbar_main').offsetHeight : 0;
31
31
  _offset.y = iframeOffset.top + toolbarH - this._w.scrollY;
32
32
  _offset.x = iframeOffset.left - this._w.scrollX;
33
33
  }
@@ -98,7 +98,7 @@ export function OnDrop_wysiwyg(fc, dragCursor, e) {
98
98
  this.html.insertNode(dragContainer, { afterNode: null, skipCharCount: true });
99
99
 
100
100
  // document type page
101
- if (fc.has('documentType-use-page')) {
101
+ if (fc.has('documentType_use_page')) {
102
102
  fc.get('documentTypePageMirror').innerHTML = fc.get('wysiwyg').innerHTML;
103
103
  fc.get('documentType').rePage(true);
104
104
  }
@@ -0,0 +1,77 @@
1
+ import { dom, keyCodeMap } from '../../../helper';
2
+
3
+ /**
4
+ * @typedef {Omit<import('../eventManager').default & Partial<__se__EditorInjector>, 'eventManager'>} EventManagerThis_handler_ww_input
5
+ */
6
+
7
+ /**
8
+ * @private
9
+ * @this {EventManagerThis_handler_ww_input}
10
+ * @param {__se__FrameContext} fc - Frame context object
11
+ * @param {InputEvent} e - Event object
12
+ */
13
+ export async function OnBeforeInput_wysiwyg(fc, e) {
14
+ if (fc.get('isReadOnly') || fc.get('isDisabled')) {
15
+ e.preventDefault();
16
+ e.stopPropagation();
17
+ return false;
18
+ }
19
+
20
+ const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
21
+ if (!keyCodeMap.isComposing(e)) {
22
+ if (!this.char.test(data, false)) {
23
+ e.preventDefault();
24
+ e.stopPropagation();
25
+ return false;
26
+ }
27
+ this._handledInBefore = true;
28
+ } else {
29
+ this._handledInBefore = false;
30
+ }
31
+
32
+ // user event
33
+ if ((await this.triggerEvent('onBeforeInput', { frameContext: fc, event: e, data })) === false) return;
34
+ // plugin event
35
+ if (this._callPluginEvent('onBeforeInput', { frameContext: fc, event: e, data }) === false) return;
36
+ }
37
+
38
+ /**
39
+ * @private
40
+ * @this {EventManagerThis_handler_ww_input}
41
+ * @param {__se__FrameContext} fc - Frame context object
42
+ * @param {InputEvent} e - Event object
43
+ */
44
+ export async function OnInput_wysiwyg(fc, e) {
45
+ if (fc.get('isReadOnly') || fc.get('isDisabled')) {
46
+ e.preventDefault();
47
+ e.stopPropagation();
48
+ return false;
49
+ }
50
+
51
+ const range = this.selection.getRange();
52
+ const selectionNode = this.selection.getNode();
53
+ const formatEl = this.format.getLine(selectionNode, null);
54
+ if (!this.format.isNormalLine(formatEl) && !this.format.isBrLine(formatEl) && range.collapsed && !this.component.is(selectionNode) && !dom.check.isList(selectionNode)) {
55
+ const rangeEl = this.format.getBlock(selectionNode, null);
56
+ this._setDefaultLine(this.format.isBlock(rangeEl) ? 'DIV' : this.options.get('defaultLine'));
57
+ }
58
+
59
+ this.selection._init();
60
+
61
+ const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
62
+ if (!this._handledInBefore) {
63
+ if (!this.char.test(data, true)) {
64
+ e.preventDefault();
65
+ e.stopPropagation();
66
+ return false;
67
+ }
68
+ }
69
+ this._handledInBefore = false;
70
+
71
+ // user event
72
+ if ((await this.triggerEvent('onInput', { frameContext: fc, event: e, data })) === false) return;
73
+ // plugin event
74
+ if (this._callPluginEvent('onInput', { frameContext: fc, event: e, data }) === false) return;
75
+
76
+ this.history.push(true);
77
+ }
@@ -0,0 +1,228 @@
1
+ import { dom, env, unicode, keyCodeMap } from '../../../helper';
2
+ import { actionExecutor } from '../executor';
3
+ import { makePorts } from '../ports';
4
+ import { reduceKeydown } from '../reducers/keydown.reducer';
5
+
6
+ const { _w } = env;
7
+ const FRONT_ZEROWIDTH = new RegExp(unicode.zeroWidthSpace + '+', '');
8
+
9
+ const keyState = {
10
+ ctrl: false,
11
+ alt: false
12
+ };
13
+ const _styleNodes = Object.preventExtensions({ value: [] });
14
+
15
+ /**
16
+ * @typedef {Omit<import('../eventManager').default & Partial<__se__EditorInjector>, 'eventManager'>} EventManagerThis_handler_ww_key_input
17
+ */
18
+
19
+ /**
20
+ * @private
21
+ * @this {EventManagerThis_handler_ww_key_input}
22
+ * @param {__se__FrameContext} fc - Frame context object
23
+ * @param {KeyboardEvent} e - Event object
24
+ */
25
+ export async function OnKeyDown_wysiwyg(fc, e) {
26
+ if ((this.isComposing = keyCodeMap.isComposing(e))) return true;
27
+ if (this.editor.selectMenuOn || !e.isTrusted) return;
28
+
29
+ let selectionNode = this.selection.getNode();
30
+ if (dom.check.isInputElement(selectionNode)) return;
31
+ if (this.menu.currentDropdownName) return;
32
+
33
+ const keyCode = e.code;
34
+ const shift = keyCodeMap.isShift(e);
35
+ const ctrl = (keyState.ctrl = keyCodeMap.isCtrl(e));
36
+ const alt = (keyState.alt = keyCodeMap.isAlt(e));
37
+
38
+ if (!ctrl && fc.get('isReadOnly') && !keyCodeMap.isDirectionKey(keyCode)) {
39
+ e.preventDefault();
40
+ return false;
41
+ }
42
+
43
+ this.menu.dropdownOff();
44
+
45
+ if (this.editor.isBalloon) {
46
+ this._hideToolbar();
47
+ } else if (this.editor.isSubBalloon) {
48
+ this._hideToolbar_sub();
49
+ }
50
+
51
+ // user event
52
+ if ((await this.triggerEvent('onKeyDown', { frameContext: fc, event: e })) === false) return;
53
+
54
+ /** default key action */
55
+ if (keyCodeMap.isEnter(keyCode) && this.format.isLine(this.selection.getRange()?.startContainer)) {
56
+ this.selection._resetRangeToTextNode();
57
+ selectionNode = this.selection.getNode();
58
+ }
59
+
60
+ const range = this.selection.getRange();
61
+ const formatEl = /** @type {HTMLElement} */ (this.format.getLine(selectionNode, null) || selectionNode);
62
+
63
+ /** Shortcuts */
64
+ if (ctrl && !keyCodeMap.isNonTextKey(keyCode) && this.shortcuts.command(e, ctrl, shift, keyCode, '', false, null, null)) {
65
+ this._onShortcutKey = true;
66
+ e.preventDefault();
67
+ e.stopPropagation();
68
+ return false;
69
+ } else if (!ctrl && !keyCodeMap.isNonTextKey(keyCode) && this.format.isLine(formatEl) && range.collapsed && dom.check.isEdgePoint(range.startContainer, 0, 'front')) {
70
+ const keyword = /** @type {Text} */ (range.startContainer).substringData?.(0, range.startOffset);
71
+ if (keyword && this.shortcuts.command(e, false, shift, keyCode, keyword, true, formatEl, range)) {
72
+ this._onShortcutKey = true;
73
+ e.preventDefault();
74
+ e.stopPropagation();
75
+ return false;
76
+ }
77
+ } else if (this._onShortcutKey) {
78
+ this._onShortcutKey = false;
79
+ }
80
+
81
+ // plugin event
82
+ if (this._callPluginEvent('onKeyDown', { frameContext: fc, event: e, range, line: formatEl }) === false) return;
83
+
84
+ // reducer / actions
85
+ /** @type {__se__EventKeydownCtx} */
86
+ const ctx = { e, fc, status: this.status, options: this.options, frameOptions: this.frameOptions, range, selectionNode, formatEl, keyCode, ctrl, alt, shift };
87
+ const ports = makePorts(this, { _styleNodes });
88
+
89
+ // action execute
90
+ const actions = await reduceKeydown(ports, ctx);
91
+ await actionExecutor(actions, { ports, ctx });
92
+ }
93
+
94
+ /**
95
+ * @private
96
+ * @this {EventManagerThis_handler_ww_key_input}
97
+ * @param {__se__FrameContext} fc - Frame context object
98
+ * @param {KeyboardEvent} e - Event object
99
+ */
100
+ export async function OnKeyUp_wysiwyg(fc, e) {
101
+ if (this._onShortcutKey || this.menu.currentDropdownName) return;
102
+
103
+ const keyCode = e.code;
104
+ const ctrl = keyCodeMap.isCtrl(e);
105
+ const alt = keyCodeMap.isAlt(e);
106
+
107
+ if (ctrl) keyState.ctrl = false;
108
+ if (alt) keyState.alt = false;
109
+
110
+ if (fc.get('isReadOnly')) return;
111
+
112
+ const range = this.selection.getRange();
113
+ let selectionNode = this.selection.getNode();
114
+
115
+ if ((this.editor.isBalloon || this.editor.isSubBalloon) && (((this.editor.isBalloonAlways || this.editor.isSubBalloonAlways) && !keyCodeMap.isEsc(keyCode)) || !range.collapsed)) {
116
+ if (this.editor.isBalloonAlways || this.editor.isSubBalloonAlways) {
117
+ if (!keyCodeMap.isEsc(keyCode)) this._showToolbarBalloonDelay();
118
+ } else {
119
+ if (this.editor.isSubBalloon) this.subToolbar._showBalloon();
120
+ else this.toolbar._showBalloon();
121
+ return;
122
+ }
123
+ }
124
+
125
+ /** when format tag deleted */
126
+ if (keyCodeMap.isBackspace(keyCode) && dom.check.isWysiwygFrame(selectionNode) && selectionNode.textContent === '' && selectionNode.children.length === 0) {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+
130
+ selectionNode.innerHTML = '';
131
+
132
+ const oFormatTag = dom.utils.createElement(this.format.isLine(this.status.currentNodes[0]) && !dom.check.isListCell(this.status.currentNodes[0]) ? this.status.currentNodes[0] : this.options.get('defaultLine'), null, '<br>');
133
+ selectionNode.appendChild(oFormatTag);
134
+ this.selection.setRange(oFormatTag, 0, oFormatTag, 0);
135
+ this.applyTagEffect();
136
+
137
+ this.history.push(false);
138
+
139
+ // document type
140
+ if (fc.has('documentType_use_header')) {
141
+ if (keyCodeMap.isDocumentTypeObserverKey(keyCode)) {
142
+ fc.get('documentType').reHeader();
143
+ }
144
+ }
145
+
146
+ return;
147
+ }
148
+
149
+ const formatEl = this.format.getLine(selectionNode, null);
150
+ const rangeEl = this.format.getBlock(selectionNode, null);
151
+ const attrs = this._formatAttrsTemp;
152
+
153
+ if (formatEl && attrs) {
154
+ for (let i = 0, len = attrs.length; i < len; i++) {
155
+ if (keyCodeMap.isEnter(keyCode) && /^id$/i.test(attrs[i].name)) {
156
+ formatEl.removeAttribute('id');
157
+ continue;
158
+ }
159
+ formatEl.setAttribute(attrs[i].name, attrs[i].value);
160
+ }
161
+ this._formatAttrsTemp = null;
162
+ }
163
+
164
+ if (
165
+ !this.format.isNormalLine(formatEl) &&
166
+ !this.format.isBrLine(formatEl) &&
167
+ range.collapsed &&
168
+ !this.component.is(selectionNode) &&
169
+ !dom.check.isList(selectionNode) &&
170
+ this._setDefaultLine(this.format.isBlock(rangeEl) ? 'DIV' : this.options.get('defaultLine')) !== null
171
+ ) {
172
+ selectionNode = this.selection.getNode();
173
+ }
174
+
175
+ const textKey = !keyState.ctrl && !keyState.alt && !keyCodeMap.isNonTextKey(keyCode);
176
+ if (textKey && selectionNode.nodeType === 3 && unicode.zeroWidthRegExp.test(selectionNode.textContent) && !(e.isComposing !== undefined ? e.isComposing : this.isComposing)) {
177
+ let so = range.startOffset,
178
+ eo = range.endOffset;
179
+ const frontZeroWidthCnt = (selectionNode.textContent.substring(0, eo).match(FRONT_ZEROWIDTH) || '').length;
180
+ so = range.startOffset - frontZeroWidthCnt;
181
+ eo = range.endOffset - frontZeroWidthCnt;
182
+ selectionNode.textContent = selectionNode.textContent.replace(unicode.zeroWidthRegExp, '');
183
+ this.selection.setRange(selectionNode, so < 0 ? 0 : so, selectionNode, eo < 0 ? 0 : eo);
184
+ }
185
+
186
+ if (keyCodeMap.isRemoveKey(keyCode) && dom.check.isZeroWidth(formatEl?.textContent) && !formatEl.previousElementSibling && !dom.check.isListCell(formatEl)) {
187
+ const rsMode = this.options.get('retainStyleMode');
188
+ if (rsMode !== 'none' && _styleNodes.value?.length > 0) {
189
+ if (rsMode === 'repeat') {
190
+ if (this.__retainTimer) {
191
+ this.__retainTimer = _w.clearTimeout(this.__retainTimer);
192
+ this._clearRetainStyleNodes(formatEl);
193
+ } else {
194
+ this.__retainTimer = _w.setTimeout(() => {
195
+ this.__retainTimer = null;
196
+ }, 0);
197
+ this._retainStyleNodes(formatEl, _styleNodes.value);
198
+ }
199
+ } else {
200
+ this.__retainTimer = null;
201
+ this._retainStyleNodes(formatEl, _styleNodes.value);
202
+ }
203
+ } else {
204
+ this._clearRetainStyleNodes(formatEl);
205
+ }
206
+ }
207
+
208
+ // document type
209
+ if (fc.has('documentType_use_header')) {
210
+ if (keyCodeMap.isDocumentTypeObserverKey(keyCode)) {
211
+ fc.get('documentType').reHeader();
212
+ const el = dom.query.getParentElement(this.selection.selectionNode, this.format.isLine.bind(this.format));
213
+ fc.get('documentType').on(el);
214
+ } else {
215
+ const el = dom.query.getParentElement(selectionNode, (current) => current.nodeType === 1);
216
+ fc.get('documentType').onChangeText(el);
217
+ }
218
+ }
219
+
220
+ // user event
221
+ if ((await this.triggerEvent('onKeyUp', { frameContext: fc, event: e })) === false) return;
222
+ // plugin event
223
+ if (this._callPluginEvent('onKeyUp', { frameContext: fc, event: e, range, line: formatEl }) === false) return;
224
+
225
+ if (keyCodeMap.isHistoryRelevantKey(keyCode)) {
226
+ this.history.push(true);
227
+ }
228
+ }
@@ -48,7 +48,7 @@ export async function OnMouseDown_wysiwyg(fc, e) {
48
48
  this._hideToolbar_sub();
49
49
  }
50
50
 
51
- if (/FIGURE/i.test(eventTarget.nodeName)) e.preventDefault();
51
+ if (/FIGURE/i.test(eventTarget?.nodeName)) e.preventDefault();
52
52
  }
53
53
 
54
54
  /**
@@ -136,10 +136,10 @@ export async function OnClick_wysiwyg(fc, e) {
136
136
  const _styleNode = [...this.editor._onCopyFormatInfo];
137
137
  const n = _styleNode.pop();
138
138
 
139
- this.format.removeInlineElement();
139
+ this.inline.remove();
140
140
 
141
141
  if (n) {
142
- const insertedNode = this.format.applyInlineElement(n, { stylesToModify: null, nodesToRemove: [n.nodeName], strictRemove: false });
142
+ const insertedNode = this.inline.apply(n, { stylesToModify: null, nodesToRemove: [n.nodeName], strictRemove: false });
143
143
  const { parent, inner } = this.nodeTransform.createNestedNode(_styleNode);
144
144
  insertedNode.parentNode.insertBefore(parent, insertedNode);
145
145
  inner.appendChild(insertedNode);
@@ -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
+ */