suneditor 3.0.0-beta.9 → 3.0.0-rc.2
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/README.md +65 -57
- package/dist/suneditor-contents.min.css +1 -0
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +110 -61
- package/src/assets/design/color.css +36 -17
- package/src/assets/design/size.css +2 -0
- package/src/assets/icons/defaultIcons.js +17 -2
- package/src/assets/suneditor-contents.css +51 -16
- package/src/assets/suneditor.css +116 -43
- package/src/core/config/contextProvider.js +288 -0
- package/src/core/config/eventManager.js +188 -0
- package/src/core/config/instanceCheck.js +59 -0
- package/src/core/config/optionProvider.js +452 -0
- package/src/core/editor.js +166 -1637
- package/src/core/event/actions/index.js +229 -0
- package/src/core/event/effects/common.registry.js +74 -0
- package/src/core/event/effects/keydown.registry.js +573 -0
- package/src/core/event/effects/ruleHelpers.js +148 -0
- package/src/core/event/eventOrchestrator.js +944 -0
- package/src/core/event/executor.js +27 -0
- package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +27 -28
- package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +10 -8
- package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +22 -23
- package/src/core/event/handlers/handler_ww_input.js +75 -0
- package/src/core/event/handlers/handler_ww_key.js +228 -0
- package/src/core/event/handlers/handler_ww_mouse.js +166 -0
- package/src/core/event/ports.js +211 -0
- package/src/core/event/reducers/keydown.reducer.js +97 -0
- package/src/core/event/rules/keydown.rule.arrow.js +63 -0
- package/src/core/event/rules/keydown.rule.backspace.js +208 -0
- package/src/core/event/rules/keydown.rule.delete.js +132 -0
- package/src/core/event/rules/keydown.rule.enter.js +150 -0
- package/src/core/event/rules/keydown.rule.tab.js +35 -0
- package/src/core/event/support/defaultLineManager.js +136 -0
- package/src/core/event/support/selectionState.js +204 -0
- package/src/core/kernel/coreKernel.js +320 -0
- package/src/core/kernel/kernelInjector.js +19 -0
- package/src/core/kernel/store.js +173 -0
- package/src/core/{class → logic/dom}/char.js +42 -45
- package/src/core/logic/dom/format.js +1075 -0
- package/src/core/{class → logic/dom}/html.js +743 -624
- package/src/core/logic/dom/inline.js +1847 -0
- package/src/core/logic/dom/listFormat.js +601 -0
- package/src/core/{class → logic/dom}/nodeTransform.js +92 -72
- package/src/core/{class → logic/dom}/offset.js +254 -317
- package/src/core/logic/dom/selection.js +754 -0
- package/src/core/logic/panel/menu.js +389 -0
- package/src/core/logic/panel/toolbar.js +449 -0
- package/src/core/logic/panel/viewer.js +761 -0
- package/src/core/logic/shell/_commandExecutor.js +380 -0
- package/src/core/logic/shell/commandDispatcher.js +241 -0
- package/src/core/logic/shell/component.js +970 -0
- package/src/core/logic/shell/focusManager.js +110 -0
- package/src/core/{base → logic/shell}/history.js +110 -60
- package/src/core/logic/shell/pluginManager.js +363 -0
- package/src/core/logic/shell/shortcuts.js +130 -0
- package/src/core/logic/shell/ui.js +904 -0
- package/src/core/schema/context.js +66 -0
- package/src/core/schema/frameContext.js +160 -0
- package/src/core/schema/options.js +628 -0
- package/src/core/section/constructor.js +194 -500
- package/src/core/section/documentType.js +297 -222
- package/src/events.js +808 -543
- package/src/helper/clipboard.js +27 -16
- package/src/helper/converter.js +100 -78
- package/src/helper/dom/domCheck.js +56 -30
- package/src/helper/dom/domQuery.js +159 -89
- package/src/helper/dom/domUtils.js +114 -49
- package/src/helper/dom/index.js +5 -1
- package/src/helper/env.js +26 -26
- package/src/helper/index.js +1 -1
- package/src/helper/keyCodeMap.js +25 -28
- package/src/helper/numbers.js +4 -8
- package/src/helper/unicode.js +4 -8
- package/src/hooks/base.js +307 -0
- package/src/hooks/params.js +130 -0
- package/src/interfaces/contracts.js +227 -0
- package/src/interfaces/index.js +7 -0
- package/src/interfaces/plugins.js +239 -0
- package/src/langs/ckb.js +4 -4
- package/src/langs/cs.js +4 -4
- package/src/langs/da.js +4 -4
- package/src/langs/de.js +4 -4
- package/src/langs/en.js +4 -4
- package/src/langs/es.js +4 -4
- package/src/langs/fa.js +4 -4
- package/src/langs/fr.js +4 -4
- package/src/langs/he.js +4 -4
- package/src/langs/hu.js +4 -4
- package/src/langs/it.js +4 -4
- package/src/langs/ja.js +4 -4
- package/src/langs/km.js +4 -4
- package/src/langs/ko.js +4 -4
- package/src/langs/lv.js +4 -4
- package/src/langs/nl.js +4 -4
- package/src/langs/pl.js +4 -4
- package/src/langs/pt_br.js +13 -13
- package/src/langs/ro.js +4 -4
- package/src/langs/ru.js +4 -4
- package/src/langs/se.js +4 -4
- package/src/langs/tr.js +4 -4
- package/src/langs/uk.js +4 -4
- package/src/langs/ur.js +4 -4
- package/src/langs/zh_cn.js +4 -4
- package/src/modules/{Browser.js → contract/Browser.js} +119 -128
- package/src/modules/{ColorPicker.js → contract/ColorPicker.js} +132 -142
- package/src/modules/contract/Controller.js +589 -0
- package/src/modules/{Figure.js → contract/Figure.js} +591 -411
- package/src/modules/{HueSlider.js → contract/HueSlider.js} +125 -86
- package/src/modules/contract/Modal.js +357 -0
- package/src/modules/contract/index.js +9 -0
- package/src/modules/manager/ApiManager.js +197 -0
- package/src/modules/{FileManager.js → manager/FileManager.js} +128 -160
- package/src/modules/manager/index.js +5 -0
- package/src/modules/{ModalAnchorEditor.js → ui/ModalAnchorEditor.js} +108 -138
- package/src/modules/{SelectMenu.js → ui/SelectMenu.js} +119 -120
- package/src/modules/{_DragHandle.js → ui/_DragHandle.js} +1 -1
- package/src/modules/ui/index.js +6 -0
- package/src/plugins/browser/audioGallery.js +23 -26
- package/src/plugins/browser/fileBrowser.js +25 -28
- package/src/plugins/browser/fileGallery.js +20 -23
- package/src/plugins/browser/imageGallery.js +24 -23
- package/src/plugins/browser/videoGallery.js +27 -29
- package/src/plugins/command/blockquote.js +11 -17
- package/src/plugins/command/exportPDF.js +26 -26
- package/src/plugins/command/fileUpload.js +138 -133
- package/src/plugins/command/list_bulleted.js +48 -44
- package/src/plugins/command/list_numbered.js +48 -44
- package/src/plugins/dropdown/align.js +64 -50
- package/src/plugins/dropdown/backgroundColor.js +34 -35
- package/src/plugins/dropdown/{formatBlock.js → blockStyle.js} +43 -37
- package/src/plugins/dropdown/font.js +50 -36
- package/src/plugins/dropdown/fontColor.js +34 -35
- package/src/plugins/dropdown/hr.js +55 -50
- package/src/plugins/dropdown/layout.js +20 -15
- package/src/plugins/dropdown/lineHeight.js +46 -30
- package/src/plugins/dropdown/list.js +32 -33
- package/src/plugins/dropdown/paragraphStyle.js +40 -34
- package/src/plugins/dropdown/table/index.js +915 -0
- package/src/plugins/dropdown/table/render/table.html.js +308 -0
- package/src/plugins/dropdown/table/render/table.menu.js +121 -0
- package/src/plugins/dropdown/table/services/table.cell.js +465 -0
- package/src/plugins/dropdown/table/services/table.clipboard.js +414 -0
- package/src/plugins/dropdown/table/services/table.grid.js +504 -0
- package/src/plugins/dropdown/table/services/table.resize.js +463 -0
- package/src/plugins/dropdown/table/services/table.selection.js +466 -0
- package/src/plugins/dropdown/table/services/table.style.js +844 -0
- package/src/plugins/dropdown/table/shared/table.constants.js +109 -0
- package/src/plugins/dropdown/table/shared/table.utils.js +219 -0
- package/src/plugins/dropdown/template.js +20 -15
- package/src/plugins/dropdown/textStyle.js +28 -22
- package/src/plugins/field/mention.js +54 -49
- package/src/plugins/index.js +5 -5
- package/src/plugins/input/fontSize.js +100 -97
- package/src/plugins/input/pageNavigator.js +13 -10
- package/src/plugins/modal/audio.js +208 -219
- package/src/plugins/modal/drawing.js +99 -104
- package/src/plugins/modal/embed.js +323 -312
- package/src/plugins/modal/image/index.js +942 -0
- package/src/plugins/modal/image/render/image.html.js +150 -0
- package/src/plugins/modal/image/services/image.size.js +198 -0
- package/src/plugins/modal/image/services/image.upload.js +216 -0
- package/src/plugins/modal/image/shared/image.constants.js +20 -0
- package/src/plugins/modal/link.js +74 -54
- package/src/plugins/modal/math.js +126 -119
- package/src/plugins/modal/video/index.js +858 -0
- package/src/plugins/modal/video/render/video.html.js +131 -0
- package/src/plugins/modal/video/services/video.size.js +281 -0
- package/src/plugins/modal/video/services/video.upload.js +92 -0
- package/src/plugins/popup/anchor.js +57 -49
- package/src/suneditor.js +73 -61
- package/src/themes/cobalt.css +155 -0
- package/src/themes/dark.css +143 -120
- package/src/typedef.js +214 -63
- package/types/assets/icons/defaultIcons.d.ts +8 -0
- package/types/assets/suneditor-contents.css.d.ts +1 -0
- package/types/assets/suneditor.css.d.ts +1 -0
- package/types/core/config/contextProvider.d.ts +148 -0
- package/types/core/config/eventManager.d.ts +68 -0
- package/types/core/config/instanceCheck.d.ts +33 -0
- package/types/core/config/optionProvider.d.ts +147 -0
- package/types/core/editor.d.ts +27 -586
- package/types/core/event/actions/index.d.ts +50 -0
- package/types/core/event/effects/common.registry.d.ts +56 -0
- package/types/core/event/effects/keydown.registry.d.ts +80 -0
- package/types/core/event/effects/ruleHelpers.d.ts +36 -0
- package/types/core/event/eventOrchestrator.d.ts +191 -0
- package/types/core/event/executor.d.ts +13 -0
- package/types/core/event/handlers/handler_toolbar.d.ts +38 -0
- package/types/core/event/handlers/handler_ww_clipboard.d.ts +36 -0
- package/types/core/event/handlers/handler_ww_dragDrop.d.ts +26 -0
- package/types/core/event/handlers/handler_ww_input.d.ts +38 -0
- package/types/core/event/handlers/handler_ww_key.d.ts +40 -0
- package/types/core/event/handlers/handler_ww_mouse.d.ts +47 -0
- package/types/core/event/ports.d.ts +256 -0
- package/types/core/event/reducers/keydown.reducer.d.ts +84 -0
- package/types/core/event/rules/keydown.rule.arrow.d.ts +19 -0
- package/types/core/event/rules/keydown.rule.backspace.d.ts +18 -0
- package/types/core/event/rules/keydown.rule.delete.d.ts +18 -0
- package/types/core/event/rules/keydown.rule.enter.d.ts +18 -0
- package/types/core/event/rules/keydown.rule.tab.d.ts +18 -0
- package/types/core/event/support/defaultLineManager.d.ts +22 -0
- package/types/core/event/support/selectionState.d.ts +29 -0
- package/types/core/kernel/coreKernel.d.ts +219 -0
- package/types/core/kernel/kernelInjector.d.ts +16 -0
- package/types/core/kernel/store.d.ts +170 -0
- package/types/core/logic/dom/char.d.ts +46 -0
- package/types/core/logic/dom/format.d.ts +234 -0
- package/types/core/logic/dom/html.d.ts +290 -0
- package/types/core/logic/dom/inline.d.ts +93 -0
- package/types/core/logic/dom/listFormat.d.ts +101 -0
- package/types/core/logic/dom/nodeTransform.d.ts +110 -0
- package/types/core/logic/dom/offset.d.ts +335 -0
- package/types/core/logic/dom/selection.d.ts +165 -0
- package/types/core/logic/panel/menu.d.ts +93 -0
- package/types/core/logic/panel/toolbar.d.ts +128 -0
- package/types/core/logic/panel/viewer.d.ts +89 -0
- package/types/core/logic/shell/_commandExecutor.d.ts +18 -0
- package/types/core/logic/shell/commandDispatcher.d.ts +65 -0
- package/types/core/logic/shell/component.d.ts +182 -0
- package/types/core/logic/shell/focusManager.d.ts +31 -0
- package/types/core/{base → logic/shell}/history.d.ts +13 -12
- package/types/core/logic/shell/pluginManager.d.ts +115 -0
- package/types/core/logic/shell/shortcuts.d.ts +131 -0
- package/types/core/logic/shell/ui.d.ts +261 -0
- package/types/core/schema/context.d.ts +104 -0
- package/types/core/schema/frameContext.d.ts +320 -0
- package/types/core/schema/options.d.ts +1241 -0
- package/types/core/section/constructor.d.ts +117 -652
- package/types/core/section/documentType.d.ts +43 -61
- package/types/events.d.ts +796 -65
- package/types/helper/clipboard.d.ts +5 -4
- package/types/helper/converter.d.ts +55 -43
- package/types/helper/dom/domCheck.d.ts +27 -19
- package/types/helper/dom/domQuery.d.ts +76 -57
- package/types/helper/dom/domUtils.d.ts +62 -39
- package/types/helper/dom/index.d.ts +87 -1
- package/types/helper/env.d.ts +16 -13
- package/types/helper/index.d.ts +8 -2
- package/types/helper/keyCodeMap.d.ts +24 -23
- package/types/helper/numbers.d.ts +4 -6
- package/types/helper/unicode.d.ts +4 -3
- package/types/hooks/base.d.ts +239 -0
- package/types/hooks/params.d.ts +65 -0
- package/types/index.d.ts +20 -117
- package/types/interfaces/contracts.d.ts +183 -0
- package/types/interfaces/index.d.ts +3 -0
- package/types/interfaces/plugins.d.ts +168 -0
- package/types/langs/_Lang.d.ts +2 -2
- package/types/langs/index.d.ts +2 -2
- package/types/modules/contract/Browser.d.ts +262 -0
- package/types/modules/contract/ColorPicker.d.ts +99 -0
- package/types/modules/contract/Controller.d.ts +204 -0
- package/types/modules/contract/Figure.d.ts +529 -0
- package/types/modules/{HueSlider.d.ts → contract/HueSlider.d.ts} +39 -28
- package/types/modules/contract/Modal.d.ts +62 -0
- package/types/modules/contract/index.d.ts +7 -0
- package/types/modules/manager/ApiManager.d.ts +106 -0
- package/types/modules/manager/FileManager.d.ts +124 -0
- package/types/modules/manager/index.d.ts +3 -0
- package/types/modules/ui/ModalAnchorEditor.d.ts +152 -0
- package/types/modules/ui/SelectMenu.d.ts +107 -0
- package/types/modules/{_DragHandle.d.ts → ui/_DragHandle.d.ts} +1 -0
- package/types/modules/ui/index.d.ts +4 -0
- package/types/plugins/browser/audioGallery.d.ts +33 -41
- package/types/plugins/browser/fileBrowser.d.ts +42 -50
- package/types/plugins/browser/fileGallery.d.ts +33 -41
- package/types/plugins/browser/imageGallery.d.ts +30 -37
- package/types/plugins/browser/videoGallery.d.ts +33 -41
- package/types/plugins/command/blockquote.d.ts +4 -21
- package/types/plugins/command/exportPDF.d.ts +23 -33
- package/types/plugins/command/fileUpload.d.ts +80 -100
- package/types/plugins/command/list_bulleted.d.ts +9 -35
- package/types/plugins/command/list_numbered.d.ts +9 -35
- package/types/plugins/dropdown/align.d.ts +23 -46
- package/types/plugins/dropdown/backgroundColor.d.ts +35 -53
- package/types/plugins/dropdown/blockStyle.d.ts +45 -0
- package/types/plugins/dropdown/font.d.ts +18 -41
- package/types/plugins/dropdown/fontColor.d.ts +35 -53
- package/types/plugins/dropdown/hr.d.ts +26 -52
- package/types/plugins/dropdown/layout.d.ts +19 -25
- package/types/plugins/dropdown/lineHeight.d.ts +21 -39
- package/types/plugins/dropdown/list.d.ts +6 -34
- package/types/plugins/dropdown/paragraphStyle.d.ts +34 -45
- package/types/plugins/dropdown/table/index.d.ts +158 -0
- package/types/plugins/dropdown/table/render/table.html.d.ts +71 -0
- package/types/plugins/dropdown/table/render/table.menu.d.ts +59 -0
- package/types/plugins/dropdown/table/services/table.cell.d.ts +76 -0
- package/types/plugins/dropdown/table/services/table.clipboard.d.ts +26 -0
- package/types/plugins/dropdown/table/services/table.grid.d.ts +77 -0
- package/types/plugins/dropdown/table/services/table.resize.d.ts +72 -0
- package/types/plugins/dropdown/table/services/table.selection.d.ts +59 -0
- package/types/plugins/dropdown/table/services/table.style.d.ts +162 -0
- package/types/plugins/dropdown/table/shared/table.constants.d.ts +134 -0
- package/types/plugins/dropdown/table/shared/table.utils.d.ts +91 -0
- package/types/plugins/dropdown/template.d.ts +19 -25
- package/types/plugins/dropdown/textStyle.d.ts +23 -30
- package/types/plugins/field/mention.d.ts +66 -72
- package/types/plugins/index.d.ts +41 -40
- package/types/plugins/input/fontSize.d.ts +57 -96
- package/types/plugins/input/pageNavigator.d.ts +5 -8
- package/types/plugins/modal/audio.d.ts +60 -153
- package/types/plugins/modal/drawing.d.ts +16 -118
- package/types/plugins/modal/embed.d.ts +46 -166
- package/types/plugins/modal/image/index.d.ts +281 -0
- package/types/plugins/modal/image/render/image.html.d.ts +45 -0
- package/types/plugins/modal/image/services/image.size.d.ts +55 -0
- package/types/plugins/modal/image/services/image.upload.d.ts +24 -0
- package/types/plugins/modal/image/shared/image.constants.d.ts +17 -0
- package/types/plugins/modal/link.d.ts +46 -66
- package/types/plugins/modal/math.d.ts +17 -86
- package/types/plugins/modal/{video.d.ts → video/index.d.ts} +89 -221
- package/types/plugins/modal/video/render/video.html.d.ts +37 -0
- package/types/plugins/modal/video/services/video.size.d.ts +74 -0
- package/types/plugins/modal/video/services/video.upload.d.ts +19 -0
- package/types/plugins/popup/anchor.d.ts +8 -38
- package/types/suneditor.d.ts +55 -24
- package/types/typedef.d.ts +344 -228
- package/CONTRIBUTING.md +0 -186
- package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
- package/src/core/base/eventHandlers/handler_ww_mouse.js +0 -194
- package/src/core/base/eventManager.js +0 -1523
- package/src/core/class/component.js +0 -856
- package/src/core/class/format.js +0 -3433
- package/src/core/class/menu.js +0 -346
- package/src/core/class/selection.js +0 -610
- package/src/core/class/shortcuts.js +0 -98
- package/src/core/class/toolbar.js +0 -431
- package/src/core/class/ui.js +0 -424
- package/src/core/class/viewer.js +0 -750
- package/src/core/section/actives.js +0 -266
- package/src/core/section/context.js +0 -102
- package/src/editorInjector/_classes.js +0 -36
- package/src/editorInjector/_core.js +0 -87
- package/src/editorInjector/index.js +0 -73
- package/src/modules/ApiManager.js +0 -191
- package/src/modules/Controller.js +0 -474
- package/src/modules/Modal.js +0 -346
- package/src/modules/index.js +0 -14
- package/src/plugins/dropdown/table.js +0 -4034
- package/src/plugins/modal/image.js +0 -1376
- package/src/plugins/modal/video.js +0 -1226
- package/types/core/base/eventHandlers/handler_toolbar.d.ts +0 -41
- package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +0 -40
- package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +0 -35
- package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +0 -45
- package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +0 -39
- package/types/core/base/eventManager.d.ts +0 -401
- package/types/core/class/char.d.ts +0 -61
- package/types/core/class/component.d.ts +0 -213
- package/types/core/class/format.d.ts +0 -623
- package/types/core/class/html.d.ts +0 -430
- package/types/core/class/menu.d.ts +0 -126
- package/types/core/class/nodeTransform.d.ts +0 -93
- package/types/core/class/offset.d.ts +0 -522
- package/types/core/class/selection.d.ts +0 -188
- package/types/core/class/shortcuts.d.ts +0 -142
- package/types/core/class/toolbar.d.ts +0 -189
- package/types/core/class/ui.d.ts +0 -164
- package/types/core/class/viewer.d.ts +0 -140
- package/types/core/section/actives.d.ts +0 -46
- package/types/core/section/context.d.ts +0 -45
- package/types/editorInjector/_classes.d.ts +0 -41
- package/types/editorInjector/_core.d.ts +0 -87
- package/types/editorInjector/index.d.ts +0 -69
- package/types/modules/ApiManager.d.ts +0 -125
- package/types/modules/Browser.d.ts +0 -326
- package/types/modules/ColorPicker.d.ts +0 -135
- package/types/modules/Controller.d.ts +0 -251
- package/types/modules/Figure.d.ts +0 -517
- package/types/modules/FileManager.d.ts +0 -202
- package/types/modules/Modal.d.ts +0 -111
- package/types/modules/ModalAnchorEditor.d.ts +0 -236
- package/types/modules/SelectMenu.d.ts +0 -194
- package/types/modules/index.d.ts +0 -26
- package/types/plugins/dropdown/formatBlock.d.ts +0 -55
- package/types/plugins/dropdown/table.d.ts +0 -627
- package/types/plugins/modal/image.d.ts +0 -451
- /package/{LICENSE → LICENSE.txt} +0 -0
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
import { dom, env, numbers, unicode, keyCodeMap, converter } from '../../../helper';
|
|
2
|
+
import { Figure } from '../../../modules/contract';
|
|
3
|
+
import { _DragHandle } from '../../../modules/ui';
|
|
4
|
+
|
|
5
|
+
const { _w, ON_OVER_COMPONENT, isMobile } = env;
|
|
6
|
+
const DIR_KEYCODE = /^Arrow(Left|Up|Right|Down)$/;
|
|
7
|
+
const DIR_UP_KEYCODE = /^Arrow(Left|Up)$/;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @description Class for managing components such as images and tables that are not in `line` format
|
|
11
|
+
*/
|
|
12
|
+
class Component {
|
|
13
|
+
#kernel;
|
|
14
|
+
#$;
|
|
15
|
+
#store;
|
|
16
|
+
|
|
17
|
+
#contextProvider;
|
|
18
|
+
#carrierWrapper;
|
|
19
|
+
#options;
|
|
20
|
+
#frameContext;
|
|
21
|
+
#eventManager;
|
|
22
|
+
|
|
23
|
+
/** @type {Object<string, (...args: *) => *>} */
|
|
24
|
+
#globalEvents;
|
|
25
|
+
/** @type {?SunEditor.Event.GlobalInfo} */
|
|
26
|
+
#bindClose_copy = null;
|
|
27
|
+
/** @type {?SunEditor.Event.GlobalInfo} */
|
|
28
|
+
#bindClose_cut = null;
|
|
29
|
+
/** @type {?SunEditor.Event.GlobalInfo} */
|
|
30
|
+
#bindClose_keydown = null;
|
|
31
|
+
/** @type {?SunEditor.Event.GlobalInfo} */
|
|
32
|
+
#bindClose_mousedown = null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @constructor
|
|
36
|
+
* @param {SunEditor.Kernel} kernel
|
|
37
|
+
*/
|
|
38
|
+
constructor(kernel) {
|
|
39
|
+
this.#kernel = kernel;
|
|
40
|
+
this.#$ = kernel.$;
|
|
41
|
+
this.#store = kernel.store;
|
|
42
|
+
|
|
43
|
+
this.#contextProvider = this.#$.contextProvider;
|
|
44
|
+
this.#carrierWrapper = this.#contextProvider.carrierWrapper;
|
|
45
|
+
this.#options = this.#$.options;
|
|
46
|
+
this.#frameContext = this.#$.frameContext;
|
|
47
|
+
this.#eventManager = this.#$.eventManager;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @description The current component information, used copy, cut, and keydown events
|
|
51
|
+
* @type {SunEditor.ComponentInfo}
|
|
52
|
+
*/
|
|
53
|
+
this.info = null;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @description Component is selected
|
|
57
|
+
* @type {boolean}
|
|
58
|
+
*/
|
|
59
|
+
this.isSelected = false;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @description Currently selected component target
|
|
63
|
+
* @type {?Node}
|
|
64
|
+
*/
|
|
65
|
+
this.currentTarget = null;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @description Currently selected component plugin instance
|
|
69
|
+
* @type {*}
|
|
70
|
+
*/
|
|
71
|
+
this.currentPlugin = null;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @description Currently selected component plugin name
|
|
75
|
+
* @type {*}
|
|
76
|
+
*/
|
|
77
|
+
this.currentPluginName = '';
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @description Currently selected component information
|
|
81
|
+
* @type {?SunEditor.ComponentInfo}
|
|
82
|
+
*/
|
|
83
|
+
this.currentInfo = null;
|
|
84
|
+
|
|
85
|
+
this.#globalEvents = {
|
|
86
|
+
copy: this.#OnCopy_component.bind(this),
|
|
87
|
+
cut: this.#OnCut_component.bind(this),
|
|
88
|
+
keydown: this.#OnKeyDown_component.bind(this),
|
|
89
|
+
mousedown: this.#CloseListener_mousedown.bind(this),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** @internal */
|
|
93
|
+
this.__selectionSelected = false;
|
|
94
|
+
/** @internal */
|
|
95
|
+
this.__prevent = false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @description Initialize eventManager reference after EventManager is created.
|
|
100
|
+
*/
|
|
101
|
+
_init() {
|
|
102
|
+
this.#contextProvider.applyToRoots((e) => {
|
|
103
|
+
// drag
|
|
104
|
+
const dragHandle = dom.utils.createElement('DIV', { class: 'se-drag-handle', draggable: 'true' }, this.#contextProvider.icons.selection);
|
|
105
|
+
e.get('wrapper').appendChild(dragHandle);
|
|
106
|
+
this.#eventManager.addEvent(dragHandle, 'mouseenter', this.#OnDragEnter.bind(this));
|
|
107
|
+
this.#eventManager.addEvent(dragHandle, 'mouseleave', this.#OnDragLeave.bind(this));
|
|
108
|
+
this.#eventManager.addEvent(dragHandle, 'dragstart', this.#OnDragStart.bind(this));
|
|
109
|
+
this.#eventManager.addEvent(dragHandle, 'dragend', this.#OnDragEnd.bind(this));
|
|
110
|
+
this.#eventManager.addEvent(dragHandle, 'click', this.#OnDragClick.bind(this));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @description Inserts an element and returns it. (Used for elements: table, hr, image, video)
|
|
116
|
+
* - If `element` is `HR`, inserts and returns the new line.
|
|
117
|
+
* @param {Node} element Element to be inserted
|
|
118
|
+
* @param {Object} [options] Options
|
|
119
|
+
* @param {boolean} [options.skipCharCount=false] If `true`, it will be inserted even if `frameOptions.get('charCounter_max')` is exceeded.
|
|
120
|
+
* @param {boolean} [options.skipHistory=false] If `true`, do not push to history.
|
|
121
|
+
* @param {boolean} [options.scrollTo=true] `true` : Scroll to the inserted element, `false` : Do not scroll.
|
|
122
|
+
* @param {SunEditor.ComponentInsertType} [options.insertBehavior] If `true`, do not automatically select the inserted component. [default: `options.get('componentInsertBehavior')`]
|
|
123
|
+
* - If `null`, no action is performed after insertion.
|
|
124
|
+
* @returns {HTMLElement} The inserted element or new line (for HR)
|
|
125
|
+
*/
|
|
126
|
+
insert(element, { skipCharCount = false, skipHistory = false, scrollTo = true, insertBehavior } = {}) {
|
|
127
|
+
if (this.#frameContext.get('isReadOnly') || (!skipCharCount && !this.#$.char.check(element))) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (insertBehavior === undefined) insertBehavior = this.#options.get('componentInsertBehavior');
|
|
132
|
+
|
|
133
|
+
const r = this.#$.html.remove();
|
|
134
|
+
const isInline = this.isInline(element);
|
|
135
|
+
this.#$.selection.getRangeAndAddLine(this.#$.selection.getRange(), r.container);
|
|
136
|
+
const selectionNode = this.#$.selection.getNode();
|
|
137
|
+
let oNode = null;
|
|
138
|
+
let formatEl = this.#$.format.getLine(selectionNode, null);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
if (dom.check.isListCell(formatEl)) {
|
|
142
|
+
this.#$.html.insertNode(element, { afterNode: isInline ? null : !dom.check.isZeroWidth(selectionNode) ? null : (selectionNode || r.container || {}).nextSibling, skipCharCount: true });
|
|
143
|
+
if (!isInline && !element.nextSibling) element.parentNode.appendChild(dom.utils.createElement('BR'));
|
|
144
|
+
} else {
|
|
145
|
+
if (!isInline && this.#$.selection.getRange().collapsed && (r.container?.nodeType === 3 || dom.check.isBreak(r.container))) {
|
|
146
|
+
const depthFormat = dom.query.getParentElement(r.container, this.#$.format.isBlock.bind(this.#$.format));
|
|
147
|
+
oNode = this.#$.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
|
|
148
|
+
if (oNode) formatEl = /** @type {HTMLElement} */ (oNode.previousSibling);
|
|
149
|
+
}
|
|
150
|
+
this.#$.html.insertNode(element, { afterNode: isInline ? null : this.#$.format.isBlock(formatEl) ? null : formatEl, skipCharCount: true });
|
|
151
|
+
if (!isInline && formatEl && dom.check.isZeroWidth(formatEl)) dom.utils.removeItem(formatEl);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isInline) {
|
|
155
|
+
const empty = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
156
|
+
element.parentNode.insertBefore(empty, element.nextSibling);
|
|
157
|
+
}
|
|
158
|
+
} catch (e) {
|
|
159
|
+
console.error('Component insert error:', e);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!skipHistory) this.#$.history.push(false);
|
|
163
|
+
|
|
164
|
+
// document type
|
|
165
|
+
if (this.#frameContext.has('documentType_use_header')) {
|
|
166
|
+
this.#frameContext.get('documentType').reHeader();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const targetElement = /** @type {HTMLElement} */ (oNode || element);
|
|
170
|
+
|
|
171
|
+
if (scrollTo) this.#$.selection.scrollTo(targetElement, { behavior: 'auto' });
|
|
172
|
+
if (insertBehavior !== null) this.applyInsertBehavior(element, oNode, insertBehavior);
|
|
173
|
+
|
|
174
|
+
return targetElement;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @description Handles post-insertion behavior for a newly created component based on the specified mode.
|
|
179
|
+
* @param {Node} container The inserted component element.
|
|
180
|
+
* @param {?Node} [oNode] Optional node to use for selection if the component cannot be selected.
|
|
181
|
+
* @param {SunEditor.ComponentInsertType} [insertBehavior] Behavior mode after component insertion.
|
|
182
|
+
*/
|
|
183
|
+
applyInsertBehavior(container, oNode, insertBehavior) {
|
|
184
|
+
const cInfo = this.get(container);
|
|
185
|
+
|
|
186
|
+
if (this.isInline(container)) {
|
|
187
|
+
const nr = this.#$.selection.getNearRange(container);
|
|
188
|
+
if (nr) {
|
|
189
|
+
this.#$.selection.setRange(nr.container, nr.offset, nr.container, nr.offset);
|
|
190
|
+
} else {
|
|
191
|
+
this.select(cInfo.target, cInfo.pluginName);
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
switch (insertBehavior) {
|
|
197
|
+
case 'auto': {
|
|
198
|
+
if (!this.#moveToNextLineOrAdd(container)) {
|
|
199
|
+
this.select(cInfo.target, cInfo.pluginName);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case 'select': {
|
|
205
|
+
this.#$.selection.setRange(container, 0, container, 0);
|
|
206
|
+
|
|
207
|
+
if (cInfo) {
|
|
208
|
+
this.select(cInfo.target, cInfo.pluginName);
|
|
209
|
+
} else if (oNode) {
|
|
210
|
+
oNode = dom.query.getEdgeChildNodes(oNode, null).sc || oNode;
|
|
211
|
+
this.#$.selection.setRange(oNode, 0, oNode, 0);
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
case 'line': {
|
|
216
|
+
if (!this.#moveToNextLineOrAdd(container)) {
|
|
217
|
+
const line = this.#$.format.addLine(container, null);
|
|
218
|
+
if (line) this.#$.selection.setRange(line, 0, line, 0);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
case 'none': {
|
|
224
|
+
// Do not select the component and remove the editor focus
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @description Gets the file component and that plugin name
|
|
232
|
+
* - return: {target, component, pluginName} | null
|
|
233
|
+
* @param {Node} element Target element (figure tag, component div, file tag)
|
|
234
|
+
* @returns {SunEditor.ComponentInfo|null}
|
|
235
|
+
*/
|
|
236
|
+
get(element) {
|
|
237
|
+
if (!element) return null;
|
|
238
|
+
|
|
239
|
+
let target;
|
|
240
|
+
let pluginName = '';
|
|
241
|
+
let options = {};
|
|
242
|
+
let isFile = false;
|
|
243
|
+
let launcher = null;
|
|
244
|
+
|
|
245
|
+
if (this.is(element)) {
|
|
246
|
+
if (dom.check.isComponentContainer(element) && !dom.utils.hasClass(element, 'se-inline-component')) element = /** @type {HTMLElement} */ (element).firstElementChild || element;
|
|
247
|
+
if (/^FIGURE$/i.test(element.nodeName)) element = /** @type {HTMLElement} */ (element).firstElementChild;
|
|
248
|
+
if (!element) return null;
|
|
249
|
+
|
|
250
|
+
const comp = this.#$.pluginManager.findComponentInfo(element);
|
|
251
|
+
if (!comp) return null;
|
|
252
|
+
target = comp.target;
|
|
253
|
+
pluginName = comp.pluginName;
|
|
254
|
+
options = comp.options;
|
|
255
|
+
launcher = comp.launcher;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!target && element.nodeName) {
|
|
259
|
+
if (this.#isFiles(element)) {
|
|
260
|
+
isFile = true;
|
|
261
|
+
}
|
|
262
|
+
const comp = this.#$.pluginManager.findComponentInfo(element);
|
|
263
|
+
if (!comp) return null;
|
|
264
|
+
target = comp.target;
|
|
265
|
+
pluginName = comp.pluginName;
|
|
266
|
+
options = comp.options;
|
|
267
|
+
launcher = comp.launcher;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (!target) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const figureInfo = Figure.GetContainer(target);
|
|
275
|
+
const container = figureInfo.container || figureInfo.cover || target;
|
|
276
|
+
return (this.info = {
|
|
277
|
+
target: figureInfo.target,
|
|
278
|
+
pluginName,
|
|
279
|
+
options,
|
|
280
|
+
container: container,
|
|
281
|
+
cover: figureInfo.cover,
|
|
282
|
+
inlineCover: figureInfo.inlineCover,
|
|
283
|
+
caption: figureInfo.caption,
|
|
284
|
+
isFile,
|
|
285
|
+
launcher,
|
|
286
|
+
isInputType: dom.utils.hasClass(container, 'se-input-component'),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @description The component(media, file component, table, etc) is selected and the resizing module is called.
|
|
292
|
+
* @param {Node} element Target element
|
|
293
|
+
* @param {string} pluginName The plugin name for the selected target.
|
|
294
|
+
* @param {Object} [options] Options
|
|
295
|
+
* @param {boolean} [options.isInput=false] Whether the target is an input component (table).
|
|
296
|
+
*/
|
|
297
|
+
select(element, pluginName, { isInput = false } = {}) {
|
|
298
|
+
const info = this.get(element);
|
|
299
|
+
if (!info || dom.check.isUneditable(dom.query.getParentElement(element, this.is.bind(this))) || dom.check.isUneditable(element)) return false;
|
|
300
|
+
|
|
301
|
+
const plugin = info.launcher || this.#$.plugins[pluginName];
|
|
302
|
+
if (!plugin) return;
|
|
303
|
+
|
|
304
|
+
const notOver = _DragHandle.get('__overInfo') !== ON_OVER_COMPONENT;
|
|
305
|
+
if (!isInput && notOver) {
|
|
306
|
+
if (this.#store.get('_mousedown')) return;
|
|
307
|
+
|
|
308
|
+
this.#store.set('_preventBlur', true);
|
|
309
|
+
this.__selectionSelected = true;
|
|
310
|
+
if (this.isInline(info.container)) {
|
|
311
|
+
this.#$.selection.setRange(info.container, 0, info.container, 0);
|
|
312
|
+
}
|
|
313
|
+
this.#$.focusManager.blur();
|
|
314
|
+
// Defer flag reset — blur event fires synchronously and checks __selectionSelected to distinguish component-initiated blur
|
|
315
|
+
_w.setTimeout(() => {
|
|
316
|
+
this.__selectionSelected = false;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
this.isSelected = true;
|
|
321
|
+
this.__prevent = true;
|
|
322
|
+
|
|
323
|
+
let isNonFigureComponent;
|
|
324
|
+
if (typeof plugin.componentSelect === 'function') isNonFigureComponent = plugin.componentSelect(element);
|
|
325
|
+
|
|
326
|
+
const isBreakComponent = dom.utils.hasClass(info.target, 'se-component-line-break');
|
|
327
|
+
if (isBreakComponent || (!isNonFigureComponent && !dom.utils.hasClass(info.container, 'se-inline-component'))) this._setComponentLineBreaker(/** @type {HTMLElement} */ (info.container || info.cover || element));
|
|
328
|
+
|
|
329
|
+
this.currentTarget = element;
|
|
330
|
+
this.currentPlugin = plugin;
|
|
331
|
+
this.currentPluginName = pluginName;
|
|
332
|
+
this.currentInfo = info;
|
|
333
|
+
|
|
334
|
+
_DragHandle.set('__dragInst', this);
|
|
335
|
+
|
|
336
|
+
const __overInfo = _DragHandle.get('__overInfo');
|
|
337
|
+
// Defer drag handle setup — let the current click/mousedown event complete before attaching global listeners
|
|
338
|
+
_w.setTimeout(() => {
|
|
339
|
+
_DragHandle.set('__overInfo', __overInfo === ON_OVER_COMPONENT ? undefined : false);
|
|
340
|
+
if (__overInfo !== ON_OVER_COMPONENT) this.#addGlobalEvent();
|
|
341
|
+
if (!info.isFile) this.#addNotFileGlobalEvent();
|
|
342
|
+
}, 0);
|
|
343
|
+
|
|
344
|
+
converter.debounce(() => {
|
|
345
|
+
dom.utils.addClass(info.container, 'se-component-selected');
|
|
346
|
+
}, 0)();
|
|
347
|
+
|
|
348
|
+
if (notOver && !this.#store.get('hasFocus') && !this.#store.get('_preventFocus')) {
|
|
349
|
+
this.#kernel._eventOrchestrator.__postFocusEvent(this.#frameContext, null);
|
|
350
|
+
this.#store.set('_preventFocus', true);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!isBreakComponent && __overInfo !== ON_OVER_COMPONENT) {
|
|
354
|
+
// set zero width space
|
|
355
|
+
if (!this.isInline(info.container)) return;
|
|
356
|
+
|
|
357
|
+
const oNode = info.container;
|
|
358
|
+
let zeroWidth = null;
|
|
359
|
+
if (!oNode.previousSibling || dom.check.isBreak(oNode.previousSibling)) {
|
|
360
|
+
zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
361
|
+
oNode.parentNode.insertBefore(zeroWidth, oNode);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!oNode.nextSibling || dom.check.isBreak(oNode.nextSibling)) {
|
|
365
|
+
zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
|
|
366
|
+
oNode.parentNode.insertBefore(zeroWidth, oNode.nextSibling);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
this.#store.set('controlActive', true);
|
|
370
|
+
} else if (isBreakComponent || !dom.utils.hasClass(info.container, 'se-input-component')) {
|
|
371
|
+
const dragHandle = /** @type {HTMLElement} */ (this.#frameContext.get('wrapper').querySelector('.se-drag-handle'));
|
|
372
|
+
dom.utils.addClass(dragHandle, 'se-drag-handle-full');
|
|
373
|
+
this.#$.ui._visibleControllers(false, false);
|
|
374
|
+
|
|
375
|
+
const sizeTarget = info.caption ? info.target : info.cover || info.container || info.target;
|
|
376
|
+
const w = sizeTarget.offsetWidth;
|
|
377
|
+
const h = sizeTarget.offsetHeight;
|
|
378
|
+
const { top, left } = this.#$.offset.getLocal(sizeTarget);
|
|
379
|
+
|
|
380
|
+
dragHandle.style.opacity = '0';
|
|
381
|
+
dragHandle.style.width = w + 'px';
|
|
382
|
+
dragHandle.style.height = h + 'px';
|
|
383
|
+
dragHandle.style.top = top + 'px';
|
|
384
|
+
dragHandle.style.left = left + 'px';
|
|
385
|
+
|
|
386
|
+
_DragHandle.set('__dragHandler', dragHandle);
|
|
387
|
+
_DragHandle.set('__dragContainer', info.container);
|
|
388
|
+
_DragHandle.set('__dragCover', info.cover);
|
|
389
|
+
|
|
390
|
+
dragHandle.style.display = 'block';
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* @description Deselects the selected component.
|
|
396
|
+
*/
|
|
397
|
+
deselect() {
|
|
398
|
+
// Defer controlActive reset — synchronous blur handlers during deselect still need to see it as active
|
|
399
|
+
_w.setTimeout(() => {
|
|
400
|
+
this.#store.set('controlActive', false);
|
|
401
|
+
}, 0);
|
|
402
|
+
this.__deselect();
|
|
403
|
+
this.#$.ui.setControllerOnDisabledButtons(false);
|
|
404
|
+
|
|
405
|
+
if (this.#store.get('_preventFocus') && !this.#store.get('hasFocus') && !this.__prevent) {
|
|
406
|
+
this.#kernel._eventOrchestrator.__postBlurEvent(this.#frameContext, null);
|
|
407
|
+
this.#store.set('_preventFocus', false);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* @description Determines if the specified node is a block component (e.g., img, iframe, video, audio, table) with the class `se-component`
|
|
413
|
+
* - or a direct `FIGURE` node. This function checks if the node itself is a component
|
|
414
|
+
* - or if it belongs to any components identified by the component manager.
|
|
415
|
+
* @param {Node} element The DOM node to check.
|
|
416
|
+
* @returns {boolean} True if the node is a block component or part of it, otherwise false.
|
|
417
|
+
*/
|
|
418
|
+
is(element) {
|
|
419
|
+
if (!element) return false;
|
|
420
|
+
|
|
421
|
+
if (/^FIGURE$/i.test(element.nodeName) || dom.check.isComponentContainer(element)) return true;
|
|
422
|
+
if (this.#$.pluginManager.findComponentInfo(element)) return true;
|
|
423
|
+
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @description Checks if the given node is an inline component (class `se-inline-component`).
|
|
429
|
+
* - If the node is a `FIGURE`, it checks the parent element instead.
|
|
430
|
+
* - It also verifies whether the node is part of an inline component recognized by the component manager.
|
|
431
|
+
* @param {Node} element The DOM node to check.
|
|
432
|
+
* @returns {boolean} True if the node is an inline component or part of it, otherwise false.
|
|
433
|
+
*/
|
|
434
|
+
isInline(element) {
|
|
435
|
+
if (!element) return false;
|
|
436
|
+
|
|
437
|
+
if (/^FIGURE$/i.test(element.nodeName)) element = element.parentElement;
|
|
438
|
+
if (dom.utils.hasClass(element, 'se-inline-component')) return true;
|
|
439
|
+
|
|
440
|
+
const comp = this.#$.pluginManager.findComponentInfo(element);
|
|
441
|
+
if (comp && (dom.utils.hasClass(element, 'se-inline-component') || dom.utils.hasClass(element.parentElement, 'se-inline-component'))) return true;
|
|
442
|
+
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @description Checks if the specified node qualifies as a basic component within the editor.
|
|
448
|
+
* - This function verifies whether the node is recognized as a component by the `is` function, while also ensuring that it is not an inline component as determined by the `isInline` function.
|
|
449
|
+
* - This is used to identify block-level elements or standalone components that are not part of the inline component classification.
|
|
450
|
+
* @param {Node} element The DOM node to check.
|
|
451
|
+
* @returns {boolean} True if the node is a basic (non-inline) component, otherwise false.
|
|
452
|
+
*/
|
|
453
|
+
isBasic(element) {
|
|
454
|
+
return this.is(element) && !this.isInline(element);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @description Copies the specified component node to the clipboard.
|
|
459
|
+
* - This function is different from the one called when the user presses the `Ctrl + C` key combination.
|
|
460
|
+
* @param {Node} container The DOM node to check.
|
|
461
|
+
*/
|
|
462
|
+
async copy(container) {
|
|
463
|
+
const cloneContainer = /** @type {HTMLElement} */ (dom.utils.clone(container, true));
|
|
464
|
+
|
|
465
|
+
RemoveSelectedClass(cloneContainer);
|
|
466
|
+
|
|
467
|
+
// copy to clipboard
|
|
468
|
+
if ((await this.#$.html.copy(cloneContainer)) === false) return;
|
|
469
|
+
|
|
470
|
+
// copy effect
|
|
471
|
+
dom.utils.flashClass(container, 'se-copy');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* @description Temporarily selects a component without showing its controller.
|
|
476
|
+
* This is a lightweight selection mode used for:
|
|
477
|
+
* - Mouse hover: Shows visual selection while hovering, auto-deselects on mouse out
|
|
478
|
+
* - Table column/row resize: Maintains selection after resize without showing controller
|
|
479
|
+
*
|
|
480
|
+
* Key differences from `select()`:
|
|
481
|
+
* - Does NOT show the component's controller (resize handles, toolbar, etc.)
|
|
482
|
+
* - Sets `__overInfo` flag so selection is automatically cleared on mouse out
|
|
483
|
+
* - Calling `select()` afterward will upgrade to full selection with controller
|
|
484
|
+
*
|
|
485
|
+
* @param {Element} target The element to hover-select
|
|
486
|
+
*/
|
|
487
|
+
hoverSelect(target) {
|
|
488
|
+
const figure = dom.query.getParentElement(target, dom.check.isFigure);
|
|
489
|
+
let info = this.get(target);
|
|
490
|
+
if (info || figure) {
|
|
491
|
+
info ||= this.get(figure);
|
|
492
|
+
if (info && !dom.utils.hasClass(info.container, 'se-component-selected')) {
|
|
493
|
+
this.#$.ui.offCurrentController();
|
|
494
|
+
_DragHandle.set('__overInfo', ON_OVER_COMPONENT);
|
|
495
|
+
this.select(info.target, info.pluginName);
|
|
496
|
+
}
|
|
497
|
+
} else if (_DragHandle.get('__overInfo') !== null && !dom.utils.hasClass(target, 'se-drag-handle')) {
|
|
498
|
+
this.__deselect();
|
|
499
|
+
_DragHandle.set('__overInfo', null);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @internal
|
|
505
|
+
* @description Deselects the currently selected component, removing any selection effects and associated event listeners.
|
|
506
|
+
* - This method resets the selection state and hides UI elements related to the component selection.
|
|
507
|
+
*/
|
|
508
|
+
__deselect() {
|
|
509
|
+
this.#store.set('_preventBlur', false);
|
|
510
|
+
_DragHandle.set('__overInfo', null);
|
|
511
|
+
this.__removeDragEvent();
|
|
512
|
+
|
|
513
|
+
if (this.currentInfo) {
|
|
514
|
+
const infoContainer = this.currentInfo.container;
|
|
515
|
+
const infoCover = this.currentInfo.cover;
|
|
516
|
+
converter.debounce(() => {
|
|
517
|
+
RemoveSelectedClass(infoContainer);
|
|
518
|
+
dom.utils.removeClass(infoCover, 'se-figure-over-selected');
|
|
519
|
+
}, 0)();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (this.#frameContext.get('lineBreaker_t')) {
|
|
523
|
+
this.#frameContext.get('lineBreaker_t').style.display = this.#frameContext.get('lineBreaker_b').style.display = 'none';
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (this.currentPlugin) {
|
|
527
|
+
this.currentPlugin.componentDeselect?.(this.currentTarget);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
this.isSelected = false;
|
|
531
|
+
this.currentPlugin = null;
|
|
532
|
+
this.currentTarget = null;
|
|
533
|
+
this.currentPluginName = '';
|
|
534
|
+
this.currentInfo = null;
|
|
535
|
+
this.__removeGlobalEvent();
|
|
536
|
+
this.#$.ui._offControllers();
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @internal
|
|
541
|
+
* @description Set line breaker of component
|
|
542
|
+
* @param {HTMLElement} element Element tag
|
|
543
|
+
*/
|
|
544
|
+
_setComponentLineBreaker(element) {
|
|
545
|
+
const _overInfo = _DragHandle.get('__overInfo') === ON_OVER_COMPONENT;
|
|
546
|
+
this.#kernel._eventOrchestrator._lineBreakComp = null;
|
|
547
|
+
const info = this.get(element);
|
|
548
|
+
if (!info) return;
|
|
549
|
+
|
|
550
|
+
const fc = this.#frameContext;
|
|
551
|
+
const container = info.container;
|
|
552
|
+
const isNonSelected = dom.utils.hasClass(container, 'se-flex-component');
|
|
553
|
+
const lb_t = fc.get('lineBreaker_t');
|
|
554
|
+
const lb_b = fc.get('lineBreaker_b');
|
|
555
|
+
const t_style = lb_t.style;
|
|
556
|
+
const b_style = lb_b.style;
|
|
557
|
+
const offsetTarget = container.offsetWidth < element.offsetWidth ? container : element;
|
|
558
|
+
const target = this.#$.ui.getVisibleFigure() || offsetTarget;
|
|
559
|
+
const isList = dom.check.isListCell(container.parentNode);
|
|
560
|
+
|
|
561
|
+
// top
|
|
562
|
+
let componentTop, w;
|
|
563
|
+
const isRtl = this.#options.get('_rtl');
|
|
564
|
+
const dir = isRtl ? ['right', 'left'] : ['left', 'right'];
|
|
565
|
+
const { top, left, right, scrollX, scrollY } = this.#$.offset.getLocal(offsetTarget);
|
|
566
|
+
const sideOffset = isRtl ? right : left;
|
|
567
|
+
|
|
568
|
+
if (isList ? (!dom.check.isBreak(container.previousElementSibling) && !container.previousSibling?.textContent?.trim()) || this.is(container.previousElementSibling) : !this.#$.format.isLine(container.previousElementSibling)) {
|
|
569
|
+
const cStyle = _w.getComputedStyle(lb_t);
|
|
570
|
+
const cH = numbers.get(cStyle.height, 1);
|
|
571
|
+
const cW = numbers.get(cStyle.width, 1);
|
|
572
|
+
|
|
573
|
+
this.#kernel._eventOrchestrator._lineBreakComp = container;
|
|
574
|
+
componentTop = top;
|
|
575
|
+
w = target.offsetWidth / 2 / 2;
|
|
576
|
+
|
|
577
|
+
t_style.top = componentTop - cH / 2 + 'px';
|
|
578
|
+
t_style[dir[0]] = (isNonSelected ? sideOffset - cW / 2 : sideOffset + w) + 'px';
|
|
579
|
+
t_style[dir[1]] = '';
|
|
580
|
+
|
|
581
|
+
lb_t.setAttribute('data-offset', scrollY + ',' + scrollX);
|
|
582
|
+
if (_overInfo) dom.utils.removeClass(lb_t, 'se-on-selected');
|
|
583
|
+
else dom.utils.addClass(lb_t, 'se-on-selected');
|
|
584
|
+
|
|
585
|
+
t_style.display = 'block';
|
|
586
|
+
t_style.visibility = '';
|
|
587
|
+
} else {
|
|
588
|
+
t_style.display = 'none';
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// bottom
|
|
592
|
+
if (isList ? (!dom.check.isBreak(container.nextElementSibling) && !container.nextSibling?.textContent?.trim()) || this.is(container.nextElementSibling) : !this.#$.format.isLine(container.nextElementSibling)) {
|
|
593
|
+
const cStyle = _w.getComputedStyle(lb_b);
|
|
594
|
+
const cH = numbers.get(cStyle.height, 1);
|
|
595
|
+
const cW = numbers.get(cStyle.width, 1);
|
|
596
|
+
|
|
597
|
+
if (!componentTop) {
|
|
598
|
+
this.#kernel._eventOrchestrator._lineBreakComp = container;
|
|
599
|
+
componentTop = top;
|
|
600
|
+
w = target.offsetWidth / 2 / 2;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
b_style.top = componentTop + target.offsetHeight - cH / 2 + 'px';
|
|
604
|
+
b_style[dir[0]] = sideOffset + target.offsetWidth - (isNonSelected ? 0 : w) - (isNonSelected ? cW / 2 : cW) + 'px';
|
|
605
|
+
b_style[dir[1]] = '';
|
|
606
|
+
|
|
607
|
+
lb_b.setAttribute('data-offset', scrollY + ',' + dir[0] + ',' + scrollX);
|
|
608
|
+
if (_overInfo) dom.utils.removeClass(lb_b, 'se-on-selected');
|
|
609
|
+
else dom.utils.addClass(lb_b, 'se-on-selected');
|
|
610
|
+
|
|
611
|
+
b_style.display = 'block';
|
|
612
|
+
b_style.visibility = '';
|
|
613
|
+
} else {
|
|
614
|
+
b_style.display = 'none';
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* @internal
|
|
620
|
+
* @description Removes global event listeners that were previously added for component interactions.
|
|
621
|
+
*/
|
|
622
|
+
__removeGlobalEvent() {
|
|
623
|
+
this.#removeNotFileGlobalEvent();
|
|
624
|
+
this.#bindClose_copy &&= this.#eventManager.removeGlobalEvent(this.#bindClose_copy);
|
|
625
|
+
this.#bindClose_cut &&= this.#eventManager.removeGlobalEvent(this.#bindClose_cut);
|
|
626
|
+
this.#bindClose_keydown &&= this.#eventManager.removeGlobalEvent(this.#bindClose_keydown);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* @internal
|
|
631
|
+
* @description Removes drag-related events and resets drag-related states.
|
|
632
|
+
*/
|
|
633
|
+
__removeDragEvent() {
|
|
634
|
+
/** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-drag-cursor')).style.left = '-10000px';
|
|
635
|
+
if (_DragHandle.get('__dragHandler')) _DragHandle.get('__dragHandler').style.display = 'none';
|
|
636
|
+
|
|
637
|
+
dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
|
|
638
|
+
dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
|
|
639
|
+
|
|
640
|
+
_DragHandle.set('__figureInst', null);
|
|
641
|
+
_DragHandle.set('__dragInst', null);
|
|
642
|
+
_DragHandle.set('__dragHandler', null);
|
|
643
|
+
_DragHandle.set('__dragContainer', null);
|
|
644
|
+
_DragHandle.set('__dragCover', null);
|
|
645
|
+
_DragHandle.set('__dragMove', null);
|
|
646
|
+
_DragHandle.set('__overInfo', null);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* @description Adds global event listeners for component interactions such as copy, cut, and keydown events.
|
|
651
|
+
*/
|
|
652
|
+
#addGlobalEvent() {
|
|
653
|
+
this.__removeGlobalEvent();
|
|
654
|
+
this.#bindClose_copy = this.#eventManager.addGlobalEvent('copy', this.#globalEvents.copy);
|
|
655
|
+
this.#bindClose_cut = this.#eventManager.addGlobalEvent('cut', this.#globalEvents.cut);
|
|
656
|
+
this.#bindClose_keydown = this.#eventManager.addGlobalEvent('keydown', this.#globalEvents.keydown);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* @description Adds global event listeners for non-file-related interactions such as mouse and touch events.
|
|
661
|
+
*/
|
|
662
|
+
#addNotFileGlobalEvent() {
|
|
663
|
+
this.#removeNotFileGlobalEvent();
|
|
664
|
+
this.#bindClose_mousedown = this.#eventManager.addGlobalEvent(isMobile ? 'click' : 'mousedown', this.#globalEvents.mousedown, true);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* @internal
|
|
669
|
+
* @description Removes global event listeners related to non-file interactions.
|
|
670
|
+
*/
|
|
671
|
+
#removeNotFileGlobalEvent() {
|
|
672
|
+
this.#bindClose_mousedown &&= this.#eventManager.removeGlobalEvent(this.#bindClose_mousedown);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* @description
|
|
677
|
+
* Attempts to move the cursor to a valid line after the given container.
|
|
678
|
+
* - If a valid next sibling line exists, moves the selection there.
|
|
679
|
+
* - If no next sibling exists, creates a new line after the container and moves the selection there.
|
|
680
|
+
* - If the next sibling exists but is not a valid line element and cannot create a new line, returns false.
|
|
681
|
+
* @param {Node} container The component container element.
|
|
682
|
+
* @returns {boolean} Returns true if the selection moved to a line (existing or newly created), otherwise false.
|
|
683
|
+
*/
|
|
684
|
+
#moveToNextLineOrAdd(container) {
|
|
685
|
+
const nextSibling = /** @type {Element} */ (container).nextElementSibling;
|
|
686
|
+
if (!nextSibling) {
|
|
687
|
+
const line = this.#$.format.addLine(container, null);
|
|
688
|
+
if (line) this.#$.selection.setRange(line, 0, line, 0);
|
|
689
|
+
return true;
|
|
690
|
+
} else if (this.#$.format.isLine(nextSibling)) {
|
|
691
|
+
this.#$.selection.setRange(nextSibling, 0, nextSibling, 0);
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* @description Checks if the given element is a file component by matching its tag name against the file manager's regular expressions.
|
|
700
|
+
* - It also verifies whether the element has the required attributes based on the tag type.
|
|
701
|
+
* @param {Node} element The element to check.
|
|
702
|
+
* @returns {boolean} Returns true if the element is a file component, otherwise false.
|
|
703
|
+
*/
|
|
704
|
+
#isFiles(element) {
|
|
705
|
+
const nodeName = element.nodeName.toLowerCase();
|
|
706
|
+
return (
|
|
707
|
+
this.#$.pluginManager.fileInfo.regExp.test(nodeName) &&
|
|
708
|
+
(!this.#$.pluginManager.fileInfo.tagAttrs[nodeName] || this.#$.pluginManager.fileInfo.tagAttrs[nodeName]?.every((v) => /** @type {HTMLElement} */ (element).hasAttribute(v)))
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
#OnDragEnter() {
|
|
713
|
+
this.#store.set('_preventBlur', true);
|
|
714
|
+
this.#$.ui._visibleControllers(false, dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full'));
|
|
715
|
+
dom.utils.addClass(_DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer'), 'se-drag-over');
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
#OnDragLeave() {
|
|
719
|
+
this.#store.set('_preventBlur', false);
|
|
720
|
+
if (!dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full')) this.#$.ui._visibleControllers(true, true);
|
|
721
|
+
dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* @param {DragEvent} e - Drag event
|
|
726
|
+
*/
|
|
727
|
+
#OnDragStart(e) {
|
|
728
|
+
const cover = _DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer');
|
|
729
|
+
|
|
730
|
+
if (!cover) {
|
|
731
|
+
e.preventDefault();
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
this.#store.set('_preventBlur', false);
|
|
736
|
+
dom.utils.addClass(_DragHandle.get('__dragHandler'), 'se-dragging');
|
|
737
|
+
dom.utils.addClass(_DragHandle.get('__dragContainer'), 'se-dragging');
|
|
738
|
+
e.dataTransfer.setDragImage(cover, this.#options.get('_rtl') ? cover.offsetWidth : -5, -5);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
#OnDragEnd() {
|
|
742
|
+
this.#store.set('_preventBlur', false);
|
|
743
|
+
dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
|
|
744
|
+
this.__removeDragEvent();
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* @param {MouseEvent} e - Mouse event
|
|
749
|
+
*/
|
|
750
|
+
#OnDragClick(e) {
|
|
751
|
+
const target = dom.query.getEventTarget(e);
|
|
752
|
+
if (!dom.utils.hasClass(target, 'se-drag-handle-full')) return;
|
|
753
|
+
|
|
754
|
+
const dragInst = _DragHandle.get('__dragInst');
|
|
755
|
+
if (!dragInst) return;
|
|
756
|
+
|
|
757
|
+
this.__removeDragEvent();
|
|
758
|
+
this.select(dragInst.currentTarget, dragInst.currentPluginName);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* @param {MouseEvent} e - Mouse event
|
|
763
|
+
*/
|
|
764
|
+
#CloseListener_mousedown(e) {
|
|
765
|
+
const target = dom.query.getEventTarget(e);
|
|
766
|
+
if (
|
|
767
|
+
this.currentTarget?.contains(target) ||
|
|
768
|
+
dom.query.getParentElement(target, '.se-controller') ||
|
|
769
|
+
dom.utils.hasClass(target, 'se-drag-handle') ||
|
|
770
|
+
(this.currentPluginName === this.#$.ui.currentControllerName && this.#$.ui.opendControllers.some(({ form }) => form.contains(target)))
|
|
771
|
+
) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
this.deselect();
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* @param {ClipboardEvent} e - Event object
|
|
779
|
+
*/
|
|
780
|
+
#OnCopy_component(e) {
|
|
781
|
+
const target = dom.query.getEventTarget(e);
|
|
782
|
+
if (dom.check.isInputElement(target) && dom.query.getParentElement(target, '.se-modal')) return;
|
|
783
|
+
|
|
784
|
+
const info = this.info;
|
|
785
|
+
if (!info) return;
|
|
786
|
+
|
|
787
|
+
const cloneContainer = info.container.cloneNode(true);
|
|
788
|
+
if (typeof this.#$.plugins[info.pluginName]?.componentCopy !== 'function' || this.#$.plugins[info.pluginName].componentCopy({ event: e, cloneContainer, info }) === false) {
|
|
789
|
+
SetClipboardComponent(e, cloneContainer, e.clipboardData);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// copy effect
|
|
793
|
+
dom.utils.flashClass(info.container, 'se-copy');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* @param {ClipboardEvent} e - Event object
|
|
798
|
+
*/
|
|
799
|
+
#OnCut_component(e) {
|
|
800
|
+
const info = this.info;
|
|
801
|
+
if (!info) return;
|
|
802
|
+
|
|
803
|
+
const cloneContainer = info.container.cloneNode(true);
|
|
804
|
+
dom.utils.removeClass(cloneContainer, 'se-component-selected');
|
|
805
|
+
|
|
806
|
+
SetClipboardComponent(e, cloneContainer, e.clipboardData);
|
|
807
|
+
this.deselect();
|
|
808
|
+
dom.utils.removeItem(info.container);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* @param {KeyboardEvent} e - Event object
|
|
813
|
+
*/
|
|
814
|
+
async #OnKeyDown_component(e) {
|
|
815
|
+
if (this.#$.ui.selectMenuOn) return;
|
|
816
|
+
|
|
817
|
+
const keyCode = e.code;
|
|
818
|
+
const ctrl = keyCodeMap.isCtrl(e);
|
|
819
|
+
|
|
820
|
+
// redo, undo
|
|
821
|
+
if (ctrl) {
|
|
822
|
+
if (keyCode !== 'ControlRight' && keyCode !== 'ControlLeft') {
|
|
823
|
+
const info = this.#$.shortcuts.keyMap.get(keyCode + (e.shiftKey ? '1000' : ''));
|
|
824
|
+
if (/^(redo|undo)$/.test(info?.command)) {
|
|
825
|
+
e.preventDefault();
|
|
826
|
+
e.stopPropagation();
|
|
827
|
+
this.#$.commandDispatcher.run(info.command, info.type, info.button);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// backspace key, delete key
|
|
834
|
+
if (keyCodeMap.isRemoveKey(keyCode)) {
|
|
835
|
+
e.preventDefault();
|
|
836
|
+
e.stopPropagation();
|
|
837
|
+
|
|
838
|
+
if (typeof this.currentPlugin?.componentDestroy === 'function' && (!this.info.isInputType || !this.#store.get('hasFocus'))) {
|
|
839
|
+
const focusNode = this.info.container.previousSibling;
|
|
840
|
+
await this.currentPlugin.componentDestroy(this.currentTarget);
|
|
841
|
+
this.deselect();
|
|
842
|
+
if (focusNode) {
|
|
843
|
+
const offset = focusNode.nodeType === 3 ? focusNode.textContent.length : 1;
|
|
844
|
+
this.#$.selection.setRange(focusNode, offset, focusNode, offset);
|
|
845
|
+
} else {
|
|
846
|
+
this.#$.focusManager.focus();
|
|
847
|
+
}
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// enter key
|
|
853
|
+
if (keyCodeMap.isEnter(keyCode)) {
|
|
854
|
+
e.preventDefault();
|
|
855
|
+
const compContext = this.currentInfo || this.get(this.currentTarget);
|
|
856
|
+
const container = compContext.container || compContext.target;
|
|
857
|
+
const sibling = container.previousElementSibling || container.nextElementSibling;
|
|
858
|
+
let newEl = null;
|
|
859
|
+
if (dom.check.isListCell(container.parentNode)) {
|
|
860
|
+
newEl = dom.utils.createElement('BR');
|
|
861
|
+
} else {
|
|
862
|
+
newEl = dom.utils.createElement(this.#$.format.isLine(sibling) ? sibling.nodeName : this.#options.get('defaultLine'), null, '<br>');
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const pluginName = this.currentPluginName;
|
|
866
|
+
this.deselect();
|
|
867
|
+
container.parentNode.insertBefore(newEl, container);
|
|
868
|
+
if (this.select(compContext.target, pluginName) === false) this.#$.focusManager.blur();
|
|
869
|
+
this.#$.history.push(false);
|
|
870
|
+
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// up down, left right
|
|
875
|
+
DIR_KEYCODE.lastIndex = 0;
|
|
876
|
+
if (DIR_KEYCODE.test(keyCode)) {
|
|
877
|
+
const { container } = this.get(this.currentTarget);
|
|
878
|
+
const isInline = this.isInline(container || this.currentTarget);
|
|
879
|
+
|
|
880
|
+
let el = null;
|
|
881
|
+
let offset = 1;
|
|
882
|
+
if (isInline) {
|
|
883
|
+
switch (keyCode) {
|
|
884
|
+
case 'ArrowLeft': // left
|
|
885
|
+
el = container.previousSibling;
|
|
886
|
+
offset = el?.nodeType === 3 ? el.textContent.length : 1;
|
|
887
|
+
break;
|
|
888
|
+
case 'ArrowRight': // right
|
|
889
|
+
el = container.nextSibling;
|
|
890
|
+
offset = 0;
|
|
891
|
+
break;
|
|
892
|
+
case 'ArrowUp': {
|
|
893
|
+
// up
|
|
894
|
+
const line = this.#$.format.getLine(container, null);
|
|
895
|
+
el = line?.previousElementSibling;
|
|
896
|
+
offset = 0;
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
case 'ArrowDown': {
|
|
900
|
+
// down
|
|
901
|
+
const line = this.#$.format.getLine(container, null);
|
|
902
|
+
el = line?.nextElementSibling;
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
} else {
|
|
907
|
+
DIR_UP_KEYCODE.lastIndex = 0;
|
|
908
|
+
if (DIR_UP_KEYCODE.test(keyCode)) {
|
|
909
|
+
el = container.previousElementSibling;
|
|
910
|
+
} else {
|
|
911
|
+
el = container.nextElementSibling;
|
|
912
|
+
offset = 0;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (!el) return;
|
|
917
|
+
|
|
918
|
+
this.deselect();
|
|
919
|
+
|
|
920
|
+
const elComp = this.get(el);
|
|
921
|
+
if (elComp?.container) {
|
|
922
|
+
e.stopPropagation();
|
|
923
|
+
e.preventDefault();
|
|
924
|
+
this.select(elComp.target, elComp.pluginName);
|
|
925
|
+
} else {
|
|
926
|
+
try {
|
|
927
|
+
this.#store.set('_preventBlur', true);
|
|
928
|
+
e.stopPropagation();
|
|
929
|
+
e.preventDefault();
|
|
930
|
+
this.#$.selection.setRange(el, offset, el, offset);
|
|
931
|
+
} finally {
|
|
932
|
+
this.#store.set('_preventBlur', false);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// ESC
|
|
940
|
+
if (keyCodeMap.isEsc(keyCode)) {
|
|
941
|
+
this.deselect();
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* @internal
|
|
948
|
+
* @description Destroy the Component instance and release memory
|
|
949
|
+
*/
|
|
950
|
+
_destroy() {
|
|
951
|
+
this.__removeGlobalEvent();
|
|
952
|
+
this.__removeDragEvent();
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
function SetClipboardComponent(e, container, clipboardData) {
|
|
957
|
+
e.preventDefault();
|
|
958
|
+
e.stopPropagation();
|
|
959
|
+
RemoveSelectedClass(container);
|
|
960
|
+
clipboardData.setData('text/html', container.outerHTML);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
function RemoveSelectedClass(container) {
|
|
964
|
+
dom.utils.removeClass(container, 'se-component-selected');
|
|
965
|
+
dom.utils.removeClass(container.querySelectorAll('.se-figure-selected'), 'se-figure-selected');
|
|
966
|
+
dom.utils.removeClass(container.querySelectorAll('.se-selected-table-cell'), 'se-selected-table-cell');
|
|
967
|
+
dom.utils.removeClass(container.querySelector('.se-selected-cell-focus'), 'se-selected-cell-focus');
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
export default Component;
|