suneditor 2.46.2 → 3.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +11 -1560
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +97 -70
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-contents.css +643 -0
  11. package/src/assets/suneditor.css +3394 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +37 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +74 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +1002 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +147 -0
  17. package/src/core/base/eventManager.js +1156 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +147 -0
  21. package/src/core/class/component.js +639 -0
  22. package/src/core/class/format.js +3258 -0
  23. package/src/core/class/html.js +1710 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +405 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +575 -0
  28. package/src/core/class/selection.js +511 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1601 -0
  33. package/src/core/section/actives.js +145 -0
  34. package/src/core/section/constructor.js +1252 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +388 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +210 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +210 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +323 -0
  72. package/src/modules/Figure.js +1176 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +307 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +90 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +90 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +181 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +492 -0
  104. package/src/plugins/modal/image.js +1064 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +363 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,1176 @@
1
+ import EditorInjector from '../editorInjector';
2
+ import { Controller, SelectMenu, _DragHandle } from '../modules';
3
+ import { domUtils, numbers, env, converter } from '../helper';
4
+
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' };
7
+ const DIR_DIAGONAL = 'tl|bl|tr|br';
8
+ const DIR_W = 'lw|rw';
9
+ let __resizing_p_wh = false;
10
+ let __resizing_p_ow = false;
11
+ let __resizing_cw = 0;
12
+ let __resizing_sw = 0;
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
+ };
100
+
101
+ /**
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}
106
+ */
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
+
112
+ /**
113
+ * @description Return HTML string of caption(FIGCAPTION) element
114
+ * @param {Element} cover Cover element(FIGURE). "CreateContainer().cover"
115
+ * @returns {Element} caption element
116
+ */
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
+
123
+ /**
124
+ * @description Get the element's container(.se-component) info.
125
+ * @param {Element} element Target element
126
+ * @returns {object} {container, cover, caption}
127
+ */
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
+
138
+ /**
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}}
144
+ */
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;
156
+ }
157
+ }
158
+
159
+ return {
160
+ w: numbers.get(rw, 4),
161
+ h: numbers.get(rh, 4)
162
+ };
163
+ };
164
+
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;
183
+ }
184
+ }
185
+
186
+ return {
187
+ w: w,
188
+ h: h
189
+ };
190
+ };
191
+
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
+ };
201
+
202
+ Figure.prototype = {
203
+ /**
204
+ * @override controller
205
+ */
206
+ close() {
207
+ this.editor._antiBlur = false;
208
+ domUtils.removeClass(this._cover, 'se-figure-selected');
209
+ this.controller.close();
210
+
211
+ if (domUtils.hasClass(this._w.event?.target, 'se-drag-handle|sun-editor-editable')) return;
212
+ this.component._removeDragEvent();
213
+ },
214
+
215
+ open(target, { nonResizing, nonSizeInfo, nonBorder, figureTarget, __fileManagerInfo }) {
216
+ if (!target) {
217
+ console.warn('[SUNEDITOR.modules.Figure.open] The target element is null.');
218
+ return;
219
+ }
220
+
221
+ if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
222
+ this.editor._offCurrentController();
223
+ } else {
224
+ nonBorder = true;
225
+ }
226
+
227
+ const figureInfo = Figure.GetContainer(target);
228
+ if (!figureInfo.container) return { container: null, cover: null };
229
+
230
+ _DragHandle.set('__figureInst', this);
231
+
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());
238
+
239
+ const sizeTarget = figureTarget ? this._cover || this._container || target : target;
240
+ const w = sizeTarget.offsetWidth;
241
+ const h = sizeTarget.offsetHeight;
242
+ const { top, left, scrollX, scrollY } = this.offset.getLocal(sizeTarget);
243
+
244
+ const dataSize = (target.getAttribute('data-se-size') || '').split(',');
245
+ const ratio = Figure.GetRatio(dataSize[0] || numbers.get(target.style.width, 2) || w, dataSize[1] || numbers.get(target.style.height, 2) || h, this.sizeUnit);
246
+ const targetInfo = {
247
+ container: figureInfo.container,
248
+ cover: figureInfo.cover,
249
+ caption: figureInfo.caption,
250
+ align: this.align,
251
+ ratio: ratio,
252
+ w: w,
253
+ h: h,
254
+ t: top,
255
+ l: left,
256
+ width: dataSize[0] || 'auto',
257
+ height: dataSize[1] || 'auto',
258
+ originWidth: target.naturalWidth || target.offsetWidth,
259
+ originHeight: target.naturalHeight || target.offsetHeight
260
+ };
261
+
262
+ this._width = targetInfo.width;
263
+ this._height = targetInfo.height;
264
+ if (__fileManagerInfo || this.__fileManagerInfo) return targetInfo;
265
+
266
+ const _figure = this.editor.frameContext.get('_figure');
267
+ this.editor._figureContainer = _figure.main;
268
+ _figure.main.style.top = top + 'px';
269
+ _figure.main.style.left = left + 'px';
270
+ _figure.main.style.width = (this.isVertical ? h : w) + 'px';
271
+ _figure.main.style.height = (this.isVertical ? w : h) + 'px';
272
+ _figure.border.style.top = '0px';
273
+ _figure.border.style.left = '0px';
274
+ _figure.border.style.width = (this.isVertical ? h : w) + 'px';
275
+ _figure.border.style.height = (this.isVertical ? w : h) + 'px';
276
+
277
+ this.__offset = { left: left + scrollX, top: top + scrollY };
278
+ this.editor.opendControllers.push({
279
+ position: 'none',
280
+ form: _figure.main,
281
+ target: sizeTarget,
282
+ inst: this,
283
+ notInCarrier: true
284
+ });
285
+
286
+ // percentage active
287
+ const value = /%$/.test(target.style.width) && /%$/.test(figureInfo.container.style.width) ? numbers.get(figureInfo.container.style.width, 0) / 100 + '' : '';
288
+ for (let i = 0, len = this.percentageButtons.length; i < len; i++) {
289
+ if (this.percentageButtons[i].getAttribute('data-value') === value) {
290
+ domUtils.addClass(this.percentageButtons[i], 'active');
291
+ } else {
292
+ domUtils.removeClass(this.percentageButtons[i], 'active');
293
+ }
294
+ }
295
+
296
+ // caption active
297
+ if (this.captionButton) {
298
+ if (figureInfo.caption) {
299
+ domUtils.addClass(this.captionButton, 'active');
300
+ } else {
301
+ domUtils.removeClass(this.captionButton, 'active');
302
+ }
303
+ }
304
+
305
+ _figure.display.style.display = nonSizeInfo ? 'none' : '';
306
+ _figure.border.style.display = nonBorder ? 'none' : '';
307
+ _figure.main.style.display = 'block';
308
+
309
+ if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
310
+ // align button
311
+ this._setAlignIcon();
312
+ this.editor._visibleControllers(true, true);
313
+ // size
314
+ const size = this.getSize(target);
315
+ domUtils.changeTxt(_figure.display, this.lang[this.align === 'none' ? 'basic' : this.align] + ' (' + size.w + ', ' + size.h + ')');
316
+ this._displayResizeHandles(!nonResizing);
317
+ // selecte
318
+ domUtils.removeClass(this._cover, 'se-figure-over-selected');
319
+ this.controller.open(_figure.main, null, { initMethod: this.__offContainer, isWWTarget: false, addOffset: null });
320
+ this._w.setTimeout(() => _DragHandle.set('__overInfo', false), 0);
321
+ } else {
322
+ domUtils.addClass(this._cover, 'se-figure-over-selected');
323
+ }
324
+
325
+ // set members
326
+ domUtils.addClass(this._cover, 'se-figure-selected');
327
+ this._element_w = this._resize_w = w;
328
+ this._element_h = this._resize_h = h;
329
+ this._element_l = left;
330
+ this._element_t = top;
331
+
332
+ // drag
333
+ if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT || domUtils.hasClass(figureInfo.container, 'se-input-component')) {
334
+ this._setDragEvent(_figure.main);
335
+ }
336
+
337
+ return targetInfo;
338
+ },
339
+
340
+ controllerHide() {
341
+ this.controller.hide();
342
+ },
343
+
344
+ controllerShow() {
345
+ this.controller.show();
346
+ },
347
+
348
+ controllerOpen(target, args) {
349
+ this._element = target;
350
+ this.controller.open(target, null, args);
351
+ },
352
+
353
+ setSize(w, h) {
354
+ if (/%$/.test(w)) {
355
+ this._setPercentSize(w, h);
356
+ } else if ((!w || w === 'auto') && (!h || h === 'auto')) {
357
+ if (this.autoRatio) this._setPercentSize(100, this.autoRatio.default || this.autoRatio.current);
358
+ else this._setAutoSize();
359
+ } else {
360
+ this._applySize(w, h, '');
361
+ }
362
+ },
363
+
364
+ /**
365
+ * @description Gets the Figure size
366
+ * @param {Element|null} target
367
+ * @returns {{w: string, h: string}}
368
+ */
369
+ getSize(target) {
370
+ if (!target) target = this._element;
371
+ if (!target) return { w: '', h: '' };
372
+
373
+ const figure = Figure.GetContainer(target);
374
+ if (!figure.container) {
375
+ return {
376
+ w: '',
377
+ h: target.style.height
378
+ };
379
+ }
380
+
381
+ 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) + '%';
388
+ return {
389
+ w: w || 'auto',
390
+ h: h || 'auto'
391
+ };
392
+ },
393
+
394
+ /**
395
+ * @description Align the container.
396
+ * @param {Element|null} target Target element
397
+ * @param {"none"|"left"|"center"|"right"} align
398
+ */
399
+ setAlign(target, align) {
400
+ if (!target) target = this._element;
401
+ this.align = align = align || 'none';
402
+
403
+ const figure = Figure.GetContainer(target);
404
+ const container = figure.container;
405
+
406
+ const cover = figure.cover;
407
+ if (/%$/.test(target.style.width) && align === 'center' && !this.component.isInline(container)) {
408
+ container.style.minWidth = '100%';
409
+ cover.style.width = container.style.width;
410
+ } else {
411
+ 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%';
413
+ }
414
+
415
+ if (!domUtils.hasClass(container, '__se__float-' + align)) {
416
+ domUtils.removeClass(container, this._floatClassStr);
417
+ domUtils.addClass(container, '__se__float-' + align);
418
+ }
419
+
420
+ if (this.autoRatio) {
421
+ const { w, h } = this.getSize(this._element);
422
+ this.__setCoverPaddingBottom(w, h);
423
+ }
424
+
425
+ this._setAlignIcon();
426
+ },
427
+
428
+ /**
429
+ * @override controller
430
+ * @param {Element} target Target button element
431
+ * @returns
432
+ */
433
+ controllerAction(target) {
434
+ const command = target.getAttribute('data-command');
435
+ const value = target.getAttribute('data-value');
436
+ const element = this._element;
437
+ if (/^(onalign|onresize)$/.test(command)) return;
438
+
439
+ switch (command) {
440
+ case 'mirror': {
441
+ const info = GetRotateValue(element);
442
+ let x = info.x;
443
+ let y = info.y;
444
+
445
+ if ((value === 'h' && !this.isVertical) || (value === 'v' && this.isVertical)) {
446
+ y = y ? '' : '180';
447
+ } else {
448
+ x = x ? '' : '180';
449
+ }
450
+
451
+ this._setRotate(element, info.r, x, y);
452
+ break;
453
+ }
454
+ case 'rotate':
455
+ this.setTransform(element, null, null, value);
456
+ break;
457
+ case 'caption':
458
+ if (!this._caption) {
459
+ const caption = Figure.CreateCaption(this._cover, this.lang.caption);
460
+ const captionText = domUtils.getEdgeChild(caption, (current) => current.nodeType === 3);
461
+
462
+ if (!captionText) {
463
+ caption.focus();
464
+ } else {
465
+ this.selection.setRange(captionText, 0, captionText, captionText.textContent.length);
466
+ }
467
+
468
+ this.controller.close();
469
+ } else {
470
+ domUtils.removeItem(this._caption);
471
+ this._w.setTimeout(this.component.select.bind(this.component, element, this.kind), 0);
472
+ }
473
+
474
+ this._caption = !this._caption;
475
+ if (/\d+/.test(element.style.height) || (this.isVertical && this._caption)) {
476
+ if (/%$/.test(element.style.width) || /auto/.test(element.style.height)) {
477
+ this.deleteTransform();
478
+ } else {
479
+ this.setTransform(element, element.style.width, element.style.height, 0);
480
+ }
481
+ }
482
+ break;
483
+ case 'revert':
484
+ this._setRevert();
485
+ break;
486
+ case 'edit':
487
+ this.inst.edit(element);
488
+ break;
489
+ case 'remove':
490
+ this.inst.destroy(element);
491
+ this.controller.close();
492
+ break;
493
+ }
494
+
495
+ if (/^__c__/.test(command)) {
496
+ this._action[command](element, value, target);
497
+ return;
498
+ }
499
+
500
+ if (/^edit$/.test(command)) return;
501
+
502
+ this.history.push(false);
503
+ if (!/^remove|caption$/.test(command)) {
504
+ this.component.select(element, this.kind, false);
505
+ }
506
+ },
507
+
508
+ /**
509
+ * @description Initialize the transform style (rotation) of the element.
510
+ * @param {Element|null} element Target element
511
+ */
512
+ deleteTransform(element) {
513
+ if (!element) element = this._element;
514
+
515
+ const size = (element.getAttribute('data-se-size') || '').split(',');
516
+ this.isVertical = false;
517
+
518
+ element.style.maxWidth = '';
519
+ element.style.transform = '';
520
+ element.style.transformOrigin = '';
521
+
522
+ this._deleteCaptionPosition(element);
523
+ this._applySize(size[0] || 'auto', size[1] || '', '');
524
+ },
525
+
526
+ /**
527
+ * @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
531
+ */
532
+ setTransform(element, width, height, deg) {
533
+ try {
534
+ this.__preventSizechange = true;
535
+ const info = GetRotateValue(element);
536
+ const slope = info.r + (deg || 0) * 1;
537
+ deg = Math.abs(slope) >= 360 ? 0 : slope;
538
+ const isVertical = (this.isVertical = /^(90|270)$/.test(Math.abs(deg).toString()));
539
+
540
+ width = numbers.get(width, 0);
541
+ height = numbers.get(height, 0);
542
+
543
+ const dataSize = (element.getAttribute('data-se-size') || 'auto,auto').split(',');
544
+ let transOrigin = '';
545
+ if (/auto|%$/.test(dataSize[0]) && !isVertical) {
546
+ if (dataSize[0] === 'auto' && dataSize[1] === 'auto') {
547
+ this._setAutoSize();
548
+ } else {
549
+ this._setPercentSize(dataSize[0], dataSize[1]);
550
+ }
551
+ } else {
552
+ const figureInfo = Figure.GetContainer(element);
553
+ const offsetW = width || element.offsetWidth;
554
+ const offsetH = height || element.offsetHeight;
555
+ const w = (isVertical ? offsetH : offsetW) + 'px';
556
+ const h = (isVertical ? offsetW : offsetH) + 'px';
557
+
558
+ this._deletePercentSize();
559
+ this._applySize(offsetW + 'px', offsetH + 'px', '');
560
+
561
+ figureInfo.cover.style.width = w;
562
+ figureInfo.cover.style.height = figureInfo.caption ? '' : h;
563
+
564
+ if (isVertical) {
565
+ const transW = offsetW / 2 + 'px ' + offsetW / 2 + 'px 0';
566
+ const transH = offsetH / 2 + 'px ' + offsetH / 2 + 'px 0';
567
+ transOrigin = deg === 90 || deg === -270 ? transH : transW;
568
+ }
569
+ }
570
+
571
+ element.style.transformOrigin = transOrigin;
572
+ this._setRotate(element, deg, info.x, info.y);
573
+
574
+ if (isVertical) element.style.maxWidth = 'none';
575
+ else element.style.maxWidth = '';
576
+
577
+ this._setCaptionPosition(element);
578
+ } finally {
579
+ this.__preventSizechange = false;
580
+ }
581
+ },
582
+
583
+ _setRotate(element, r, x, y) {
584
+ let width = (element.offsetWidth - element.offsetHeight) * (/^-/.test(r) ? 1 : -1);
585
+ let translate = '';
586
+
587
+ if (/[1-9]/.test(r) && (x || y)) {
588
+ translate = x ? 'Y' : 'X';
589
+
590
+ switch (r + '') {
591
+ case '90':
592
+ translate = x && y ? 'X' : y ? translate : '';
593
+ break;
594
+ case '270':
595
+ width *= -1;
596
+ translate = x && y ? 'Y' : x ? translate : '';
597
+ break;
598
+ case '-90':
599
+ translate = x && y ? 'Y' : x ? translate : '';
600
+ break;
601
+ case '-270':
602
+ width *= -1;
603
+ translate = x && y ? 'X' : y ? translate : '';
604
+ break;
605
+ default:
606
+ translate = '';
607
+ }
608
+ }
609
+
610
+ if (r % 180 === 0) {
611
+ element.style.maxWidth = '';
612
+ }
613
+
614
+ element.style.transform = 'rotate(' + r + 'deg)' + (x ? ' rotateX(' + x + 'deg)' : '') + (y ? ' rotateY(' + y + 'deg)' : '') + (translate ? ' translate' + translate + '(' + width + 'px)' : '');
615
+ },
616
+
617
+ _applySize(w, h, direction) {
618
+ const onlyW = /^(rw|lw)$/.test(direction) && /\d+/.test(this._element.style.height);
619
+ 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;
622
+
623
+ if (!/%$/.test(w) && !/%$/.test(h) && !onlyW && !onlyH) this._deletePercentSize();
624
+
625
+ const sizeTarget = this._cover || this._element;
626
+
627
+ if (this.autoRatio) this._cover.style.width = w;
628
+ if (!onlyH) {
629
+ sizeTarget.style.width = this._element.style.width = w;
630
+ }
631
+ if (!onlyW) {
632
+ h = numbers.is(h) ? h + this.sizeUnit : h;
633
+ sizeTarget.style.height = this._element.style.height = this.autoRatio && !this.isVertical ? '100%' : h;
634
+ if (this.autoRatio) {
635
+ this._cover.style.height = h;
636
+ this.__setCoverPaddingBottom(w, h);
637
+ }
638
+ }
639
+
640
+ if (this.align === 'center') this.setAlign(this._element, this.align);
641
+
642
+ // save current size
643
+ this._saveCurrentSize();
644
+ },
645
+
646
+ __setCoverPaddingBottom(w, h) {
647
+ this._cover.style.height = h;
648
+ if (/%$/.test(w) && this.align === 'center') {
649
+ this._cover.style.paddingBottom = !/%$/.test(h) ? h : numbers.get((numbers.get(h, 2) / 100) * numbers.get(w, 2), 2) + '%';
650
+ } else {
651
+ this._cover.style.paddingBottom = h;
652
+ }
653
+ },
654
+
655
+ _setAutoSize() {
656
+ if (this._caption) this._caption.style.marginTop = '';
657
+ this.deleteTransform();
658
+ this._deletePercentSize();
659
+
660
+ if (this.autoRatio) {
661
+ this._setPercentSize('100%', this.autoRatio.current || this.autoRatio.default);
662
+ } else {
663
+ this._element.style.maxWidth = '';
664
+ this._element.style.width = '';
665
+ this._element.style.height = '';
666
+ this._cover.style.width = '';
667
+ this._cover.style.height = '';
668
+ }
669
+
670
+ this.setAlign(this._element, this.align);
671
+
672
+ // save current size
673
+ this._saveCurrentSize();
674
+ },
675
+
676
+ _setPercentSize(w, h) {
677
+ 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 : '');
679
+
680
+ const heightPercentage = /%$/.test(h);
681
+ this._container.style.width = numbers.is(w) ? w + '%' : w;
682
+ this._container.style.height = '';
683
+ this._cover.style.width = '100%';
684
+ this._cover.style.height = h;
685
+ this._element.style.width = '100%';
686
+ this._element.style.maxWidth = '';
687
+ this._element.style.height = this.autoRatio ? '100%' : heightPercentage ? '' : h;
688
+
689
+ if (this.align === 'center') this.setAlign(this._element, this.align);
690
+ if (this.autoRatio) {
691
+ this.__setCoverPaddingBottom(w, h);
692
+ }
693
+
694
+ this._setCaptionPosition(this._element);
695
+
696
+ // save current size
697
+ this._saveCurrentSize();
698
+ },
699
+
700
+ _deletePercentSize() {
701
+ this._cover.style.width = '';
702
+ this._cover.style.height = '';
703
+ this._container.style.width = '';
704
+ this._container.style.height = '';
705
+
706
+ domUtils.removeClass(this._container, this._floatClassStr);
707
+ domUtils.addClass(this._container, '__se__float-' + this.align);
708
+
709
+ if (this.align === 'center') this.setAlign(this._element, this.align);
710
+ },
711
+
712
+ _setRevert() {
713
+ this.setSize(this.__revertSize.w, this.__revertSize.h);
714
+ },
715
+
716
+ _setAlignIcon() {
717
+ if (!this.alignButton) return;
718
+ domUtils.changeElement(this.alignButton.firstElementChild, this._alignIcons[this.align]);
719
+ },
720
+
721
+ _saveCurrentSize() {
722
+ if (this.__preventSizechange) return;
723
+
724
+ const dataSize = (this._element.getAttribute('data-se-size') || ',').split(',');
725
+ this.__revertSize.w = dataSize[0];
726
+ this.__revertSize.h = dataSize[1];
727
+
728
+ const size = this.getSize(this._element);
729
+ // add too width, height attribute
730
+ this._element.setAttribute('width', size.w.replace('px', ''));
731
+ this._element.setAttribute('height', size.h.replace('px', ''));
732
+ this._element.setAttribute('data-se-size', size.w + ',' + size.h);
733
+ if (this.autoRatio) {
734
+ this.autoRatio.current = /%$/.test(size.h) ? size.h : '';
735
+ }
736
+ },
737
+
738
+ _setCaptionPosition(element) {
739
+ const figcaption = domUtils.getEdgeChild(domUtils.getParentElement(element, 'FIGURE'), 'FIGCAPTION');
740
+ if (figcaption) {
741
+ figcaption.style.marginTop = (this.isVertical ? element.offsetWidth - element.offsetHeight : 0) + 'px';
742
+ }
743
+ },
744
+
745
+ _deleteCaptionPosition(element) {
746
+ const figcaption = domUtils.getEdgeChild(domUtils.getParentElement(element, 'FIGURE'), 'FIGCAPTION');
747
+ if (figcaption) {
748
+ figcaption.style.marginTop = '';
749
+ }
750
+ },
751
+
752
+ _displayResizeHandles(display) {
753
+ display = !display ? 'none' : 'flex';
754
+ this.controller.form.style.display = display;
755
+
756
+ const _figure = this.editor.frameContext.get('_figure');
757
+ const resizeHandles = _figure.handles;
758
+ for (let i = 0, len = resizeHandles.length; i < len; i++) {
759
+ resizeHandles[i].style.display = display;
760
+ }
761
+
762
+ if (display === 'none') {
763
+ domUtils.addClass(_figure.main, 'se-resize-ing');
764
+ this.__onResizeESCEvent = this.eventManager.addGlobalEvent('keydown', this.__containerResizingESC);
765
+ } else {
766
+ domUtils.removeClass(_figure.main, 'se-resize-ing');
767
+ }
768
+ },
769
+
770
+ _offResizeEvent() {
771
+ this.component._removeDragEvent();
772
+ this.eventManager.removeGlobalEvent(this.__onContainerEvent);
773
+ this.eventManager.removeGlobalEvent(this.__offContainerEvent);
774
+ this.eventManager.removeGlobalEvent(this.__onResizeESCEvent);
775
+
776
+ this._displayResizeHandles(true);
777
+ this.editor._offCurrentController();
778
+ this.editor.disableBackWrapper();
779
+ },
780
+
781
+ _setDragEvent(figureMain) {
782
+ const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
783
+ domUtils.removeClass(dragHandle, 'se-drag-handle-full');
784
+
785
+ dragHandle.style.opacity = '';
786
+ dragHandle.style.width = '';
787
+ dragHandle.style.height = '';
788
+
789
+ _DragHandle.set('__dragHandler', dragHandle);
790
+ _DragHandle.set('__dragContainer', this._container);
791
+ _DragHandle.set('__dragCover', this._cover);
792
+ _DragHandle.set('__dragMove', OnScrollDragHandler.bind(this, dragHandle, figureMain));
793
+
794
+ _DragHandle.get('__dragMove')();
795
+
796
+ dragHandle.style.display = 'block';
797
+ },
798
+
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;
801
+
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);
824
+ }
825
+ }
826
+ },
827
+
828
+ constructor: Figure
829
+ };
830
+
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
+ }
836
+
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
+ }
846
+
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;
868
+ }
869
+
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;
874
+ }
875
+ }
876
+
877
+ inst.__onContainerEvent = inst.eventManager.addGlobalEvent('mousemove', inst.__containerResizing);
878
+ inst.__offContainerEvent = inst.eventManager.addGlobalEvent('mouseup', inst.__containerResizingOff);
879
+ inst._displayResizeHandles(false);
880
+ }
881
+
882
+ function ContainerResizing(e) {
883
+ const direction = this._resize_direction;
884
+ const clientX = e.clientX;
885
+ const clientY = e.clientY;
886
+
887
+ let resultW = this._element_w;
888
+ let resultH = this._element_h;
889
+
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;
894
+
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';
897
+
898
+ if (/r|l/.test(direction)) {
899
+ resizeBorder.style.width = w + 'px';
900
+ resultW = w;
901
+ }
902
+
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;
909
+ }
910
+
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
+ }
916
+
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;
935
+ }
936
+ }
937
+
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);
946
+ }
947
+
948
+ this.history.push(false);
949
+ this.component.select(this._element, this.kind, false);
950
+ }
951
+
952
+ function ContainerResizingESC(e) {
953
+ if (!/^27$/.test(e.keyCode)) return;
954
+ this._offResizeEvent();
955
+ this.component.select(this._element, this.kind, false);
956
+ }
957
+
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
+ }
963
+
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];
973
+ }
974
+
975
+ this.deleteTransform();
976
+ this._setPercentSize(value * 1, numbers.get(dataY, 0) === null || !/%$/.test(dataY) ? '' : dataY);
977
+ }
978
+
979
+ this.selectMenu_resize.close();
980
+ this.component.select(this._element, this.kind, false);
981
+ }
982
+
983
+ function CreateAlign(inst, button) {
984
+ if (!button) return null;
985
+
986
+ const icons = [inst._alignIcons.none, inst._alignIcons.left, inst._alignIcons.center, inst._alignIcons.right];
987
+ const langs = [inst.lang.basic, inst.lang.left, inst.lang.center, inst.lang.right];
988
+ const commands = ['none', 'left', 'center', 'right'];
989
+ const html = [];
990
+ const items = [];
991
+ for (let i = 0; i < commands.length; i++) {
992
+ html.push(/*html*/ `
993
+ <button type="button" class="se-btn-list se-tooltip" data-command="${commands[i]}">
994
+ ${icons[i]}
995
+ <span class="se-tooltip-inner">
996
+ <span class="se-tooltip-text">${langs[i]}</span>
997
+ </span>
998
+ </button>`);
999
+ items.push(commands[i]);
1000
+ }
1001
+
1002
+ return { html: html, items: items };
1003
+ }
1004
+
1005
+ function CreateResize(editor, button) {
1006
+ if (!button) return null;
1007
+
1008
+ const items = button.getAttribute('data-value').split(',');
1009
+ const html = [];
1010
+ for (let i = 0, n, c, v, l; i < items.length; i++) {
1011
+ v = items[i];
1012
+ n = numbers.is(v);
1013
+ c = n ? 'resize_percent' + v : 'auto';
1014
+ l = n ? v + '%' : editor.lang.autoSize;
1015
+ html.push('<button type="button" class="se-btn-list" data-command="' + c + '" data-value="' + v + '"><span>' + l + '</span></button>');
1016
+ }
1017
+
1018
+ return { html: html, items: items };
1019
+ }
1020
+
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
+ function CreateHTML_resizeDot() {
1053
+ const html = /*html*/ `
1054
+ <div class="se-resize-dot">
1055
+ <span class="tl"></span>
1056
+ <span class="tr"></span>
1057
+ <span class="bl"></span>
1058
+ <span class="br"></span>
1059
+ <span class="lw"></span>
1060
+ <span class="th"></span>
1061
+ <span class="rw"></span>
1062
+ <span class="bh"></span>
1063
+ <div class="se-resize-display"></div>
1064
+ </div>`;
1065
+
1066
+ return domUtils.createElement('DIV', { class: 'se-controller se-resizing-container', style: 'display: none;' }, html);
1067
+ }
1068
+
1069
+ function GET_CONTROLLER_BUTTONS(group) {
1070
+ const g = group.split('_');
1071
+ const command = g[0];
1072
+ const value = g[1];
1073
+ let c, v, l, t, i;
1074
+
1075
+ switch (command) {
1076
+ case 'resize':
1077
+ c = 'onresize';
1078
+ v = value;
1079
+ l = 'resize';
1080
+ i = 'resize';
1081
+ break;
1082
+ case 'auto':
1083
+ c = 'auto';
1084
+ l = 'autoSize';
1085
+ i = 'auto_size';
1086
+ break;
1087
+ case 'rotate':
1088
+ c = 'rotate';
1089
+ v = value === 'l' ? -90 : value === 'r' ? 90 : numbers.get(value);
1090
+ l = v < 0 ? 'rotateLeft' : 'rotateRight';
1091
+ i = v < 0 ? 'rotate_left' : 'rotate_right';
1092
+ break;
1093
+ case 'mirror':
1094
+ c = 'mirror';
1095
+ v = value;
1096
+ l = value === 'h' ? 'mirrorHorizontal' : 'mirrorVertical';
1097
+ i = value === 'h' ? 'mirror_horizontal' : 'mirror_vertical';
1098
+ break;
1099
+ case 'align':
1100
+ c = 'onalign';
1101
+ l = 'align';
1102
+ i = 'align_justify';
1103
+ break;
1104
+ case 'caption':
1105
+ c = 'caption';
1106
+ l = 'caption';
1107
+ i = 'caption';
1108
+ break;
1109
+ case 'revert':
1110
+ c = 'revert';
1111
+ l = 'revert';
1112
+ i = 'revert';
1113
+ break;
1114
+ case 'edit':
1115
+ c = 'edit';
1116
+ l = 'edit';
1117
+ i = 'edit';
1118
+ break;
1119
+ case 'remove':
1120
+ c = 'remove';
1121
+ l = 'remove';
1122
+ i = 'delete';
1123
+ break;
1124
+ }
1125
+
1126
+ if (!c) return null;
1127
+
1128
+ return {
1129
+ c: c,
1130
+ v: v,
1131
+ l: l,
1132
+ t: t,
1133
+ i: i
1134
+ };
1135
+ }
1136
+
1137
+ function CreateHTML_controller(inst, controls) {
1138
+ let html = null;
1139
+
1140
+ if (controls?.length > 0) {
1141
+ const { lang, icons } = inst;
1142
+ html = '<div class="se-arrow se-arrow-up"></div>';
1143
+ for (let i = 0, group; i < controls.length; i++) {
1144
+ group = controls[i];
1145
+ html += '<div class="se-btn-group">';
1146
+ for (let j = 0, len = group.length, m; j < len; j++) {
1147
+ m = group[j];
1148
+
1149
+ if (typeof m?.action === 'function') {
1150
+ const g = m;
1151
+ m = {
1152
+ c: `__c__${g.command}`,
1153
+ v: g.value || '',
1154
+ l: g.title,
1155
+ i: g.icon
1156
+ };
1157
+ inst._action[m.c] = g.action;
1158
+ } else {
1159
+ m = GET_CONTROLLER_BUTTONS(m);
1160
+ if (!m) continue;
1161
+ }
1162
+
1163
+ 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}
1166
+ <span class="se-tooltip-inner"><span class="se-tooltip-text">${lang[m.l] || m.l}</span></span>
1167
+ </button>`;
1168
+ }
1169
+ html += '</div>';
1170
+ }
1171
+ }
1172
+
1173
+ return domUtils.createElement('DIV', { class: 'se-controller se-controller-resizing' + (!html ? ' se-empty-controller' : '') }, html);
1174
+ }
1175
+
1176
+ export default Figure;