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
@@ -7,11 +7,12 @@ import { dom, unicode, numbers, env, converter } from '../../helper';
7
7
  import { _DragHandle } from '../../modules';
8
8
 
9
9
  // event handlers
10
- import { ButtonsHandler, OnClick_menuTray, OnClick_toolbar } from './eventHandlers/handler_toolbar';
11
- import { OnMouseDown_wysiwyg, OnMouseUp_wysiwyg, OnClick_wysiwyg, OnMouseMove_wysiwyg, OnMouseLeave_wysiwyg } from './eventHandlers/handler_ww_mouse';
12
- import { OnBeforeInput_wysiwyg, OnInput_wysiwyg, OnKeyDown_wysiwyg, OnKeyUp_wysiwyg } from './eventHandlers/handler_ww_key_input';
13
- import { OnPaste_wysiwyg, OnCopy_wysiwyg, OnCut_wysiwyg } from './eventHandlers/handler_ww_clipboard';
14
- import { OnDragOver_wysiwyg, OnDragEnd_wysiwyg, OnDrop_wysiwyg } from './eventHandlers/handler_ww_dragDrop';
10
+ import { ButtonsHandler, OnClick_menuTray, OnClick_toolbar } from './handlers/handler_toolbar';
11
+ import { OnMouseDown_wysiwyg, OnMouseUp_wysiwyg, OnClick_wysiwyg, OnMouseMove_wysiwyg, OnMouseLeave_wysiwyg } from './handlers/handler_ww_mouse';
12
+ import { OnBeforeInput_wysiwyg, OnInput_wysiwyg } from './handlers/handler_ww_input';
13
+ import { OnKeyDown_wysiwyg, OnKeyUp_wysiwyg } from './handlers/handler_ww_key';
14
+ import { OnPaste_wysiwyg, OnCopy_wysiwyg, OnCut_wysiwyg } from './handlers/handler_ww_clipboard';
15
+ import { OnDragOver_wysiwyg, OnDragEnd_wysiwyg, OnDrop_wysiwyg } from './handlers/handler_ww_dragDrop';
15
16
 
16
17
  const { _w, ON_OVER_COMPONENT, isMobile, isTouchDevice } = env;
17
18
 
@@ -447,93 +448,6 @@ EventManager.prototype = {
447
448
  return dom.check.isElement(node) && node.getAttribute('data-se-non-focus') === 'true';
448
449
  },
449
450
 
