suneditor 3.0.0-alpha.9 → 3.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/CONTRIBUTING.md +170 -22
  2. package/{LICENSE.txt → LICENSE} +9 -9
  3. package/README.md +168 -30
  4. package/dist/suneditor.min.css +1 -1
  5. package/dist/suneditor.min.js +1 -1
  6. package/package.json +47 -21
  7. package/src/assets/design/color.css +121 -0
  8. package/src/assets/design/index.css +3 -0
  9. package/src/assets/design/size.css +35 -0
  10. package/src/assets/design/typography.css +37 -0
  11. package/src/assets/icons/defaultIcons.js +232 -0
  12. package/src/assets/suneditor-contents.css +181 -46
  13. package/src/assets/suneditor.css +1403 -650
  14. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  15. package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
  16. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
  17. package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
  18. package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
  19. package/src/core/base/eventManager.js +520 -179
  20. package/src/core/base/history.js +95 -41
  21. package/src/core/class/char.js +26 -11
  22. package/src/core/class/component.js +345 -137
  23. package/src/core/class/format.js +683 -519
  24. package/src/core/class/html.js +485 -305
  25. package/src/core/class/menu.js +133 -47
  26. package/src/core/class/nodeTransform.js +90 -71
  27. package/src/core/class/offset.js +408 -92
  28. package/src/core/class/selection.js +216 -106
  29. package/src/core/class/shortcuts.js +68 -8
  30. package/src/core/class/toolbar.js +106 -116
  31. package/src/core/class/ui.js +422 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +496 -389
  34. package/src/core/section/actives.js +123 -27
  35. package/src/core/section/constructor.js +615 -206
  36. package/src/core/section/context.js +28 -23
  37. package/src/core/section/documentType.js +561 -0
  38. package/src/editorInjector/_classes.js +19 -5
  39. package/src/editorInjector/_core.js +71 -7
  40. package/src/editorInjector/index.js +63 -1
  41. package/src/events.js +622 -0
  42. package/src/helper/clipboard.js +59 -0
  43. package/src/helper/converter.js +202 -26
  44. package/src/helper/dom/domCheck.js +304 -0
  45. package/src/helper/dom/domQuery.js +669 -0
  46. package/src/helper/dom/domUtils.js +557 -0
  47. package/src/helper/dom/index.js +12 -0
  48. package/src/helper/env.js +46 -56
  49. package/src/helper/index.js +10 -4
  50. package/src/helper/keyCodeMap.js +183 -0
  51. package/src/helper/numbers.js +12 -8
  52. package/src/helper/unicode.js +9 -5
  53. package/src/langs/ckb.js +74 -4
  54. package/src/langs/cs.js +72 -2
  55. package/src/langs/da.js +73 -3
  56. package/src/langs/de.js +73 -4
  57. package/src/langs/en.js +23 -3
  58. package/src/langs/es.js +73 -4
  59. package/src/langs/fa.js +75 -3
  60. package/src/langs/fr.js +73 -3
  61. package/src/langs/he.js +73 -4
  62. package/src/langs/hu.js +230 -0
  63. package/src/langs/index.js +7 -3
  64. package/src/langs/it.js +70 -1
  65. package/src/langs/ja.js +72 -4
  66. package/src/langs/km.js +230 -0
  67. package/src/langs/ko.js +22 -2
  68. package/src/langs/lv.js +74 -5
  69. package/src/langs/nl.js +73 -4
  70. package/src/langs/pl.js +73 -4
  71. package/src/langs/pt_br.js +70 -1
  72. package/src/langs/ro.js +74 -5
  73. package/src/langs/ru.js +73 -4
  74. package/src/langs/se.js +73 -4
  75. package/src/langs/tr.js +73 -1
  76. package/src/langs/{ua.js → uk.js} +75 -6
  77. package/src/langs/ur.js +77 -8
  78. package/src/langs/zh_cn.js +74 -5
  79. package/src/modules/ApiManager.js +77 -54
  80. package/src/modules/Browser.js +667 -0
  81. package/src/modules/ColorPicker.js +162 -102
  82. package/src/modules/Controller.js +273 -142
  83. package/src/modules/Figure.js +925 -484
  84. package/src/modules/FileManager.js +121 -69
  85. package/src/modules/HueSlider.js +113 -61
  86. package/src/modules/Modal.js +291 -122
  87. package/src/modules/ModalAnchorEditor.js +383 -234
  88. package/src/modules/SelectMenu.js +270 -168
  89. package/src/modules/_DragHandle.js +2 -1
  90. package/src/modules/index.js +3 -3
  91. package/src/plugins/browser/audioGallery.js +83 -0
  92. package/src/plugins/browser/fileBrowser.js +103 -0
  93. package/src/plugins/browser/fileGallery.js +83 -0
  94. package/src/plugins/browser/imageGallery.js +81 -0
  95. package/src/plugins/browser/videoGallery.js +103 -0
  96. package/src/plugins/command/blockquote.js +40 -27
  97. package/src/plugins/command/exportPDF.js +134 -0
  98. package/src/plugins/command/fileUpload.js +229 -162
  99. package/src/plugins/command/list_bulleted.js +83 -47
  100. package/src/plugins/command/list_numbered.js +83 -47
  101. package/src/plugins/dropdown/align.js +66 -54
  102. package/src/plugins/dropdown/backgroundColor.js +63 -49
  103. package/src/plugins/dropdown/font.js +71 -47
  104. package/src/plugins/dropdown/fontColor.js +63 -48
  105. package/src/plugins/dropdown/formatBlock.js +70 -33
  106. package/src/plugins/dropdown/hr.js +92 -51
  107. package/src/plugins/dropdown/layout.js +37 -26
  108. package/src/plugins/dropdown/lineHeight.js +54 -38
  109. package/src/plugins/dropdown/list.js +60 -45
  110. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  111. package/src/plugins/dropdown/table.js +2003 -813
  112. package/src/plugins/dropdown/template.js +38 -26
  113. package/src/plugins/dropdown/textStyle.js +43 -31
  114. package/src/plugins/field/mention.js +147 -86
  115. package/src/plugins/index.js +32 -6
  116. package/src/plugins/input/fontSize.js +161 -108
  117. package/src/plugins/input/pageNavigator.js +70 -0
  118. package/src/plugins/modal/audio.js +358 -173
  119. package/src/plugins/modal/drawing.js +531 -0
  120. package/src/plugins/modal/embed.js +886 -0
  121. package/src/plugins/modal/image.js +674 -362
  122. package/src/plugins/modal/link.js +100 -71
  123. package/src/plugins/modal/math.js +367 -167
  124. package/src/plugins/modal/video.js +691 -335
  125. package/src/plugins/popup/anchor.js +222 -0
  126. package/src/suneditor.js +50 -13
  127. package/src/themes/dark.css +122 -0
  128. package/src/typedef.js +130 -0
  129. package/types/assets/icons/defaultIcons.d.ts +153 -0
  130. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  131. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  132. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  133. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  134. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  135. package/types/core/base/eventManager.d.ts +385 -0
  136. package/types/core/base/history.d.ts +81 -0
  137. package/types/core/class/char.d.ts +60 -0
  138. package/types/core/class/component.d.ts +212 -0
  139. package/types/core/class/format.d.ts +616 -0
  140. package/types/core/class/html.d.ts +422 -0
  141. package/types/core/class/menu.d.ts +126 -0
  142. package/types/core/class/nodeTransform.d.ts +93 -0
  143. package/types/core/class/offset.d.ts +522 -0
  144. package/types/core/class/selection.d.ts +188 -0
  145. package/types/core/class/shortcuts.d.ts +142 -0
  146. package/types/core/class/toolbar.d.ts +189 -0
  147. package/types/core/class/ui.d.ts +164 -0
  148. package/types/core/class/viewer.d.ts +140 -0
  149. package/types/core/editor.d.ts +610 -0
  150. package/types/core/section/actives.d.ts +46 -0
  151. package/types/core/section/constructor.d.ts +777 -0
  152. package/types/core/section/context.d.ts +45 -0
  153. package/types/core/section/documentType.d.ts +178 -0
  154. package/types/editorInjector/_classes.d.ts +41 -0
  155. package/types/editorInjector/_core.d.ts +92 -0
  156. package/types/editorInjector/index.d.ts +71 -0
  157. package/types/events.d.ts +273 -0
  158. package/types/helper/clipboard.d.ts +12 -0
  159. package/types/helper/converter.d.ts +197 -0
  160. package/types/helper/dom/domCheck.d.ts +189 -0
  161. package/types/helper/dom/domQuery.d.ts +223 -0
  162. package/types/helper/dom/domUtils.d.ts +226 -0
  163. package/types/helper/dom/index.d.ts +9 -0
  164. package/types/helper/env.d.ts +132 -0
  165. package/types/helper/index.d.ts +174 -0
  166. package/types/helper/keyCodeMap.d.ts +110 -0
  167. package/types/helper/numbers.d.ts +46 -0
  168. package/types/helper/unicode.d.ts +28 -0
  169. package/types/index.d.ts +120 -0
  170. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
  171. package/types/langs/ckb.d.ts +3 -0
  172. package/types/langs/cs.d.ts +3 -0
  173. package/types/langs/da.d.ts +3 -0
  174. package/types/langs/de.d.ts +3 -0
  175. package/types/langs/en.d.ts +3 -0
  176. package/types/langs/es.d.ts +3 -0
  177. package/types/langs/fa.d.ts +3 -0
  178. package/types/langs/fr.d.ts +3 -0
  179. package/types/langs/he.d.ts +3 -0
  180. package/types/langs/hu.d.ts +3 -0
  181. package/types/langs/index.d.ts +54 -0
  182. package/types/langs/it.d.ts +3 -0
  183. package/types/langs/ja.d.ts +3 -0
  184. package/types/langs/km.d.ts +3 -0
  185. package/types/langs/ko.d.ts +3 -0
  186. package/types/langs/lv.d.ts +3 -0
  187. package/types/langs/nl.d.ts +3 -0
  188. package/types/langs/pl.d.ts +3 -0
  189. package/types/langs/pt_br.d.ts +3 -0
  190. package/types/langs/ro.d.ts +3 -0
  191. package/types/langs/ru.d.ts +3 -0
  192. package/types/langs/se.d.ts +3 -0
  193. package/types/langs/tr.d.ts +3 -0
  194. package/types/langs/uk.d.ts +3 -0
  195. package/types/langs/ur.d.ts +3 -0
  196. package/types/langs/zh_cn.d.ts +3 -0
  197. package/types/modules/ApiManager.d.ts +125 -0
  198. package/types/modules/Browser.d.ts +326 -0
  199. package/types/modules/ColorPicker.d.ts +131 -0
  200. package/types/modules/Controller.d.ts +251 -0
  201. package/types/modules/Figure.d.ts +517 -0
  202. package/types/modules/FileManager.d.ts +202 -0
  203. package/types/modules/HueSlider.d.ts +136 -0
  204. package/types/modules/Modal.d.ts +111 -0
  205. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  206. package/types/modules/SelectMenu.d.ts +194 -0
  207. package/types/modules/_DragHandle.d.ts +7 -0
  208. package/types/modules/index.d.ts +26 -0
  209. package/types/plugins/browser/audioGallery.d.ts +55 -0
  210. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  211. package/types/plugins/browser/fileGallery.d.ts +55 -0
  212. package/types/plugins/browser/imageGallery.d.ts +51 -0
  213. package/types/plugins/browser/videoGallery.d.ts +57 -0
  214. package/types/plugins/command/blockquote.d.ts +28 -0
  215. package/types/plugins/command/exportPDF.d.ts +46 -0
  216. package/types/plugins/command/fileUpload.d.ts +156 -0
  217. package/types/plugins/command/list_bulleted.d.ts +46 -0
  218. package/types/plugins/command/list_numbered.d.ts +46 -0
  219. package/types/plugins/dropdown/align.d.ts +60 -0
  220. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  221. package/types/plugins/dropdown/font.d.ts +54 -0
  222. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  223. package/types/plugins/dropdown/formatBlock.d.ts +54 -0
  224. package/types/plugins/dropdown/hr.d.ts +71 -0
  225. package/types/plugins/dropdown/layout.d.ts +40 -0
  226. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  227. package/types/plugins/dropdown/list.d.ts +39 -0
  228. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  229. package/types/plugins/dropdown/table.d.ts +627 -0
  230. package/types/plugins/dropdown/template.d.ts +40 -0
  231. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  232. package/types/plugins/field/mention.d.ts +102 -0
  233. package/types/plugins/index.d.ts +107 -0
  234. package/types/plugins/input/fontSize.d.ts +170 -0
  235. package/types/plugins/input/pageNavigator.d.ts +28 -0
  236. package/types/plugins/modal/audio.d.ts +269 -0
  237. package/types/plugins/modal/drawing.d.ts +246 -0
  238. package/types/plugins/modal/embed.d.ts +387 -0
  239. package/types/plugins/modal/image.d.ts +451 -0
  240. package/types/plugins/modal/link.d.ts +128 -0
  241. package/types/plugins/modal/math.d.ts +193 -0
  242. package/types/plugins/modal/video.d.ts +485 -0
  243. package/types/plugins/popup/anchor.d.ts +56 -0
  244. package/types/suneditor.d.ts +51 -0
  245. package/types/typedef.d.ts +233 -0
  246. package/.eslintignore +0 -7
  247. package/.eslintrc.json +0 -64
  248. package/src/assets/icons/_default.js +0 -194
  249. package/src/core/base/events.js +0 -320
  250. package/src/core/class/notice.js +0 -42
  251. package/src/helper/domUtils.js +0 -1177
  252. package/src/modules/FileBrowser.js +0 -271
  253. package/src/plugins/command/exportPdf.js +0 -168
  254. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  255. package/src/themes/test.css +0 -61
  256. package/typings/CommandPlugin.d.ts +0 -8
  257. package/typings/DialogPlugin.d.ts +0 -20
  258. package/typings/FileBrowserPlugin.d.ts +0 -30
  259. package/typings/Module.d.ts +0 -15
  260. package/typings/Plugin.d.ts +0 -42
  261. package/typings/SubmenuPlugin.d.ts +0 -8
  262. package/typings/_classes.d.ts +0 -17
  263. package/typings/_colorPicker.d.ts +0 -60
  264. package/typings/_core.d.ts +0 -55
  265. package/typings/align.d.ts +0 -5
  266. package/typings/audio.d.ts +0 -5
  267. package/typings/backgroundColor.d.ts +0 -5
  268. package/typings/blockquote.d.ts +0 -5
  269. package/typings/char.d.ts +0 -39
  270. package/typings/component.d.ts +0 -38
  271. package/typings/context.d.ts +0 -39
  272. package/typings/converter.d.ts +0 -33
  273. package/typings/dialog.d.ts +0 -28
  274. package/typings/domUtils.d.ts +0 -361
  275. package/typings/editor.d.ts +0 -7
  276. package/typings/editor.ts +0 -542
  277. package/typings/env.d.ts +0 -70
  278. package/typings/eventManager.d.ts +0 -37
  279. package/typings/events.d.ts +0 -262
  280. package/typings/fileBrowser.d.ts +0 -42
  281. package/typings/fileManager.d.ts +0 -67
  282. package/typings/font.d.ts +0 -5
  283. package/typings/fontColor.d.ts +0 -5
  284. package/typings/fontSize.d.ts +0 -5
  285. package/typings/format.d.ts +0 -191
  286. package/typings/formatBlock.d.ts +0 -5
  287. package/typings/history.d.ts +0 -48
  288. package/typings/horizontalRule.d.ts +0 -5
  289. package/typings/image.d.ts +0 -5
  290. package/typings/imageGallery.d.ts +0 -5
  291. package/typings/index.d.ts +0 -21
  292. package/typings/index.modules.d.ts +0 -11
  293. package/typings/index.plugins.d.ts +0 -58
  294. package/typings/lineHeight.d.ts +0 -5
  295. package/typings/link.d.ts +0 -5
  296. package/typings/list.d.ts +0 -5
  297. package/typings/math.d.ts +0 -5
  298. package/typings/mediaContainer.d.ts +0 -25
  299. package/typings/mention.d.ts +0 -5
  300. package/typings/node.d.ts +0 -57
  301. package/typings/notice.d.ts +0 -16
  302. package/typings/numbers.d.ts +0 -29
  303. package/typings/offset.d.ts +0 -24
  304. package/typings/options.d.ts +0 -589
  305. package/typings/paragraphStyle.d.ts +0 -5
  306. package/typings/resizing.d.ts +0 -141
  307. package/typings/selection.d.ts +0 -94
  308. package/typings/shortcuts.d.ts +0 -13
  309. package/typings/suneditor.d.ts +0 -9
  310. package/typings/table.d.ts +0 -5
  311. package/typings/template.d.ts +0 -5
  312. package/typings/textStyle.d.ts +0 -5
  313. package/typings/toolbar.d.ts +0 -32
  314. package/typings/unicode.d.ts +0 -25
  315. package/typings/video.d.ts +0 -5
