suneditor 3.1.4 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/suneditor-contents.min.css +1 -1
- package/dist/suneditor.min.css +28 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +2 -1
- package/src/assets/design/color.css +12 -0
- package/src/assets/design/size.css +9 -2
- package/src/assets/icons/defaultIcons.js +96 -47
- package/src/assets/suneditor-contents.css +3 -2
- package/src/assets/suneditor.css +481 -31
- package/src/core/config/contextProvider.js +2 -1
- package/src/core/config/eventManager.js +41 -2
- package/src/core/config/optionProvider.js +23 -2
- package/src/core/editor.js +32 -14
- package/src/core/event/actions/index.js +76 -9
- package/src/core/event/effects/common.registry.js +2 -1
- package/src/core/event/effects/keydown.registry.js +169 -33
- package/src/core/event/effects/ruleHelpers.js +20 -6
- package/src/core/event/eventOrchestrator.js +162 -30
- package/src/core/event/handlers/handler_toolbar.js +4 -2
- package/src/core/event/handlers/handler_ww_dragDrop.js +10 -0
- package/src/core/event/handlers/handler_ww_input.js +84 -2
- package/src/core/event/handlers/handler_ww_key.js +82 -21
- package/src/core/event/handlers/handler_ww_mouse.js +45 -8
- package/src/core/event/ports.js +27 -13
- package/src/core/event/reducers/keydown.reducer.js +33 -5
- package/src/core/event/rules/keydown.rule.arrow.js +12 -2
- package/src/core/event/rules/keydown.rule.backspace.js +110 -15
- package/src/core/event/rules/keydown.rule.delete.js +62 -7
- package/src/core/event/rules/keydown.rule.enter.js +62 -31
- package/src/core/event/support/defaultLineManager.js +9 -2
- package/src/core/event/support/selectionState.js +13 -3
- package/src/core/kernel/coreKernel.js +1 -0
- package/src/core/logic/dom/char.js +13 -3
- package/src/core/logic/dom/format.js +171 -39
- package/src/core/logic/dom/html.js +350 -72
- package/src/core/logic/dom/inline.js +229 -34
- package/src/core/logic/dom/listFormat.js +111 -20
- package/src/core/logic/dom/nodeTransform.js +36 -11
- package/src/core/logic/dom/offset.js +116 -31
- package/src/core/logic/dom/selection.js +147 -29
- package/src/core/logic/panel/blockHandle.js +785 -0
- package/src/core/logic/panel/blockResolver.js +278 -0
- package/src/core/logic/panel/finder.js +16 -6
- package/src/core/logic/panel/menu.js +119 -18
- package/src/core/logic/panel/toolbar.js +75 -19
- package/src/core/logic/panel/viewer.js +76 -20
- package/src/core/logic/shell/_commandExecutor.js +44 -9
- package/src/core/logic/shell/commandDispatcher.js +46 -4
- package/src/core/logic/shell/component.js +102 -25
- package/src/core/logic/shell/focusManager.js +13 -3
- package/src/core/logic/shell/history.js +21 -6
- package/src/core/logic/shell/pluginManager.js +21 -13
- package/src/core/logic/shell/shortcuts.js +9 -1
- package/src/core/logic/shell/ui.js +139 -37
- package/src/core/schema/frameContext.js +34 -3
- package/src/core/schema/options.js +46 -4
- package/src/core/section/constructor.js +537 -106
- package/src/core/section/documentType.js +35 -6
- package/src/helper/converter.js +24 -7
- package/src/helper/dom/domCheck.js +25 -5
- package/src/helper/dom/domQuery.js +2 -1
- package/src/helper/dom/domUtils.js +17 -4
- package/src/helper/env.js +11 -2
- package/src/helper/keyCodeMap.js +6 -2
- package/src/helper/markdown.js +24 -5
- package/src/helper/msOffice.js +9 -2
- package/src/interfaces/plugins.js +1 -1
- package/src/langs/ckb.js +0 -1
- package/src/langs/cs.js +0 -1
- package/src/langs/da.js +0 -1
- package/src/langs/de.js +0 -1
- package/src/langs/en.js +0 -1
- package/src/langs/es.js +0 -1
- package/src/langs/fa.js +0 -1
- package/src/langs/fr.js +0 -1
- package/src/langs/he.js +0 -1
- package/src/langs/hu.js +0 -1
- package/src/langs/index.js +27 -1
- package/src/langs/it.js +0 -1
- package/src/langs/ja.js +0 -1
- package/src/langs/km.js +0 -1
- package/src/langs/ko.js +0 -1
- package/src/langs/lv.js +0 -1
- package/src/langs/nl.js +0 -1
- package/src/langs/pl.js +0 -1
- package/src/langs/pt_br.js +0 -1
- package/src/langs/ro.js +0 -1
- package/src/langs/ru.js +0 -1
- package/src/langs/se.js +0 -1
- package/src/langs/tr.js +0 -1
- package/src/langs/uk.js +0 -1
- package/src/langs/ur.js +0 -1
- package/src/langs/zh_cn.js +0 -1
- package/src/modules/contract/Browser.js +58 -14
- package/src/modules/contract/ColorPicker.js +12 -4
- package/src/modules/contract/Controller.js +37 -7
- package/src/modules/contract/Figure.js +156 -36
- package/src/modules/contract/HueSlider.js +27 -4
- package/src/modules/contract/Modal.js +50 -10
- package/src/modules/manager/FileManager.js +50 -8
- package/src/modules/ui/CommandMenu.js +597 -0
- package/src/modules/ui/ModalAnchorEditor.js +33 -6
- package/src/modules/ui/SelectMenu.js +481 -36
- package/src/modules/ui/index.js +1 -0
- package/src/plugins/browser/audioGallery.js +2 -1
- package/src/plugins/browser/fileBrowser.js +9 -2
- package/src/plugins/browser/fileGallery.js +2 -1
- package/src/plugins/browser/imageGallery.js +18 -3
- package/src/plugins/browser/videoGallery.js +13 -4
- package/src/plugins/command/blockquote.js +6 -1
- package/src/plugins/command/codeBlock.js +43 -5
- package/src/plugins/command/exportPDF.js +20 -4
- package/src/plugins/command/fileUpload.js +46 -11
- package/src/plugins/command/list_bulleted.js +6 -1
- package/src/plugins/command/list_numbered.js +6 -1
- package/src/plugins/dropdown/align.js +21 -33
- package/src/plugins/dropdown/backgroundColor.js +10 -2
- package/src/plugins/dropdown/blockStyle.js +17 -22
- package/src/plugins/dropdown/font.js +34 -34
- package/src/plugins/dropdown/hr.js +15 -43
- package/src/plugins/dropdown/layout.js +10 -27
- package/src/plugins/dropdown/lineHeight.js +10 -33
- package/src/plugins/dropdown/list.js +19 -25
- package/src/plugins/dropdown/paragraphStyle.js +16 -24
- package/src/plugins/dropdown/table/index.js +72 -17
- package/src/plugins/dropdown/table/render/table.html.js +3 -1
- package/src/plugins/dropdown/table/services/table.cell.js +33 -7
- package/src/plugins/dropdown/table/services/table.clipboard.js +5 -1
- package/src/plugins/dropdown/table/services/table.grid.js +40 -9
- package/src/plugins/dropdown/table/services/table.resize.js +55 -11
- package/src/plugins/dropdown/table/services/table.selection.js +27 -7
- package/src/plugins/dropdown/table/services/table.style.js +120 -20
- package/src/plugins/dropdown/template.js +13 -29
- package/src/plugins/dropdown/textStyle.js +22 -35
- package/src/plugins/field/autocomplete.js +8 -4
- package/src/plugins/field/slashCommand.js +297 -0
- package/src/plugins/index.js +3 -0
- package/src/plugins/input/fontSize.js +37 -8
- package/src/plugins/input/pageNavigator.js +7 -1
- package/src/plugins/modal/audio.js +71 -17
- package/src/plugins/modal/drawing.js +41 -11
- package/src/plugins/modal/embed.js +92 -22
- package/src/plugins/modal/image/index.js +114 -28
- package/src/plugins/modal/image/services/image.size.js +9 -2
- package/src/plugins/modal/image/services/image.upload.js +38 -4
- package/src/plugins/modal/link.js +9 -2
- package/src/plugins/modal/math.js +10 -2
- package/src/plugins/modal/video/index.js +112 -26
- package/src/plugins/modal/video/render/video.html.js +4 -1
- package/src/plugins/modal/video/services/video.size.js +15 -4
- package/src/plugins/modal/video/services/video.upload.js +10 -2
- package/src/plugins/popup/anchor.js +14 -2
- package/src/suneditor.js +8 -2
- package/src/themes/cobalt.css +12 -0
- package/src/themes/cream.css +12 -0
- package/src/themes/dark.css +12 -0
- package/src/themes/midnight.css +12 -0
- package/src/typedef.js +32 -21
- package/types/assets/icons/defaultIcons.d.ts +1 -0
- package/types/core/config/contextProvider.d.ts +7 -1
- package/types/core/config/eventManager.d.ts +37 -4
- package/types/core/config/optionProvider.d.ts +5 -1
- package/types/core/event/actions/index.d.ts +44 -6
- package/types/core/event/effects/keydown.registry.d.ts +37 -7
- package/types/core/event/effects/ruleHelpers.d.ts +6 -1
- package/types/core/event/eventOrchestrator.d.ts +13 -3
- package/types/core/event/handlers/handler_ww_clipboard.d.ts +15 -3
- package/types/core/event/handlers/handler_ww_dragDrop.d.ts +14 -2
- package/types/core/event/handlers/handler_ww_input.d.ts +10 -2
- package/types/core/event/handlers/handler_ww_key.d.ts +10 -2
- package/types/core/event/handlers/handler_ww_mouse.d.ts +25 -5
- package/types/core/event/ports.d.ts +11 -4
- package/types/core/event/reducers/keydown.reducer.d.ts +12 -3
- package/types/core/event/rules/keydown.rule.backspace.d.ts +6 -1
- package/types/core/kernel/store.d.ts +4 -1
- package/types/core/logic/dom/format.d.ts +32 -14
- package/types/core/logic/dom/html.d.ts +11 -3
- package/types/core/logic/dom/nodeTransform.d.ts +6 -6
- package/types/core/logic/panel/blockHandle.d.ts +64 -0
- package/types/core/logic/panel/blockResolver.d.ts +50 -0
- package/types/core/logic/panel/menu.d.ts +72 -3
- package/types/core/logic/shell/commandDispatcher.d.ts +8 -0
- package/types/core/logic/shell/component.d.ts +5 -3
- package/types/core/logic/shell/shortcuts.d.ts +10 -1
- package/types/core/logic/shell/ui.d.ts +7 -1
- package/types/core/schema/context.d.ts +7 -1
- package/types/core/schema/frameContext.d.ts +36 -4
- package/types/core/schema/options.d.ts +83 -2
- package/types/core/section/constructor.d.ts +38 -1
- package/types/events.d.ts +208 -32
- package/types/helper/converter.d.ts +4 -2
- package/types/helper/dom/domCheck.d.ts +12 -2
- package/types/helper/dom/domQuery.d.ts +35 -7
- package/types/helper/dom/domUtils.d.ts +4 -1
- package/types/interfaces/plugins.d.ts +2 -2
- package/types/langs/_Lang.d.ts +0 -1
- package/types/modules/contract/ColorPicker.d.ts +2 -2
- package/types/modules/contract/Controller.d.ts +7 -0
- package/types/modules/contract/Figure.d.ts +31 -4
- package/types/modules/ui/CommandMenu.d.ts +262 -0
- package/types/modules/ui/SelectMenu.d.ts +56 -3
- package/types/modules/ui/index.d.ts +1 -0
- package/types/plugins/browser/audioGallery.d.ts +1 -1
- package/types/plugins/browser/fileBrowser.d.ts +1 -1
- package/types/plugins/browser/fileGallery.d.ts +1 -1
- package/types/plugins/browser/imageGallery.d.ts +1 -1
- package/types/plugins/browser/videoGallery.d.ts +1 -1
- package/types/plugins/dropdown/align.d.ts +1 -1
- package/types/plugins/dropdown/blockStyle.d.ts +3 -1
- package/types/plugins/dropdown/table/index.d.ts +4 -1
- package/types/plugins/dropdown/table/services/table.clipboard.d.ts +5 -1
- package/types/plugins/dropdown/table/services/table.grid.d.ts +10 -2
- package/types/plugins/field/autocomplete.d.ts +0 -1
- package/types/plugins/field/slashCommand.d.ts +165 -0
- package/types/plugins/index.d.ts +3 -0
- package/types/plugins/modal/link.d.ts +4 -1
- package/types/typedef.d.ts +48 -23
|
@@ -4,7 +4,13 @@ import { _DragHandle } from '../../modules/ui';
|
|
|
4
4
|
|
|
5
5
|
// event handlers
|
|
6
6
|
import { ButtonsHandler, OnClick_menuTray, OnClick_toolbar } from '../event/handlers/handler_toolbar';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
OnMouseDown_wysiwyg,
|
|
9
|
+
OnMouseUp_wysiwyg,
|
|
10
|
+
OnClick_wysiwyg,
|
|
11
|
+
OnMouseMove_wysiwyg,
|
|
12
|
+
OnMouseLeave_wysiwyg,
|
|
13
|
+
} from '../event/handlers/handler_ww_mouse';
|
|
8
14
|
import { OnBeforeInput_wysiwyg, OnInput_wysiwyg } from '../event/handlers/handler_ww_input';
|
|
9
15
|
import { OnKeyDown_wysiwyg, OnKeyUp_wysiwyg } from '../event/handlers/handler_ww_key';
|
|
10
16
|
import { OnPaste_wysiwyg, OnCopy_wysiwyg, OnCut_wysiwyg } from '../event/handlers/handler_ww_clipboard';
|
|
@@ -106,9 +112,6 @@ class EventOrchestrator extends KernelInjector {
|
|
|
106
112
|
this.__eventDoc = null;
|
|
107
113
|
/** @type {string} */
|
|
108
114
|
this.__secopy = null;
|
|
109
|
-
|
|
110
|
-
/** @type {HTMLInputElement} */
|
|
111
|
-
this.__focusTemp = this.#contextProvider.carrierWrapper.querySelector('.__se__focus__temp__');
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
/**
|
|
@@ -200,6 +203,32 @@ class EventOrchestrator extends KernelInjector {
|
|
|
200
203
|
return this.defaultLineManager.execute(formatName);
|
|
201
204
|
}
|
|
202
205
|
|
|
206
|
+
/**
|
|
207
|
+
* @internal
|
|
208
|
+
* @description Normalize the Enter range before the reducer reads it: reset to a text node, and when the
|
|
209
|
+
* caret sits inside a zero-width text node adjacent to a `<br>`, move it onto the `<br>`.
|
|
210
|
+
* @returns {?(HTMLElement|Text)} The updated selection node, or `null` when the caret is not on a line (no normalization ran).
|
|
211
|
+
*/
|
|
212
|
+
_normalizeEnterRange() {
|
|
213
|
+
if (!this.$.format.isLine(this.$.selection.getRange()?.startContainer)) return null;
|
|
214
|
+
|
|
215
|
+
this.$.selection.resetRangeToTextNode();
|
|
216
|
+
|
|
217
|
+
const r = this.$.selection.getRange();
|
|
218
|
+
if (
|
|
219
|
+
r.startContainer === r.endContainer &&
|
|
220
|
+
r.startOffset !== r.endOffset &&
|
|
221
|
+
r.startContainer.nodeType === 3 &&
|
|
222
|
+
dom.check.isZeroWidth(r.startContainer)
|
|
223
|
+
) {
|
|
224
|
+
const br = r.startContainer.nextSibling;
|
|
225
|
+
if (br && dom.check.isBreak(br)) this.$.selection.setRange(br, 0, br, 0);
|
|
226
|
+
else this.$.selection.setRange(r.endContainer, r.endOffset, r.endContainer, r.endOffset);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return this.$.selection.getNode();
|
|
230
|
+
}
|
|
231
|
+
|
|
203
232
|
/**
|
|
204
233
|
* @internal
|
|
205
234
|
* @description Handles data transfer actions for `paste` and `drop` events.
|
|
@@ -245,14 +274,21 @@ class EventOrchestrator extends KernelInjector {
|
|
|
245
274
|
// SE copy data
|
|
246
275
|
const SEData = this.__secopy === plainText;
|
|
247
276
|
// MS word, OneNode, Excel
|
|
248
|
-
const MSData =
|
|
277
|
+
const MSData =
|
|
278
|
+
/class=["']*Mso(Normal|List)/i.test(cleanData) ||
|
|
279
|
+
/content=["']*Word.Document/i.test(cleanData) ||
|
|
280
|
+
/content=["']*OneNote.File/i.test(cleanData) ||
|
|
281
|
+
/content=["']*Excel.Sheet/i.test(cleanData);
|
|
249
282
|
// from
|
|
250
283
|
const from = SEData ? 'SE' : MSData ? 'MS' : '';
|
|
251
284
|
|
|
252
285
|
if (onlyText) {
|
|
253
286
|
cleanData = converter.htmlToEntity(plainText).replace(/\n/g, '<br>');
|
|
254
287
|
} else {
|
|
255
|
-
cleanData = cleanData.replace(
|
|
288
|
+
cleanData = cleanData.replace(
|
|
289
|
+
/^<html>\r?\n?<body>\r?\n?\x3C!--StartFragment-->|\x3C!--EndFragment-->\r?\n?<\/body>\r?\n?<\/html>$/g,
|
|
290
|
+
'',
|
|
291
|
+
);
|
|
256
292
|
if (MSData) {
|
|
257
293
|
cleanData = cleanData.replace(/\n/g, ' ');
|
|
258
294
|
plainText = plainText.replace(/\n/g, ' ');
|
|
@@ -273,10 +309,19 @@ class EventOrchestrator extends KernelInjector {
|
|
|
273
309
|
cleanData = this.$.html.clean(cleanData, { forceFormat: false, whitelist: null, blacklist: null });
|
|
274
310
|
}
|
|
275
311
|
|
|
276
|
-
const maxCharCount = this.$.char.test(
|
|
312
|
+
const maxCharCount = this.$.char.test(
|
|
313
|
+
this.$.frameOptions.get('charCounter_type') === 'byte-html' ? cleanData : plainText,
|
|
314
|
+
false,
|
|
315
|
+
);
|
|
277
316
|
// user event - paste
|
|
278
317
|
if (type === 'paste') {
|
|
279
|
-
const value = await this.#eventManager.triggerEvent('onPaste', {
|
|
318
|
+
const value = await this.#eventManager.triggerEvent('onPaste', {
|
|
319
|
+
frameContext,
|
|
320
|
+
event: e,
|
|
321
|
+
data: cleanData,
|
|
322
|
+
maxCharCount,
|
|
323
|
+
from,
|
|
324
|
+
});
|
|
280
325
|
if (value === false) {
|
|
281
326
|
return false;
|
|
282
327
|
} else if (typeof value === 'string') {
|
|
@@ -286,7 +331,13 @@ class EventOrchestrator extends KernelInjector {
|
|
|
286
331
|
}
|
|
287
332
|
// user event - drop
|
|
288
333
|
if (type === 'drop') {
|
|
289
|
-
const value = await this.#eventManager.triggerEvent('onDrop', {
|
|
334
|
+
const value = await this.#eventManager.triggerEvent('onDrop', {
|
|
335
|
+
frameContext,
|
|
336
|
+
event: e,
|
|
337
|
+
data: cleanData,
|
|
338
|
+
maxCharCount,
|
|
339
|
+
from,
|
|
340
|
+
});
|
|
290
341
|
if (value === false) {
|
|
291
342
|
return false;
|
|
292
343
|
} else if (typeof value === 'string') {
|
|
@@ -311,7 +362,14 @@ class EventOrchestrator extends KernelInjector {
|
|
|
311
362
|
|
|
312
363
|
if (cleanData) {
|
|
313
364
|
const domParser = new DOMParser().parseFromString(cleanData, 'text/html');
|
|
314
|
-
if (
|
|
365
|
+
if (
|
|
366
|
+
(await this._callPluginEventAsync('onPaste', {
|
|
367
|
+
frameContext,
|
|
368
|
+
event: e,
|
|
369
|
+
data: cleanData,
|
|
370
|
+
doc: domParser,
|
|
371
|
+
})) !== false
|
|
372
|
+
) {
|
|
315
373
|
this.$.html.insert(cleanData, { selectInserted: false, skipCharCount: true, skipCleaning: true });
|
|
316
374
|
}
|
|
317
375
|
|
|
@@ -422,12 +480,21 @@ class EventOrchestrator extends KernelInjector {
|
|
|
422
480
|
this.#eventManager.addEvent(
|
|
423
481
|
eventWysiwyg,
|
|
424
482
|
'dragover',
|
|
425
|
-
OnDragOver_wysiwyg.bind(
|
|
483
|
+
OnDragOver_wysiwyg.bind(
|
|
484
|
+
this,
|
|
485
|
+
fc,
|
|
486
|
+
dragCursor,
|
|
487
|
+
isIframe ? this.$.frameContext.get('topArea') : null,
|
|
488
|
+
!this.#options.get('toolbar_container') && !this.#store.mode.isBalloon && !this.#store.mode.isInline,
|
|
489
|
+
),
|
|
426
490
|
false,
|
|
427
491
|
);
|
|
428
492
|
this.#eventManager.addEvent(eventWysiwyg, 'dragend', OnDragEnd_wysiwyg.bind(this, dragCursor), false);
|
|
429
493
|
this.#eventManager.addEvent(eventWysiwyg, 'drop', OnDrop_wysiwyg.bind(this, fc, dragCursor), false);
|
|
430
|
-
this.#eventManager.addEvent(eventWysiwyg, 'scroll', this.#OnScroll_wysiwyg.bind(this, fc, eventWysiwyg), {
|
|
494
|
+
this.#eventManager.addEvent(eventWysiwyg, 'scroll', this.#OnScroll_wysiwyg.bind(this, fc, eventWysiwyg), {
|
|
495
|
+
passive: true,
|
|
496
|
+
capture: false,
|
|
497
|
+
});
|
|
431
498
|
this.#eventManager.addEvent(eventWysiwyg, 'focus', this.#OnFocus_wysiwyg.bind(this, fc), false);
|
|
432
499
|
this.#eventManager.addEvent(eventWysiwyg, 'blur', this.#OnBlur_wysiwyg.bind(this, fc), false);
|
|
433
500
|
this.#eventManager.addEvent(codeArea, 'mousedown', this.#OnFocus_code.bind(this, fc), false);
|
|
@@ -445,8 +512,18 @@ class EventOrchestrator extends KernelInjector {
|
|
|
445
512
|
);
|
|
446
513
|
|
|
447
514
|
/** line breaker */
|
|
448
|
-
this.#eventManager.addEvent(
|
|
449
|
-
|
|
515
|
+
this.#eventManager.addEvent(
|
|
516
|
+
fc.get('lineBreaker_t'),
|
|
517
|
+
'pointerdown',
|
|
518
|
+
this.#DisplayLineBreak.bind(this, 't'),
|
|
519
|
+
false,
|
|
520
|
+
);
|
|
521
|
+
this.#eventManager.addEvent(
|
|
522
|
+
fc.get('lineBreaker_b'),
|
|
523
|
+
'pointerdown',
|
|
524
|
+
this.#DisplayLineBreak.bind(this, 'b'),
|
|
525
|
+
false,
|
|
526
|
+
);
|
|
450
527
|
|
|
451
528
|
/** Events are registered mobile. */
|
|
452
529
|
if (isTouchDevice) {
|
|
@@ -459,7 +536,12 @@ class EventOrchestrator extends KernelInjector {
|
|
|
459
536
|
/** code view area auto line */
|
|
460
537
|
if (!this.#options.get('hasCodeMirror')) {
|
|
461
538
|
const codeNumbers = fc.get('codeNumbers');
|
|
462
|
-
const cvAuthHeight = this.$.viewer._codeViewAutoHeight.bind(
|
|
539
|
+
const cvAuthHeight = this.$.viewer._codeViewAutoHeight.bind(
|
|
540
|
+
this.$.viewer,
|
|
541
|
+
fc.get('code'),
|
|
542
|
+
codeNumbers,
|
|
543
|
+
this.$.frameOptions.get('height') === 'auto',
|
|
544
|
+
);
|
|
463
545
|
|
|
464
546
|
this.#eventManager.addEvent(codeArea, 'keydown', cvAuthHeight, false);
|
|
465
547
|
this.#eventManager.addEvent(codeArea, 'keyup', cvAuthHeight, false);
|
|
@@ -471,7 +553,13 @@ class EventOrchestrator extends KernelInjector {
|
|
|
471
553
|
}
|
|
472
554
|
|
|
473
555
|
/** code view numbers */
|
|
474
|
-
if (codeNumbers)
|
|
556
|
+
if (codeNumbers)
|
|
557
|
+
this.#eventManager.addEvent(
|
|
558
|
+
codeArea,
|
|
559
|
+
'scroll',
|
|
560
|
+
this.$.viewer._scrollLineNumbers.bind(codeArea, codeNumbers),
|
|
561
|
+
false,
|
|
562
|
+
);
|
|
475
563
|
}
|
|
476
564
|
|
|
477
565
|
/** markdown view area */
|
|
@@ -480,7 +568,12 @@ class EventOrchestrator extends KernelInjector {
|
|
|
480
568
|
this.#eventManager.addEvent(markdownArea, 'mousedown', this.#OnFocus_markdown.bind(this, fc), false);
|
|
481
569
|
|
|
482
570
|
const mdNumbers = fc.get('markdownNumbers');
|
|
483
|
-
const mdAutoHeight = this.$.viewer._markdownViewAutoHeight.bind(
|
|
571
|
+
const mdAutoHeight = this.$.viewer._markdownViewAutoHeight.bind(
|
|
572
|
+
this.$.viewer,
|
|
573
|
+
markdownArea,
|
|
574
|
+
mdNumbers,
|
|
575
|
+
this.$.frameOptions.get('height') === 'auto',
|
|
576
|
+
);
|
|
484
577
|
|
|
485
578
|
this.#eventManager.addEvent(markdownArea, 'keydown', mdAutoHeight, false);
|
|
486
579
|
this.#eventManager.addEvent(markdownArea, 'keyup', mdAutoHeight, false);
|
|
@@ -491,7 +584,13 @@ class EventOrchestrator extends KernelInjector {
|
|
|
491
584
|
this.#eventManager.addEvent(markdownArea, 'keydown', InsertTab, false);
|
|
492
585
|
}
|
|
493
586
|
|
|
494
|
-
if (mdNumbers)
|
|
587
|
+
if (mdNumbers)
|
|
588
|
+
this.#eventManager.addEvent(
|
|
589
|
+
markdownArea,
|
|
590
|
+
'scroll',
|
|
591
|
+
this.$.viewer._scrollMarkdownLineNumbers.bind(markdownArea, mdNumbers),
|
|
592
|
+
false,
|
|
593
|
+
);
|
|
495
594
|
}
|
|
496
595
|
|
|
497
596
|
if (fc.has('statusbar')) this.__addStatusbarEvent(fc, fc.get('options'));
|
|
@@ -503,13 +602,15 @@ class EventOrchestrator extends KernelInjector {
|
|
|
503
602
|
this.#eventManager.addEvent(parent, 'scroll', OnScrollAbs, false);
|
|
504
603
|
}
|
|
505
604
|
|
|
506
|
-
/** focus temp (mobile) */
|
|
507
|
-
this.#eventManager.addEvent(this.__focusTemp, 'focus', (e) => e.preventDefault(), false);
|
|
508
|
-
|
|
509
605
|
/** document event */
|
|
510
606
|
if (this.__eventDoc !== fc.get('_wd')) {
|
|
511
607
|
this.__eventDoc = fc.get('_wd');
|
|
512
|
-
this.#eventManager.addEvent(
|
|
608
|
+
this.#eventManager.addEvent(
|
|
609
|
+
this.__eventDoc,
|
|
610
|
+
'selectionchange',
|
|
611
|
+
this.#OnSelectionchange_document.bind(this, this.__eventDoc),
|
|
612
|
+
false,
|
|
613
|
+
);
|
|
513
614
|
}
|
|
514
615
|
}
|
|
515
616
|
|
|
@@ -522,7 +623,15 @@ class EventOrchestrator extends KernelInjector {
|
|
|
522
623
|
*/
|
|
523
624
|
__addStatusbarEvent(fc, fo) {
|
|
524
625
|
if (/\d+/.test(fo.get('height')) && fo.get('statusbar_resizeEnable')) {
|
|
525
|
-
fo.set(
|
|
626
|
+
fo.set(
|
|
627
|
+
'__statusbarEvent',
|
|
628
|
+
this.#eventManager.addEvent(
|
|
629
|
+
fc.get('statusbar'),
|
|
630
|
+
'mousedown',
|
|
631
|
+
this.#OnMouseDown_statusbar.bind(this),
|
|
632
|
+
false,
|
|
633
|
+
),
|
|
634
|
+
);
|
|
526
635
|
} else {
|
|
527
636
|
dom.utils.addClass(fc.get('statusbar'), 'se-resizing-none');
|
|
528
637
|
}
|
|
@@ -569,7 +678,6 @@ class EventOrchestrator extends KernelInjector {
|
|
|
569
678
|
this.__inputPlugin = null;
|
|
570
679
|
this.__inputBlurEvent = null;
|
|
571
680
|
this.__inputKeyEvent = null;
|
|
572
|
-
this.__focusTemp = null;
|
|
573
681
|
this.__eventDoc = null;
|
|
574
682
|
this.__secopy = null;
|
|
575
683
|
this._lineBreakComp = null;
|
|
@@ -673,6 +781,9 @@ class EventOrchestrator extends KernelInjector {
|
|
|
673
781
|
// sticky
|
|
674
782
|
this.#toolbar._resetSticky();
|
|
675
783
|
|
|
784
|
+
// placeholder
|
|
785
|
+
this.#ui._updatePlaceholder(frameContext);
|
|
786
|
+
|
|
676
787
|
// user event
|
|
677
788
|
this.#eventManager.triggerEvent('onFocus', { frameContext, event });
|
|
678
789
|
// plugin event
|
|
@@ -735,12 +846,14 @@ class EventOrchestrator extends KernelInjector {
|
|
|
735
846
|
}
|
|
736
847
|
|
|
737
848
|
const toolbar = this.#context.get('toolbar_main');
|
|
738
|
-
const isToolbarHidden =
|
|
849
|
+
const isToolbarHidden =
|
|
850
|
+
toolbar.style.display === 'none' || (this.#store.mode.isInline && !this.#toolbar.inlineToolbarAttr.isShow);
|
|
739
851
|
if (toolbar.offsetWidth === 0 && !isToolbarHidden) return;
|
|
740
852
|
|
|
741
853
|
const opendBrowser = this.#ui.opendBrowser;
|
|
742
854
|
if (opendBrowser && opendBrowser.area.style.display === 'block') {
|
|
743
|
-
opendBrowser.body.style.maxHeight =
|
|
855
|
+
opendBrowser.body.style.maxHeight =
|
|
856
|
+
dom.utils.getClientSize().h - opendBrowser.header.offsetHeight - 50 + 'px';
|
|
744
857
|
}
|
|
745
858
|
|
|
746
859
|
if (this.#menu.currentDropdownActiveButton && this.#menu.currentDropdown) {
|
|
@@ -812,7 +925,11 @@ class EventOrchestrator extends KernelInjector {
|
|
|
812
925
|
return;
|
|
813
926
|
}
|
|
814
927
|
|
|
815
|
-
if (
|
|
928
|
+
if (
|
|
929
|
+
(this.#store.get('rootKey') === rootKey && this.#store.get('_preventBlur')) ||
|
|
930
|
+
this.#store.get('_preventFocus')
|
|
931
|
+
)
|
|
932
|
+
return;
|
|
816
933
|
this.#store.set('_preventFocus', true);
|
|
817
934
|
|
|
818
935
|
dom.utils.removeClass(this.$.commandDispatcher.targets.get('codeView'), 'active');
|
|
@@ -838,6 +955,9 @@ class EventOrchestrator extends KernelInjector {
|
|
|
838
955
|
this.#store.set('_lastSelectionNode', null);
|
|
839
956
|
this.#eventManager.triggerEvent('onNativeBlur', { frameContext, event: e });
|
|
840
957
|
|
|
958
|
+
// Drop the per-line placeholder on blur; the empty-editor placeholder takes over if applicable.
|
|
959
|
+
this.#ui._updatePlaceholder(frameContext);
|
|
960
|
+
|
|
841
961
|
if (this._inputFocus || this.#store.get('_preventBlur')) return;
|
|
842
962
|
this.#store.set('_preventFocus', false);
|
|
843
963
|
|
|
@@ -897,7 +1017,9 @@ class EventOrchestrator extends KernelInjector {
|
|
|
897
1017
|
if (!component) return;
|
|
898
1018
|
|
|
899
1019
|
const isList = dom.check.isListCell(component.parentElement);
|
|
900
|
-
const format = dom.utils.createElement(
|
|
1020
|
+
const format = dom.utils.createElement(
|
|
1021
|
+
isList ? 'BR' : dom.check.isTableCell(component.parentElement) ? 'DIV' : this.#options.get('defaultLine'),
|
|
1022
|
+
);
|
|
901
1023
|
if (!isList) format.innerHTML = '<br>';
|
|
902
1024
|
|
|
903
1025
|
if (this.$.frameOptions.get('charCounter_type') === 'byte-html' && !this.$.char.check(format.outerHTML)) return;
|
|
@@ -939,7 +1061,11 @@ class EventOrchestrator extends KernelInjector {
|
|
|
939
1061
|
this.__setViewportSize();
|
|
940
1062
|
|
|
941
1063
|
if (isMobile && prevHeight > 0 && prevHeight - _w.visualViewport.height > 100 && this.#store.get('hasFocus')) {
|
|
942
|
-
this.$.selection.scrollTo(this.$.selection.getRange(), {
|
|
1064
|
+
this.$.selection.scrollTo(this.$.selection.getRange(), {
|
|
1065
|
+
behavior: 'auto',
|
|
1066
|
+
block: 'nearest',
|
|
1067
|
+
inline: 'nearest',
|
|
1068
|
+
});
|
|
943
1069
|
}
|
|
944
1070
|
}
|
|
945
1071
|
|
|
@@ -984,6 +1110,9 @@ class EventOrchestrator extends KernelInjector {
|
|
|
984
1110
|
this.$.selection.init();
|
|
985
1111
|
this.applyTagEffect();
|
|
986
1112
|
|
|
1113
|
+
// Notion-style per-line placeholder follows the caret's line.
|
|
1114
|
+
this.#ui._updatePlaceholder(root);
|
|
1115
|
+
|
|
987
1116
|
// balloon toolbar - touch devices
|
|
988
1117
|
if (isTouchDevice && (this.#store.mode.isBalloon || this.#store.mode.isSubBalloon)) {
|
|
989
1118
|
this.#toggleToolbarBalloonDelay();
|
|
@@ -991,7 +1120,10 @@ class EventOrchestrator extends KernelInjector {
|
|
|
991
1120
|
|
|
992
1121
|
// document type
|
|
993
1122
|
if (root.has('documentType_use_header')) {
|
|
994
|
-
const el = dom.query.getParentElement(
|
|
1123
|
+
const el = dom.query.getParentElement(
|
|
1124
|
+
this.$.selection.selectionNode,
|
|
1125
|
+
this.$.format.isLine.bind(this.$.format),
|
|
1126
|
+
);
|
|
995
1127
|
root.get('documentType').on(el);
|
|
996
1128
|
}
|
|
997
1129
|
}
|
|
@@ -53,13 +53,15 @@ export function ButtonsHandler(e) {
|
|
|
53
53
|
if (this.__inputBlurEvent) this.__removeInput();
|
|
54
54
|
|
|
55
55
|
// blur event
|
|
56
|
-
if (typeof plugin.toolbarInputChange === 'function')
|
|
56
|
+
if (typeof plugin.toolbarInputChange === 'function')
|
|
57
|
+
this.__inputPlugin = { obj: plugin, target: eventTarget, value: eventTarget.value };
|
|
57
58
|
this.__inputBlurEvent = this.$.eventManager.addEvent(eventTarget, 'blur', (ev) => {
|
|
58
59
|
if (plugin.isInputActive) return;
|
|
59
60
|
|
|
60
61
|
try {
|
|
61
62
|
const value = eventTarget.value.trim();
|
|
62
|
-
if (typeof plugin.toolbarInputChange === 'function' && value !== this.__inputPlugin.value)
|
|
63
|
+
if (typeof plugin.toolbarInputChange === 'function' && value !== this.__inputPlugin.value)
|
|
64
|
+
plugin.toolbarInputChange({ target: eventTarget, value, event: ev });
|
|
63
65
|
} finally {
|
|
64
66
|
// Defer flag reset — wysiwyg focus event fires synchronously during blur and checks this flag
|
|
65
67
|
_w.setTimeout(() => (this._inputFocus = false), 0);
|
|
@@ -16,6 +16,11 @@ const { _w } = env;
|
|
|
16
16
|
* @param {DragEvent} e - Event object
|
|
17
17
|
*/
|
|
18
18
|
export function OnDragOver_wysiwyg(fc, dragCursor, _iframeTopArea, _innerToolbar, e) {
|
|
19
|
+
// Block-handle drag uses its own indicator + drop logic — skip the component
|
|
20
|
+
if (e.dataTransfer && Array.from(e.dataTransfer.types || []).includes('application/x-suneditor-block-drag')) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
19
24
|
const { sc, so, ec, eo } = this.$.selection.getDragEventLocationRange(e);
|
|
20
25
|
if (!sc) return;
|
|
21
26
|
|
|
@@ -91,6 +96,11 @@ export function OnDrop_wysiwyg(fc, dragCursor, e) {
|
|
|
91
96
|
const dataTransfer = e.dataTransfer;
|
|
92
97
|
if (!dataTransfer) return true;
|
|
93
98
|
|
|
99
|
+
// Block-handle drag handles its own drop — skip the text-insertion path.
|
|
100
|
+
if (Array.from(dataTransfer.types || []).includes('application/x-suneditor-block-drag')) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
94
104
|
const { sc, so, ec, eo } = this.$.selection.getDragEventLocationRange(e);
|
|
95
105
|
if (!sc) return;
|
|
96
106
|
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { dom, keyCodeMap } from '../../../helper';
|
|
2
|
+
import { actionExecutor } from '../executor';
|
|
3
|
+
import { makePorts } from '../ports';
|
|
4
|
+
import { reduceEnterDown } from '../rules/keydown.rule.enter';
|
|
5
|
+
import { ENTER_FROM_BEFOREINPUT } from '../reducers/keydown.reducer';
|
|
6
|
+
|
|
7
|
+
// The Enter rule/effects never touch the retain-style node cache (a backspace concern) — a local
|
|
8
|
+
// placeholder is enough to satisfy `makePorts`.
|
|
9
|
+
const _enterStyleNodes = { value: [] };
|
|
2
10
|
|
|
3
11
|
/**
|
|
4
12
|
* @typedef {import('../eventOrchestrator').default} EventManagerThis_handler_ww_input
|
|
@@ -16,6 +24,14 @@ export async function OnBeforeInput_wysiwyg(fc, e) {
|
|
|
16
24
|
return false;
|
|
17
25
|
}
|
|
18
26
|
|
|
27
|
+
// Enter is dispatched here — not on keydown — so the IME has finished committing before the DOM
|
|
28
|
+
// mutates (iOS/mobile marked-text stability). `insertParagraph` = Enter, `insertLineBreak` = Shift+Enter.
|
|
29
|
+
// ctrl/alt+Enter are shortcuts and never produce these inputTypes, so they stay on the keydown path.
|
|
30
|
+
if (ENTER_FROM_BEFOREINPUT && (e.inputType === 'insertParagraph' || e.inputType === 'insertLineBreak')) {
|
|
31
|
+
await dispatchEnter.call(this, fc, e);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || '';
|
|
20
36
|
if (!keyCodeMap.isComposing(e)) {
|
|
21
37
|
if (!this.$.char.test(data, false)) {
|
|
@@ -29,11 +45,71 @@ export async function OnBeforeInput_wysiwyg(fc, e) {
|
|
|
29
45
|
}
|
|
30
46
|
|
|
31
47
|
// user event
|
|
32
|
-
if ((await this.$.eventManager.triggerEvent('onBeforeInput', { frameContext: fc, event: e, data })) === false)
|
|
48
|
+
if ((await this.$.eventManager.triggerEvent('onBeforeInput', { frameContext: fc, event: e, data })) === false)
|
|
49
|
+
return;
|
|
33
50
|
// plugin event
|
|
34
51
|
await this._callPluginEventAsync('onBeforeInput', { frameContext: fc, event: e, data });
|
|
35
52
|
}
|
|
36
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @this {EventManagerThis_handler_ww_input}
|
|
56
|
+
* @description Runs SunEditor's Enter logic from the `beforeinput` event (post-IME-commit) by reusing the
|
|
57
|
+
* exact keydown Enter rule + effects — only the dispatch site moves off keydown. See ENTER_FROM_BEFOREINPUT.
|
|
58
|
+
* The guards mirror `OnKeyDown_wysiwyg` (selectMenu, input-element, open-dropdown) so a `beforeinput` Enter
|
|
59
|
+
* is dropped in the same situations a keydown Enter is.
|
|
60
|
+
* @param {SunEditor.FrameContext} fc - Frame context object
|
|
61
|
+
* @param {InputEvent} e - The `beforeinput` event (`insertParagraph` | `insertLineBreak`)
|
|
62
|
+
*/
|
|
63
|
+
async function dispatchEnter(fc, e) {
|
|
64
|
+
// Skip while an IME composition is still active
|
|
65
|
+
if (e.isComposing || this.isComposing) return;
|
|
66
|
+
if (this.$.ui.selectMenuOn) return;
|
|
67
|
+
|
|
68
|
+
let selectionNode = this.$.selection.getNode();
|
|
69
|
+
if (dom.check.isInputElement(selectionNode)) return;
|
|
70
|
+
if (this.$.menu.currentDropdownName) return;
|
|
71
|
+
|
|
72
|
+
if (dom.check.isWysiwygFrame(selectionNode)) {
|
|
73
|
+
this._setDefaultLine(this.$.options.get('defaultLine'));
|
|
74
|
+
selectionNode = this.$.selection.getNode();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const normalized = this._normalizeEnterRange();
|
|
78
|
+
if (normalized) selectionNode = normalized;
|
|
79
|
+
|
|
80
|
+
const range = this.$.selection.getRange();
|
|
81
|
+
const formatEl = /** @type {HTMLElement} */ (this.$.format.getLine(selectionNode, null) || selectionNode);
|
|
82
|
+
const shift = e.inputType === 'insertLineBreak';
|
|
83
|
+
|
|
84
|
+
/** @type {import('../reducers/keydown.reducer').KeydownReducerCtx} */
|
|
85
|
+
const ctx = {
|
|
86
|
+
e,
|
|
87
|
+
fc,
|
|
88
|
+
store: this.$.store,
|
|
89
|
+
options: this.$.options,
|
|
90
|
+
frameOptions: this.$.frameOptions,
|
|
91
|
+
range,
|
|
92
|
+
selectionNode,
|
|
93
|
+
formatEl,
|
|
94
|
+
keyCode: 'Enter',
|
|
95
|
+
ctrl: false,
|
|
96
|
+
alt: false,
|
|
97
|
+
shift,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const ports = makePorts(this, { _styleNodes: _enterStyleNodes });
|
|
101
|
+
const actions = [];
|
|
102
|
+
reduceEnterDown(actions, ports, ctx);
|
|
103
|
+
|
|
104
|
+
// `beforeinput.preventDefault()` MUST run synchronously (before the first `await` below), or the browser
|
|
105
|
+
// commits its native insertParagraph/insertLineBreak on top of ours (duplicate line / cloned container).
|
|
106
|
+
if (actions.some((a) => a.t === 'event.prevent' || a.t === 'event.prevent.stop')) {
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await actionExecutor(actions, { ports, ctx });
|
|
111
|
+
}
|
|
112
|
+
|
|
37
113
|
/**
|
|
38
114
|
* @this {EventManagerThis_handler_ww_input}
|
|
39
115
|
* @param {SunEditor.FrameContext} fc - Frame context object
|
|
@@ -49,7 +125,13 @@ export async function OnInput_wysiwyg(fc, e) {
|
|
|
49
125
|
const range = this.$.selection.getRange();
|
|
50
126
|
const selectionNode = this.$.selection.getNode();
|
|
51
127
|
const formatEl = this.$.format.getLine(selectionNode, null);
|
|
52
|
-
if (
|
|
128
|
+
if (
|
|
129
|
+
!this.$.format.isNormalLine(formatEl) &&
|
|
130
|
+
!this.$.format.isBrLine(formatEl) &&
|
|
131
|
+
range.collapsed &&
|
|
132
|
+
!this.$.component.is(selectionNode) &&
|
|
133
|
+
!dom.check.isList(selectionNode)
|
|
134
|
+
) {
|
|
53
135
|
const rangeEl = this.$.format.getBlock(selectionNode, null);
|
|
54
136
|
this._setDefaultLine(this.$.format.isBlock(rangeEl) ? 'DIV' : this.$.options.get('defaultLine'));
|
|
55
137
|
}
|