suneditor 3.0.0-alpha.9 → 3.0.0-beta.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 (315) hide show
  1. package/CONTRIBUTING.md +170 -22
  2. package/{LICENSE.txt → LICENSE} +9 -9
  3. package/README.md +168 -30
  4. package/dist/suneditor.min.css +1 -1
  5. package/dist/suneditor.min.js +1 -1
  6. package/package.json +47 -21
  7. package/src/assets/design/color.css +121 -0
  8. package/src/assets/design/index.css +3 -0
  9. package/src/assets/design/size.css +35 -0
  10. package/src/assets/design/typography.css +37 -0
  11. package/src/assets/icons/defaultIcons.js +232 -0
  12. package/src/assets/suneditor-contents.css +181 -46
  13. package/src/assets/suneditor.css +1403 -650
  14. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  15. package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
  16. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
  17. package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
  18. package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
  19. package/src/core/base/eventManager.js +520 -179
  20. package/src/core/base/history.js +95 -41
  21. package/src/core/class/char.js +26 -11
  22. package/src/core/class/component.js +345 -137
  23. package/src/core/class/format.js +683 -519
  24. package/src/core/class/html.js +485 -305
  25. package/src/core/class/menu.js +133 -47
  26. package/src/core/class/nodeTransform.js +90 -71
  27. package/src/core/class/offset.js +408 -92
  28. package/src/core/class/selection.js +216 -106
  29. package/src/core/class/shortcuts.js +68 -8
  30. package/src/core/class/toolbar.js +106 -116
  31. package/src/core/class/ui.js +422 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +496 -389
  34. package/src/core/section/actives.js +123 -27
  35. package/src/core/section/constructor.js +615 -206
  36. package/src/core/section/context.js +28 -23
  37. package/src/core/section/documentType.js +561 -0
  38. package/src/editorInjector/_classes.js +19 -5
  39. package/src/editorInjector/_core.js +71 -7
  40. package/src/editorInjector/index.js +63 -1
  41. package/src/events.js +622 -0
  42. package/src/helper/clipboard.js +59 -0
  43. package/src/helper/converter.js +202 -26
  44. package/src/helper/dom/domCheck.js +304 -0
  45. package/src/helper/dom/domQuery.js +669 -0
  46. package/src/helper/dom/domUtils.js +557 -0
  47. package/src/helper/dom/index.js +12 -0
  48. package/src/helper/env.js +46 -56
  49. package/src/helper/index.js +10 -4
  50. package/src/helper/keyCodeMap.js +183 -0
  51. package/src/helper/numbers.js +12 -8
  52. package/src/helper/unicode.js +9 -5
  53. package/src/langs/ckb.js +74 -4
  54. package/src/langs/cs.js +72 -2
  55. package/src/langs/da.js +73 -3
  56. package/src/langs/de.js +73 -4
  57. package/src/langs/en.js +23 -3
  58. package/src/langs/es.js +73 -4
  59. package/src/langs/fa.js +75 -3
  60. package/src/langs/fr.js +73 -3
  61. package/src/langs/he.js +73 -4
  62. package/src/langs/hu.js +230 -0
  63. package/src/langs/index.js +7 -3
  64. package/src/langs/it.js +70 -1
  65. package/src/langs/ja.js +72 -4
  66. package/src/langs/km.js +230 -0
  67. package/src/langs/ko.js +22 -2
  68. package/src/langs/lv.js +74 -5
  69. package/src/langs/nl.js +73 -4
  70. package/src/langs/pl.js +73 -4
  71. package/src/langs/pt_br.js +70 -1
  72. package/src/langs/ro.js +74 -5
  73. package/src/langs/ru.js +73 -4
  74. package/src/langs/se.js +73 -4
  75. package/src/langs/tr.js +73 -1
  76. package/src/langs/{ua.js → uk.js} +75 -6
  77. package/src/langs/ur.js +77 -8
  78. package/src/langs/zh_cn.js +74 -5
  79. package/src/modules/ApiManager.js +77 -54
  80. package/src/modules/Browser.js +667 -0
  81. package/src/modules/ColorPicker.js +162 -102
  82. package/src/modules/Controller.js +273 -142
  83. package/src/modules/Figure.js +925 -484
  84. package/src/modules/FileManager.js +121 -69
  85. package/src/modules/HueSlider.js +113 -61
  86. package/src/modules/Modal.js +291 -122
  87. package/src/modules/ModalAnchorEditor.js +383 -234
  88. package/src/modules/SelectMenu.js +270 -168
  89. package/src/modules/_DragHandle.js +2 -1
  90. package/src/modules/index.js +3 -3
  91. package/src/plugins/browser/audioGallery.js +83 -0
  92. package/src/plugins/browser/fileBrowser.js +103 -0
  93. package/src/plugins/browser/fileGallery.js +83 -0
  94. package/src/plugins/browser/imageGallery.js +81 -0
  95. package/src/plugins/browser/videoGallery.js +103 -0
  96. package/src/plugins/command/blockquote.js +40 -27
  97. package/src/plugins/command/exportPDF.js +134 -0
  98. package/src/plugins/command/fileUpload.js +229 -162
  99. package/src/plugins/command/list_bulleted.js +83 -47
  100. package/src/plugins/command/list_numbered.js +83 -47
  101. package/src/plugins/dropdown/align.js +66 -54
  102. package/src/plugins/dropdown/backgroundColor.js +63 -49
  103. package/src/plugins/dropdown/font.js +71 -47
  104. package/src/plugins/dropdown/fontColor.js +63 -48
  105. package/src/plugins/dropdown/formatBlock.js +70 -33
  106. package/src/plugins/dropdown/hr.js +92 -51
  107. package/src/plugins/dropdown/layout.js +37 -26
  108. package/src/plugins/dropdown/lineHeight.js +54 -38
  109. package/src/plugins/dropdown/list.js +60 -45
  110. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  111. package/src/plugins/dropdown/table.js +2003 -813
  112. package/src/plugins/dropdown/template.js +38 -26
  113. package/src/plugins/dropdown/textStyle.js +43 -31
  114. package/src/plugins/field/mention.js +147 -86
  115. package/src/plugins/index.js +32 -6
  116. package/src/plugins/input/fontSize.js +161 -108
  117. package/src/plugins/input/pageNavigator.js +70 -0
  118. package/src/plugins/modal/audio.js +358 -173
  119. package/src/plugins/modal/drawing.js +531 -0
  120. package/src/plugins/modal/embed.js +886 -0
  121. package/src/plugins/modal/image.js +674 -362
  122. package/src/plugins/modal/link.js +100 -71
  123. package/src/plugins/modal/math.js +367 -167
  124. package/src/plugins/modal/video.js +691 -335
  125. package/src/plugins/popup/anchor.js +222 -0
  126. package/src/suneditor.js +50 -13
  127. package/src/themes/dark.css +122 -0
  128. package/src/typedef.js +130 -0
  129. package/types/assets/icons/defaultIcons.d.ts +153 -0
  130. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  131. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  132. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  133. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  134. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  135. package/types/core/base/eventManager.d.ts +385 -0
  136. package/types/core/base/history.d.ts +81 -0
  137. package/types/core/class/char.d.ts +60 -0
  138. package/types/core/class/component.d.ts +212 -0
  139. package/types/core/class/format.d.ts +616 -0
  140. package/types/core/class/html.d.ts +422 -0
  141. package/types/core/class/menu.d.ts +126 -0
  142. package/types/core/class/nodeTransform.d.ts +93 -0
  143. package/types/core/class/offset.d.ts +522 -0
  144. package/types/core/class/selection.d.ts +188 -0
  145. package/types/core/class/shortcuts.d.ts +142 -0
  146. package/types/core/class/toolbar.d.ts +189 -0
  147. package/types/core/class/ui.d.ts +164 -0
  148. package/types/core/class/viewer.d.ts +140 -0
  149. package/types/core/editor.d.ts +610 -0
  150. package/types/core/section/actives.d.ts +46 -0
  151. package/types/core/section/constructor.d.ts +777 -0
  152. package/types/core/section/context.d.ts +45 -0
  153. package/types/core/section/documentType.d.ts +178 -0
  154. package/types/editorInjector/_classes.d.ts +41 -0
  155. package/types/editorInjector/_core.d.ts +92 -0
  156. package/types/editorInjector/index.d.ts +71 -0
  157. package/types/events.d.ts +273 -0
  158. package/types/helper/clipboard.d.ts +12 -0
  159. package/types/helper/converter.d.ts +197 -0
  160. package/types/helper/dom/domCheck.d.ts +189 -0
  161. package/types/helper/dom/domQuery.d.ts +223 -0
  162. package/types/helper/dom/domUtils.d.ts +226 -0
  163. package/types/helper/dom/index.d.ts +9 -0
  164. package/types/helper/env.d.ts +132 -0
  165. package/types/helper/index.d.ts +174 -0
  166. package/types/helper/keyCodeMap.d.ts +110 -0
  167. package/types/helper/numbers.d.ts +46 -0
  168. package/types/helper/unicode.d.ts +28 -0
  169. package/types/index.d.ts +120 -0
  170. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
  171. package/types/langs/ckb.d.ts +3 -0
  172. package/types/langs/cs.d.ts +3 -0
  173. package/types/langs/da.d.ts +3 -0
  174. package/types/langs/de.d.ts +3 -0
  175. package/types/langs/en.d.ts +3 -0
  176. package/types/langs/es.d.ts +3 -0
  177. package/types/langs/fa.d.ts +3 -0
  178. package/types/langs/fr.d.ts +3 -0
  179. package/types/langs/he.d.ts +3 -0
  180. package/types/langs/hu.d.ts +3 -0
  181. package/types/langs/index.d.ts +54 -0
  182. package/types/langs/it.d.ts +3 -0
  183. package/types/langs/ja.d.ts +3 -0
  184. package/types/langs/km.d.ts +3 -0
  185. package/types/langs/ko.d.ts +3 -0
  186. package/types/langs/lv.d.ts +3 -0
  187. package/types/langs/nl.d.ts +3 -0
  188. package/types/langs/pl.d.ts +3 -0
  189. package/types/langs/pt_br.d.ts +3 -0
  190. package/types/langs/ro.d.ts +3 -0
  191. package/types/langs/ru.d.ts +3 -0
  192. package/types/langs/se.d.ts +3 -0
  193. package/types/langs/tr.d.ts +3 -0
  194. package/types/langs/uk.d.ts +3 -0
  195. package/types/langs/ur.d.ts +3 -0
  196. package/types/langs/zh_cn.d.ts +3 -0
  197. package/types/modules/ApiManager.d.ts +125 -0
  198. package/types/modules/Browser.d.ts +326 -0
  199. package/types/modules/ColorPicker.d.ts +131 -0
  200. package/types/modules/Controller.d.ts +251 -0
  201. package/types/modules/Figure.d.ts +517 -0
  202. package/types/modules/FileManager.d.ts +202 -0
  203. package/types/modules/HueSlider.d.ts +136 -0
  204. package/types/modules/Modal.d.ts +111 -0
  205. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  206. package/types/modules/SelectMenu.d.ts +194 -0
  207. package/types/modules/_DragHandle.d.ts +7 -0
  208. package/types/modules/index.d.ts +26 -0
  209. package/types/plugins/browser/audioGallery.d.ts +55 -0
  210. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  211. package/types/plugins/browser/fileGallery.d.ts +55 -0
  212. package/types/plugins/browser/imageGallery.d.ts +51 -0
  213. package/types/plugins/browser/videoGallery.d.ts +57 -0
  214. package/types/plugins/command/blockquote.d.ts +28 -0
  215. package/types/plugins/command/exportPDF.d.ts +46 -0
  216. package/types/plugins/command/fileUpload.d.ts +156 -0
  217. package/types/plugins/command/list_bulleted.d.ts +46 -0
  218. package/types/plugins/command/list_numbered.d.ts +46 -0
  219. package/types/plugins/dropdown/align.d.ts +60 -0
  220. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  221. package/types/plugins/dropdown/font.d.ts +54 -0
  222. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  223. package/types/plugins/dropdown/formatBlock.d.ts +54 -0
  224. package/types/plugins/dropdown/hr.d.ts +71 -0
  225. package/types/plugins/dropdown/layout.d.ts +40 -0
  226. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  227. package/types/plugins/dropdown/list.d.ts +39 -0
  228. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  229. package/types/plugins/dropdown/table.d.ts +627 -0
  230. package/types/plugins/dropdown/template.d.ts +40 -0
  231. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  232. package/types/plugins/field/mention.d.ts +102 -0
  233. package/types/plugins/index.d.ts +107 -0
  234. package/types/plugins/input/fontSize.d.ts +170 -0
  235. package/types/plugins/input/pageNavigator.d.ts +28 -0
  236. package/types/plugins/modal/audio.d.ts +269 -0
  237. package/types/plugins/modal/drawing.d.ts +246 -0
  238. package/types/plugins/modal/embed.d.ts +387 -0
  239. package/types/plugins/modal/image.d.ts +451 -0
  240. package/types/plugins/modal/link.d.ts +128 -0
  241. package/types/plugins/modal/math.d.ts +193 -0
  242. package/types/plugins/modal/video.d.ts +485 -0
  243. package/types/plugins/popup/anchor.d.ts +56 -0
  244. package/types/suneditor.d.ts +51 -0
  245. package/types/typedef.d.ts +233 -0
  246. package/.eslintignore +0 -7
  247. package/.eslintrc.json +0 -64
  248. package/src/assets/icons/_default.js +0 -194
  249. package/src/core/base/events.js +0 -320
  250. package/src/core/class/notice.js +0 -42
  251. package/src/helper/domUtils.js +0 -1177
  252. package/src/modules/FileBrowser.js +0 -271
  253. package/src/plugins/command/exportPdf.js +0 -168
  254. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  255. package/src/themes/test.css +0 -61
  256. package/typings/CommandPlugin.d.ts +0 -8
  257. package/typings/DialogPlugin.d.ts +0 -20
  258. package/typings/FileBrowserPlugin.d.ts +0 -30
  259. package/typings/Module.d.ts +0 -15
  260. package/typings/Plugin.d.ts +0 -42
  261. package/typings/SubmenuPlugin.d.ts +0 -8
  262. package/typings/_classes.d.ts +0 -17
  263. package/typings/_colorPicker.d.ts +0 -60
  264. package/typings/_core.d.ts +0 -55
  265. package/typings/align.d.ts +0 -5
  266. package/typings/audio.d.ts +0 -5
  267. package/typings/backgroundColor.d.ts +0 -5
  268. package/typings/blockquote.d.ts +0 -5
  269. package/typings/char.d.ts +0 -39
  270. package/typings/component.d.ts +0 -38
  271. package/typings/context.d.ts +0 -39
  272. package/typings/converter.d.ts +0 -33
  273. package/typings/dialog.d.ts +0 -28
  274. package/typings/domUtils.d.ts +0 -361
  275. package/typings/editor.d.ts +0 -7
  276. package/typings/editor.ts +0 -542
  277. package/typings/env.d.ts +0 -70
  278. package/typings/eventManager.d.ts +0 -37
  279. package/typings/events.d.ts +0 -262
  280. package/typings/fileBrowser.d.ts +0 -42
  281. package/typings/fileManager.d.ts +0 -67
  282. package/typings/font.d.ts +0 -5
  283. package/typings/fontColor.d.ts +0 -5
  284. package/typings/fontSize.d.ts +0 -5
  285. package/typings/format.d.ts +0 -191
  286. package/typings/formatBlock.d.ts +0 -5
  287. package/typings/history.d.ts +0 -48
  288. package/typings/horizontalRule.d.ts +0 -5
  289. package/typings/image.d.ts +0 -5
  290. package/typings/imageGallery.d.ts +0 -5
  291. package/typings/index.d.ts +0 -21
  292. package/typings/index.modules.d.ts +0 -11
  293. package/typings/index.plugins.d.ts +0 -58
  294. package/typings/lineHeight.d.ts +0 -5
  295. package/typings/link.d.ts +0 -5
  296. package/typings/list.d.ts +0 -5
  297. package/typings/math.d.ts +0 -5
  298. package/typings/mediaContainer.d.ts +0 -25
  299. package/typings/mention.d.ts +0 -5
  300. package/typings/node.d.ts +0 -57
  301. package/typings/notice.d.ts +0 -16
  302. package/typings/numbers.d.ts +0 -29
  303. package/typings/offset.d.ts +0 -24
  304. package/typings/options.d.ts +0 -589
  305. package/typings/paragraphStyle.d.ts +0 -5
  306. package/typings/resizing.d.ts +0 -141
  307. package/typings/selection.d.ts +0 -94
  308. package/typings/shortcuts.d.ts +0 -13
  309. package/typings/suneditor.d.ts +0 -9
  310. package/typings/table.d.ts +0 -5
  311. package/typings/template.d.ts +0 -5
  312. package/typings/textStyle.d.ts +0 -5
  313. package/typings/toolbar.d.ts +0 -32
  314. package/typings/unicode.d.ts +0 -25
  315. package/typings/video.d.ts +0 -5