@@ -12,6 +12,87 @@ const FONT_VALUES_MAP = {
12
12
  'xxx-large': 8
13
13
  };
14
14
 
15
+ function NodeToJson(node) {
16
+ // text
17
+ if (node.nodeType === 3) {
18
+ const text = node.nodeValue.trim();
19
+ if (text) return { type: 'text', content: text };
20
+ return null;
21
+ }
22
+
23
+ // element
24
+ if (node.nodeType === 1) {
25
+ const jsonNode = {
26
+ type: 'element',
27
+ tag: node.tagName.toLowerCase(),
28
+ attributes: {},
29
+ children: []
30
+ };
31
+
32
+ // get attribute
33
+ for (const attr of node.attributes) {
34
+ jsonNode.attributes[attr.name] = attr.value;
35
+ }
36
+
37
+ // children
38
+ for (const child of node.childNodes) {
39
+ const childJson = NodeToJson(child);
40
+ if (childJson) jsonNode.children.push(childJson);
41
+ }
42
+
43
+ return jsonNode;
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * @description Parses an HTML string into a DOM tree, then recursively traverses the nodes to convert them into a structured JSON representation.
51
+ * -Each element includes its tag name, attributes, and children.
52
+ * -Text nodes are represented as { type: 'text', content: '...' }.
53
+ * @param {string} content HTML string
54
+ * @returns {Object<string, *>} JSON data
55
+ */
56
+ export function htmlToJson(content) {
57
+ const parser = new DOMParser();
58
+ const doc = parser.parseFromString(content, 'text/html');
59
+ return NodeToJson(doc.body);
60
+ }
61
+
62
+ /**
63
+ * @description Takes a JSON structure representing HTML elements and recursively serializes it into a valid HTML string.
64
+ * -It rebuilds each tag with attributes and inner content.
65
+ * Text content and attributes are safely escaped to prevent parsing issues or XSS.
66
+ * Useful for restoring dynamic HTML from a data format.
67
+ * @param {Object<string, *>} jsonData
68
+ * @returns {string} HTML string
69
+ */
70
+ export function jsonToHtml(jsonData) {
71
+ if (!jsonData) return '';
72
+
73
+ if (jsonData.type === 'text') {
74
+ return htmlToEntity(jsonData.content || '');
75
+ }
76
+
77
+ if (jsonData.type === 'element') {
78
+ const { tag, attributes = {}, children = [] } = jsonData;
79
+
80
+ // 속성 문자열 구성
81
+ const attrString = Object.entries(attributes)
82
+ .map(([key, value]) => `${key}="${htmlToEntity(value)}"`)
83
+ .join(' ');
84
+
85
+ const openTag = attrString ? `<${tag} ${attrString}>` : `<${tag}>`;
86
+ const closeTag = `</${tag}>`;
87
+
88
+ const childrenHtml = children.map(jsonToHtml).join('');
89
+
90
+ return `${openTag}${childrenHtml}${closeTag}`;
91
+ }
92
+
93
+ return '';
94
+ }
95
+
15
96
  /**
16
97
  * @description Convert HTML string to HTML Entity
17
98
  * @param {string} content
@@ -53,9 +134,9 @@ export function entityToHTML(content) {
53
134
 
54
135
  /**
55
136
  * @description Debounce function
56
- * @param {Function} func function
137
+ * @param {(...args: *) => void} func function
57
138
  * @param {number} wait delay ms
58
- * @returns
139
+ * @returns {*} executedFunction
59
140
  */
60
141
  export function debounce(func, wait) {
61
142
  let timeout;
@@ -67,19 +148,84 @@ export function debounce(func, wait) {
67
148
  };
68
149
 
69
150
  _w.clearTimeout(timeout);
70
- timeout = setTimeout(later, wait);
151
+ timeout = _w.setTimeout(later, wait);
71
152
  };
72
153
  }
73
154
 
155
+ /**
156
+ * @description Synchronizes two Map objects by updating the first Map with the values from the second,
157
+ * - and deleting any keys in the first Map that are not present in the second.
158
+ * @param {Map<*, *>} targetMap The Map to update (target).
159
+ * @param {Map<*, *>} referenceMap The Map providing the reference values (source).
160
+ */
161
+ export function syncMaps(targetMap, referenceMap) {
162
+ referenceMap.forEach((value, key) => {
163
+ targetMap.set(key, value);
164
+ });
165
+
166
+ targetMap.forEach((_value, key) => {
167
+ if (!referenceMap.has(key)) {
168
+ targetMap.delete(key);
169
+ }
170
+ });
171
+ }
172
+
173
+ /**
174
+ * @description Object.values
175
+ * @param {Object<*, *>} obj Object parameter.
176
+ * @returns {Array<*>}
177
+ */
178
+ export function getValues(obj) {
179
+ return !obj
180
+ ? []
181
+ : Object.keys(obj).map(function (i) {
182
+ return obj[i];
183
+ });
184
+ }
185
+
186
+ /**
187
+ * @description Convert the CamelCase To the KebabCase.
188
+ * @param {string|Array<string>} param [Camel string]
189
+ */
190
+ export function camelToKebabCase(param) {
191
+ if (typeof param === 'string') {
192
+ return param.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase());
193
+ } else {
194
+ return param.map(function (str) {
195
+ return camelToKebabCase(str);
196
+ });
197
+ }
198
+ }
199
+
200
+ /**
201
+ * @overload
202
+ * @param {string} param - Kebab-case string.
203
+ * @returns {string} CamelCase string.
204
+ */
205
+ /**
206
+ * @overload
207
+ * @param {Array<string>} param - Array of Kebab-case strings.
208
+ * @returns {Array<string>} Array of CamelCase strings.
209
+ */
210
+ export function kebabToCamelCase(param) {
211
+ if (typeof param === 'string') {
212
+ return param.replace(/-[a-zA-Z]/g, (letter) => letter.replace('-', '').toUpperCase());
213
+ } else {
214
+ return param.map(function (str) {
215
+ return camelToKebabCase(str);
216
+ });
217
+ }
218
+ }
219
+
74
220
  /**
75
221
  *
76
222
  * @param {"em"|"rem"|"%"|"pt"|"px"} to Size units to be converted
77
223
  * @param {string} size siSize to convert with units (ex: "15rem")
78
224
  * @returns {string}
79
225
  */
