suneditor 2.46.2 → 3.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) 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/package.json +94 -70
  7. package/src/assets/icons/_default.js +194 -0
  8. package/src/assets/suneditor-content.css +642 -0
  9. package/src/assets/suneditor.css +3378 -0
  10. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  11. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  12. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  13. package/src/core/base/eventHandlers/handler_ww_key_input.js +978 -0
  14. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  15. package/src/core/base/eventManager.js +1129 -0
  16. package/src/core/base/events.js +320 -0
  17. package/src/core/base/history.js +301 -0
  18. package/src/core/class/char.js +146 -0
  19. package/src/core/class/component.js +624 -0
  20. package/src/core/class/format.js +3255 -0
  21. package/src/core/class/html.js +1621 -0
  22. package/src/core/class/menu.js +260 -0
  23. package/src/core/class/nodeTransform.js +379 -0
  24. package/src/core/class/notice.js +42 -0
  25. package/src/core/class/offset.js +578 -0
  26. package/src/core/class/selection.js +508 -0
  27. package/src/core/class/shortcuts.js +38 -0
  28. package/src/core/class/toolbar.js +440 -0
  29. package/src/core/class/viewer.js +646 -0
  30. package/src/core/editor.js +1588 -0
  31. package/src/core/section/actives.js +107 -0
  32. package/src/core/section/constructor.js +1237 -0
  33. package/src/core/section/context.js +97 -0
  34. package/src/editorInjector/_classes.js +22 -0
  35. package/src/editorInjector/_core.js +28 -0
  36. package/src/editorInjector/index.js +13 -0
  37. package/src/helper/converter.js +313 -0
  38. package/src/helper/domUtils.js +1177 -0
  39. package/src/helper/env.js +250 -0
  40. package/src/helper/index.js +19 -0
  41. package/src/helper/numbers.js +68 -0
  42. package/src/helper/unicode.js +43 -0
  43. package/src/langs/ckb.js +161 -0
  44. package/src/langs/cs.js +161 -0
  45. package/src/langs/da.js +161 -0
  46. package/src/langs/de.js +162 -0
  47. package/src/langs/en.js +199 -0
  48. package/src/langs/es.js +162 -0
  49. package/src/langs/fa.js +159 -0
  50. package/src/langs/fr.js +161 -0
  51. package/src/langs/he.js +162 -0
  52. package/src/{lang → langs}/index.js +0 -2
  53. package/src/langs/it.js +162 -0
  54. package/src/langs/ja.js +162 -0
  55. package/src/langs/ko.js +162 -0
  56. package/src/langs/lv.js +162 -0
  57. package/src/langs/nl.js +162 -0
  58. package/src/langs/pl.js +162 -0
  59. package/src/langs/pt_br.js +162 -0
  60. package/src/langs/ro.js +162 -0
  61. package/src/langs/ru.js +162 -0
  62. package/src/langs/se.js +162 -0
  63. package/src/langs/tr.js +159 -0
  64. package/src/langs/ua.js +162 -0
  65. package/src/langs/ur.js +162 -0
  66. package/src/langs/zh_cn.js +162 -0
  67. package/src/modules/ApiManager.js +168 -0
  68. package/src/modules/ColorPicker.js +302 -0
  69. package/src/modules/Controller.js +315 -0
  70. package/src/modules/Figure.js +1174 -0
  71. package/src/modules/FileBrowser.js +271 -0
  72. package/src/modules/FileManager.js +290 -0
  73. package/src/modules/HueSlider.js +513 -0
  74. package/src/modules/Modal.js +177 -0
  75. package/src/modules/ModalAnchorEditor.js +494 -0
  76. package/src/modules/SelectMenu.js +447 -0
  77. package/src/modules/_DragHandle.js +16 -0
  78. package/src/modules/index.js +14 -0
  79. package/src/plugins/command/blockquote.js +47 -47
  80. package/src/plugins/command/exportPdf.js +168 -0
  81. package/src/plugins/command/fileUpload.js +389 -0
  82. package/src/plugins/command/list_bulleted.js +112 -0
  83. package/src/plugins/command/list_numbered.js +115 -0
  84. package/src/plugins/dropdown/align.js +143 -0
  85. package/src/plugins/dropdown/backgroundColor.js +73 -0
  86. package/src/plugins/dropdown/font.js +113 -0
  87. package/src/plugins/dropdown/fontColor.js +73 -0
  88. package/src/plugins/dropdown/formatBlock.js +141 -0
  89. package/src/plugins/dropdown/hr.js +111 -0
  90. package/src/plugins/dropdown/layout.js +72 -0
  91. package/src/plugins/dropdown/lineHeight.js +114 -0
  92. package/src/plugins/dropdown/list.js +107 -0
  93. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  94. package/src/plugins/dropdown/table.js +2810 -0
  95. package/src/plugins/dropdown/template.js +71 -0
  96. package/src/plugins/dropdown/textStyle.js +137 -0
  97. package/src/plugins/field/mention.js +172 -0
  98. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  99. package/src/plugins/index.js +86 -24
  100. package/src/plugins/input/fontSize.js +357 -0
  101. package/src/plugins/modal/audio.js +492 -0
  102. package/src/plugins/modal/image.js +1062 -0
  103. package/src/plugins/modal/link.js +211 -0
  104. package/src/plugins/modal/math.js +347 -0
  105. package/src/plugins/modal/video.js +870 -0
  106. package/src/suneditor.js +62 -67
  107. package/src/themes/test.css +61 -0
  108. package/typings/CommandPlugin.d.ts +8 -0
  109. package/typings/DialogPlugin.d.ts +20 -0
  110. package/typings/FileBrowserPlugin.d.ts +30 -0
  111. package/typings/Lang.d.ts +124 -0
  112. package/typings/Module.d.ts +15 -0
  113. package/typings/Plugin.d.ts +42 -0
  114. package/typings/SubmenuPlugin.d.ts +8 -0
  115. package/typings/_classes.d.ts +17 -0
  116. package/typings/_colorPicker.d.ts +60 -0
  117. package/typings/_core.d.ts +55 -0
  118. package/typings/align.d.ts +5 -0
  119. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  120. package/typings/backgroundColor.d.ts +5 -0
  121. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  122. package/typings/char.d.ts +39 -0
  123. package/typings/component.d.ts +38 -0
  124. package/typings/context.d.ts +39 -0
  125. package/typings/converter.d.ts +33 -0
  126. package/typings/dialog.d.ts +28 -0
  127. package/typings/domUtils.d.ts +361 -0
  128. package/typings/editor.d.ts +7 -0
  129. package/typings/editor.ts +542 -0
  130. package/typings/env.d.ts +70 -0
  131. package/typings/eventManager.d.ts +37 -0
  132. package/typings/events.d.ts +262 -0
  133. package/typings/fileBrowser.d.ts +42 -0
  134. package/typings/fileManager.d.ts +67 -0
  135. package/typings/font.d.ts +5 -0
  136. package/typings/fontColor.d.ts +5 -0
  137. package/typings/fontSize.d.ts +5 -0
  138. package/typings/format.d.ts +191 -0
  139. package/typings/formatBlock.d.ts +5 -0
  140. package/typings/history.d.ts +48 -0
  141. package/typings/horizontalRule.d.ts +5 -0
  142. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  143. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  144. package/typings/index.d.ts +21 -0
  145. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  146. package/typings/index.plugins.d.ts +58 -0
  147. package/typings/lineHeight.d.ts +5 -0
  148. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  149. package/typings/list.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  151. package/typings/mediaContainer.d.ts +25 -0
  152. package/typings/node.d.ts +57 -0
  153. package/typings/notice.d.ts +16 -0
  154. package/typings/numbers.d.ts +29 -0
  155. package/typings/offset.d.ts +24 -0
  156. package/typings/options.d.ts +589 -0
  157. package/typings/paragraphStyle.d.ts +5 -0
  158. package/typings/resizing.d.ts +141 -0
  159. package/typings/selection.d.ts +94 -0
  160. package/typings/shortcuts.d.ts +13 -0
  161. package/typings/suneditor.d.ts +9 -0
  162. package/typings/table.d.ts +5 -0
  163. package/typings/template.d.ts +5 -0
  164. package/typings/textStyle.d.ts +5 -0
  165. package/typings/toolbar.d.ts +32 -0
  166. package/typings/unicode.d.ts +25 -0
  167. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  168. package/dist/css/suneditor.min.css +0 -1
  169. package/dist/suneditor.min.js +0 -2
  170. package/src/assets/css/suneditor-contents.css +0 -562
  171. package/src/assets/css/suneditor.css +0 -566
  172. package/src/assets/defaultIcons.js +0 -103
  173. package/src/lang/Lang.d.ts +0 -144
  174. package/src/lang/ckb.d.ts +0 -5
  175. package/src/lang/ckb.js +0 -188
  176. package/src/lang/cs.d.ts +0 -5
  177. package/src/lang/cs.js +0 -188
  178. package/src/lang/da.d.ts +0 -5
  179. package/src/lang/da.js +0 -191
  180. package/src/lang/de.d.ts +0 -5
  181. package/src/lang/de.js +0 -188
  182. package/src/lang/en.d.ts +0 -5
  183. package/src/lang/en.js +0 -188
  184. package/src/lang/es.d.ts +0 -5
  185. package/src/lang/es.js +0 -188
  186. package/src/lang/fa.d.ts +0 -5
  187. package/src/lang/fa.js +0 -188
  188. package/src/lang/fr.d.ts +0 -5
  189. package/src/lang/fr.js +0 -188
  190. package/src/lang/he.d.ts +0 -5
  191. package/src/lang/he.js +0 -188
  192. package/src/lang/index.d.ts +0 -23
  193. package/src/lang/it.d.ts +0 -5
  194. package/src/lang/it.js +0 -188
  195. package/src/lang/ja.d.ts +0 -5
  196. package/src/lang/ja.js +0 -188
  197. package/src/lang/ko.d.ts +0 -5
  198. package/src/lang/ko.js +0 -188
  199. package/src/lang/lv.d.ts +0 -5
  200. package/src/lang/lv.js +0 -188
  201. package/src/lang/nl.d.ts +0 -5
  202. package/src/lang/nl.js +0 -188
  203. package/src/lang/pl.d.ts +0 -5
  204. package/src/lang/pl.js +0 -188
  205. package/src/lang/pt_br.d.ts +0 -5
  206. package/src/lang/pt_br.js +0 -189
  207. package/src/lang/ro.d.ts +0 -5
  208. package/src/lang/ro.js +0 -188
  209. package/src/lang/ru.d.ts +0 -5
  210. package/src/lang/ru.js +0 -188
  211. package/src/lang/se.d.ts +0 -5
  212. package/src/lang/se.js +0 -191
  213. package/src/lang/tr.d.ts +0 -5
  214. package/src/lang/tr.js +0 -191
  215. package/src/lang/ua.d.ts +0 -5
  216. package/src/lang/ua.js +0 -188
  217. package/src/lang/ur.d.ts +0 -5
  218. package/src/lang/ur.js +0 -188
  219. package/src/lang/zh_cn.d.ts +0 -5
  220. package/src/lang/zh_cn.js +0 -187
  221. package/src/lib/constructor.js +0 -954
  222. package/src/lib/context.d.ts +0 -42
  223. package/src/lib/context.js +0 -71
  224. package/src/lib/core.d.ts +0 -1135
  225. package/src/lib/core.js +0 -9395
  226. package/src/lib/history.d.ts +0 -48
  227. package/src/lib/history.js +0 -219
  228. package/src/lib/util.d.ts +0 -678
  229. package/src/lib/util.js +0 -2131
  230. package/src/options.d.ts +0 -608
  231. package/src/plugins/CommandPlugin.d.ts +0 -8
  232. package/src/plugins/DialogPlugin.d.ts +0 -20
  233. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  234. package/src/plugins/Module.d.ts +0 -15
  235. package/src/plugins/Plugin.d.ts +0 -42
  236. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  237. package/src/plugins/dialog/audio.js +0 -559
  238. package/src/plugins/dialog/image.js +0 -1126
  239. package/src/plugins/dialog/link.js +0 -223
  240. package/src/plugins/dialog/math.js +0 -295
  241. package/src/plugins/dialog/mention.js +0 -242
  242. package/src/plugins/dialog/video.js +0 -979
  243. package/src/plugins/index.d.ts +0 -79
  244. package/src/plugins/modules/_anchor.js +0 -461
  245. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  246. package/src/plugins/modules/_colorPicker.js +0 -201
  247. package/src/plugins/modules/_notice.d.ts +0 -21
  248. package/src/plugins/modules/_notice.js +0 -72
  249. package/src/plugins/modules/_selectMenu.js +0 -119
  250. package/src/plugins/modules/component.d.ts +0 -25
  251. package/src/plugins/modules/component.js +0 -81
  252. package/src/plugins/modules/dialog.d.ts +0 -28
  253. package/src/plugins/modules/dialog.js +0 -175
  254. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  255. package/src/plugins/modules/fileBrowser.js +0 -374
  256. package/src/plugins/modules/fileManager.d.ts +0 -67
  257. package/src/plugins/modules/fileManager.js +0 -326
  258. package/src/plugins/modules/index.js +0 -9
  259. package/src/plugins/modules/resizing.d.ts +0 -154
  260. package/src/plugins/modules/resizing.js +0 -903
  261. package/src/plugins/submenu/align.d.ts +0 -5
  262. package/src/plugins/submenu/align.js +0 -160
  263. package/src/plugins/submenu/font.d.ts +0 -5
  264. package/src/plugins/submenu/font.js +0 -123
  265. package/src/plugins/submenu/fontColor.d.ts +0 -5
  266. package/src/plugins/submenu/fontColor.js +0 -101
  267. package/src/plugins/submenu/fontSize.d.ts +0 -5
  268. package/src/plugins/submenu/fontSize.js +0 -112
  269. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  270. package/src/plugins/submenu/formatBlock.js +0 -273
  271. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  272. package/src/plugins/submenu/hiliteColor.js +0 -102
  273. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  274. package/src/plugins/submenu/horizontalRule.js +0 -98
  275. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  276. package/src/plugins/submenu/lineHeight.js +0 -104
  277. package/src/plugins/submenu/list.d.ts +0 -5
  278. package/src/plugins/submenu/list.js +0 -456
  279. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  280. package/src/plugins/submenu/paragraphStyle.js +0 -135
  281. package/src/plugins/submenu/table.d.ts +0 -5
  282. package/src/plugins/submenu/table.js +0 -1431
  283. package/src/plugins/submenu/template.d.ts +0 -5
  284. package/src/plugins/submenu/template.js +0 -72
  285. package/src/plugins/submenu/textStyle.d.ts +0 -5
  286. package/src/plugins/submenu/textStyle.js +0 -167
  287. package/src/suneditor.d.ts +0 -9
  288. package/src/suneditor_build.js +0 -18
  289. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,1588 @@
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
+
1151
+ if (autoFrame) {
1152
+ this._w.setTimeout(() => {
1153
+ const h = autoFrame.offsetHeight;
1154
+ fc.get('wysiwygFrame').style.height = h + 'px';
1155
+ if (!env.isResizeObserverSupported) this.__callResizeFunction(fc, h, null);
1156
+ }, 0);
1157
+ } else if (!env.isResizeObserverSupported) {
1158
+ this.__callResizeFunction(fc, fc.get('wysiwygFrame').offsetHeight, null);
1159
+ }
1160
+ },
1161
+
1162
+ __callResizeFunction(fc, h, resizeObserverEntry) {
1163
+ h =
1164
+ h === -1
1165
+ ? resizeObserverEntry?.borderBoxSize && resizeObserverEntry.borderBoxSize[0]
1166
+ ? resizeObserverEntry.borderBoxSize[0].blockSize
1167
+ : resizeObserverEntry.contentRect.height + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-left')) + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-right'))
1168
+ : h;
1169
+ if (fc.get('_editorHeight') !== h) {
1170
+ this.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
1171
+ fc.set('_editorHeight', h);
1172
+ }
1173
+ },
1174
+
1175
+ /**
1176
+ * @description Set display property when there is placeholder.
1177
+ * @private
1178
+ */
1179
+ _checkPlaceholder(fc) {
1180
+ fc = fc || this.frameContext;
1181
+ const placeholder = fc.get('placeholder');
1182
+
1183
+ if (placeholder) {
1184
+ if (fc.get('isCodeView')) {
1185
+ placeholder.style.display = 'none';
1186
+ return;
1187
+ }
1188
+
1189
+ if (this.isEmpty(fc)) {
1190
+ placeholder.style.display = 'block';
1191
+ } else {
1192
+ placeholder.style.display = 'none';
1193
+ }
1194
+ }
1195
+ },
1196
+
1197
+ /**
1198
+ * @description Initializ editor
1199
+ * @private
1200
+ */
1201
+ __editorInit(options) {
1202
+ this.applyFrameRoots((e) => {
1203
+ this.__setEditorParams(e);
1204
+ });
1205
+
1206
+ // initialize core and add event listeners
1207
+ this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
1208
+ this.__init(options);
1209
+ for (const v of this._onPluginEvents.values()) {
1210
+ v.sort((a, b) => a.index - b.index);
1211
+ }
1212
+
1213
+ this.applyFrameRoots((e) => {
1214
+ this.eventManager._addFrameEvents(e);
1215
+ this._initWysiwygArea(e, e.get('options').get('value'));
1216
+ });
1217
+
1218
+ this.eventManager.__eventDoc = null;
1219
+ this._componentsInfoInit = false;
1220
+ this._componentsInfoReset = false;
1221
+ this._checkComponents(true);
1222
+
1223
+ this._w.setTimeout(() => {
1224
+ // toolbar visibility
1225
+ this.context.get('toolbar.main').style.visibility = '';
1226
+ // roots
1227
+ this.applyFrameRoots((e) => {
1228
+ if (typeof this._resourcesStateChange !== 'function') return;
1229
+ // observer
1230
+ if (this.eventManager._wwFrameObserver) this.eventManager._wwFrameObserver.observe(e.get('wysiwygFrame'));
1231
+ if (this.eventManager._toolbarObserver) this.eventManager._toolbarObserver.observe(e.get('_toolbarShadow'));
1232
+ // resource state
1233
+ this._resourcesStateChange(e);
1234
+ });
1235
+ // history reset
1236
+ this.history.reset();
1237
+ // user event
1238
+ this.triggerEvent('onload', {});
1239
+ }, 0);
1240
+ },
1241
+
1242
+ /**
1243
+ * @description Initializ core variable
1244
+ * @private
1245
+ */
1246
+ __init(options) {
1247
+ // file components
1248
+ this._fileInfoPluginsCheck = [];
1249
+ this._fileInfoPluginsReset = [];
1250
+
1251
+ // text components
1252
+ this._MELInfo = new Map();
1253
+
1254
+ // Command and file plugins registration
1255
+ this.activeCommands = ACTIVE_EVENT_COMMANDS;
1256
+ this._onPluginEvents = new Map([
1257
+ ['onMouseMove', []],
1258
+ ['onMouseLeave', []],
1259
+ ['onMouseDown', []],
1260
+ ['onMouseUp', []],
1261
+ ['onScroll', []],
1262
+ ['onClick', []],
1263
+ ['onInput', []],
1264
+ ['onKeyDown', []],
1265
+ ['onKeyUp', []],
1266
+ ['onFocus', []],
1267
+ ['onBlur', []],
1268
+ ['onPastAndDrop', []]
1269
+ ]);
1270
+ this._fileManager.tags = [];
1271
+ this._fileManager.pluginMap = {};
1272
+ this._fileManager.tagAttrs = {};
1273
+
1274
+ const plugins = this.plugins;
1275
+ const isArray = Array.isArray;
1276
+ const shortcuts = this.options.get('shortcuts');
1277
+ const filePluginRegExp = [];
1278
+ let plugin;
1279
+ for (const key in plugins) {
1280
+ this.registerPlugin(key, this._pluginCallButtons[key], options[key], shortcuts[key]);
1281
+ this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key], shortcuts[key]);
1282
+ plugin = this.plugins[key];
1283
+
1284
+ // Filemanager
1285
+ if (typeof plugin.__fileManagement === 'object') {
1286
+ const fm = plugin.__fileManagement;
1287
+ this._fileInfoPluginsCheck.push(fm._checkInfo.bind(fm));
1288
+ this._fileInfoPluginsReset.push(fm._resetInfo.bind(fm));
1289
+ if (isArray(fm.tagNames)) {
1290
+ const tagNames = fm.tagNames;
1291
+ this._fileManager.tags = this._fileManager.tags.concat(tagNames);
1292
+ filePluginRegExp.push(key);
1293
+ for (let tag = 0, tLen = tagNames.length, t; tag < tLen; tag++) {
1294
+ t = tagNames[tag].toLowerCase();
1295
+ this._fileManager.pluginMap[t] = key;
1296
+ if (fm.tagAttrs) {
1297
+ this._fileManager.tagAttrs[t] = fm.tagAttrs;
1298
+ }
1299
+ }
1300
+ }
1301
+ }
1302
+
1303
+ // Not file component
1304
+ if (typeof plugin.constructor.component === 'function') {
1305
+ this._componentManager.push(
1306
+ function (launcher, element) {
1307
+ if (!(element = launcher.component?.call(this, element))) return null;
1308
+ return {
1309
+ target: element,
1310
+ pluginName: launcher.key,
1311
+ options: launcher.options
1312
+ };
1313
+ }.bind(plugin, plugin.constructor)
1314
+ );
1315
+ }
1316
+
1317
+ // plugin event
1318
+ const pluginOptions = plugin.constructor.options || {};
1319
+ this._onPluginEvents.forEach((v, k) => {
1320
+ if (typeof plugin[k] === 'function') {
1321
+ const f = plugin[k].bind(plugin);
1322
+ f.index = pluginOptions[`eventIndex_${k}`] || pluginOptions.eventIndex || 0;
1323
+ v.push(f);
1324
+ }
1325
+ });
1326
+
1327
+ // plugin maintain
1328
+ if (plugin.retainFormat) {
1329
+ const info = plugin.retainFormat();
1330
+ this._MELInfo.set(info.query, info.method);
1331
+ }
1332
+ }
1333
+
1334
+ this._fileManager.regExp = new RegExp(`^(${this._fileManager.tags.join('|') || '\\^'})$`, 'i');
1335
+ this._fileManager.pluginRegExp = new RegExp(`^(${filePluginRegExp.length === 0 ? '\\^' : filePluginRegExp.join('|')})$`, 'i');
1336
+
1337
+ delete this._pluginCallButtons;
1338
+ delete this._pluginCallButtons_sub;
1339
+
1340
+ this.__cachingButtons();
1341
+ },
1342
+
1343
+ /**
1344
+ * @description Caching basic buttons to use
1345
+ * @private
1346
+ */
1347
+ __cachingButtons() {
1348
+ const ctx = this.context;
1349
+ this.__setDisabledButtons();
1350
+ this.__saveCommandButtons(this.allCommandButtons, ctx.get('toolbar.buttonTray'));
1351
+ if (this.options.has('_subMode')) {
1352
+ this.__saveCommandButtons(this.subAllCommandButtons, ctx.get('toolbar.sub.buttonTray'));
1353
+ }
1354
+ },
1355
+
1356
+ __setDisabledButtons() {
1357
+ const ctx = this.context;
1358
+
1359
+ this._codeViewDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW));
1360
+ this._controllerOnDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER));
1361
+
1362
+ if (this.options.has('_subMode')) {
1363
+ this._codeViewDisabledButtons = this._codeViewDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW)));
1364
+ this._controllerOnDisabledButtons = this._controllerOnDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER)));
1365
+ }
1366
+ },
1367
+
1368
+ /**
1369
+ * @description Save the current buttons
1370
+ * @private
1371
+ */
1372
+ __saveCommandButtons(cmdButtons, tray) {
1373
+ const currentButtons = tray.querySelectorAll(COMMAND_BUTTONS);
1374
+ const shortcuts = this.options.get('shortcuts');
1375
+ const reverseCommandArray = this.options.get('_reverseCommandArray');
1376
+ const keyMap = this.shortcutsKeyMap;
1377
+ const reverseKeys = this.reverseKeys;
1378
+
1379
+ for (let i = 0, len = currentButtons.length, e, c; i < len; i++) {
1380
+ e = currentButtons[i];
1381
+ c = e.getAttribute('data-command');
1382
+ // command set
1383
+ cmdButtons.set(c, e);
1384
+ this.__setCommandTargets(c, e);
1385
+ // shortcuts
1386
+ CreateShortcuts(c, e, shortcuts[c], keyMap, reverseCommandArray, reverseKeys);
1387
+ }
1388
+ },
1389
+
1390
+ __setCommandTargets(cmd, target) {
1391
+ if (!cmd || !target) return;
1392
+
1393
+ const isBasicCmd = BASIC_COMMANDS.includes(cmd);
1394
+ if (!isBasicCmd && !this.plugins[cmd]) return;
1395
+
1396
+ if (!this.commandTargets.get(cmd)) {
1397
+ this.commandTargets.set(cmd, [target]);
1398
+ } else if (!this.commandTargets.get(cmd).includes(target)) {
1399
+ this.commandTargets.get(cmd).push(target);
1400
+ }
1401
+ },
1402
+
1403
+ __setIframeDocument(frame, originOptions, targetOptions) {
1404
+ frame.setAttribute('scrolling', 'auto');
1405
+ frame.contentDocument.head.innerHTML =
1406
+ '<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">' +
1407
+ converter._setIframeStyleLinks(targetOptions.get('iframe_cssFileName')) +
1408
+ converter._setAutoHeightStyle(targetOptions.get('height'));
1409
+ frame.contentDocument.body.className = originOptions.get('_editableClass');
1410
+ frame.contentDocument.body.setAttribute('contenteditable', true);
1411
+ },
1412
+
1413
+ __setEditorParams(e) {
1414
+ const frameOptions = e.get('options');
1415
+ const _w = this._w;
1416
+
1417
+ e.set('wwComputedStyle', _w.getComputedStyle(e.get('wysiwyg')));
1418
+
1419
+ if (!frameOptions.get('iframe') && typeof ShadowRoot === 'function') {
1420
+ let child = e.get('wysiwygFrame');
1421
+ while (child) {
1422
+ if (child.shadowRoot) {
1423
+ this._shadowRoot = child.shadowRoot;
1424
+ break;
1425
+ } else if (child instanceof ShadowRoot) {
1426
+ this._shadowRoot = child;
1427
+ break;
1428
+ }
1429
+ child = child.parentNode;
1430
+ }
1431
+ }
1432
+
1433
+ // wisywig attributes
1434
+ const attr = frameOptions.get('editableFrameAttributes');
1435
+ for (const k in attr) {
1436
+ e.get('wysiwyg').setAttribute(k, attr[k]);
1437
+ }
1438
+
1439
+ // init, validate
1440
+ if (frameOptions.get('iframe')) {
1441
+ e.set('_ww', e.get('wysiwygFrame').contentWindow);
1442
+ e.set('_wd', e.get('wysiwygFrame').contentDocument);
1443
+ e.set('wysiwyg', e.get('_wd').body);
1444
+ // e.get('wysiwyg').className += ' ' + options.get('_editableClass');
1445
+ if (frameOptions.get('_defaultStyles').editor) e.get('wysiwyg').style.cssText = frameOptions.get('_defaultStyles').editor;
1446
+ if (frameOptions.get('height') === 'auto') e.set('_iframeAuto', e.get('_wd').body);
1447
+ } else {
1448
+ e.set('_ww', _w);
1449
+ e.set('_wd', this._d);
1450
+ }
1451
+ },
1452
+
1453
+ __registerClass() {
1454
+ // use events
1455
+ this.events = { ...Events(), ...this.options.get('events') };
1456
+ this.triggerEvent = async (eventName, eventData) => {
1457
+ const eventHandler = this.events[eventName];
1458
+ if (typeof eventHandler === 'function') {
1459
+ return await eventHandler({ editor: this, ...eventData });
1460
+ }
1461
+ return env.NO_EVENT;
1462
+ };
1463
+
1464
+ // history function
1465
+ this.history = History(this);
1466
+
1467
+ // eventManager
1468
+ this.eventManager = new EventManager(this);
1469
+
1470
+ // util classes
1471
+ this.offset = new Offset(this);
1472
+ this.shortcuts = new Shortcuts(this);
1473
+ this.notice = new Notice(this);
1474
+ // main classes
1475
+ this.toolbar = new Toolbar(this, { keyName: 'toolbar', balloon: this.isBalloon, balloonAlways: this.isBalloonAlways, inline: this.isInline, res: this._responsiveButtons });
1476
+ if (this.options.has('_subMode'))
1477
+ this.subToolbar = new Toolbar(this, {
1478
+ keyName: 'toolbar.sub',
1479
+ balloon: this.isSubBalloon,
1480
+ balloonAlways: this.isSubBalloonAlways,
1481
+ inline: false,
1482
+ res: this._responsiveButtons_sub
1483
+ });
1484
+ this.selection = new Selection(this);
1485
+ this.html = new HTML(this);
1486
+ this.nodeTransform = new NodeTransform(this);
1487
+ this.component = new Component(this);
1488
+ this.format = new Format(this);
1489
+ this.menu = new Menu(this);
1490
+ this.char = new Char(this);
1491
+ this.viewer = new Viewer(this);
1492
+
1493
+ // register classes to the eventManager
1494
+ ClassInjector.call(this.eventManager, this);
1495
+ // register main classes
1496
+ ClassInjector.call(this.char, this);
1497
+ ClassInjector.call(this.component, this);
1498
+ ClassInjector.call(this.format, this);
1499
+ ClassInjector.call(this.html, this);
1500
+ ClassInjector.call(this.menu, this);
1501
+ ClassInjector.call(this.nodeTransform, this);
1502
+ ClassInjector.call(this.selection, this);
1503
+ ClassInjector.call(this.toolbar, this);
1504
+ ClassInjector.call(this.viewer, this);
1505
+ if (this.options.has('_subMode')) ClassInjector.call(this.subToolbar, this);
1506
+
1507
+ // delete self reference
1508
+ delete this.char.char;
1509
+ delete this.component.component;
1510
+ delete this.format.format;
1511
+ delete this.html.html;
1512
+ delete this.menu.menu;
1513
+ delete this.nodeTransform.nodeTransform;
1514
+ delete this.selection.selection;
1515
+ delete this.toolbar.toolbar;
1516
+ delete this.viewer.viewer;
1517
+ if (this.subToolbar) delete this.subToolbar.subToolbar;
1518
+
1519
+ this._responsiveButtons = this._responsiveButtons_res = null;
1520
+ },
1521
+
1522
+ async __Create(originOptions) {
1523
+ // set modes
1524
+ this.isInline = /inline/i.test(this.options.get('mode'));
1525
+ this.isBalloon = /balloon/i.test(this.options.get('mode'));
1526
+ this.isBalloonAlways = /balloon-always/i.test(this.options.get('mode'));
1527
+ this.isClassic = /classic/i.test(this.options.get('mode'));
1528
+ // set subToolbar modes
1529
+ this.isSubBalloon = /balloon/i.test(this.options.get('_subMode'));
1530
+ this.isSubBalloonAlways = /balloon-always/i.test(this.options.get('_subMode'));
1531
+
1532
+ // register class
1533
+ this.__registerClass();
1534
+
1535
+ // common events
1536
+ this.eventManager._addCommonEvents();
1537
+
1538
+ // init
1539
+ const iframePromises = [];
1540
+ this.applyFrameRoots((e) => {
1541
+ const o = e.get('originElement');
1542
+ const t = e.get('topArea');
1543
+ o.style.display = 'none';
1544
+ t.style.display = 'block';
1545
+ o.parentNode.insertBefore(t, o.nextElementSibling);
1546
+
1547
+ if (e.get('options').get('iframe')) {
1548
+ const iframeLoaded = new Promise((resolve) => {
1549
+ e.get('wysiwygFrame').addEventListener('load', ({ target }) => {
1550
+ this.__setIframeDocument(target, this.options, e.get('options'));
1551
+ resolve();
1552
+ });
1553
+ });
1554
+ iframePromises.push(iframeLoaded);
1555
+ }
1556
+ });
1557
+
1558
+ this.applyFrameRoots((e) => {
1559
+ e.get('wrapper').appendChild(e.get('wysiwygFrame'));
1560
+ });
1561
+
1562
+ if (iframePromises.length > 0) {
1563
+ await Promise.all(iframePromises);
1564
+ }
1565
+
1566
+ this.__editorInit(originOptions);
1567
+ },
1568
+
1569
+ Constructor: Editor
1570
+ };
1571
+
1572
+ function GetResetDiffKey(key) {
1573
+ if (/^statusbar/i.test(key)) return 'statusbar';
1574
+ return key;
1575
+ }
1576
+
1577
+ function CheckResetKeys(keys, plugins, root) {
1578
+ for (let i = 0, len = keys.length, k; i < len; i++) {
1579
+ k = keys[i];
1580
+ if (RO_UNAVAILABD.includes(k) || (plugins && plugins[k])) {
1581
+ console.warn(`[SUNEDITOR.warn.resetOptions] "[${root + k}]" options not available in resetOptions have no effect.`);
1582
+ keys.splice(i--, 1);
1583
+ len--;
1584
+ }
1585
+ }
1586
+ }
1587
+
1588
+ export default Editor;