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,533 @@
1
+ import { _d, _w } from '../env';
2
+ import check from './domCheck';
3
+
4
+ /**
5
+ * @template {Node} T
6
+ * @description Clones a node while preserving its type.
7
+ * @param {T} node - The node to clone.
8
+ * @param {boolean} [deep=false] - Whether to perform a deep clone.
9
+ * @returns {T} - The cloned node.
10
+ */
11
+ function clone(node, deep = false) {
12
+ return /** @type {T} */ (node.cloneNode(deep));
13
+ }
14
+
15
+ /**
16
+ * @template {HTMLElement} T
17
+ * @description Create Element node
18
+ * @param {string} elementName Element name
19
+ * @param {?Object<string, string>=} attributes The attributes of the tag. {style: 'font-size:12px;..', class: 'el_class',..}
20
+ * @param {?string|Node=} inner A innerHTML string or inner node.
21
+ * @returns {T}
22
+ */
23
+ export function createElement(elementName, attributes, inner) {
24
+ const el = _d.createElement(elementName);
25
+
26
+ if (attributes) {
27
+ for (const key in attributes) {
28
+ if (attributes[key] !== undefined && attributes[key] !== null) el.setAttribute(key, attributes[key]);
29
+ }
30
+ }
31
+
32
+ if (inner) {
33
+ if (typeof inner === 'string') {
34
+ el.innerHTML = inner;
35
+ } else if (typeof inner === 'object') {
36
+ el.appendChild(inner);
37
+ }
38
+ }
39
+
40
+ return /** @type {T} */ (el);
41
+ }
42
+
43
+ /**
44
+ * @description Create text node
45
+ * @param {string} text text content
46
+ * @returns {Text}
47
+ */
48
+ export function createTextNode(text) {
49
+ return _d.createTextNode(text || '');
50
+ }
51
+
52
+ /**
53
+ * @description Get attributes of argument element to string ('class="---" name="---" ')
54
+ * @param {Node} element Element object
55
+ * @param {Array<string>|null} exceptAttrs Array of attribute names to exclude from the result
56
+ * @returns {string}
57
+ */
58
+ export function getAttributesToString(element, exceptAttrs) {
59
+ const attrs = /** @type {HTMLElement} */ (element).attributes;
60
+ if (!attrs) return '';
61
+
62
+ let attrString = '';
63
+ for (let i = 0, len = attrs.length; i < len; i++) {
64
+ if (exceptAttrs?.includes(attrs[i].name)) continue;
65
+ attrString += attrs[i].name + '="' + attrs[i].value + '" ';
66
+ }
67
+
68
+ return attrString;
69
+ }
70
+
71
+ /**
72
+ * @description Get the items array from the array that matches the condition.
73
+ * @param {__se__NodeCollection} array Array to get item
74
+ * @param {?(current: *) => boolean} validation Conditional function
75
+ * @returns {Array<Node>|null}
76
+ */
77
+ export function arrayFilter(array, validation) {
78
+ if (!array || array.length === 0) return null;
79
+
80
+ validation =
81
+ validation ||
82
+ function () {
83
+ return true;
84
+ };
85
+ const arr = [];
86
+
87
+ for (let i = 0, len = array.length, a; i < len; i++) {
88
+ a = array[i];
89
+ if (validation(a)) {
90
+ arr.push(a);
91
+ }
92
+ }
93
+
94
+ return arr;
95
+ }
96
+
97
+ /**
98
+ * @description Get the item from the array that matches the condition.
99
+ * @param {__se__NodeCollection} array Array to get item
100
+ * @param {?(current: *) => boolean} validation Conditional function
101
+ * @returns {Node|null}
102
+ */
103
+ export function arrayFind(array, validation) {
104
+ if (!array || array.length === 0) return null;
105
+
106
+ validation =
107
+ validation ||
108
+ function () {
109
+ return true;
110
+ };
111
+
112
+ for (let i = 0, len = array.length, a; i < len; i++) {
113
+ a = array[i];
114
+ if (validation(a)) {
115
+ return a;
116
+ }
117
+ }
118
+
119
+ return null;
120
+ }
121
+
122
+ /**
123
+ * @description Check if an array contains an element
124
+ * @param {__se__NodeCollection} array element array
125
+ * @param {Node} node The node to check for
126
+ * @returns {boolean}
127
+ */
128
+ export function arrayIncludes(array, node) {
129
+ for (let i = 0; i < array.length; i++) {
130
+ if (array[i] === node) {
131
+ return true;
132
+ }
133
+ }
134
+ return false;
135
+ }
136
+
137
+ /**
138
+ * @description Get the index of the argument value in the element array
139
+ * @param {__se__NodeCollection} array element array
140
+ * @param {Node} node The element to find index
141
+ * @returns {number}
142
+ */
143
+ export function getArrayIndex(array, node) {
144
+ let idx = -1;
145
+ for (let i = 0, len = array.length; i < len; i++) {
146
+ if (array[i] === node) {
147
+ idx = i;
148
+ break;
149
+ }
150
+ }
151
+
152
+ return idx;
153
+ }
154
+
155
+ /**
156
+ * @description Get the next index of the argument value in the element array
157
+ * @param {__se__NodeCollection} array element array
158
+ * @param {Node} item The element to find index
159
+ * @returns {number}
160
+ */
161
+ export function nextIndex(array, item) {
162
+ const idx = getArrayIndex(array, item);
163
+ if (idx === -1) return -1;
164
+ return idx + 1;
165
+ }
166
+
167
+ /**
168
+ * @description Get the previous index of the argument value in the element array
169
+ * @param {__se__NodeCollection} array Element array
170
+ * @param {Node} item The element to find index
171
+ * @returns {number}
172
+ */
173
+ export function prevIndex(array, item) {
174
+ const idx = getArrayIndex(array, item);
175
+ if (idx === -1) return -1;
176
+ return idx - 1;
177
+ }
178
+
179
+ /**
180
+ * @description Add style and className of copyEl to originEl
181
+ * @param {Node} originEl Origin element
182
+ * @param {Node} copyEl Element to copy
183
+ * @param {?Array<string>=} blacklist Blacklist array(LowerCase)
184
+ */
185
+ export function copyTagAttributes(originEl, copyEl, blacklist) {
186
+ const o = /** @type {HTMLElement} */ (originEl);
187
+ const c = /** @type {HTMLElement} */ (copyEl);
188
+ if (c.style.cssText) {
189
+ const copyStyles = c.style;
190
+ for (let i = 0, len = copyStyles.length; i < len; i++) {
191
+ o.style[copyStyles[i]] = copyStyles[copyStyles[i]];
192
+ }
193
+ }
194
+
195
+ const attrs = c.attributes;
196
+ for (let i = 0, len = attrs.length, name; i < len; i++) {
197
+ name = attrs[i].name.toLowerCase();
198
+ if (blacklist?.includes(name) || !attrs[i].value) o.removeAttribute(name);
199
+ else if (name !== 'style') o.setAttribute(attrs[i].name, attrs[i].value);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * @description Copy and apply attributes of format tag that should be maintained. (style, class) Ignore "__se__format__" class
205
+ * @param {Node} originEl Origin element
206
+ * @param {Node} copyEl Element to copy
207
+ */
208
+ export function copyFormatAttributes(originEl, copyEl) {
209
+ const c = /** @type {HTMLElement} */ (copyEl.cloneNode(false));
210
+ c.className = c.className.replace(/(\s|^)__se__format__[^\s]+/g, '');
211
+ copyTagAttributes(originEl, c);
212
+ }
213
+
214
+ /**
215
+ * @description Delete argumenu value element
216
+ * @param {Node} item Node to be remove
217
+ */
218
+ export function removeItem(item) {
219
+ if (!item) return;
220
+ if ('remove' in item && typeof item.remove === 'function') item.remove();
221
+ else if (item.parentNode) item.parentNode.removeChild(item);
222
+ }
223
+
224
+ /**
225
+ * @description Replace element
226
+ * @param {Node} element Target element
227
+ * @param {string|Node} newElement String or element of the new element to apply
228
+ */
229
+ export function changeElement(element, newElement) {
230
+ if (!element) return;
231
+
232
+ if (typeof newElement === 'string') {
233
+ if ('outerHTML' in element) {
234
+ element.outerHTML = newElement;
235
+ } else {
236
+ const doc = createElement('DIV');
237
+ doc.innerHTML = newElement;
238
+ element.parentNode.replaceChild(doc.firstChild, element);
239
+ }
240
+ } else if (newElement?.nodeType === 1) {
241
+ element.parentNode.replaceChild(newElement, element);
242
+ }
243
+ }
244
+
245
+ /**
246
+ * @description Set the text content value of the argument value element
247
+ * @param {Node} node Element to replace text content
248
+ * @param {string} txt Text to be applied
249
+ */
250
+ export function changeTxt(node, txt) {
251
+ if (!node || !txt) return;
252
+ node.textContent = txt;
253
+ }
254
+
255
+ /**
256
+ * @description Set style, if all styles are deleted, the style properties are deleted.
257
+ * @param {Node|Node[]} elements Element to set style
258
+ * @param {string} styleName Style attribute name (marginLeft, textAlign...)
259
+ * @param {string|number} value Style value
260
+ */
261
+ export function setStyle(elements, styleName, value) {
262
+ elements = Array.isArray(elements) ? elements : [elements];
263
+
264
+ for (let i = 0, len = elements.length, e; i < len; i++) {
265
+ e = /** @type {HTMLElement} */ (elements[i]);
266
+ e.style[styleName] = value;
267
+ if (!value && !e.style.cssText) {
268
+ e.removeAttribute('style');
269
+ }
270
+ }
271
+ }
272
+
273
+ /**
274
+ * @description In the predefined code view mode, the buttons except the executable button are changed to the 'disabled' state.
275
+ * @param {Array<HTMLButtonElement|HTMLInputElement>} buttonList (Button | Input) Element array
276
+ * @param {boolean} disabled Disabled value
277
+ * @param {boolean} [important=false] If priveleged mode should be used (Necessary to switch importantDisabled buttons)
278
+ */
279
+ export function setDisabled(buttonList, disabled, important) {
280
+ for (let i = 0, len = buttonList.length; i < len; i++) {
281
+ const button = buttonList[i];
282
+ if (important || !check.isImportantDisabled(button)) button.disabled = disabled;
283
+ if (important) {
284
+ if (disabled) {
285
+ button.setAttribute('data-important-disabled', '');
286
+ } else {
287
+ button.removeAttribute('data-important-disabled');
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ /**
294
+ * @description Determine whether any of the matched elements are assigned the given class
295
+ * @param {?Node} element Elements to search class name
296
+ * @param {string} className Class name to search for
297
+ * @returns {boolean}
298
+ */
299
+ export function hasClass(element, className) {
300
+ if (!element || element.nodeType !== 1) return;
301
+ const valid = new RegExp(`(\\s|^)${className}(\\s|$)`);
302
+ return valid.test(/** @type {HTMLElement} */ (element).className);
303
+ }
304
+
305
+ /**
306
+ * @description Append the className value of the argument value element
307
+ * @param {Node|__se__NodeCollection} element Elements to add class name
308
+ * @param {string} className Class name to be add
309
+ */
310
+ export function addClass(element, className) {
311
+ if (!element) return;
312
+
313
+ const elements = element instanceof HTMLCollection || element instanceof NodeList || element instanceof Array ? element : [element];
314
+ const classNames = className.split('|');
315
+
316
+ for (let i = 0, len = elements.length; i < len; i++) {
317
+ const e = elements[i];
318
+ if (!e || e.nodeType !== 1) continue;
319
+ for (const c of classNames) {
320
+ if (c) /** @type {HTMLElement} */ (e).classList.add(c);
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * @description Delete the className value of the argument value element
327
+ * @param {Node|__se__NodeCollection} element Elements to remove class name
328
+ * @param {string} className Class name to be remove
329
+ */
330
+ export function removeClass(element, className) {
331
+ if (!element) return;
332
+
333
+ const elements = element instanceof HTMLCollection || element instanceof NodeList || element instanceof Array ? element : [element];
334
+ const classNames = className.split('|');
335
+
336
+ for (let i = 0, len = elements.length; i < len; i++) {
337
+ const e = elements[i];
338
+ if (!e || e.nodeType !== 1) continue;
339
+ for (const c of classNames) {
340
+ if (c) /** @type {HTMLElement} */ (e).classList.remove(c);
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * @description Argument value If there is no class name, insert it and delete the class name if it exists
347
+ * @param {Node} element Element to replace class name
348
+ * @param {string} className Class name to be change
349
+ * @returns {boolean|undefined}
350
+ */
351
+ export function toggleClass(element, className) {
352
+ if (!element || element.nodeType !== 1) return;
353
+
354
+ const el = /** @type {HTMLElement} */ (element);
355
+
356
+ let result = false;
357
+ const valid = new RegExp(`(\\s|^)${className}(\\s|$)`);
358
+ if (valid.test(el.className)) {
359
+ el.className = el.className.replace(valid, ' ').trim();
360
+ } else {
361
+ el.className += ' ' + className;
362
+ result = true;
363
+ }
364
+
365
+ if (!el.className.trim()) el.removeAttribute('class');
366
+
367
+ return result;
368
+ }
369
+
370
+ /**
371
+ * @description Gets the size of the documentElement client size.
372
+ * @param {Document} doc Document object
373
+ * @returns {{w: number, h: number}} documentElement.clientWidth, documentElement.clientHeight
374
+ */
375
+ export function getClientSize(doc = _d) {
376
+ return {
377
+ w: doc.documentElement.clientWidth,
378
+ h: doc.documentElement.clientHeight
379
+ };
380
+ }
381
+
382
+ /**
383
+ * @description Gets the size of the window visualViewport size
384
+ * @returns {{top: number, left: number, scale: number}}
385
+ */
386
+ export function getViewportSize() {
387
+ if ('visualViewport' in _w) {
388
+ return {
389
+ top: _w.visualViewport.pageTop,
390
+ left: _w.visualViewport.pageLeft,
391
+ scale: _w.visualViewport.scale
392
+ };
393
+ }
394
+
395
+ return {
396
+ top: 0,
397
+ left: 0,
398
+ scale: 1
399
+ };
400
+ }
401
+
402
+ /**
403
+ * @description Copies the "wwTarget" element and returns it with inline all styles applied.
404
+ * @param {Node} wwTarget Target element to copy(.sun-editor.sun-editor-editable)
405
+ * @param {boolean} includeWW Include the "wwTarget" element in the copy
406
+ * @param {Array<string>} styles Style list - kamel case
407
+ * @returns
408
+ */
409
+ export function applyInlineStylesAll(wwTarget, includeWW, styles) {
410
+ if (!wwTarget) {
411
+ console.warn('"parentTarget" is not exist');
412
+ return null;
413
+ }
414
+
415
+ let ww = /** @type {HTMLElement} */ (wwTarget);
416
+ const tempTarget = _d.createElement('DIV');
417
+ tempTarget.style.display = 'none';
418
+
419
+ if (/body/i.test(ww.nodeName)) {
420
+ const wwDiv = _d.createElement('DIV');
421
+ const attrs = ww.attributes;
422
+ for (let i = 0, len = attrs.length; i < len; i++) {
423
+ wwDiv.setAttribute(attrs[i].name, attrs[i].value);
424
+ }
425
+ wwDiv.innerHTML = ww.innerHTML;
426
+ ww = wwDiv;
427
+ } else {
428
+ ww = /** @type {HTMLElement} */ (ww.cloneNode(true));
429
+ }
430
+
431
+ tempTarget.appendChild(ww);
432
+ _d.body.appendChild(tempTarget);
433
+
434
+ /** @type {HTMLElement[]} */
435
+ const allElements = Array.from(ww.querySelectorAll('*'));
436
+ const elements = includeWW ? [ww].concat(allElements) : allElements;
437
+ for (let i = 0, el; (el = elements[i]); i++) {
438
+ if (el.nodeType !== 1) continue;
439
+ const computedStyle = _w.getComputedStyle(el);
440
+ const els = el.style;
441
+ for (const props of styles) {
442
+ els.setProperty(props, computedStyle.getPropertyValue(props) || '');
443
+ }
444
+ }
445
+
446
+ _d.body.removeChild(tempTarget);
447
+
448
+ return ww;
449
+ }
450
+
451
+ /**
452
+ * @description Wait for media elements to load
453
+ * @param {Node} target Target element
454
+ * @param {number} timeout Timeout milliseconds
455
+ * @returns {Promise<void>}
456
+ */
457
+ function waitForMediaLoad(target, timeout = 5000) {
458
+ const doc = /** @type {HTMLElement|Document} */ (target || _d);
459
+ return new Promise((resolveAll) => {
460
+ const selectors = ['img', 'video', 'audio', 'iframe'];
461
+ const mediaElements = selectors.flatMap((selector) => Array.from(doc.querySelectorAll(selector)));
462
+
463
+ if (mediaElements.length === 0) {
464
+ resolveAll();
465
+ return;
466
+ }
467
+
468
+ const mediaPromises = mediaElements.map((element) => {
469
+ // image
470
+ if (element instanceof HTMLImageElement) {
471
+ if (element.complete) {
472
+ return Promise.resolve();
473
+ }
474
+ }
475
+ // video, audio
476
+ else if (element instanceof HTMLMediaElement) {
477
+ if (element.readyState >= 2) {
478
+ return Promise.resolve();
479
+ }
480
+ }
481
+ // iframe
482
+ else if (element instanceof HTMLIFrameElement) {
483
+ try {
484
+ if (element.contentDocument?.readyState === 'complete') {
485
+ return Promise.resolve();
486
+ }
487
+ } catch (e) {
488
+ console.warn(['[SUNEDITOR] Iframe load error', e]);
489
+ }
490
+ }
491
+
492
+ // load event
493
+ return new Promise((resolve) => {
494
+ element.addEventListener('load', resolve, { once: true });
495
+ element.addEventListener('error', resolve, { once: true });
496
+ });
497
+ });
498
+
499
+ Promise.race([Promise.all(mediaPromises), new Promise((resolve) => setTimeout(resolve, timeout))]).then(() => {
500
+ resolveAll();
501
+ });
502
+ });
503
+ }
504
+
505
+ const utils = {
506
+ clone,
507
+ createElement,
508
+ createTextNode,
509
+ getAttributesToString,
510
+ arrayFilter,
511
+ arrayFind,
512
+ arrayIncludes,
513
+ getArrayIndex,
514
+ nextIndex,
515
+ prevIndex,
516
+ copyTagAttributes,
517
+ copyFormatAttributes,
518
+ removeItem,
519
+ changeElement,
520
+ changeTxt,
521
+ setStyle,
522
+ setDisabled,
523
+ hasClass,
524
+ addClass,
525
+ removeClass,
526
+ toggleClass,
527
+ getClientSize,
528
+ getViewportSize,
529
+ applyInlineStylesAll,
530
+ waitForMediaLoad
531
+ };
532
+
533
+ export default utils;
@@ -0,0 +1,12 @@
1
+ // index.js
2
+ import query from './domQuery';
3
+ import check from './domCheck';
4
+ import utils from './domUtils';
5
+
6
+ const dom = {
7
+ query,
8
+ check,
9
+ utils
10
+ };
11
+
12
+ export default dom;
package/src/helper/env.js CHANGED
@@ -1,15 +1,26 @@
1
+ /** @type {Window} */
1
2
  export const _w = window;
3
+ /** @type {Document} */
2
4
  export const _d = document;
3
5
 
6
+ /**
7
+ * @description No event symbol
8
+ * @type {Symbol}
9
+ */
4
10
  export const NO_EVENT = Symbol('noEventHandler');
11
+
12
+ /**
13
+ * @description On over component symbol
14
+ * @type {Symbol}
15
+ */
5
16
  export const ON_OVER_COMPONENT = Symbol('onOverComponent');
6
17
 
7
18
  const userAgent = _w.navigator.userAgent.toLowerCase();
8
19
 
9
20
  /**
10
21
  * @description Object.values
11
- * @param {Object.<any>} obj Object parameter.
12
- * @returns {Array.<any>}
22
+ * @param {Object<*, *>} obj Object parameter.
23
+ * @returns {Array<*>}
13
24
  */
14
25
  export function getValues(obj) {
15
26
  return !obj
@@ -21,7 +32,7 @@ export function getValues(obj) {
21
32
 
22
33
  /**
23
34
  * @description Convert the CamelCase To the KebabCase.
24
- * @param {string|Array.<string>} param [Camel string]
35
+ * @param {string|Array<string>} param [Camel string]
25
36
  */
26
37
  export function camelToKebabCase(param) {
27
38
  if (typeof param === 'string') {
@@ -34,9 +45,14 @@ export function camelToKebabCase(param) {
34
45
  }
35
46
 
36
47
  /**
37
- * @description Convert the KebabCase To the CamelCase.
38
- * @param {String|Array} param [KebabCase string]
39
- * @returns {String|Array}
48
+ * @overload
49
+ * @param {string} param - Kebab-case string.
50
+ * @returns {string} CamelCase string.
51
+ */
52
+ /**
53
+ * @overload
54
+ * @param {Array<string>} param - Array of Kebab-case strings.
55
+ * @returns {Array<string>} Array of CamelCase strings.
40
56
  */
41
57
  export function kebabToCamelCase(param) {
42
58
  if (typeof param === 'string') {
@@ -50,7 +66,7 @@ export function kebabToCamelCase(param) {
50
66
 
51
67
  /**
52
68
  * @description Gets XMLHttpRequest object
53
- * @returns {XMLHttpRequest|ActiveXObject}
69
+ * @returns {XMLHttpRequest}
54
70
  */
55
71
  export function getXMLHttpRequest() {
56
72
  return new XMLHttpRequest();
@@ -86,10 +102,9 @@ export function getPageStyle(doc) {
86
102
  /**
87
103
  * @deprecated
88
104
  * @description Get the the tag path of the arguments value
89
- * If not found, return the first found value
90
- * @param {Array.<string>} nameArray File name array
105
+ * @param {Array<string>} nameArray File name array
91
106
  * @param {string} extension js, css
92
- * @returns {string}
107
+ * @returns {string} If not found, return the first found value
93
108
  */
94
109
  export function getIncludePath(nameArray, extension) {
95
110
  let path = '';
@@ -122,7 +137,7 @@ export function getIncludePath(nameArray, extension) {
122
137
  if (path === '') path = pathList.length > 0 ? pathList[0][src] : '';
123
138
 
124
139
  if (!path.includes(':/') && '//' !== path.slice(0, 2)) {
125
- path = 0 === path.includes('/') ? location.href.match(/^.*?:\/\/[^/]*/)[0] + path : location.href.match(/^[^?]*\/(?:)/)[0] + path;
140
+ path = false === path.includes('/') ? location.href.match(/^.*?:\/\/[^/]*/)[0] + path : location.href.match(/^[^?]*\/(?:)/)[0] + path;
126
141
  }
127
142
 
128
143
  if (!path) {
@@ -146,15 +161,15 @@ export const isResizeObserverSupported = (() => {
146
161
  * @returns {boolean} Whether User Agent is Edge or not.
147
162
  */
148
163
  export const isEdge = (() => {
149
- return navigator.appVersion.includes('Edge');
164
+ return /Edg/.test(navigator.userAgent);
150
165
  })();
151
166
 
152
167
  /**
153
- * @description Check if platform is OSX or IOS
168
+ * @description Check if User Agent is OSX or IOS
154
169
  * @type {boolean}
155
170
  */
156
171
  export const isOSX_IOS = (() => {
157
- return /(Mac|iPhone|iPod|iPad)/.test(navigator.platform);
172
+ return /(Mac|iPhone|iPod|iPad)/.test(navigator.userAgent);
158
173
  })();
159
174
 
160
175
  /**
@@ -178,7 +193,7 @@ export const isGecko = (() => {
178
193
  * @type {boolean}
179
194
  */
180
195
  export const isChromium = (() => {
181
- return !!window.chrome;
196
+ return !!(/** @type {Window & { chrome: any }} */ (_w).chrome);
182
197
  })();
183
198
 
184
199
  /**
@@ -191,11 +206,11 @@ export const isSafari = (() => {
191
206
 
192
207
  /**
193
208
  * @description Check if User Agent is Mobile device.
194
- * when the device is touchable, it is judged as a mobile device.
209
+ * - when the device is touchable, it is judged as a mobile device.
195
210
  * @type {boolean}
196
211
  */
197
212
  export const isMobile = (() => {
198
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) || 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
213
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent) || (navigator.maxTouchPoints > 0 && 'ontouchstart' in _w);
199
214
  })();
200
215
 
201
216
  /**
@@ -218,9 +233,15 @@ export const cmdIcon = isOSX_IOS ? '⌘' : 'CTRL';
218
233
  */
219
234
  export const shiftIcon = isOSX_IOS ? '⇧' : '+SHIFT';
220
235
 
236
+ /**
237
+ * @description Device pixel ratio
238
+ * @type {number}
239
+ */
240
+ export const DPI = _w.devicePixelRatio;
241
+
221
242
  /** --- editor env --- */
222
- export const _allowedEmptyNodeList = '.se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas, details';
223
243
  export const KATEX_WEBSITE = 'https://katex.org/docs/supported.html';
244
+ export const MATHJAX_WEBSITE = 'https://www.mathjax.org/';
224
245
 
225
246
  const env = {
226
247
  _w,
@@ -244,7 +265,9 @@ const env = {
244
265
  isMobile,
245
266
  cmdIcon,
246
267
  shiftIcon,
247
- _allowedEmptyNodeList
268
+ DPI,
269
+ KATEX_WEBSITE,
270
+ MATHJAX_WEBSITE
248
271
  };
249
272
 
250
273
  export default env;