suneditor 2.46.1 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +7 -0
- package/.eslintrc.json +64 -0
- package/CONTRIBUTING.md +36 -0
- package/LICENSE.txt +1 -1
- package/README.md +174 -805
- package/dist/suneditor.min.css +1 -0
- package/dist/suneditor.min.js +1 -2
- package/package.json +96 -70
- package/src/assets/icons/_default.js +194 -0
- package/src/assets/suneditor-content.css +646 -0
- package/src/assets/suneditor.css +3378 -0
- package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
- package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
- package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
- package/src/core/base/eventManager.js +1115 -0
- package/src/core/base/events.js +320 -0
- package/src/core/base/history.js +301 -0
- package/src/core/class/char.js +146 -0
- package/src/core/class/component.js +627 -0
- package/src/core/class/format.js +3255 -0
- package/src/core/class/html.js +1621 -0
- package/src/core/class/menu.js +260 -0
- package/src/core/class/nodeTransform.js +379 -0
- package/src/core/class/notice.js +42 -0
- package/src/core/class/offset.js +578 -0
- package/src/core/class/selection.js +508 -0
- package/src/core/class/shortcuts.js +38 -0
- package/src/core/class/toolbar.js +440 -0
- package/src/core/class/viewer.js +646 -0
- package/src/core/editor.js +1593 -0
- package/src/core/section/actives.js +107 -0
- package/src/core/section/constructor.js +1237 -0
- package/src/core/section/context.js +97 -0
- package/src/editorInjector/_classes.js +22 -0
- package/src/editorInjector/_core.js +28 -0
- package/src/editorInjector/index.js +13 -0
- package/src/helper/converter.js +313 -0
- package/src/helper/domUtils.js +1177 -0
- package/src/helper/env.js +250 -0
- package/src/helper/index.js +19 -0
- package/src/helper/numbers.js +68 -0
- package/src/helper/unicode.js +43 -0
- package/src/langs/ckb.js +161 -0
- package/src/langs/cs.js +161 -0
- package/src/langs/da.js +161 -0
- package/src/langs/de.js +162 -0
- package/src/langs/en.js +199 -0
- package/src/langs/es.js +162 -0
- package/src/langs/fa.js +159 -0
- package/src/langs/fr.js +161 -0
- package/src/langs/he.js +162 -0
- package/src/{lang → langs}/index.js +0 -2
- package/src/langs/it.js +162 -0
- package/src/langs/ja.js +162 -0
- package/src/langs/ko.js +162 -0
- package/src/langs/lv.js +162 -0
- package/src/langs/nl.js +162 -0
- package/src/langs/pl.js +162 -0
- package/src/langs/pt_br.js +162 -0
- package/src/langs/ro.js +162 -0
- package/src/langs/ru.js +162 -0
- package/src/langs/se.js +162 -0
- package/src/langs/tr.js +159 -0
- package/src/langs/ua.js +162 -0
- package/src/langs/ur.js +162 -0
- package/src/langs/zh_cn.js +162 -0
- package/src/modules/ApiManager.js +168 -0
- package/src/modules/ColorPicker.js +302 -0
- package/src/modules/Controller.js +315 -0
- package/src/modules/Figure.js +1160 -0
- package/src/modules/FileBrowser.js +271 -0
- package/src/modules/FileManager.js +290 -0
- package/src/modules/HueSlider.js +513 -0
- package/src/modules/Modal.js +177 -0
- package/src/modules/ModalAnchorEditor.js +494 -0
- package/src/modules/SelectMenu.js +447 -0
- package/src/modules/_DragHandle.js +16 -0
- package/src/modules/index.js +14 -0
- package/src/plugins/command/blockquote.js +47 -47
- package/src/plugins/command/exportPdf.js +168 -0
- package/src/plugins/command/fileUpload.js +389 -0
- package/src/plugins/command/list_bulleted.js +112 -0
- package/src/plugins/command/list_numbered.js +115 -0
- package/src/plugins/dropdown/align.js +143 -0
- package/src/plugins/dropdown/backgroundColor.js +73 -0
- package/src/plugins/dropdown/font.js +113 -0
- package/src/plugins/dropdown/fontColor.js +73 -0
- package/src/plugins/dropdown/formatBlock.js +141 -0
- package/src/plugins/dropdown/hr.js +111 -0
- package/src/plugins/dropdown/layout.js +72 -0
- package/src/plugins/dropdown/lineHeight.js +114 -0
- package/src/plugins/dropdown/list.js +107 -0
- package/src/plugins/dropdown/paragraphStyle.js +117 -0
- package/src/plugins/dropdown/table.js +2810 -0
- package/src/plugins/dropdown/template.js +71 -0
- package/src/plugins/dropdown/textStyle.js +137 -0
- package/src/plugins/field/mention.js +172 -0
- package/src/plugins/fileBrowser/imageGallery.js +76 -59
- package/src/plugins/index.js +86 -24
- package/src/plugins/input/fontSize.js +357 -0
- package/src/plugins/modal/audio.js +510 -0
- package/src/plugins/modal/image.js +1062 -0
- package/src/plugins/modal/link.js +211 -0
- package/src/plugins/modal/math.js +347 -0
- package/src/plugins/modal/video.js +870 -0
- package/src/suneditor.js +62 -67
- package/src/themes/test.css +61 -0
- package/typings/CommandPlugin.d.ts +8 -0
- package/typings/DialogPlugin.d.ts +20 -0
- package/typings/FileBrowserPlugin.d.ts +30 -0
- package/typings/Lang.d.ts +124 -0
- package/typings/Module.d.ts +15 -0
- package/typings/Plugin.d.ts +42 -0
- package/typings/SubmenuPlugin.d.ts +8 -0
- package/typings/_classes.d.ts +17 -0
- package/typings/_colorPicker.d.ts +60 -0
- package/typings/_core.d.ts +55 -0
- package/typings/align.d.ts +5 -0
- package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
- package/typings/backgroundColor.d.ts +5 -0
- package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
- package/typings/char.d.ts +39 -0
- package/typings/component.d.ts +38 -0
- package/typings/context.d.ts +39 -0
- package/typings/converter.d.ts +33 -0
- package/typings/dialog.d.ts +28 -0
- package/typings/domUtils.d.ts +361 -0
- package/typings/editor.d.ts +7 -0
- package/typings/editor.ts +542 -0
- package/typings/env.d.ts +70 -0
- package/typings/eventManager.d.ts +37 -0
- package/typings/events.d.ts +262 -0
- package/typings/fileBrowser.d.ts +42 -0
- package/typings/fileManager.d.ts +67 -0
- package/typings/font.d.ts +5 -0
- package/typings/fontColor.d.ts +5 -0
- package/typings/fontSize.d.ts +5 -0
- package/typings/format.d.ts +191 -0
- package/typings/formatBlock.d.ts +5 -0
- package/typings/history.d.ts +48 -0
- package/typings/horizontalRule.d.ts +5 -0
- package/{src/plugins/dialog → typings}/image.d.ts +1 -1
- package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
- package/typings/index.d.ts +21 -0
- package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
- package/typings/index.plugins.d.ts +58 -0
- package/typings/lineHeight.d.ts +5 -0
- package/{src/plugins/dialog → typings}/link.d.ts +1 -1
- package/typings/list.d.ts +5 -0
- package/{src/plugins/dialog → typings}/math.d.ts +1 -1
- package/typings/mediaContainer.d.ts +25 -0
- package/typings/node.d.ts +57 -0
- package/typings/notice.d.ts +16 -0
- package/typings/numbers.d.ts +29 -0
- package/typings/offset.d.ts +24 -0
- package/typings/options.d.ts +589 -0
- package/typings/paragraphStyle.d.ts +5 -0
- package/typings/resizing.d.ts +141 -0
- package/typings/selection.d.ts +94 -0
- package/typings/shortcuts.d.ts +13 -0
- package/typings/suneditor.d.ts +9 -0
- package/typings/table.d.ts +5 -0
- package/typings/template.d.ts +5 -0
- package/typings/textStyle.d.ts +5 -0
- package/typings/toolbar.d.ts +32 -0
- package/typings/unicode.d.ts +25 -0
- package/{src/plugins/dialog → typings}/video.d.ts +1 -1
- package/dist/css/suneditor.min.css +0 -1
- package/src/assets/css/suneditor-contents.css +0 -562
- package/src/assets/css/suneditor.css +0 -566
- package/src/assets/defaultIcons.js +0 -103
- package/src/lang/Lang.d.ts +0 -144
- package/src/lang/ckb.d.ts +0 -5
- package/src/lang/ckb.js +0 -188
- package/src/lang/cs.d.ts +0 -5
- package/src/lang/cs.js +0 -188
- package/src/lang/da.d.ts +0 -5
- package/src/lang/da.js +0 -191
- package/src/lang/de.d.ts +0 -5
- package/src/lang/de.js +0 -188
- package/src/lang/en.d.ts +0 -5
- package/src/lang/en.js +0 -188
- package/src/lang/es.d.ts +0 -5
- package/src/lang/es.js +0 -188
- package/src/lang/fa.d.ts +0 -5
- package/src/lang/fa.js +0 -188
- package/src/lang/fr.d.ts +0 -5
- package/src/lang/fr.js +0 -188
- package/src/lang/he.d.ts +0 -5
- package/src/lang/he.js +0 -188
- package/src/lang/index.d.ts +0 -23
- package/src/lang/it.d.ts +0 -5
- package/src/lang/it.js +0 -188
- package/src/lang/ja.d.ts +0 -5
- package/src/lang/ja.js +0 -188
- package/src/lang/ko.d.ts +0 -5
- package/src/lang/ko.js +0 -188
- package/src/lang/lv.d.ts +0 -5
- package/src/lang/lv.js +0 -188
- package/src/lang/nl.d.ts +0 -5
- package/src/lang/nl.js +0 -188
- package/src/lang/pl.d.ts +0 -5
- package/src/lang/pl.js +0 -188
- package/src/lang/pt_br.d.ts +0 -5
- package/src/lang/pt_br.js +0 -189
- package/src/lang/ro.d.ts +0 -5
- package/src/lang/ro.js +0 -188
- package/src/lang/ru.d.ts +0 -5
- package/src/lang/ru.js +0 -188
- package/src/lang/se.d.ts +0 -5
- package/src/lang/se.js +0 -191
- package/src/lang/tr.d.ts +0 -5
- package/src/lang/tr.js +0 -191
- package/src/lang/ua.d.ts +0 -5
- package/src/lang/ua.js +0 -188
- package/src/lang/ur.d.ts +0 -5
- package/src/lang/ur.js +0 -188
- package/src/lang/zh_cn.d.ts +0 -5
- package/src/lang/zh_cn.js +0 -187
- package/src/lib/constructor.js +0 -954
- package/src/lib/context.d.ts +0 -42
- package/src/lib/context.js +0 -71
- package/src/lib/core.d.ts +0 -1135
- package/src/lib/core.js +0 -9395
- package/src/lib/history.d.ts +0 -48
- package/src/lib/history.js +0 -219
- package/src/lib/util.d.ts +0 -678
- package/src/lib/util.js +0 -2131
- package/src/options.d.ts +0 -608
- package/src/plugins/CommandPlugin.d.ts +0 -8
- package/src/plugins/DialogPlugin.d.ts +0 -20
- package/src/plugins/FileBrowserPlugin.d.ts +0 -30
- package/src/plugins/Module.d.ts +0 -15
- package/src/plugins/Plugin.d.ts +0 -42
- package/src/plugins/SubmenuPlugin.d.ts +0 -8
- package/src/plugins/dialog/audio.js +0 -559
- package/src/plugins/dialog/image.js +0 -1126
- package/src/plugins/dialog/link.js +0 -223
- package/src/plugins/dialog/math.js +0 -295
- package/src/plugins/dialog/mention.js +0 -242
- package/src/plugins/dialog/video.js +0 -979
- package/src/plugins/index.d.ts +0 -79
- package/src/plugins/modules/_anchor.js +0 -461
- package/src/plugins/modules/_colorPicker.d.ts +0 -60
- package/src/plugins/modules/_colorPicker.js +0 -201
- package/src/plugins/modules/_notice.d.ts +0 -21
- package/src/plugins/modules/_notice.js +0 -72
- package/src/plugins/modules/_selectMenu.js +0 -119
- package/src/plugins/modules/component.d.ts +0 -25
- package/src/plugins/modules/component.js +0 -81
- package/src/plugins/modules/dialog.d.ts +0 -28
- package/src/plugins/modules/dialog.js +0 -175
- package/src/plugins/modules/fileBrowser.d.ts +0 -42
- package/src/plugins/modules/fileBrowser.js +0 -374
- package/src/plugins/modules/fileManager.d.ts +0 -67
- package/src/plugins/modules/fileManager.js +0 -326
- package/src/plugins/modules/index.js +0 -9
- package/src/plugins/modules/resizing.d.ts +0 -154
- package/src/plugins/modules/resizing.js +0 -903
- package/src/plugins/submenu/align.d.ts +0 -5
- package/src/plugins/submenu/align.js +0 -160
- package/src/plugins/submenu/font.d.ts +0 -5
- package/src/plugins/submenu/font.js +0 -123
- package/src/plugins/submenu/fontColor.d.ts +0 -5
- package/src/plugins/submenu/fontColor.js +0 -101
- package/src/plugins/submenu/fontSize.d.ts +0 -5
- package/src/plugins/submenu/fontSize.js +0 -112
- package/src/plugins/submenu/formatBlock.d.ts +0 -5
- package/src/plugins/submenu/formatBlock.js +0 -273
- package/src/plugins/submenu/hiliteColor.d.ts +0 -5
- package/src/plugins/submenu/hiliteColor.js +0 -102
- package/src/plugins/submenu/horizontalRule.d.ts +0 -5
- package/src/plugins/submenu/horizontalRule.js +0 -98
- package/src/plugins/submenu/lineHeight.d.ts +0 -5
- package/src/plugins/submenu/lineHeight.js +0 -104
- package/src/plugins/submenu/list.d.ts +0 -5
- package/src/plugins/submenu/list.js +0 -456
- package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
- package/src/plugins/submenu/paragraphStyle.js +0 -135
- package/src/plugins/submenu/table.d.ts +0 -5
- package/src/plugins/submenu/table.js +0 -1431
- package/src/plugins/submenu/template.d.ts +0 -5
- package/src/plugins/submenu/template.js +0 -72
- package/src/plugins/submenu/textStyle.d.ts +0 -5
- package/src/plugins/submenu/textStyle.js +0 -167
- package/src/suneditor.d.ts +0 -9
- package/src/suneditor_build.js +0 -18
- /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
|
@@ -0,0 +1,1237 @@
|
|
|
1
|
+
import _icons from '../../assets/icons/_default';
|
|
2
|
+
import _defaultLang from '../../langs/en';
|
|
3
|
+
import { CreateContext, CreateFrameContext } from './context';
|
|
4
|
+
import { domUtils, numbers, converter, env } from '../../helper';
|
|
5
|
+
|
|
6
|
+
const _d = env._d;
|
|
7
|
+
const DEFAULT_BUTTON_LIST = [['undo', 'redo'], ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'], ['removeFormat'], ['outdent', 'indent'], ['fullScreen', 'showBlocks', 'codeView'], ['preview', 'print']];
|
|
8
|
+
|
|
9
|
+
const REQUIRED_FORMAT_LINE = 'div';
|
|
10
|
+
const REQUIRED_ELEMENT_WHITELIST = 'br|div';
|
|
11
|
+
const DEFAULT_ELEMENT_WHITELIST =
|
|
12
|
+
'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
|
+
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
|
+
const DEFAULT_ATTRIBUTE_WHITELIST = 'contenteditable|target|href|title|download|rel|src|alt|class|type|controls|colspan|rowspan';
|
|
15
|
+
|
|
16
|
+
const DEFAULT_FORMAT_LINE = 'P|H[1-6]|LI|TH|TD|DETAILS';
|
|
17
|
+
const DEFAULT_FORMAT_BR_LINE = 'PRE';
|
|
18
|
+
const DEFAULT_FORMAT_CLOSURE_BR_LINE = '';
|
|
19
|
+
const DEFAULT_FORMAT_BLOCK = 'BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS';
|
|
20
|
+
const DEFAULT_FORMAT_CLOSURE_BLOCK = 'TH|TD';
|
|
21
|
+
|
|
22
|
+
const DEFAULT_SIZE_UNITS = ['px', 'pt', 'em', 'rem'];
|
|
23
|
+
|
|
24
|
+
const DEFAULT_CLASS_NAME = '^__se__|^se-|^katex';
|
|
25
|
+
const DEFAULT_EXTRA_TAG_MAP = { script: false, style: false, meta: false, link: false, '[a-z]+:[a-z]+': false };
|
|
26
|
+
|
|
27
|
+
const DEFAULT_TAG_STYLES = {
|
|
28
|
+
'table|th|td': 'border|border-[a-z]+|background-color|text-align|float|font-weight|text-decoration|font-style',
|
|
29
|
+
'ol|ul': 'list-style-type'
|
|
30
|
+
};
|
|
31
|
+
const DEFAULT_TEXT_STYLES = 'font-family|font-size|color|background-color';
|
|
32
|
+
const DEFAULT_LINE_STYLES = 'text-align|margin-left|margin-right|line-height';
|
|
33
|
+
const DEFAULT_CONTENT_STYLES =
|
|
34
|
+
'background|background-clip|background-color|' +
|
|
35
|
+
'border|border-bottom|border-collapse|border-color|border-image|border-left-width|border-radius|border-right-width|border-spacing|border-style|border-top|border-width|' +
|
|
36
|
+
'box-shadow|box-sizing|' +
|
|
37
|
+
'caption-side|color|content|' +
|
|
38
|
+
'direction|display|' +
|
|
39
|
+
'float|font|font-family|font-size|font-style|font-weight|' +
|
|
40
|
+
'height|' +
|
|
41
|
+
'left|letter-spacing|line-height|list-style-position|list-style-type|' +
|
|
42
|
+
'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
|
+
'outline|overflow|' +
|
|
44
|
+
'position|padding|padding-bottom|padding-inline-start|padding-left|padding-right|padding-top|' +
|
|
45
|
+
'rotate|rotateX|rotateY|' +
|
|
46
|
+
'table-layout|text-align|text-decoration|text-shadow|text-transform|top|' +
|
|
47
|
+
'text-indent|text-rendering|' +
|
|
48
|
+
'vertical-align|visibility|' +
|
|
49
|
+
'white-space|width|word-break|word-wrap';
|
|
50
|
+
|
|
51
|
+
const RETAIN_STYLE_MODE = ['repeat', 'always', 'none'];
|
|
52
|
+
|
|
53
|
+
export const RO_UNAVAILABD = [
|
|
54
|
+
'mode',
|
|
55
|
+
'externalLibs',
|
|
56
|
+
'keepStyleOnDelete',
|
|
57
|
+
'iframe',
|
|
58
|
+
'convertTextTags',
|
|
59
|
+
'textStyleTags',
|
|
60
|
+
'fontSizeUnits',
|
|
61
|
+
'spanStyles',
|
|
62
|
+
'lineStyles',
|
|
63
|
+
'tagStyles',
|
|
64
|
+
'reverseCommands',
|
|
65
|
+
'shortcutsDisable',
|
|
66
|
+
'shortcuts',
|
|
67
|
+
'buttonList',
|
|
68
|
+
'subToolbar',
|
|
69
|
+
'toolbar_container',
|
|
70
|
+
'statusbar_container',
|
|
71
|
+
'elementWhitelist',
|
|
72
|
+
'elementBlacklist',
|
|
73
|
+
'attributeWhitelist',
|
|
74
|
+
'attributeBlacklist',
|
|
75
|
+
'defaultLine',
|
|
76
|
+
'formatClosureBrLine',
|
|
77
|
+
'formatBrLine',
|
|
78
|
+
'formatLine',
|
|
79
|
+
'formatClosureBlock',
|
|
80
|
+
'formatBlock',
|
|
81
|
+
'__defaultElementWhitelist',
|
|
82
|
+
'__defaultAttributeWhitelist',
|
|
83
|
+
'__listCommonStyle',
|
|
84
|
+
'icons',
|
|
85
|
+
'lang',
|
|
86
|
+
'codeMirror'
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @description document create
|
|
91
|
+
* @param {Object} options Options
|
|
92
|
+
* @param {Element|Array.<Element>} editorTargets Target textarea
|
|
93
|
+
* @returns {Object}
|
|
94
|
+
*/
|
|
95
|
+
const Constructor = function (editorTargets, options) {
|
|
96
|
+
if (typeof options !== 'object') options = {};
|
|
97
|
+
|
|
98
|
+
/** --- Plugins ------------------------------------------------------------------------------------------ */
|
|
99
|
+
const plugins = {};
|
|
100
|
+
if (options.plugins) {
|
|
101
|
+
const originPlugins = options.plugins;
|
|
102
|
+
const pluginsValues = Array.isArray(originPlugins.length)
|
|
103
|
+
? originPlugins
|
|
104
|
+
: Object.keys(originPlugins).map(function (name) {
|
|
105
|
+
return originPlugins[name];
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
for (let i = 0, len = pluginsValues.length, p; i < len; i++) {
|
|
109
|
+
p = pluginsValues[i].default || pluginsValues[i];
|
|
110
|
+
plugins[p.key] = p;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** --- options --------------------------------------------------------------- */
|
|
115
|
+
const optionMap = InitOptions(options, editorTargets);
|
|
116
|
+
const o = optionMap.o;
|
|
117
|
+
const icons = optionMap.i;
|
|
118
|
+
const lang = optionMap.l;
|
|
119
|
+
const loadingBox = domUtils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
|
|
120
|
+
|
|
121
|
+
/** --- carrier wrapper --------------------------------------------------------------- */
|
|
122
|
+
const editor_carrier_wrapper = domUtils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
123
|
+
// menuTray
|
|
124
|
+
const menuTray = domUtils.createElement('DIV', { class: 'se-menu-tray' });
|
|
125
|
+
editor_carrier_wrapper.appendChild(menuTray);
|
|
126
|
+
// focus temp element
|
|
127
|
+
const focusTemp = domUtils.createElement('INPUT', {
|
|
128
|
+
class: '__se__focus__temp__',
|
|
129
|
+
style: 'position: absolute !important; top: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;'
|
|
130
|
+
});
|
|
131
|
+
focusTemp.tabIndex = 0;
|
|
132
|
+
editor_carrier_wrapper.appendChild(focusTemp);
|
|
133
|
+
|
|
134
|
+
// modal
|
|
135
|
+
const modal = domUtils.createElement('DIV', { class: 'se-modal sun-editor-common' });
|
|
136
|
+
const modal_back = domUtils.createElement('DIV', { class: 'se-modal-back', style: 'display: none;' });
|
|
137
|
+
const modal_inner = domUtils.createElement('DIV', { class: 'se-modal-inner', style: 'display: none;' });
|
|
138
|
+
modal.appendChild(modal_back);
|
|
139
|
+
modal.appendChild(modal_inner);
|
|
140
|
+
editor_carrier_wrapper.appendChild(modal);
|
|
141
|
+
|
|
142
|
+
// loding box, resizing back
|
|
143
|
+
editor_carrier_wrapper.appendChild(domUtils.createElement('DIV', { class: 'se-back-wrapper' }));
|
|
144
|
+
editor_carrier_wrapper.appendChild(loadingBox.cloneNode(true));
|
|
145
|
+
|
|
146
|
+
// drag cursor
|
|
147
|
+
const dragCursor = domUtils.createElement('DIV', { class: 'se-drag-cursor' });
|
|
148
|
+
editor_carrier_wrapper.appendChild(dragCursor);
|
|
149
|
+
|
|
150
|
+
// set carrier wrapper
|
|
151
|
+
_d.body.appendChild(editor_carrier_wrapper);
|
|
152
|
+
|
|
153
|
+
/** --- toolbar --------------------------------------------------------------- */
|
|
154
|
+
let subbar = null,
|
|
155
|
+
sub_main = null;
|
|
156
|
+
const tool_bar_main = CreateToolBar(optionMap.buttons, plugins, o, icons, lang, false);
|
|
157
|
+
const toolbar = tool_bar_main.element;
|
|
158
|
+
toolbar.style.visibility = 'hidden';
|
|
159
|
+
// toolbar mode
|
|
160
|
+
if (/inline/i.test(o.get('mode'))) {
|
|
161
|
+
toolbar.className += ' se-toolbar-inline';
|
|
162
|
+
toolbar.style.width = o.get('toolbar_width');
|
|
163
|
+
} else if (/balloon/i.test(o.get('mode'))) {
|
|
164
|
+
toolbar.className += ' se-toolbar-balloon';
|
|
165
|
+
toolbar.style.width = o.get('toolbar_width');
|
|
166
|
+
toolbar.appendChild(domUtils.createElement('DIV', { class: 'se-arrow' }));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** --- subToolbar --------------------------------------------------------------- */
|
|
170
|
+
if (optionMap.subButtons) {
|
|
171
|
+
sub_main = CreateToolBar(optionMap.subButtons, plugins, o, icons, lang, false);
|
|
172
|
+
subbar = sub_main.element;
|
|
173
|
+
subbar.style.visibility = 'hidden';
|
|
174
|
+
// subbar mode must be balloon-*
|
|
175
|
+
subbar.className += ' se-toolbar-balloon se-toolbar-sub';
|
|
176
|
+
subbar.style.width = o.get('toolbar.sub_width');
|
|
177
|
+
subbar.appendChild(domUtils.createElement('DIV', { class: 'se-arrow' }));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** frame - root set - start -------------------------------------------------------------- */
|
|
181
|
+
const rootId = editorTargets[0].key || null;
|
|
182
|
+
const rootKeys = [];
|
|
183
|
+
const frameRoots = new Map();
|
|
184
|
+
const statusbarContainer = optionMap.statusbarContainer;
|
|
185
|
+
let default_status_bar = null;
|
|
186
|
+
for (let i = 0, len = editorTargets.length; i < len; i++) {
|
|
187
|
+
const editTarget = editorTargets[i];
|
|
188
|
+
const to = editTarget.options;
|
|
189
|
+
const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (to.get('_rtl') ? ' se-rtl' : '') });
|
|
190
|
+
const container = domUtils.createElement('DIV', { class: 'se-container' });
|
|
191
|
+
const editor_div = domUtils.createElement('DIV', { class: 'se-wrapper' });
|
|
192
|
+
|
|
193
|
+
container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-shadow' }));
|
|
194
|
+
|
|
195
|
+
// init element
|
|
196
|
+
const initElements = _initTargetElements(editTarget.key, o, top_div, to);
|
|
197
|
+
const bottomBar = initElements.bottomBar;
|
|
198
|
+
const statusbar = bottomBar.statusbar;
|
|
199
|
+
const wysiwyg_div = initElements.wysiwygFrame;
|
|
200
|
+
const placeholder_span = initElements.placeholder;
|
|
201
|
+
let textarea = initElements.codeView;
|
|
202
|
+
|
|
203
|
+
// line breaker
|
|
204
|
+
const line_breaker_t = domUtils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-t', title: lang.insertLine }, icons.line_break);
|
|
205
|
+
const line_breaker_b = domUtils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-b', title: lang.insertLine }, icons.line_break);
|
|
206
|
+
|
|
207
|
+
editor_div.appendChild(line_breaker_t);
|
|
208
|
+
editor_div.appendChild(line_breaker_b);
|
|
209
|
+
|
|
210
|
+
// append container
|
|
211
|
+
if (placeholder_span) editor_div.appendChild(placeholder_span);
|
|
212
|
+
container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
|
|
213
|
+
container.appendChild(editor_div);
|
|
214
|
+
|
|
215
|
+
// statusbar
|
|
216
|
+
if (statusbar) {
|
|
217
|
+
if (statusbarContainer) {
|
|
218
|
+
if (!default_status_bar) {
|
|
219
|
+
statusbarContainer.appendChild(domUtils.createElement('DIV', { class: 'sun-editor' }, statusbar));
|
|
220
|
+
default_status_bar = statusbar;
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
container.appendChild(statusbar);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// loading bar
|
|
228
|
+
container.appendChild(loadingBox.cloneNode(true));
|
|
229
|
+
|
|
230
|
+
// root key
|
|
231
|
+
const key = editTarget.key || null;
|
|
232
|
+
|
|
233
|
+
// code view - wrapper
|
|
234
|
+
const codeWrapper = domUtils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
|
|
235
|
+
codeWrapper.style.setProperty('display', 'none', 'important');
|
|
236
|
+
editor_div.appendChild(codeWrapper);
|
|
237
|
+
|
|
238
|
+
// check code mirror
|
|
239
|
+
const codeMirrorEl = _checkCodeMirror(o, to, textarea);
|
|
240
|
+
// not used code mirror
|
|
241
|
+
if (textarea === codeMirrorEl) {
|
|
242
|
+
// add line nubers
|
|
243
|
+
const codeNumbers = domUtils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
|
|
244
|
+
codeWrapper.insertBefore(codeNumbers, textarea);
|
|
245
|
+
} else {
|
|
246
|
+
textarea = codeMirrorEl;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// set container
|
|
250
|
+
top_div.appendChild(container);
|
|
251
|
+
rootKeys.push(key);
|
|
252
|
+
frameRoots.set(key, CreateFrameContext(editTarget, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, key));
|
|
253
|
+
}
|
|
254
|
+
/** frame - root set - end -------------------------------------------------------------- */
|
|
255
|
+
|
|
256
|
+
// toolbar container
|
|
257
|
+
const toolbar_container = o.get('toolbar_container');
|
|
258
|
+
if (toolbar_container) {
|
|
259
|
+
const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (o.get('_rtl') ? ' se-rtl' : '') });
|
|
260
|
+
const container = domUtils.createElement('DIV', { class: 'se-container' });
|
|
261
|
+
container.appendChild(toolbar);
|
|
262
|
+
if (subbar) container.appendChild(subbar);
|
|
263
|
+
top_div.appendChild(container);
|
|
264
|
+
toolbar_container.appendChild(top_div);
|
|
265
|
+
toolbar_container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
|
|
266
|
+
} else {
|
|
267
|
+
const rootContainer = frameRoots.get(rootId).get('container');
|
|
268
|
+
rootContainer.insertBefore(toolbar, rootContainer.firstElementChild);
|
|
269
|
+
if (subbar) rootContainer.insertBefore(subbar, rootContainer.firstElementChild);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
context: CreateContext(toolbar, toolbar_container, menuTray, subbar, statusbarContainer),
|
|
274
|
+
carrierWrapper: editor_carrier_wrapper,
|
|
275
|
+
options: o,
|
|
276
|
+
plugins: plugins,
|
|
277
|
+
icons: icons,
|
|
278
|
+
lang: lang,
|
|
279
|
+
value: optionMap.v,
|
|
280
|
+
rootId: rootId,
|
|
281
|
+
rootKeys: rootKeys,
|
|
282
|
+
frameRoots: frameRoots,
|
|
283
|
+
pluginCallButtons: tool_bar_main.pluginCallButtons,
|
|
284
|
+
responsiveButtons: tool_bar_main.responsiveButtons,
|
|
285
|
+
pluginCallButtons_sub: sub_main ? sub_main.pluginCallButtons : [],
|
|
286
|
+
responsiveButtons_sub: sub_main ? sub_main.responsiveButtons : []
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @description Create shortcuts desc span.
|
|
292
|
+
* @param {string} command Command string
|
|
293
|
+
* @param {Array.<string>} values options.shortcuts[command]
|
|
294
|
+
* @param {Element} button Command button element
|
|
295
|
+
* @param {Map} keyMap Map to store shortcut key info
|
|
296
|
+
* @param {Array} rc "_reverseCommandArray" option
|
|
297
|
+
* @param {Array} reverseKeys Reverse key array
|
|
298
|
+
*/
|
|
299
|
+
export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys) {
|
|
300
|
+
if (!values || values.length < 2) return;
|
|
301
|
+
const tooptip = button.querySelector('.se-tooltip-text');
|
|
302
|
+
|
|
303
|
+
for (let i = 0, v, s, t, k, r; i < values.length; i += 2) {
|
|
304
|
+
v = values[i];
|
|
305
|
+
s = /^s/i.test(v);
|
|
306
|
+
k = numbers.get(v) + (s ? 1000 : 0);
|
|
307
|
+
if (!keyMap.has(k)) {
|
|
308
|
+
r = rc.indexOf(command);
|
|
309
|
+
r = r === -1 ? '' : numbers.isOdd(r) ? rc[r + 1] : rc[r - 1];
|
|
310
|
+
if (r) reverseKeys.push(k);
|
|
311
|
+
keyMap.set(k, { c: command, r: r, t: button.getAttribute('data-type'), e: button });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!(t = values[i + 1])) continue;
|
|
315
|
+
if (tooptip) _addTooltip(tooptip, s, t);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function _addTooltip(tooptipBtn, shift, shortcut) {
|
|
320
|
+
tooptipBtn.appendChild(domUtils.createElement('SPAN', { class: 'se-shortcut' }, env.cmdIcon + (shift ? env.shiftIcon : '') + '+<span class="se-shortcut-key">' + shortcut + '</span>'));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @description Returns a new object with merge "a" and "b"
|
|
325
|
+
* @param {Object} obj object
|
|
326
|
+
* @returns {Object}
|
|
327
|
+
*/
|
|
328
|
+
function _mergeObject(a, b) {
|
|
329
|
+
return [a, b].reduce((_default, _new) => {
|
|
330
|
+
for (const key in _new) {
|
|
331
|
+
_default[key] = (_new[key] || '').toLowerCase();
|
|
332
|
+
}
|
|
333
|
+
return _default;
|
|
334
|
+
}, {});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @description Initialize options
|
|
339
|
+
* @param {Object} options Options object
|
|
340
|
+
* @param {Array.<Element>} editorTargets Target textarea
|
|
341
|
+
* @returns {o:Map, p:Map} {{o: options map, p: plugins map}}
|
|
342
|
+
*/
|
|
343
|
+
export function InitOptions(options, editorTargets) {
|
|
344
|
+
const buttonList = options.buttonList || DEFAULT_BUTTON_LIST;
|
|
345
|
+
const o = new Map();
|
|
346
|
+
|
|
347
|
+
/** Multi root */
|
|
348
|
+
if (editorTargets.length > 1) {
|
|
349
|
+
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.');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Base */
|
|
353
|
+
const modeValue = options.strictMode !== false;
|
|
354
|
+
o.set('strictMode', {
|
|
355
|
+
tagFilter: modeValue,
|
|
356
|
+
formatFilter: modeValue,
|
|
357
|
+
classFilter: modeValue,
|
|
358
|
+
styleNodeFilter: modeValue,
|
|
359
|
+
attrFilter: modeValue,
|
|
360
|
+
styleFilter: modeValue,
|
|
361
|
+
...options.strictMode
|
|
362
|
+
});
|
|
363
|
+
o.set('mode', options.mode || 'classic'); // classic, inline, balloon, balloon-always
|
|
364
|
+
o.set('externalLibs', options.externalLibs || {});
|
|
365
|
+
o.set('keepStyleOnDelete', !!options.keepStyleOnDelete);
|
|
366
|
+
o.set('fontSizeUnits', Array.isArray(options.fontSizeUnits) && options.fontSizeUnits.length > 0 ? options.fontSizeUnits.map((v) => v.toLowerCase()) : DEFAULT_SIZE_UNITS);
|
|
367
|
+
o.set('allowedClassName', new RegExp(`${options.allowedClassName && typeof options.allowedClassName === 'string' ? options.allowedClassName + '|' : ''}${DEFAULT_CLASS_NAME}`));
|
|
368
|
+
|
|
369
|
+
let retainStyleMode = options.retainStyleMode;
|
|
370
|
+
if (typeof retainStyleMode === 'string' && !RETAIN_STYLE_MODE.includes(retainStyleMode)) {
|
|
371
|
+
console.error(`Invalid retainStyleMode: ${retainStyleMode}. Valid options are ${RETAIN_STYLE_MODE.join(', ')}. Using default 'once'.`);
|
|
372
|
+
retainStyleMode = 'repeat';
|
|
373
|
+
}
|
|
374
|
+
o.set('retainStyleMode', retainStyleMode);
|
|
375
|
+
|
|
376
|
+
const allowedExtraTags = { ...DEFAULT_EXTRA_TAG_MAP, ...options.allowedExtraTags, '-': true };
|
|
377
|
+
const extraKeys = Object.keys(allowedExtraTags);
|
|
378
|
+
const allowedKeys = extraKeys.filter((k) => allowedExtraTags[k]).join('|');
|
|
379
|
+
const disallowedKeys = extraKeys.filter((k) => !allowedExtraTags[k]).join('|');
|
|
380
|
+
o.set('_allowedExtraTag', allowedKeys);
|
|
381
|
+
o.set('_disallowedExtraTag', disallowedKeys);
|
|
382
|
+
|
|
383
|
+
o.set('events', options.events || {});
|
|
384
|
+
|
|
385
|
+
// text style tags
|
|
386
|
+
o.set('textStyleTags', (typeof options.__textStyleTags === 'string' ? options.__textStyleTags : DEFAULT_TEXT_STYLE_TAGS) + (options.textStyleTags ? '|' + options.textStyleTags : ''));
|
|
387
|
+
const textTags = _mergeObject(
|
|
388
|
+
{
|
|
389
|
+
bold: 'strong',
|
|
390
|
+
underline: 'u',
|
|
391
|
+
italic: 'em',
|
|
392
|
+
strike: 'del',
|
|
393
|
+
subscript: 'sub',
|
|
394
|
+
superscript: 'sup'
|
|
395
|
+
},
|
|
396
|
+
options.convertTextTags || {}
|
|
397
|
+
);
|
|
398
|
+
o.set('convertTextTags', textTags);
|
|
399
|
+
o.set('_textStyleTags', Object.values(textTags).concat(['span', 'li']));
|
|
400
|
+
o.set(
|
|
401
|
+
'tagStyles',
|
|
402
|
+
[{ ...DEFAULT_TAG_STYLES, ...(options.__tagStyles || {}) }, options.tagStyles || {}].reduce((_default, _new) => {
|
|
403
|
+
for (const key in _new) {
|
|
404
|
+
_default[key] = _new[key];
|
|
405
|
+
}
|
|
406
|
+
return _default;
|
|
407
|
+
}, {})
|
|
408
|
+
);
|
|
409
|
+
o.set('_textStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULT_TEXT_STYLES}${options.spanStyles ? '|' + options.spanStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
410
|
+
o.set('_lineStylesRegExp', new RegExp(`\\s*[^-a-zA-Z](${DEFAULT_LINE_STYLES}${options.lineStyles ? '|' + options.lineStyles : ''})\\s*:[^;]+(?!;)*`, 'gi'));
|
|
411
|
+
o.set('_defaultStyleTagMap', {
|
|
412
|
+
strong: textTags.bold,
|
|
413
|
+
b: textTags.bold,
|
|
414
|
+
u: textTags.underline,
|
|
415
|
+
ins: textTags.underline,
|
|
416
|
+
em: textTags.italic,
|
|
417
|
+
i: textTags.italic,
|
|
418
|
+
del: textTags.strike,
|
|
419
|
+
strike: textTags.strike,
|
|
420
|
+
s: textTags.strike,
|
|
421
|
+
sub: textTags.subscript,
|
|
422
|
+
sup: textTags.superscript
|
|
423
|
+
});
|
|
424
|
+
o.set(
|
|
425
|
+
'_styleCommandMap',
|
|
426
|
+
_mergeObject(converter.swapKeyValue(textTags), {
|
|
427
|
+
strong: 'bold',
|
|
428
|
+
b: 'bold',
|
|
429
|
+
u: 'underline',
|
|
430
|
+
ins: 'underline',
|
|
431
|
+
em: 'italic',
|
|
432
|
+
i: 'italic',
|
|
433
|
+
del: 'strike',
|
|
434
|
+
strike: 'strike',
|
|
435
|
+
s: 'strike',
|
|
436
|
+
sub: 'subscript',
|
|
437
|
+
sup: 'superscript'
|
|
438
|
+
})
|
|
439
|
+
);
|
|
440
|
+
o.set('_defaultTagCommand', {
|
|
441
|
+
bold: textTags.bold,
|
|
442
|
+
underline: textTags.underline,
|
|
443
|
+
italic: textTags.italic,
|
|
444
|
+
strike: textTags.strike,
|
|
445
|
+
subscript: textTags.sub,
|
|
446
|
+
superscript: textTags.sup
|
|
447
|
+
});
|
|
448
|
+
// text direction
|
|
449
|
+
o.set('textDirection', typeof options.textDirection !== 'string' ? 'ltr' : options.textDirection);
|
|
450
|
+
o.set('_rtl', o.get('textDirection') === 'rtl');
|
|
451
|
+
o.set('reverseCommands', ['indent-outdent'].concat(options.reverseButtons || []));
|
|
452
|
+
o.set('_reverseCommandArray', ('-' + o.get('reverseCommands').join('-')).split('-'));
|
|
453
|
+
if (numbers.isEven(o.get('_reverseCommandArray').length)) {
|
|
454
|
+
console.warn('[SUNEDITOR.create.warning] The "reverseCommands" option is invalid, Shortcuts key may not work properly.');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// etc
|
|
458
|
+
o.set('historyStackDelayTime', typeof options.historyStackDelayTime === 'number' ? options.historyStackDelayTime : 400);
|
|
459
|
+
o.set('_editableClass', 'sun-editor-editable' + (o.get('_rtl') ? ' se-rtl' : ''));
|
|
460
|
+
o.set('lineAttrReset', ['id'].concat(options.lineAttrReset && typeof options.lineAttrReset === 'string' ? options.lineAttrReset.toLowerCase().split('|') : []));
|
|
461
|
+
o.set('printClass', typeof options.printClass === 'string' ? options.printClass : null);
|
|
462
|
+
|
|
463
|
+
/** whitelist, blacklist */
|
|
464
|
+
// default line
|
|
465
|
+
o.set('defaultLine', typeof options.defaultLine === 'string' && options.defaultLine.length > 0 ? options.defaultLine : 'p');
|
|
466
|
+
// element
|
|
467
|
+
const elw = (typeof options.elementWhitelist === 'string' ? options.elementWhitelist : '').toLowerCase();
|
|
468
|
+
o.set('elementWhitelist', elw + (elw ? '|' : '') + o.get('_allowedExtraTag'));
|
|
469
|
+
const elb = _createBlacklist((typeof options.elementBlacklist === 'string' ? options.elementBlacklist : '').toLowerCase(), o.get('defaultLine'));
|
|
470
|
+
o.set('elementBlacklist', elb + (elb ? '|' : '') + o.get('_disallowedExtraTag'));
|
|
471
|
+
// attribute
|
|
472
|
+
o.set('attributeWhitelist', !options.attributeWhitelist || typeof options.attributeWhitelist !== 'object' ? null : options.attributeWhitelist);
|
|
473
|
+
o.set('attributeBlacklist', !options.attributeBlacklist || typeof options.attributeBlacklist !== 'object' ? null : options.attributeBlacklist);
|
|
474
|
+
// format tag
|
|
475
|
+
o.set(
|
|
476
|
+
'formatClosureBrLine',
|
|
477
|
+
_createFormatInfo(
|
|
478
|
+
options.formatClosureBrLine,
|
|
479
|
+
(options.__defaultFormatClosureBrLine = typeof options.__defaultFormatClosureBrLine === 'string' ? options.__defaultFormatClosureBrLine : DEFAULT_FORMAT_CLOSURE_BR_LINE).toLowerCase(),
|
|
480
|
+
o.get('elementBlacklist')
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
o.set(
|
|
484
|
+
'formatBrLine',
|
|
485
|
+
_createFormatInfo(
|
|
486
|
+
(options.formatBrLine || '') + '|' + o.get('formatClosureBrLine').str,
|
|
487
|
+
(options.__defaultFormatBrLine = typeof options.__defaultFormatBrLine === 'string' ? options.__defaultFormatBrLine : DEFAULT_FORMAT_BR_LINE).toLowerCase(),
|
|
488
|
+
o.get('elementBlacklist')
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
o.set(
|
|
492
|
+
'formatLine',
|
|
493
|
+
_createFormatInfo(
|
|
494
|
+
REQUIRED_FORMAT_LINE + '|' + (options.formatLine || '') + '|' + o.get('formatBrLine').str,
|
|
495
|
+
(options.__defaultFormatLine = typeof options.__defaultFormatLine === 'string' ? options.__defaultFormatLine : DEFAULT_FORMAT_LINE).toLowerCase(),
|
|
496
|
+
o.get('elementBlacklist')
|
|
497
|
+
)
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
// Error - default line
|
|
501
|
+
if (!o.get('formatLine').reg.test(o.get('defaultLine'))) {
|
|
502
|
+
throw Error(`[SUNEDITOR.create.fail] The "defaultLine(${o.get('defaultLine')})" option must be included in the "formatLine(${o.get('formatLine').str})" option.`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
o.set(
|
|
506
|
+
'formatClosureBlock',
|
|
507
|
+
_createFormatInfo(
|
|
508
|
+
options.formatClosureBlock,
|
|
509
|
+
(options.__defaultFormatClosureBlock = typeof options.__defaultFormatClosureBlock === 'string' ? options.__defaultFormatClosureBlock : DEFAULT_FORMAT_CLOSURE_BLOCK).toLowerCase(),
|
|
510
|
+
o.get('elementBlacklist')
|
|
511
|
+
)
|
|
512
|
+
);
|
|
513
|
+
o.set(
|
|
514
|
+
'formatBlock',
|
|
515
|
+
_createFormatInfo(
|
|
516
|
+
(options.formatBlock || '') + '|' + o.get('formatClosureBlock').str,
|
|
517
|
+
(options.__defaultFormatBlock = typeof options.__defaultFormatBlock === 'string' ? options.__defaultFormatBlock : DEFAULT_FORMAT_BLOCK).toLowerCase(),
|
|
518
|
+
o.get('elementBlacklist')
|
|
519
|
+
)
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
/** __defaults */
|
|
523
|
+
o.set('__defaultElementWhitelist', REQUIRED_ELEMENT_WHITELIST + '|' + (typeof options.__defaultElementWhitelist === 'string' ? options.__defaultElementWhitelist : DEFAULT_ELEMENT_WHITELIST).toLowerCase());
|
|
524
|
+
o.set('__defaultAttributeWhitelist', (typeof options.__defaultAttributeWhitelist === 'string' ? options.__defaultAttributeWhitelist : DEFAULT_ATTRIBUTE_WHITELIST).toLowerCase());
|
|
525
|
+
// --- create element whitelist (__defaultElementWhiteList + elementWhitelist + format[line, BrLine, Block, Closureblock, ClosureBrLine] - elementBlacklist)
|
|
526
|
+
o.set('_editorElementWhitelist', o.get('elementWhitelist') === '*' ? '*' : _createWhitelist(o));
|
|
527
|
+
|
|
528
|
+
/** Toolbar */
|
|
529
|
+
o.set('toolbar_width', options.toolbar_width ? (numbers.is(options.toolbar_width) ? options.toolbar_width + 'px' : options.toolbar_width) : 'auto');
|
|
530
|
+
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);
|
|
531
|
+
o.set('toolbar_sticky', /balloon/i.test(o.get('mode')) ? -1 : options.toolbar_sticky === undefined ? 0 : /^\d+/.test(options.toolbar_sticky) ? numbers.get(options.toolbar_sticky, 0) : -1);
|
|
532
|
+
o.set('toolbar_hide', !!options.toolbar_hide);
|
|
533
|
+
|
|
534
|
+
/** subToolbar */
|
|
535
|
+
let subButtons = null;
|
|
536
|
+
const subbar = options.subToolbar;
|
|
537
|
+
if (subbar?.buttonList?.length > 0) {
|
|
538
|
+
if (/balloon/.test(o.get('mode'))) {
|
|
539
|
+
console.warn('[SUNEDITOR.create.subToolbar.fail] When the "mode" option is "balloon-*", the "subToolbar" option is omitted.');
|
|
540
|
+
} else {
|
|
541
|
+
o.set('_subMode', subbar.mode || 'balloon');
|
|
542
|
+
o.set('toolbar.sub_width', subbar.width ? (numbers.is(subbar.width) ? subbar.width + 'px' : subbar.width) : 'auto');
|
|
543
|
+
subButtons = o.get('_rtl') ? subbar.buttonList.reverse() : subbar.buttonList;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** root options */
|
|
548
|
+
for (let i = 0, len = editorTargets.length; i < len; i++) {
|
|
549
|
+
InitFrameOptions(editorTargets[i].options || {}, options, (editorTargets[i].options = new Map()));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/** Key actions */
|
|
553
|
+
o.set('tabDisable', !!options.tabDisable);
|
|
554
|
+
o.set('shortcutsHint', options.shortcutsHint === undefined ? true : !!options.shortcutsHint);
|
|
555
|
+
const shortcuts = !(options.shortcutsDisable === undefined ? true : !!options.shortcutsDisable)
|
|
556
|
+
? {}
|
|
557
|
+
: [
|
|
558
|
+
{
|
|
559
|
+
// default command
|
|
560
|
+
selectAll: ['65', 'A'],
|
|
561
|
+
bold: ['66', 'B'],
|
|
562
|
+
strike: ['s83', 'S'],
|
|
563
|
+
underline: ['85', 'U'],
|
|
564
|
+
italic: ['73', 'I'],
|
|
565
|
+
redo: ['89', 'Y', 's90', 'Z'],
|
|
566
|
+
undo: ['90', 'Z'],
|
|
567
|
+
indent: ['221', ']'],
|
|
568
|
+
outdent: ['219', '['],
|
|
569
|
+
sup: ['187', '='],
|
|
570
|
+
sub: ['s187', '='],
|
|
571
|
+
save: ['83', 'S'],
|
|
572
|
+
// plugins
|
|
573
|
+
link: ['75', 'K']
|
|
574
|
+
},
|
|
575
|
+
options.shortcuts || {}
|
|
576
|
+
].reduce((_default, _new) => {
|
|
577
|
+
for (const key in _new) {
|
|
578
|
+
_default[key] = _new[key];
|
|
579
|
+
}
|
|
580
|
+
return _default;
|
|
581
|
+
}, {});
|
|
582
|
+
o.set('shortcuts', shortcuts);
|
|
583
|
+
|
|
584
|
+
/** View */
|
|
585
|
+
o.set('fullScreenOffset', options.fullScreenOffset === undefined ? 0 : /^\d+/.test(options.fullScreenOffset) ? numbers.get(options.fullScreenOffset, 0) : 0);
|
|
586
|
+
o.set('previewTemplate', typeof options.previewTemplate === 'string' ? options.previewTemplate : null);
|
|
587
|
+
o.set('printTemplate', typeof options.printTemplate === 'string' ? options.printTemplate : null);
|
|
588
|
+
|
|
589
|
+
/** --- Media select */
|
|
590
|
+
o.set('mediaAutoSelect', options.mediaAutoSelect === undefined ? true : !!options.mediaAutoSelect);
|
|
591
|
+
|
|
592
|
+
/** --- Url input protocol */
|
|
593
|
+
o.set('defaultUrlProtocol', typeof options.defaultUrlProtocol === 'string' ? options.defaultUrlProtocol : null);
|
|
594
|
+
|
|
595
|
+
/** External library */
|
|
596
|
+
// CodeMirror
|
|
597
|
+
const cm = o.get('externalLibs').codeMirror;
|
|
598
|
+
if (cm) {
|
|
599
|
+
o.set('codeMirror', cm);
|
|
600
|
+
if (cm.EditorView) {
|
|
601
|
+
o.set('codeMirror6Editor', true);
|
|
602
|
+
} else if (cm.src) {
|
|
603
|
+
o.set('codeMirror5Editor', true);
|
|
604
|
+
} else {
|
|
605
|
+
console.warn('[SUNEDITOR.options.externalLibs.codeMirror.fail] The codeMirror option is set incorrectly.');
|
|
606
|
+
o.set('codeMirror', null);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/** Private options */
|
|
611
|
+
o.set('__listCommonStyle', options.__listCommonStyle || ['fontSize', 'color', 'fontFamily', 'fontWeight', 'fontStyle']);
|
|
612
|
+
|
|
613
|
+
/** --- Icons ------------------------------------------------------------------------------------------ */
|
|
614
|
+
const icons =
|
|
615
|
+
!options.icons || typeof options.icons !== 'object'
|
|
616
|
+
? _icons
|
|
617
|
+
: [_icons, options.icons].reduce((_default, _new) => {
|
|
618
|
+
for (const key in _new) {
|
|
619
|
+
_default[key] = _new[key];
|
|
620
|
+
}
|
|
621
|
+
return _default;
|
|
622
|
+
}, {});
|
|
623
|
+
o.set('icons', icons);
|
|
624
|
+
|
|
625
|
+
/** Create all used styles */
|
|
626
|
+
const allUsedStyles = new Set(DEFAULT_CONTENT_STYLES.split('|'));
|
|
627
|
+
const _ss = options.spanStyles?.split('|') || [];
|
|
628
|
+
const _ls = o.get('__listCommonStyle');
|
|
629
|
+
const _dts = DEFAULT_TEXT_STYLES.split('|');
|
|
630
|
+
for (let i = 0, len = _dts.length; i < len; i++) {
|
|
631
|
+
allUsedStyles.add(_dts[i]);
|
|
632
|
+
}
|
|
633
|
+
for (const _ts of Object.values(o.get('tagStyles'))) {
|
|
634
|
+
const _tss = _ts.split('|');
|
|
635
|
+
for (let i = 0, len = _tss.length; i < len; i++) {
|
|
636
|
+
allUsedStyles.add(_tss[i]);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
for (let i = 0, len = _ss.length; i < len; i++) {
|
|
640
|
+
allUsedStyles.add(_ss[i]);
|
|
641
|
+
}
|
|
642
|
+
for (let i = 0, len = _ls.length; i < len; i++) {
|
|
643
|
+
allUsedStyles.add(_ls[i]);
|
|
644
|
+
}
|
|
645
|
+
const _aus = (typeof options.allUsedStyles === 'string' ? options.allUsedStyles.split('|') : options.allUsedStyles) || [];
|
|
646
|
+
for (let i = 0, len = _aus.length; i < len; i++) {
|
|
647
|
+
allUsedStyles.add(_aus[i]);
|
|
648
|
+
}
|
|
649
|
+
o.set('allUsedStyles', allUsedStyles);
|
|
650
|
+
|
|
651
|
+
return {
|
|
652
|
+
o: o,
|
|
653
|
+
i: icons,
|
|
654
|
+
l: options.lang || _defaultLang,
|
|
655
|
+
v: (options.value = typeof options.value === 'string' ? options.value : null),
|
|
656
|
+
buttons: o.get('_rtl') ? buttonList.reverse() : buttonList,
|
|
657
|
+
subButtons: subButtons,
|
|
658
|
+
statusbarContainer: typeof options.statusbar_container === 'string' ? _d.querySelector(options.statusbar_container) : options.statusbar_container
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export function CreateStatusbar(targetOptions, statusbar) {
|
|
663
|
+
let navigation = null;
|
|
664
|
+
let charWrapper = null;
|
|
665
|
+
let charCounter = null;
|
|
666
|
+
|
|
667
|
+
if (targetOptions.get('statusbar')) {
|
|
668
|
+
statusbar = statusbar || domUtils.createElement('DIV', { class: 'se-status-bar sun-editor-common' });
|
|
669
|
+
|
|
670
|
+
/** navigation */
|
|
671
|
+
navigation = statusbar.querySelector('.se-navigation') || domUtils.createElement('DIV', { class: 'se-navigation sun-editor-common' });
|
|
672
|
+
statusbar.appendChild(navigation);
|
|
673
|
+
|
|
674
|
+
/** char counter */
|
|
675
|
+
if (targetOptions.get('charCounter')) {
|
|
676
|
+
charWrapper = statusbar.querySelector('.se-char-counter-wrapper') || domUtils.createElement('DIV', { class: 'se-char-counter-wrapper' });
|
|
677
|
+
|
|
678
|
+
if (targetOptions.get('charCounter_label')) {
|
|
679
|
+
const charLabel = charWrapper.querySelector('.se-char-label') || domUtils.createElement('SPAN', { class: 'se-char-label' });
|
|
680
|
+
charLabel.textContent = targetOptions.get('charCounter_label');
|
|
681
|
+
charWrapper.appendChild(charLabel);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
charCounter = charWrapper.querySelector('.se-char-counter') || domUtils.createElement('SPAN', { class: 'se-char-counter' });
|
|
685
|
+
charCounter.textContent = '0';
|
|
686
|
+
charWrapper.appendChild(charCounter);
|
|
687
|
+
|
|
688
|
+
if (targetOptions.get('charCounter_max') > 0) {
|
|
689
|
+
const char_max = charWrapper.querySelector('.se-char-max') || domUtils.createElement('SPAN', { class: 'se-char-max' });
|
|
690
|
+
char_max.textContent = ' / ' + targetOptions.get('charCounter_max');
|
|
691
|
+
charWrapper.appendChild(char_max);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
statusbar.appendChild(charWrapper);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return {
|
|
699
|
+
statusbar: statusbar,
|
|
700
|
+
navigation: navigation,
|
|
701
|
+
charWrapper: charWrapper,
|
|
702
|
+
charCounter: charCounter
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function InitFrameOptions(o, origin, fo) {
|
|
707
|
+
fo.set('_origin', o);
|
|
708
|
+
const barContainer = origin.statusbar_container;
|
|
709
|
+
|
|
710
|
+
// members
|
|
711
|
+
const value = o.value === undefined ? origin.value : o.value;
|
|
712
|
+
const placeholder = o.placeholder === undefined ? origin.placeholder : o.placeholder;
|
|
713
|
+
const editableFrameAttributes = o.editableFrameAttributes === undefined ? origin.editableFrameAttributes : o.editableFrameAttributes;
|
|
714
|
+
const width = o.width === undefined ? origin.width : o.width;
|
|
715
|
+
const minWidth = o.minWidth === undefined ? origin.minWidth : o.minWidth;
|
|
716
|
+
const maxWidth = o.maxWidth === undefined ? origin.maxWidth : o.maxWidth;
|
|
717
|
+
const height = o.height === undefined ? origin.height : o.height;
|
|
718
|
+
const minHeight = o.minHeight === undefined ? origin.minHeight : o.minHeight;
|
|
719
|
+
const maxHeight = o.maxHeight === undefined ? origin.maxHeight : o.maxHeight;
|
|
720
|
+
const editorStyle = o.editorStyle === undefined ? origin.editorStyle : o.editorStyle;
|
|
721
|
+
const iframe = o.iframe === undefined ? origin.iframe : o.iframe;
|
|
722
|
+
const iframe_fullPage = o.iframe_fullPage === undefined ? origin.iframe_fullPage : o.iframe_fullPage;
|
|
723
|
+
const iframe_attributes = o.iframe_attributes === undefined ? origin.iframe_attributes : o.iframe_attributes;
|
|
724
|
+
const iframe_cssFileName = o.iframe_cssFileName === undefined ? origin.iframe_cssFileName : o.iframe_cssFileName;
|
|
725
|
+
const statusbar = barContainer || o.statusbar === undefined ? origin.statusbar : o.statusbar;
|
|
726
|
+
const statusbar_showPathLabel = barContainer || o.statusbar_showPathLabel === undefined ? origin.statusbar_showPathLabel : o.statusbar_showPathLabel;
|
|
727
|
+
const statusbar_resizeEnable = barContainer ? false : o.statusbar_resizeEnable === undefined ? origin.statusbar_resizeEnable : o.statusbar_resizeEnable;
|
|
728
|
+
const charCounter = barContainer || o.charCounter === undefined ? origin.charCounter : o.charCounter;
|
|
729
|
+
const charCounter_max = barContainer || o.charCounter_max === undefined ? origin.charCounter_max : o.charCounter_max;
|
|
730
|
+
const charCounter_label = barContainer || o.charCounter_label === undefined ? origin.charCounter_label : o.charCounter_label;
|
|
731
|
+
const charCounter_type = barContainer || o.charCounter_type === undefined ? origin.charCounter_type : o.charCounter_type;
|
|
732
|
+
|
|
733
|
+
// value
|
|
734
|
+
fo.set('value', value);
|
|
735
|
+
fo.set('placeholder', placeholder);
|
|
736
|
+
fo.set('editableFrameAttributes', editableFrameAttributes || {});
|
|
737
|
+
// styles
|
|
738
|
+
fo.set('width', width ? (numbers.is(width) ? width + 'px' : width) : '100%');
|
|
739
|
+
fo.set('minWidth', (numbers.is(minWidth) ? minWidth + 'px' : minWidth) || '');
|
|
740
|
+
fo.set('maxWidth', (numbers.is(maxWidth) ? maxWidth + 'px' : maxWidth) || '');
|
|
741
|
+
fo.set('height', height ? (numbers.is(height) ? height + 'px' : height) : 'auto');
|
|
742
|
+
fo.set('minHeight', (numbers.is(minHeight) ? minHeight + 'px' : minHeight) || '');
|
|
743
|
+
fo.set('maxHeight', (numbers.is(maxHeight) ? maxHeight + 'px' : maxHeight) || '');
|
|
744
|
+
fo.set('_defaultStyles', converter._setDefaultOptionStyle(fo, typeof editorStyle === 'string' ? editorStyle : ''));
|
|
745
|
+
// iframe
|
|
746
|
+
fo.set('iframe', !!(iframe_fullPage || iframe));
|
|
747
|
+
fo.set('iframe_fullPage', !!iframe_fullPage);
|
|
748
|
+
fo.set('iframe_attributes', iframe_attributes || {});
|
|
749
|
+
fo.set('iframe_cssFileName', iframe ? (typeof iframe_cssFileName === 'string' ? [iframe_cssFileName] : iframe_cssFileName || ['suneditor']) : null);
|
|
750
|
+
// status bar
|
|
751
|
+
const hasStatusbar = statusbar === undefined ? true : !!statusbar;
|
|
752
|
+
fo.set('statusbar', hasStatusbar);
|
|
753
|
+
fo.set('statusbar_showPathLabel', !hasStatusbar ? false : typeof statusbar_showPathLabel === 'boolean' ? statusbar_showPathLabel : true);
|
|
754
|
+
fo.set('statusbar_resizeEnable', !hasStatusbar ? false : statusbar_resizeEnable === undefined ? true : !!statusbar_resizeEnable);
|
|
755
|
+
// status bar - character count
|
|
756
|
+
fo.set('charCounter', charCounter_max > 0 ? true : typeof charCounter === 'boolean' ? charCounter : false);
|
|
757
|
+
fo.set('charCounter_max', numbers.is(charCounter_max) && charCounter_max > -1 ? charCounter_max * 1 : null);
|
|
758
|
+
fo.set('charCounter_label', typeof charCounter_label === 'string' ? charCounter_label.trim() : null);
|
|
759
|
+
fo.set('charCounter_type', typeof charCounter_type === 'string' ? charCounter_type : 'char');
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* @description Initialize property of suneditor elements
|
|
764
|
+
* @param {string} key Key
|
|
765
|
+
* @param {Object} options Options
|
|
766
|
+
* @param {Element} topDiv Suneditor top div
|
|
767
|
+
* @returns {Object} Bottom bar elements (statusbar, navigation, charWrapper, charCounter)
|
|
768
|
+
*/
|
|
769
|
+
function _initTargetElements(key, options, topDiv, targetOptions) {
|
|
770
|
+
const editorStyles = targetOptions.get('_defaultStyles');
|
|
771
|
+
/** top div */
|
|
772
|
+
topDiv.style.cssText = editorStyles.top;
|
|
773
|
+
|
|
774
|
+
/** editor */
|
|
775
|
+
// wysiwyg div or iframe
|
|
776
|
+
const wysiwygDiv = domUtils.createElement(!targetOptions.get('iframe') ? 'DIV' : 'IFRAME', {
|
|
777
|
+
class: 'se-wrapper-inner se-wrapper-wysiwyg',
|
|
778
|
+
'data-root-key': key
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
if (!targetOptions.get('iframe')) {
|
|
782
|
+
wysiwygDiv.setAttribute('contenteditable', true);
|
|
783
|
+
wysiwygDiv.setAttribute('scrolling', 'auto');
|
|
784
|
+
wysiwygDiv.className += ' ' + options.get('_editableClass');
|
|
785
|
+
wysiwygDiv.style.cssText = editorStyles.frame + editorStyles.editor;
|
|
786
|
+
} else {
|
|
787
|
+
const frameAttrs = targetOptions.get('iframe_attributes');
|
|
788
|
+
for (const frameKey in frameAttrs) {
|
|
789
|
+
wysiwygDiv.setAttribute(frameKey, frameAttrs[frameKey]);
|
|
790
|
+
}
|
|
791
|
+
wysiwygDiv.allowFullscreen = true;
|
|
792
|
+
wysiwygDiv.frameBorder = 0;
|
|
793
|
+
wysiwygDiv.style.cssText = editorStyles.frame;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// textarea for code view
|
|
797
|
+
const textarea = domUtils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
|
|
798
|
+
let placeholder = null;
|
|
799
|
+
if (targetOptions.get('placeholder')) {
|
|
800
|
+
placeholder = domUtils.createElement('SPAN', { class: 'se-placeholder' });
|
|
801
|
+
placeholder.innerText = targetOptions.get('placeholder');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return {
|
|
805
|
+
bottomBar: CreateStatusbar(targetOptions, null),
|
|
806
|
+
wysiwygFrame: wysiwygDiv,
|
|
807
|
+
codeView: textarea,
|
|
808
|
+
placeholder: placeholder
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* @description Check the CodeMirror option to apply the CodeMirror and return the CodeMirror element.
|
|
814
|
+
* @param {Object} options options
|
|
815
|
+
* @param {Element} textarea textarea element
|
|
816
|
+
*/
|
|
817
|
+
function _checkCodeMirror(options, targetOptions, textarea) {
|
|
818
|
+
let cmeditor = null;
|
|
819
|
+
let hasCodeMirror = false;
|
|
820
|
+
|
|
821
|
+
if (options.get('codeMirror6Editor')) {
|
|
822
|
+
const codeMirror = options.get('codeMirror');
|
|
823
|
+
const codeStyles = textarea.style.cssText;
|
|
824
|
+
const cm = new codeMirror.EditorView({
|
|
825
|
+
parent: textarea.parentElement,
|
|
826
|
+
extensions: codeMirror.extensions,
|
|
827
|
+
state: codeMirror.state
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
targetOptions.set('codeMirror6Editor', cm);
|
|
831
|
+
cmeditor = cm.dom;
|
|
832
|
+
cmeditor.style.cssText = codeStyles;
|
|
833
|
+
hasCodeMirror = true;
|
|
834
|
+
} else if (options.get('codeMirror5Editor')) {
|
|
835
|
+
const codeMirror = options.get('codeMirror');
|
|
836
|
+
const cmOptions = [
|
|
837
|
+
{
|
|
838
|
+
mode: 'htmlmixed',
|
|
839
|
+
htmlMode: true,
|
|
840
|
+
lineNumbers: true,
|
|
841
|
+
lineWrapping: true
|
|
842
|
+
},
|
|
843
|
+
codeMirror.options || {}
|
|
844
|
+
].reduce((init, option) => {
|
|
845
|
+
for (const key in option) {
|
|
846
|
+
init[key] = option[key];
|
|
847
|
+
}
|
|
848
|
+
return init;
|
|
849
|
+
}, {});
|
|
850
|
+
|
|
851
|
+
if (targetOptions.get('height') === 'auto') {
|
|
852
|
+
cmOptions.viewportMargin = Infinity;
|
|
853
|
+
cmOptions.height = 'auto';
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const codeStyles = textarea.style.cssText;
|
|
857
|
+
const cm = codeMirror.src.fromTextArea(textarea, cmOptions);
|
|
858
|
+
targetOptions.set('codeMirror5Editor', cm);
|
|
859
|
+
cmeditor = cm.display.wrapper;
|
|
860
|
+
cmeditor.style.cssText = codeStyles;
|
|
861
|
+
hasCodeMirror = true;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
options.set('hasCodeMirror', hasCodeMirror);
|
|
865
|
+
if (cmeditor) {
|
|
866
|
+
domUtils.removeItem(textarea);
|
|
867
|
+
cmeditor.className += ' se-code-viewer-mirror';
|
|
868
|
+
return cmeditor;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return textarea;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* @description create blacklist
|
|
876
|
+
* @param {string} blacklist blacklist
|
|
877
|
+
* @param {string} defaultLine options.get('defaultLine')
|
|
878
|
+
* @returns {string}
|
|
879
|
+
*/
|
|
880
|
+
function _createBlacklist(blacklist, defaultLine) {
|
|
881
|
+
defaultLine = defaultLine.toLowerCase();
|
|
882
|
+
return blacklist
|
|
883
|
+
.split('|')
|
|
884
|
+
.filter(function (v) {
|
|
885
|
+
if (v !== defaultLine) {
|
|
886
|
+
return true;
|
|
887
|
+
} else {
|
|
888
|
+
console.warn(`[SUNEDITOR.constructor.createBlacklist.warn] defaultLine("<${defaultLine}>") cannot be included in the blacklist and will be removed.`);
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
})
|
|
892
|
+
.join('|');
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* @description create formats regexp object.
|
|
897
|
+
* @param {string} value value
|
|
898
|
+
* @param {string} defaultValue default value
|
|
899
|
+
* @param {string} blacklist blacklist
|
|
900
|
+
* @returns {{reg: RegExp, str: string}}
|
|
901
|
+
*/
|
|
902
|
+
function _createFormatInfo(value, defaultValue, blacklist) {
|
|
903
|
+
const blist = blacklist.split('|');
|
|
904
|
+
const str = (defaultValue + '|' + (typeof value === 'string' ? value.toLowerCase() : ''))
|
|
905
|
+
.replace(/^\||\|$/g, '')
|
|
906
|
+
.split('|')
|
|
907
|
+
.filter((v) => v && !blist.includes(v))
|
|
908
|
+
.join('|');
|
|
909
|
+
return {
|
|
910
|
+
reg: new RegExp(`^(${str})$`, 'i'),
|
|
911
|
+
str: str
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* @description create whitelist or blacklist.
|
|
917
|
+
* @param {Object} o options
|
|
918
|
+
* @returns {string} whitelist
|
|
919
|
+
*/
|
|
920
|
+
function _createWhitelist(o) {
|
|
921
|
+
const blacklist = o.get('elementBlacklist').split('|');
|
|
922
|
+
const whitelist = (o.get('__defaultElementWhitelist') + '|' + o.get('elementWhitelist') + '|' + o.get('formatLine').str + '|' + o.get('formatBrLine').str + '|' + o.get('formatClosureBlock').str + '|' + o.get('formatClosureBrLine').str)
|
|
923
|
+
.replace(/(^\||\|$)/g, '')
|
|
924
|
+
.split('|')
|
|
925
|
+
.filter((v, i, a) => v && a.indexOf(v) === i && !blacklist.includes(v));
|
|
926
|
+
|
|
927
|
+
return whitelist.join('|');
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* @description Suneditor's Default button list
|
|
932
|
+
* @param {Object} options options
|
|
933
|
+
*/
|
|
934
|
+
function _defaultButtons(options, icons, lang) {
|
|
935
|
+
const isRTL = options.get('_rtl');
|
|
936
|
+
return {
|
|
937
|
+
bold: ['', lang.bold, 'bold', '', icons.bold],
|
|
938
|
+
underline: ['', lang.underline, 'underline', '', icons.underline],
|
|
939
|
+
italic: ['', lang.italic, 'italic', '', icons.italic],
|
|
940
|
+
strike: ['', lang.strike, 'strike', '', icons.strike],
|
|
941
|
+
subscript: ['', lang.subscript, 'subscript', '', icons.subscript],
|
|
942
|
+
superscript: ['', lang.superscript, 'superscript', '', icons.superscript],
|
|
943
|
+
removeFormat: ['', lang.removeFormat, 'removeFormat', '', icons.remove_format],
|
|
944
|
+
indent: ['se-icon-flip-rtl', lang.indent, 'indent', '', isRTL ? icons.outdent : icons.indent],
|
|
945
|
+
outdent: ['se-icon-flip-rtl', lang.outdent, 'outdent', '', isRTL ? icons.indent : icons.outdent],
|
|
946
|
+
fullScreen: ['se-code-view-enabled se-component-enabled', lang.fullScreen, 'fullScreen', '', icons.expansion],
|
|
947
|
+
showBlocks: ['', lang.showBlocks, 'showBlocks', '', icons.show_blocks],
|
|
948
|
+
codeView: ['se-code-view-enabled se-component-enabled', lang.codeView, 'codeView', '', icons.code_view],
|
|
949
|
+
undo: ['se-component-enabled', lang.undo, 'undo', '', icons.undo],
|
|
950
|
+
redo: ['se-component-enabled', lang.redo, 'redo', '', icons.redo],
|
|
951
|
+
preview: ['se-component-enabled', lang.preview, 'preview', '', icons.preview],
|
|
952
|
+
print: ['se-component-enabled', lang.print, 'print', '', icons.print],
|
|
953
|
+
dir: ['', lang[isRTL ? 'dir_ltr' : 'dir_rtl'], 'dir', '', icons[isRTL ? 'dir_ltr' : 'dir_rtl']],
|
|
954
|
+
dir_ltr: ['', lang.dir_ltr, 'dir_ltr', '', icons.dir_ltr],
|
|
955
|
+
dir_rtl: ['', lang.dir_rtl, 'dir_rtl', '', icons.dir_rtl],
|
|
956
|
+
save: ['se-component-enabled', lang.save, 'save', '', icons.save],
|
|
957
|
+
newDocument: ['se-component-enabled', lang.newDocument, 'newDocument', '', icons.new_document],
|
|
958
|
+
selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all]
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* @description Create a group div containing each module
|
|
964
|
+
* @returns {Object}
|
|
965
|
+
*/
|
|
966
|
+
function _createModuleGroup() {
|
|
967
|
+
const oUl = domUtils.createElement('UL', { class: 'se-menu-list' });
|
|
968
|
+
const oDiv = domUtils.createElement('DIV', { class: 'se-btn-module se-btn-module-border' }, oUl);
|
|
969
|
+
|
|
970
|
+
return {
|
|
971
|
+
div: oDiv,
|
|
972
|
+
ul: oUl
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* @description Create a button element
|
|
978
|
+
* @param {string} className className in button
|
|
979
|
+
* @param {string} title Title in button
|
|
980
|
+
* @param {string} dataCommand The data-command property of the button
|
|
981
|
+
* @param {string} dataType The data-type property of the button ('modal', 'dropdown', 'command', 'container')
|
|
982
|
+
* @param {string} innerHTML Html in button
|
|
983
|
+
* @param {string} _disabled Button disabled
|
|
984
|
+
* @param {Object} icons Icons
|
|
985
|
+
* @returns {Object}
|
|
986
|
+
*/
|
|
987
|
+
function _createButton(className, title, dataCommand, dataType, innerHTML, _disabled, icons) {
|
|
988
|
+
const oLi = domUtils.createElement('LI');
|
|
989
|
+
const label = title || '';
|
|
990
|
+
const oButton = domUtils.createElement(/^INPUT|FIELD$/i.test(dataType) ? 'DIV' : 'BUTTON', {
|
|
991
|
+
type: 'button',
|
|
992
|
+
class: 'se-toolbar-btn se-btn se-tooltip' + (className ? ' ' + className : ''),
|
|
993
|
+
'data-command': dataCommand,
|
|
994
|
+
'data-type': dataType,
|
|
995
|
+
'aria-label': label.replace(/<span .+<\/span>/, ''),
|
|
996
|
+
tabindex: '-1'
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
if (/^default\./i.test(innerHTML)) {
|
|
1000
|
+
innerHTML = icons[innerHTML.replace(/^default\./i, '')];
|
|
1001
|
+
}
|
|
1002
|
+
if (/^text\./i.test(innerHTML)) {
|
|
1003
|
+
innerHTML = innerHTML.replace(/^text\./i, '');
|
|
1004
|
+
oButton.className += ' se-btn-more-text';
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (_disabled) oButton.setAttribute('disabled', true);
|
|
1008
|
+
|
|
1009
|
+
if (/^FIELD$/i.test(dataType)) domUtils.addClass(oLi, 'se-toolbar-hidden-btn');
|
|
1010
|
+
|
|
1011
|
+
if (label) innerHTML += CreateTooltipInner(label);
|
|
1012
|
+
if (innerHTML) oButton.innerHTML = innerHTML;
|
|
1013
|
+
|
|
1014
|
+
oLi.appendChild(oButton);
|
|
1015
|
+
|
|
1016
|
+
return {
|
|
1017
|
+
li: oLi,
|
|
1018
|
+
button: oButton
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
export function CreateTooltipInner(text) {
|
|
1023
|
+
return `<span class="se-tooltip-inner"><span class="se-tooltip-text">${text}</span></span>`;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
export function UpdateButton(element, plugin, icons, lang) {
|
|
1027
|
+
if (!element) return;
|
|
1028
|
+
|
|
1029
|
+
const noneInner = plugin.inner === false;
|
|
1030
|
+
|
|
1031
|
+
element.innerHTML = noneInner
|
|
1032
|
+
? ''
|
|
1033
|
+
: (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>';
|
|
1034
|
+
|
|
1035
|
+
element.setAttribute('aria-label', plugin.title);
|
|
1036
|
+
|
|
1037
|
+
if (plugin.type) {
|
|
1038
|
+
element.setAttribute('data-type', plugin.type);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (plugin.className) {
|
|
1042
|
+
element.className += ' ' + plugin.className;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// side, replace button
|
|
1046
|
+
if (plugin.afterButton) {
|
|
1047
|
+
domUtils.addClass(plugin.afterButton, 'se-toolbar-btn');
|
|
1048
|
+
element.parentElement.appendChild(plugin.afterButton);
|
|
1049
|
+
|
|
1050
|
+
domUtils.addClass(element, 'se-side-btn-a');
|
|
1051
|
+
domUtils.addClass(plugin.afterButton, 'se-side-btn-after');
|
|
1052
|
+
}
|
|
1053
|
+
if (plugin.beforeButton) {
|
|
1054
|
+
domUtils.addClass(plugin.beforeButton, 'se-toolbar-btn');
|
|
1055
|
+
element.parentElement.insertBefore(plugin.beforeButton, element);
|
|
1056
|
+
|
|
1057
|
+
if (plugin.afterButton) {
|
|
1058
|
+
domUtils.addClass(element, 'se-side-btn');
|
|
1059
|
+
domUtils.removeClass(element, 'se-side-btn-a');
|
|
1060
|
+
} else {
|
|
1061
|
+
domUtils.addClass(element, 'se-side-btn-b');
|
|
1062
|
+
}
|
|
1063
|
+
domUtils.addClass(plugin.beforeButton, 'se-side-btn-before');
|
|
1064
|
+
}
|
|
1065
|
+
if (plugin.replaceButton) {
|
|
1066
|
+
element.parentElement.appendChild(plugin.replaceButton);
|
|
1067
|
+
element.style.display = 'none';
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
if (!plugin.replaceButton && /^INPUT$/i.test(element.getAttribute('data-type'))) {
|
|
1071
|
+
const inputTarget = element.querySelector('input');
|
|
1072
|
+
if (inputTarget) {
|
|
1073
|
+
domUtils.addClass(inputTarget, 'se-toolbar-btn');
|
|
1074
|
+
inputTarget.setAttribute('data-command', element.getAttribute('data-command'));
|
|
1075
|
+
inputTarget.setAttribute('data-type', element.getAttribute('data-type'));
|
|
1076
|
+
if (element.hasAttribute('disabled')) inputTarget.setAttribute('disabled', true);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* @description Create editor HTML
|
|
1083
|
+
* @param {Array} buttonList option.buttonList
|
|
1084
|
+
* @param {Object|null} plugins Plugins
|
|
1085
|
+
* @param {Array} options options
|
|
1086
|
+
* @param {Object} icons icons
|
|
1087
|
+
* @param {Object} lang lang
|
|
1088
|
+
* @param {boolean} isUpdate Is update
|
|
1089
|
+
* @returns {Object} { element: (Element) Toolbar element, plugins: (Array|null) Plugins Array, pluginCallButtons: (Object), responsiveButtons: (Array) }
|
|
1090
|
+
*/
|
|
1091
|
+
export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdate) {
|
|
1092
|
+
/** create button list */
|
|
1093
|
+
buttonList = JSON.parse(JSON.stringify(buttonList));
|
|
1094
|
+
const defaultButtonList = _defaultButtons(options, icons, lang);
|
|
1095
|
+
const pluginCallButtons = {};
|
|
1096
|
+
const responsiveButtons = [];
|
|
1097
|
+
const updateButtons = [];
|
|
1098
|
+
|
|
1099
|
+
let modules = null;
|
|
1100
|
+
let button = null;
|
|
1101
|
+
let plugin = null;
|
|
1102
|
+
let moduleElement = null;
|
|
1103
|
+
let buttonElement = null;
|
|
1104
|
+
let vertical = false;
|
|
1105
|
+
const moreLayer = domUtils.createElement('DIV', { class: 'se-toolbar-more-layer' });
|
|
1106
|
+
const buttonTray = domUtils.createElement('DIV', { class: 'se-btn-tray' });
|
|
1107
|
+
const separator_vertical = domUtils.createElement('DIV', { class: 'se-toolbar-separator-vertical' });
|
|
1108
|
+
|
|
1109
|
+
buttonGroupLoop: for (let i = 0, more, moreContainer, moreCommand, buttonGroup, align; i < buttonList.length; i++) {
|
|
1110
|
+
more = false;
|
|
1111
|
+
align = '';
|
|
1112
|
+
buttonGroup = buttonList[i];
|
|
1113
|
+
moduleElement = _createModuleGroup();
|
|
1114
|
+
|
|
1115
|
+
// button object
|
|
1116
|
+
if (typeof buttonGroup === 'object') {
|
|
1117
|
+
// buttons loop
|
|
1118
|
+
for (let j = 0, moreButton; j < buttonGroup.length; j++) {
|
|
1119
|
+
button = buttonGroup[j];
|
|
1120
|
+
moreButton = false;
|
|
1121
|
+
plugin = plugins[button];
|
|
1122
|
+
|
|
1123
|
+
if (/^%\d+/.test(button) && j === 0) {
|
|
1124
|
+
buttonGroup[0] = button.replace(/[^\d]/g, '');
|
|
1125
|
+
responsiveButtons.push(buttonGroup);
|
|
1126
|
+
buttonList.splice(i--, 1);
|
|
1127
|
+
continue buttonGroupLoop;
|
|
1128
|
+
}
|
|
1129
|
+
if (typeof plugin === 'function') {
|
|
1130
|
+
modules = [plugin.className, plugin.title, button, plugin.type, plugin.innerHTML, plugin._disabled];
|
|
1131
|
+
} else if (typeof plugin === 'object') {
|
|
1132
|
+
const originFnc = plugin.constructor;
|
|
1133
|
+
modules = [plugin.className || originFnc.className, plugin.title || originFnc.title, button, plugin.type || originFnc.type, plugin.innerHTML || originFnc.innerHTML, plugin._disabled || originFnc._disabled];
|
|
1134
|
+
} else {
|
|
1135
|
+
// align
|
|
1136
|
+
if (/^-/.test(button)) {
|
|
1137
|
+
align = button.substr(1);
|
|
1138
|
+
moduleElement.div.className += ' module-float-' + align;
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// rtl fix
|
|
1143
|
+
if (/^#/.test(button)) {
|
|
1144
|
+
const option = button.substr(1);
|
|
1145
|
+
if (option === 'fix') moduleElement.ul.className += ' se-menu-dir-fix';
|
|
1146
|
+
continue;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// more button
|
|
1150
|
+
if (/^:/.test(button)) {
|
|
1151
|
+
moreButton = true;
|
|
1152
|
+
const matched = button.match(/^:([^-]+)-([^-]+)/);
|
|
1153
|
+
moreCommand = '__se__more_' + i;
|
|
1154
|
+
const title = matched[1].trim();
|
|
1155
|
+
const innerHTML = matched[2].trim();
|
|
1156
|
+
modules = ['se-btn-more', /^lang\./i.test(title) ? lang[title.replace(/^lang\./i, '')] : title, moreCommand, 'MORE', innerHTML];
|
|
1157
|
+
} else {
|
|
1158
|
+
// default command
|
|
1159
|
+
modules = defaultButtonList[button];
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
if (!modules) {
|
|
1163
|
+
if (!plugin) throw Error(`[SUNEDITOR.create.toolbar.fail] The button name of a plugin that does not exist. [${button}]`);
|
|
1164
|
+
plugin = typeof plugin === 'object' ? plugin.constructor : plugin;
|
|
1165
|
+
modules = [plugin.className, plugin.title, plugin.key, plugin.type, plugin.innerHTML, plugin._disabled];
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
buttonElement = _createButton(modules[0], modules[1], modules[2], modules[3], modules[4], modules[5], icons);
|
|
1170
|
+
(more ? moreContainer : moduleElement.ul).appendChild(buttonElement.li);
|
|
1171
|
+
|
|
1172
|
+
if (plugin) {
|
|
1173
|
+
if (pluginCallButtons[button]) {
|
|
1174
|
+
pluginCallButtons[button].push(buttonElement.button);
|
|
1175
|
+
} else {
|
|
1176
|
+
pluginCallButtons[button] = [buttonElement.button];
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
if (isUpdate) {
|
|
1180
|
+
updateButtons.push({ button: buttonElement.button, plugin, key: button });
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// more button
|
|
1185
|
+
if (moreButton) {
|
|
1186
|
+
more = true;
|
|
1187
|
+
moreContainer = domUtils.createElement('DIV');
|
|
1188
|
+
moreContainer.className = 'se-more-layer ' + moreCommand;
|
|
1189
|
+
moreContainer.setAttribute('data-ref', moreCommand);
|
|
1190
|
+
moreContainer.innerHTML = '<div class="se-more-form"><ul class="se-menu-list"' + (align ? ' style="float: ' + align + ';"' : '') + '></ul></div>';
|
|
1191
|
+
moreLayer.appendChild(moreContainer);
|
|
1192
|
+
moreContainer = moreContainer.firstElementChild.firstElementChild;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
if (vertical) {
|
|
1197
|
+
const sv = separator_vertical.cloneNode(false);
|
|
1198
|
+
buttonTray.appendChild(sv);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
buttonTray.appendChild(moduleElement.div);
|
|
1202
|
+
vertical = true;
|
|
1203
|
+
} else if (/^\/$/.test(buttonGroup)) {
|
|
1204
|
+
/** line break */
|
|
1205
|
+
const enterDiv = domUtils.createElement('DIV', { class: 'se-btn-module-enter' });
|
|
1206
|
+
buttonTray.appendChild(enterDiv);
|
|
1207
|
+
vertical = false;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
switch (buttonTray.children.length) {
|
|
1212
|
+
case 0:
|
|
1213
|
+
buttonTray.style.display = 'none';
|
|
1214
|
+
break;
|
|
1215
|
+
case 1:
|
|
1216
|
+
domUtils.removeClass(buttonTray.firstElementChild, 'se-btn-module-border');
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
if (moreLayer.children.length > 0) buttonTray.appendChild(moreLayer);
|
|
1221
|
+
if (responsiveButtons.length > 0) responsiveButtons.unshift(buttonList);
|
|
1222
|
+
|
|
1223
|
+
// rendering toolbar
|
|
1224
|
+
const tool_bar = domUtils.createElement('DIV', { class: 'se-toolbar sun-editor-common' + (!options.get('shortcutsHint') ? ' se-shortcut-hide' : '') }, buttonTray);
|
|
1225
|
+
|
|
1226
|
+
if (options.get('toolbar_hide')) tool_bar.style.display = 'none';
|
|
1227
|
+
|
|
1228
|
+
return {
|
|
1229
|
+
element: tool_bar,
|
|
1230
|
+
pluginCallButtons,
|
|
1231
|
+
responsiveButtons,
|
|
1232
|
+
buttonTray,
|
|
1233
|
+
updateButtons
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
export default Constructor;
|