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.
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +77 -39
- package/src/core/{section → base}/actives.js +1 -1
- package/src/core/class/component.js +2 -0
- package/src/core/class/format.js +44 -2435
- package/src/core/class/html.js +5 -4
- package/src/core/class/inline.js +1853 -0
- package/src/core/class/listFormat.js +582 -0
- package/src/core/class/nodeTransform.js +1 -3
- package/src/core/class/selection.js +4 -2
- package/src/core/class/ui.js +1 -1
- package/src/core/class/viewer.js +4 -4
- package/src/core/config/options.js +37 -18
- package/src/core/editor.js +43 -29
- package/src/core/event/actions/index.js +229 -0
- package/src/core/event/effects/common.registry.js +60 -0
- package/src/core/event/effects/keydown.registry.js +551 -0
- package/src/core/event/effects/ruleHelpers.js +145 -0
- package/src/core/{base → event}/eventManager.js +8 -124
- package/src/core/event/executor.js +21 -0
- package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +1 -1
- package/src/core/event/handlers/handler_ww_input.js +77 -0
- package/src/core/event/handlers/handler_ww_key.js +228 -0
- package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
- package/src/core/event/ports.js +211 -0
- package/src/core/event/reducers/keydown.reducer.js +89 -0
- package/src/core/event/rules/keydown.rule.arrow.js +54 -0
- package/src/core/event/rules/keydown.rule.backspace.js +202 -0
- package/src/core/event/rules/keydown.rule.delete.js +126 -0
- package/src/core/event/rules/keydown.rule.enter.js +144 -0
- package/src/core/event/rules/keydown.rule.tab.js +29 -0
- package/src/core/section/constructor.js +57 -23
- package/src/editorInjector/_classes.js +4 -0
- package/src/editorInjector/index.js +4 -0
- package/src/helper/clipboard.js +0 -1
- package/src/helper/converter.js +6 -7
- package/src/helper/dom/domCheck.js +1 -1
- package/src/helper/dom/domQuery.js +1 -1
- package/src/helper/dom/domUtils.js +2 -2
- package/src/helper/dom/index.js +4 -0
- package/src/helper/env.js +1 -6
- package/src/helper/keyCodeMap.js +0 -1
- package/src/langs/ckb.js +1 -1
- package/src/langs/cs.js +1 -1
- package/src/langs/da.js +1 -1
- package/src/langs/de.js +1 -1
- package/src/langs/en.js +1 -1
- package/src/langs/es.js +1 -1
- package/src/langs/fa.js +1 -1
- package/src/langs/fr.js +1 -1
- package/src/langs/he.js +1 -1
- package/src/langs/hu.js +1 -1
- package/src/langs/it.js +1 -1
- package/src/langs/ja.js +1 -1
- package/src/langs/km.js +1 -1
- package/src/langs/ko.js +1 -1
- package/src/langs/lv.js +1 -1
- package/src/langs/nl.js +1 -1
- package/src/langs/pl.js +1 -1
- package/src/langs/pt_br.js +1 -1
- package/src/langs/ro.js +1 -1
- package/src/langs/ru.js +1 -1
- package/src/langs/se.js +1 -1
- package/src/langs/tr.js +1 -1
- package/src/langs/uk.js +1 -1
- package/src/langs/ur.js +1 -1
- package/src/langs/zh_cn.js +1 -1
- package/src/modules/ApiManager.js +5 -0
- package/src/modules/Figure.js +4 -10
- package/src/modules/HueSlider.js +18 -4
- package/src/modules/SelectMenu.js +1 -1
- package/src/plugins/command/fileUpload.js +1 -1
- package/src/plugins/command/list_bulleted.js +1 -1
- package/src/plugins/command/list_numbered.js +1 -1
- package/src/plugins/dropdown/backgroundColor.js +2 -2
- package/src/plugins/dropdown/font.js +2 -2
- package/src/plugins/dropdown/fontColor.js +2 -2
- package/src/plugins/dropdown/list.js +1 -1
- package/src/plugins/dropdown/table.js +1 -3
- package/src/plugins/dropdown/textStyle.js +1 -1
- package/src/plugins/field/mention.js +2 -2
- package/src/plugins/input/fontSize.js +9 -9
- package/src/plugins/modal/audio.js +5 -5
- package/src/plugins/modal/embed.js +5 -5
- package/src/plugins/modal/image.js +7 -7
- package/src/plugins/modal/link.js +23 -8
- package/src/plugins/modal/video.js +5 -5
- package/src/suneditor.js +9 -34
- package/src/typedef.js +15 -9
- package/types/core/class/format.d.ts +2 -352
- package/types/core/class/html.d.ts +2 -2
- package/types/core/class/inline.d.ts +263 -0
- package/types/core/class/listFormat.d.ts +135 -0
- package/types/core/config/options.d.ts +52 -78
- package/types/core/editor.d.ts +22 -12
- package/types/core/event/actions/index.d.ts +47 -0
- package/types/core/event/effects/common.registry.d.ts +50 -0
- package/types/core/event/effects/keydown.registry.d.ts +73 -0
- package/types/core/event/effects/ruleHelpers.d.ts +31 -0
- package/types/core/{base → event}/eventManager.d.ts +0 -42
- package/types/core/event/executor.d.ts +6 -0
- package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
- package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -33
- package/types/core/event/ports.d.ts +255 -0
- package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
- package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
- package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
- package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
- package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
- package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
- package/types/core/section/constructor.d.ts +165 -39
- package/types/editorInjector/_classes.d.ts +4 -0
- package/types/editorInjector/index.d.ts +4 -0
- package/types/helper/converter.d.ts +4 -20
- package/types/helper/dom/index.d.ts +86 -1
- package/types/index.d.ts +11 -121
- package/types/langs/index.d.ts +2 -2
- package/types/modules/HueSlider.d.ts +12 -0
- package/types/modules/index.d.ts +3 -3
- package/types/plugins/index.d.ts +38 -38
- package/types/plugins/modal/link.d.ts +6 -4
- package/types/suneditor.d.ts +18 -19
- package/types/typedef.d.ts +6 -2
- package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1267
- package/types/core/section/context.d.ts +0 -67
- package/types/core/section/options.d.ts +0 -1022
- package/types/langs/_Lang.d.ts +0 -194
- /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
- /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +0 -0
- /package/types/core/{section → base}/actives.d.ts +0 -0
- /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
- /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
- /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
- /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 './
|
|
11
|
-
import { OnMouseDown_wysiwyg, OnMouseUp_wysiwyg, OnClick_wysiwyg, OnMouseMove_wysiwyg, OnMouseLeave_wysiwyg } from './
|
|
12
|
-
import { OnBeforeInput_wysiwyg, OnInput_wysiwyg
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
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
|
|
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 (
|
|
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
|
+
}
|
|
@@ -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
|
|
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.
|
|
139
|
+
this.inline.remove();
|
|
140
140
|
|
|
141
141
|
if (n) {
|
|
142
|
-
const insertedNode = this.
|
|
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);
|