80
- export function fontSize(to, size) {
226
+ export function toFontUnit(to, size) {
81
227
  const value = size.match(/(\d+(?:\.\d+)?)(.+)/);
82
- const sizeNum = value ? value[1] * 1 : FONT_VALUES_MAP[size];
228
+ const sizeNum = value ? Number(value[1]) : FONT_VALUES_MAP[size];
83
229
  const from = value ? value[2] : 'rem';
84
230
  let pxSize = sizeNum;
85
231
 
@@ -96,9 +242,9 @@ export function fontSize(to, size) {
96
242
  case 'rem':
97
243
  return (pxSize * 0.0625).toFixed(2) + to;
98
244
  case '%':
99
- return (pxSize * 0.0625).toFixed(2) * 100 + to;
245
+ return Number((pxSize * 0.0625).toFixed(2)) * 100 + to;
100
246
  case 'pt':
101
- return Math.floor(pxSize / 1.333) + to;
247
+ return Math.round(pxSize / 1.333) + to;
102
248
  default:
103
249
  // px
104
250
  return pxSize + to;
@@ -107,7 +253,7 @@ export function fontSize(to, size) {
107
253
 
108
254
  /**
109
255
  * @description Convert the node list to an array. If not, returns an empty array.
110
- * @param {NodeList|null} nodeList
256
+ * @param {?__se__NodeCollection} nodeList
111
257
  * @returns Array
112
258
  */
113
259
  export function nodeListToArray(nodeList) {
@@ -117,8 +263,8 @@ export function nodeListToArray(nodeList) {
117
263
 
118
264
  /**
119
265
  * @description Returns a new object with keys and values swapped.
120
- * @param {Object} obj object
121
- * @returns {Object}
266
+ * @param {Object<*, *>} obj object
267
+ * @returns {Object<*, *>}
122
268
  */
123
269
  export function swapKeyValue(obj) {
124
270
  const swappedObj = {};
@@ -134,9 +280,8 @@ export function swapKeyValue(obj) {
134
280
 
135
281
  /**
136
282
  * @description Create whitelist RegExp object.
137
- * Return RegExp format: new RegExp("<\\/?\\b(?!" + list + ")\\b[^>^<]*+>", "gi")
138
283
  * @param {string} list Tags list ("br|p|div|pre...")
139
- * @returns {RegExp}
284
+ * @returns {RegExp} Return RegExp format: new RegExp("<\\/?\\b(?!" + list + ")\\b[^>^<]*+>", "gi")
140
285
  */
141
286
  export function createElementWhitelist(list) {
142
287
  return new RegExp(`<\\/?\\b(?!\\b${(list || '').replace(/\|/g, '\\b|\\b')}\\b)[^>]*>`, 'gi');
@@ -144,9 +289,8 @@ export function createElementWhitelist(list) {
144
289
 
145
290
  /**
146
291
  * @description Create blacklist RegExp object.
147
- * Return RegExp format: new RegExp("<\\/?\\b(?:" + list + ")\\b[^>^<]*+>", "gi")
148
292
  * @param {string} list Tags list ("br|p|div|pre...")
149
- * @returns {RegExp}
293
+ * @returns {RegExp} Return RegExp format: new RegExp("<\\/?\\b(?:" + list + ")\\b[^>^<]*+>", "gi")
150
294
  */
151
295
  export function createElementBlacklist(list) {
152
296
  return new RegExp(`<\\/?\\b(?:\\b${(list || '^').replace(/\|/g, '\\b|\\b')}\\b)[^>]*>`, 'gi');
@@ -162,7 +306,7 @@ export function isHexColor(str) {
162
306
 
163
307
  /**
164
308
  * @description Function to convert hex format to a rgb color
165
- * @param {string} rgb RGB color format
309
+ * @param {string} rgba RGBA color format
166
310
  * @returns {string}
167
311
  */
168
312
  export function rgb2hex(rgba) {
@@ -191,15 +335,15 @@ export function rgb2hex(rgba) {
191
335
 
192
336
  /**
193
337
  * @description Computes the width as a percentage of the parent's width, and returns this value rounded to two decimal places.
194
- * @param {Element} target
195
- * @param {Element|null} parentTarget
338
+ * @param {HTMLElement} target The target element for which to calculate the width percentage.
339
+ * @param {?HTMLElement=} parentTarget The parent element to use as the reference for the width calculation. If not provided, the target's parent element is used.
196
340
  * @returns {number}
197
341
  */
198
342
  export function getWidthInPercentage(target, parentTarget) {
199
- const parent = parentTarget || target.parentElement;
343
+ const parent = /** @type {HTMLElement} */ (parentTarget || target.parentElement);
200
344
  const parentStyle = _w.getComputedStyle(parent);
201
- const parentPaddingLeft = _w.parseFloat(parentStyle.paddingLeft);
202
- const parentPaddingRight = _w.parseFloat(parentStyle.paddingRight);
345
+ const parentPaddingLeft = parseFloat(parentStyle.paddingLeft);
346
+ const parentPaddingRight = parseFloat(parentStyle.paddingRight);
203
347
  const scrollbarWidth = parent.offsetWidth - parent.clientWidth;
204
348
  const parentWidth = parent.offsetWidth - parentPaddingLeft - parentPaddingRight - scrollbarWidth;
205
349
  const widthInPercentage = (target.offsetWidth / parentWidth) * 100;
@@ -209,11 +353,13 @@ export function getWidthInPercentage(target, parentTarget) {
209
353
  /**
210
354
  * @description Convert url pattern text node to anchor node
211
355
  * @param {Node} node Text node
356
+ * @returns {boolean} Return true if the text node is converted to an anchor node
212
357
  */
213
358
  export function textToAnchor(node) {
214
359
  if (node.nodeType === 3 && URLPattern.test(node.textContent) && !/^A$/i.test(node.parentNode?.nodeName)) {
215
360
  const textContent = node.textContent;
216
361
  const fragment = _d.createDocumentFragment();
362
+
217
363
  let lastIndex = 0;
218
364
  textContent.replace(URLPattern, (match, offset) => {
219
365
  if (offset > 0) {
@@ -228,20 +374,25 @@ export function textToAnchor(node) {
228
374
  if (lastIndex < textContent.length) {
229
375
  fragment.appendChild(_d.createTextNode(textContent.slice(lastIndex)));
230
376
  }
377
+ return match;
231
378
  });
379
+
232
380
  node.parentNode.replaceChild(fragment, node);
381
+ return true;
233
382
  }
383
+
384
+ return false;
234
385
  }
235
386
 
236
387
  /**
237
388
  * Converts styles within a <span> tag to corresponding HTML tags (e.g., <strong>, <em>, <u>, <s>).
238
389
  * Maintains the original <span> tag and wraps its content with the new tags.
239
- * @param {Object} styleToTag An object mapping style properties to HTML tags. ex) {bold: { regex: /font-weight\s*:\s*bold/i, tag: 'strong' },}
390
+ * @param {{ regex: RegExp, tag: string }} styleToTag An object mapping style properties to HTML tags. ex) {bold: { regex: /font-weight\s*:\s*bold/i, tag: 'strong' },}
240
391
  * @param {Node} node Node
241
392
  */
242
393
  export function spanToStyleNode(styleToTag, node) {
243
- if (node.nodeType === 1 && /^SPAN$/i.test(node.nodeName) && node.hasAttribute('style')) {
244
- const style = node.getAttribute('style');
394
+ if (node.nodeType === 1 && /^SPAN$/i.test(node.nodeName) && /** @type {HTMLElement} */ (node).hasAttribute('style')) {
395
+ const style = /** @type {HTMLElement} */ (node).getAttribute('style');
245
396
  const tags = [];
246
397
  Object.keys(styleToTag).forEach((key) => {
247
398
  if (styleToTag[key].regex.test(style)) {
@@ -278,9 +429,27 @@ export function spanToStyleNode(styleToTag, node) {
278
429
  }
279
430
  }
280
431
 
432
+ /**
433
+ * Adds a query string to a URL. If the URL already contains a query string, the new query is appended to the existing one.
434
+ * @param {string} url The original URL to which the query string will be added.
435
+ * @param {string} query The query string to be added to the URL.
436
+ * @returns {string} The updated URL with the query string appended.
437
+ */
438
+ export function addUrlQuery(url, query) {
439
+ if (query.length > 0) {
440
+ if (/\?/.test(url)) {
441
+ const splitUrl = url.split('?');
442
+ url = splitUrl[0] + '?' + query + '&' + splitUrl[1];
443
+ } else {
444
+ url += '?' + query;
445
+ }
446
+ }
447
+ return url;
448
+ }
449
+
281
450
  /**
282
451
  * @description Converts options-related styles and returns them for each frame.
283
- * @param {Object.<string, any>} fo frameOptions
452
+ * @param {Map<string, *>} fo editor.frameOptions
284
453
  * @param {string} cssText Style string
285
454
  * @returns {{top: string, frame: string, editor: string}}
286
455
  * @private
@@ -325,7 +494,7 @@ export function _setDefaultOptionStyle(fo, cssText) {
325
494
 
326
495
  /**
327
496
  * @description Set default style tag of the iframe
328
- * @param {Object.<string, any>} options Options
497
+ * @param {Array<string>} linkNames link names array of CSS files
329
498
  * @returns {string} "<link rel="stylesheet" href=".." />.."
330
499
  */
331
500
  export function _setIframeStyleLinks(linkNames) {
@@ -367,10 +536,16 @@ export function _setAutoHeightStyle(frameHeight) {
367
536
  }
368
537
 
369
538
  const converter = {
539
+ htmlToJson,
540
+ jsonToHtml,
370
541
  htmlToEntity,
371
542
  entityToHTML,
372
543
  debounce,
373
- fontSize,
544
+ syncMaps,
545
+ getValues,
546
+ camelToKebabCase,
547
+ kebabToCamelCase,
548
+ toFontUnit,
374
549
  nodeListToArray,
375
550
  swapKeyValue,
376
551
  createElementWhitelist,
@@ -380,6 +555,7 @@ const converter = {
380
555
  getWidthInPercentage,
381
556
  textToAnchor,
382
557
  spanToStyleNode,
558
+ addUrlQuery,
383
559
  _setDefaultOptionStyle,
384
560
  _setIframeStyleLinks,
385
561
  _setAutoHeightStyle
@@ -0,0 +1,304 @@
1
+ /**
2
+ * @fileoverview Implements Helper for checking the node type and attributes.
3
+ */
4
+
5
+ import { onlyZeroWidthRegExp } from '../unicode';
6
+ import domUtils from './domUtils';
7
+
8
+ /**
9
+ * @description A method that checks If the text is blank or to see if it contains 'ZERO WIDTH SPACE' or empty (unicode.zeroWidthSpace)
10
+ * @param {string|Node} text String value or Node
11
+ * @returns {boolean}
12
+ */
13
+ export function isZeroWidth(text) {
14
+ if (text === null || text === undefined) return false;
15
+ if (typeof text !== 'string') text = text.textContent;
16
+ return text === '' || onlyZeroWidthRegExp.test(text);
17
+ }
18
+
19
+ /**
20
+ * @description Determine if this offset is the edge offset of container
21
+ * @param {Node} container The node of the selection object. (range.startContainer..)
22
+ * @param {number} offset The offset of the selection object. (core.getRange().startOffset...)
23
+ * @param {?"front"|"end"=} dir Select check point - Both edge, Front edge or End edge. ("front": Front edge, "end": End edge, undefined: Both edge)
24
+ * @returns {boolean}
25
+ */
26
+ export function isEdgePoint(container, offset, dir) {
27
+ return (dir !== 'end' && offset === 0) || ((!dir || dir !== 'front') && !container.nodeValue && offset === 1) || ((!dir || dir === 'end') && container.nodeValue && offset >= container.nodeValue.length);
28
+ }
29
+
30
+ /**
31
+ * @description Check the node is a text node.
32
+ * @param {?Node} node The node to check
33
+ * @returns {node is Text}
34
+ */
35
+ export function isText(node) {
36
+ return node?.nodeType === 3;
37
+ }
38
+
39
+ /**
40
+ * @description Check the node is an HTMLElement node.
41
+ * @param {?Node} node The node to check
42
+ * @returns {node is HTMLElement}
43
+ */
44
+ export function isElement(node) {
45
+ return node?.nodeType === 1;
46
+ }
47
+
48
+ /**
49
+ * @description It is judged whether it is the input element (INPUT, TEXTAREA)
50
+ * @param {?Node} node The node to check
51
+ * @returns {node is HTMLInputElement}
52
+ */
53
+ export function isInputElement(node) {
54
+ return isElement(node) && /^(INPUT|TEXTAREA|SELECT|OPTION)$/i.test(node.nodeName);
55
+ }
56
+
57
+ /**
58
+ * @description It is judged whether it is the button element
59
+ * @param {?Node} node The node to check
60
+ * @returns {node is HTMLButtonElement}
61
+ */
62
+ export function isButtonElement(node) {
63
+ return isElement(node) && /^(BUTTON)$/i.test(node.nodeName);
64
+ }
65
+
66
+ /**
67
+ * @description Check the node is a list (ol, ul)
68
+ * @param {?Node|string} node The element or element name to check
69
+ * @returns {node is HTMLOListElement|HTMLUListElement}
70
+ */
71
+ export function isList(node) {
72
+ return /^(OL|UL)$/i.test(typeof node === 'string' ? node : node?.nodeName);
73
+ }
74
+
75
+ /**
76
+ * @description Check the node is a list cell (li)
77
+ * @param {?Node|string} node The element or element name to check
78
+ * @returns {node is HTMLLIElement}
79
+ */
80
+ export function isListCell(node) {
81
+ return /^LI$/i.test(typeof node === 'string' ? node : node?.nodeName);
82
+ }
83
+
84
+ /**
85
+ * @description Check the node is a table
86
+ * @param {?Node|string} node The element or element name to check
87
+ * @returns {node is HTMLTableElement}
88
+ */
89
+ export function isTable(node) {
90
+ return /^TABLE$/i.test(typeof node === 'string' ? node : node?.nodeName);
91
+ }
92
+
93
+ /**
94
+ * @description Check the node is a table elements. (table, thead, tbody, tr, th, td)
95
+ * @param {?Node|string} node The element or element name to check
96
+ * @returns {node is HTMLTableElement|HTMLTableSectionElement|HTMLTableRowElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableColElement}
97
+ */
98
+ export function isTableElements(node) {
99
+ return /^(TABLE|THEAD|TBODY|TR|TH|TD|COL)$/i.test(typeof node === 'string' ? node : node?.nodeName);
100
+ }
101
+
102
+ /**
103
+ * @description Check the node is a table cell (td, th)
104
+ * @param {?Node|string} node The element or element name to check
105
+ * @returns {node is HTMLTableCellElement|HTMLTableColElement}
106
+ */
107
+ export function isTableCell(node) {
108
+ return /^(TD|TH)$/i.test(typeof node === 'string' ? node : node?.nodeName);
109
+ }
110
+
111
+ /**
112
+ * @description Check the node is a table row (tr)
113
+ * @param {?Node|string} node The element or element name to check
114
+ * @returns {node is HTMLTableRowElement}
115
+ */
116
+ export function isTableRow(node) {
117
+ return /^TR$/i.test(typeof node === 'string' ? node : node?.nodeName);
118
+ }
119
+
120
+ /**
121
+ * @description Check the node is a break node (BR)
122
+ * @param {?Node|string} node The element or element name to check
123
+ * @returns {node is HTMLBRElement}
124
+ */
125
+ export function isBreak(node) {
126
+ return /^BR$/i.test(typeof node === 'string' ? node : node?.nodeName);
127
+ }
128
+
129
+ /**
130
+ * @description Check the node is a anchor node (A)
131
+ * @param {?Node|string} node The element or element name to check
132
+ * @returns {node is HTMLAnchorElement}
133
+ */
134
+ export function isAnchor(node) {
135
+ return /^A$/i.test(typeof node === 'string' ? node : node?.nodeName);
136
+ }
137
+
138
+ /**
139
+ * @description Check the node is a media node (img, iframe, audio, video, canvas)
140
+ * @param {?Node|string} node The element or element name to check
141
+ * @returns {node is HTMLImageElement|HTMLIFrameElement|HTMLAudioElement|HTMLVideoElement|HTMLCanvasElement}
142
+ */
143
+ export function isMedia(node) {
144
+ return /^(IMG|IFRAME|AUDIO|VIDEO|CANVAS)$/i.test(typeof node === 'string' ? node : node?.nodeName);
145
+ }
146
+
147
+ /**
148
+ * @description Check the node is a iframe tag
149
+ * @param {?Node|string} node The element or element name to check
150
+ * @returns {node is HTMLIFrameElement}
151
+ */
152
+ export function isIFrame(node) {
153
+ return /^IFRAME$/i.test(typeof node === 'string' ? node : node?.nodeName);
154
+ }
155
+
156
+ /**
157
+ * @description Check the node is a figure tag
158
+ * @param {?Node|string} node The element or element name to check
159
+ * @returns {boolean}
160
+ */
161
+ export function isFigure(node) {
162
+ return /^FIGURE$/i.test(typeof node === 'string' ? node : node?.nodeName);
163
+ }
164
+
165
+ /**
166
+ * @description Checks whether the given node is a content-less (void) HTML tag
167
+ * @param {?Node|string} node The element or element name to check
168
+ * @returns {boolean}
169
+ */
170
+ export function isContentLess(node) {
171
+ return /^(BR|COLGROUP|COL|THEAD|TBODY|TFOOT|TR|AREA|BASE|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR)$/i.test(typeof node === 'string' ? node : node?.nodeName);
172
+ }
173
+
174
+ /**
175
+ * @description Check the line element is empty.
176
+ * @param {Node} node "line" element node
177
+ * @returns {boolean}
178
+ */
179
+ export function isEmptyLine(node) {
180
+ if (!node?.parentNode) return true;
181
+ const el = /** @type {HTMLElement} */ (node);
182
+ return !el.querySelector('IMG, IFRAME, AUDIO, VIDEO, CANVAS, TABLE') && el.children.length === 0 && check.isZeroWidth(el.textContent);
183
+ }
184
+
185
+ /**
186
+ * @description It is judged whether it is the edit region top div element or iframe's body tag.
187
+ * @param {?Node} node The node to check
188
+ * @returns {node is HTMLElement}
189
+ */
190
+ export function isWysiwygFrame(node) {
191
+ return node?.nodeType === 1 && (domUtils.hasClass(node, 'se-wrapper-wysiwyg|sun-editor-carrier-wrapper') || /^BODY$/i.test(node.nodeName));
192
+ }
193
+
194
+ /**
195
+ * @description It is judged whether it is the contenteditable property is false.
196
+ * @param {?Node} node The node to check
197
+ * @returns {node is HTMLElement}
198
+ */
199
+ export function isNonEditable(node) {
200
+ return node?.nodeType === 1 && /** @type {HTMLElement} */ (node).getAttribute('contenteditable') === 'false';
201
+ }
202
+
203
+ /**
204
+ * @description Check the span's attributes are empty.
205
+ * @param {?Node} node Element node
206
+ * @returns {boolean}
207
+ */
208
+ export function isSpanWithoutAttr(node) {
209
+ if (node?.nodeType !== 1) return false;
210
+ const el = /** @type {HTMLElement} */ (node);
211
+ return /^SPAN$/i.test(el.nodeName) && !el.className && !el.style.cssText;
212
+ }
213
+
214
+ /**
215
+ * @description Compares the style and class for equal values.
216
+ * @param {Node} a Node to compare
217
+ * @param {Node} b Node to compare
218
+ * @returns {boolean} Returns true if both are text nodes.
219
+ */
220
+ export function isSameAttributes(a, b) {
221
+ if (a.nodeType === 3 && b.nodeType === 3) return true;
222
+ if (a.nodeType === 3 || b.nodeType === 3) return false;
223
+
224
+ const aEl = /** @type {HTMLElement} */ (a);
225
+ const bEl = /** @type {HTMLElement} */ (b);
226
+
227
+ const style_a = aEl.style;
228
+ const style_b = bEl.style;
229
+ let compStyle = 0;
230
+
231
+ for (let i = 0, len = style_a.length; i < len; i++) {
232
+ if (style_a[style_a[i]] === style_b[style_a[i]]) compStyle++;
233
+ }
234
+
235
+ const class_a = aEl.classList;
236
+ const class_b = bEl.classList;
237
+ const wRegExp = RegExp;
238
+ let compClass = 0;
239
+
240
+ for (let i = 0, len = class_a.length; i < len; i++) {
241
+ if (wRegExp('(s|^)' + class_a[i] + '(s|$)').test(class_b.value)) compClass++;
242
+ }
243
+
244
+ return compStyle === style_b.length && compStyle === style_a.length && compClass === class_b.length && compClass === class_a.length;
245
+ }
246
+
247
+ /**
248
+ * @description It is judged whether it is the not checking node. (class="katex", "MathJax", "se-exclude-format")
249
+ * @param {Node} node The node to check
250
+ * @returns {node is HTMLElement}
251
+ */
252
+ export function isExcludeFormat(node) {
253
+ return /(\s|^)(katex|MathJax|se-exclude-format)(\s|$)/.test(/** @type {HTMLElement} */ (node)?.className);
254
+ }
255
+
256
+ /**
257
+ * @description Checks for "__se__uneditable" in the class list.
258
+ * - Components with class "__se__uneditable" cannot be modified.
259
+ * @param {Node} node The element to check
260
+ * @returns {boolean}
261
+ */
262
+ export function isUneditable(node) {
263
+ return domUtils.hasClass(node, '__se__uneditable');
264
+ }
265
+
266
+ /**
267
+ * @description Checks if element can't be easily enabled
268
+ * @param {Node} node Element to check for
269
+ * @returns {boolean}
270
+ */
271
+ export function isImportantDisabled(node) {
272
+ return /** @type {HTMLElement} */ (node).hasAttribute('data-important-disabled');
273
+ }
274
+
275
+ const check = {
276
+ isZeroWidth,
277
+ isEdgePoint,
278
+ isText,
279
+ isElement,
280
+ isInputElement,
281
+ isButtonElement,
282
+ isList,
283
+ isListCell,
284
+ isTable,
285
+ isTableElements,
286
+ isTableCell,
287
+ isTableRow,
288
+ isBreak,
289
+ isAnchor,
290
+ isMedia,
291
+ isIFrame,
292
+ isFigure,
293
+ isContentLess,
294
+ isEmptyLine,
295
+ isWysiwygFrame,
296
+ isNonEditable,
297
+ isSpanWithoutAttr,
298
+ isSameAttributes,
299
+ isExcludeFormat,
300
+ isUneditable,
301
+ isImportantDisabled
302
+ };
303
+
304
+ export default check;