450
- /**
451
- * @private
452
- * @this {EventManagerThis}
453
- * @description Determines if the "range" is within an uneditable node.
454
- * @param {Range} range The range object
455
- * @param {boolean} isFront Whether to check the start or end of the range
456
- * @returns {Node|null} The uneditable node if found, otherwise null
457
- */
458
- _isUneditableNode(range, isFront) {
459
- const container = isFront ? range.startContainer : range.endContainer;
460
- const offset = isFront ? range.startOffset : range.endOffset;
461
- const siblingKey = isFront ? 'previousSibling' : 'nextSibling';
462
- const isElement = container.nodeType === 1;
463
-
464
- let siblingNode;
465
- if (isElement) {
466
- siblingNode = /** @type {HTMLElement} */ (this._isUneditableNode_getSibling(container.childNodes[offset], siblingKey, container));
467
- return dom.check.isComponentContainer(siblingNode) || dom.check.isNonEditable(siblingNode) ? siblingNode : null;
468
- } else {
469
- siblingNode = /** @type {HTMLElement} */ (this._isUneditableNode_getSibling(container, siblingKey, container));
470
- return dom.check.isEdgePoint(container, offset, isFront ? 'front' : 'end') && (dom.check.isComponentContainer(siblingNode) || dom.check.isNonEditable(siblingNode)) ? siblingNode : null;
471
- }
472
- },
473
-
474
- /**
475
- * @private
476
- * @this {EventManagerThis}
477
- * @description Retrieves the sibling node of a selected node if it is uneditable. || component node.
478
- * - Used only in `_isUneditableNode`.
479
- * @param {Node} selectNode The selected node
480
- * @param {string} siblingKey The key to access the sibling (`previousSibling` or `nextSibling`)
481
- * @param {Node} container The parent container node
482
- * @returns {Node|null} The sibling node if found, otherwise null
483
- */
484
- _isUneditableNode_getSibling(selectNode, siblingKey, container) {
485
- if (!selectNode) return null;
486
- let siblingNode = selectNode[siblingKey];
487
-
488
- if (!siblingNode) {
489
- siblingNode = this.format.getLine(container);
490
- siblingNode = siblingNode ? siblingNode[siblingKey] : null;
491
- if (siblingNode && !this.component.is(siblingNode)) siblingNode = siblingKey === 'previousSibling' ? siblingNode.firstChild : siblingNode.lastChild;
492
- else return null;
493
- }
494
-
495
- return siblingNode;
496
- },
497
-
498
- /**
499
- * @private
500
- * @this {EventManagerThis}
501
- * @description Deletes specific elements such as tables in "Firefox" and media elements (image, video, audio) in "Chrome".
502
- * - Handles deletion logic based on selection range and node types.
503
- * @returns {boolean} Returns `true` if an element was deleted and focus was adjusted, otherwise `false`.
504
- */
505
- _hardDelete() {
506
- const range = this.selection.getRange();
507
- const sc = range.startContainer;
508
- const ec = range.endContainer;
509
-
510
- // table
511
- const sCell = this.format.getBlock(sc);
512
- const eCell = this.format.getBlock(ec);
513
- const sIsCell = dom.check.isTableCell(sCell);
514
- const eIsCell = dom.check.isTableCell(eCell);
515
- if (((sIsCell && !sCell.previousElementSibling && !sCell.parentElement.previousElementSibling) || (eIsCell && !eCell.nextElementSibling && !eCell.parentElement.nextElementSibling)) && sCell !== eCell) {
516
- const ancestor = dom.query.getParentElement(range.commonAncestorContainer, dom.check.isFigure)?.parentElement || range.commonAncestorContainer;
517
- if (!sIsCell) {
518
- dom.utils.removeItem(dom.query.getParentElement(eCell, (current) => ancestor === current.parentNode));
519
- } else if (!eIsCell) {
520
- dom.utils.removeItem(dom.query.getParentElement(sCell, (current) => ancestor === current.parentNode));
521
- } else {
522
- dom.utils.removeItem(dom.query.getParentElement(sCell, (current) => ancestor === current.parentNode));
523
- this.editor._nativeFocus();
524
- return true;
525
- }
526
- }
527
-
528
- // component
529
- const sComp = sc.nodeType === 1 ? dom.query.getParentElement(sc, '.se-component') : null;
530
- const eComp = ec.nodeType === 1 ? dom.query.getParentElement(ec, '.se-component') : null;
531
- if (sComp) dom.utils.removeItem(sComp);
532
- if (eComp) dom.utils.removeItem(eComp);
533
-
534
- return false;
535
- },
536
-
537
451
  /**
538
452
  * @private
539
453
  * @this {EventManagerThis}
@@ -612,7 +526,6 @@ EventManager.prototype = {
612
526
  return;
613
527
  }
614
528
 
615
- /* eslint-disable @typescript-eslint/no-unused-vars */
616
529
  try {
617
530
  if (commonCon.nodeType === 3) {
618
531
  format = dom.utils.createElement(formatName || this.options.get('defaultLine'));
@@ -627,13 +540,12 @@ EventManager.prototype = {
627
540
  focusNode.parentNode.insertBefore(zeroWidth, focusNode);
628
541
  focusNode = zeroWidth;
629
542
  }
630
- } catch (e) {
543
+ } catch {
631
544
  this.editor.execCommand('formatBlock', false, formatName || this.options.get('defaultLine'));
632
545
  this.editor.effectNode = null;
633
546
  this.selection._init();
634
547
  return;
635
548
  }
636
- /* eslint-disable @typescript-eslint/no-unused-vars */
637
549
 
638
550
  if (format) {
639
551
  if (dom.check.isBreak(format.nextSibling)) dom.utils.removeItem(format.nextSibling);
@@ -1043,7 +955,7 @@ EventManager.prototype = {
1043
955
  }
1044
956
 
1045
957
  const openCont = this.editor.opendControllers;
1046
- if (!openCont.length) return;
958
+ if (openCont.length === 0) return;
1047
959
 
1048
960
  this.__rePositionController(openCont);
1049
961
  },
@@ -1209,34 +1121,6 @@ EventManager.prototype = {
1209
1121
  this.__inputPlugin = null;
1210
1122
  },
1211
1123
 
1212
- /**
1213
- * @private
1214
- * @this {EventManagerThis}
1215
- * @description Prevents the default behavior of the Enter key and refocuses the editor.
1216
- * @param {Event} e The keyboard event
1217
- */
1218
- __enterPrevent(e) {
1219
- e.preventDefault();
1220
- if (!isMobile) return;
1221
-
1222
- this.__focusTemp.focus({ preventScroll: true });
1223
- this.frameContext.get('wysiwyg').focus({ preventScroll: true });
1224
- },
1225
-
1226
- /**
1227
- * @private
1228
- * @description Scrolls the editor view to the caret position after pressing Enter. (Ignored on mobile devices)
1229
- * @this {EventManagerThis}
1230
- * @param {*} range Range object
1231
- */
1232
- __enterScrollTo(range) {
1233
- this.editor._iframeAutoHeight(this.frameContext);
1234
-
1235
- // scroll to
1236
- if (env.isMobile && this.scrollparents.length > 0) return;
1237
- this.editor.selection.scrollTo(range, { behavior: 'auto', block: 'nearest', inline: 'nearest' });
1238
- },
1239
-
1240
1124
  /**
1241
1125
  * @private
1242
1126
  * @description Focus Event Postprocessing
@@ -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
+ }
@@ -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
 
@@ -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);