@@ -1,9 +1,9 @@
1
1
  import EditorInjector from '../editorInjector';
2
2
  import { Controller, SelectMenu, _DragHandle } from '../modules';
3
- import { domUtils, numbers, env, converter } from '../helper';
3
+ import { dom, numbers, env, converter, keyCodeMap } from '../helper';
4
4
 
5
5
  const { ON_OVER_COMPONENT } = env;
6
- const DIRECTION_CURSOR_MAP = { tl: 'nw-resize', tr: 'ne-resize', bl: 'sw-resize', br: 'se-resize', lw: 'w-resize', th: 'n-resize', rw: 'e-resize', bh: 's-resize' };
6
+ const DIRECTION_CURSOR_MAP = { tl: 'nwse-resize', tr: 'nesw-resize', bl: 'nesw-resize', br: 'nwse-resize', lw: 'ew-resize', th: 'ns-resize', rw: 'ew-resize', bh: 'ns-resize' };
7
7
  const DIR_DIAGONAL = 'tl|bl|tr|br';
8
8
  const DIR_W = 'lw|rw';
9
9
  let __resizing_p_wh = false;
@@ -11,234 +11,334 @@ let __resizing_p_ow = false;
11
11
  let __resizing_cw = 0;
12
12
  let __resizing_sw = 0;
13
13
 
14
- const Figure = function (inst, controls, params) {
15
- EditorInjector.call(this, inst.editor);
16
- this.kind = inst.constructor.key || inst.constructor.name;
17
- this._alignIcons = {
18
- none: this.icons.format_float_none,
19
- left: this.icons.format_float_left,
20
- right: this.icons.format_float_right,
21
- center: this.icons.format_float_center
22
- };
23
-
24
- // modules
25
- this._action = {};
26
- const controllerEl = CreateHTML_controller(this, controls || []);
27
- this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true }, this.kind);
28
- // align selectmenu
29
- this.alignButton = controllerEl.querySelector('[data-command="onalign"]');
30
- const alignMenus = CreateAlign(this, this.alignButton);
31
- if (alignMenus) {
32
- this.selectMenu_align = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
33
- this.selectMenu_align.on(this.alignButton, SetMenuAlign.bind(this), { class: 'se-resizing-align-list' });
34
- this.selectMenu_align.create(alignMenus.items, alignMenus.html);
35
- }
36
- // resize selectmenu
37
- this.resizeButton = controllerEl.querySelector('[data-command="onresize"]');
38
- const resizeMenus = CreateResize(this, this.resizeButton);
39
- if (resizeMenus) {
40
- this.selectMenu_resize = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr' });
41
- this.selectMenu_resize.on(this.resizeButton, SetResize.bind(this));
42
- this.selectMenu_resize.create(resizeMenus.items, resizeMenus.html);
43
- }
44
-
45
- // members
46
- this.inst = inst;
47
- this.sizeUnit = params.sizeUnit || 'px';
48
- this.autoRatio = params.autoRatio;
49
- this.isVertical = false;
50
- this.percentageButtons = controllerEl.querySelectorAll('[data-command="resize_percent"]');
51
- this.captionButton = controllerEl.querySelector('[data-command="caption"]');
52
- this.align = 'none';
53
- this._element = null;
54
- this._cover = null;
55
- this._container = null;
56
- this._caption = null;
57
- this._width = 0;
58
- this._height = 0;
59
- this._element_w = 0;
60
- this._element_h = 0;
61
- this._element_l = 0;
62
- this._element_t = 0;
63
- this._resize_w = 0;
64
- this._resize_h = 0;
65
- this._resizeClientX = 0;
66
- this._resizeClientY = 0;
67
- this._resize_direction = '';
68
- this._floatClassStr = '__se__float-none|__se__float-left|__se__float-center|__se__float-right';
69
- this.__preventSizechange = false;
70
- this.__revertSize = { w: '', h: '' };
71
- this.__offset = {};
72
- this.__offContainer = OffFigureContainer.bind(this);
73
- this.__containerResizing = ContainerResizing.bind(this);
74
- this.__containerResizingOff = ContainerResizingOff.bind(this);
75
- this.__containerResizingESC = ContainerResizingESC.bind(this);
76
- this.__onContainerEvent = null;
77
- this.__offContainerEvent = null;
78
- this.__onResizeESCEvent = null;
79
- this.__fileManagerInfo = false;
80
-
81
- // init
82
- this.eventManager.addEvent(this.alignButton, 'click', OnClick_alignButton.bind(this));
83
- this.eventManager.addEvent(this.resizeButton, 'click', OnClick_resizeButton.bind(this));
84
- this.editor.applyFrameRoots((e) => {
85
- if (!e.get('wrapper').querySelector('.se-controller.se-resizing-container')) {
86
- // resizing
87
- const main = CreateHTML_resizeDot();
88
- const handles = main.querySelectorAll('.se-resize-dot > span');
89
- e.set('_figure', {
90
- main: main,
91
- border: main.querySelector('.se-resize-dot'),
92
- display: main.querySelector('.se-resize-display'),
93
- handles: handles
94
- });
95
- e.get('wrapper').appendChild(main);
96
- this.eventManager.addEvent(handles, 'mousedown', OnResizeContainer.bind(this));
97
- }
98
- });
99
- };
14
+ /**
15
+ * @typedef {Object} FigureParams
16
+ * @property {string} [sizeUnit="px"] Size unit
17
+ * @property {{ current: string, default: string }} [autoRatio=null] Auto ratio { current: '00%', default: '00%' }
18
+ */
100
19
 
101
20
  /**
102
- * @description Create a container for the resizing component and insert the element.
103
- * @param {Element} element Target element
104
- * @param {string} className Class name of container (fixed: se-component)
105
- * @returns {object} {container, cover, caption}
21
+ * @typedef {Object} FigureInfo
22
+ * @property {HTMLElement} target Target element (img, iframe, video, audio, table, etc.)
23
+ * @property {HTMLElement} container Container element (div.se-component|span.se-component.se-inline-component)
24
+ * @property {?HTMLElement} cover Cover element (FIGURE|null)
25
+ * @property {?HTMLElement} inlineCover Inline cover element (span.se-inline-component)
26
+ * @property {?HTMLElement} caption Caption element (FIGCAPTION)
106
27
  */
107
- Figure.CreateContainer = function (element, className) {
108
- domUtils.createElement('DIV', { class: 'se-component' + (className ? ' ' + className : '') }, domUtils.createElement('FIGURE', null, element));
109
- return Figure.GetContainer(element);
110
- };
111
28
 
112
29
  /**
113
- * @description Return HTML string of caption(FIGCAPTION) element
114
- * @param {Element} cover Cover element(FIGURE). "CreateContainer().cover"
115
- * @returns {Element} caption element
30
+ * @typedef {Object} FigureTargetInfo
31
+ * @property {HTMLElement} container Container element (div.se-component|span.se-component.se-inline-component)
32
+ * @property {?HTMLElement=} cover Cover element (FIGURE|null)
33
+ * @property {?HTMLElement=} caption Caption element (FIGCAPTION)
34
+ * @property {string} [align] - Alignment of the element.
35
+ * @property {{w:number, h:number}} [ratio] - The aspect ratio of the element.
36
+ * @property {string|number} [w] - Width of the element.
37
+ * @property {string|number} [h] - Height of the element.
38
+ * @property {number} [t] - Top position.
39
+ * @property {number} [l] - Left position.
40
+ * @property {string|number} width - Width, can be a number or 'auto'.
41
+ * @property {string|number} height - Height, can be a number or 'auto'.
42
+ * @property {number} [originWidth] - Original width from `naturalWidth` or `offsetWidth`.
43
+ * @property {number} [originHeight] - Original height from `naturalHeight` or `offsetHeight`.
116
44
  */
117
- Figure.CreateCaption = function (cover, text) {
118
- const caption = domUtils.createElement('FIGCAPTION', null, '<div>' + text + '</div>');
119
- cover.appendChild(caption);
120
- return caption;
121
- };
122
45
 
123
46
  /**
124
- * @description Get the element's container(.se-component) info.
125
- * @param {Element} element Target element
126
- * @returns {object} {container, cover, caption}
47
+ * @typedef {Array<Array<
48
+ * string |
49
+ * {
50
+ * action: (element: Node, value: string, target: Node) => void,
51
+ * command: string,
52
+ * value: string,
53
+ * title: string,
54
+ * icon: string
55
+ * }
56
+ * >>} FigureControls
57
+ * "mirror". "rotate", "caption", "revert", "edit", "copy", "remove", "as", "resize_auto,[number]"
127
58
  */
128
- Figure.GetContainer = function (element) {
129
- const cover = domUtils.getParentElement(element, 'FIGURE');
130
- return {
131
- target: element,
132
- container: domUtils.getParentElement(element, Figure.__is) || cover,
133
- cover: cover,
134
- caption: domUtils.getEdgeChild(element.parentElement, 'FIGCAPTION')
135
- };
136
- };
137
59
 
138
60
  /**
139
- * @description Ratio calculation
140
- * @param {string|number} w Width size
141
- * @param {string|number} h Height size
142
- * @param {defaultSizeUnit|undefined|null} defaultSizeUnit Default size unit (default: "px")
143
- * @return {{w: number, h: number}}
61
+ * @class
62
+ * @description Controller module class
144
63
  */
