suneditor 3.0.0-alpha.2 → 3.0.0-alpha.20

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 (306) hide show
  1. package/.eslintrc.json +4 -3
  2. package/CONTRIBUTING.md +4 -2
  3. package/README.md +19 -11
  4. package/README_V3_TEMP.md +705 -0
  5. package/dist/suneditor.min.css +1 -0
  6. package/dist/suneditor.min.js +1 -0
  7. package/example.md +587 -0
  8. package/package.json +15 -9
  9. package/src/assets/icons/_default.js +166 -131
  10. package/src/assets/{suneditor-content.css → suneditor-contents.css} +182 -45
  11. package/src/assets/suneditor.css +1195 -556
  12. package/src/assets/variables.css +138 -0
  13. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  14. package/src/core/base/eventHandlers/handler_ww_clipboard.js +29 -4
  15. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +59 -15
  16. package/src/core/base/eventHandlers/handler_ww_key_input.js +426 -212
  17. package/src/core/base/eventHandlers/handler_ww_mouse.js +108 -32
  18. package/src/core/base/eventManager.js +540 -209
  19. package/src/core/base/events.js +616 -320
  20. package/src/core/base/history.js +93 -39
  21. package/src/core/class/char.js +29 -13
  22. package/src/core/class/component.js +332 -145
  23. package/src/core/class/format.js +671 -509
  24. package/src/core/class/html.js +504 -290
  25. package/src/core/class/menu.js +114 -47
  26. package/src/core/class/nodeTransform.js +111 -66
  27. package/src/core/class/offset.js +409 -105
  28. package/src/core/class/selection.js +220 -108
  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 +330 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +489 -384
  34. package/src/core/section/actives.js +118 -22
  35. package/src/core/section/constructor.js +504 -170
  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/helper/converter.js +137 -19
  42. package/src/helper/dom/domCheck.js +294 -0
  43. package/src/helper/dom/domQuery.js +609 -0
  44. package/src/helper/dom/domUtils.js +533 -0
  45. package/src/helper/dom/index.js +12 -0
  46. package/src/helper/env.js +42 -19
  47. package/src/helper/index.js +7 -4
  48. package/src/helper/keyCodeMap.js +183 -0
  49. package/src/helper/numbers.js +8 -8
  50. package/src/helper/unicode.js +5 -5
  51. package/src/langs/ckb.js +69 -3
  52. package/src/langs/cs.js +67 -1
  53. package/src/langs/da.js +68 -2
  54. package/src/langs/de.js +68 -3
  55. package/src/langs/en.js +29 -1
  56. package/src/langs/es.js +68 -3
  57. package/src/langs/fa.js +70 -2
  58. package/src/langs/fr.js +68 -2
  59. package/src/langs/he.js +68 -3
  60. package/src/langs/hu.js +226 -0
  61. package/src/langs/index.js +3 -2
  62. package/src/langs/it.js +65 -0
  63. package/src/langs/ja.js +68 -3
  64. package/src/langs/ko.js +66 -1
  65. package/src/langs/lv.js +68 -3
  66. package/src/langs/nl.js +68 -3
  67. package/src/langs/pl.js +68 -3
  68. package/src/langs/pt_br.js +65 -0
  69. package/src/langs/ro.js +69 -4
  70. package/src/langs/ru.js +68 -3
  71. package/src/langs/se.js +68 -3
  72. package/src/langs/tr.js +68 -0
  73. package/src/langs/ua.js +68 -3
  74. package/src/langs/ur.js +71 -6
  75. package/src/langs/zh_cn.js +69 -4
  76. package/src/modules/ApiManager.js +77 -54
  77. package/src/modules/Browser.js +667 -0
  78. package/src/modules/ColorPicker.js +162 -102
  79. package/src/modules/Controller.js +233 -136
  80. package/src/modules/Figure.js +913 -489
  81. package/src/modules/FileManager.js +141 -72
  82. package/src/modules/HueSlider.js +113 -61
  83. package/src/modules/Modal.js +292 -113
  84. package/src/modules/ModalAnchorEditor.js +380 -230
  85. package/src/modules/SelectMenu.js +270 -168
  86. package/src/modules/_DragHandle.js +2 -1
  87. package/src/modules/index.js +3 -3
  88. package/src/plugins/browser/audioGallery.js +83 -0
  89. package/src/plugins/browser/fileBrowser.js +103 -0
  90. package/src/plugins/browser/fileGallery.js +83 -0
  91. package/src/plugins/browser/imageGallery.js +81 -0
  92. package/src/plugins/browser/videoGallery.js +103 -0
  93. package/src/plugins/command/blockquote.js +40 -27
  94. package/src/plugins/command/exportPDF.js +134 -0
  95. package/src/plugins/command/fileUpload.js +226 -158
  96. package/src/plugins/command/list_bulleted.js +93 -47
  97. package/src/plugins/command/list_numbered.js +93 -47
  98. package/src/plugins/dropdown/align.js +66 -54
  99. package/src/plugins/dropdown/backgroundColor.js +76 -45
  100. package/src/plugins/dropdown/font.js +71 -47
  101. package/src/plugins/dropdown/fontColor.js +78 -46
  102. package/src/plugins/dropdown/formatBlock.js +74 -33
  103. package/src/plugins/dropdown/hr.js +102 -51
  104. package/src/plugins/dropdown/layout.js +37 -26
  105. package/src/plugins/dropdown/lineHeight.js +54 -38
  106. package/src/plugins/dropdown/list.js +60 -45
  107. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  108. package/src/plugins/dropdown/table.js +1269 -777
  109. package/src/plugins/dropdown/template.js +38 -26
  110. package/src/plugins/dropdown/textStyle.js +43 -31
  111. package/src/plugins/field/mention.js +144 -82
  112. package/src/plugins/index.js +32 -6
  113. package/src/plugins/input/fontSize.js +161 -108
  114. package/src/plugins/input/pageNavigator.js +70 -0
  115. package/src/plugins/modal/audio.js +341 -169
  116. package/src/plugins/modal/drawing.js +530 -0
  117. package/src/plugins/modal/embed.js +886 -0
  118. package/src/plugins/modal/image.js +673 -358
  119. package/src/plugins/modal/link.js +100 -71
  120. package/src/plugins/modal/math.js +384 -168
  121. package/src/plugins/modal/video.js +693 -336
  122. package/src/plugins/popup/anchor.js +222 -0
  123. package/src/suneditor.js +54 -12
  124. package/src/themes/dark.css +85 -0
  125. package/src/typedef.js +86 -0
  126. package/types/assets/icons/_default.d.ts +152 -0
  127. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  128. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  129. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  130. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  131. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  132. package/types/core/base/eventManager.d.ts +377 -0
  133. package/types/core/base/events.d.ts +297 -0
  134. package/types/core/base/history.d.ts +81 -0
  135. package/types/core/class/char.d.ts +60 -0
  136. package/types/core/class/component.d.ts +259 -0
  137. package/types/core/class/format.d.ts +615 -0
  138. package/types/core/class/html.d.ts +377 -0
  139. package/types/core/class/menu.d.ts +118 -0
  140. package/types/core/class/nodeTransform.d.ts +93 -0
  141. package/types/core/class/offset.d.ts +512 -0
  142. package/types/core/class/selection.d.ts +188 -0
  143. package/types/core/class/shortcuts.d.ts +142 -0
  144. package/types/core/class/toolbar.d.ts +189 -0
  145. package/types/core/class/ui.d.ts +144 -0
  146. package/types/core/class/viewer.d.ts +140 -0
  147. package/types/core/editor.d.ts +606 -0
  148. package/types/core/section/actives.d.ts +46 -0
  149. package/types/core/section/constructor.d.ts +748 -0
  150. package/types/core/section/context.d.ts +45 -0
  151. package/types/core/section/documentType.d.ts +178 -0
  152. package/types/editorInjector/_classes.d.ts +41 -0
  153. package/types/editorInjector/_core.d.ts +92 -0
  154. package/types/editorInjector/index.d.ts +71 -0
  155. package/types/helper/converter.d.ts +150 -0
  156. package/types/helper/dom/domCheck.d.ts +182 -0
  157. package/types/helper/dom/domQuery.d.ts +214 -0
  158. package/types/helper/dom/domUtils.d.ts +211 -0
  159. package/types/helper/dom/index.d.ts +9 -0
  160. package/types/helper/env.d.ts +149 -0
  161. package/types/helper/index.d.ts +163 -0
  162. package/types/helper/keyCodeMap.d.ts +110 -0
  163. package/types/helper/numbers.d.ts +43 -0
  164. package/types/helper/unicode.d.ts +28 -0
  165. package/types/index.d.ts +0 -0
  166. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +170 -103
  167. package/types/langs/ckb.d.ts +384 -0
  168. package/types/langs/cs.d.ts +384 -0
  169. package/types/langs/da.d.ts +384 -0
  170. package/types/langs/de.d.ts +384 -0
  171. package/types/langs/en.d.ts +384 -0
  172. package/types/langs/es.d.ts +384 -0
  173. package/types/langs/fa.d.ts +384 -0
  174. package/types/langs/fr.d.ts +384 -0
  175. package/types/langs/he.d.ts +384 -0
  176. package/types/langs/hu.d.ts +384 -0
  177. package/types/langs/index.d.ts +48 -0
  178. package/types/langs/it.d.ts +384 -0
  179. package/types/langs/ja.d.ts +384 -0
  180. package/types/langs/ko.d.ts +384 -0
  181. package/types/langs/lv.d.ts +384 -0
  182. package/types/langs/nl.d.ts +384 -0
  183. package/types/langs/pl.d.ts +384 -0
  184. package/types/langs/pt_br.d.ts +384 -0
  185. package/types/langs/ro.d.ts +384 -0
  186. package/types/langs/ru.d.ts +384 -0
  187. package/types/langs/se.d.ts +384 -0
  188. package/types/langs/tr.d.ts +384 -0
  189. package/types/langs/ua.d.ts +384 -0
  190. package/types/langs/ur.d.ts +384 -0
  191. package/types/langs/zh_cn.d.ts +384 -0
  192. package/types/modules/ApiManager.d.ts +125 -0
  193. package/types/modules/Browser.d.ts +326 -0
  194. package/types/modules/ColorPicker.d.ts +131 -0
  195. package/types/modules/Controller.d.ts +231 -0
  196. package/types/modules/Figure.d.ts +504 -0
  197. package/types/modules/FileManager.d.ts +202 -0
  198. package/types/modules/HueSlider.d.ts +136 -0
  199. package/types/modules/Modal.d.ts +117 -0
  200. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  201. package/types/modules/SelectMenu.d.ts +194 -0
  202. package/types/modules/_DragHandle.d.ts +7 -0
  203. package/types/modules/index.d.ts +26 -0
  204. package/types/plugins/browser/audioGallery.d.ts +55 -0
  205. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  206. package/types/plugins/browser/fileGallery.d.ts +55 -0
  207. package/types/plugins/browser/imageGallery.d.ts +51 -0
  208. package/types/plugins/browser/videoGallery.d.ts +57 -0
  209. package/types/plugins/command/blockquote.d.ts +28 -0
  210. package/types/plugins/command/exportPDF.d.ts +46 -0
  211. package/types/plugins/command/fileUpload.d.ts +156 -0
  212. package/types/plugins/command/list_bulleted.d.ts +56 -0
  213. package/types/plugins/command/list_numbered.d.ts +56 -0
  214. package/types/plugins/dropdown/align.d.ts +60 -0
  215. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  216. package/types/plugins/dropdown/font.d.ts +54 -0
  217. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  218. package/types/plugins/dropdown/formatBlock.d.ts +58 -0
  219. package/types/plugins/dropdown/hr.d.ts +81 -0
  220. package/types/plugins/dropdown/layout.d.ts +40 -0
  221. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  222. package/types/plugins/dropdown/list.d.ts +39 -0
  223. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  224. package/types/plugins/dropdown/table.d.ts +579 -0
  225. package/types/plugins/dropdown/template.d.ts +40 -0
  226. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  227. package/types/plugins/field/mention.d.ts +102 -0
  228. package/types/plugins/index.d.ts +107 -0
  229. package/types/plugins/input/fontSize.d.ts +170 -0
  230. package/types/plugins/input/pageNavigator.d.ts +28 -0
  231. package/types/plugins/modal/audio.d.ts +269 -0
  232. package/types/plugins/modal/drawing.d.ts +246 -0
  233. package/types/plugins/modal/embed.d.ts +387 -0
  234. package/types/plugins/modal/image.d.ts +451 -0
  235. package/types/plugins/modal/link.d.ts +128 -0
  236. package/types/plugins/modal/math.d.ts +193 -0
  237. package/types/plugins/modal/video.d.ts +485 -0
  238. package/types/plugins/popup/anchor.d.ts +56 -0
  239. package/types/suneditor.d.ts +51 -0
  240. package/types/typedef-global.d.ts +144 -0
  241. package/src/core/class/notice.js +0 -42
  242. package/src/helper/domUtils.js +0 -1177
  243. package/src/modules/FileBrowser.js +0 -271
  244. package/src/plugins/command/exportPdf.js +0 -168
  245. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  246. package/src/themes/test.css +0 -61
  247. package/typings/CommandPlugin.d.ts +0 -8
  248. package/typings/DialogPlugin.d.ts +0 -20
  249. package/typings/FileBrowserPlugin.d.ts +0 -30
  250. package/typings/Module.d.ts +0 -15
  251. package/typings/Plugin.d.ts +0 -42
  252. package/typings/SubmenuPlugin.d.ts +0 -8
  253. package/typings/_classes.d.ts +0 -17
  254. package/typings/_colorPicker.d.ts +0 -60
  255. package/typings/_core.d.ts +0 -55
  256. package/typings/align.d.ts +0 -5
  257. package/typings/audio.d.ts +0 -5
  258. package/typings/backgroundColor.d.ts +0 -5
  259. package/typings/blockquote.d.ts +0 -5
  260. package/typings/char.d.ts +0 -39
  261. package/typings/component.d.ts +0 -38
  262. package/typings/context.d.ts +0 -39
  263. package/typings/converter.d.ts +0 -33
  264. package/typings/dialog.d.ts +0 -28
  265. package/typings/domUtils.d.ts +0 -361
  266. package/typings/editor.d.ts +0 -7
  267. package/typings/editor.ts +0 -542
  268. package/typings/env.d.ts +0 -70
  269. package/typings/eventManager.d.ts +0 -37
  270. package/typings/events.d.ts +0 -262
  271. package/typings/fileBrowser.d.ts +0 -42
  272. package/typings/fileManager.d.ts +0 -67
  273. package/typings/font.d.ts +0 -5
  274. package/typings/fontColor.d.ts +0 -5
  275. package/typings/fontSize.d.ts +0 -5
  276. package/typings/format.d.ts +0 -191
  277. package/typings/formatBlock.d.ts +0 -5
  278. package/typings/history.d.ts +0 -48
  279. package/typings/horizontalRule.d.ts +0 -5
  280. package/typings/image.d.ts +0 -5
  281. package/typings/imageGallery.d.ts +0 -5
  282. package/typings/index.d.ts +0 -21
  283. package/typings/index.modules.d.ts +0 -11
  284. package/typings/index.plugins.d.ts +0 -58
  285. package/typings/lineHeight.d.ts +0 -5
  286. package/typings/link.d.ts +0 -5
  287. package/typings/list.d.ts +0 -5
  288. package/typings/math.d.ts +0 -5
  289. package/typings/mediaContainer.d.ts +0 -25
  290. package/typings/mention.d.ts +0 -5
  291. package/typings/node.d.ts +0 -57
  292. package/typings/notice.d.ts +0 -16
  293. package/typings/numbers.d.ts +0 -29
  294. package/typings/offset.d.ts +0 -24
  295. package/typings/options.d.ts +0 -589
  296. package/typings/paragraphStyle.d.ts +0 -5
  297. package/typings/resizing.d.ts +0 -141
  298. package/typings/selection.d.ts +0 -94
  299. package/typings/shortcuts.d.ts +0 -13
  300. package/typings/suneditor.d.ts +0 -9
  301. package/typings/table.d.ts +0 -5
  302. package/typings/template.d.ts +0 -5
  303. package/typings/textStyle.d.ts +0 -5
  304. package/typings/toolbar.d.ts +0 -32
  305. package/typings/unicode.d.ts +0 -25
  306. package/typings/video.d.ts +0 -5
