suneditor 2.46.1 → 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -70
  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,1593 @@
1
+ import { env, converter, domUtils, numbers } from '../helper';
2
+ import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, RO_UNAVAILABD } from './section/constructor';
3
+ import { UpdateStatusbarContext } from './section/context';
4
+ import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, FONT_STYLE } from './section/actives';
5
+ import History from './base/history';
6
+ import EventManager from './base/eventManager';
7
+ import Events from './base/events';
8
+
9
+ // class injector
10
+ import ClassInjector from '../editorInjector/_classes';
11
+
12
+ // classes
13
+ import Char from './class/char';
14
+ import Component from './class/component';
15
+ import Format from './class/format';
16
+ import HTML from './class/html';
17
+ import Menu from './class/menu';
18
+ import NodeTransform from './class/nodeTransform';
19
+ import Notice from './class/notice';
20
+ import Offset from './class/offset';
21
+ import Selection from './class/selection';
22
+ import Shortcuts from './class/shortcuts';
23
+ import Toolbar from './class/toolbar';
24
+ import Viewer from './class/viewer';
25
+
26
+ const COMMAND_BUTTONS = '.se-menu-list .se-toolbar-btn[data-command]';
27
+ const DISABLE_BUTTONS_CODEVIEW = `${COMMAND_BUTTONS}:not([class~="se-code-view-enabled"]):not([data-type="MORE"])`;
28
+ const DISABLE_BUTTONS_CONTROLLER = `${COMMAND_BUTTONS}:not([class~="se-component-enabled"]):not([data-type="MORE"])`;
29
+
30
+ /**
31
+ * @description SunEditor constructor function.
32
+ * @param {Array.<Element>} multiTargets Target textarea
33
+ * @param {Object} options options
34
+ * @returns {Object}
35
+ */
36
+ const Editor = function (multiTargets, options) {
37
+ const _d = multiTargets[0].target.ownerDocument || env._d;
38
+ const _w = _d.defaultView || env._w;
39
+ const product = Constructor(multiTargets, options);
40
+
41
+ // properties
42
+ this.rootKeys = product.rootKeys;
43
+ this.frameRoots = product.frameRoots;
44
+ this.context = product.context;
45
+ this.frameContext = new Map();
46
+ this.frameOptions = new Map();
47
+ this._lineBreaker_t = null;
48
+ this._lineBreaker_b = null;
49
+
50
+ /**
51
+ * @description Document object
52
+ * @type {Document}
53
+ */
54
+ this._d = _d;
55
+
56
+ /**
57
+ * @description Window object
58
+ * @type {Window}
59
+ */
60
+ this._w = _w;
61
+
62
+ /**
63
+ * @description Controllers carrier
64
+ */
65
+ this.carrierWrapper = product.carrierWrapper;
66
+
67
+ /**
68
+ * @description Editor options
69
+ * @type {Object.<string, any>}
70
+ */
71
+ this.options = product.options;
72
+
73
+ /**
74
+ * @description Plugins
75
+ * @type {Object.<string, any>}
76
+ */
77
+ this.plugins = product.plugins || {};
78
+
79
+ /**
80
+ * @description Events object, call by triggerEvent function
81
+ * @type {Object.<string, any>}
82
+ */
83
+ this.events = null;
84
+
85
+ /**
86
+ * @description Call the event function by injecting self: this.
87
+ * @type {Function}
88
+ */
89
+ this.triggerEvent = null;
90
+
91
+ /**
92
+ * @description Default icons object
93
+ * @type {Object.<string, string>}
94
+ */
95
+ this.icons = product.icons;
96
+
97
+ /**
98
+ * @description loaded language
99
+ * @type {Object.<string, any>}
100
+ */
101
+ this.lang = product.lang;
102
+
103
+ /**
104
+ * @description Variables used internally in editor operation
105
+ * @property {boolean} hasFocus Boolean value of whether the editor has focus
106
+ * @property {number} tabSize Indent size of tab (4)
107
+ * @property {number} indentSize Indent size (25)px
108
+ * @property {number} codeIndentSize Indent size of Code view mode (2)
109
+ * @property {Array} currentNodes An element array of the current cursor's node structure
110
+ * @property {Array} currentNodesMap An element name array of the current cursor's node structure
111
+ * @property {number} rootKey Current root key
112
+ */
113
+ this.status = {
114
+ hasFocus: false,
115
+ tabSize: 4,
116
+ indentSize: 25,
117
+ codeIndentSize: 2,
118
+ currentNodes: [],
119
+ currentNodesMap: [],
120
+ rootKey: product.rootId,
121
+ _range: null
122
+ };
123
+
124
+ /**
125
+ * @description Is classic mode?
126
+ */
127
+ this.isClassic = null;
128
+
129
+ /**
130
+ * @description Is inline mode?
131
+ */
132
+ this.isInline = null;
133
+
134
+ /**
135
+ * @description Is balloon|balloon-always mode?
136
+ */
137
+ this.isBalloon = null;
138
+
139
+ /**
140
+ * @description Is balloon-always mode?
141
+ */
142
+ this.isBalloonAlways = null;
143
+
144
+ /**
145
+ * @description Is subToolbar balloon|balloon-always mode?
146
+ */
147
+ this.isSubBalloon = null;
148
+
149
+ /**
150
+ * @description Is subToolbar balloon-always mode?
151
+ */
152
+ this.isSubBalloonAlways = null;
153
+
154
+ // ----- Properties not shared with _core -----
155
+ /**
156
+ * @description All command buttons map
157
+ */
158
+ this.allCommandButtons = new Map();
159
+ this.subAllCommandButtons = new Map();
160
+
161
+ /**
162
+ * @description Shoutcuts key map
163
+ */
164
+ this.shortcutsKeyMap = new Map();
165
+ this.reverseKeys = [];
166
+
167
+ /**
168
+ * @description A map with the plugin's buttons having an "active" method and the default command buttons with an "active" action.
169
+ * Each button is contained in an array.
170
+ */
171
+ this.commandTargets = new Map();
172
+
173
+ /**
174
+ * @description Plugins array with "active" method.
175
+ * "activeCommands" runs the "add" method when creating the editor.
176
+ */
177
+ this.activeCommands = null;
178
+
179
+ /**
180
+ * @description The selection node (selection.getNode()) to which the effect was last applied
181
+ */
182
+ this.effectNode = null;
183
+
184
+ // ------------------------------------------------------- private properties -------------------------------------------------------
185
+ /**
186
+ * @description Closest ShadowRoot to editor if found
187
+ * @type {ShadowRoot}
188
+ * @private
189
+ */
190
+ this._shadowRoot = null;
191
+
192
+ /**
193
+ * @description Plugin call event map
194
+ * @private
195
+ */
196
+ this._onPluginEvents = null;
197
+
198
+ /**
199
+ * @description Controller, modal relative
200
+ * @private
201
+ */
202
+ this.opendModal = null;
203
+ this.opendControllers = [];
204
+ this.currentControllerName = '';
205
+ this._controllerTargetContext = null;
206
+ this.selectMenuOn = false;
207
+ this._backWrapper = product.carrierWrapper.querySelector('.se-back-wrapper');
208
+
209
+ this._controllerOnDisabledButtons = [];
210
+ this._codeViewDisabledButtons = [];
211
+
212
+ /**
213
+ * @description Button List in Responsive Toolbar.
214
+ * @private
215
+ */
216
+ this._pluginCallButtons = product.pluginCallButtons;
217
+ this._pluginCallButtons_sub = product.pluginCallButtons_sub;
218
+ this._responsiveButtons = product.responsiveButtons;
219
+ this._responsiveButtons_sub = product.responsiveButtons_sub;
220
+
221
+ /**
222
+ * @description Variable that controls the "blur" event in the editor of inline or balloon mode when the focus is moved to dropdown
223
+ * @private
224
+ */
225
+ this._notHideToolbar = false;
226
+
227
+ /**
228
+ * @description Variables for controlling focus and blur events
229
+ * @private
230
+ */
231
+ this._antiBlur = false;
232
+
233
+ /**
234
+ * @description If true, (initialize, reset) all indexes of image, video information
235
+ * @private
236
+ */
237
+ this._componentsInfoInit = true;
238
+ this._componentsInfoReset = false;
239
+
240
+ /**
241
+ * @description plugin retainFormat info Map()
242
+ * @private
243
+ */
244
+ this._MELInfo = null;
245
+
246
+ /**
247
+ * @description Properties for managing files in the "FileManager" module
248
+ * @private
249
+ */
250
+ this._fileInfoPluginsCheck = null;
251
+
252
+ /**
253
+ * @description Properties for managing files in the "FileManager" module
254
+ * @private
255
+ */
256
+ this._fileInfoPluginsReset = null;
257
+
258
+ /**
259
+ * @description Variables for file component management
260
+ * @private
261
+ */
262
+ this._fileManager = {
263
+ tags: null,
264
+ regExp: null,
265
+ pluginRegExp: null,
266
+ pluginMap: null
267
+ };
268
+ this._componentManager = [];
269
+
270
+ /**
271
+ * @description Current Figure container.
272
+ * @private
273
+ */
274
+ this._figureContainer = null;
275
+
276
+ /**
277
+ * @description Origin options
278
+ * @private
279
+ */
280
+ this._originOptions = options;
281
+
282
+ /** ----- Create editor ------------------------------------------------------------ */
283
+ this.__Create(options);
284
+ };
285
+
286
+ Editor.prototype = {
287
+ /**
288
+ * @description If the plugin is not added, add the plugin and call the 'add' function.
289
+ * If the plugin is added call callBack function.
290
+ * @param {string} pluginName The name of the plugin to call
291
+ * @param {Array.<Element>|null} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
292
+ * @param {object|null} pluginOptions Plugin's options
293
+ * @param {object} shortcuts this.options.get('shortcuts')
294
+ */
295
+ registerPlugin(pluginName, targets, pluginOptions, shortcuts) {
296
+ let plugin = this.plugins[pluginName];
297
+ if (!plugin) {
298
+ throw Error(`[SUNEDITOR.registerPlugin.fail] The called plugin does not exist or is in an invalid format. (pluginName: "${pluginName}")`);
299
+ } else if (typeof this.plugins[pluginName] === 'function') {
300
+ plugin = this.plugins[pluginName] = new this.plugins[pluginName](this, pluginOptions || {});
301
+ if (typeof plugin.init === 'function') plugin.init();
302
+ }
303
+
304
+ if (targets) {
305
+ for (let i = 0, len = targets.length; i < len; i++) {
306
+ UpdateButton(targets[i], plugin, this.icons, this.lang, shortcuts);
307
+ }
308
+
309
+ if (!this.activeCommands.includes(pluginName) && typeof this.plugins[pluginName].active === 'function') {
310
+ this.activeCommands.push(pluginName);
311
+ }
312
+ }
313
+ },
314
+
315
+ /**
316
+ * @description Run plugin calls and basic commands.
317
+ * @param {string} command Command string
318
+ * @param {string} type Display type string ('command', 'dropdown', 'modal', 'container')
319
+ * @param {Element|null} button The element of command button
320
+ */
321
+ run(command, type, button) {
322
+ if (type) {
323
+ if (/more/i.test(type)) {
324
+ const toolbar = domUtils.getParentElement(button, '.se-toolbar');
325
+ const toolInst = domUtils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
326
+ if (button !== toolInst.currentMoreLayerActiveButton) {
327
+ const layer = toolbar.querySelector('.' + command);
328
+ if (layer) {
329
+ toolInst._moreLayerOn(button, layer);
330
+ toolInst._showBalloon();
331
+ toolInst._showInline();
332
+ }
333
+ domUtils.addClass(button, 'on');
334
+ } else if (toolInst.currentMoreLayerActiveButton) {
335
+ toolInst._moreLayerOff();
336
+ toolInst._showBalloon();
337
+ toolInst._showInline();
338
+ }
339
+
340
+ this.viewer._resetFullScreenHeight();
341
+ return;
342
+ }
343
+
344
+ if (/container/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentContainerActiveButton)) {
345
+ this.menu.containerOn(button);
346
+ return;
347
+ }
348
+
349
+ if (this.frameContext.get('isReadOnly') && domUtils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
350
+ if (/dropdown/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentDropdownActiveButton)) {
351
+ this.menu.dropdownOn(button);
352
+ return;
353
+ } else if (/modal/.test(type)) {
354
+ this.plugins[command].open(button);
355
+ return;
356
+ } else if (/command/.test(type)) {
357
+ this.plugins[command].action(button);
358
+ } else if (/fileBrowser/.test(type)) {
359
+ this.plugins[command].open(null);
360
+ }
361
+ } else if (command) {
362
+ this.commandHandler(command);
363
+ }
364
+
365
+ if (/dropdown/.test(type)) {
366
+ this.menu.dropdownOff();
367
+ } else if (!/command/.test(type)) {
368
+ this.menu.dropdownOff();
369
+ this.menu.containerOff();
370
+ }
371
+ },
372
+
373
+ /**
374
+ * @description Execute default command of command button
375
+ * (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
376
+ * @param {string} command Property of command button (data-value)
377
+ */
378
+ async commandHandler(command) {
379
+ if (this.frameContext.get('isReadOnly') && !/copy|cut|selectAll|codeView|fullScreen|print|preview|showBlocks/.test(command)) return;
380
+
381
+ switch (command) {
382
+ case 'copy':
383
+ case 'cut':
384
+ this.execCommand(command);
385
+ break;
386
+ case 'paste':
387
+ // @todo
388
+ break;
389
+ case 'selectAll':
390
+ SELECT_ALL(this);
391
+ break;
392
+ case 'newDocument':
393
+ this.html.set(`<${this.options.get('defaultLine')}><br></${this.options.get('defaultLine')}>`);
394
+ this.focus();
395
+ this.history.push(false);
396
+ break;
397
+ case 'codeView':
398
+ this.viewer.codeView(!this.frameContext.get('isCodeView'));
399
+ break;
400
+ case 'fullScreen':
401
+ this.viewer.fullScreen(!this.frameContext.get('isFullScreen'));
402
+ break;
403
+ case 'indent':
404
+ this.format.indent();
405
+ break;
406
+ case 'outdent':
407
+ this.format.outdent();
408
+ break;
409
+ case 'undo':
410
+ this.history.undo();
411
+ break;
412
+ case 'redo':
413
+ this.history.redo();
414
+ break;
415
+ case 'removeFormat':
416
+ this.format.removeTextStyle();
417
+ this.focus();
418
+ break;
419
+ case 'print':
420
+ this.viewer.print();
421
+ break;
422
+ case 'preview':
423
+ this.viewer.preview();
424
+ break;
425
+ case 'showBlocks':
426
+ this.viewer.showBlocks(!this.frameContext.get('isShowBlocks'));
427
+ break;
428
+ case 'dir':
429
+ this.setDir(this.options.get('_rtl') ? 'ltr' : 'rtl');
430
+ break;
431
+ case 'dir_ltr':
432
+ this.setDir('ltr');
433
+ break;
434
+ case 'dir_rtl':
435
+ this.setDir('rtl');
436
+ break;
437
+ case 'save':
438
+ await SAVE(this);
439
+ break;
440
+ default:
441
+ FONT_STYLE(this, command);
442
+ }
443
+ },
444
+
445
+ /**
446
+ * @description Execute "editor.run" with command button.
447
+ * @param {Element} target Command target
448
+ */
449
+ runFromTarget(target) {
450
+ const isInput = domUtils.isInputElement(target);
451
+ if (isInput || !(target = domUtils.getCommandTarget(target))) return;
452
+
453
+ const command = target.getAttribute('data-command');
454
+ const type = target.getAttribute('data-type');
455
+
456
+ if (!command && !type) return;
457
+ if (target.disabled) return;
458
+
459
+ this.run(command, type, target);
460
+ },
461
+
462
+ /**
463
+ * @description It is executed by inserting the button of commandTargets as the argument value of the "f" function.
464
+ * "f" is called as long as the button array's length.
465
+ * @param {string} cmd data-command
466
+ * @param {Function} f Function.
467
+ */
468
+ applyCommandTargets(cmd, f) {
469
+ if (this.commandTargets.has(cmd)) {
470
+ this.commandTargets.get(cmd).forEach(f);
471
+ }
472
+ },
473
+
474
+ /**
475
+ * @description Executes a function by traversing all root targets.
476
+ * @param {Function} f Function
477
+ */
478
+ applyFrameRoots(f) {
479
+ this.frameRoots.forEach(f);
480
+ },
481
+
482
+ /**
483
+ * @description Checks if the content of the editor is empty.
484
+ * Display criteria for "placeholder".
485
+ * @param {frameContext|null} fc Frame context, if not present, currently selected frame context.
486
+ * @returns {boolean}
487
+ */
488
+ isEmpty(fc) {
489
+ fc = fc || this.frameContext;
490
+ const wysiwyg = fc.get('wysiwyg');
491
+ return domUtils.isZeroWith(wysiwyg.textContent) && !wysiwyg.querySelector(env._allowedEmptyNodeList) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
492
+ },
493
+
494
+ /**
495
+ * @description Set direction to "rtl" or "ltr".
496
+ * @param {string} dir "rtl" or "ltr"
497
+ */
498
+ setDir(dir) {
499
+ const rtl = dir === 'rtl';
500
+ if (this.options.get('_rtl') === rtl) return;
501
+
502
+ try {
503
+ this.options.set('_rtl', rtl);
504
+ this._offCurrentController();
505
+
506
+ const fc = this.frameContext;
507
+ const plugins = this.plugins;
508
+ for (const k in plugins) {
509
+ if (typeof plugins[k].setDir === 'function') plugins[k].setDir(dir);
510
+ }
511
+
512
+ const toolbarWrapper = this.context.get('toolbar._wrapper');
513
+ const statusbarWrapper = this.context.get('statusbar._wrapper');
514
+ if (rtl) {
515
+ this.applyFrameRoots((e) => {
516
+ domUtils.addClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
517
+ });
518
+ domUtils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
519
+ } else {
520
+ this.applyFrameRoots((e) => {
521
+ domUtils.removeClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
522
+ });
523
+ domUtils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
524
+ }
525
+
526
+ const lineNodes = domUtils.getListChildren(fc.wysiwyg, (current) => {
527
+ return this.format.isLine(current) && (current.style.marginRight || current.style.marginLeft || current.style.textAlign);
528
+ });
529
+
530
+ for (let i = 0, n, l, r; (n = lineNodes[i]); i++) {
531
+ n = lineNodes[i];
532
+ // indent margin
533
+ r = n.style.marginRight;
534
+ l = n.style.marginLeft;
535
+ if (r || l) {
536
+ n.style.marginRight = l;
537
+ n.style.marginLeft = r;
538
+ }
539
+ // text align
540
+ r = n.style.textAlign;
541
+ if (r === 'left') n.style.textAlign = 'right';
542
+ else if (r === 'right') n.style.textAlign = 'left';
543
+ }
544
+
545
+ DIR_BTN_ACTIVE(this, rtl);
546
+
547
+ if (this.isBalloon) this.toolbar._showBalloon();
548
+ else if (this.isSubBalloon) this.subToolbar._showBalloon();
549
+ } catch (e) {
550
+ this.options.set('_rtl', !rtl);
551
+ console.warn(`[SUNEDITOR.setDir.fail] ${e.toString()}`);
552
+ }
553
+
554
+ this.effectNode = null;
555
+ this.eventManager.applyTagEffect();
556
+ },
557
+
558
+ /**
559
+ * @description Add or reset option property (Editor is reloaded)
560
+ * @param {Object} newOptions Options
561
+ */
562
+ resetOptions(newOptions) {
563
+ const _keys = Object.keys;
564
+ this.viewer.codeView(false);
565
+ this.viewer.showBlocks(false);
566
+
567
+ const newOptionKeys = _keys(newOptions);
568
+ CheckResetKeys(newOptionKeys, this.plugins, '');
569
+ if (newOptionKeys.length === 0) return;
570
+
571
+ // option merge
572
+ const rootDiff = {};
573
+ const rootKeys = this.rootKeys;
574
+ const frameRoots = this.frameRoots;
575
+ const newRoots = [];
576
+ const newRootKeys = {};
577
+ this._originOptions = [newOptions, this._originOptions].reduce(function (init, option) {
578
+ for (const key in option) {
579
+ if (rootKeys.includes(key) && option[key]) {
580
+ const nro = option[key];
581
+ const newKeys = _keys(nro);
582
+ CheckResetKeys(newKeys, null, key + '.');
583
+ if (newKeys.length === 0) continue;
584
+
585
+ rootDiff[key] = new Map();
586
+ const o = frameRoots.get(key).get('options').get('_origin');
587
+ for (const rk in nro) {
588
+ const roV = nro[rk];
589
+ if (!newKeys.includes(rk) || o[rk] === roV) continue;
590
+ rootDiff[key].set(GetResetDiffKey(rk), true);
591
+ o[rk] = roV;
592
+ }
593
+ newRoots.push((newRootKeys[key] = { options: o }));
594
+ } else {
595
+ init[key] = option[key];
596
+ }
597
+ }
598
+ return init;
599
+ }, {});
600
+
601
+ // init options
602
+ const options = this.options;
603
+ const newMap = InitOptions(this._originOptions, newRoots).o;
604
+ /** --------- root start --------- */
605
+ for (let i = 0, k; (k = newOptionKeys[i]); i++) {
606
+ if (newRootKeys[k]) {
607
+ const diff = rootDiff[k];
608
+ const fc = frameRoots.get(k);
609
+ const originOptions = fc.get('options');
610
+ const newRootOptions = newRootKeys[k].options;
611
+
612
+ // statusbar
613
+ if (diff.has('statusbar')) {
614
+ domUtils.removeItem(fc.get('statusbar'));
615
+ if (newRootOptions.get('statusbar')) {
616
+ const statusbar = CreateStatusbar(newRootOptions, null).statusbar;
617
+ fc.get('container').appendChild(statusbar);
618
+ UpdateStatusbarContext(statusbar, fc);
619
+ this.eventManager.__addStatusbarEvent(fc, newRootOptions);
620
+ } else {
621
+ this.eventManager.removeEvent(originOptions.get('__statusbarEvent'));
622
+ newRootOptions.set('__statusbarEvent', null);
623
+ UpdateStatusbarContext(null, fc);
624
+ }
625
+ }
626
+
627
+ // iframe's options
628
+ if (diff.has('iframe_attributes')) {
629
+ const frame = fc.get('wysiwygFrame');
630
+ const originAttr = originOptions.get('iframe_attributes');
631
+ const newAttr = newRootOptions.get('iframe_attributes');
632
+ for (const origin_k in originAttr) frame.removeAttribute(origin_k, originAttr[origin_k]);
633
+ for (const new_k in newAttr) frame.setAttribute(new_k, newAttr[new_k]);
634
+ }
635
+ if (diff.has('iframe_cssFileName')) {
636
+ const docHead = fc.get('_wd').head;
637
+ const links = docHead.getElementsByTagName('link');
638
+ while (links[0]) docHead.removeChild(links[0]);
639
+ const parseDocument = new DOMParser().parseFromString(converter._setIframeStyleLinks(newRootOptions.get('iframe_cssFileName')), 'text/html');
640
+ const newLinks = parseDocument.head.children;
641
+ const sTag = docHead.querySelector('style');
642
+ while (newLinks[0]) docHead.insertBefore(newLinks[0], sTag);
643
+ }
644
+
645
+ // --- options set ---
646
+ fc.set('options', newRootOptions);
647
+
648
+ // frame styles
649
+ this.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
650
+
651
+ // frame attributes
652
+ const frame = fc.get('wysiwyg');
653
+ const originAttr = originOptions.get('editableFrameAttributes');
654
+ const newAttr = newRootOptions.get('editableFrameAttributes');
655
+ for (const origin_k in originAttr) frame.removeAttribute(origin_k, originAttr[origin_k]);
656
+ for (const new_k in newAttr) frame.setAttribute(new_k, newAttr[new_k]);
657
+
658
+ continue;
659
+ }
660
+ /** --------- root end --------- */
661
+
662
+ options.set(k, newMap.get(k));
663
+
664
+ /** apply option */
665
+ // history delay time
666
+ if (k === 'historyStackDelayTime') {
667
+ this.history.resetDelayTime(options.get('historyStackDelayTime'));
668
+ continue;
669
+ }
670
+ // set dir
671
+ if (k === 'textDirection') {
672
+ this.setDir(options.get('_rtl') ? 'ltr' : 'rtl');
673
+ continue;
674
+ }
675
+ }
676
+
677
+ /** apply options */
678
+ // toolbar
679
+ const toolbar = this.context.get('toolbar.main');
680
+ // width
681
+ if (/inline|balloon/i.test(options.get('mode')) && newOptionKeys.includes('toolbar_width')) {
682
+ toolbar.style.width = options.get('toolbar_width');
683
+ }
684
+ // hide
685
+ if (options.get('toolbar_hide')) {
686
+ toolbar.style.display = 'none';
687
+ }
688
+ // shortcuts hint
689
+ if (options.get('shortcutsHint')) {
690
+ domUtils.removeClass(toolbar, 'se-shortcut-hide');
691
+ } else {
692
+ domUtils.addClass(toolbar, 'se-shortcut-hide');
693
+ }
694
+
695
+ this.effectNode = null;
696
+ this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
697
+ },
698
+
699
+ /**
700
+ * @description Change the current root index.
701
+ * @param {number} rootKey
702
+ */
703
+ changeFrameContext(rootKey) {
704
+ if (rootKey === this.status.rootKey) return;
705
+
706
+ this.status.rootKey = rootKey;
707
+ this._setFrameInfo(this.frameRoots.get(rootKey));
708
+ this.toolbar._resetSticky();
709
+ },
710
+
711
+ /**
712
+ * @description javascript execCommand
713
+ * @param {string} command javascript execCommand function property
714
+ * @param {Boolean|undefined} showDefaultUI javascript execCommand function property
715
+ * @param {string|undefined} value javascript execCommand function property
716
+ */
717
+ execCommand(command, showDefaultUI, value) {
718
+ this.frameContext.get('_wd').execCommand(command, showDefaultUI, command === 'formatBlock' ? '<' + value + '>' : value);
719
+ this.history.push(true);
720
+ },
721
+
722
+ /**
723
+ * @description Focus to wysiwyg area
724
+ * @param {number|undefined} rootKey Root index
725
+ */
726
+ focus(rootKey) {
727
+ if (rootKey) this.changeFrameContext(rootKey);
728
+ if (this.frameContext.get('wysiwygFrame').style.display === 'none') return;
729
+ this._antiBlur = false;
730
+
731
+ if (this.frameOptions.get('iframe') || !this.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
732
+ this._nativeFocus();
733
+ } else {
734
+ try {
735
+ const range = this.selection.getRange();
736
+ if (range.startContainer === range.endContainer && domUtils.isWysiwygFrame(range.startContainer)) {
737
+ const currentNode = range.commonAncestorContainer.children[range.startOffset];
738
+ if (!this.format.isLine(currentNode) && !this.component.is(currentNode)) {
739
+ const br = domUtils.createElement('BR');
740
+ const format = domUtils.createElement(this.options.get('defaultLine'), null, br);
741
+ this.frameContext.get('wysiwyg').insertBefore(format, currentNode);
742
+ this.selection.setRange(br, 0, br, 0);
743
+ return;
744
+ }
745
+ }
746
+ this.selection.setRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
747
+ } catch (e) {
748
+ console.warn('[SUNEDITOR.focus.warn] ', e);
749
+ this._nativeFocus();
750
+ }
751
+ }
752
+
753
+ if (this.isBalloon) this.eventManager._toggleToolbarBalloon();
754
+ },
755
+
756
+ /**
757
+ * @description If "focusEl" is a component, then that component is selected; if it is a format element, the last text is selected
758
+ * If "focusEdge" is null, then selected last element
759
+ * @param {Element|null} focusEl Focus element
760
+ */
761
+ focusEdge(focusEl) {
762
+ this._antiBlur = false;
763
+ if (!focusEl) focusEl = this.frameContext.get('wysiwyg').lastElementChild;
764
+
765
+ const fileComponentInfo = this.component.get(focusEl);
766
+ if (fileComponentInfo) {
767
+ this.component.select(fileComponentInfo.target, fileComponentInfo.pluginName, false);
768
+ } else if (focusEl) {
769
+ if (focusEl.nodeType !== 3) {
770
+ focusEl = domUtils.getEdgeChild(
771
+ focusEl,
772
+ function (current) {
773
+ return current.childNodes.length === 0 || current.nodeType === 3;
774
+ },
775
+ true
776
+ );
777
+ }
778
+ if (!focusEl) this._nativeFocus();
779
+ else this.selection.setRange(focusEl, focusEl.textContent.length, focusEl, focusEl.textContent.length);
780
+ } else {
781
+ this.focus();
782
+ }
783
+ },
784
+
785
+ /**
786
+ * @description Focusout to wysiwyg area (.blur())
787
+ */
788
+ blur() {
789
+ if (this.frameOptions.get('iframe')) {
790
+ this.frameContext.get('wysiwygFrame').blur();
791
+ } else {
792
+ this.frameContext.get('wysiwyg').blur();
793
+ }
794
+ },
795
+
796
+ /**
797
+ * @description Set "options.get('editorStyle')" style.
798
+ * Define the style of the edit area
799
+ * It can also be defined with the "setOptions" method, but the "setEditorStyle" method does not render the editor again.
800
+ * @param {string} style Style string
801
+ * @param {FrameContext|null} fc Frame context
802
+ */
803
+ setEditorStyle(style, fc) {
804
+ fc = fc || this.frameContext;
805
+ const fo = fc.get('options');
806
+
807
+ const newStyles = converter._setDefaultOptionStyle(fo, style);
808
+ fo.set('_defaultStyles', newStyles);
809
+
810
+ // top area
811
+ fc.get('topArea').style.cssText = newStyles.top;
812
+
813
+ // code view
814
+ const code = fc.get('code');
815
+ code.style.cssText = fo.get('_defaultStyles').frame;
816
+ code.style.display = 'none';
817
+
818
+ // wysiwyg frame
819
+ if (!fo.get('iframe')) {
820
+ fc.get('wysiwygFrame').style.cssText = newStyles.frame + newStyles.editor;
821
+ } else {
822
+ fc.get('wysiwygFrame').style.cssText = newStyles.frame;
823
+ fc.get('wysiwyg').style.cssText = newStyles.editor;
824
+ }
825
+ },
826
+
827
+ /**
828
+ * @description Switch to or off "ReadOnly" mode.
829
+ * @param {boolean} value "readOnly" boolean value.
830
+ * @param {string|undefined} rootKey Root key
831
+ */
832
+ readOnly(value, rootKey) {
833
+ const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
834
+
835
+ fc.set('isReadOnly', !!value);
836
+ domUtils.setDisabled(this._controllerOnDisabledButtons, !!value);
837
+
838
+ if (value) {
839
+ this._offCurrentController();
840
+ this._offCurrentModal();
841
+
842
+ if (this.toolbar?.currentMoreLayerActiveButton?.disabled) this.toolbar.moreLayerOff();
843
+ if (this.subToolbar?.currentMoreLayerActiveButton?.disabled) this.subToolbar.moreLayerOff();
844
+ if (this.menu?.currentDropdownActiveButton?.disabled) this.menu.dropdownOff();
845
+ if (this.menu?.currentContainerActiveButton?.disabled) this.menu.containerOff();
846
+ if (this.modalForm) this.plugins.modal.close.call(this);
847
+
848
+ fc.get('code').setAttribute('readOnly', 'true');
849
+ domUtils.addClass(fc.get('wysiwygFrame'), 'se-read-only');
850
+ } else {
851
+ fc.get('code').removeAttribute('readOnly');
852
+ domUtils.removeClass(fc.get('wysiwygFrame'), 'se-read-only');
853
+ }
854
+
855
+ if (this.options.get('hasCodeMirror')) {
856
+ this.viewer._codeMirrorEditor('readonly', !!value, rootKey);
857
+ }
858
+ },
859
+
860
+ /**
861
+ * @description Disable the suneditor
862
+ * @param {string|undefined} rootKey Root key
863
+ */
864
+ disable(rootKey) {
865
+ const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
866
+
867
+ this.toolbar.disable();
868
+ this._offCurrentController();
869
+ this._offCurrentModal();
870
+
871
+ if (this.modalForm) this.plugins.modal.close.call(this);
872
+
873
+ fc.get('wysiwyg').setAttribute('contenteditable', false);
874
+ fc.set('isDisabled', true);
875
+
876
+ if (this.options.get('hasCodeMirror')) {
877
+ this.viewer._codeMirrorEditor('readonly', true, rootKey);
878
+ } else {
879
+ fc.get('code').setAttribute('disabled', true);
880
+ }
881
+ },
882
+
883
+ /**
884
+ * @description Enable the suneditor
885
+ * @param {string|undefined} rootKey Root key
886
+ */
887
+ enable(rootKey) {
888
+ const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
889
+
890
+ this.toolbar.enable();
891
+ fc.get('wysiwyg').setAttribute('contenteditable', true);
892
+ fc.set('isDisabled', false);
893
+
894
+ if (this.options.get('hasCodeMirror')) {
895
+ this.viewer._codeMirrorEditor('readonly', false, rootKey);
896
+ } else {
897
+ fc.get('code').removeAttribute('disabled');
898
+ }
899
+ },
900
+
901
+ /**
902
+ * @description Show the suneditor
903
+ * @param {string|undefined} rootKey Root key
904
+ */
905
+ show(rootKey) {
906
+ const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
907
+ const topAreaStyle = fc.get('topArea').style;
908
+ if (topAreaStyle.display === 'none') topAreaStyle.display = 'block';
909
+ },
910
+
911
+ /**
912
+ * @description Hide the suneditor
913
+ * @param {string|undefined} rootKey Root key
914
+ */
915
+ hide(rootKey) {
916
+ const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
917
+ fc.get('topArea').style.display = 'none';
918
+ },
919
+
920
+ /**
921
+ * @description Show loading box
922
+ * @param {string|undefined} rootKey Root key
923
+ */
924
+ showLoading(rootKey) {
925
+ (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'block';
926
+ },
927
+
928
+ /**
929
+ * @description Hide loading box
930
+ * @param {string|undefined} rootKey Root key
931
+ */
932
+ hideLoading(rootKey) {
933
+ (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'none';
934
+ },
935
+
936
+ /**
937
+ * @description Activate the transparent background "div" so that other elements are not affected during resizing.
938
+ * @param {cursor} cursor cursor css property
939
+ */
940
+ enableBackWrapper(cursor) {
941
+ this._backWrapper.style.cursor = cursor;
942
+ this._backWrapper.style.display = 'block';
943
+ },
944
+
945
+ /**
946
+ * @description Disabled background "div"
947
+ */
948
+ disableBackWrapper() {
949
+ this._backWrapper.style.display = 'none';
950
+ this._backWrapper.style.cursor = 'default';
951
+ },
952
+
953
+ /**
954
+ * @description Destroy the suneditor
955
+ */
956
+ destroy() {
957
+ /** remove history */
958
+ this.history.destroy();
959
+
960
+ /** remove event listeners */
961
+ this.eventManager._removeAllEvents();
962
+
963
+ /** destroy external library */
964
+ if (this.options.get('codeMirror6Editor')) {
965
+ this.options.get('codeMirror6Editor').destroy();
966
+ }
967
+
968
+ /** remove element */
969
+ domUtils.removeItem(this.carrierWrapper);
970
+ domUtils.removeItem(this.context.get('toolbar._wrapper'));
971
+ domUtils.removeItem(this.context.get('toolbar.sub._wrapper'));
972
+ domUtils.removeItem(this.context.get('statusbar._wrapper'));
973
+ this.applyFrameRoots((e) => {
974
+ domUtils.removeItem(e.get('topArea'));
975
+ e.get('options').clear();
976
+ e.clear();
977
+ });
978
+
979
+ /** remove object reference */
980
+ this.options.clear();
981
+ this.context.clear();
982
+
983
+ let obj = this.plugins;
984
+ for (const k in obj) {
985
+ const p = obj[k];
986
+ if (typeof p._destroy === 'function') p._destroy();
987
+ for (const pk in p) {
988
+ delete p[pk];
989
+ }
990
+ delete obj[k];
991
+ }
992
+ obj = this.events;
993
+ for (const k in obj) {
994
+ delete obj[k];
995
+ }
996
+
997
+ obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'notice', 'offset', 'selection', 'shortcuts', 'toolbar', 'viewer'];
998
+ for (let i = 0, len = obj.length, c; i < len; i++) {
999
+ c = this[obj[i]];
1000
+ for (const k in c) {
1001
+ delete c[k];
1002
+ }
1003
+ }
1004
+ obj = this.subToolbar;
1005
+ if (obj) {
1006
+ for (const k in obj) {
1007
+ delete obj[k];
1008
+ }
1009
+ }
1010
+
1011
+ obj = null;
1012
+ for (const k in this) {
1013
+ delete this[k];
1014
+ }
1015
+
1016
+ return null;
1017
+ },
1018
+
1019
+ /** ----- private methods ----------------------------------------------------------------------------------------------------------------------------- */
1020
+ /**
1021
+ * @description Set frameContext, frameOptions
1022
+ * @param {rootTarget} rt Root target
1023
+ */
1024
+ _setFrameInfo(rt) {
1025
+ this.frameContext = rt;
1026
+ this.frameOptions = rt.get('options');
1027
+ rt.set('_editorHeight', rt.get('wysiwygFrame').offsetHeight);
1028
+ this._lineBreaker_t = rt.get('lineBreaker_t');
1029
+ this._lineBreaker_b = rt.get('lineBreaker_b');
1030
+ },
1031
+
1032
+ /**
1033
+ * @description visible controllers
1034
+ * @param {boolean} value hidden/show
1035
+ * @param {boolean?} lineBreakShow Line break hidden/show (default: Follows the value "value".)
1036
+ * @private
1037
+ */
1038
+ _visibleControllers(value, lineBreakShow) {
1039
+ const visible = value ? '' : 'hidden';
1040
+ const breakerVisible = lineBreakShow ?? visible ? '' : 'hidden';
1041
+
1042
+ const cont = this.opendControllers;
1043
+ for (let i = 0, c; i < cont.length; i++) {
1044
+ c = cont[i];
1045
+ if (c.form) c.form.style.visibility = visible;
1046
+ }
1047
+
1048
+ this._lineBreaker_t.style.visibility = breakerVisible;
1049
+ this._lineBreaker_b.style.visibility = breakerVisible;
1050
+ },
1051
+
1052
+ /**
1053
+ * @description Off current controllers
1054
+ * @private
1055
+ */
1056
+ _offCurrentController() {
1057
+ this.__offControllers();
1058
+ this.component.deselect();
1059
+ },
1060
+
1061
+ /**
1062
+ * @description Off controllers
1063
+ * @private
1064
+ */
1065
+ __offControllers() {
1066
+ const cont = this.opendControllers;
1067
+ const fixedCont = [];
1068
+ for (let i = 0, c; i < cont.length; i++) {
1069
+ c = cont[i];
1070
+ if (c.fixed) {
1071
+ fixedCont.push(c);
1072
+ continue;
1073
+ }
1074
+ if (typeof c.inst.close === 'function') c.inst.close();
1075
+ if (c.form) c.form.style.display = 'none';
1076
+ }
1077
+ this.opendControllers = fixedCont;
1078
+ this.currentControllerName = '';
1079
+ this._antiBlur = false;
1080
+ },
1081
+
1082
+ /**
1083
+ * @description Off current modal
1084
+ * @private
1085
+ */
1086
+ _offCurrentModal() {
1087
+ if (this.opendModal) {
1088
+ this.opendModal.close();
1089
+ }
1090
+ },
1091
+
1092
+ /**
1093
+ * @description Focus to wysiwyg area using "native focus function"
1094
+ * @private
1095
+ */
1096
+ _nativeFocus() {
1097
+ this.selection.__focus();
1098
+ this.selection._init();
1099
+ },
1100
+
1101
+ /**
1102
+ * @description Check the components such as image and video and modify them according to the format.
1103
+ * @private
1104
+ */
1105
+ _checkComponents(loaded) {
1106
+ for (let i = 0, len = this._fileInfoPluginsCheck.length; i < len; i++) {
1107
+ this._fileInfoPluginsCheck[i](loaded);
1108
+ }
1109
+ },
1110
+
1111
+ /**
1112
+ * @description Initialize the information of the components.
1113
+ * @private
1114
+ */
1115
+ _resetComponents() {
1116
+ for (let i = 0, len = this._fileInfoPluginsReset.length; i < len; i++) {
1117
+ this._fileInfoPluginsReset[i]();
1118
+ }
1119
+ },
1120
+
1121
+ /**
1122
+ * @description Initializ wysiwyg area (Only called from core._init)
1123
+ * @param {Map} e frameContext
1124
+ * @param {string} value initial html string
1125
+ * @private
1126
+ */
1127
+ _initWysiwygArea(e, value) {
1128
+ e.get('wysiwyg').innerHTML =
1129
+ this.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', true, null, null) ||
1130
+ '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
1131
+
1132
+ if (e.has('charCounter')) e.get('charCounter').textContent = this.char.getLength();
1133
+ },
1134
+
1135
+ /**
1136
+ * @description Called when there are changes to tags in the wysiwyg region.
1137
+ * @private
1138
+ */
1139
+ _resourcesStateChange(fc) {
1140
+ this._iframeAutoHeight(fc);
1141
+ this._checkPlaceholder(fc);
1142
+ },
1143
+
1144
+ /**
1145
+ * @description Modify the height value of the iframe when the height of the iframe is automatic.
1146
+ * @private
1147
+ */
1148
+ _iframeAutoHeight(fc) {
1149
+ const autoFrame = fc.get('_iframeAuto');
1150
+ if (autoFrame) {
1151
+ this._w.setTimeout(() => {
1152
+ fc.get('wysiwygFrame').style.height = autoFrame.offsetHeight + 'px';
1153
+ }, 0);
1154
+ }
1155
+
1156
+ if (autoFrame) {
1157
+ this._w.setTimeout(() => {
1158
+ const h = autoFrame.offsetHeight;
1159
+ fc.get('wysiwygFrame').style.height = h + 'px';
1160
+ if (!env.isResizeObserverSupported) this.__callResizeFunction(fc, h, null);
1161
+ }, 0);
1162
+ } else if (!env.isResizeObserverSupported) {
1163
+ this.__callResizeFunction(fc, fc.get('wysiwygFrame').offsetHeight, null);
1164
+ }
1165
+ },
1166
+
1167
+ __callResizeFunction(fc, h, resizeObserverEntry) {
1168
+ h =
1169
+ h === -1
1170
+ ? resizeObserverEntry?.borderBoxSize && resizeObserverEntry.borderBoxSize[0]
1171
+ ? resizeObserverEntry.borderBoxSize[0].blockSize
1172
+ : resizeObserverEntry.contentRect.height + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-left')) + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-right'))
1173
+ : h;
1174
+ if (fc.get('_editorHeight') !== h) {
1175
+ this.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
1176
+ fc.set('_editorHeight', h);
1177
+ }
1178
+ },
1179
+
1180
+ /**
1181
+ * @description Set display property when there is placeholder.
1182
+ * @private
1183
+ */
1184
+ _checkPlaceholder(fc) {
1185
+ fc = fc || this.frameContext;
1186
+ const placeholder = fc.get('placeholder');
1187
+
1188
+ if (placeholder) {
1189
+ if (fc.get('isCodeView')) {
1190
+ placeholder.style.display = 'none';
1191
+ return;
1192
+ }
1193
+
1194
+ if (this.isEmpty(fc)) {
1195
+ placeholder.style.display = 'block';
1196
+ } else {
1197
+ placeholder.style.display = 'none';
1198
+ }
1199
+ }
1200
+ },
1201
+
1202
+ /**
1203
+ * @description Initializ editor
1204
+ * @private
1205
+ */
1206
+ __editorInit(options) {
1207
+ this.applyFrameRoots((e) => {
1208
+ this.__setEditorParams(e);
1209
+ });
1210
+
1211
+ // initialize core and add event listeners
1212
+ this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
1213
+ this.__init(options);
1214
+ for (const v of this._onPluginEvents.values()) {
1215
+ v.sort((a, b) => a.index - b.index);
1216
+ }
1217
+
1218
+ this.applyFrameRoots((e) => {
1219
+ this.eventManager._addFrameEvents(e);
1220
+ this._initWysiwygArea(e, e.get('options').get('value'));
1221
+ });
1222
+
1223
+ this.eventManager.__eventDoc = null;
1224
+ this._componentsInfoInit = false;
1225
+ this._componentsInfoReset = false;
1226
+ this._checkComponents(true);
1227
+
1228
+ this._w.setTimeout(() => {
1229
+ // toolbar visibility
1230
+ this.context.get('toolbar.main').style.visibility = '';
1231
+ // roots
1232
+ this.applyFrameRoots((e) => {
1233
+ if (typeof this._resourcesStateChange !== 'function') return;
1234
+ // observer
1235
+ if (this.eventManager._wwFrameObserver) this.eventManager._wwFrameObserver.observe(e.get('wysiwygFrame'));
1236
+ if (this.eventManager._toolbarObserver) this.eventManager._toolbarObserver.observe(e.get('_toolbarShadow'));
1237
+ // resource state
1238
+ this._resourcesStateChange(e);
1239
+ });
1240
+ // history reset
1241
+ this.history.reset();
1242
+ // user event
1243
+ this.triggerEvent('onload', {});
1244
+ }, 0);
1245
+ },
1246
+
1247
+ /**
1248
+ * @description Initializ core variable
1249
+ * @private
1250
+ */
1251
+ __init(options) {
1252
+ // file components
1253
+ this._fileInfoPluginsCheck = [];
1254
+ this._fileInfoPluginsReset = [];
1255
+
1256
+ // text components
1257
+ this._MELInfo = new Map();
1258
+
1259
+ // Command and file plugins registration
1260
+ this.activeCommands = ACTIVE_EVENT_COMMANDS;
1261
+ this._onPluginEvents = new Map([
1262
+ ['onMouseMove', []],
1263
+ ['onMouseLeave', []],
1264
+ ['onMouseDown', []],
1265
+ ['onMouseUp', []],
1266
+ ['onScroll', []],
1267
+ ['onClick', []],
1268
+ ['onInput', []],
1269
+ ['onKeyDown', []],
1270
+ ['onKeyUp', []],
1271
+ ['onFocus', []],
1272
+ ['onBlur', []],
1273
+ ['onPastAndDrop', []]
1274
+ ]);
1275
+ this._fileManager.tags = [];
1276
+ this._fileManager.pluginMap = {};
1277
+ this._fileManager.tagAttrs = {};
1278
+
1279
+ const plugins = this.plugins;
1280
+ const isArray = Array.isArray;
1281
+ const shortcuts = this.options.get('shortcuts');
1282
+ const filePluginRegExp = [];
1283
+ let plugin;
1284
+ for (const key in plugins) {
1285
+ this.registerPlugin(key, this._pluginCallButtons[key], options[key], shortcuts[key]);
1286
+ this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key], shortcuts[key]);
1287
+ plugin = this.plugins[key];
1288
+
1289
+ // Filemanager
1290
+ if (typeof plugin.__fileManagement === 'object') {
1291
+ const fm = plugin.__fileManagement;
1292
+ this._fileInfoPluginsCheck.push(fm._checkInfo.bind(fm));
1293
+ this._fileInfoPluginsReset.push(fm._resetInfo.bind(fm));
1294
+ if (isArray(fm.tagNames)) {
1295
+ const tagNames = fm.tagNames;
1296
+ this._fileManager.tags = this._fileManager.tags.concat(tagNames);
1297
+ filePluginRegExp.push(key);
1298
+ for (let tag = 0, tLen = tagNames.length, t; tag < tLen; tag++) {
1299
+ t = tagNames[tag].toLowerCase();
1300
+ this._fileManager.pluginMap[t] = key;
1301
+ if (fm.tagAttrs) {
1302
+ this._fileManager.tagAttrs[t] = fm.tagAttrs;
1303
+ }
1304
+ }
1305
+ }
1306
+ }
1307
+
1308
+ // Not file component
1309
+ if (typeof plugin.constructor.component === 'function') {
1310
+ this._componentManager.push(
1311
+ function (launcher, element) {
1312
+ if (!(element = launcher.component?.call(this, element))) return null;
1313
+ return {
1314
+ target: element,
1315
+ pluginName: launcher.key,
1316
+ options: launcher.options
1317
+ };
1318
+ }.bind(plugin, plugin.constructor)
1319
+ );
1320
+ }
1321
+
1322
+ // plugin event
1323
+ const pluginOptions = plugin.constructor.options || {};
1324
+ this._onPluginEvents.forEach((v, k) => {
1325
+ if (typeof plugin[k] === 'function') {
1326
+ const f = plugin[k].bind(plugin);
1327
+ f.index = pluginOptions[`eventIndex_${k}`] || pluginOptions.eventIndex || 0;
1328
+ v.push(f);
1329
+ }
1330
+ });
1331
+
1332
+ // plugin maintain
1333
+ if (plugin.retainFormat) {
1334
+ const info = plugin.retainFormat();
1335
+ this._MELInfo.set(info.query, info.method);
1336
+ }
1337
+ }
1338
+
1339
+ this._fileManager.regExp = new RegExp(`^(${this._fileManager.tags.join('|') || '\\^'})$`, 'i');
1340
+ this._fileManager.pluginRegExp = new RegExp(`^(${filePluginRegExp.length === 0 ? '\\^' : filePluginRegExp.join('|')})$`, 'i');
1341
+
1342
+ delete this._pluginCallButtons;
1343
+ delete this._pluginCallButtons_sub;
1344
+
1345
+ this.__cachingButtons();
1346
+ },
1347
+
1348
+ /**
1349
+ * @description Caching basic buttons to use
1350
+ * @private
1351
+ */
1352
+ __cachingButtons() {
1353
+ const ctx = this.context;
1354
+ this.__setDisabledButtons();
1355
+ this.__saveCommandButtons(this.allCommandButtons, ctx.get('toolbar.buttonTray'));
1356
+ if (this.options.has('_subMode')) {
1357
+ this.__saveCommandButtons(this.subAllCommandButtons, ctx.get('toolbar.sub.buttonTray'));
1358
+ }
1359
+ },
1360
+
1361
+ __setDisabledButtons() {
1362
+ const ctx = this.context;
1363
+
1364
+ this._codeViewDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW));
1365
+ this._controllerOnDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER));
1366
+
1367
+ if (this.options.has('_subMode')) {
1368
+ this._codeViewDisabledButtons = this._codeViewDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW)));
1369
+ this._controllerOnDisabledButtons = this._controllerOnDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER)));
1370
+ }
1371
+ },
1372
+
1373
+ /**
1374
+ * @description Save the current buttons
1375
+ * @private
1376
+ */
1377
+ __saveCommandButtons(cmdButtons, tray) {
1378
+ const currentButtons = tray.querySelectorAll(COMMAND_BUTTONS);
1379
+ const shortcuts = this.options.get('shortcuts');
1380
+ const reverseCommandArray = this.options.get('_reverseCommandArray');
1381
+ const keyMap = this.shortcutsKeyMap;
1382
+ const reverseKeys = this.reverseKeys;
1383
+
1384
+ for (let i = 0, len = currentButtons.length, e, c; i < len; i++) {
1385
+ e = currentButtons[i];
1386
+ c = e.getAttribute('data-command');
1387
+ // command set
1388
+ cmdButtons.set(c, e);
1389
+ this.__setCommandTargets(c, e);
1390
+ // shortcuts
1391
+ CreateShortcuts(c, e, shortcuts[c], keyMap, reverseCommandArray, reverseKeys);
1392
+ }
1393
+ },
1394
+
1395
+ __setCommandTargets(cmd, target) {
1396
+ if (!cmd || !target) return;
1397
+
1398
+ const isBasicCmd = BASIC_COMMANDS.includes(cmd);
1399
+ if (!isBasicCmd && !this.plugins[cmd]) return;
1400
+
1401
+ if (!this.commandTargets.get(cmd)) {
1402
+ this.commandTargets.set(cmd, [target]);
1403
+ } else if (!this.commandTargets.get(cmd).includes(target)) {
1404
+ this.commandTargets.get(cmd).push(target);
1405
+ }
1406
+ },
1407
+
1408
+ __setIframeDocument(frame, originOptions, targetOptions) {
1409
+ frame.setAttribute('scrolling', 'auto');
1410
+ frame.contentDocument.head.innerHTML =
1411
+ '<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">' +
1412
+ converter._setIframeStyleLinks(targetOptions.get('iframe_cssFileName')) +
1413
+ converter._setAutoHeightStyle(targetOptions.get('height'));
1414
+ frame.contentDocument.body.className = originOptions.get('_editableClass');
1415
+ frame.contentDocument.body.setAttribute('contenteditable', true);
1416
+ },
1417
+
1418
+ __setEditorParams(e) {
1419
+ const frameOptions = e.get('options');
1420
+ const _w = this._w;
1421
+
1422
+ e.set('wwComputedStyle', _w.getComputedStyle(e.get('wysiwyg')));
1423
+
1424
+ if (!frameOptions.get('iframe') && typeof ShadowRoot === 'function') {
1425
+ let child = e.get('wysiwygFrame');
1426
+ while (child) {
1427
+ if (child.shadowRoot) {
1428
+ this._shadowRoot = child.shadowRoot;
1429
+ break;
1430
+ } else if (child instanceof ShadowRoot) {
1431
+ this._shadowRoot = child;
1432
+ break;
1433
+ }
1434
+ child = child.parentNode;
1435
+ }
1436
+ }
1437
+
1438
+ // wisywig attributes
1439
+ const attr = frameOptions.get('editableFrameAttributes');
1440
+ for (const k in attr) {
1441
+ e.get('wysiwyg').setAttribute(k, attr[k]);
1442
+ }
1443
+
1444
+ // init, validate
1445
+ if (frameOptions.get('iframe')) {
1446
+ e.set('_ww', e.get('wysiwygFrame').contentWindow);
1447
+ e.set('_wd', e.get('wysiwygFrame').contentDocument);
1448
+ e.set('wysiwyg', e.get('_wd').body);
1449
+ // e.get('wysiwyg').className += ' ' + options.get('_editableClass');
1450
+ if (frameOptions.get('_defaultStyles').editor) e.get('wysiwyg').style.cssText = frameOptions.get('_defaultStyles').editor;
1451
+ if (frameOptions.get('height') === 'auto') e.set('_iframeAuto', e.get('_wd').body);
1452
+ } else {
1453
+ e.set('_ww', _w);
1454
+ e.set('_wd', this._d);
1455
+ }
1456
+ },
1457
+
1458
+ __registerClass() {
1459
+ // use events
1460
+ this.events = { ...Events(), ...this.options.get('events') };
1461
+ this.triggerEvent = async (eventName, eventData) => {
1462
+ const eventHandler = this.events[eventName];
1463
+ if (typeof eventHandler === 'function') {
1464
+ return await eventHandler({ editor: this, ...eventData });
1465
+ }
1466
+ return env.NO_EVENT;
1467
+ };
1468
+
1469
+ // history function
1470
+ this.history = History(this);
1471
+
1472
+ // eventManager
1473
+ this.eventManager = new EventManager(this);
1474
+
1475
+ // util classes
1476
+ this.offset = new Offset(this);
1477
+ this.shortcuts = new Shortcuts(this);
1478
+ this.notice = new Notice(this);
1479
+ // main classes
1480
+ this.toolbar = new Toolbar(this, { keyName: 'toolbar', balloon: this.isBalloon, balloonAlways: this.isBalloonAlways, inline: this.isInline, res: this._responsiveButtons });
1481
+ if (this.options.has('_subMode'))
1482
+ this.subToolbar = new Toolbar(this, {
1483
+ keyName: 'toolbar.sub',
1484
+ balloon: this.isSubBalloon,
1485
+ balloonAlways: this.isSubBalloonAlways,
1486
+ inline: false,
1487
+ res: this._responsiveButtons_sub
1488
+ });
1489
+ this.selection = new Selection(this);
1490
+ this.html = new HTML(this);
1491
+ this.nodeTransform = new NodeTransform(this);
1492
+ this.component = new Component(this);
1493
+ this.format = new Format(this);
1494
+ this.menu = new Menu(this);
1495
+ this.char = new Char(this);
1496
+ this.viewer = new Viewer(this);
1497
+
1498
+ // register classes to the eventManager
1499
+ ClassInjector.call(this.eventManager, this);
1500
+ // register main classes
1501
+ ClassInjector.call(this.char, this);
1502
+ ClassInjector.call(this.component, this);
1503
+ ClassInjector.call(this.format, this);
1504
+ ClassInjector.call(this.html, this);
1505
+ ClassInjector.call(this.menu, this);
1506
+ ClassInjector.call(this.nodeTransform, this);
1507
+ ClassInjector.call(this.selection, this);
1508
+ ClassInjector.call(this.toolbar, this);
1509
+ ClassInjector.call(this.viewer, this);
1510
+ if (this.options.has('_subMode')) ClassInjector.call(this.subToolbar, this);
1511
+
1512
+ // delete self reference
1513
+ delete this.char.char;
1514
+ delete this.component.component;
1515
+ delete this.format.format;
1516
+ delete this.html.html;
1517
+ delete this.menu.menu;
1518
+ delete this.nodeTransform.nodeTransform;
1519
+ delete this.selection.selection;
1520
+ delete this.toolbar.toolbar;
1521
+ delete this.viewer.viewer;
1522
+ if (this.subToolbar) delete this.subToolbar.subToolbar;
1523
+
1524
+ this._responsiveButtons = this._responsiveButtons_res = null;
1525
+ },
1526
+
1527
+ async __Create(originOptions) {
1528
+ // set modes
1529
+ this.isInline = /inline/i.test(this.options.get('mode'));
1530
+ this.isBalloon = /balloon/i.test(this.options.get('mode'));
1531
+ this.isBalloonAlways = /balloon-always/i.test(this.options.get('mode'));
1532
+ this.isClassic = /classic/i.test(this.options.get('mode'));
1533
+ // set subToolbar modes
1534
+ this.isSubBalloon = /balloon/i.test(this.options.get('_subMode'));
1535
+ this.isSubBalloonAlways = /balloon-always/i.test(this.options.get('_subMode'));
1536
+
1537
+ // register class
1538
+ this.__registerClass();
1539
+
1540
+ // common events
1541
+ this.eventManager._addCommonEvents();
1542
+
1543
+ // init
1544
+ const iframePromises = [];
1545
+ this.applyFrameRoots((e) => {
1546
+ const o = e.get('originElement');
1547
+ const t = e.get('topArea');
1548
+ o.style.display = 'none';
1549
+ t.style.display = 'block';
1550
+ o.parentNode.insertBefore(t, o.nextElementSibling);
1551
+
1552
+ if (e.get('options').get('iframe')) {
1553
+ const iframeLoaded = new Promise((resolve) => {
1554
+ e.get('wysiwygFrame').addEventListener('load', ({ target }) => {
1555
+ this.__setIframeDocument(target, this.options, e.get('options'));
1556
+ resolve();
1557
+ });
1558
+ });
1559
+ iframePromises.push(iframeLoaded);
1560
+ }
1561
+ });
1562
+
1563
+ this.applyFrameRoots((e) => {
1564
+ e.get('wrapper').appendChild(e.get('wysiwygFrame'));
1565
+ });
1566
+
1567
+ if (iframePromises.length > 0) {
1568
+ await Promise.all(iframePromises);
1569
+ }
1570
+
1571
+ this.__editorInit(originOptions);
1572
+ },
1573
+
1574
+ Constructor: Editor
1575
+ };
1576
+
1577
+ function GetResetDiffKey(key) {
1578
+ if (/^statusbar/i.test(key)) return 'statusbar';
1579
+ return key;
1580
+ }
1581
+
1582
+ function CheckResetKeys(keys, plugins, root) {
1583
+ for (let i = 0, len = keys.length, k; i < len; i++) {
1584
+ k = keys[i];
1585
+ if (RO_UNAVAILABD.includes(k) || (plugins && plugins[k])) {
1586
+ console.warn(`[SUNEDITOR.warn.resetOptions] "[${root + k}]" options not available in resetOptions have no effect.`);
1587
+ keys.splice(i--, 1);
1588
+ len--;
1589
+ }
1590
+ }
1591
+ }
1592
+
1593
+ export default Editor;