145
- Figure.GetRatio = function (w, h, defaultSizeUnit) {
146
- let rw = 1,
147
- rh = 1;
148
- if (/\d+/.test(w) && /\d+/.test(h)) {
149
- const xUnit = (!numbers.is(w) && w.replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
150
- const yUnit = (!numbers.is(h) && h.replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
151
- if (xUnit === yUnit) {
152
- const w_number = numbers.get(w, 4);
153
- const h_number = numbers.get(h, 4);
154
- rw = w_number / h_number;
155
- rh = h_number / w_number;
64
+ class Figure extends EditorInjector {
65
+ /**
66
+ * @constructor
67
+ * @param {*} inst The instance object that called the constructor.
68
+ * @param {FigureControls} controls Controller button array
69
+ * @param {FigureParams} params Figure options
70
+ */
71
+ constructor(inst, controls, params) {
72
+ super(inst.editor);
73
+ this.kind = inst.constructor.key || inst.constructor.name;
74
+ this._alignIcons = {
75
+ none: this.icons.format_float_none,
76
+ left: this.icons.format_float_left,
77
+ right: this.icons.format_float_right,
78
+ center: this.icons.format_float_center
79
+ };
80
+
81
+ // modules
82
+ /** @type {Object<string, *>} */
83
+ this._action = {};
84
+ const controllerEl = CreateHTML_controller(this, controls || []);
85
+ this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true }, this.kind);
86
+ // align selectmenu
87
+ this.alignButton = controllerEl.querySelector('[data-command="onalign"]');
88
+ const alignMenus = CreateAlign(this, this.alignButton);
89
+ if (alignMenus) {
90
+ this.selectMenu_align = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
91
+ this.selectMenu_align.on(this.alignButton, this.#SetMenuAlign.bind(this), { class: 'se-figure-select-list' });
92
+ this.selectMenu_align.create(alignMenus.items, alignMenus.html);
156
93
  }
94
+ // as [block, inline] selectmenu
95
+ this.asButton = controllerEl.querySelector('[data-command="onas"]');
96
+ const asMenus = CreateAs(this, this.asButton);
97
+ if (asMenus) {
98
+ this.selectMenu_as = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
99
+ this.selectMenu_as.on(this.asButton, this.#SetMenuAs.bind(this), { class: 'se-figure-select-list' });
100
+ this.selectMenu_as.create(asMenus.items, asMenus.html);
101
+ }
102
+ // resize selectmenu
103
+ this.resizeButton = controllerEl.querySelector('[data-command="onresize"]');
104
+ const resizeMenus = CreateResize(this, this.resizeButton);
105
+ if (resizeMenus) {
106
+ this.selectMenu_resize = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr' });
107
+ this.selectMenu_resize.on(this.resizeButton, this.#SetResize.bind(this));
108
+ this.selectMenu_resize.create(resizeMenus.items, resizeMenus.html);
109
+ }
110
+
111
+ // members
112
+ this.inst = inst;
113
+ this.sizeUnit = params.sizeUnit || 'px';
114
+ this.autoRatio = params.autoRatio;
115
+ this.isVertical = false;
116
+ this.percentageButtons = controllerEl.querySelectorAll('[data-command="resize_percent"]');
117
+ this.captionButton = controllerEl.querySelector('[data-command="caption"]');
118
+ this.align = 'none';
119
+ this.as = 'block';
120
+ this._element = null;
121
+ this._cover = null;
122
+ this._inlineCover = null;
123
+ this._container = null;
124
+ this._caption = null;
125
+ this._width = '';
126
+ this._height = '';
127
+ this._resize_w = 0;
128
+ this._resize_h = 0;
129
+ this._element_w = 0;
130
+ this._element_h = 0;
131
+ this._element_l = 0;
132
+ this._element_t = 0;
133
+ this._resizeClientX = 0;
134
+ this._resizeClientY = 0;
135
+ this._resize_direction = '';
136
+ this._floatClassStr = '__se__float-none|__se__float-left|__se__float-center|__se__float-right';
137
+ this.__preventSizechange = false;
138
+ this.__revertSize = { w: '', h: '' };
139
+ /** @type {{left?: number, top?: number}} */
140
+ this.__offset = {};
141
+ this.__offContainer = this.#OffFigureContainer.bind(this);
142
+ this.__containerResizing = this.#ContainerResizing.bind(this);
143
+ this.__containerResizingOff = this.#ContainerResizingOff.bind(this);
144
+ this.__containerResizingESC = this.#ContainerResizingESC.bind(this);
145
+ this.__onContainerEvent = null;
146
+ this.__offContainerEvent = null;
147
+ this.__onResizeESCEvent = null;
148
+ this.__fileManagerInfo = false;
149
+
150
+ // init
151
+ this.eventManager.addEvent(this.alignButton, 'click', this.#OnClick_alignButton.bind(this));
152
+ this.eventManager.addEvent(this.asButton, 'click', this.#OnClick_asButton.bind(this));
153
+ this.eventManager.addEvent(this.resizeButton, 'click', this.#OnClick_resizeButton.bind(this));
154
+ this.editor.applyFrameRoots((e) => {
155
+ if (!e.get('wrapper').querySelector('.se-controller.se-resizing-container')) {
156
+ // resizing
157
+ const main = CreateHTML_resizeDot();
158
+ const handles = main.querySelectorAll('.se-resize-dot > span');
159
+ e.set('_figure', {
160
+ main: main,
161
+ border: main.querySelector('.se-resize-dot'),
162
+ display: main.querySelector('.se-resize-display'),
163
+ handles: handles
164
+ });
165
+ e.get('wrapper').appendChild(main);
166
+ this.eventManager.addEvent(handles, 'mousedown', this.#OnResizeContainer.bind(this));
167
+ }
168
+ });
157
169
  }
158
170
 
159
- return {
160
- w: numbers.get(rw, 4),
161
- h: numbers.get(rh, 4)
162
- };
163
- };
171
+ /**
172
+ * @description Create a container for the resizing component and insert the element.
173
+ * @param {Node} element Target element
174
+ * @param {string=} className Class name of container (fixed: se-component)
175
+ * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
176
+ */
177
+ static CreateContainer(element, className) {
178
+ dom.utils.createElement('DIV', { class: 'se-component' + (className ? ' ' + className : '') }, dom.utils.createElement('FIGURE', null, element));
179
+ return Figure.GetContainer(element);
180
+ }
164
181
 
165
- /**
166
- * @description Ratio calculation
167
- * @param {string|number} w Width size
168
- * @param {string|number} h Height size
169
- * @param {defaultSizeUnit|undefined|null} defaultSizeUnit Default size unit (default: "px")
170
- * @param {{w: number, h: number}} ratio Ratio size (Figure.GetRatio)
171
- * @return {{w: string|number, h: string|number}}
172
- */
173
- Figure.CalcRatio = function (w, h, defaultSizeUnit, ratio) {
174
- if (/\d+/.test(w) && /\d+/.test(h)) {
175
- const xUnit = (!numbers.is(w) && w.replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
176
- const yUnit = (!numbers.is(h) && h.replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
177
- if (xUnit === yUnit) {
178
- const dec = xUnit === '%' ? 2 : 0;
179
- const ow = w;
180
- const oh = h;
181
- h = numbers.get(ratio.h * numbers.get(ow, dec), dec) + yUnit;
182
- w = numbers.get(ratio.w * numbers.get(oh, dec), dec) + xUnit;
182
+ /**
183
+ * @description Create a container for the inline resizing component and insert the element.
184
+ * @param {Node} element Target element
185
+ * @param {string} [className] Class name of container (fixed: se-component se-inline-component)
186
+ * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
187
+ */
188
+ static CreateInlineContainer(element, className) {
189
+ dom.utils.createElement('SPAN', { class: 'se-component se-inline-component' + (className ? ' ' + className : '') }, element);
190
+ return Figure.GetContainer(element);
191
+ }
192
+
193
+ /**
194
+ * @description Return HTML string of caption(FIGCAPTION) element
195
+ * @param {Node} cover Cover element(FIGURE). "CreateContainer().cover"
196
+ * @returns {HTMLElement} caption element
197
+ */
198
+ static CreateCaption(cover, text) {
199
+ const caption = dom.utils.createElement('FIGCAPTION', null, '<div>' + text + '</div>');
200
+ cover.appendChild(caption);
201
+ return caption;
202
+ }
203
+
204
+ /**
205
+ * @description Get the element's container(.se-component) info.
206
+ * @param {Node} element Target element
207
+ * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
208
+ */
209
+ static GetContainer(element) {
210
+ const cover = dom.query.getParentElement(element, 'FIGURE', 2);
211
+ const inlineCover = dom.query.getParentElement(element, 'SPAN', 2);
212
+ return {
213
+ target: /** @type {HTMLElement} */ (element),
214
+ container: /** @type {HTMLElement} */ (dom.query.getParentElement(element, Figure.is, 2) || cover),
215
+ cover: /** @type {HTMLElement} */ (cover),
216
+ inlineCover: dom.utils.hasClass(inlineCover, 'se-inline-component') ? /** @type {HTMLElement} */ (inlineCover) : null,
217
+ caption: /** @type {HTMLElement} */ (dom.query.getEdgeChild(element.parentElement, 'FIGCAPTION', false))
218
+ };
219
+ }
220
+
221
+ /**
222
+ * @description Ratio calculation
223
+ * @param {string|number} w Width size
224
+ * @param {string|number} h Height size
225
+ * @param {?string=} [defaultSizeUnit="px"] Default size unit (default: "px")
226
+ * @return {{w: number, h: number}}
227
+ */
228
+ static GetRatio(w, h, defaultSizeUnit) {
229
+ let rw = 1,
230
+ rh = 1;
231
+ if (/\d+/.test(w + '') && /\d+/.test(h + '')) {
232
+ const xUnit = (!numbers.is(w) && String(w).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
233
+ const yUnit = (!numbers.is(h) && String(h).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
234
+ if (xUnit === yUnit) {
235
+ const w_number = numbers.get(w, 4);
236
+ const h_number = numbers.get(h, 4);
237
+ rw = w_number / h_number;
238
+ rh = h_number / w_number;
239
+ }
183
240
  }
241
+
242
+ return {
243
+ w: numbers.get(rw, 4),
244
+ h: numbers.get(rh, 4)
245
+ };
184
246
  }
185
247
 
186
- return {
187
- w: w,
188
- h: h
189
- };
190
- };
248
+ /**
249
+ * @description Ratio calculation
250
+ * @param {string|number} w Width size
251
+ * @param {string|number} h Height size
252
+ * @param {string} defaultSizeUnit Default size unit (default: "px")
253
+ * @param {{w: number, h: number}} ratio Ratio size (Figure.GetRatio)
254
+ * @return {{w: string|number, h: string|number}}
255
+ */
256
+ static CalcRatio(w, h, defaultSizeUnit, ratio) {
257
+ if (/\d+/.test(w + '') && /\d+/.test(h + '')) {
258
+ const xUnit = (!numbers.is(w) && String(w).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
259
+ const yUnit = (!numbers.is(h) && String(h).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
260
+ if (xUnit === yUnit) {
261
+ const dec = xUnit === '%' ? 2 : 0;
262
+ const ow = w;
263
+ const oh = h;
264
+ h = numbers.get(ratio.h * numbers.get(ow, dec), dec) + yUnit;
265
+ w = numbers.get(ratio.w * numbers.get(oh, dec), dec) + xUnit;
266
+ }
267
+ }
191
268
 
192
- /**
193
- * @description It is judged whether it is the component[img, iframe, video, audio, table] cover(class="se-component") and table, hr
194
- * @param {Node} element Target element
195
- * @returns {boolean}
196
- * @private
197
- */
198
- Figure.__is = function (element) {
199
- return domUtils.hasClass(element, 'se-component') || /^(HR)$/.test(element?.nodeName);
200
- };
269
+ return {
270
+ w: w,
271
+ h: h
272
+ };
273
+ }
274
+
275
+ /**
276
+ * @description It is judged whether it is the component[img, iframe, video, audio, table] cover(class="se-component") and table, hr
277
+ * @param {Node} element Target element
278
+ * @returns {boolean}
279
+ */
280
+ static is(element) {
281
+ return dom.utils.hasClass(element, 'se-component') || /^(HR)$/.test(element?.nodeName);
282
+ }
201
283
 
202
- Figure.prototype = {
203
284
  /**
204
- * @override controller
285
+ * @description Close the figure's controller
205
286
  */
206
287
  close() {
207
- this.editor._antiBlur = false;
208
- domUtils.removeClass(this._cover, 'se-figure-selected');
288
+ this.editor._preventBlur = false;
289
+ dom.utils.removeClass(this._cover, 'se-figure-selected');
209
290
  this.controller.close();
210
-
211
- if (domUtils.hasClass(this._w.event?.target, 'se-drag-handle|sun-editor-editable')) return;
212
291
  this.component._removeDragEvent();
213
- },
292
+ }
214
293
 
215
- open(target, { nonResizing, nonSizeInfo, nonBorder, figureTarget, __fileManagerInfo }) {
216
- if (!target) {
217
- console.warn('[SUNEDITOR.modules.Figure.open] The target element is null.');
294
+ /**
295
+ * @description Open the figure's controller
296
+ * @param {Node} targetNode Target element
297
+ * @param {Object} params params
298
+ * @param {boolean} [params.nonResizing=false] Do not display the resizing button
299
+ * @param {boolean} [params.nonSizeInfo=false] Do not display the size information
300
+ * @param {boolean} [params.nonBorder=false] Do not display the selected style line
301
+ * @param {boolean} [params.figureTarget=false] If true, the target is a figure element
302
+ * @param {boolean} [params.__fileManagerInfo=false] If true, the file manager is called
303
+ * @returns {FigureTargetInfo|undefined} figure target info
304
+ */
305
+ open(targetNode, { nonResizing, nonSizeInfo, nonBorder, figureTarget, __fileManagerInfo }) {
306
+ if (!targetNode) {
307
+ console.warn('[SUNEDITOR.modules.Figure.open] The "targetNode" is null.');
218
308
  return;
219
309
  }
220
310
 
221
311
  if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
222
- this.editor._offCurrentController();
312
+ this.ui._offCurrentController();
223
313
  } else {
224
314
  nonBorder = true;
225
315
  }
226
316
 
227
- const figureInfo = Figure.GetContainer(target);
228
- if (!figureInfo.container) return { container: null, cover: null };
317
+ const figureInfo = Figure.GetContainer(targetNode);
318
+ const target = figureInfo.target;
319
+ let exceptionFormat = false;
320
+ if (!figureInfo.container) {
321
+ if (!this.options.get('strictMode').formatFilter) {
322
+ figureInfo.container = target;
323
+ figureInfo.cover = target;
324
+ exceptionFormat = true;
325
+ } else {
326
+ return {
327
+ container: null,
328
+ cover: null,
329
+ width: target.style.width || (!numbers.is(/** @type {HTMLImageElement} */ (target).width) ? /** @type {HTMLImageElement} */ (target).width : '') || '',
330
+ height: target.style.height || (!numbers.is(/** @type {HTMLImageElement} */ (target).height) ? /** @type {HTMLImageElement} */ (target).height : '') || ''
331
+ };
332
+ }
333
+ }
229
334
 
230
335
  _DragHandle.set('__figureInst', this);
231
336
 
232
- this._cover = figureInfo.cover;
233
- this._container = figureInfo.container;
234
- this._caption = figureInfo.caption;
235
- this._element = target;
236
- this.align = (this._container.className.match(/(?:^|\s)__se__float-(none|left|center|right)(?:$|\s)/) || [])[1] || target.style.float || 'none';
237
- this.isVertical = /^(90|270)$/.test(Math.abs(GetRotateValue(target).r).toString());
337
+ this._setFigureInfo(figureInfo);
238
338
 
239
- const sizeTarget = figureTarget ? this._cover || this._container || target : target;
240
- const w = sizeTarget.offsetWidth;
241
- const h = sizeTarget.offsetHeight;
339
+ const sizeTarget = /** @type {HTMLElement} */ (figureTarget ? this._cover || this._container || target : target);
340
+ const w = sizeTarget.offsetWidth || null;
341
+ const h = sizeTarget.offsetHeight || null;
242
342
  const { top, left, scrollX, scrollY } = this.offset.getLocal(sizeTarget);
243
343
 
244
344
  const dataSize = (target.getAttribute('data-se-size') || '').split(',');
@@ -249,14 +349,14 @@ Figure.prototype = {
249
349
  caption: figureInfo.caption,
250
350
  align: this.align,
251
351
  ratio: ratio,
252
- w: w,
253
- h: h,
352
+ w: w || '',
353
+ h: h || '',
254
354
  t: top,
255
355
  l: left,
256
356
  width: dataSize[0] || 'auto',
257
357
  height: dataSize[1] || 'auto',
258
- originWidth: target.naturalWidth || target.offsetWidth,
259
- originHeight: target.naturalHeight || target.offsetHeight
358
+ originWidth: /** @type {HTMLImageElement} */ (target).naturalWidth || target.offsetWidth,
359
+ originHeight: /** @type {HTMLImageElement} */ (target).naturalHeight || target.offsetHeight
260
360
  };
261
361
 
262
362
  this._width = targetInfo.width;
@@ -287,71 +387,106 @@ Figure.prototype = {
287
387
  const value = /%$/.test(target.style.width) && /%$/.test(figureInfo.container.style.width) ? numbers.get(figureInfo.container.style.width, 0) / 100 + '' : '';
288
388
  for (let i = 0, len = this.percentageButtons.length; i < len; i++) {
289
389
  if (this.percentageButtons[i].getAttribute('data-value') === value) {
290
- domUtils.addClass(this.percentageButtons[i], 'active');
390
+ dom.utils.addClass(this.percentageButtons[i], 'active');
291
391
  } else {
292
- domUtils.removeClass(this.percentageButtons[i], 'active');
392
+ dom.utils.removeClass(this.percentageButtons[i], 'active');
293
393
  }
294
394
  }
295
395
 
296
396
  // caption active
297
397
  if (this.captionButton) {
298
398
  if (figureInfo.caption) {
299
- domUtils.addClass(this.captionButton, 'active');
399
+ dom.utils.addClass(this.captionButton, 'active');
300
400
  } else {
301
- domUtils.removeClass(this.captionButton, 'active');
401
+ dom.utils.removeClass(this.captionButton, 'active');
302
402
  }
303
403
  }
304
404
 
305
- _figure.display.style.display = nonSizeInfo ? 'none' : '';
405
+ _figure.display.style.display = nonSizeInfo || this._inlineCover ? 'none' : '';
306
406
  _figure.border.style.display = nonBorder ? 'none' : '';
307
407
  _figure.main.style.display = 'block';
308
408
 
309
409
  if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
310
410
  // align button
311
411
  this._setAlignIcon();
312
- this.editor._visibleControllers(true, true);
412
+ // as button
413
+ this._setAsIcon();
414
+ this.ui._visibleControllers(true, true);
313
415
  // size
314
416
  const size = this.getSize(target);
315
- domUtils.changeTxt(_figure.display, this.lang[this.align === 'none' ? 'basic' : this.align] + ' (' + size.w + ', ' + size.h + ')');
417
+ dom.utils.changeTxt(_figure.display, this.lang[this.align === 'none' ? 'basic' : this.align] + ' (' + size.w + ', ' + size.h + ')');
316
418
  this._displayResizeHandles(!nonResizing);
419
+ // rotate, aption, align, onresize - display;
420
+ const transformButtons = this.controller.form.querySelectorAll(
421
+ '[data-command="rotate"][data-value="90"], [data-command="rotate"][data-value="-90"], [data-command="caption"], [data-command="onalign"], [data-command="onresize"]'
422
+ );
423
+ const display = this._inlineCover || exceptionFormat ? 'none' : '';
424
+ transformButtons.forEach((button) => {
425
+ /** @type {HTMLButtonElement} */ (button).style.display = display;
426
+ });
427
+ // onas
428
+ const onas = this.controller.form.querySelector('[data-command="onas"]');
429
+ if (onas) {
430
+ /** @type {HTMLButtonElement} */ (onas).style.display = exceptionFormat ? 'none' : '';
431
+ }
317
432
  // selecte
318
- domUtils.removeClass(this._cover, 'se-figure-over-selected');
433
+ dom.utils.removeClass(this._cover, 'se-figure-over-selected');
319
434
  this.controller.open(_figure.main, null, { initMethod: this.__offContainer, isWWTarget: false, addOffset: null });
320
435
  this._w.setTimeout(() => _DragHandle.set('__overInfo', false), 0);
321
436
  } else {
322
- domUtils.addClass(this._cover, 'se-figure-over-selected');
437
+ dom.utils.addClass(this._cover, 'se-figure-over-selected');
323
438
  }
324
439
 
325
440
  // set members
326
- domUtils.addClass(this._cover, 'se-figure-selected');
441
+ dom.utils.addClass(this._cover, 'se-figure-selected');
327
442
  this._element_w = this._resize_w = w;
328
443
  this._element_h = this._resize_h = h;
329
444
  this._element_l = left;
330
445
  this._element_t = top;
331
446
 
332
447
  // drag
333
- if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT || domUtils.hasClass(figureInfo.container, 'se-input-component')) {
448
+ if (!this._inlineCover && (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT || dom.utils.hasClass(figureInfo.container, 'se-input-component'))) {
334
449
  this._setDragEvent(_figure.main);
335
450
  }
336
451
 
337
452
  return targetInfo;
338
- },
453
+ }
339
454
 
455
+ /**
456
+ * @description Hide the controller
457
+ */
340
458
  controllerHide() {
341
459
  this.controller.hide();
342
- },
460
+ }
343
461
 
462
+ /**
463
+ * @description Hide the controller
464
+ */
344
465
  controllerShow() {
345
466
  this.controller.show();
346
- },
467
+ }
347
468
 
348
- controllerOpen(target, args) {
349
- this._element = target;
350
- this.controller.open(target, null, args);
351
- },
469
+ /**
470
+ * @description Open the figure's controller
471
+ * @param {Node} target Target element
472
+ * @param {Object} [params={}] params
473
+ * @param {boolean=} params.isWWTarget If the controller is in the WYSIWYG area, set it to true.
474
+ * @param {() => void=} params.initMethod Method to be called when the controller is closed.
475
+ * @param {boolean=} params.disabled If true, the controller is disabled.
476
+ * @param {{left: number, top: number}=} params.addOffset Additional offset values
477
+ */
478
+ controllerOpen(target, params) {
479
+ this._element = /** @type {HTMLElement} */ (target);
480
+ this.controller.open(target, null, params);
481
+ }
352
482
 
483
+ /**
484
+ * @description Set the element's container size
485
+ * @param {string|number} w Width size
486
+ * @param {string|number} h Height size
487
+ */
353
488
  setSize(w, h) {
354
- if (/%$/.test(w)) {
489
+ if (/%$/.test(w + '')) {
355
490
  this._setPercentSize(w, h);
356
491
  } else if ((!w || w === 'auto') && (!h || h === 'auto')) {
357
492
  if (this.autoRatio) this._setPercentSize(100, this.autoRatio.default || this.autoRatio.current);
@@ -359,19 +494,27 @@ Figure.prototype = {
359
494
  } else {
360
495
  this._applySize(w, h, '');
361
496
  }
362
- },
497
+ }
363
498
 
364
499
  /**
365
500
  * @description Gets the Figure size
366
- * @param {Element|null} target
501
+ * @param {?Node=} targetNode Target element, default is the current element
367
502
  * @returns {{w: string, h: string}}
368
503
  */
369
- getSize(target) {
370
- if (!target) target = this._element;
371
- if (!target) return { w: '', h: '' };
504
+ getSize(targetNode) {
505
+ if (!targetNode) targetNode = this._element;
506
+ if (!targetNode) return { w: '', h: '' };
372
507
 
373
- const figure = Figure.GetContainer(target);
508
+ const figure = Figure.GetContainer(targetNode);
509
+ const target = figure.target;
374
510
  if (!figure.container) {
511
+ // exceptionFormat
512
+ if (!this.options.get('strictMode').formatFilter) {
513
+ return {
514
+ w: target.style.width || 'auto',
515
+ h: target.style.height || 'auto'
516
+ };
517
+ }
375
518
  return {
376
519
  w: '',
377
520
  h: target.style.height
@@ -379,42 +522,45 @@ Figure.prototype = {
379
522
  }
380
523
 
381
524
  const w = !/%$/.test(target.style.width) ? target.style.width : ((figure.container && numbers.get(figure.container.style.width, 2)) || 100) + '%';
382
- const h =
383
- numbers.get(figure.cover.style.paddingBottom, 0) > 0 && !this.isVertical
384
- ? figure.cover.style.height
385
- : !/%$/.test(target.style.height) || !/%$/.test(target.style.width)
386
- ? target.style.height
387
- : ((figure.container && numbers.get(figure.container.style.height, 2)) || 100) + '%';
525
+ const h = figure.inlineCover
526
+ ? figure.inlineCover.style.height
527
+ : numbers.get(figure.cover.style.paddingBottom, 0) > 0 && !this.isVertical
528
+ ? figure.cover.style.height
529
+ : !/%$/.test(target.style.height) || !/%$/.test(target.style.width)
530
+ ? target.style.height
531
+ : ((figure.container && numbers.get(figure.container.style.height, 2)) || 100) + '%';
388
532
  return {
389
533
  w: w || 'auto',
390
534
  h: h || 'auto'
391
535
  };
392
- },
536
+ }
393
537
 
394
538
  /**
395
539
  * @description Align the container.
396
- * @param {Element|null} target Target element
397
- * @param {"none"|"left"|"center"|"right"} align
540
+ * @param {?Node} targetNode Target element
541
+ * @param {string} align "none"|"left"|"center"|"right"
398
542
  */
399
- setAlign(target, align) {
400
- if (!target) target = this._element;
543
+ setAlign(targetNode, align) {
544
+ if (!targetNode) targetNode = this._element;
401
545
  this.align = align = align || 'none';
402
546
 
403
- const figure = Figure.GetContainer(target);
404
- const container = figure.container;
547
+ const figure = Figure.GetContainer(targetNode);
548
+ if (!figure.cover) return;
405
549
 
550
+ const target = figure.target;
551
+ const container = figure.container;
406
552
  const cover = figure.cover;
407
553
  if (/%$/.test(target.style.width) && align === 'center' && !this.component.isInline(container)) {
408
554
  container.style.minWidth = '100%';
409
555
  cover.style.width = container.style.width;
410
556
  } else {
411
557
  container.style.minWidth = '';
412
- cover.style.width = this.isVertical ? target.style.height || target.offsetHeight : !target.style.width || target.style.width === 'auto' ? '' : target.style.width || '100%';
558
+ cover.style.width = this.isVertical ? target.style.height || target.offsetHeight + 'px' : !target.style.width || target.style.width === 'auto' ? '' : target.style.width || '100%';
413
559
  }
414
560
 
415
- if (!domUtils.hasClass(container, '__se__float-' + align)) {
416
- domUtils.removeClass(container, this._floatClassStr);
417
- domUtils.addClass(container, '__se__float-' + align);
561
+ if (!dom.utils.hasClass(container, '__se__float-' + align)) {
562
+ dom.utils.removeClass(container, this._floatClassStr);
563
+ dom.utils.addClass(container, '__se__float-' + align);
418
564
  }
419
565
 
420
566
  if (this.autoRatio) {
@@ -423,22 +569,116 @@ Figure.prototype = {
423
569
  }
424
570
 
425
571
  this._setAlignIcon();
426
- },
572
+ }
427
573
 
428
574
  /**
429
- * @override controller
430
- * @param {Element} target Target button element
575
+ * @description As style[block, inline] the component
576
+ * @param {?Node} targetNode Target element
577
+ * @param {"block"|"inline"} formatStyle Format style
578
+ */
579
+ convertAsFormat(targetNode, formatStyle) {
580
+ if (!targetNode) targetNode = this._element;
581
+ this.as = formatStyle || 'block';
582
+ const { container, inlineCover, target } = Figure.GetContainer(targetNode);
583
+ const { w, h } = this.getSize(target);
584
+
585
+ const newTarget = /** @type {HTMLElement} */ (target.cloneNode(false));
586
+
587
+ switch (formatStyle) {
588
+ case 'inline': {
589
+ if (inlineCover) break;
590
+ this.component.deselect();
591
+
592
+ const next = container.nextElementSibling;
593
+ const parent = container.parentElement;
594
+
595
+ newTarget.style.width = '';
596
+ newTarget.style.height = '';
597
+ const figure = Figure.CreateInlineContainer(newTarget);
598
+ dom.utils.addClass(
599
+ figure.container,
600
+ container.className
601
+ .split(' ')
602
+ .filter((v) => v !== 'se-figure-selected' && v !== 'se-component-selected')
603
+ .join('|')
604
+ );
605
+
606
+ this._asFormatChange(figure, w, h);
607
+
608
+ const line = dom.utils.createElement(this.options.get('defaultLine'), null, figure.container);
609
+ parent.insertBefore(line, next);
610
+ dom.utils.removeItem(container);
611
+
612
+ break;
613
+ }
614
+ case 'block': {
615
+ if (!inlineCover) break;
616
+ this.component.deselect();
617
+
618
+ this.selection.setRange(container, 0, container, 1);
619
+ const r = this.html.remove();
620
+ const s = this.nodeTransform.split(r.container, r.offset, 0);
621
+
622
+ if (s?.previousElementSibling && dom.check.isZeroWidth(s.previousElementSibling)) {
623
+ dom.utils.removeItem(s.previousElementSibling);
624
+ }
625
+
626
+ newTarget.style.width = '';
627
+ newTarget.style.height = '';
628
+ const figure = Figure.CreateContainer(newTarget);
629
+ dom.utils.addClass(
630
+ figure.container,
631
+ container.className
632
+ .split(' ')
633
+ .filter((v) => v !== 'se-inline-component' && v !== 'se-figure-selected' && v !== 'se-component-selected')
634
+ .join('|')
635
+ );
636
+
637
+ this._asFormatChange(figure, w, h);
638
+
639
+ (s || r.container).parentElement.insertBefore(figure.container, s);
640
+
641
+ break;
642
+ }
643
+ }
644
+ }
645
+
646
+ /**
647
+ * @private
648
+ * @description Handles format conversion (block/inline) for the figure component and applies size changes.
649
+ * @param {FigureInfo} figureinfo {target, container, cover, inlineCover, caption}
650
+ * @param {string|number} w Width value.
651
+ * @param {string|number} h Height value.
652
+ */
653
+ _asFormatChange(figureinfo, w, h) {
654
+ const kind = this.kind;
655
+ figureinfo.target.onload = () => this.component.select(figureinfo.target, kind);
656
+
657
+ this._setFigureInfo(figureinfo);
658
+
659
+ if (figureinfo.inlineCover) {
660
+ this.setAlign(figureinfo.target, 'none');
661
+ this.deleteTransform();
662
+ }
663
+
664
+ this.setSize(w, h);
665
+ }
666
+
667
+ /**
668
+ * @description Controller button action
669
+ * @param {HTMLButtonElement} target Target button element
431
670
  * @returns
432
671
  */
433
672
  controllerAction(target) {
434
673
  const command = target.getAttribute('data-command');
435
674
  const value = target.getAttribute('data-value');
675
+ const type = target.getAttribute('data-type');
436
676
  const element = this._element;
437
- if (/^(onalign|onresize)$/.test(command)) return;
677
+ if (/^on.+/.test(command) || type === 'selectMenu') return;
438
678
 
439
679
  switch (command) {
440
680
  case 'mirror': {
441
- const info = GetRotateValue(element);
681
+ const info = this.#GetRotateValue(element);
442
682
  let x = info.x;
443
683
  let y = info.y;
444
684
 
@@ -457,7 +697,7 @@ Figure.prototype = {
457
697
  case 'caption':
458
698
  if (!this._caption) {
459
699
  const caption = Figure.CreateCaption(this._cover, this.lang.caption);
460
- const captionText = domUtils.getEdgeChild(caption, (current) => current.nodeType === 3);
700
+ const captionText = dom.query.getEdgeChild(caption, (current) => current.nodeType === 3, false);
461
701
 
462
702
  if (!captionText) {
463
703
  caption.focus();
@@ -467,7 +707,7 @@ Figure.prototype = {
467
707
 
468
708
  this.controller.close();
469
709
  } else {
470
- domUtils.removeItem(this._caption);
710
+ dom.utils.removeItem(this._caption);
471
711
  this._w.setTimeout(this.component.select.bind(this.component, element, this.kind), 0);
472
712
  }
473
713
 
@@ -486,6 +726,10 @@ Figure.prototype = {
486
726
  case 'edit':
487
727
  this.inst.edit(element);
488
728
  break;
729
+ case 'copy': {
730
+ this.component.copy(this._container);
731
+ break;
732
+ }
489
733
  case 'remove':
490
734
  this.inst.destroy(element);
491
735
  this.controller.close();
@@ -501,17 +745,59 @@ Figure.prototype = {
501
745
 
502
746
  this.history.push(false);
503
747
  if (!/^remove|caption$/.test(command)) {
504
- this.component.select(element, this.kind, false);
748
+ this.component.select(element, this.kind);
749
+ }
750
+ }
751
+
752
+ /**
753
+ * @description Inspect the figure component format and change it to the correct format.
754
+ * @param {Node} container - The container element of the figure component.
755
+ * @param {Node} originEl - The original element of the figure component.
756
+ * @param {Node} anchorCover - The anchor cover element of the figure component.
757
+ * @param {import('./FileManager').default} [fileManagerInst=null] - FileManager module instance, if used.
758
+ */
759
+ retainFigureFormat(container, originEl, anchorCover, fileManagerInst) {
760
+ const isInline = this.component.isInline(container);
761
+ let existElement = this.format.isBlock(originEl.parentNode) || dom.check.isWysiwygFrame(originEl.parentNode) ? originEl : dom.check.isAnchor(originEl.parentNode) ? originEl.parentNode : this.format.getLine(originEl) || originEl;
762
+
763
+ if (dom.query.getParentElement(originEl, dom.check.isExcludeFormat)) {
764
+ existElement = anchorCover && anchorCover !== originEl ? anchorCover : originEl;
765
+ existElement.parentNode.replaceChild(container, existElement);
766
+ } else if (isInline && this.format.isLine(existElement)) {
767
+ const refer = isInline && /^SPAN$/i.test(originEl.parentElement.nodeName) ? originEl.parentElement : originEl;
768
+ refer.parentElement.replaceChild(container, refer);
769
+ } else if (dom.check.isListCell(existElement)) {
770
+ const refer = dom.query.getParentElement(originEl, (current) => current.parentNode === existElement);
771
+ existElement.insertBefore(container, refer);
772
+ dom.utils.removeItem(originEl);
773
+ this.nodeTransform.removeEmptyNode(refer, null, true);
774
+ } else if (this.format.isLine(existElement)) {
775
+ const refer = dom.query.getParentElement(originEl, (current) => current.parentNode === existElement);
776
+ existElement = this.nodeTransform.split(existElement, refer);
777
+ existElement.parentNode.insertBefore(container, existElement);
778
+ dom.utils.removeItem(originEl);
779
+ this.nodeTransform.removeEmptyNode(existElement, null, true);
780
+ } else {
781
+ if (this.format.isLine(existElement.parentNode)) {
782
+ const formats = existElement.parentNode;
783
+ formats.parentNode.insertBefore(container, existElement.previousSibling ? formats.nextElementSibling : formats);
784
+ if (fileManagerInst?.__updateTags.map((current) => existElement.contains(current)).length === 0) dom.utils.removeItem(existElement);
785
+ else if (dom.check.isZeroWidth(existElement)) dom.utils.removeItem(existElement);
786
+ } else {
787
+ existElement = dom.check.isFigure(existElement.parentNode) ? dom.query.getParentElement(existElement.parentNode, Figure.is) : existElement;
788
+ existElement.parentNode.replaceChild(container, existElement);
789
+ }
505
790
  }
506
- },
791
+ }
507
792
 
508
793
  /**
509
794
  * @description Initialize the transform style (rotation) of the element.
510
- * @param {Element|null} element Target element
795
+ * @param {?Node=} node Target element, default is the current element
511
796
  */
512
- deleteTransform(element) {
513
- if (!element) element = this._element;
797
+ deleteTransform(node) {
798
+ if (!node) node = this._element;
514
799
 
800
+ const element = /** @type {HTMLElement} */ (node);
515
801
  const size = (element.getAttribute('data-se-size') || '').split(',');
516
802
  this.isVertical = false;
517
803
 
@@ -521,18 +807,18 @@ Figure.prototype = {
521
807
 
522
808
  this._deleteCaptionPosition(element);
523
809
  this._applySize(size[0] || 'auto', size[1] || '', '');
524
- },
810
+ }
525
811
 
526
812
  /**
527
813
  * @description Set the transform style (rotation) of the element.
528
- * @param {Element} element Target element
529
- * @param {Number|null} width Element's width size
530
- * @param {Number|null} height Element's height size
814
+ * @param {Node} node Target element
815
+ * @param {?string|number} width Element's width size
816
+ * @param {?string|number} height Element's height size
531
817
  */
532
- setTransform(element, width, height, deg) {
818
+ setTransform(node, width, height, deg) {
533
819
  try {
534
820
  this.__preventSizechange = true;
535
- const info = GetRotateValue(element);
821
+ const info = this.#GetRotateValue(node);
536
822
  const slope = info.r + (deg || 0) * 1;
537
823
  deg = Math.abs(slope) >= 360 ? 0 : slope;
538
824
  const isVertical = (this.isVertical = /^(90|270)$/.test(Math.abs(deg).toString()));
@@ -540,6 +826,7 @@ Figure.prototype = {
540
826
  width = numbers.get(width, 0);
541
827
  height = numbers.get(height, 0);
542
828
 
829
+ const element = /** @type {HTMLElement} */ (node);
543
830
  const dataSize = (element.getAttribute('data-se-size') || 'auto,auto').split(',');
544
831
  let transOrigin = '';
545
832
  if (/auto|%$/.test(dataSize[0]) && !isVertical) {
@@ -550,6 +837,7 @@ Figure.prototype = {
550
837
  }
551
838
  } else {
552
839
  const figureInfo = Figure.GetContainer(element);
840
+ const cover = figureInfo.cover || figureInfo.inlineCover;
553
841
  const offsetW = width || element.offsetWidth;
554
842
  const offsetH = height || element.offsetHeight;
555
843
  const w = (isVertical ? offsetH : offsetW) + 'px';
@@ -558,8 +846,8 @@ Figure.prototype = {
558
846
  this._deletePercentSize();
559
847
  this._applySize(offsetW + 'px', offsetH + 'px', '');
560
848
 
561
- figureInfo.cover.style.width = w;
562
- figureInfo.cover.style.height = figureInfo.caption ? '' : h;
849
+ cover.style.width = w;
850
+ cover.style.height = figureInfo.caption || figureInfo.inlineCover ? '' : h;
563
851
 
564
852
  if (isVertical) {
565
853
  const transW = offsetW / 2 + 'px ' + offsetW / 2 + 'px 0';
@@ -578,13 +866,37 @@ Figure.prototype = {
578
866
  } finally {
579
867
  this.__preventSizechange = false;
580
868
  }
581
- },
869
+ }
582
870
 
871
+ /**
872
+ * @private
873
+ * @description Sets figure component properties such as cover, container, caption, and alignment.
874
+ * @param {FigureInfo} figureInfo - {target, container, cover, inlineCover, caption}
875
+ */
876
+ _setFigureInfo(figureInfo) {
877
+ this._inlineCover = figureInfo.inlineCover;
878
+ this._cover = figureInfo.cover || this._inlineCover;
879
+ this._container = figureInfo.container;
880
+ this._caption = figureInfo.caption;
881
+ this._element = figureInfo.target;
882
+ this.align = (this._container.className.match(/(?:^|\s)__se__float-(none|left|center|right)(?:$|\s)/) || [])[1] || figureInfo.target.style.float || 'none';
883
+ this.as = this._inlineCover ? 'inline' : 'block';
884
+ this.isVertical = /^(90|270)$/.test(Math.abs(this.#GetRotateValue(figureInfo.target).r).toString());
885
+ }
886
+
887
+ /**
888
+ * @private
889
+ * @description Applies rotation transformation to the target element.
890
+ * @param {HTMLElement} element Target element.
891
+ * @param {number} r Rotation degree.
892
+ * @param {number} x X-axis rotation value.
893
+ * @param {number} y Y-axis rotation value.
894
+ */
583
895
  _setRotate(element, r, x, y) {
584
- let width = (element.offsetWidth - element.offsetHeight) * (/^-/.test(r) ? 1 : -1);
896
+ let width = (element.offsetWidth - element.offsetHeight) * (/^-/.test(r + '') ? 1 : -1);
585
897
  let translate = '';
586
898
 
587
- if (/[1-9]/.test(r) && (x || y)) {
899
+ if (/[1-9]/.test(r + '') && (x || y)) {
588
900
  translate = x ? 'Y' : 'X';
589
901
 
590
902
  switch (r + '') {
@@ -612,13 +924,20 @@ Figure.prototype = {
612
924
  }
613
925
 
614
926
  element.style.transform = 'rotate(' + r + 'deg)' + (x ? ' rotateX(' + x + 'deg)' : '') + (y ? ' rotateY(' + y + 'deg)' : '') + (translate ? ' translate' + translate + '(' + width + 'px)' : '');
615
- },
927
+ }
616
928
 
929
+ /**
930
+ * @private
931
+ * @description Applies size adjustments to the figure element.
932
+ * @param {string|number} w Width value.
933
+ * @param {string|number} h Height value.
934
+ * @param {string} direction Resize direction.
935
+ */
617
936
  _applySize(w, h, direction) {
618
937
  const onlyW = /^(rw|lw)$/.test(direction) && /\d+/.test(this._element.style.height);
619
938
  const onlyH = /^(th|bh)$/.test(direction) && /\d+/.test(this._element.style.width);
620
- h = h || (this.autoRatio ? this.autoRatio.current || this.autoRatio.default : h);
621
- w = numbers.is(w) ? w + this.sizeUnit : w;
939
+ h = /** @type {string} */ (h || (this.autoRatio ? this.autoRatio.current || this.autoRatio.default : h));
940
+ w = /** @type {string} */ (numbers.is(w) ? w + this.sizeUnit : w);
622
941
 
623
942
  if (!/%$/.test(w) && !/%$/.test(h) && !onlyW && !onlyH) this._deletePercentSize();
624
943
 
@@ -641,17 +960,29 @@ Figure.prototype = {
641
960
 
642
961
  // save current size
643
962
  this._saveCurrentSize();
644
- },
963
+ }
645
964
 
965
+ /**
966
+ * @private
967
+ * @description Sets padding-bottom for cover elements based on width and height.
968
+ * @param {string} w Width value.
969
+ * @param {string} h Height value.
970
+ */
646
971
  __setCoverPaddingBottom(w, h) {
972
+ if (this._inlineCover === this._cover) return;
973
+
647
974
  this._cover.style.height = h;
648
975
  if (/%$/.test(w) && this.align === 'center') {
649
976
  this._cover.style.paddingBottom = !/%$/.test(h) ? h : numbers.get((numbers.get(h, 2) / 100) * numbers.get(w, 2), 2) + '%';
650
977
  } else {
651
978
  this._cover.style.paddingBottom = h;
652
979
  }
653
- },
980
+ }
654
981
 
982
+ /**
983
+ * @private
984
+ * @description Sets the figure element to its auto size.
985
+ */
655
986
  _setAutoSize() {
656
987
  if (this._caption) this._caption.style.marginTop = '';
657
988
  this.deleteTransform();
@@ -671,53 +1002,93 @@ Figure.prototype = {
671
1002
 
672
1003
  // save current size
673
1004
  this._saveCurrentSize();
674
- },
1005
+ }
675
1006
 
1007
+ /**
1008
+ * @private
1009
+ * @description Sets the figure element's size in percentage.
1010
+ * @param {string|number} w Width percentage.
1011
+ * @param {string|number} h Height percentage.
1012
+ */
676
1013
  _setPercentSize(w, h) {
677
1014
  if (!h) h = this.autoRatio ? (/%$/.test(this.autoRatio.current) ? this.autoRatio.current : this.autoRatio.default) : h;
678
- h = h && !/%$/.test(h) && !numbers.get(h, 0) ? (numbers.is(h) ? h + '%' : h) : numbers.is(h) ? h + this.sizeUnit : h || (this.autoRatio ? this.autoRatio.default : '');
1015
+ h = h && !/%$/.test(h + '') && !numbers.get(h, 0) ? (numbers.is(h) ? h + '%' : h) : numbers.is(h) ? h + this.sizeUnit : h || (this.autoRatio ? this.autoRatio.default : '');
679
1016
 
680
- const heightPercentage = /%$/.test(h);
681
- this._container.style.width = numbers.is(w) ? w + '%' : w;
1017
+ const heightPercentage = /%$/.test(h + '');
1018
+ this._container.style.width = String(numbers.is(w) ? w + '%' : w);
682
1019
  this._container.style.height = '';
683
- this._cover.style.width = '100%';
684
- this._cover.style.height = h;
1020
+
1021
+ // exceptionFormat
1022
+ if (this._element === this._cover && !this.options.get('strictMode').formatFilter) {
1023
+ this._saveCurrentSize();
1024
+ return;
1025
+ }
1026
+
1027
+ if (this._inlineCover !== this._cover) {
1028
+ this._cover.style.width = '100%';
1029
+ this._cover.style.height = String(h);
1030
+ }
685
1031
  this._element.style.width = '100%';
686
1032
  this._element.style.maxWidth = '';
687
- this._element.style.height = this.autoRatio ? '100%' : heightPercentage ? '' : h;
1033
+ this._element.style.height = String(this.autoRatio ? '100%' : heightPercentage ? '' : h);
688
1034
 
689
1035
  if (this.align === 'center') this.setAlign(this._element, this.align);
690
1036
  if (this.autoRatio) {
691
- this.__setCoverPaddingBottom(w, h);
1037
+ this.__setCoverPaddingBottom(String(w), String(h));
692
1038
  }
693
1039
 
694
1040
  this._setCaptionPosition(this._element);
695
1041
 
696
1042
  // save current size
697
1043
  this._saveCurrentSize();
698
- },
1044
+ }
699
1045
 
1046
+ /**
1047
+ * @private
1048
+ * @description Deletes percentage-based sizing from the figure element.
1049
+ */
700
1050
  _deletePercentSize() {
701
1051
  this._cover.style.width = '';
702
1052
  this._cover.style.height = '';
703
1053
  this._container.style.width = '';
704
1054
  this._container.style.height = '';
705
1055
 
706
- domUtils.removeClass(this._container, this._floatClassStr);
707
- domUtils.addClass(this._container, '__se__float-' + this.align);
1056
+ dom.utils.removeClass(this._container, this._floatClassStr);
1057
+ dom.utils.addClass(this._container, '__se__float-' + this.align);
708
1058
 
709
1059
  if (this.align === 'center') this.setAlign(this._element, this.align);
710
- },
1060
+ }
711
1061
 
1062
+ /**
1063
+ * @private
1064
+ * @description Reverts the figure element to its previously saved size.
1065
+ */
712
1066
  _setRevert() {
713
1067
  this.setSize(this.__revertSize.w, this.__revertSize.h);
714
- },
1068
+ }
715
1069
 
1070
+ /**
1071
+ * @private
1072
+ * @description Updates the figure's alignment icon.
1073
+ */
716
1074
  _setAlignIcon() {
717
1075
  if (!this.alignButton) return;
718
- domUtils.changeElement(this.alignButton.firstElementChild, this._alignIcons[this.align]);
719
- },
1076
+ dom.utils.changeElement(this.alignButton.firstElementChild, this._alignIcons[this.align]);
1077
+ }
720
1078
 
1079
+ /**
1080
+ * @private
1081
+ * @description Updates the figure's block/inline format icon.
1082
+ */
1083
+ _setAsIcon() {
1084
+ if (!this.asButton) return;
1085
+ dom.utils.changeElement(this.asButton.firstElementChild, this.icons[`as_${this.as}`]);
1086
+ }
1087
+
1088
+ /**
1089
+ * @private
1090
+ * @description Saves the current size of the figure component.
1091
+ */
721
1092
  _saveCurrentSize() {
722
1093
  if (this.__preventSizechange) return;
723
1094
 
@@ -733,40 +1104,59 @@ Figure.prototype = {
733
1104
  if (this.autoRatio) {
734
1105
  this.autoRatio.current = /%$/.test(size.h) ? size.h : '';
735
1106
  }
736
- },
1107
+ }
737
1108
 
1109
+ /**
1110
+ * @private
1111
+ * @description Adjusts the position of the caption within the figure.
1112
+ * @param {HTMLElement} element Target element.
1113
+ */
738
1114
  _setCaptionPosition(element) {
739
- const figcaption = domUtils.getEdgeChild(domUtils.getParentElement(element, 'FIGURE'), 'FIGCAPTION');
1115
+ const figcaption = /** @type {HTMLElement} */ (dom.query.getEdgeChild(dom.query.getParentElement(element, 'FIGURE'), 'FIGCAPTION', false));
740
1116
  if (figcaption) {
741
1117
  figcaption.style.marginTop = (this.isVertical ? element.offsetWidth - element.offsetHeight : 0) + 'px';
742
1118
  }
743
- },
1119
+ }
744
1120
 
1121
+ /**
1122
+ * @private
1123
+ * @description Removes the margin top property from the figure caption.
1124
+ * @param {HTMLElement} element Target element.
1125
+ */
745
1126
  _deleteCaptionPosition(element) {
746
- const figcaption = domUtils.getEdgeChild(domUtils.getParentElement(element, 'FIGURE'), 'FIGCAPTION');
1127
+ const figcaption = /** @type {HTMLElement} */ (dom.query.getEdgeChild(dom.query.getParentElement(element, 'FIGURE'), 'FIGCAPTION', false));
747
1128
  if (figcaption) {
748
1129
  figcaption.style.marginTop = '';
749
1130
  }
750
- },
1131
+ }
751
1132
 
1133
+ /**
1134
+ * @private
1135
+ * @description Displays or hides the resize handles of the figure component.
1136
+ * @param {boolean} display Whether to display resize handles.
1137
+ */
752
1138
  _displayResizeHandles(display) {
753
- display = !display ? 'none' : 'flex';
754
- this.controller.form.style.display = display;
1139
+ const type = !display ? 'none' : 'flex';
1140
+ this.controller.form.style.display = type;
755
1141
 
756
1142
  const _figure = this.editor.frameContext.get('_figure');
757
1143
  const resizeHandles = _figure.handles;
758
1144
  for (let i = 0, len = resizeHandles.length; i < len; i++) {
759
- resizeHandles[i].style.display = display;
1145
+ resizeHandles[i].style.display = type;
760
1146
  }
761
1147
 
762
- if (display === 'none') {
763
- domUtils.addClass(_figure.main, 'se-resize-ing');
1148
+ if (type === 'none') {
1149
+ dom.utils.addClass(_figure.main, 'se-resize-ing');
764
1150
  this.__onResizeESCEvent = this.eventManager.addGlobalEvent('keydown', this.__containerResizingESC);
765
1151
  } else {
766
- domUtils.removeClass(_figure.main, 'se-resize-ing');
1152
+ dom.utils.removeClass(_figure.main, 'se-resize-ing');
767
1153
  }
768
- },
1154
+ }
769
1155
 
1156
+ /**
1157
+ * @private
1158
+ * @description Removes the resize event listeners.
1159
+ */
770
1160
  _offResizeEvent() {
771
1161
  this.component._removeDragEvent();
772
1162
  this.eventManager.removeGlobalEvent(this.__onContainerEvent);
@@ -774,13 +1164,18 @@ Figure.prototype = {
774
1164
  this.eventManager.removeGlobalEvent(this.__onResizeESCEvent);
775
1165
 
776
1166
  this._displayResizeHandles(true);
777
- this.editor._offCurrentController();
778
- this.editor.disableBackWrapper();
779
- },
1167
+ this.ui._offCurrentController();
1168
+ this.ui.disableBackWrapper();
1169
+ }
780
1170
 
1171
+ /**
1172
+ * @private
1173
+ * @description Sets up drag event handling for the figure component.
1174
+ * @param {Node} figureMain The main figure container element.
1175
+ */
781
1176
  _setDragEvent(figureMain) {
782
1177
  const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
783
- domUtils.removeClass(dragHandle, 'se-drag-handle-full');
1178
+ dom.utils.removeClass(dragHandle, 'se-drag-handle-full');
784
1179
 
785
1180
  dragHandle.style.opacity = '';
786
1181
  dragHandle.style.width = '';
@@ -789,195 +1184,240 @@ Figure.prototype = {
789
1184
  _DragHandle.set('__dragHandler', dragHandle);
790
1185
  _DragHandle.set('__dragContainer', this._container);
791
1186
  _DragHandle.set('__dragCover', this._cover);
792
- _DragHandle.set('__dragMove', OnScrollDragHandler.bind(this, dragHandle, figureMain));
1187
+ _DragHandle.set('__dragMove', this.#OnScrollDragHandler.bind(this, dragHandle, figureMain));
793
1188
 
794
1189
  _DragHandle.get('__dragMove')();
795
1190
 
796
1191
  dragHandle.style.display = 'block';
797
- },
1192
+ }
798
1193
 
799
- _retainFigureFormat(container, originEl, anchorCover) {
800
- let existElement = this.format.isBlock(originEl.parentNode) || domUtils.isWysiwygFrame(originEl.parentNode) ? originEl : domUtils.isAnchor(originEl.parentNode) ? originEl.parentNode : this.format.getLine(originEl) || originEl;
1194
+ /**
1195
+ * @param {HTMLElement} dragHandle Drag handle element
1196
+ * @param {HTMLElement} figureMain Figure container element
1197
+ */
1198
+ #OnScrollDragHandler(dragHandle, figureMain) {
1199
+ dragHandle.style.display = 'block';
1200
+ dragHandle.style.left = figureMain.offsetLeft + (this.options.get('_rtl') ? dragHandle.offsetWidth : figureMain.offsetWidth - dragHandle.offsetWidth * 1.5) + 'px';
1201
+ dragHandle.style.top = figureMain.offsetTop - dragHandle.offsetHeight + 'px';
1202
+ }
801
1203
 
802
- if (domUtils.getParentElement(originEl, domUtils.isExcludeFormat)) {
803
- existElement = anchorCover && anchorCover !== originEl ? anchorCover : originEl;
804
- existElement.parentNode.replaceChild(container, existElement);
805
- } else if (domUtils.isListCell(existElement)) {
806
- const refer = domUtils.getParentElement(originEl, (current) => current.parentNode === existElement);
807
- existElement.insertBefore(container, refer);
808
- domUtils.removeItem(originEl);
809
- this.nodeTransform.removeEmptyNode(refer, null, true);
810
- } else if (this.format.isLine(existElement)) {
811
- const refer = domUtils.getParentElement(originEl, (current) => current.parentNode === existElement);
812
- existElement = this.nodeTransform.split(existElement, refer);
813
- existElement.parentNode.insertBefore(container, existElement);
814
- domUtils.removeItem(originEl);
815
- this.nodeTransform.removeEmptyNode(existElement, null, true);
816
- } else {
817
- if (this.format.isLineOnly(existElement.parentNode)) {
818
- const formats = existElement.parentNode;
819
- formats.parentNode.insertBefore(container, existElement.previousSibling ? formats.nextElementSibling : formats);
820
- if (this.fileManager.__updateTags.map((current) => existElement.contains(current)).length === 0) domUtils.removeItem(existElement);
821
- } else {
822
- existElement = domUtils.isFigure(existElement.parentNode) ? domUtils.getParentElement(existElement.parentNode, Figure.__is) : existElement;
823
- existElement.parentNode.replaceChild(container, existElement);
1204
+ /**
1205
+ * @param {MouseEvent} e Event object
1206
+ */
1207
+ #OnResizeContainer(e) {
1208
+ e.stopPropagation();
1209
+ e.preventDefault();
1210
+
1211
+ const eventTarget = dom.query.getEventTarget(e);
1212
+ const inst = _DragHandle.get('__figureInst');
1213
+ const direction = (inst._resize_direction = eventTarget.classList[0]);
1214
+ inst._resizeClientX = e.clientX;
1215
+ inst._resizeClientY = e.clientY;
1216
+ inst.editor.frameContext.get('_figure').main.style.float = /l/.test(direction) ? 'right' : /r/.test(direction) ? 'left' : 'none';
1217
+ this.ui.enableBackWrapper(DIRECTION_CURSOR_MAP[direction]);
1218
+
1219
+ const { w, h } = this.getSize(inst._element);
1220
+ __resizing_p_wh = __resizing_p_ow = false;
1221
+ __resizing_cw = __resizing_sw = 0;
1222
+ if (!this.isVertical) {
1223
+ const pw = !w || /auto|%$/.test(w);
1224
+ const ph = !h || /auto|%$/.test(h);
1225
+ if (DIR_DIAGONAL.includes(direction) && pw && ph) {
1226
+ __resizing_p_wh = true;
1227
+ } else if (DIR_W.includes(direction) && pw) {
1228
+ __resizing_p_ow = true;
1229
+ }
1230
+
1231
+ if (__resizing_p_wh || __resizing_p_ow) {
1232
+ const sizeTarget = inst._cover || inst._element;
1233
+ __resizing_sw = sizeTarget.offsetWidth;
1234
+ __resizing_cw = converter.getWidthInPercentage(sizeTarget, this.editor.frameContext.get('wysiwygFrame')) / 100;
824
1235
  }
825
1236
  }
826
- },
827
1237
 
828
- constructor: Figure
829
- };
1238
+ inst.__onContainerEvent = inst.eventManager.addGlobalEvent('mousemove', inst.__containerResizing);
1239
+ inst.__offContainerEvent = inst.eventManager.addGlobalEvent('mouseup', inst.__containerResizingOff);
1240
+ inst._displayResizeHandles(false);
830
1241
 
831
- function OnScrollDragHandler(dragHandle, figureMain) {
832
- dragHandle.style.display = 'block';
833
- dragHandle.style.left = figureMain.offsetLeft + (this.options.get('_rtl') ? dragHandle.offsetWidth : figureMain.offsetWidth - dragHandle.offsetWidth * 1.5) + 'px';
834
- dragHandle.style.top = figureMain.offsetTop - dragHandle.offsetHeight + 'px';
835
- }
1242
+ const _display = this.editor.frameContext.get('_figure').display;
1243
+ _display.style.display = 'block';
1244
+ dom.utils.changeTxt(_display, w + ' x ' + h);
1245
+ }
836
1246
 
837
- function GetRotateValue(element) {
838
- const transform = element.style.transform;
839
- if (!transform) return { r: 0, x: '', y: '' };
840
- return {
841
- r: ((transform.match(/rotate\(([-0-9]+)deg\)/) || [])[1] || 0) * 1,
842
- x: (transform.match(/rotateX\(([-0-9]+)deg\)/) || [])[1] || '',
843
- y: (transform.match(/rotateY\(([-0-9]+)deg\)/) || [])[1] || ''
844
- };
845
- }
1247
+ /**
1248
+ * @description Handles the resizing of the figure container.
1249
+ * @param {MouseEvent} e Mouse event.
1250
+ */
1251
+ #ContainerResizing(e) {
1252
+ const direction = this._resize_direction;
1253
+ const clientX = e.clientX;
1254
+ const clientY = e.clientY;
1255
+
1256
+ let resultW = this._element_w;
1257
+ let resultH = this._element_h;
1258
+
1259
+ const w = resultW + (/r/.test(direction) ? clientX - this._resizeClientX : this._resizeClientX - clientX);
1260
+ const h = resultH + (/b/.test(direction) ? clientY - this._resizeClientY : this._resizeClientY - clientY);
1261
+ const wh = (resultH / resultW) * w;
1262
+ const resizeBorder = this.editor.frameContext.get('_figure').border;
846
1263
 
847
- function OnResizeContainer(e) {
848
- e.stopPropagation();
849
- e.preventDefault();
850
-
851
- const inst = _DragHandle.get('__figureInst');
852
- const direction = (inst._resize_direction = e.target.classList[0]);
853
- inst._resizeClientX = e.clientX;
854
- inst._resizeClientY = e.clientY;
855
- inst.editor.frameContext.get('_figure').main.style.float = /l/.test(direction) ? 'right' : /r/.test(direction) ? 'left' : 'none';
856
- this.editor.enableBackWrapper(DIRECTION_CURSOR_MAP[direction]);
857
-
858
- const { w, h } = this.getSize(inst._element);
859
- __resizing_p_wh = __resizing_p_ow = false;
860
- __resizing_cw = __resizing_sw = 0;
861
- if (!this.isVertical) {
862
- const pw = !w || /auto|%$/.test(w);
863
- const ph = !h || /auto|%$/.test(h);
864
- if (DIR_DIAGONAL.includes(direction) && pw && ph) {
865
- __resizing_p_wh = true;
866
- } else if (DIR_W.includes(direction) && pw) {
867
- __resizing_p_ow = true;
1264
+ if (/t/.test(direction)) resizeBorder.style.top = resultH - (/h/.test(direction) ? h : wh) + 'px';
1265
+ if (/l/.test(direction)) resizeBorder.style.left = resultW - w + 'px';
1266
+
1267
+ if (/r|l/.test(direction)) {
1268
+ resizeBorder.style.width = w + 'px';
1269
+ resultW = w;
868
1270
  }
869
1271
 
870
- if (__resizing_p_wh || __resizing_p_ow) {
871
- const sizeTarget = inst._cover || inst._element;
872
- __resizing_sw = sizeTarget.offsetWidth;
873
- __resizing_cw = converter.getWidthInPercentage(sizeTarget, this.editor.frameContext.get('wysiwygFrame')) / 100;
1272
+ if (/^(t|b)[^h]$/.test(direction)) {
1273
+ resizeBorder.style.height = wh + 'px';
1274
+ resultH = wh;
1275
+ } else if (/^(t|b)h$/.test(direction)) {
1276
+ resizeBorder.style.height = h + 'px';
1277
+ resultH = h;
874
1278
  }
875
- }
876
1279
 
877
- inst.__onContainerEvent = inst.eventManager.addGlobalEvent('mousemove', inst.__containerResizing);
878
- inst.__offContainerEvent = inst.eventManager.addGlobalEvent('mouseup', inst.__containerResizingOff);
879
- inst._displayResizeHandles(false);
880
- }
1280
+ this._resize_w = /** @type {number} */ (/h$/.test(direction) ? this._width : Math.round(resultW));
1281
+ this._resize_h = /** @type {number} */ (/w$/.test(direction) ? this._height : Math.round(resultH));
1282
+ const rw = __resizing_cw ? (this._resize_w / __resizing_sw) * __resizing_cw * 100 : this._resize_w;
1283
+ dom.utils.changeTxt(this.editor.frameContext.get('_figure').display, __resizing_cw ? numbers.get(rw > 100 ? 100 : rw, 2).toFixed(2) + '%' : rw + ' x ' + this._resize_h);
1284
+ }
881
1285
 
882
- function ContainerResizing(e) {
883
- const direction = this._resize_direction;
884
- const clientX = e.clientX;
885
- const clientY = e.clientY;
1286
+ /**
1287
+ * @description Finalizes the resizing process of the figure container.
1288
+ */
1289
+ #ContainerResizingOff() {
1290
+ this._offResizeEvent();
1291
+
1292
+ // set size
1293
+ let w = this.isVertical ? this._resize_h : this._resize_w;
1294
+ let h = this.isVertical ? this._resize_w : this._resize_h;
1295
+ w = Math.round(w) || w;
1296
+ h = Math.round(h) || h;
1297
+
1298
+ if (!this.isVertical && !/%$/.test(w + '')) {
1299
+ const limit =
1300
+ this.editor.frameContext.get('wysiwygFrame').clientWidth -
1301
+ numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-left')) +
1302
+ numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-right')) -
1303
+ 2;
1304
+ if (numbers.get(w, 0) > limit) {
1305
+ h = Math.round((h / w) * limit);
1306
+ w = limit;
1307
+ }
1308
+ }
886
1309
 
887
- let resultW = this._element_w;
888
- let resultH = this._element_h;
1310
+ if (__resizing_p_wh || __resizing_p_ow) {
1311
+ const sizeTarget = this._cover || this._element;
1312
+ w = (w / sizeTarget.offsetWidth) * __resizing_cw * 100;
1313
+ const wp = numbers.get(w > 100 ? 100 : w, 2) + '%';
1314
+ this._setPercentSize(wp, __resizing_p_ow ? this.getSize(this._element).h : '');
1315
+ } else {
1316
+ this._applySize(w, h, this._resize_direction);
1317
+ if (this.isVertical) this.setTransform(this._element, w, h, 0);
1318
+ }
889
1319
 
890
- const w = resultW + (/r/.test(direction) ? clientX - this._resizeClientX : this._resizeClientX - clientX);
891
- const h = resultH + (/b/.test(direction) ? clientY - this._resizeClientY : this._resizeClientY - clientY);
892
- const wh = (resultH / resultW) * w;
893
- const resizeBorder = this.editor.frameContext.get('_figure').border;
1320
+ this.history.push(false);
1321
+ this.component.select(this._element, this.kind);
1322
+ }
894
1323
 
895
- if (/t/.test(direction)) resizeBorder.style.top = resultH - (/h/.test(direction) ? h : wh) + 'px';
896
- if (/l/.test(direction)) resizeBorder.style.left = resultW - w + 'px';
1324
+ /**
1325
+ * @description Cancels the resizing process when the escape key is pressed.
1326
+ * @param {KeyboardEvent} e Keyboard event.
1327
+ */
1328
+ #ContainerResizingESC(e) {
1329
+ if (!keyCodeMap.isEsc(e.code)) return;
1330
+ this._offResizeEvent();
1331
+ this.component.select(this._element, this.kind);
1332
+ }
897
1333
 
898
- if (/r|l/.test(direction)) {
899
- resizeBorder.style.width = w + 'px';
900
- resultW = w;
1334
+ /**
1335
+ * @param { "none"|"left"|"center"|"right"} value align value
1336
+ */
1337
+ #SetMenuAlign(value) {
1338
+ this.setAlign(this._element, value);
1339
+ this.selectMenu_align.close();
1340
+ this.component.select(this._element, this.kind);
901
1341
  }
902
1342
 
903
- if (/^(t|b)[^h]$/.test(direction)) {
904
- resizeBorder.style.height = wh + 'px';
905
- resultH = wh;
906
- } else if (/^(t|b)h$/.test(direction)) {
907
- resizeBorder.style.height = h + 'px';
908
- resultH = h;
1343
+ /**
1344
+ * @param {"block"|"inline"} value Format style
1345
+ */
1346
+ #SetMenuAs(value) {
1347
+ this.convertAsFormat(this._element, value);
1348
+ this.selectMenu_as.close();
909
1349
  }
910
1350
 
911
- this._resize_w = /h$/.test(direction) ? this._width : Math.round(resultW);
912
- this._resize_h = /w$/.test(direction) ? this._height : Math.round(resultH);
913
- const rw = __resizing_cw ? (this._resize_w / __resizing_sw) * __resizing_cw * 100 : this._resize_w;
914
- domUtils.changeTxt(this.editor.frameContext.get('_figure').display, __resizing_cw ? numbers.get(rw > 100 ? 100 : rw, 2).toFixed(2) + '%' : rw + ' x ' + this._resize_h);
915
- }
1351
+ /**
1352
+ * @param {"auto"|number} value Resize value
1353
+ */
1354
+ #SetResize(value) {
1355
+ if (value === 'auto') {
1356
+ this.deleteTransform();
1357
+ this._setAutoSize();
1358
+ } else {
1359
+ let dataY = this.getSize(this._element).h;
1360
+ if (this.isVertical) {
1361
+ const dataSize = (this._element.getAttribute('data-se-size') || ',').split(',');
1362
+ if (dataSize[1]) dataY = dataSize[1];
1363
+ }
916
1364
 
917
- function ContainerResizingOff() {
918
- this._offResizeEvent();
919
-
920
- // set size
921
- let w = this.isVertical ? this._resize_h : this._resize_w;
922
- let h = this.isVertical ? this._resize_w : this._resize_h;
923
- w = Math.round(w) || w;
924
- h = Math.round(h) || h;
925
-
926
- if (!this.isVertical && !/%$/.test(w)) {
927
- const limit =
928
- this.editor.frameContext.get('wysiwygFrame').clientWidth -
929
- numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-left')) +
930
- numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-right')) -
931
- 2;
932
- if (numbers.get(w, 0) > limit) {
933
- h = Math.round((h / w) * limit);
934
- w = limit;
1365
+ this.deleteTransform();
1366
+ this._setPercentSize(value * 1, numbers.get(dataY, 0) === null || !/%$/.test(dataY) ? '' : dataY);
935
1367
  }
936
- }
937
1368
 
938
- if (__resizing_p_wh || __resizing_p_ow) {
939
- const sizeTarget = this._cover || this._element;
940
- w = (w / sizeTarget.offsetWidth) * __resizing_cw * 100;
941
- w = numbers.get(w > 100 ? 100 : w, 2) + '%';
942
- this._setPercentSize(w, __resizing_p_ow ? this.getSize(this._element).h : '');
943
- } else {
944
- this._applySize(w, h, this._resize_direction);
945
- if (this.isVertical) this.setTransform(this._element, w, h, 0);
1369
+ this.selectMenu_resize.close();
1370
+ this.component.select(this._element, this.kind);
946
1371
  }
947
1372
 
948
- this.history.push(false);
949
- this.component.select(this._element, this.kind, false);
950
- }
1373
+ #OffFigureContainer() {
1374
+ this.editor.frameContext.get('_figure').main.style.display = 'none';
1375
+ this.editor._figureContainer = null;
1376
+ }
951
1377
 
952
- function ContainerResizingESC(e) {
953
- if (!/^27$/.test(e.keyCode)) return;
954
- this._offResizeEvent();
955
- this.component.select(this._element, this.kind, false);
956
- }
1378
+ #OnClick_alignButton() {
1379
+ this.selectMenu_align.open('', '[data-command="' + this.align + '"]');
1380
+ }
957
1381
 
958
- function SetMenuAlign(value) {
959
- this.setAlign(this._element, value);
960
- this.selectMenu_align.close();
961
- this.component.select(this._element, this.kind, false);
962
- }
1382
+ #OnClick_asButton() {
1383
+ this.selectMenu_as.open('', '[data-command="' + this.as + '"]');
1384
+ }
963
1385
 
964
- function SetResize(value) {
965
- if (value === 'auto') {
966
- this.deleteTransform();
967
- this._setAutoSize();
968
- } else {
969
- let dataY = this.getSize(this._element).h;
970
- if (this.isVertical) {
971
- const dataSize = (this._element.getAttribute('data-se-size') || ',').split(',');
972
- if (dataSize[1]) dataY = dataSize[1];
1386
+ #OnClick_resizeButton() {
1387
+ const size = this.getSize(this._element);
1388
+ const w = size.w;
1389
+ const h = size.h;
1390
+ let command = '';
1391
+ if (this.autoRatio) {
1392
+ if (h === this.autoRatio.default && /%$/.test(w)) {
1393
+ const nw = numbers.get(w);
1394
+ if (nw === 100) command = 'auto';
1395
+ else command = 'resize_percent' + nw;
1396
+ }
1397
+ } else if (h === 'auto') {
1398
+ if (w === 'auto') {
1399
+ command = 'auto';
1400
+ } else if (/%$/.test(w)) {
1401
+ command = 'resize_percent' + numbers.get(w);
1402
+ }
973
1403
  }
974
1404
 
975
- this.deleteTransform();
976
- this._setPercentSize(value * 1, numbers.get(dataY, 0) === null || !/%$/.test(dataY) ? '' : dataY);
1405
+ this.selectMenu_resize.open('', '[data-command="' + command + '"]');
977
1406
  }
978
1407
 
979
- this.selectMenu_resize.close();
980
- this.component.select(this._element, this.kind, false);
1408
+ /**
1409
+ * @param {Node} element Target element
1410
+ * @returns {{ r: *, x: *, y: * }} Rotation value
1411
+ */
1412
+ #GetRotateValue(element) {
1413
+ const transform = /** @type {HTMLElement} */ (element).style.transform;
1414
+ if (!transform) return { r: 0, x: '', y: '' };
1415
+ return {
1416
+ r: Number((transform.match(/rotate\(([-0-9]+)deg\)/) || [])[1] || 0),
1417
+ x: (transform.match(/rotateX\(([-0-9]+)deg\)/) || [])[1] || '',
1418
+ y: (transform.match(/rotateY\(([-0-9]+)deg\)/) || [])[1] || ''
1419
+ };
1420
+ }
981
1421
  }
982
1422
 
983
1423
  function CreateAlign(inst, button) {
@@ -990,7 +1430,29 @@ function CreateAlign(inst, button) {
990
1430
  const items = [];
991
1431
  for (let i = 0; i < commands.length; i++) {
992
1432
  html.push(/*html*/ `
993
- <button type="button" class="se-btn-list se-tooltip" data-command="${commands[i]}">
1433
+ <button type="button" class="se-btn-list se-tooltip" data-command="${commands[i]}" data-type="selectMenu" >
1434
+ ${icons[i]}
1435
+ <span class="se-tooltip-inner">
1436
+ <span class="se-tooltip-text">${langs[i]}</span>
1437
+ </span>
1438
+ </button>`);
1439
+ items.push(commands[i]);
1440
+ }
1441
+
1442
+ return { html: html, items: items };
1443
+ }
1444
+
1445
+ function CreateAs(inst, button) {
1446
+ if (!button) return null;
1447
+
1448
+ const icons = [inst.icons.as_block, inst.icons.as_inline];
1449
+ const langs = [inst.lang.asBlock, inst.lang.asInline];
1450
+ const commands = ['block', 'inline'];
1451
+ const html = [];
1452
+ const items = [];
1453
+ for (let i = 0; i < commands.length; i++) {
1454
+ html.push(/*html*/ `
1455
+ <button type="button" class="se-btn-list se-tooltip" data-command="${commands[i]}" data-type="selectMenu" >
994
1456
  ${icons[i]}
995
1457
  <span class="se-tooltip-inner">
996
1458
  <span class="se-tooltip-text">${langs[i]}</span>
@@ -1018,37 +1480,6 @@ function CreateResize(editor, button) {
1018
1480
  return { html: html, items: items };
1019
1481
  }
1020
1482
 
1021
- function OffFigureContainer() {
1022
- this.editor.frameContext.get('_figure').main.style.display = 'none';
1023
- this.editor._figureContainer = null;
1024
- }
1025
-
1026
- function OnClick_alignButton() {
1027
- this.selectMenu_align.open('', '[data-command="' + this.align + '"]');
1028
- }
1029
-
1030
- function OnClick_resizeButton() {
1031
- const size = this.getSize(this._element);
1032
- const w = size.w;
1033
- const h = size.h;
1034
- let command = '';
1035
- if (this.autoRatio) {
1036
- if (h === this.autoRatio.default && /%$/.test(w)) {
1037
- const nw = numbers.get(w);
1038
- if (nw === 100) command = 'auto';
1039
- else command = 'resize_percent' + nw;
1040
- }
1041
- } else if (h === 'auto') {
1042
- if (w === 'auto') {
1043
- command = 'auto';
1044
- } else if (/%$/.test(w)) {
1045
- command = 'resize_percent' + numbers.get(w);
1046
- }
1047
- }
1048
-
1049
- this.selectMenu_resize.open('', '[data-command="' + command + '"]');
1050
- }
1051
-
1052
1483
  function CreateHTML_resizeDot() {
1053
1484
  const html = /*html*/ `
1054
1485
  <div class="se-resize-dot">
@@ -1063,7 +1494,7 @@ function CreateHTML_resizeDot() {
1063
1494
  <div class="se-resize-display"></div>
1064
1495
  </div>`;
1065
1496
 
1066
- return domUtils.createElement('DIV', { class: 'se-controller se-resizing-container', style: 'display: none;' }, html);
1497
+ return dom.utils.createElement('DIV', { class: 'se-controller se-resizing-container', style: 'display: none;' }, html);
1067
1498
  }
1068
1499
 
1069
1500
  function GET_CONTROLLER_BUTTONS(group) {
@@ -1116,6 +1547,16 @@ function GET_CONTROLLER_BUTTONS(group) {
1116
1547
  l = 'edit';
1117
1548
  i = 'edit';
1118
1549
  break;
1550
+ case 'as':
1551
+ c = 'onas';
1552
+ l = 'blockStyle';
1553
+ i = 'as_block';
1554
+ break;
1555
+ case 'copy':
1556
+ c = 'copy';
1557
+ l = 'copy';
1558
+ i = 'copy';
1559
+ break;
1119
1560
  case 'remove':
1120
1561
  c = 'remove';
1121
1562
  l = 'remove';
@@ -1161,8 +1602,8 @@ function CreateHTML_controller(inst, controls) {
1161
1602
  }
1162
1603
 
1163
1604
  html += /*html*/ `
1164
- <button type="button" data-command="${m.c}" data-value="${m.v}" class="${m.t ? 'se-btn-w-auto ' : ''}se-btn se-tooltip">
1165
- ${icons[m.i] || m.t || m.i}
1605
+ <button type="button" data-command="${m.c}" data-value="${m.v}" class="se-btn se-tooltip">
1606
+ ${icons[m.i] || m.i}
1166
1607
  <span class="se-tooltip-inner"><span class="se-tooltip-text">${lang[m.l] || m.l}</span></span>
1167
1608
  </button>`;
1168
1609
  }
@@ -1170,7 +1611,7 @@ function CreateHTML_controller(inst, controls) {
1170
1611
  }
1171
1612
  }
1172
1613
 
1173
- return domUtils.createElement('DIV', { class: 'se-controller se-controller-resizing' + (!html ? ' se-empty-controller' : '') }, html);
1614
+ return dom.utils.createElement('DIV', { class: 'se-controller se-controller-resizing' + (!html ? ' se-empty-controller' : '') }, html);
1174
1615
  }
1175
1616
 
1176
1617
  export default Figure;