suneditor 2.46.2 → 3.0.0-alpha.10

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