suneditor 3.0.0-alpha.9 → 3.0.0-beta.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/CONTRIBUTING.md +170 -22
- package/{LICENSE.txt → LICENSE} +9 -9
- package/README.md +168 -30
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +47 -21
- package/src/assets/design/color.css +121 -0
- package/src/assets/design/index.css +3 -0
- package/src/assets/design/size.css +35 -0
- package/src/assets/design/typography.css +37 -0
- package/src/assets/icons/defaultIcons.js +232 -0
- package/src/assets/suneditor-contents.css +181 -46
- package/src/assets/suneditor.css +1403 -650
- package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
- package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
- package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
- package/src/core/base/eventManager.js +520 -179
- package/src/core/base/history.js +95 -41
- package/src/core/class/char.js +26 -11
- package/src/core/class/component.js +345 -137
- package/src/core/class/format.js +683 -519
- package/src/core/class/html.js +485 -305
- package/src/core/class/menu.js +133 -47
- package/src/core/class/nodeTransform.js +90 -71
- package/src/core/class/offset.js +408 -92
- package/src/core/class/selection.js +216 -106
- package/src/core/class/shortcuts.js +68 -8
- package/src/core/class/toolbar.js +106 -116
- package/src/core/class/ui.js +422 -0
- package/src/core/class/viewer.js +178 -74
- package/src/core/editor.js +496 -389
- package/src/core/section/actives.js +123 -27
- package/src/core/section/constructor.js +615 -206
- package/src/core/section/context.js +28 -23
- package/src/core/section/documentType.js +561 -0
- package/src/editorInjector/_classes.js +19 -5
- package/src/editorInjector/_core.js +71 -7
- package/src/editorInjector/index.js +63 -1
- package/src/events.js +622 -0
- package/src/helper/clipboard.js +59 -0
- package/src/helper/converter.js +202 -26
- package/src/helper/dom/domCheck.js +304 -0
- package/src/helper/dom/domQuery.js +669 -0
- package/src/helper/dom/domUtils.js +557 -0
- package/src/helper/dom/index.js +12 -0
- package/src/helper/env.js +46 -56
- package/src/helper/index.js +10 -4
- package/src/helper/keyCodeMap.js +183 -0
- package/src/helper/numbers.js +12 -8
- package/src/helper/unicode.js +9 -5
- package/src/langs/ckb.js +74 -4
- package/src/langs/cs.js +72 -2
- package/src/langs/da.js +73 -3
- package/src/langs/de.js +73 -4
- package/src/langs/en.js +23 -3
- package/src/langs/es.js +73 -4
- package/src/langs/fa.js +75 -3
- package/src/langs/fr.js +73 -3
- package/src/langs/he.js +73 -4
- package/src/langs/hu.js +230 -0
- package/src/langs/index.js +7 -3
- package/src/langs/it.js +70 -1
- package/src/langs/ja.js +72 -4
- package/src/langs/km.js +230 -0
- package/src/langs/ko.js +22 -2
- package/src/langs/lv.js +74 -5
- package/src/langs/nl.js +73 -4
- package/src/langs/pl.js +73 -4
- package/src/langs/pt_br.js +70 -1
- package/src/langs/ro.js +74 -5
- package/src/langs/ru.js +73 -4
- package/src/langs/se.js +73 -4
- package/src/langs/tr.js +73 -1
- package/src/langs/{ua.js → uk.js} +75 -6
- package/src/langs/ur.js +77 -8
- package/src/langs/zh_cn.js +74 -5
- package/src/modules/ApiManager.js +77 -54
- package/src/modules/Browser.js +667 -0
- package/src/modules/ColorPicker.js +162 -102
- package/src/modules/Controller.js +273 -142
- package/src/modules/Figure.js +925 -484
- package/src/modules/FileManager.js +121 -69
- package/src/modules/HueSlider.js +113 -61
- package/src/modules/Modal.js +291 -122
- package/src/modules/ModalAnchorEditor.js +383 -234
- package/src/modules/SelectMenu.js +270 -168
- package/src/modules/_DragHandle.js +2 -1
- package/src/modules/index.js +3 -3
- package/src/plugins/browser/audioGallery.js +83 -0
- package/src/plugins/browser/fileBrowser.js +103 -0
- package/src/plugins/browser/fileGallery.js +83 -0
- package/src/plugins/browser/imageGallery.js +81 -0
- package/src/plugins/browser/videoGallery.js +103 -0
- package/src/plugins/command/blockquote.js +40 -27
- package/src/plugins/command/exportPDF.js +134 -0
- package/src/plugins/command/fileUpload.js +229 -162
- package/src/plugins/command/list_bulleted.js +83 -47
- package/src/plugins/command/list_numbered.js +83 -47
- package/src/plugins/dropdown/align.js +66 -54
- package/src/plugins/dropdown/backgroundColor.js +63 -49
- package/src/plugins/dropdown/font.js +71 -47
- package/src/plugins/dropdown/fontColor.js +63 -48
- package/src/plugins/dropdown/formatBlock.js +70 -33
- package/src/plugins/dropdown/hr.js +92 -51
- package/src/plugins/dropdown/layout.js +37 -26
- package/src/plugins/dropdown/lineHeight.js +54 -38
- package/src/plugins/dropdown/list.js +60 -45
- package/src/plugins/dropdown/paragraphStyle.js +51 -30
- package/src/plugins/dropdown/table.js +2003 -813
- package/src/plugins/dropdown/template.js +38 -26
- package/src/plugins/dropdown/textStyle.js +43 -31
- package/src/plugins/field/mention.js +147 -86
- package/src/plugins/index.js +32 -6
- package/src/plugins/input/fontSize.js +161 -108
- package/src/plugins/input/pageNavigator.js +70 -0
- package/src/plugins/modal/audio.js +358 -173
- package/src/plugins/modal/drawing.js +531 -0
- package/src/plugins/modal/embed.js +886 -0
- package/src/plugins/modal/image.js +674 -362
- package/src/plugins/modal/link.js +100 -71
- package/src/plugins/modal/math.js +367 -167
- package/src/plugins/modal/video.js +691 -335
- package/src/plugins/popup/anchor.js +222 -0
- package/src/suneditor.js +50 -13
- package/src/themes/dark.css +122 -0
- package/src/typedef.js +130 -0
- package/types/assets/icons/defaultIcons.d.ts +153 -0
- package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
- package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
- package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
- package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
- package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
- package/types/core/base/eventManager.d.ts +385 -0
- package/types/core/base/history.d.ts +81 -0
- package/types/core/class/char.d.ts +60 -0
- package/types/core/class/component.d.ts +212 -0
- package/types/core/class/format.d.ts +616 -0
- package/types/core/class/html.d.ts +422 -0
- package/types/core/class/menu.d.ts +126 -0
- package/types/core/class/nodeTransform.d.ts +93 -0
- package/types/core/class/offset.d.ts +522 -0
- package/types/core/class/selection.d.ts +188 -0
- package/types/core/class/shortcuts.d.ts +142 -0
- package/types/core/class/toolbar.d.ts +189 -0
- package/types/core/class/ui.d.ts +164 -0
- package/types/core/class/viewer.d.ts +140 -0
- package/types/core/editor.d.ts +610 -0
- package/types/core/section/actives.d.ts +46 -0
- package/types/core/section/constructor.d.ts +777 -0
- package/types/core/section/context.d.ts +45 -0
- package/types/core/section/documentType.d.ts +178 -0
- package/types/editorInjector/_classes.d.ts +41 -0
- package/types/editorInjector/_core.d.ts +92 -0
- package/types/editorInjector/index.d.ts +71 -0
- package/types/events.d.ts +273 -0
- package/types/helper/clipboard.d.ts +12 -0
- package/types/helper/converter.d.ts +197 -0
- package/types/helper/dom/domCheck.d.ts +189 -0
- package/types/helper/dom/domQuery.d.ts +223 -0
- package/types/helper/dom/domUtils.d.ts +226 -0
- package/types/helper/dom/index.d.ts +9 -0
- package/types/helper/env.d.ts +132 -0
- package/types/helper/index.d.ts +174 -0
- package/types/helper/keyCodeMap.d.ts +110 -0
- package/types/helper/numbers.d.ts +46 -0
- package/types/helper/unicode.d.ts +28 -0
- package/types/index.d.ts +120 -0
- package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
- package/types/langs/ckb.d.ts +3 -0
- package/types/langs/cs.d.ts +3 -0
- package/types/langs/da.d.ts +3 -0
- package/types/langs/de.d.ts +3 -0
- package/types/langs/en.d.ts +3 -0
- package/types/langs/es.d.ts +3 -0
- package/types/langs/fa.d.ts +3 -0
- package/types/langs/fr.d.ts +3 -0
- package/types/langs/he.d.ts +3 -0
- package/types/langs/hu.d.ts +3 -0
- package/types/langs/index.d.ts +54 -0
- package/types/langs/it.d.ts +3 -0
- package/types/langs/ja.d.ts +3 -0
- package/types/langs/km.d.ts +3 -0
- package/types/langs/ko.d.ts +3 -0
- package/types/langs/lv.d.ts +3 -0
- package/types/langs/nl.d.ts +3 -0
- package/types/langs/pl.d.ts +3 -0
- package/types/langs/pt_br.d.ts +3 -0
- package/types/langs/ro.d.ts +3 -0
- package/types/langs/ru.d.ts +3 -0
- package/types/langs/se.d.ts +3 -0
- package/types/langs/tr.d.ts +3 -0
- package/types/langs/uk.d.ts +3 -0
- package/types/langs/ur.d.ts +3 -0
- package/types/langs/zh_cn.d.ts +3 -0
- package/types/modules/ApiManager.d.ts +125 -0
- package/types/modules/Browser.d.ts +326 -0
- package/types/modules/ColorPicker.d.ts +131 -0
- package/types/modules/Controller.d.ts +251 -0
- package/types/modules/Figure.d.ts +517 -0
- package/types/modules/FileManager.d.ts +202 -0
- package/types/modules/HueSlider.d.ts +136 -0
- package/types/modules/Modal.d.ts +111 -0
- package/types/modules/ModalAnchorEditor.d.ts +236 -0
- package/types/modules/SelectMenu.d.ts +194 -0
- package/types/modules/_DragHandle.d.ts +7 -0
- package/types/modules/index.d.ts +26 -0
- package/types/plugins/browser/audioGallery.d.ts +55 -0
- package/types/plugins/browser/fileBrowser.d.ts +64 -0
- package/types/plugins/browser/fileGallery.d.ts +55 -0
- package/types/plugins/browser/imageGallery.d.ts +51 -0
- package/types/plugins/browser/videoGallery.d.ts +57 -0
- package/types/plugins/command/blockquote.d.ts +28 -0
- package/types/plugins/command/exportPDF.d.ts +46 -0
- package/types/plugins/command/fileUpload.d.ts +156 -0
- package/types/plugins/command/list_bulleted.d.ts +46 -0
- package/types/plugins/command/list_numbered.d.ts +46 -0
- package/types/plugins/dropdown/align.d.ts +60 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
- package/types/plugins/dropdown/font.d.ts +54 -0
- package/types/plugins/dropdown/fontColor.d.ts +63 -0
- package/types/plugins/dropdown/formatBlock.d.ts +54 -0
- package/types/plugins/dropdown/hr.d.ts +71 -0
- package/types/plugins/dropdown/layout.d.ts +40 -0
- package/types/plugins/dropdown/lineHeight.d.ts +50 -0
- package/types/plugins/dropdown/list.d.ts +39 -0
- package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
- package/types/plugins/dropdown/table.d.ts +627 -0
- package/types/plugins/dropdown/template.d.ts +40 -0
- package/types/plugins/dropdown/textStyle.d.ts +41 -0
- package/types/plugins/field/mention.d.ts +102 -0
- package/types/plugins/index.d.ts +107 -0
- package/types/plugins/input/fontSize.d.ts +170 -0
- package/types/plugins/input/pageNavigator.d.ts +28 -0
- package/types/plugins/modal/audio.d.ts +269 -0
- package/types/plugins/modal/drawing.d.ts +246 -0
- package/types/plugins/modal/embed.d.ts +387 -0
- package/types/plugins/modal/image.d.ts +451 -0
- package/types/plugins/modal/link.d.ts +128 -0
- package/types/plugins/modal/math.d.ts +193 -0
- package/types/plugins/modal/video.d.ts +485 -0
- package/types/plugins/popup/anchor.d.ts +56 -0
- package/types/suneditor.d.ts +51 -0
- package/types/typedef.d.ts +233 -0
- package/.eslintignore +0 -7
- package/.eslintrc.json +0 -64
- package/src/assets/icons/_default.js +0 -194
- package/src/core/base/events.js +0 -320
- package/src/core/class/notice.js +0 -42
- package/src/helper/domUtils.js +0 -1177
- package/src/modules/FileBrowser.js +0 -271
- package/src/plugins/command/exportPdf.js +0 -168
- package/src/plugins/fileBrowser/imageGallery.js +0 -81
- package/src/themes/test.css +0 -61
- package/typings/CommandPlugin.d.ts +0 -8
- package/typings/DialogPlugin.d.ts +0 -20
- package/typings/FileBrowserPlugin.d.ts +0 -30
- package/typings/Module.d.ts +0 -15
- package/typings/Plugin.d.ts +0 -42
- package/typings/SubmenuPlugin.d.ts +0 -8
- package/typings/_classes.d.ts +0 -17
- package/typings/_colorPicker.d.ts +0 -60
- package/typings/_core.d.ts +0 -55
- package/typings/align.d.ts +0 -5
- package/typings/audio.d.ts +0 -5
- package/typings/backgroundColor.d.ts +0 -5
- package/typings/blockquote.d.ts +0 -5
- package/typings/char.d.ts +0 -39
- package/typings/component.d.ts +0 -38
- package/typings/context.d.ts +0 -39
- package/typings/converter.d.ts +0 -33
- package/typings/dialog.d.ts +0 -28
- package/typings/domUtils.d.ts +0 -361
- package/typings/editor.d.ts +0 -7
- package/typings/editor.ts +0 -542
- package/typings/env.d.ts +0 -70
- package/typings/eventManager.d.ts +0 -37
- package/typings/events.d.ts +0 -262
- package/typings/fileBrowser.d.ts +0 -42
- package/typings/fileManager.d.ts +0 -67
- package/typings/font.d.ts +0 -5
- package/typings/fontColor.d.ts +0 -5
- package/typings/fontSize.d.ts +0 -5
- package/typings/format.d.ts +0 -191
- package/typings/formatBlock.d.ts +0 -5
- package/typings/history.d.ts +0 -48
- package/typings/horizontalRule.d.ts +0 -5
- package/typings/image.d.ts +0 -5
- package/typings/imageGallery.d.ts +0 -5
- package/typings/index.d.ts +0 -21
- package/typings/index.modules.d.ts +0 -11
- package/typings/index.plugins.d.ts +0 -58
- package/typings/lineHeight.d.ts +0 -5
- package/typings/link.d.ts +0 -5
- package/typings/list.d.ts +0 -5
- package/typings/math.d.ts +0 -5
- package/typings/mediaContainer.d.ts +0 -25
- package/typings/mention.d.ts +0 -5
- package/typings/node.d.ts +0 -57
- package/typings/notice.d.ts +0 -16
- package/typings/numbers.d.ts +0 -29
- package/typings/offset.d.ts +0 -24
- package/typings/options.d.ts +0 -589
- package/typings/paragraphStyle.d.ts +0 -5
- package/typings/resizing.d.ts +0 -141
- package/typings/selection.d.ts +0 -94
- package/typings/shortcuts.d.ts +0 -13
- package/typings/suneditor.d.ts +0 -9
- package/typings/table.d.ts +0 -5
- package/typings/template.d.ts +0 -5
- package/typings/textStyle.d.ts +0 -5
- package/typings/toolbar.d.ts +0 -32
- package/typings/unicode.d.ts +0 -25
- package/typings/video.d.ts +0 -5
|
@@ -1,17 +1,35 @@
|
|
|
1
|
-
import _icons from '../../assets/icons/
|
|
1
|
+
import _icons from '../../assets/icons/defaultIcons';
|
|
2
2
|
import _defaultLang from '../../langs/en';
|
|
3
3
|
import { CreateContext, CreateFrameContext } from './context';
|
|
4
|
-
import {
|
|
4
|
+
import { dom, numbers, converter, env } from '../../helper';
|
|
5
5
|
|
|
6
6
|
const _d = env._d;
|
|
7
|
-
const DEFAULT_BUTTON_LIST = [
|
|
7
|
+
const DEFAULT_BUTTON_LIST = [
|
|
8
|
+
['undo', 'redo'],
|
|
9
|
+
'|',
|
|
10
|
+
['bold', 'underline', 'italic', 'strike', '|', 'subscript', 'superscript'],
|
|
11
|
+
'|',
|
|
12
|
+
['removeFormat'],
|
|
13
|
+
'|',
|
|
14
|
+
['outdent', 'indent'],
|
|
15
|
+
'|',
|
|
16
|
+
['fullScreen', 'showBlocks', 'codeView'],
|
|
17
|
+
'|',
|
|
18
|
+
['preview', 'print']
|
|
19
|
+
];
|
|
8
20
|
|
|
9
21
|
const REQUIRED_FORMAT_LINE = 'div';
|
|
10
22
|
const REQUIRED_ELEMENT_WHITELIST = 'br|div';
|
|
11
23
|
const DEFAULT_ELEMENT_WHITELIST =
|
|
12
24
|
'p|pre|blockquote|h1|h2|h3|h4|h5|h6|ol|ul|li|hr|figure|figcaption|img|iframe|audio|video|source|table|thead|tbody|tr|th|td|caption|a|b|strong|var|i|em|u|ins|s|span|strike|del|sub|sup|code|svg|path|details|summary';
|
|
13
25
|
const DEFAULT_TEXT_STYLE_TAGS = 'strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary';
|
|
14
|
-
|
|
26
|
+
|
|
27
|
+
/* scopeSelectionTags */
|
|
28
|
+
const DEFAULT_SCOPE_SELECTION_TAGS = 'td|table|li|ol|ul|pre|figcaption|blockquote|dl|dt|dd';
|
|
29
|
+
|
|
30
|
+
const _video_audio_attr = '|controls|autoplay|loop|muted|poster|preload|playsinline|volume|crossorigin|disableRemotePlayback|controlsList';
|
|
31
|
+
const _iframe_attr = '|allowfullscreen|sandbox|loading|allow|referrerpolicy|frameborder|scrolling';
|
|
32
|
+
const DEFAULT_ATTRIBUTE_WHITELIST = 'contenteditable|target|href|title|download|rel|src|alt|class|type|colspan|rowspan' + _video_audio_attr + _iframe_attr;
|
|
15
33
|
|
|
16
34
|
const DEFAULT_FORMAT_LINE = 'P|H[1-6]|LI|TH|TD|DETAILS';
|
|
17
35
|
const DEFAULT_FORMAT_BR_LINE = 'PRE';
|
|
@@ -19,9 +37,12 @@ const DEFAULT_FORMAT_CLOSURE_BR_LINE = '';
|
|
|
19
37
|
const DEFAULT_FORMAT_BLOCK = 'BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS';
|
|
20
38
|
const DEFAULT_FORMAT_CLOSURE_BLOCK = 'TH|TD';
|
|
21
39
|
|
|
40
|
+
const DEFAULT_ALLOWED_EMPTY_NODE_LIST = '.se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas, details';
|
|
41
|
+
|
|
22
42
|
const DEFAULT_SIZE_UNITS = ['px', 'pt', 'em', 'rem'];
|
|
23
43
|
|
|
24
|
-
const DEFAULT_CLASS_NAME = '^__se__|^se-|^katex';
|
|
44
|
+
const DEFAULT_CLASS_NAME = '^__se__|^se-|^katex|^MathJax';
|
|
45
|
+
const DEFAULT_CLASS_MJX = 'mjx-container|mjx-math|mjx-mrow|mjx-mi|mjx-mo|mjx-mn|mjx-msup|mjx-mfrac|mjx-munderover';
|
|
25
46
|
const DEFAULT_EXTRA_TAG_MAP = { script: false, style: false, meta: false, link: false, '[a-z]+:[a-z]+': false };
|
|
26
47
|
|
|
27
48
|
const DEFAULT_TAG_STYLES = {
|
|
@@ -42,6 +63,7 @@ const DEFAULT_CONTENT_STYLES =
|
|
|
42
63
|
'margin|margin-block-end|margin-block-start|margin-bottom|margin-inline-end|margin-inline-start|margin-left|margin-right|margin-top|max-width|min-width|' +
|
|
43
64
|
'outline|overflow|' +
|
|
44
65
|
'position|padding|padding-bottom|padding-inline-start|padding-left|padding-right|padding-top|' +
|
|
66
|
+
'page-break-before|page-break-after|page-break-inside|' +
|
|
45
67
|
'rotate|rotateX|rotateY|' +
|
|
46
68
|
'table-layout|text-align|text-decoration|text-shadow|text-transform|top|' +
|
|
47
69
|
'text-indent|text-rendering|' +
|
|
@@ -50,49 +72,270 @@ const DEFAULT_CONTENT_STYLES =
|
|
|
50
72
|
|
|
51
73
|
const RETAIN_STYLE_MODE = ['repeat', 'always', 'none'];
|
|
52
74
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
]
|
|
75
|
+
/**
|
|
76
|
+
* @typedef {Object} EditorFrameOptions
|
|
77
|
+
* @property {string} [value=""] - Initial value for the editor.
|
|
78
|
+
* @property {string} [placeholder=""] - Placeholder text.
|
|
79
|
+
* @property {Object<string, string>} [editableFrameAttributes={}] - Attributes for the editable frame[.sun-editor-editable]. (e.g. [key]: value)
|
|
80
|
+
* @property {string} [width="100%"] - Width for the editor.
|
|
81
|
+
* @property {string} [minWidth=""] - Min width for the editor.
|
|
82
|
+
* @property {string} [maxWidth=""] - Max width for the editor.
|
|
83
|
+
* @property {string} [height="auto"] - Height for the editor.
|
|
84
|
+
* @property {string} [minHeight=""] - Min height for the editor.
|
|
85
|
+
* @property {string} [maxHeight=""] - Max height for the editor.
|
|
86
|
+
* @property {string} [editorStyle=""] - Style string of the top frame of the editor. (e.g. "border: 1px solid #ccc;").
|
|
87
|
+
* @property {boolean} [iframe=false] - Content will be placed in an iframe and isolated from the rest of the page.
|
|
88
|
+
* @property {boolean} [iframe_fullPage=false] - Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration on the "iframe".
|
|
89
|
+
* @property {Object<string, string>} [iframe_attributes={}] - Attributes of the "iframe". (e.g. {'scrolling': 'no'})
|
|
90
|
+
* @property {string} [iframe_cssFileName="suneditor"] - Name or Array of the CSS file to apply inside the iframe.
|
|
91
|
+
* - You can also use regular expressions.
|
|
92
|
+
* - Applied by searching by filename in the link tag of document,
|
|
93
|
+
* - or put the URL value (".css" can be omitted).
|
|
94
|
+
* @property {boolean} [statusbar=true] - Enables the status bar.
|
|
95
|
+
* @property {boolean} [statusbar_showPathLabel=true] - Displays the current node structure to status bar.
|
|
96
|
+
* @property {boolean} [statusbar_resizeEnable=true] - Enables resize function of bottom status bar
|
|
97
|
+
* @property {boolean} [charCounter=false] - Shows the number of characters in the editor.
|
|
98
|
+
* - If the maxCharCount option has a value, it becomes true.
|
|
99
|
+
* @property {number} [charCounter_max] - The maximum number of characters allowed to be inserted into the editor.
|
|
100
|
+
* @property {string} [charCounter_label] - Text to be displayed in the "charCounter" area of the bottom bar. (e.g. "Characters : 20/200")
|
|
101
|
+
* @property {"char"|"byte"|"byte-html"} [charCounter_type="char"] - Defines the calculation method of the "charCounter" option.
|
|
102
|
+
* - 'char': Characters length.
|
|
103
|
+
* - 'byte': Binary data size of characters.
|
|
104
|
+
* - 'byte-html': Binary data size of the full HTML string.
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {Object} EditorBaseOptions
|
|
109
|
+
* @property {Object<string, *>|Array<Object<string, *>>} [plugins] - Plugin configuration.
|
|
110
|
+
* @property {Array<string>} [excludedPlugins] - Plugin configuration.
|
|
111
|
+
* @property {Array<string[]|string>} [buttonList] - List of toolbar buttons, grouped by sub-arrays.
|
|
112
|
+
* @property {boolean} [v2Migration=false] - Enables migration mode for SunEditor v2.
|
|
113
|
+
* @property {boolean|{tagFilter: boolean, formatFilter: boolean, classFilter: boolean, styleNodeFilter: boolean, attrFilter: boolean, styleFilter: boolean}} [strictMode=true] - Enables strict filtering of tags, attributes, and styles.
|
|
114
|
+
* @property {"classic"|"inline"|"balloon"|"balloon-always"} [mode="classic"] - Toolbar mode: "classic", "inline", "balloon", "balloon-always".
|
|
115
|
+
* @property {string} [type=""] - Editor type: "document:header,page".
|
|
116
|
+
* @property {string} [theme=""] - Editor theme.
|
|
117
|
+
* @property {Object<string, string>} [lang] - Language configuration.
|
|
118
|
+
* @property {Array<string>} [fontSizeUnits=["px", "pt", "em", "rem"]] - Allowed font size units.
|
|
119
|
+
* @property {string} [allowedClassName] - Allowed class names.
|
|
120
|
+
* @property {boolean} [closeModalOutsideClick=false] - Closes modals when clicking outside.
|
|
121
|
+
* @property {boolean} [copyFormatKeepOn=false] - Keeps the format of the copied content.
|
|
122
|
+
* @property {boolean} [syncTabIndent=true] - Synchronizes tab indent with spaces.
|
|
123
|
+
* @property {boolean} [tabDisable=false] - Disables tab key input.
|
|
124
|
+
* @property {boolean} [autoLinkify] - Automatically converts URLs into hyperlinks. ("Link" plugin required)
|
|
125
|
+
* @property {Array<string>} [autoStyleify=["bold", "underline", "italic", "strike"]] - Styles applied automatically on text input.
|
|
126
|
+
* @property {Object<string, string|number>} [scrollToOptions={behavior: "auto", block: "nearest"}] - Configuration for scroll behavior when navigating editor content.
|
|
127
|
+
* @property {Object<string, string|number>} [componentScrollToOptions={behavior: "smooth", block: "center"}] - Configuration for scroll behavior when navigating components.
|
|
128
|
+
* @property {"repeat"|"always"|"none"} [retainStyleMode="repeat"] - This option determines how inline elements (such as <span>, <strong>, etc.) are handled when deleting text.
|
|
129
|
+
* - "repeat": Inline styles are retained unless the backspace key is repeatedly pressed. If the user continuously presses backspace, the styles will eventually be removed.
|
|
130
|
+
* - "none": Inline styles are not retained at all. When deleting text, the associated inline elements are immediately removed along with it.
|
|
131
|
+
* - "always": Inline styles persist indefinitely unless explicitly removed. Even if all text inside an inline element is deleted, the element itself remains until manually removed.
|
|
132
|
+
* @property {Object<string, boolean>} [allowedExtraTags={script: false, style: false, meta: false, link: false, "[a-z]+:[a-z]+": false}] - Specifies extra allowed or disallowed tags.
|
|
133
|
+
* @property {Object<string, (...args: *) => *>} [events={}] - Custom event handlers.
|
|
134
|
+
* @property {string} [__textStyleTags="strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary"] - The basic tags that serves as the base for "textStyleTags"
|
|
135
|
+
* @property {string} [textStyleTags="strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary"] - Additional text style tags.
|
|
136
|
+
* @property {Object<string, string>} [convertTextTags={bold: "strong", underline: "u", italic: "em", strike: "del", subscript: "sub", superscript: "sup"}] - Maps text styles to specific HTML tags.
|
|
137
|
+
* @property {Object<string, string>} [__tagStyles={'table|th|td': 'border|border-[a-z]+|background-color|text-align|float|font-weight|text-decoration|font-style', 'ol|ul': 'list-style-type'}] - The basic tags that serves as the base for "tagStyles"
|
|
138
|
+
* @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags.
|
|
139
|
+
* @property {string} [spanStyles="font-family|font-size|color|background-color"] - Specifies allowed styles for the "span" tag.
|
|
140
|
+
* @property {string} [lineStyles="text-align|margin-left|margin-right|line-height"] - Specifies allowed styles for the "line" element (p..).
|
|
141
|
+
* @property {string} [textDirection="ltr"] - Text direction: "ltr" or "rtl".
|
|
142
|
+
* @property {Array<string>} [reverseButtons=['indent-outdent']] - An array of command pairs whose shortcut icons should be opposite each other, depending on the "textDirection" mode.
|
|
143
|
+
* @property {number} [historyStackDelayTime=400] - Delay time for history stack updates (ms).
|
|
144
|
+
* @property {string} [lineAttrReset=""] - Line properties that should be reset when changing lines (e.g. "id|name").
|
|
145
|
+
* @property {string} [printClass=""] - Class name for printing.
|
|
146
|
+
* @property {string} [defaultLine="p"] - Default line element when inserting new lines.
|
|
147
|
+
* @property {"line"|"br"} [defaultLineBreakFormat="line"] - Specifies the default line break format.
|
|
148
|
+
* - [Recommended] "line" : is a line break that is divided into general tags.
|
|
149
|
+
* - [Not recommended] "br" : Line breaks are treated as <br> on the same line. (like shift+enter)
|
|
150
|
+
* - Line breaks are handled as <br> within "line".
|
|
151
|
+
* - You can create a new "line" by entering a line break twice in a row.
|
|
152
|
+
* - Formats that include "line", such as "Quote", still operate on a "line" basis.
|
|
153
|
+
* - ● suneditor processes work in "line" units.
|
|
154
|
+
* - ● When set to "br", performance may decrease when editing a lot of data.
|
|
155
|
+
* @property {Array<string>} [scopeSelectionTags=["td", "table", "li", "ol", "ul", "pre", "figcaption", "blockquote", "dl", "dt", "dd"]] - Tags treated as whole units when selecting all content.
|
|
156
|
+
* @property {string} [__defaultElementWhitelist="br|div"] - Default allowed HTML elements. The default values are maintained.
|
|
157
|
+
* @property {string} [elementWhitelist=""] - Allowed HTML elements. Delimiter: "|" (e.g. "p|div", "*").
|
|
158
|
+
* @property {string} [elementBlacklist=""] - Disallowed HTML elements. Delimiter: "|" (e.g. "script|style").
|
|
159
|
+
* @property {string} [__defaultAttributeWhitelist] - Allowed attributes. Delimiter: "|" (e.g. "href|target").
|
|
160
|
+
* @property {Object<string, string>} [attributeWhitelist=""] - Allowed attributes. (e.g. {a: "href|target", img: "src|alt"}).
|
|
161
|
+
* @property {Object<string, string>} [attributeBlacklist=""] - Disallowed attributes. (e.g. {a: "href|target", img: "src|alt"}).
|
|
162
|
+
* @property {string} [__defaultFormatLine="P|DIV|H[1-6]|LI|TH|TD|DETAILS"] - Overrides the editor's default "line" element.
|
|
163
|
+
* @property {string} [formatLine="P|DIV|H[1-6]|LI|TH|TD|DETAILS"] - Specifies the editor's "line" elements.
|
|
164
|
+
* - (P, DIV, H[1-6], PRE, LI | class="__se__format__line_xxx")
|
|
165
|
+
* - "line" element also contain "brLine" element
|
|
166
|
+
* @property {string} [__defaultFormatBrLine="PRE"] - Overrides the editor's default "brLine" element.
|
|
167
|
+
* @property {string} [formatBrLine="PRE"] - Specifies the editor's "brLine" elements. (e.g. "PRE").
|
|
168
|
+
* - (PRE | class="__se__format__br_line_xxx")
|
|
169
|
+
* - "brLine" elements is included in the "line" element.
|
|
170
|
+
* - "brLine" elements's line break is "BR" tag.
|
|
171
|
+
* ※ Entering the Enter key in the space on the last line ends "brLine" and appends "line".
|
|
172
|
+
* @property {string} [__defaultFormatClosureBrLine=""] - Overrides the editor's default "closureBrLine" element.
|
|
173
|
+
* @property {string} [formatClosureBrLine=""] - Specifies the editor's "closureBrLine" elements.
|
|
174
|
+
* - (class="__se__format__br_line__closure_xxx")
|
|
175
|
+
* - "closureBrLine" elements is included in the "brLine".
|
|
176
|
+
* - "closureBrLine" elements's line break is "BR" tag.
|
|
177
|
+
* - ※ You cannot exit this format with the Enter key or Backspace key.
|
|
178
|
+
* - ※ Use it only in special cases. ([ex] format of table cells)
|
|
179
|
+
* @property {string} [__defaultFormatBlock="BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS"] - Overrides the editor's default "block" element.
|
|
180
|
+
* @property {string} [formatBlock="BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS"] - Specifies the editor's "block" elements.
|
|
181
|
+
* - (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD | class="__se__format__block_xxx")
|
|
182
|
+
* - "block" is wrap the "line" and "component"
|
|
183
|
+
* @property {string} [__defaultFormatClosureBlock="TH|TD"] - Overrides the editor's default "closureBlock" element.
|
|
184
|
+
* @property {string} [formatClosureBlock="TH|TD"] - Specifies the editor's "closureBlock" elements.
|
|
185
|
+
* - (TH, TD | class="__se__format__block_closure_xxx")
|
|
186
|
+
* - "closureBlock" elements is included in the "block".
|
|
187
|
+
* - "closureBlock" element is wrap the "line" and "component"
|
|
188
|
+
* - ※ You cannot exit this format with the Enter key or Backspace key.
|
|
189
|
+
* - ※ Use it only in special cases. ([ex] format of table cells)
|
|
190
|
+
* @property {string} [allowedEmptyTags=".se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas, details"] - Allowed empty tags.
|
|
191
|
+
* @property {number|string} [toolbar_width="auto"] - Toolbar width.
|
|
192
|
+
* @property {Element|string} [toolbar_container] - Container element for the toolbar.
|
|
193
|
+
* @property {number} [toolbar_sticky=0] - Enables sticky toolbar with optional offset.
|
|
194
|
+
* @property {boolean} [toolbar_hide=false] - Hides toolbar initially.
|
|
195
|
+
* @property {Object} [subToolbar] - Sub-toolbar configuration.
|
|
196
|
+
* @property {Array<Array<string>>} [subToolbar.buttonList] - List of Sub-toolbar buttons, grouped by sub-arrays.
|
|
197
|
+
* @property {"balloon"|"balloon-always"} [subToolbar.mode="balloon"] - Sub-toolbar mode: "balloon", "balloon-always".
|
|
198
|
+
* @property {number|string} [subToolbar.width="auto"] - Sub-toolbar width.
|
|
199
|
+
* @property {Element|string} [statusbar_container] - Container element for the status bar.
|
|
200
|
+
* @property {boolean} [shortcutsHint=true] - Displays shortcut hints in tooltips.
|
|
201
|
+
* @property {boolean} [shortcutsDisable=false] - Disables keyboard shortcuts.
|
|
202
|
+
* @property {Object<string, Array<string>>} [shortcuts] - Custom keyboard shortcuts.
|
|
203
|
+
* @property {number} [fullScreenOffset=0] - Offset applied when entering fullscreen mode.
|
|
204
|
+
* @property {string} [previewTemplate] - Custom template for preview mode.
|
|
205
|
+
* @property {string} [printTemplate] - Custom template for print mode.
|
|
206
|
+
* @property {boolean} [componentAutoSelect=false] - Enables automatic selection of inserted components.
|
|
207
|
+
* @property {string} [defaultUrlProtocol] - Default URL protocol for links.
|
|
208
|
+
* @property {string} [allUsedStyles] - Specifies additional styles to the list of allowed styles. Delimiter: "|" (e.g. "color|background-color").
|
|
209
|
+
* @property {Object<"copy", number>} [toastMessageTime] - {"copy": 1500} - Duration for displaying toast messages.
|
|
210
|
+
* @property {Object<string, string>} [icons] - Overrides the default icons.
|
|
211
|
+
* @property {string} [freeCodeViewMode=false] - Enables free code view mode.
|
|
212
|
+
* @property {boolean} [__lineFormatFilter=true] - Line format filter configuration.
|
|
213
|
+
* @property {boolean} [__pluginRetainFilter=true] - Plugin retain filter configuration.
|
|
214
|
+
* @property {Array<string>} [__listCommonStyle=["fontSize", "color", "fontFamily", "fontWeight", "fontStyle"]] - Defines the list of styles that are applied directly to the `<li>` element
|
|
215
|
+
* - when a text style is applied to the entire list item.
|
|
216
|
+
* - For example, when changing the font size or color of a list item (`<li>`),
|
|
217
|
+
* - these styles will be applied to the `<li>` tag instead of wrapping the content inside additional tags.
|
|
218
|
+
* @property {Object<string, *>} [externalLibs] - External libraries like CodeMirror or MathJax.
|
|
219
|
+
*
|
|
220
|
+
* @property {Object<string, *>} [Dynamic_pluginOptions] - Dynamic plugin options, where the key is the plugin name and the value is its configuration.
|
|
221
|
+
*/
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @typedef {EditorBaseOptions & EditorFrameOptions} EditorInitOptions
|
|
225
|
+
*/
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* @description For all EditorInitOptions keys, only boolean | null values are allowed.
|
|
229
|
+
* - 'fixed' → Immutable / null → Resettable.
|
|
230
|
+
* @type {Partial<Record<keyof EditorInitOptions, "fixed" | true>>}
|
|
231
|
+
*/
|
|
232
|
+
export const OPTION_FIXED_FLAG = {
|
|
233
|
+
value: 'fixed',
|
|
234
|
+
placeholder: 'fixed',
|
|
235
|
+
editableFrameAttributes: null,
|
|
236
|
+
width: null,
|
|
237
|
+
minWidth: null,
|
|
238
|
+
maxWidth: null,
|
|
239
|
+
height: null,
|
|
240
|
+
minHeight: null,
|
|
241
|
+
maxHeight: null,
|
|
242
|
+
editorStyle: null,
|
|
243
|
+
iframe: 'fixed',
|
|
244
|
+
iframe_fullPage: null,
|
|
245
|
+
iframe_attributes: null,
|
|
246
|
+
iframe_cssFileName: null,
|
|
247
|
+
statusbar: null,
|
|
248
|
+
statusbar_showPathLabel: null,
|
|
249
|
+
statusbar_resizeEnable: null,
|
|
250
|
+
charCounter: null,
|
|
251
|
+
charCounter_max: null,
|
|
252
|
+
charCounter_label: null,
|
|
253
|
+
charCounter_type: null,
|
|
254
|
+
plugins: null,
|
|
255
|
+
excludedPlugins: null,
|
|
256
|
+
buttonList: 'fixed',
|
|
257
|
+
v2Migration: null,
|
|
258
|
+
strictMode: null,
|
|
259
|
+
mode: 'fixed',
|
|
260
|
+
type: 'fixed',
|
|
261
|
+
theme: null,
|
|
262
|
+
lang: 'fixed',
|
|
263
|
+
fontSizeUnits: 'fixed',
|
|
264
|
+
allowedClassName: null,
|
|
265
|
+
closeModalOutsideClick: null,
|
|
266
|
+
copyFormatKeepOn: null,
|
|
267
|
+
syncTabIndent: null,
|
|
268
|
+
tabDisable: null,
|
|
269
|
+
autoLinkify: null,
|
|
270
|
+
autoStyleify: null,
|
|
271
|
+
scrollToOptions: null,
|
|
272
|
+
componentScrollToOptions: null,
|
|
273
|
+
retainStyleMode: null,
|
|
274
|
+
allowedExtraTags: null,
|
|
275
|
+
events: null,
|
|
276
|
+
__textStyleTags: 'fixed',
|
|
277
|
+
textStyleTags: 'fixed',
|
|
278
|
+
convertTextTags: 'fixed',
|
|
279
|
+
__tagStyles: null,
|
|
280
|
+
tagStyles: 'fixed',
|
|
281
|
+
spanStyles: 'fixed',
|
|
282
|
+
lineStyles: 'fixed',
|
|
283
|
+
textDirection: null,
|
|
284
|
+
reverseButtons: null,
|
|
285
|
+
historyStackDelayTime: null,
|
|
286
|
+
lineAttrReset: null,
|
|
287
|
+
printClass: null,
|
|
288
|
+
defaultLine: 'fixed',
|
|
289
|
+
defaultLineBreakFormat: null,
|
|
290
|
+
scopeSelectionTags: null,
|
|
291
|
+
__defaultElementWhitelist: 'fixed',
|
|
292
|
+
elementWhitelist: 'fixed',
|
|
293
|
+
elementBlacklist: 'fixed',
|
|
294
|
+
__defaultAttributeWhitelist: 'fixed',
|
|
295
|
+
attributeWhitelist: 'fixed',
|
|
296
|
+
attributeBlacklist: 'fixed',
|
|
297
|
+
__defaultFormatLine: null,
|
|
298
|
+
formatLine: 'fixed',
|
|
299
|
+
__defaultFormatBrLine: null,
|
|
300
|
+
formatBrLine: 'fixed',
|
|
301
|
+
__defaultFormatClosureBrLine: 'fixed',
|
|
302
|
+
formatClosureBrLine: 'fixed',
|
|
303
|
+
__defaultFormatBlock: null,
|
|
304
|
+
formatBlock: 'fixed',
|
|
305
|
+
__defaultFormatClosureBlock: null,
|
|
306
|
+
formatClosureBlock: 'fixed',
|
|
307
|
+
allowedEmptyTags: null,
|
|
308
|
+
toolbar_width: null,
|
|
309
|
+
toolbar_container: 'fixed',
|
|
310
|
+
toolbar_sticky: null,
|
|
311
|
+
toolbar_hide: null,
|
|
312
|
+
subToolbar: 'fixed',
|
|
313
|
+
statusbar_container: 'fixed',
|
|
314
|
+
shortcutsHint: null,
|
|
315
|
+
shortcutsDisable: 'fixed',
|
|
316
|
+
shortcuts: 'fixed',
|
|
317
|
+
fullScreenOffset: null,
|
|
318
|
+
previewTemplate: null,
|
|
319
|
+
printTemplate: null,
|
|
320
|
+
componentAutoSelect: null,
|
|
321
|
+
defaultUrlProtocol: null,
|
|
322
|
+
allUsedStyles: null,
|
|
323
|
+
toastMessageTime: null,
|
|
324
|
+
icons: 'fixed',
|
|
325
|
+
freeCodeViewMode: null,
|
|
326
|
+
__lineFormatFilter: null,
|
|
327
|
+
__pluginRetainFilter: null,
|
|
328
|
+
__listCommonStyle: 'fixed',
|
|
329
|
+
externalLibs: 'fixed'
|
|
330
|
+
};
|
|
88
331
|
|
|
89
332
|
/**
|
|
90
|
-
* @description
|
|
91
|
-
* @param {
|
|
92
|
-
* @param {
|
|
93
|
-
* @returns {Object}
|
|
333
|
+
* @description Creates a new SunEditor instance with specified options.
|
|
334
|
+
* @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} editorTargets - Target element or multi-root object.
|
|
335
|
+
* @param {EditorInitOptions} options - Configuration options for the editor.
|
|
336
|
+
* @returns {Object<string, *>} - SunEditor instance with context, options, and DOM elements.
|
|
94
337
|
*/
|
|
95
|
-
|
|
338
|
+
function Constructor(editorTargets, options) {
|
|
96
339
|
if (typeof options !== 'object') options = {};
|
|
97
340
|
|
|
98
341
|
/** --- Plugins ------------------------------------------------------------------------------------------ */
|
|
@@ -113,35 +356,45 @@ const Constructor = function (editorTargets, options) {
|
|
|
113
356
|
const o = optionMap.o;
|
|
114
357
|
const icons = optionMap.i;
|
|
115
358
|
const lang = optionMap.l;
|
|
116
|
-
const loadingBox =
|
|
359
|
+
const loadingBox = dom.utils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
|
|
117
360
|
|
|
118
361
|
/** --- carrier wrapper --------------------------------------------------------------- */
|
|
119
|
-
const editor_carrier_wrapper =
|
|
362
|
+
const editor_carrier_wrapper = dom.utils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
120
363
|
// menuTray
|
|
121
|
-
const menuTray =
|
|
364
|
+
const menuTray = dom.utils.createElement('DIV', { class: 'se-menu-tray' });
|
|
122
365
|
editor_carrier_wrapper.appendChild(menuTray);
|
|
123
366
|
// focus temp element
|
|
124
|
-
const focusTemp =
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
367
|
+
const focusTemp = /** @type {HTMLInputElement} */ (
|
|
368
|
+
dom.utils.createElement('INPUT', {
|
|
369
|
+
class: '__se__focus__temp__',
|
|
370
|
+
style: 'position: fixed !important; top: -10000px !important; left: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;'
|
|
371
|
+
})
|
|
372
|
+
);
|
|
128
373
|
focusTemp.tabIndex = 0;
|
|
129
374
|
editor_carrier_wrapper.appendChild(focusTemp);
|
|
130
375
|
|
|
131
376
|
// modal
|
|
132
|
-
const modal =
|
|
133
|
-
const modal_back =
|
|
134
|
-
const modal_inner =
|
|
377
|
+
const modal = dom.utils.createElement('DIV', { class: 'se-modal se-modal-area sun-editor-common' });
|
|
378
|
+
const modal_back = dom.utils.createElement('DIV', { class: 'se-modal-back' });
|
|
379
|
+
const modal_inner = dom.utils.createElement('DIV', { class: 'se-modal-inner' });
|
|
135
380
|
modal.appendChild(modal_back);
|
|
136
381
|
modal.appendChild(modal_inner);
|
|
137
382
|
editor_carrier_wrapper.appendChild(modal);
|
|
138
383
|
|
|
384
|
+
// alert
|
|
385
|
+
const alert = dom.utils.createElement('DIV', { class: 'se-alert se-modal-area sun-editor-common', style: 'display: none;' });
|
|
386
|
+
const alert_back = dom.utils.createElement('DIV', { class: 'se-modal-back' });
|
|
387
|
+
const alert_inner = dom.utils.createElement('DIV', { class: 'se-modal-inner' });
|
|
388
|
+
alert.appendChild(alert_back);
|
|
389
|
+
alert.appendChild(alert_inner);
|
|
390
|
+
editor_carrier_wrapper.appendChild(alert);
|
|
391
|
+
|
|
139
392
|
// loding box, resizing back
|
|
140
|
-
editor_carrier_wrapper.appendChild(
|
|
393
|
+
editor_carrier_wrapper.appendChild(dom.utils.createElement('DIV', { class: 'se-back-wrapper' }));
|
|
141
394
|
editor_carrier_wrapper.appendChild(loadingBox.cloneNode(true));
|
|
142
395
|
|
|
143
396
|
// drag cursor
|
|
144
|
-
const dragCursor =
|
|
397
|
+
const dragCursor = dom.utils.createElement('DIV', { class: 'se-drag-cursor' });
|
|
145
398
|
editor_carrier_wrapper.appendChild(dragCursor);
|
|
146
399
|
|
|
147
400
|
// set carrier wrapper
|
|
@@ -160,7 +413,7 @@ const Constructor = function (editorTargets, options) {
|
|
|
160
413
|
} else if (/balloon/i.test(o.get('mode'))) {
|
|
161
414
|
toolbar.className += ' se-toolbar-balloon';
|
|
162
415
|
toolbar.style.width = o.get('toolbar_width');
|
|
163
|
-
toolbar.appendChild(
|
|
416
|
+
toolbar.appendChild(dom.utils.createElement('DIV', { class: 'se-arrow' }));
|
|
164
417
|
}
|
|
165
418
|
|
|
166
419
|
/** --- subToolbar --------------------------------------------------------------- */
|
|
@@ -171,7 +424,7 @@ const Constructor = function (editorTargets, options) {
|
|
|
171
424
|
// subbar mode must be balloon-*
|
|
172
425
|
subbar.className += ' se-toolbar-balloon se-toolbar-sub';
|
|
173
426
|
subbar.style.width = o.get('toolbar.sub_width');
|
|
174
|
-
subbar.appendChild(
|
|
427
|
+
subbar.appendChild(dom.utils.createElement('DIV', { class: 'se-arrow' }));
|
|
175
428
|
}
|
|
176
429
|
|
|
177
430
|
/** frame - root set - start -------------------------------------------------------------- */
|
|
@@ -182,12 +435,12 @@ const Constructor = function (editorTargets, options) {
|
|
|
182
435
|
let default_status_bar = null;
|
|
183
436
|
for (let i = 0, len = editorTargets.length; i < len; i++) {
|
|
184
437
|
const editTarget = editorTargets[i];
|
|
185
|
-
const to = editTarget.
|
|
186
|
-
const top_div =
|
|
187
|
-
const container =
|
|
188
|
-
const editor_div =
|
|
438
|
+
const to = optionMap.frameMap.get(editTarget.key);
|
|
439
|
+
const top_div = dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
440
|
+
const container = dom.utils.createElement('DIV', { class: 'se-container' });
|
|
441
|
+
const editor_div = dom.utils.createElement('DIV', { class: 'se-wrapper' + (o.get('type') === 'document' ? ' se-type-document' : '') });
|
|
189
442
|
|
|
190
|
-
container.appendChild(
|
|
443
|
+
container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-shadow' }));
|
|
191
444
|
|
|
192
445
|
// init element
|
|
193
446
|
const initElements = _initTargetElements(editTarget.key, o, top_div, to);
|
|
@@ -198,22 +451,22 @@ const Constructor = function (editorTargets, options) {
|
|
|
198
451
|
let textarea = initElements.codeView;
|
|
199
452
|
|
|
200
453
|
// line breaker
|
|
201
|
-
const line_breaker_t =
|
|
202
|
-
const line_breaker_b =
|
|
454
|
+
const line_breaker_t = dom.utils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-t', title: lang.insertLine }, icons.line_break);
|
|
455
|
+
const line_breaker_b = dom.utils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-b', title: lang.insertLine }, icons.line_break);
|
|
203
456
|
|
|
204
457
|
editor_div.appendChild(line_breaker_t);
|
|
205
458
|
editor_div.appendChild(line_breaker_b);
|
|
206
459
|
|
|
207
460
|
// append container
|
|
208
461
|
if (placeholder_span) editor_div.appendChild(placeholder_span);
|
|
209
|
-
container.appendChild(
|
|
462
|
+
container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
|
|
210
463
|
container.appendChild(editor_div);
|
|
211
464
|
|
|
212
465
|
// statusbar
|
|
213
466
|
if (statusbar) {
|
|
214
467
|
if (statusbarContainer) {
|
|
215
468
|
if (!default_status_bar) {
|
|
216
|
-
statusbarContainer.appendChild(
|
|
469
|
+
statusbarContainer.appendChild(dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') }, statusbar));
|
|
217
470
|
default_status_bar = statusbar;
|
|
218
471
|
}
|
|
219
472
|
} else {
|
|
@@ -228,7 +481,7 @@ const Constructor = function (editorTargets, options) {
|
|
|
228
481
|
const key = editTarget.key || null;
|
|
229
482
|
|
|
230
483
|
// code view - wrapper
|
|
231
|
-
const codeWrapper =
|
|
484
|
+
const codeWrapper = dom.utils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
|
|
232
485
|
codeWrapper.style.setProperty('display', 'none', 'important');
|
|
233
486
|
editor_div.appendChild(codeWrapper);
|
|
234
487
|
|
|
@@ -237,29 +490,46 @@ const Constructor = function (editorTargets, options) {
|
|
|
237
490
|
// not used code mirror
|
|
238
491
|
if (textarea === codeMirrorEl) {
|
|
239
492
|
// add line nubers
|
|
240
|
-
const codeNumbers =
|
|
493
|
+
const codeNumbers = dom.utils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
|
|
241
494
|
codeWrapper.insertBefore(codeNumbers, textarea);
|
|
242
495
|
} else {
|
|
243
496
|
textarea = codeMirrorEl;
|
|
244
497
|
}
|
|
245
498
|
|
|
499
|
+
// document type
|
|
500
|
+
const documentTypeInner = { inner: null, page: null, pageMirror: null };
|
|
501
|
+
if (o.get('_type_options').includes('header')) {
|
|
502
|
+
documentTypeInner.inner = dom.utils.createElement('DIV', { class: 'se-document-lines', style: `height: ${to.get('height')};` }, '<div class="se-document-lines-inner"></div>');
|
|
503
|
+
}
|
|
504
|
+
if (o.get('_type_options').includes('page')) {
|
|
505
|
+
documentTypeInner.page = dom.utils.createElement('DIV', { class: 'se-document-page' }, null);
|
|
506
|
+
documentTypeInner.pageMirror = dom.utils.createElement(
|
|
507
|
+
'DIV',
|
|
508
|
+
{
|
|
509
|
+
class: 'sun-editor-editable se-document-page-mirror-a4',
|
|
510
|
+
style: `position: absolute; width: 21cm; columns: 21cm; border: 0; overflow: hidden; height: auto; top: -10000px; left: -10000px;`
|
|
511
|
+
},
|
|
512
|
+
null
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
|
|
246
516
|
// set container
|
|
247
517
|
top_div.appendChild(container);
|
|
248
518
|
rootKeys.push(key);
|
|
249
|
-
frameRoots.set(key, CreateFrameContext(editTarget, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, key));
|
|
519
|
+
frameRoots.set(key, CreateFrameContext({ target: editTarget.target, key: editTarget.key, options: to }, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, documentTypeInner, key));
|
|
250
520
|
}
|
|
251
521
|
/** frame - root set - end -------------------------------------------------------------- */
|
|
252
522
|
|
|
253
523
|
// toolbar container
|
|
254
524
|
const toolbar_container = o.get('toolbar_container');
|
|
255
525
|
if (toolbar_container) {
|
|
256
|
-
const top_div =
|
|
257
|
-
const container =
|
|
526
|
+
const top_div = dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
527
|
+
const container = dom.utils.createElement('DIV', { class: 'se-container' });
|
|
258
528
|
container.appendChild(toolbar);
|
|
259
529
|
if (subbar) container.appendChild(subbar);
|
|
260
530
|
top_div.appendChild(container);
|
|
261
531
|
toolbar_container.appendChild(top_div);
|
|
262
|
-
toolbar_container.appendChild(
|
|
532
|
+
toolbar_container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
|
|
263
533
|
} else {
|
|
264
534
|
const rootContainer = frameRoots.get(rootId).get('container');
|
|
265
535
|
rootContainer.insertBefore(toolbar, rootContainer.firstElementChild);
|
|
@@ -282,30 +552,74 @@ const Constructor = function (editorTargets, options) {
|
|
|
282
552
|
pluginCallButtons_sub: sub_main ? sub_main.pluginCallButtons : [],
|
|
283
553
|
responsiveButtons_sub: sub_main ? sub_main.responsiveButtons : []
|
|
284
554
|
};
|
|
285
|
-
}
|
|
555
|
+
}
|
|
286
556
|
|
|
287
557
|
/**
|
|
288
558
|
* @description Create shortcuts desc span.
|
|
289
559
|
* @param {string} command Command string
|
|
290
|
-
* @param {Array
|
|
291
|
-
* @param {Element} button Command button element
|
|
292
|
-
* @param {Map} keyMap Map to store shortcut key info
|
|
560
|
+
* @param {Array<string>} values options.shortcuts[command]
|
|
561
|
+
* @param {Element|null} button Command button element
|
|
562
|
+
* @param {Map<string, *>} keyMap Map to store shortcut key info
|
|
293
563
|
* @param {Array} rc "_reverseCommandArray" option
|
|
294
564
|
* @param {Array} reverseKeys Reverse key array
|
|
295
565
|
*/
|
|
296
566
|
export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys) {
|
|
297
567
|
if (!values || values.length < 2) return;
|
|
298
|
-
const tooptip = button
|
|
568
|
+
const tooptip = button?.querySelector('.se-tooltip-text');
|
|
569
|
+
|
|
570
|
+
for (let i = 0, a, v, c, s, edge, space, enter, textTrigger, plugin, method, t, k, r, _i; i < values.length; i += 2 + _i) {
|
|
571
|
+
_i = 0;
|
|
572
|
+
a = values[i].split('+');
|
|
573
|
+
|
|
574
|
+
plugin = null;
|
|
575
|
+
method = a[a.length - 1].trim?.();
|
|
576
|
+
if (method.startsWith('~')) {
|
|
577
|
+
plugin = command;
|
|
578
|
+
method = a.pop().trim().substring(1);
|
|
579
|
+
} else if (method.startsWith('p~')) {
|
|
580
|
+
const a_ = a.pop().trim().substring(2).split('.');
|
|
581
|
+
plugin = a_[0];
|
|
582
|
+
method = a_[1];
|
|
583
|
+
} else if (method.startsWith('$')) {
|
|
584
|
+
_i = 1;
|
|
585
|
+
method = values[i + 2];
|
|
586
|
+
} else {
|
|
587
|
+
method = '';
|
|
588
|
+
}
|
|
299
589
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
590
|
+
c = s = edge = space = enter = textTrigger = v = null;
|
|
591
|
+
for (const a_ of a) {
|
|
592
|
+
switch (a_.trim()) {
|
|
593
|
+
case 'c':
|
|
594
|
+
c = true;
|
|
595
|
+
break;
|
|
596
|
+
case '!':
|
|
597
|
+
edge = true;
|
|
598
|
+
break;
|
|
599
|
+
case 's':
|
|
600
|
+
s = true;
|
|
601
|
+
break;
|
|
602
|
+
case '_':
|
|
603
|
+
space = true;
|
|
604
|
+
break;
|
|
605
|
+
case '=':
|
|
606
|
+
textTrigger = true;
|
|
607
|
+
break;
|
|
608
|
+
case '/':
|
|
609
|
+
enter = true;
|
|
610
|
+
break;
|
|
611
|
+
default:
|
|
612
|
+
v = a_;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
k = c ? v + (s ? '1000' : '') : v;
|
|
304
617
|
if (!keyMap.has(k)) {
|
|
305
618
|
r = rc.indexOf(command);
|
|
306
619
|
r = r === -1 ? '' : numbers.isOdd(r) ? rc[r + 1] : rc[r - 1];
|
|
307
620
|
if (r) reverseKeys.push(k);
|
|
308
|
-
|
|
621
|
+
|
|
622
|
+
keyMap.set(k, { c, s, edge, space, enter, textTrigger, plugin, command, method, r, type: button?.getAttribute('data-type'), button, key: k });
|
|
309
623
|
}
|
|
310
624
|
|
|
311
625
|
if (!(t = values[i + 1])) continue;
|
|
@@ -314,13 +628,15 @@ export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys
|
|
|
314
628
|
}
|
|
315
629
|
|
|
316
630
|
function _addTooltip(tooptipBtn, shift, shortcut) {
|
|
317
|
-
tooptipBtn.appendChild(
|
|
631
|
+
tooptipBtn.appendChild(dom.utils.createElement('SPAN', { class: 'se-shortcut' }, env.cmdIcon + (shift ? env.shiftIcon : '') + '+<span class="se-shortcut-key">' + shortcut + '</span>'));
|
|
318
632
|
}
|
|
319
633
|
|
|
320
634
|
/**
|
|
635
|
+
* @private
|
|
321
636
|
* @description Returns a new object with merge "a" and "b"
|
|
322
|
-
* @param {Object}
|
|
323
|
-
* @
|
|
637
|
+
* @param {Object<*, *>} a object
|
|
638
|
+
* @param {Object<*, *>} b object
|
|
639
|
+
* @returns {Object<*, *>} new object
|
|
324
640
|
*/
|
|
325
641
|
function _mergeObject(a, b) {
|
|
326
642
|
return [a, b].reduce((_default, _new) => {
|
|
@@ -333,10 +649,18 @@ function _mergeObject(a, b) {
|
|
|
333
649
|
|
|
334
650
|
/**
|
|
335
651
|
* @description Initialize options
|
|
336
|
-
* @param {
|
|
337
|
-
* @param {Array
|
|
338
|
-
* @param {Object} plugins Plugins object
|
|
339
|
-
* @returns {o:Map,
|
|
652
|
+
* @param {EditorInitOptions} options Configuration options for the editor.
|
|
653
|
+
* @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} editorTargets Target textarea
|
|
654
|
+
* @param {Object<string, *>} plugins Plugins object
|
|
655
|
+
* @returns {{o: Map<string, *>, i: Object<string, string>, l: Object<string, string>, v: string, buttons: Array<string[]|string>, subButtons: Array<string[]|string>, statusbarContainer: Element|null, frameMap: Map<*, *>}}
|
|
656
|
+
* - o: options
|
|
657
|
+
* - i: icons
|
|
658
|
+
* - l: lang
|
|
659
|
+
* - v: value
|
|
660
|
+
* - buttons: Toolbar button list
|
|
661
|
+
* - subButtons: Sub-Toolbar button list
|
|
662
|
+
* - statusbarContainer: statusbar container
|
|
663
|
+
* - frameMap: converted options map
|
|
340
664
|
*/
|
|
341
665
|
export function InitOptions(options, editorTargets, plugins) {
|
|
342
666
|
const buttonList = options.buttonList || DEFAULT_BUTTON_LIST;
|
|
@@ -347,7 +671,11 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
347
671
|
if (!options.toolbar_container && !/inline|balloon/i.test(options.mode)) throw Error('[SUNEDITOR.create.fail] In multi root, The "mode" option cannot be "classic" without using the "toolbar_container" option.');
|
|
348
672
|
}
|
|
349
673
|
|
|
674
|
+
// migration data-.+
|
|
675
|
+
o.set('v2Migration', !!options.v2Migration);
|
|
676
|
+
|
|
350
677
|
/** Base */
|
|
678
|
+
o.set('buttons', new Set(buttonList.toString().split(',')));
|
|
351
679
|
const modeValue = options.strictMode !== false;
|
|
352
680
|
o.set('strictMode', {
|
|
353
681
|
tagFilter: modeValue,
|
|
@@ -356,18 +684,24 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
356
684
|
styleNodeFilter: modeValue,
|
|
357
685
|
attrFilter: modeValue,
|
|
358
686
|
styleFilter: modeValue,
|
|
359
|
-
...options.strictMode
|
|
687
|
+
...(typeof options.strictMode === 'boolean' ? {} : options.strictMode)
|
|
360
688
|
});
|
|
689
|
+
o.set('freeCodeViewMode', !!options.freeCodeViewMode);
|
|
361
690
|
o.set('__lineFormatFilter', options.__lineFormatFilter ?? true);
|
|
362
691
|
o.set('__pluginRetainFilter', options.__pluginRetainFilter ?? true);
|
|
363
692
|
o.set('mode', options.mode || 'classic'); // classic, inline, balloon, balloon-always
|
|
693
|
+
o.set('type', options.type?.split(':')[0] || ''); // document:header,page
|
|
694
|
+
o.set('theme', options.theme || '');
|
|
695
|
+
o.set('_themeClass', options.theme ? ` se-theme-${options.theme}` : '');
|
|
696
|
+
o.set('_type_options', options.type?.split(':')[1] || '');
|
|
364
697
|
o.set('externalLibs', options.externalLibs || {});
|
|
365
|
-
o.set('keepStyleOnDelete', !!options.keepStyleOnDelete);
|
|
366
698
|
o.set('fontSizeUnits', Array.isArray(options.fontSizeUnits) && options.fontSizeUnits.length > 0 ? options.fontSizeUnits.map((v) => v.toLowerCase()) : DEFAULT_SIZE_UNITS);
|
|
367
699
|
o.set('allowedClassName', new RegExp(`${options.allowedClassName && typeof options.allowedClassName === 'string' ? options.allowedClassName + '|' : ''}${DEFAULT_CLASS_NAME}`));
|
|
700
|
+
o.set('closeModalOutsideClick', !!options.closeModalOutsideClick);
|
|
368
701
|
|
|
369
702
|
// format
|
|
370
703
|
o.set('copyFormatKeepOn', !!options.copyFormatKeepOn);
|
|
704
|
+
o.set('syncTabIndent', options.syncTabIndent ?? true);
|
|
371
705
|
|
|
372
706
|
// auto convert on paste
|
|
373
707
|
o.set('autoLinkify', options.autoLinkify ?? !!plugins.link);
|
|
@@ -377,9 +711,6 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
377
711
|
o.set('scrollToOptions', { behavior: 'auto', block: 'nearest', ...options.scrollToOptions });
|
|
378
712
|
o.set('componentScrollToOptions', { behavior: 'smooth', block: 'center', ...options.componentScrollToOptions });
|
|
379
713
|
|
|
380
|
-
// migration data-.+
|
|
381
|
-
o.set('v2Migration', !!options.v2Migration);
|
|
382
|
-
|
|
383
714
|
let retainStyleMode = options.retainStyleMode;
|
|
384
715
|
if (typeof retainStyleMode === 'string' && !RETAIN_STYLE_MODE.includes(retainStyleMode)) {
|
|
385
716
|
console.error(`Invalid retainStyleMode: ${retainStyleMode}. Valid options are ${RETAIN_STYLE_MODE.join(', ')}. Using default 'once'.`);
|
|
@@ -462,6 +793,7 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
462
793
|
// text direction
|
|
463
794
|
o.set('textDirection', typeof options.textDirection !== 'string' ? 'ltr' : options.textDirection);
|
|
464
795
|
o.set('_rtl', o.get('textDirection') === 'rtl');
|
|
796
|
+
// An array of key codes generated with the reverseButtons option, used to reverse the action for a specific key combination.
|
|
465
797
|
o.set('reverseCommands', ['indent-outdent'].concat(options.reverseButtons || []));
|
|
466
798
|
o.set('_reverseCommandArray', ('-' + o.get('reverseCommands').join('-')).split('-'));
|
|
467
799
|
if (numbers.isEven(o.get('_reverseCommandArray').length)) {
|
|
@@ -470,16 +802,19 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
470
802
|
|
|
471
803
|
// etc
|
|
472
804
|
o.set('historyStackDelayTime', typeof options.historyStackDelayTime === 'number' ? options.historyStackDelayTime : 400);
|
|
473
|
-
o.set('_editableClass', 'sun-editor-editable' + (o.get('_rtl') ? ' se-rtl' : ''));
|
|
805
|
+
o.set('_editableClass', 'sun-editor-editable' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') + (o.get('type') === 'document' ? ' se-type-document-editable' : ''));
|
|
474
806
|
o.set('lineAttrReset', ['id'].concat(options.lineAttrReset && typeof options.lineAttrReset === 'string' ? options.lineAttrReset.toLowerCase().split('|') : []));
|
|
475
|
-
o.set('printClass', typeof options.printClass === 'string' ? options.printClass : null);
|
|
807
|
+
o.set('printClass', typeof options.printClass === 'string' ? options.printClass + ' ' + o.get('_editableClass') : null);
|
|
476
808
|
|
|
477
809
|
/** whitelist, blacklist */
|
|
478
810
|
// default line
|
|
479
811
|
o.set('defaultLine', typeof options.defaultLine === 'string' && options.defaultLine.length > 0 ? options.defaultLine : 'p');
|
|
812
|
+
o.set('_defaultBrLineBreak', options.defaultLineBreakFormat === 'br');
|
|
813
|
+
o.set('scopeSelectionTags', options.scopeSelectionTags || DEFAULT_SCOPE_SELECTION_TAGS.split('|'));
|
|
480
814
|
// element
|
|
481
815
|
const elw = (typeof options.elementWhitelist === 'string' ? options.elementWhitelist : '').toLowerCase();
|
|
482
|
-
o.
|
|
816
|
+
const mjxEls = o.get('externalLibs').mathjax ? DEFAULT_CLASS_MJX + '|' : '';
|
|
817
|
+
o.set('elementWhitelist', elw + (elw ? '|' : '') + mjxEls + o.get('_allowedExtraTag'));
|
|
483
818
|
const elb = _createBlacklist((typeof options.elementBlacklist === 'string' ? options.elementBlacklist : '').toLowerCase(), o.get('defaultLine'));
|
|
484
819
|
o.set('elementBlacklist', elb + (elb ? '|' : '') + o.get('_disallowedExtraTag'));
|
|
485
820
|
// attribute
|
|
@@ -533,6 +868,8 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
533
868
|
)
|
|
534
869
|
);
|
|
535
870
|
|
|
871
|
+
o.set('allowedEmptyTags', DEFAULT_ALLOWED_EMPTY_NODE_LIST + (options.allowedEmptyTags ? ', ' + options.allowedEmptyTags : ''));
|
|
872
|
+
|
|
536
873
|
/** __defaults */
|
|
537
874
|
o.set('__defaultElementWhitelist', REQUIRED_ELEMENT_WHITELIST + '|' + (typeof options.__defaultElementWhitelist === 'string' ? options.__defaultElementWhitelist : DEFAULT_ELEMENT_WHITELIST).toLowerCase());
|
|
538
875
|
o.set('__defaultAttributeWhitelist', (typeof options.__defaultAttributeWhitelist === 'string' ? options.__defaultAttributeWhitelist : DEFAULT_ATTRIBUTE_WHITELIST).toLowerCase());
|
|
@@ -542,7 +879,7 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
542
879
|
/** Toolbar */
|
|
543
880
|
o.set('toolbar_width', options.toolbar_width ? (numbers.is(options.toolbar_width) ? options.toolbar_width + 'px' : options.toolbar_width) : 'auto');
|
|
544
881
|
o.set('toolbar_container', options.toolbar_container && !/inline/i.test(o.get('mode')) ? (typeof options.toolbar_container === 'string' ? _d.querySelector(options.toolbar_container) : options.toolbar_container) : null);
|
|
545
|
-
o.set('toolbar_sticky', /balloon/i.test(o.get('mode')) ? -1 : options.toolbar_sticky === undefined ? 0 :
|
|
882
|
+
o.set('toolbar_sticky', /balloon/i.test(o.get('mode')) ? -1 : options.toolbar_sticky === undefined ? 0 : numbers.is(options.toolbar_sticky) ? numbers.get(options.toolbar_sticky, 0) : -1);
|
|
546
883
|
o.set('toolbar_hide', !!options.toolbar_hide);
|
|
547
884
|
|
|
548
885
|
/** subToolbar */
|
|
@@ -555,12 +892,14 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
555
892
|
o.set('_subMode', subbar.mode || 'balloon');
|
|
556
893
|
o.set('toolbar.sub_width', subbar.width ? (numbers.is(subbar.width) ? subbar.width + 'px' : subbar.width) : 'auto');
|
|
557
894
|
subButtons = o.get('_rtl') ? subbar.buttonList.reverse() : subbar.buttonList;
|
|
895
|
+
o.set('buttons_sub', new Set(subButtons.toString().split(',')));
|
|
558
896
|
}
|
|
559
897
|
}
|
|
560
898
|
|
|
561
899
|
/** root options */
|
|
900
|
+
const frameMap = new Map();
|
|
562
901
|
for (let i = 0, len = editorTargets.length; i < len; i++) {
|
|
563
|
-
|
|
902
|
+
frameMap.set(editorTargets[i].key, InitFrameOptions(editorTargets[i].options || {}, options));
|
|
564
903
|
}
|
|
565
904
|
|
|
566
905
|
/** Key actions */
|
|
@@ -571,20 +910,25 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
571
910
|
: [
|
|
572
911
|
{
|
|
573
912
|
// default command
|
|
574
|
-
selectAll: ['
|
|
575
|
-
bold: ['
|
|
576
|
-
strike: ['
|
|
577
|
-
underline: ['
|
|
578
|
-
italic: ['
|
|
579
|
-
redo: ['
|
|
580
|
-
undo: ['
|
|
581
|
-
indent: ['
|
|
582
|
-
outdent: ['
|
|
583
|
-
|
|
584
|
-
sub: ['s187', '='],
|
|
585
|
-
save: ['83', 'S'],
|
|
913
|
+
selectAll: ['c+KeyA', 'A'],
|
|
914
|
+
bold: ['c+KeyB', 'B'],
|
|
915
|
+
strike: ['c+s+KeyS', 'S'],
|
|
916
|
+
underline: ['c+KeyU', 'U'],
|
|
917
|
+
italic: ['c+KeyI', 'I'],
|
|
918
|
+
redo: ['c+KeyY', 'Y', 'c+s+KeyZ', 'Z'],
|
|
919
|
+
undo: ['c+KeyZ', 'Z'],
|
|
920
|
+
indent: ['c+BracketRight', ']'],
|
|
921
|
+
outdent: ['c+BracketLeft', '['],
|
|
922
|
+
save: ['c+KeyS', 'S'],
|
|
586
923
|
// plugins
|
|
587
|
-
link: ['
|
|
924
|
+
link: ['c+KeyK', 'K'],
|
|
925
|
+
hr: ['!+---+=+~shortcut', ''],
|
|
926
|
+
list_numbered: ['!+1.+_+~shortcut', ''],
|
|
927
|
+
list_bulleted: ['!+*.+_+~shortcut', ''],
|
|
928
|
+
// custom
|
|
929
|
+
_h1: ['c+s+Digit1+p~formatBlock.createHeader', ''],
|
|
930
|
+
_h2: ['c+s+Digit2+p~formatBlock.createHeader', ''],
|
|
931
|
+
_h3: ['c+s+Digit3+p~formatBlock.createHeader', '']
|
|
588
932
|
},
|
|
589
933
|
options.shortcuts || {}
|
|
590
934
|
].reduce((_default, _new) => {
|
|
@@ -596,7 +940,7 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
596
940
|
o.set('shortcuts', shortcuts);
|
|
597
941
|
|
|
598
942
|
/** View */
|
|
599
|
-
o.set('fullScreenOffset', options.fullScreenOffset === undefined ? 0 :
|
|
943
|
+
o.set('fullScreenOffset', options.fullScreenOffset === undefined ? 0 : numbers.is(options.fullScreenOffset) ? numbers.get(options.fullScreenOffset, 0) : 0);
|
|
600
944
|
o.set('previewTemplate', typeof options.previewTemplate === 'string' ? options.previewTemplate : null);
|
|
601
945
|
o.set('printTemplate', typeof options.printTemplate === 'string' ? options.printTemplate : null);
|
|
602
946
|
|
|
@@ -661,46 +1005,54 @@ export function InitOptions(options, editorTargets, plugins) {
|
|
|
661
1005
|
allUsedStyles.add(_aus[i]);
|
|
662
1006
|
}
|
|
663
1007
|
o.set('allUsedStyles', allUsedStyles);
|
|
1008
|
+
o.set('toastMessageTime', { copy: 1500, ...options.toastMessageTime });
|
|
664
1009
|
|
|
665
1010
|
return {
|
|
666
1011
|
o: o,
|
|
667
1012
|
i: icons,
|
|
668
|
-
l: options.lang || _defaultLang,
|
|
1013
|
+
l: /** @type {Object<string, string>} */ (options.lang || _defaultLang),
|
|
669
1014
|
v: (options.value = typeof options.value === 'string' ? options.value : null),
|
|
670
1015
|
buttons: o.get('_rtl') ? buttonList.reverse() : buttonList,
|
|
671
1016
|
subButtons: subButtons,
|
|
672
|
-
statusbarContainer: typeof options.statusbar_container === 'string' ? _d.querySelector(options.statusbar_container) : options.statusbar_container
|
|
1017
|
+
statusbarContainer: typeof options.statusbar_container === 'string' ? _d.querySelector(options.statusbar_container) : options.statusbar_container,
|
|
1018
|
+
frameMap: frameMap
|
|
673
1019
|
};
|
|
674
1020
|
}
|
|
675
1021
|
|
|
1022
|
+
/**
|
|
1023
|
+
* @description Create a context object for the editor frame.
|
|
1024
|
+
* @param {Map<string, *>} targetOptions - editor.frameOptions
|
|
1025
|
+
* @param {HTMLElement} statusbar - statusbar element
|
|
1026
|
+
* @returns {{statusbar: HTMLElement, navigation: HTMLElement, charWrapper: HTMLElement, charCounter: HTMLElement}}
|
|
1027
|
+
*/
|
|
676
1028
|
export function CreateStatusbar(targetOptions, statusbar) {
|
|
677
1029
|
let navigation = null;
|
|
678
1030
|
let charWrapper = null;
|
|
679
1031
|
let charCounter = null;
|
|
680
1032
|
|
|
681
1033
|
if (targetOptions.get('statusbar')) {
|
|
682
|
-
statusbar = statusbar ||
|
|
1034
|
+
statusbar = statusbar || dom.utils.createElement('DIV', { class: 'se-status-bar sun-editor-common' });
|
|
683
1035
|
|
|
684
1036
|
/** navigation */
|
|
685
|
-
navigation = statusbar.querySelector('.se-navigation') ||
|
|
1037
|
+
navigation = statusbar.querySelector('.se-navigation') || dom.utils.createElement('DIV', { class: 'se-navigation sun-editor-common' });
|
|
686
1038
|
statusbar.appendChild(navigation);
|
|
687
1039
|
|
|
688
1040
|
/** char counter */
|
|
689
1041
|
if (targetOptions.get('charCounter')) {
|
|
690
|
-
charWrapper = statusbar.querySelector('.se-char-counter-wrapper') ||
|
|
1042
|
+
charWrapper = statusbar.querySelector('.se-char-counter-wrapper') || dom.utils.createElement('DIV', { class: 'se-char-counter-wrapper' });
|
|
691
1043
|
|
|
692
1044
|
if (targetOptions.get('charCounter_label')) {
|
|
693
|
-
const charLabel = charWrapper.querySelector('.se-char-label') ||
|
|
1045
|
+
const charLabel = charWrapper.querySelector('.se-char-label') || dom.utils.createElement('SPAN', { class: 'se-char-label' });
|
|
694
1046
|
charLabel.textContent = targetOptions.get('charCounter_label');
|
|
695
1047
|
charWrapper.appendChild(charLabel);
|
|
696
1048
|
}
|
|
697
1049
|
|
|
698
|
-
charCounter = charWrapper.querySelector('.se-char-counter') ||
|
|
1050
|
+
charCounter = charWrapper.querySelector('.se-char-counter') || dom.utils.createElement('SPAN', { class: 'se-char-counter' });
|
|
699
1051
|
charCounter.textContent = '0';
|
|
700
1052
|
charWrapper.appendChild(charCounter);
|
|
701
1053
|
|
|
702
1054
|
if (targetOptions.get('charCounter_max') > 0) {
|
|
703
|
-
const char_max = charWrapper.querySelector('.se-char-max') ||
|
|
1055
|
+
const char_max = charWrapper.querySelector('.se-char-max') || dom.utils.createElement('SPAN', { class: 'se-char-max' });
|
|
704
1056
|
char_max.textContent = ' / ' + targetOptions.get('charCounter_max');
|
|
705
1057
|
charWrapper.appendChild(char_max);
|
|
706
1058
|
}
|
|
@@ -711,13 +1063,21 @@ export function CreateStatusbar(targetOptions, statusbar) {
|
|
|
711
1063
|
|
|
712
1064
|
return {
|
|
713
1065
|
statusbar: statusbar,
|
|
714
|
-
navigation: navigation,
|
|
715
|
-
charWrapper: charWrapper,
|
|
716
|
-
charCounter: charCounter
|
|
1066
|
+
navigation: /** @type {HTMLElement} */ (navigation),
|
|
1067
|
+
charWrapper: /** @type {HTMLElement} */ (charWrapper),
|
|
1068
|
+
charCounter: /** @type {HTMLElement} */ (charCounter)
|
|
717
1069
|
};
|
|
718
1070
|
}
|
|
719
1071
|
|
|
720
|
-
|
|
1072
|
+
/**
|
|
1073
|
+
* @description Initialize options.
|
|
1074
|
+
* @param {EditorFrameOptions} o - Target options
|
|
1075
|
+
* @param {EditorInitOptions} origin - Full options
|
|
1076
|
+
* @returns {Map<string, *>}
|
|
1077
|
+
*/
|
|
1078
|
+
function InitFrameOptions(o, origin) {
|
|
1079
|
+
const fo = new Map();
|
|
1080
|
+
|
|
721
1081
|
fo.set('_origin', o);
|
|
722
1082
|
const barContainer = origin.statusbar_container;
|
|
723
1083
|
|
|
@@ -771,14 +1131,18 @@ function InitFrameOptions(o, origin, fo) {
|
|
|
771
1131
|
fo.set('charCounter_max', numbers.is(charCounter_max) && charCounter_max > -1 ? charCounter_max * 1 : null);
|
|
772
1132
|
fo.set('charCounter_label', typeof charCounter_label === 'string' ? charCounter_label.trim() : null);
|
|
773
1133
|
fo.set('charCounter_type', typeof charCounter_type === 'string' ? charCounter_type : 'char');
|
|
1134
|
+
|
|
1135
|
+
return fo;
|
|
774
1136
|
}
|
|
775
1137
|
|
|
776
1138
|
/**
|
|
1139
|
+
* @private
|
|
777
1140
|
* @description Initialize property of suneditor elements
|
|
778
|
-
* @param {string} key
|
|
779
|
-
* @param {
|
|
780
|
-
* @param {
|
|
781
|
-
* @
|
|
1141
|
+
* @param {string} key - The key of the editor frame
|
|
1142
|
+
* @param {Map<string, *>} options - options
|
|
1143
|
+
* @param {HTMLElement} topDiv - top div
|
|
1144
|
+
* @param {Map<string, *>} targetOptions - editor.frameOptions
|
|
1145
|
+
* @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, placeholder: HTMLElement}}
|
|
782
1146
|
*/
|
|
783
1147
|
function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
784
1148
|
const editorStyles = targetOptions.get('_defaultStyles');
|
|
@@ -787,13 +1151,13 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
|
787
1151
|
|
|
788
1152
|
/** editor */
|
|
789
1153
|
// wysiwyg div or iframe
|
|
790
|
-
const wysiwygDiv =
|
|
1154
|
+
const wysiwygDiv = dom.utils.createElement(!targetOptions.get('iframe') ? 'DIV' : 'IFRAME', {
|
|
791
1155
|
class: 'se-wrapper-inner se-wrapper-wysiwyg',
|
|
792
1156
|
'data-root-key': key
|
|
793
1157
|
});
|
|
794
1158
|
|
|
795
1159
|
if (!targetOptions.get('iframe')) {
|
|
796
|
-
wysiwygDiv.setAttribute('contenteditable', true);
|
|
1160
|
+
wysiwygDiv.setAttribute('contenteditable', 'true');
|
|
797
1161
|
wysiwygDiv.setAttribute('scrolling', 'auto');
|
|
798
1162
|
wysiwygDiv.className += ' ' + options.get('_editableClass');
|
|
799
1163
|
wysiwygDiv.style.cssText = editorStyles.frame + editorStyles.editor;
|
|
@@ -802,17 +1166,19 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
|
802
1166
|
for (const frameKey in frameAttrs) {
|
|
803
1167
|
wysiwygDiv.setAttribute(frameKey, frameAttrs[frameKey]);
|
|
804
1168
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
1169
|
+
|
|
1170
|
+
const iframeWW = /** @type {HTMLIFrameElement} */ (wysiwygDiv);
|
|
1171
|
+
iframeWW.allowFullscreen = true;
|
|
1172
|
+
iframeWW.frameBorder = '0';
|
|
1173
|
+
iframeWW.style.cssText = editorStyles.frame;
|
|
808
1174
|
}
|
|
809
1175
|
|
|
810
1176
|
// textarea for code view
|
|
811
|
-
const textarea =
|
|
1177
|
+
const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
|
|
812
1178
|
let placeholder = null;
|
|
813
1179
|
if (targetOptions.get('placeholder')) {
|
|
814
|
-
placeholder =
|
|
815
|
-
placeholder.
|
|
1180
|
+
placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
|
|
1181
|
+
placeholder.textContent = targetOptions.get('placeholder');
|
|
816
1182
|
}
|
|
817
1183
|
|
|
818
1184
|
return {
|
|
@@ -824,9 +1190,10 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
|
824
1190
|
}
|
|
825
1191
|
|
|
826
1192
|
/**
|
|
1193
|
+
* @private
|
|
827
1194
|
* @description Check the CodeMirror option to apply the CodeMirror and return the CodeMirror element.
|
|
828
|
-
* @param {
|
|
829
|
-
* @param {
|
|
1195
|
+
* @param {Map<string, *>} options options
|
|
1196
|
+
* @param {HTMLElement} textarea textarea element
|
|
830
1197
|
*/
|
|
831
1198
|
function _checkCodeMirror(options, targetOptions, textarea) {
|
|
832
1199
|
let cmeditor = null;
|
|
@@ -877,7 +1244,7 @@ function _checkCodeMirror(options, targetOptions, textarea) {
|
|
|
877
1244
|
|
|
878
1245
|
options.set('hasCodeMirror', hasCodeMirror);
|
|
879
1246
|
if (cmeditor) {
|
|
880
|
-
|
|
1247
|
+
dom.utils.removeItem(textarea);
|
|
881
1248
|
cmeditor.className += ' se-code-viewer-mirror';
|
|
882
1249
|
return cmeditor;
|
|
883
1250
|
}
|
|
@@ -886,6 +1253,7 @@ function _checkCodeMirror(options, targetOptions, textarea) {
|
|
|
886
1253
|
}
|
|
887
1254
|
|
|
888
1255
|
/**
|
|
1256
|
+
* @private
|
|
889
1257
|
* @description create blacklist
|
|
890
1258
|
* @param {string} blacklist blacklist
|
|
891
1259
|
* @param {string} defaultLine options.get('defaultLine')
|
|
@@ -907,6 +1275,7 @@ function _createBlacklist(blacklist, defaultLine) {
|
|
|
907
1275
|
}
|
|
908
1276
|
|
|
909
1277
|
/**
|
|
1278
|
+
* @private
|
|
910
1279
|
* @description create formats regexp object.
|
|
911
1280
|
* @param {string} value value
|
|
912
1281
|
* @param {string} defaultValue default value
|
|
@@ -927,8 +1296,9 @@ function _createFormatInfo(value, defaultValue, blacklist) {
|
|
|
927
1296
|
}
|
|
928
1297
|
|
|
929
1298
|
/**
|
|
1299
|
+
* @private
|
|
930
1300
|
* @description create whitelist or blacklist.
|
|
931
|
-
* @param {
|
|
1301
|
+
* @param {Map<string, *>} o options
|
|
932
1302
|
* @returns {string} whitelist
|
|
933
1303
|
*/
|
|
934
1304
|
function _createWhitelist(o) {
|
|
@@ -942,8 +1312,9 @@ function _createWhitelist(o) {
|
|
|
942
1312
|
}
|
|
943
1313
|
|
|
944
1314
|
/**
|
|
1315
|
+
* @private
|
|
945
1316
|
* @description Suneditor's Default button list
|
|
946
|
-
* @param {
|
|
1317
|
+
* @param {Map<string, *>} options options
|
|
947
1318
|
*/
|
|
948
1319
|
function _defaultButtons(options, icons, lang) {
|
|
949
1320
|
const isRTL = options.get('_rtl');
|
|
@@ -965,22 +1336,29 @@ function _defaultButtons(options, icons, lang) {
|
|
|
965
1336
|
redo: ['se-component-enabled', lang.redo, 'redo', '', icons.redo],
|
|
966
1337
|
preview: ['se-component-enabled', lang.preview, 'preview', '', icons.preview],
|
|
967
1338
|
print: ['se-component-enabled', lang.print, 'print', '', icons.print],
|
|
1339
|
+
copy: ['', lang.copy, 'copy', '', icons.copy],
|
|
968
1340
|
dir: ['', lang[isRTL ? 'dir_ltr' : 'dir_rtl'], 'dir', '', icons[isRTL ? 'dir_ltr' : 'dir_rtl']],
|
|
969
1341
|
dir_ltr: ['', lang.dir_ltr, 'dir_ltr', '', icons.dir_ltr],
|
|
970
1342
|
dir_rtl: ['', lang.dir_rtl, 'dir_rtl', '', icons.dir_rtl],
|
|
971
1343
|
save: ['se-component-enabled', lang.save, 'save', '', icons.save],
|
|
972
1344
|
newDocument: ['se-component-enabled', lang.newDocument, 'newDocument', '', icons.new_document],
|
|
973
|
-
selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all]
|
|
1345
|
+
selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all],
|
|
1346
|
+
pageBreak: ['se-component-enabled', lang.pageBreak, 'pageBreak', '', icons.page_break],
|
|
1347
|
+
// document type buttons
|
|
1348
|
+
pageUp: ['se-component-enabled', lang.pageUp, 'pageUp', '', icons.page_up],
|
|
1349
|
+
pageDown: ['se-component-enabled', lang.pageDown, 'pageDown', '', icons.page_down],
|
|
1350
|
+
pageNavigator: ['se-component-enabled', '', 'pageNavigator', 'input', '']
|
|
974
1351
|
};
|
|
975
1352
|
}
|
|
976
1353
|
|
|
977
1354
|
/**
|
|
1355
|
+
* @private
|
|
978
1356
|
* @description Create a group div containing each module
|
|
979
|
-
* @returns {
|
|
1357
|
+
* @returns {{div: Element, ul: Element}}
|
|
980
1358
|
*/
|
|
981
1359
|
function _createModuleGroup() {
|
|
982
|
-
const oUl =
|
|
983
|
-
const oDiv =
|
|
1360
|
+
const oUl = dom.utils.createElement('UL', { class: 'se-menu-list' });
|
|
1361
|
+
const oDiv = dom.utils.createElement('DIV', { class: 'se-btn-module se-btn-module-border' }, oUl);
|
|
984
1362
|
|
|
985
1363
|
return {
|
|
986
1364
|
div: oDiv,
|
|
@@ -989,27 +1367,38 @@ function _createModuleGroup() {
|
|
|
989
1367
|
}
|
|
990
1368
|
|
|
991
1369
|
/**
|
|
1370
|
+
* @private
|
|
992
1371
|
* @description Create a button element
|
|
993
1372
|
* @param {string} className className in button
|
|
994
1373
|
* @param {string} title Title in button
|
|
995
1374
|
* @param {string} dataCommand The data-command property of the button
|
|
996
|
-
* @param {
|
|
1375
|
+
* @param {"command"|"dropdown"|"field"|"browser"|"input"|"modal"|"popup"} dataType The data-type property of the button
|
|
997
1376
|
* @param {string} innerHTML Html in button
|
|
998
1377
|
* @param {string} _disabled Button disabled
|
|
999
|
-
* @param {Object} icons Icons
|
|
1000
|
-
* @returns {
|
|
1378
|
+
* @param {Object<string, string>} icons Icons
|
|
1379
|
+
* @returns {{li: HTMLElement, button: HTMLElement}}
|
|
1001
1380
|
*/
|
|
1002
1381
|
function _createButton(className, title, dataCommand, dataType, innerHTML, _disabled, icons) {
|
|
1003
|
-
|
|
1382
|
+
if (!innerHTML) innerHTML = '';
|
|
1383
|
+
|
|
1384
|
+
const oLi = dom.utils.createElement('LI');
|
|
1004
1385
|
const label = title || '';
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1386
|
+
const isDiv = /^INPUT|FIELD$/i.test(dataType);
|
|
1387
|
+
const oButton = /** @type {HTMLButtonElement} */ (
|
|
1388
|
+
'se-toolbar-separator-vertical' === className
|
|
1389
|
+
? dom.utils.createElement('DIV', { class: className, tabindex: '-1' }, null)
|
|
1390
|
+
: dom.utils.createElement(isDiv ? 'DIV' : 'BUTTON', {
|
|
1391
|
+
class: 'se-toolbar-btn se-btn se-tooltip' + (className ? ' ' + className : ''),
|
|
1392
|
+
'data-command': dataCommand,
|
|
1393
|
+
'data-type': dataType,
|
|
1394
|
+
'aria-label': label.replace(/<span .+<\/span>/, ''),
|
|
1395
|
+
tabindex: '-1'
|
|
1396
|
+
})
|
|
1397
|
+
);
|
|
1398
|
+
|
|
1399
|
+
if (!isDiv) {
|
|
1400
|
+
oButton.setAttribute('type', 'button');
|
|
1401
|
+
}
|
|
1013
1402
|
|
|
1014
1403
|
if (/^default\./i.test(innerHTML)) {
|
|
1015
1404
|
innerHTML = icons[innerHTML.replace(/^default\./i, '')];
|
|
@@ -1019,11 +1408,11 @@ function _createButton(className, title, dataCommand, dataType, innerHTML, _disa
|
|
|
1019
1408
|
oButton.className += ' se-btn-more-text';
|
|
1020
1409
|
}
|
|
1021
1410
|
|
|
1022
|
-
if (_disabled) oButton.
|
|
1411
|
+
if (_disabled) oButton.disabled = true;
|
|
1023
1412
|
|
|
1024
|
-
if (/^FIELD$/i.test(dataType))
|
|
1413
|
+
if (/^FIELD$/i.test(dataType)) dom.utils.addClass(oLi, 'se-toolbar-hidden-btn');
|
|
1025
1414
|
|
|
1026
|
-
if (label) innerHTML +=
|
|
1415
|
+
if (label) innerHTML += dom.utils.createTooltipInner(label);
|
|
1027
1416
|
if (innerHTML) oButton.innerHTML = innerHTML;
|
|
1028
1417
|
|
|
1029
1418
|
oLi.appendChild(oButton);
|
|
@@ -1034,18 +1423,25 @@ function _createButton(className, title, dataCommand, dataType, innerHTML, _disa
|
|
|
1034
1423
|
};
|
|
1035
1424
|
}
|
|
1036
1425
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1426
|
+
/**
|
|
1427
|
+
* @description Update a button state, attributes, and icons
|
|
1428
|
+
* @param {HTMLElement|null} element Button element
|
|
1429
|
+
* @param {Object<string, *>} plugin Plugin
|
|
1430
|
+
* @param {Object<string, string>} icons Icons
|
|
1431
|
+
* @param {Object<string, string>} lang lang
|
|
1432
|
+
*/
|
|
1041
1433
|
export function UpdateButton(element, plugin, icons, lang) {
|
|
1042
1434
|
if (!element) return;
|
|
1043
1435
|
|
|
1044
1436
|
const noneInner = plugin.inner === false;
|
|
1045
1437
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1438
|
+
if (plugin.inner?.nodeType === 1) {
|
|
1439
|
+
element.appendChild(plugin.inner);
|
|
1440
|
+
} else {
|
|
1441
|
+
element.innerHTML = noneInner
|
|
1442
|
+
? ''
|
|
1443
|
+
: (plugin.inner || icons[plugin.icon] || plugin.icon || '<span class="se-icon-text">!</span>') + '<span class="se-tooltip-inner"><span class="se-tooltip-text">' + (lang[plugin.title] || plugin.title) + '</span></span>';
|
|
1444
|
+
}
|
|
1049
1445
|
|
|
1050
1446
|
element.setAttribute('aria-label', plugin.title);
|
|
1051
1447
|
|
|
@@ -1058,24 +1454,24 @@ export function UpdateButton(element, plugin, icons, lang) {
|
|
|
1058
1454
|
}
|
|
1059
1455
|
|
|
1060
1456
|
// side, replace button
|
|
1061
|
-
if (plugin.
|
|
1062
|
-
|
|
1063
|
-
element.parentElement.appendChild(plugin.
|
|
1457
|
+
if (plugin.afterItem) {
|
|
1458
|
+
dom.utils.addClass(plugin.afterItem, 'se-toolbar-btn');
|
|
1459
|
+
element.parentElement.appendChild(plugin.afterItem);
|
|
1064
1460
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1461
|
+
dom.utils.addClass(element, 'se-side-btn-a');
|
|
1462
|
+
dom.utils.addClass(plugin.afterItem, 'se-side-btn-after');
|
|
1067
1463
|
}
|
|
1068
|
-
if (plugin.
|
|
1069
|
-
|
|
1070
|
-
element.parentElement.insertBefore(plugin.
|
|
1464
|
+
if (plugin.beforeItem) {
|
|
1465
|
+
dom.utils.addClass(plugin.beforeItem, 'se-toolbar-btn');
|
|
1466
|
+
element.parentElement.insertBefore(plugin.beforeItem, element);
|
|
1071
1467
|
|
|
1072
|
-
if (plugin.
|
|
1073
|
-
|
|
1074
|
-
|
|
1468
|
+
if (plugin.afterItem) {
|
|
1469
|
+
dom.utils.addClass(element, 'se-side-btn');
|
|
1470
|
+
dom.utils.removeClass(element, 'se-side-btn-a');
|
|
1075
1471
|
} else {
|
|
1076
|
-
|
|
1472
|
+
dom.utils.addClass(element, 'se-side-btn-b');
|
|
1077
1473
|
}
|
|
1078
|
-
|
|
1474
|
+
dom.utils.addClass(plugin.beforeItem, 'se-side-btn-before');
|
|
1079
1475
|
}
|
|
1080
1476
|
if (plugin.replaceButton) {
|
|
1081
1477
|
element.parentElement.appendChild(plugin.replaceButton);
|
|
@@ -1085,10 +1481,10 @@ export function UpdateButton(element, plugin, icons, lang) {
|
|
|
1085
1481
|
if (!plugin.replaceButton && /^INPUT$/i.test(element.getAttribute('data-type'))) {
|
|
1086
1482
|
const inputTarget = element.querySelector('input');
|
|
1087
1483
|
if (inputTarget) {
|
|
1088
|
-
|
|
1484
|
+
dom.utils.addClass(inputTarget, 'se-toolbar-btn');
|
|
1089
1485
|
inputTarget.setAttribute('data-command', element.getAttribute('data-command'));
|
|
1090
1486
|
inputTarget.setAttribute('data-type', element.getAttribute('data-type'));
|
|
1091
|
-
if (element.hasAttribute('disabled')) inputTarget.
|
|
1487
|
+
if (element.hasAttribute('disabled')) inputTarget.disabled = true;
|
|
1092
1488
|
}
|
|
1093
1489
|
}
|
|
1094
1490
|
}
|
|
@@ -1096,17 +1492,18 @@ export function UpdateButton(element, plugin, icons, lang) {
|
|
|
1096
1492
|
/**
|
|
1097
1493
|
* @description Create editor HTML
|
|
1098
1494
|
* @param {Array} buttonList option.buttonList
|
|
1099
|
-
* @param {Object
|
|
1100
|
-
* @param {
|
|
1101
|
-
* @param {Object} icons icons
|
|
1102
|
-
* @param {Object} lang lang
|
|
1495
|
+
* @param {?Object<string, *>} plugins Plugins
|
|
1496
|
+
* @param {Map<string, *>} options options
|
|
1497
|
+
* @param {Object<string, string>} icons icons
|
|
1498
|
+
* @param {Object<string, string>} lang lang
|
|
1103
1499
|
* @param {boolean} isUpdate Is update
|
|
1104
|
-
* @returns {
|
|
1500
|
+
* @returns {{element: HTMLElement, pluginCallButtons: Object<string, Array<HTMLElement>>, responsiveButtons: Array<HTMLElement>, buttonTray: HTMLElement, updateButtons: Array<{button: HTMLElement, plugin: *, key: string}>}}}
|
|
1105
1501
|
*/
|
|
1106
1502
|
export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdate) {
|
|
1107
1503
|
/** create button list */
|
|
1108
1504
|
buttonList = JSON.parse(JSON.stringify(buttonList));
|
|
1109
1505
|
const defaultButtonList = _defaultButtons(options, icons, lang);
|
|
1506
|
+
/** @type {Object<string, Array<HTMLElement>>} */
|
|
1110
1507
|
const pluginCallButtons = {};
|
|
1111
1508
|
const responsiveButtons = [];
|
|
1112
1509
|
const updateButtons = [];
|
|
@@ -1116,10 +1513,10 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1116
1513
|
let plugin = null;
|
|
1117
1514
|
let moduleElement = null;
|
|
1118
1515
|
let buttonElement = null;
|
|
1119
|
-
let vertical = false;
|
|
1120
|
-
const moreLayer =
|
|
1121
|
-
const buttonTray =
|
|
1122
|
-
const separator_vertical =
|
|
1516
|
+
// let vertical = false;
|
|
1517
|
+
const moreLayer = dom.utils.createElement('DIV', { class: 'se-toolbar-more-layer' });
|
|
1518
|
+
const buttonTray = dom.utils.createElement('DIV', { class: 'se-btn-tray' });
|
|
1519
|
+
const separator_vertical = dom.utils.createElement('DIV', { class: 'se-toolbar-separator-vertical' });
|
|
1123
1520
|
|
|
1124
1521
|
buttonGroupLoop: for (let i = 0, more, moreContainer, moreCommand, buttonGroup, align; i < buttonList.length; i++) {
|
|
1125
1522
|
more = false;
|
|
@@ -1149,14 +1546,14 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1149
1546
|
} else {
|
|
1150
1547
|
// align
|
|
1151
1548
|
if (/^-/.test(button)) {
|
|
1152
|
-
align = button.
|
|
1549
|
+
align = button.substring(1);
|
|
1153
1550
|
moduleElement.div.className += ' module-float-' + align;
|
|
1154
1551
|
continue;
|
|
1155
1552
|
}
|
|
1156
1553
|
|
|
1157
1554
|
// rtl fix
|
|
1158
1555
|
if (/^#/.test(button)) {
|
|
1159
|
-
const option = button.
|
|
1556
|
+
const option = button.substring(1);
|
|
1160
1557
|
if (option === 'fix') moduleElement.ul.className += ' se-menu-dir-fix';
|
|
1161
1558
|
continue;
|
|
1162
1559
|
}
|
|
@@ -1169,8 +1566,15 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1169
1566
|
const title = matched[1].trim();
|
|
1170
1567
|
const innerHTML = matched[2].trim();
|
|
1171
1568
|
modules = ['se-btn-more', /^lang\./i.test(title) ? lang[title.replace(/^lang\./i, '')] : title, moreCommand, 'MORE', innerHTML];
|
|
1569
|
+
} else if (button === '|') {
|
|
1570
|
+
// separator vertical
|
|
1571
|
+
modules = ['se-toolbar-separator-vertical', '', '', 'separator', ''];
|
|
1172
1572
|
} else {
|
|
1173
1573
|
// default command
|
|
1574
|
+
if (button === 'copy' && !env.isClipboardSupported) {
|
|
1575
|
+
console.warn('[SUNEDITOR.constructor.warn] Clipboard is not supported in this browser. : [copy] button is not rendered.');
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1174
1578
|
modules = defaultButtonList[button];
|
|
1175
1579
|
}
|
|
1176
1580
|
|
|
@@ -1199,7 +1603,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1199
1603
|
// more button
|
|
1200
1604
|
if (moreButton) {
|
|
1201
1605
|
more = true;
|
|
1202
|
-
moreContainer =
|
|
1606
|
+
moreContainer = dom.utils.createElement('DIV');
|
|
1203
1607
|
moreContainer.className = 'se-more-layer ' + moreCommand;
|
|
1204
1608
|
moreContainer.setAttribute('data-ref', moreCommand);
|
|
1205
1609
|
moreContainer.innerHTML = '<div class="se-more-form"><ul class="se-menu-list"' + (align ? ' style="float: ' + align + ';"' : '') + '></ul></div>';
|
|
@@ -1208,18 +1612,23 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1208
1612
|
}
|
|
1209
1613
|
}
|
|
1210
1614
|
|
|
1211
|
-
if (vertical) {
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1615
|
+
// if (vertical) {
|
|
1616
|
+
// const sv = separator_vertical.cloneNode(false);
|
|
1617
|
+
// buttonTray.appendChild(sv);
|
|
1618
|
+
// }
|
|
1215
1619
|
|
|
1216
1620
|
buttonTray.appendChild(moduleElement.div);
|
|
1217
|
-
vertical = true;
|
|
1621
|
+
// vertical = true;
|
|
1622
|
+
} else if (buttonGroup === '|') {
|
|
1623
|
+
// // separator vertical
|
|
1624
|
+
const sv = separator_vertical.cloneNode(false);
|
|
1625
|
+
buttonTray.appendChild(sv);
|
|
1626
|
+
continue;
|
|
1218
1627
|
} else if (/^\/$/.test(buttonGroup)) {
|
|
1219
1628
|
/** line break */
|
|
1220
|
-
const enterDiv =
|
|
1629
|
+
const enterDiv = dom.utils.createElement('DIV', { class: 'se-btn-module-enter' });
|
|
1221
1630
|
buttonTray.appendChild(enterDiv);
|
|
1222
|
-
vertical = false;
|
|
1631
|
+
// vertical = false;
|
|
1223
1632
|
}
|
|
1224
1633
|
}
|
|
1225
1634
|
|
|
@@ -1228,7 +1637,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1228
1637
|
buttonTray.style.display = 'none';
|
|
1229
1638
|
break;
|
|
1230
1639
|
case 1:
|
|
1231
|
-
|
|
1640
|
+
dom.utils.removeClass(buttonTray.firstElementChild, 'se-btn-module-border');
|
|
1232
1641
|
break;
|
|
1233
1642
|
}
|
|
1234
1643
|
|
|
@@ -1236,7 +1645,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
|
|
|
1236
1645
|
if (responsiveButtons.length > 0) responsiveButtons.unshift(buttonList);
|
|
1237
1646
|
|
|
1238
1647
|
// rendering toolbar
|
|
1239
|
-
const tool_bar =
|
|
1648
|
+
const tool_bar = dom.utils.createElement('DIV', { class: 'se-toolbar sun-editor-common' + (!options.get('shortcutsHint') ? ' se-shortcut-hide' : '') }, buttonTray);
|
|
1240
1649
|
|
|
1241
1650
|
if (options.get('toolbar_hide')) tool_bar.style.display = 'none';
|
|
1242
1651
|
|