suneditor 2.46.2 → 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.
Files changed (290) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +174 -805
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +96 -69
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-content.css +646 -0
  11. package/src/assets/suneditor.css +3378 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  17. package/src/core/base/eventManager.js +1115 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +146 -0
  21. package/src/core/class/component.js +627 -0
  22. package/src/core/class/format.js +3255 -0
  23. package/src/core/class/html.js +1621 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +379 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +578 -0
  28. package/src/core/class/selection.js +508 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1593 -0
  33. package/src/core/section/actives.js +107 -0
  34. package/src/core/section/constructor.js +1237 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +313 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +199 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +162 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +315 -0
  72. package/src/modules/Figure.js +1160 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +290 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +73 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +73 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +172 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +510 -0
  104. package/src/plugins/modal/image.js +1062 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +347 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /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;