suneditor 2.46.2 → 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +174 -805
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +96 -69
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-content.css +646 -0
  11. package/src/assets/suneditor.css +3378 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  17. package/src/core/base/eventManager.js +1115 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +146 -0
  21. package/src/core/class/component.js +627 -0
  22. package/src/core/class/format.js +3255 -0
  23. package/src/core/class/html.js +1621 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +379 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +578 -0
  28. package/src/core/class/selection.js +508 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1593 -0
  33. package/src/core/section/actives.js +107 -0
  34. package/src/core/section/constructor.js +1237 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +313 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +199 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +162 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +315 -0
  72. package/src/modules/Figure.js +1160 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +290 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +73 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +73 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +172 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +510 -0
  104. package/src/plugins/modal/image.js +1062 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +347 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,168 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { domUtils, env } from '../../helper';
3
+ import { ApiManager } from '../../modules';
4
+
5
+ const { _d } = env;
6
+
7
+ const ExportPdf = function (editor, pluginOptions) {
8
+ EditorInjector.call(this, editor);
9
+ // plugin basic properties
10
+ this.title = this.lang.exportPdf;
11
+ this.icon = 'pdf';
12
+
13
+ // plugin options
14
+ this.apiUrl = pluginOptions.apiUrl;
15
+ this.fileName = pluginOptions.fileName || 'suneditor-pdf';
16
+ this.jsPDFOptions = pluginOptions.jsPDFOptions || {};
17
+ this.html2canvasOptions = pluginOptions.html2canvasOptions || {};
18
+
19
+ // option check
20
+ if (!this.apiUrl && !this.options.get('externalLibs').html2canvas && !this.options.get('externalLibs').jsPDF) {
21
+ console.warn('[SUNEDITOR.plugins.exportPdf.error] Requires "apiUrl" or externalLibs.html2canvas and externalLibs.jsPDF options.');
22
+ } else if (this.apiUrl) {
23
+ this.apiManager = new ApiManager(this, {
24
+ method: 'POST',
25
+ url: this.apiUrl,
26
+ headers: {
27
+ 'Content-Type': 'application/json'
28
+ },
29
+ responseType: 'blob'
30
+ });
31
+ }
32
+ };
33
+
34
+ ExportPdf.key = 'exportPdf';
35
+ ExportPdf.type = 'command';
36
+ ExportPdf.className = 'se-component-enabled';
37
+ ExportPdf.prototype = {
38
+ /**
39
+ * @override core
40
+ * @param {Element} target Target command button
41
+ */
42
+ async action() {
43
+ this.editor.showLoading();
44
+ let ww = null;
45
+
46
+ try {
47
+ const topArea = this.editor.frameContext.get('topArea');
48
+ const editableDiv = domUtils.createElement('div', { class: this.editor.frameContext.get('wysiwygFrame').className }, this.html.get());
49
+ ww = domUtils.createElement('div', { style: `position: absolute; left: -10000px; width: ${topArea.clientWidth}px; height: auto;` }, editableDiv);
50
+
51
+ if (this.apiUrl) {
52
+ const inlineWW = domUtils.applyInlineStylesAll(editableDiv, true, this.options.get('allUsedStyles'));
53
+ ww.innerHTML = inlineWW.outerHTML;
54
+ }
55
+
56
+ _d.body.appendChild(ww);
57
+
58
+ // before event
59
+ if ((await this.triggerEvent('onExportPdfBefore', { editableDiv })) === false) return;
60
+
61
+ // at server
62
+ if (this.apiUrl) {
63
+ await this._createByServer(ww);
64
+ return;
65
+ }
66
+
67
+ // at client
68
+ const checkAndProcessResources = async () => {
69
+ const resources = ww.querySelectorAll('img, audio, video');
70
+ const resourcesLoaded = Array.from(resources).map((resource) => {
71
+ switch (resource.tagName.toLowerCase()) {
72
+ case 'img':
73
+ return new Promise((resolve) => {
74
+ if (resource.complete && resource.naturalHeight !== 0) {
75
+ resolve();
76
+ } else {
77
+ resource.onload = resolve;
78
+ resource.onerror = () => resolve();
79
+ }
80
+ });
81
+ case 'audio':
82
+ case 'video':
83
+ return new Promise((resolve) => {
84
+ if (resource.readyState >= 4) {
85
+ // HAVE_ENOUGH_DATA
86
+ resolve();
87
+ } else {
88
+ resource.onloadeddata = resolve;
89
+ resource.onerror = () => resolve();
90
+ }
91
+ });
92
+ default:
93
+ return Promise.resolve();
94
+ }
95
+ });
96
+
97
+ await Promise.all(resourcesLoaded);
98
+ await this._createByHtml2canvas(ww);
99
+ };
100
+
101
+ // run observer
102
+ const observer = new MutationObserver(checkAndProcessResources);
103
+ observer.observe(ww, { childList: true, subtree: true, attributes: true });
104
+
105
+ await checkAndProcessResources();
106
+ } catch (error) {
107
+ console.error(`[SUNEDITOR.plugins.exportPdf.error] ${error.message}`);
108
+ } finally {
109
+ // domUtils.removeItem(ww);
110
+ this.editor.hideLoading();
111
+ }
112
+ },
113
+
114
+ async _createByHtml2canvas(ww) {
115
+ const canvas = await this.options.get('externalLibs').html2canvas(ww, {
116
+ useCORS: true,
117
+ logging: true,
118
+ ...this.html2canvasOptions
119
+ });
120
+ const imageData = canvas.toDataURL('image/png');
121
+
122
+ const pdf = new (this.options.get('externalLibs').jsPDF)({
123
+ orientation: 'portrait',
124
+ unit: 'px',
125
+ format: [canvas.width, canvas.height],
126
+ ...this.jsPDFOptions
127
+ });
128
+
129
+ pdf.addImage(imageData, 'PNG', 0, 0, canvas.width, canvas.height);
130
+
131
+ // save PDF file
132
+ pdf.save(`${this.fileName}.pdf`);
133
+ },
134
+
135
+ async _createByServer(ww) {
136
+ const data = {
137
+ fileName: this.fileName,
138
+ htmlContent: ww.innerHTML
139
+ };
140
+
141
+ const xhr = await this.apiManager.asyncCall({ data: JSON.stringify(data) });
142
+
143
+ if (xhr.status !== 200) {
144
+ const res = !xhr.responseText ? xhr : JSON.parse(xhr.responseText);
145
+ throw Error(`[SUNEDITOR.plugins.exportPdf.error] ${res.errorMessage}`);
146
+ }
147
+
148
+ const blob = new Blob([xhr.response], { type: 'application/pdf' });
149
+ const contentDisposition = xhr.getResponseHeader('Content-Disposition');
150
+ const downloadUrl = URL.createObjectURL(blob);
151
+ const filename = (contentDisposition.match(/filename="([^"]+)/) || [])[1] || this.fileName + '.pdf';
152
+ const a = domUtils.createElement('A', { href: downloadUrl, download: filename, style: 'display: none;' }, null);
153
+
154
+ try {
155
+ _d.body.appendChild(a);
156
+ a.click();
157
+ } finally {
158
+ setTimeout(() => {
159
+ domUtils.removeItem(a);
160
+ URL.revokeObjectURL(downloadUrl);
161
+ }, 100);
162
+ }
163
+ },
164
+
165
+ constructor: ExportPdf
166
+ };
167
+
168
+ export default ExportPdf;
@@ -0,0 +1,389 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { CreateTooltipInner } from '../../core/section/constructor';
3
+ import { domUtils, env, numbers } from '../../helper';
4
+ import { FileManager, Figure, Controller } from '../../modules';
5
+
6
+ const { NO_EVENT } = env;
7
+
8
+ const FileUpload = function (editor, pluginOptions) {
9
+ EditorInjector.call(this, editor);
10
+ // plugin basic properties
11
+ this.title = this.lang.fileUpload;
12
+ this.icon = 'file_upload';
13
+
14
+ if (!pluginOptions.uploadUrl) console.warn('[SUNEDITOR.fileUpload.warn] "fileUpload" plugin must be have "uploadUrl" option.');
15
+
16
+ // members
17
+ this.uploadUrl = pluginOptions.uploadUrl;
18
+ this.uploadHeaders = pluginOptions.uploadHeaders;
19
+ this.uploadSizeLimit = /\d+/.test(pluginOptions.uploadSizeLimit) ? numbers.get(pluginOptions.uploadSizeLimit, 0) : null;
20
+ this.uploadSingleSizeLimit = /\d+/.test(pluginOptions.uploadSingleSizeLimit) ? numbers.get(pluginOptions.uploadSingleSizeLimit, 0) : null;
21
+ this.allowMultiple = !!pluginOptions.allowMultiple;
22
+ this.acceptedFormats = typeof pluginOptions.acceptedFormats !== 'string' ? '*' : pluginOptions.acceptedFormats.trim() || '*';
23
+ this._acceptedCheck = this.acceptedFormats.split(', ');
24
+ this.as = pluginOptions.as || 'box';
25
+ this.input = domUtils.createElement('input', { type: 'file', accept: this.acceptedFormats });
26
+ if (this.allowMultiple) {
27
+ this.input.setAttribute('multiple', 'multiple');
28
+ }
29
+ this._element = null;
30
+
31
+ // figure
32
+ const customItems = {
33
+ 'custom-download': {
34
+ command: 'download',
35
+ title: this.lang.download,
36
+ icon: 'download',
37
+ action: (target) => {
38
+ const url = target.getAttribute('href');
39
+ if (url) domUtils.createElement('A', { href: url }, null).click();
40
+ }
41
+ },
42
+ 'custom-as': {
43
+ command: 'as',
44
+ value: 'link', // 'block' or 'link'
45
+ title: this.lang.asLink,
46
+ icon: 'reduction',
47
+ action: (target, value) => {
48
+ this.convertFormat(target, value);
49
+ }
50
+ }
51
+ };
52
+ let figureControls = pluginOptions.controls || [['custom-as', 'edit', 'align', 'remove', 'custom-download']];
53
+ figureControls = figureControls.map((subArray) => subArray.map((item) => (item.startsWith('custom-') ? customItems[item] : item)));
54
+ this.figure = new Figure(this, figureControls, {});
55
+
56
+ // file manager
57
+ this.fileManager = new FileManager(this, {
58
+ query: 'a[download][data-se-file-download]',
59
+ loadHandler: this.events.onFileLoad,
60
+ eventHandler: this.events.onFileAction
61
+ });
62
+
63
+ // controller
64
+ if (/\bedit\b/.test(JSON.stringify(figureControls))) {
65
+ const controllerEl = CreateHTML_controller(this);
66
+ this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true }, FileUpload.key);
67
+ this.editInput = controllerEl.querySelector('input');
68
+ }
69
+
70
+ // init
71
+ this.eventManager.addEvent(this.input, 'change', OnChangeFile.bind(this));
72
+ };
73
+
74
+ FileUpload.key = 'fileUpload';
75
+ FileUpload.type = 'command';
76
+ FileUpload.className = '';
77
+ FileUpload.options = { eventIndex: 10000 };
78
+ FileUpload.component = function (node) {
79
+ return domUtils.isAnchor(node) && node.hasAttribute('download') && node.hasAttribute('data-se-file-download') ? node : null;
80
+ };
81
+ FileUpload.prototype = {
82
+ /**
83
+ * @override core
84
+ * @param {Element} target Target command button
85
+ */
86
+ action() {
87
+ this.input.click();
88
+ },
89
+
90
+ /**
91
+ * @override fileManager
92
+ * @param {Element} target Target element
93
+ */
94
+ select(target) {
95
+ this._element = target;
96
+ const asBtn = this.figure.controller.form.querySelector('[data-command="__c__as"]');
97
+ if (domUtils.isFigure(target.parentElement)) {
98
+ asBtn.innerHTML = this.icons.reduction + CreateTooltipInner(this.lang.asLink);
99
+ asBtn.setAttribute('data-value', 'link');
100
+ this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
101
+ } else {
102
+ asBtn.innerHTML = this.icons.expansion + CreateTooltipInner(this.lang.asBlock);
103
+ asBtn.setAttribute('data-value', 'box');
104
+ this.figure.controllerOpen(target, { isWWTarget: true });
105
+ return true;
106
+ }
107
+ },
108
+
109
+ /**
110
+ * @description On paste or drop
111
+ * @param {*} params { frameContext, event, file }
112
+ */
113
+ onPastAndDrop({ file }) {
114
+ const fileType = file.type;
115
+ if (
116
+ !this._acceptedCheck.some((format) => {
117
+ if (format.startsWith('*')) return true;
118
+ if (format.startsWith(fileType)) return true;
119
+ })
120
+ ) {
121
+ return;
122
+ }
123
+
124
+ this._submitFile([file]);
125
+ this.editor.focus();
126
+
127
+ return false;
128
+ },
129
+
130
+ /**
131
+ * @override Figure
132
+ * @param {Element} target Target element
133
+ */
134
+ edit(target) {
135
+ this.editInput.value = target.textContent;
136
+ this.figure.controllerHide();
137
+ this.controller.open(target, null, { isWWTarget: !domUtils.isFigure(target.parentElement), initMethod: null, addOffset: null });
138
+ this.editInput.focus();
139
+ },
140
+
141
+ /**
142
+ * @override controller
143
+ * @param {Element} target Target button element
144
+ * @returns
145
+ */
146
+ controllerAction(target) {
147
+ const command = target.getAttribute('data-command');
148
+ if (!command) return;
149
+
150
+ if (command === 'edit') {
151
+ if (this.editInput.value.trim().length === 0) return;
152
+ this._element.textContent = this.editInput.value;
153
+ }
154
+
155
+ this.controller.close();
156
+ this.component.select(this._element, FileUpload.key, false);
157
+ },
158
+
159
+ async _submitFile(fileList) {
160
+ if (fileList.length === 0) return;
161
+
162
+ let fileSize = 0;
163
+ const files = [];
164
+ const slngleSizeLimit = this.uploadSingleSizeLimit;
165
+ for (let i = 0, len = fileList.length, f, s; i < len; i++) {
166
+ f = fileList[i];
167
+ s = f.size;
168
+ if (slngleSizeLimit && slngleSizeLimit > s) {
169
+ const err = '[SUNEDITOR.fileUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
170
+ const message = await this.triggerEvent('onFileUploadError', {
171
+ error: err,
172
+ limitSize: slngleSizeLimit,
173
+ uploadSize: s,
174
+ file: f
175
+ });
176
+
177
+ this.notice.open(message === NO_EVENT ? err : message || err);
178
+
179
+ return false;
180
+ }
181
+
182
+ files.push(f);
183
+ fileSize += s;
184
+ }
185
+
186
+ const limitSize = this.uploadSizeLimit;
187
+ const currentSize = this.fileManager.getSize();
188
+ if (limitSize > 0 && fileSize + currentSize > limitSize) {
189
+ const err = '[SUNEDITOR.fileUpload.fail] Size of uploadable total files: ' + limitSize / 1000 + 'KB';
190
+ const message = await this.triggerEvent('onFileUploadError', {
191
+ error: err,
192
+ limitSize,
193
+ currentSize,
194
+ uploadSize: fileSize
195
+ });
196
+
197
+ this.notice.open(message === NO_EVENT ? err : message || err);
198
+
199
+ return false;
200
+ }
201
+
202
+ const fileInfo = {
203
+ url: this.uploadUrl,
204
+ uploadHeaders: this.uploadHeaders,
205
+ files
206
+ };
207
+
208
+ const handler = async function (infos, newInfos) {
209
+ infos = newInfos || infos;
210
+ const xmlHttp = await this.fileManager.asyncUpload(infos.url, infos.uploadHeaders, infos.files);
211
+ this._uploadCallBack(xmlHttp);
212
+ }.bind(this, fileInfo);
213
+
214
+ const result = await this.triggerEvent('onFileUploadBefore', {
215
+ ...fileInfo,
216
+ handler
217
+ });
218
+
219
+ if (result === undefined) return true;
220
+ if (result === false) return false;
221
+ if (result !== null && typeof result === 'object') handler(result);
222
+
223
+ if (result === true || result === NO_EVENT) handler(null);
224
+ },
225
+
226
+ /**
227
+ * @override fileManager, Figure
228
+ * @param {Element} target Target element
229
+ */
230
+ async destroy(target) {
231
+ if (!target) return;
232
+
233
+ const figure = Figure.GetContainer(target);
234
+ target = domUtils.getParentElement(target, '.se-component') || target;
235
+
236
+ const message = await this.triggerEvent('onFileDeleteBefore', { target: figure.target, container: figure, url: figure.target.getAttribute('href') });
237
+ if (message === false) return;
238
+
239
+ const isInlineComp = this.component.isInline(target);
240
+ const focusEl = isInlineComp ? target.previousSibling || target.nextSibling : target.previousElementSibling || target.nextElementSibling;
241
+ domUtils.removeItem(target);
242
+ this.editor._offCurrentController();
243
+
244
+ this.editor.focusEdge(focusEl);
245
+ this.history.push(false);
246
+ },
247
+
248
+ /**
249
+ * @description Convert format to link or block
250
+ * @param {Element} target Target element
251
+ * @param {string} value 'link' or 'block'
252
+ */
253
+ convertFormat(target, value) {
254
+ if (value === 'link') {
255
+ this.figure.close();
256
+ const { container } = Figure.GetContainer(target);
257
+ const next = container.nextElementSibling;
258
+ const parent = container.parentElement;
259
+
260
+ target.removeAttribute('data-se-non-focus');
261
+ target.setAttribute('contenteditable', false);
262
+ domUtils.addClass(target, 'se-component|se-inline-component');
263
+
264
+ const line = domUtils.createElement(this.options.get('defaultLine'), null, target);
265
+ parent.insertBefore(line, next);
266
+ domUtils.removeItem(container);
267
+ } else {
268
+ // block
269
+ this.selection.setRange(target, 0, target, 1);
270
+ const r = this.html.remove();
271
+ const s = this.nodeTransform.split(r.container, r.offset, 0);
272
+
273
+ if (s?.previousElementSibling && domUtils.isZeroWith(s.previousElementSibling)) {
274
+ domUtils.removeItem(s.previousElementSibling);
275
+ }
276
+
277
+ target.setAttribute('data-se-non-focus', 'true');
278
+ target.removeAttribute('contenteditable');
279
+ domUtils.removeClass(target, 'se-component|se-component-selected|se-inline-component');
280
+
281
+ const figure = Figure.CreateContainer(target, 'se-file-figure se-flex-component');
282
+ (s || r.container).parentElement.insertBefore(figure.container, s);
283
+ }
284
+
285
+ this.history.push(false);
286
+ this.component.select(target, FileUpload.key, false);
287
+ },
288
+
289
+ _register(response) {
290
+ response.result.forEach((file, i, a) => {
291
+ this._create(
292
+ file.url,
293
+ {
294
+ name: file.name,
295
+ size: file.size
296
+ },
297
+ i === a.length - 1
298
+ );
299
+ });
300
+ },
301
+
302
+ _create(url, file, isLast) {
303
+ const name = file.name || url;
304
+ const a = domUtils.createElement(
305
+ 'A',
306
+ {
307
+ href: url,
308
+ title: name,
309
+ download: name,
310
+ 'data-se-file-download': '',
311
+ contenteditable: 'false',
312
+ 'data-se-non-focus': 'true',
313
+ 'data-se-non-link': 'true'
314
+ },
315
+ name
316
+ );
317
+
318
+ this.fileManager.setFileData(a, file);
319
+
320
+ if (this.as === 'link') {
321
+ a.className = 'se-component se-inline-component';
322
+ this.component.insert(a, false, false);
323
+ return;
324
+ }
325
+
326
+ const figure = Figure.CreateContainer(a);
327
+ domUtils.addClass(figure.container, 'se-file-figure|se-flex-component');
328
+
329
+ if (!this.component.insert(figure.container, false, isLast ? !this.options.get('mediaAutoSelect') : true)) {
330
+ this.editor.focus();
331
+ return;
332
+ }
333
+
334
+ if (!isLast) return;
335
+
336
+ if (!this.options.get('mediaAutoSelect')) {
337
+ const line = this.format.addLine(figure.container, null);
338
+ if (line) this.selection.setRange(line, 0, line, 0);
339
+ } else {
340
+ this.component.select(a, FileUpload.key, false);
341
+ }
342
+ },
343
+
344
+ async _error(response) {
345
+ const message = await this.triggerEvent('onFileUploadError', { error: response });
346
+ if (message === false) return;
347
+ const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
348
+ this.notice.open(err);
349
+ console.error('[SUNEDITOR.plugin.fileUpload.error]', err);
350
+ },
351
+
352
+ _uploadCallBack(xmlHttp) {
353
+ const response = JSON.parse(xmlHttp.responseText);
354
+ if (response.errorMessage) {
355
+ this._error(response);
356
+ } else {
357
+ this._register(response);
358
+ }
359
+ },
360
+
361
+ constructor: FileUpload
362
+ };
363
+
364
+ async function OnChangeFile(e) {
365
+ await this._submitFile(e.target.files);
366
+ }
367
+
368
+ function CreateHTML_controller({ lang, icons }) {
369
+ const html = /*html*/ `
370
+ <div class="se-arrow se-arrow-up"></div>
371
+ <form>
372
+ <div class="se-btn-group se-form-group">
373
+ <input type="text" />
374
+ <button type="submit" data-command="edit" class="se-btn se-tooltip se-btn-success">
375
+ ${icons.checked}
376
+ <span class="se-tooltip-inner"><span class="se-tooltip-text">${lang.save}</span></span>
377
+ </button>
378
+ <button type="button" data-command="cancel" class="se-btn se-tooltip se-btn-danger">
379
+ ${icons.cancel}
380
+ <span class="se-tooltip-inner"><span class="se-tooltip-text">${lang.cancel}</span></span>
381
+ </button>
382
+ </div>
383
+ </form>
384
+ `;
385
+
386
+ return domUtils.createElement('DIV', { class: 'se-controller se-controller-resizing' }, html);
387
+ }
388
+
389
+ export default FileUpload;
@@ -0,0 +1,112 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { domUtils } from '../../helper';
3
+
4
+ const DEFAULT_TYPE = 'disc';
5
+
6
+ const List_bulleted = function (editor) {
7
+ // plugin bisic properties
8
+ EditorInjector.call(this, editor);
9
+ this.title = this.lang.bulletedList;
10
+ this.icon = 'list_bulleted';
11
+ this.afterButton = domUtils.createElement(
12
+ 'button',
13
+ { class: 'se-btn se-tooltip se-sub-arrow-btn', 'data-command': List_bulleted.key, 'data-type': 'dropdown' },
14
+ `${this.icons.arrow_down}<span class="se-tooltip-inner"><span class="se-tooltip-text">${this.lang.bulletedList}</span></span>`
15
+ );
16
+
17
+ // create HTML
18
+ const menu = CreateHTML();
19
+
20
+ // members
21
+ this.listItems = menu.querySelectorAll('li button ul');
22
+
23
+ // init
24
+ this.menu.initDropdownTarget({ key: List_bulleted.key, type: 'dropdown' }, menu);
25
+ };
26
+
27
+ List_bulleted.key = 'list_bulleted';
28
+ List_bulleted.type = 'command';
29
+ List_bulleted.className = 'se-icon-flip-rtl';
30
+ List_bulleted.prototype = {
31
+ /**
32
+ * @override core
33
+ */
34
+ active(element, target) {
35
+ if (domUtils.isListCell(element) && /^UL$/i.test(element.parentElement.nodeName)) {
36
+ domUtils.addClass(target, 'active');
37
+ return true;
38
+ }
39
+
40
+ domUtils.removeClass(target, 'active');
41
+ return false;
42
+ },
43
+
44
+ /**
45
+ * @override dropdown
46
+ */
47
+ on() {
48
+ const list = this.listItems;
49
+ const el = this.format.getBlock(this.selection.getNode());
50
+ const type = el?.style ? el.style.listStyleType || DEFAULT_TYPE : '';
51
+
52
+ for (let i = 0, len = list.length, l; i < len; i++) {
53
+ l = list[i];
54
+ if (type === l.style.listStyleType) {
55
+ domUtils.addClass(l.parentElement, 'active');
56
+ } else {
57
+ domUtils.removeClass(l.parentElement, 'active');
58
+ }
59
+ }
60
+ },
61
+
62
+ /**
63
+ * @override core
64
+ * @param {Element|null} target Target command button
65
+ */
66
+ action(target) {
67
+ const el = this.format.getBlock(this.selection.getNode());
68
+ const type = target?.querySelector('ul')?.style.listStyleType || '';
69
+
70
+ if (domUtils.isList(el) && type) {
71
+ el.style.listStyleType = type;
72
+ } else {
73
+ const range = this.format.applyList(`ul:${type}`, null, false);
74
+ if (range) this.selection.setRange(range.sc, range.so, range.ec, range.eo);
75
+ }
76
+
77
+ this.menu.dropdownOff();
78
+ this.editor.focus();
79
+ this.history.push(false);
80
+ },
81
+
82
+ constructor: List_bulleted
83
+ };
84
+
85
+ function CreateHTML() {
86
+ const html = /*html*/ `
87
+ <div class="se-list-inner">
88
+ <ul class="se-list-basic se-list-horizontal se-list-carrier">
89
+ ${_CreateLI(['disc', 'circle', 'square'])}
90
+ </ul>
91
+ </div>`;
92
+
93
+ return domUtils.createElement('DIV', { class: 'se-dropdown se-list-layer' }, html);
94
+ }
95
+
96
+ function _CreateLI(types) {
97
+ return types
98
+ .map((v) => {
99
+ return /*html*/ `
100
+ <li>
101
+ <button type="button" class="se-btn se-btn-list se-icon-flip-rtl" data-command="${v}" title="${v}" aria-label="${v}">
102
+ <ul style="list-style-type: ${v};">
103
+ <li></li><li></li><li></li>
104
+ </ul>
105
+ </button>
106
+ </li>
107
+ `;
108
+ })
109
+ .join('');
110
+ }
111
+
112
+ export default List_bulleted;