@@ -0,0 +1,530 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { Modal } from '../../modules';
3
+ import { dom, env } from '../../helper';
4
+ import { CreateTooltipInner } from '../../core/section/constructor';
5
+
6
+ const { _w, isMobile } = env;
7
+
8
+ /**
9
+ * @typedef {Object} DrawingPluginOptions
10
+ * @property {string} [outputFormat="dataurl"] - The output format of the drawing. Options: "dataurl", "svg".
11
+ * @property {boolean} [useFormatType=false] - Whether to enable format type selection (block vs inline).
12
+ * @property {string} [defaultFormatType="block"] - The default format type, either "block" or "inline".
13
+ * @property {boolean} [keepFormatType=false] - Whether to maintain the chosen format type after drawing.
14
+ * @property {number} [lineWidth=5] - The width of the drawing line.
15
+ * @property {boolean} [lineReconnect=false] - Whether to reconnect lines when drawing.
16
+ * @property {CanvasLineCap} [lineCap="round"] - The style of the line cap ("butt", "round", or "square").
17
+ * @property {string} [lineColor=""] - The color of the drawing line.
18
+ * @property {boolean} [canResize=true] - Whether the modal form can be resized.
19
+ * @property {boolean} [maintainRatio=true] - Whether to maintain the aspect ratio when resizing.
20
+ * @property {Object} [formSize={}] - The size configuration for the drawing modal form.
21
+ * @property {string} [formSize.width="750px"] - The width of the modal form.
22
+ * @property {string} [formSize.height="50vh"] - The height of the modal form.
23
+ * @property {string} [formSize.maxWidth=""] - The maximum width of the modal form.
24
+ * @property {string} [formSize.maxHeight=""] - The maximum height of the modal form.
25
+ * @property {string} [formSize.minWidth="150px"] - The minimum width of the modal form.
26
+ * @property {string} [formSize.minHeight="100px"] - The minimum height of the modal form.
27
+ */
28
+
29
+ /**
30
+ * @class
31
+ * @description Drawing modal plugin.
32
+ */
33
+ class Drawing extends EditorInjector {
34
+ static key = 'drawing';
35
+ static type = 'modal';
36
+ static className = '';
37
+
38
+ /**
39
+ * @constructor
40
+ * @param {__se__EditorCore} editor - The root editor instance
41
+ * @param {DrawingPluginOptions} pluginOptions
42
+ */
43
+ constructor(editor, pluginOptions) {
44
+ // plugin basic properties
45
+ super(editor);
46
+ this.title = this.lang.drawing;
47
+ this.icon = 'drawing';
48
+ this.pluginOptions = {
49
+ outputFormat: pluginOptions.outputFormat || 'dataurl', // dataurl, svg
50
+ useFormatType: pluginOptions.useFormatType ?? false,
51
+ defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block',
52
+ keepFormatType: pluginOptions.keepFormatType ?? false,
53
+ lineWidth: pluginOptions.lineWidth || 5,
54
+ lineReconnect: !!pluginOptions.lineReconnect,
55
+ lineCap: ['butt', 'round', 'square'].includes(pluginOptions.lineCap) ? pluginOptions.lineCap : 'round',
56
+ lineColor: pluginOptions.lineColor || '',
57
+ formSize: {
58
+ width: '750px',
59
+ height: '50vh',
60
+ maxWidth: '',
61
+ maxHeight: '',
62
+ minWidth: '150px',
63
+ minHeight: '100px',
64
+ ...pluginOptions.formSize
65
+ },
66
+ canResize: pluginOptions.canResize ?? true,
67
+ maintainRatio: pluginOptions.maintainRatio ?? true
68
+ };
69
+
70
+ // exception
71
+ if (!this.plugins.image) {
72
+ console.warn('[SUNEDITOR.plugins.drawing.warn] The drawing plugin must need either "image" plugin. Please add the "image" plugin.');
73
+ } else if (this.pluginOptions.outputFormat === 'svg' && !this.plugins.image.pluginOptions.uploadUrl) {
74
+ console.warn('[SUNEDITOR.plugins.drawing.warn] The drawing plugin must need the "image" plugin with the "uploadUrl" option. Please add the "image" plugin with the "uploadUrl" option.');
75
+ }
76
+
77
+ // create HTML
78
+ const modalEl = CreateHTML_modal(this);
79
+
80
+ // modules
81
+ this.modal = new Modal(this, modalEl);
82
+
83
+ // members
84
+ this.as = this.pluginOptions.defaultFormatType;
85
+ if (this.pluginOptions.useFormatType) {
86
+ this.asBlock = modalEl.querySelector('[data-command="asBlock"]');
87
+ this.asInline = modalEl.querySelector('[data-command="asInline"]');
88
+ this.eventManager.addEvent([this.asBlock, this.asInline], 'click', this.#OnClickAsButton.bind(this));
89
+ }
90
+
91
+ /**
92
+ * @type {HTMLCanvasElement}
93
+ */
94
+ this.canvas = null;
95
+ this.ctx = null;
96
+ this.isDrawing = false;
97
+ this.points = [];
98
+ this.paths = [];
99
+ this.resizeObserver = null;
100
+ this.__events = {
101
+ mousedown: isMobile ? this.#OnCanvasTouchStart.bind(this) : this.#OnCanvasMouseDown.bind(this),
102
+ mousemove: isMobile ? this.#OnCanvasTouchMove.bind(this) : this.#OnCanvasMouseMove.bind(this),
103
+ mouseup: this.#OnCanvasMouseUp.bind(this),
104
+ mouseleave: this.#OnCanvasMouseLeave.bind(this),
105
+ mouseenter: this.#OnCanvasMouseEnter.bind(this)
106
+ };
107
+ this.__eventsRegister = {
108
+ mousedown: null,
109
+ mousemove: null,
110
+ mouseup: null,
111
+ mouseleave: null,
112
+ mouseenter: null
113
+ };
114
+ this.__eventNameMap = {
115
+ mousedown: isMobile ? 'touchstart' : 'mousedown',
116
+ mousemove: isMobile ? 'touchmove' : 'mousemove',
117
+ mouseup: isMobile ? 'touchend' : 'mouseup',
118
+ mouseleave: 'mouseleave',
119
+ mouseenter: 'mouseenter'
120
+ };
121
+
122
+ // init
123
+ this.eventManager.addEvent(modalEl.querySelector('[data-command="remove"]'), 'click', this.#OnRemove.bind(this));
124
+ }
125
+
126
+ /**
127
+ * @editorMethod Modules.Modal
128
+ * @description Executes the method that is called when a "Modal" module's is opened.
129
+ */
130
+ open() {
131
+ if (this.pluginOptions.useFormatType) {
132
+ this._activeAsInline((this.pluginOptions.keepFormatType ? this.as : this.pluginOptions.defaultFormatType) === 'inline');
133
+ }
134
+ this.modal.open();
135
+ this._initDrawing();
136
+ }
137
+
138
+ /**
139
+ * @editorMethod Modules.Modal
140
+ * @description Executes the method that is called when a plugin's "modal" is closed.
141
+ */
142
+ off() {
143
+ this._destroyDrawing();
144
+ }
145
+
146
+ /**
147
+ * @editorMethod Modules.Modal
148
+ * @description This function is called when a form within a modal window is "submit".
149
+ * @returns {boolean} Success or failure
150
+ */
151
+ modalAction() {
152
+ if (this.pluginOptions.outputFormat === 'svg') {
153
+ const files = this._getSVGFileList();
154
+ this.plugins.image.init();
155
+ this.plugins.image.submitFile(files);
156
+ } else {
157
+ // dataurl | svg
158
+ const data = this.canvas.toDataURL();
159
+ const file = { name: 'drawing', size: 0 };
160
+ this.plugins.image.init();
161
+ if (this.as !== 'inline') {
162
+ this.plugins.image.create(data, null, 'auto', '', 'none', file, '');
163
+ } else {
164
+ this.plugins.image.createInline(data, null, 'auto', '', 'none', file, '');
165
+ }
166
+ }
167
+
168
+ return true;
169
+ }
170
+
171
+ /**
172
+ * @private
173
+ * @description Initializes the drawing canvas, sets up event listeners, and configures resize handling.
174
+ */
175
+ _initDrawing() {
176
+ const canvas = (this.canvas = this.modal.form.querySelector('.se-drawing-canvas'));
177
+ this.ctx = canvas.getContext('2d');
178
+ canvas.width = canvas.offsetWidth;
179
+ canvas.height = canvas.offsetHeight;
180
+
181
+ this.points = [];
182
+ this.paths = [];
183
+
184
+ this._setCtx();
185
+
186
+ this.__eventsRegister.mousedown = this.eventManager.addEvent(canvas, this.__eventNameMap.mousedown, this.__events.mousedown, { passive: false, capture: true });
187
+ this.__eventsRegister.mousemove = this.eventManager.addEvent(canvas, this.__eventNameMap.mousemove, this.__events.mousemove, true);
188
+ this.__eventsRegister.mouseup = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseup, this.__events.mouseup, true);
189
+ this.__eventsRegister.mouseleave = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseleave, this.__events.mouseleave);
190
+ this.__eventsRegister.mouseenter = this.eventManager.addEvent(canvas, this.__eventNameMap.mouseenter, this.__events.mouseenter);
191
+
192
+ if (this.resizeObserver) {
193
+ this.resizeObserver.disconnect();
194
+ this.resizeObserver = null;
195
+ }
196
+
197
+ this.resizeObserver = new ResizeObserver(() => {
198
+ const prevWidth = canvas.width;
199
+ const prevHeight = canvas.height;
200
+ const newWidth = canvas.offsetWidth;
201
+ const newHeight = canvas.offsetHeight;
202
+ canvas.width = newWidth;
203
+ canvas.height = newHeight;
204
+ if (prevWidth !== canvas.width || prevHeight !== canvas.height) {
205
+ if (this.pluginOptions.maintainRatio) this._adjustPathsToNewDimensions(prevWidth, prevHeight, newWidth, newHeight);
206
+ this._drawAll();
207
+ }
208
+ });
209
+
210
+ this.resizeObserver.observe(canvas);
211
+ }
212
+
213
+ /**
214
+ * @private
215
+ * @description Destroys the drawing canvas, removes event listeners, and clears stored drawing data.
216
+ */
217
+ _destroyDrawing() {
218
+ if (this.resizeObserver) {
219
+ this.resizeObserver.disconnect();
220
+ this.resizeObserver = null;
221
+ }
222
+
223
+ if (this.canvas) {
224
+ this.eventManager.removeEvent(this.__eventsRegister.mousedown);
225
+ this.eventManager.removeEvent(this.__eventsRegister.mousemove);
226
+ this.eventManager.removeEvent(this.__eventsRegister.mouseup);
227
+ this.eventManager.removeEvent(this.__eventsRegister.mouseleave);
228
+ this.eventManager.removeEvent(this.__eventsRegister.mouseenter);
229
+ }
230
+
231
+ this.canvas = null;
232
+ this.ctx = null;
233
+ this.points = [];
234
+ this.paths = [];
235
+ this.isDrawing = false;
236
+ }
237
+
238
+ /**
239
+ * @private
240
+ * @description Configures the drawing context (canvas settings like line width, color, etc.).
241
+ */
242
+ _setCtx() {
243
+ this.ctx.lineWidth = this.pluginOptions.lineWidth;
244
+ this.ctx.lineCap = this.pluginOptions.lineCap;
245
+ this.ctx.strokeStyle = this.pluginOptions.lineColor || _w.getComputedStyle(this.carrierWrapper).color;
246
+ }
247
+
248
+ /**
249
+ * @private
250
+ * @description Draws the current stroke based on collected points.
251
+ */
252
+ _draw() {
253
+ this._setCtx();
254
+ this.ctx.beginPath();
255
+ this.points.forEach(([x, y], i) => {
256
+ if (i === 0) {
257
+ this.ctx.moveTo(x, y);
258
+ } else {
259
+ this.ctx.lineTo(x, y);
260
+ }
261
+ });
262
+ this.ctx.stroke();
263
+ }
264
+
265
+ /**
266
+ * @private
267
+ * @description Redraws all stored paths onto the canvas.
268
+ */
269
+ _drawAll() {
270
+ this._setCtx();
271
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
272
+ this.paths.forEach((path) => {
273
+ this.points = path;
274
+ this._draw();
275
+ });
276
+ this.points = [];
277
+ }
278
+
279
+ /**
280
+ * @private
281
+ * @description Adjusts all stored paths to fit new canvas dimensions after a resize event.
282
+ * @param {number} prevWidth - The previous width of the canvas.
283
+ * @param {number} prevHeight - The previous height of the canvas.
284
+ * @param {number} newWidth - The new width of the canvas.
285
+ * @param {number} newHeight - The new height of the canvas.
286
+ */
287
+ _adjustPathsToNewDimensions(prevWidth, prevHeight, newWidth, newHeight) {
288
+ const xRatio = newWidth / prevWidth;
289
+ const yRatio = newHeight / prevHeight;
290
+
291
+ this.paths = this.paths.map((path) => path.map(([x, y]) => [x * xRatio, y * yRatio]));
292
+ }
293
+
294
+ /**
295
+ * @private
296
+ * @description Clears the canvas and resets stored drawing paths.
297
+ */
298
+ _clearCanvas() {
299
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
300
+ this.points = [];
301
+ this.paths = [];
302
+ }
303
+
304
+ /**
305
+ * @private
306
+ * @description Generates an SVG representation of the drawn content.
307
+ * @returns {*} The generated SVG element.
308
+ */
309
+ _getSVG() {
310
+ const svgNS = 'http://www.w3.org/2000/svg';
311
+ const svg = document.createElementNS(svgNS, 'svg');
312
+ svg.setAttribute('width', this.canvas.width + '');
313
+ svg.setAttribute('height', this.canvas.height + '');
314
+ svg.setAttribute('viewBox', `0 0 ${this.canvas.width} ${this.canvas.height}`);
315
+ svg.setAttribute('xmlns', svgNS);
316
+
317
+ this.paths.forEach((path) => {
318
+ const pathData = path.reduce((acc, [x, y], i) => {
319
+ return acc + (i === 0 ? `M ${x} ${y}` : ` L ${x} ${y}`);
320
+ }, '');
321
+ const svgPath = document.createElementNS(svgNS, 'path');
322
+ svgPath.setAttribute('d', pathData);
323
+ svgPath.setAttribute('fill', 'none');
324
+ svgPath.setAttribute('stroke', String(this.ctx.strokeStyle));
325
+ svgPath.setAttribute('stroke-width', this.ctx.lineWidth + '');
326
+ svg.appendChild(svgPath);
327
+ });
328
+
329
+ return svg;
330
+ }
331
+
332
+ /**
333
+ * @private
334
+ * @description Converts the SVG element into a downloadable file.
335
+ * @returns {FileList} A FileList containing the generated SVG file.
336
+ */
337
+ _getSVGFileList() {
338
+ const svgElement = this._getSVG();
339
+ const serializer = new XMLSerializer();
340
+ const svgString = serializer.serializeToString(svgElement);
341
+ const blob = new Blob([svgString], { type: 'image/svg+xml' });
342
+ const file = new File([blob], 'drawing.svg', { type: 'image/svg+xml' });
343
+
344
+ // Creating a FileList
345
+ const dataTransfer = new DataTransfer();
346
+ dataTransfer.items.add(file);
347
+
348
+ return dataTransfer.files;
349
+ }
350
+
351
+ /**
352
+ * @private
353
+ * @description Retrieves touch coordinates relative to the canvas.
354
+ * @param {TouchEvent} e - The touch event.
355
+ * @returns {{x: number, y: number}} An object containing the x and y coordinates.
356
+ */
357
+ _getCanvasTouchPointer(e) {
358
+ const { touches } = e;
359
+ const rect = this.canvas.getBoundingClientRect();
360
+ const x = touches[0].clientX - rect.left;
361
+ const y = touches[0].clientY - rect.top;
362
+ return { x, y };
363
+ }
364
+
365
+ /**
366
+ * @private
367
+ * @description Activates either block or inline format mode for inserted drawings.
368
+ * @param {boolean} isInline - Whether the drawing should be inserted as an inline element.
369
+ */
370
+ _activeAsInline(isInline) {
371
+ if (isInline) {
372
+ dom.utils.addClass(this.asInline, 'on');
373
+ dom.utils.removeClass(this.asBlock, 'on');
374
+ this.as = 'inline';
375
+ } else {
376
+ dom.utils.addClass(this.asBlock, 'on');
377
+ dom.utils.removeClass(this.asInline, 'on');
378
+ this.as = 'block';
379
+ }
380
+ }
381
+
382
+ /**
383
+ * @param {MouseEvent} e - Event object
384
+ */
385
+ #OnCanvasMouseDown(e) {
386
+ e.preventDefault();
387
+ this.isDrawing = true;
388
+ this.points.push([e.offsetX, e.offsetY]);
389
+ this._draw();
390
+ }
391
+
392
+ /**
393
+ * @param {MouseEvent} e - Event object
394
+ */
395
+ #OnCanvasMouseMove(e) {
396
+ e.preventDefault();
397
+ if (!this.isDrawing) return;
398
+ this.points.push([e.offsetX, e.offsetY]);
399
+ this._draw();
400
+ }
401
+
402
+ /**
403
+ * @param {TouchEvent} e - Event object
404
+ */
405
+ #OnCanvasTouchStart(e) {
406
+ e.preventDefault();
407
+ const { x, y } = this._getCanvasTouchPointer(e);
408
+ this.isDrawing = true;
409
+ this.points.push([x, y]);
410
+ this._draw();
411
+ }
412
+
413
+ /**
414
+ * @param {TouchEvent} e - Event object
415
+ */
416
+ #OnCanvasTouchMove(e) {
417
+ e.preventDefault();
418
+ const { x, y } = this._getCanvasTouchPointer(e);
419
+ if (!this.isDrawing) return;
420
+ this.points.push([x, y]);
421
+ this._draw();
422
+ }
423
+
424
+ #OnCanvasMouseUp() {
425
+ this.isDrawing = false;
426
+ if (this.points.length > 0) {
427
+ this.paths.push([...this.points]);
428
+ this.points = [];
429
+ }
430
+ }
431
+
432
+ #OnCanvasMouseLeave() {
433
+ if (this.isDrawing) {
434
+ this.paths.push([...this.points]);
435
+ if (!this.pluginOptions.lineReconnect) {
436
+ this.points = [];
437
+ this.isDrawing = false;
438
+ }
439
+ }
440
+ }
441
+
442
+ /**
443
+ * @param {MouseEvent} e - Event object
444
+ */
445
+ #OnCanvasMouseEnter(e) {
446
+ if (e.buttons === 1) {
447
+ this.isDrawing = true;
448
+ if (!this.pluginOptions.lineReconnect) {
449
+ this.points.push([e.offsetX, e.offsetY]);
450
+ } else {
451
+ const lastPath = this.paths[this.paths.length - 1];
452
+ const lastPoint = lastPath[lastPath.length - 1];
453
+ this.points.push([lastPoint[0], lastPoint[1]]);
454
+ this.points.push([e.offsetX, e.offsetY]);
455
+ }
456
+ this._draw();
457
+ }
458
+ }
459
+
460
+ #OnRemove() {
461
+ this._clearCanvas();
462
+ }
463
+
464
+ /**
465
+ * @param {MouseEvent} e - Event object
466
+ */
467
+ #OnClickAsButton(e) {
468
+ this._activeAsInline(dom.query.getEventTarget(e).getAttribute('data-command') === 'asInline');
469
+ }
470
+ }
471
+
472
+ function CreateHTML_modal({ lang, icons, pluginOptions }) {
473
+ const { width, height, maxWidth, maxHeight, minWidth, minHeight } = pluginOptions.formSize;
474
+ const html = /*html*/ `
475
+ <form>
476
+ <div class="se-modal-header">
477
+ <button type="button" data-command="close" class="se-btn se-close-btn" title="${lang.close}" aria-label="${lang.close}">
478
+ ${icons.cancel}
479
+ </button>
480
+ <span class="se-modal-title">${lang.drawing_modal_title}</span>
481
+ </div>
482
+ <div class="se-modal-body" style="width: ${width}; height: ${height}; min-width: ${minWidth}; min-height: ${minHeight};">
483
+ <canvas class="se-drawing-canvas" style="width: 100%; height: 100%;"></canvas>
484
+ ${pluginOptions.canResize ? '<div class="se-modal-resize-handle-w"></div><div class="se-modal-resize-handle-h"></div><div class="se-modal-resize-handle-c"></div>' : ''}
485
+ </div>
486
+ <div class="se-modal-body-bottom">
487
+ <div class="se-modal-form">
488
+ <div class="se-modal-flex-form">
489
+ ${
490
+ pluginOptions.useFormatType
491
+ ? /*html*/ `
492
+ <div class="se-modal-flex-group">
493
+ <button type="button" class="se-btn se-tooltip" data-command="asBlock" aria-label="${lang.blockStyle}">
494
+ ${icons.as_block}
495
+ ${CreateTooltipInner(lang.blockStyle)}
496
+ </button>
497
+ <button type="button" class="se-btn se-tooltip" data-command="asInline" aria-label="${lang.inlineStyle}">
498
+ ${icons.as_inline}
499
+ ${CreateTooltipInner(lang.inlineStyle)}
500
+ </button>
501
+ </div>`
502
+ : ''
503
+ }
504
+ <div class="se-modal-flex-group">
505
+ <button type="button" class="se-btn se-tooltip" data-command="remove" aria-label="${lang.remove}">
506
+ ${icons.eraser}
507
+ ${CreateTooltipInner(lang.remove)}
508
+ </button>
509
+ </div>
510
+ </div>
511
+ </div>
512
+ </div>
513
+ <div class="se-modal-footer">
514
+ <button type="submit" class="se-btn-primary" title="${lang.submitButton}" aria-label="${lang.submitButton}">
515
+ <span>${lang.submitButton}</span>
516
+ </button>
517
+ </div>
518
+ </form>`;
519
+
520
+ return dom.utils.createElement(
521
+ 'DIV',
522
+ {
523
+ class: 'se-modal-content se-modal-responsive',
524
+ style: `max-width: ${maxWidth}; max-height: ${maxHeight};`
525
+ },
526
+ html
527
+ );
528
+ }
529
+
530
+ export default Drawing;