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
@@ -3,23 +3,51 @@
3
3
  */
4
4
 
5
5
  import CoreInjector from '../../editorInjector/_core';
6
- import { domUtils, unicode } from '../../helper';
6
+ import { dom, unicode, env } from '../../helper';
7
7
 
8
- const Selection = function (editor) {
8
+ /**
9
+ * @typedef {Omit<Selection_ & Partial<__se__EditorInjector>, 'selection'>} SelectionThis
10
+ */
11
+
12
+ /**
13
+ * @typedef {import('./offset').RectsInfo} RectsInfo_selection
14
+ */
15
+
16
+ /**
17
+ * @constructor
18
+ * @this {SelectionThis}
19
+ * @description Selection, Range related class
20
+ * @param {__se__EditorCore} editor - The root editor instance
21
+ */
22
+ function Selection_(editor) {
9
23
  CoreInjector.call(this, editor);
10
24
 
11
25
  // members
26
+ /** @type {Range} */
12
27
  this.range = null;
28
+ /** @type {HTMLElement|Text} */
13
29
  this.selectionNode = null;
14
- };
30
+ this.__iframeFocus = false;
31
+ }
15
32
 
16
- Selection.prototype = {
33
+ Selection_.prototype = {
17
34
  /**
35
+ * @this {SelectionThis}
18
36
  * @description Get window selection obejct
19
- * @returns {Object}
37
+ * @returns {Selection}
20
38
  */
21
39
  get() {
22
- const selection = this._shadowRoot?.getSelection() || this.editor.frameContext.get('_ww').getSelection();
40
+ const wSelection = this.editor.frameContext.get('_ww').getSelection();
41
+ let selection = null;
42
+
43
+ if (this._shadowRoot) {
44
+ selection = wSelection.getComposedRanges?.();
45
+ }
46
+
47
+ if (!selection) {
48
+ selection = wSelection;
49
+ }
50
+
23
51
  if (!selection) return null;
24
52
  if (!this.status._range && !this.editor.frameContext.get('wysiwyg').contains(selection.focusNode)) {
25
53
  selection.removeAllRanges();
@@ -29,8 +57,20 @@ Selection.prototype = {
29
57
  },
30
58
 
31
59
  /**
60
+ * @this {SelectionThis}
61
+ * @description Check if the range object is valid
62
+ * @param {*} range Range object
63
+ * @returns {boolean}
64
+ */
65
+ isRange(range) {
66
+ // return /Range/.test(Object.prototype.toString.call(range?.__proto__));
67
+ return range instanceof Range;
68
+ },
69
+
70
+ /**
71
+ * @this {SelectionThis}
32
72
  * @description Get current editor's range object
33
- * @returns {Object}
73
+ * @returns {Range}
34
74
  */
35
75
  getRange() {
36
76
  const range = this.status._range || this._createDefaultRange();
@@ -54,38 +94,61 @@ Selection.prototype = {
54
94
  ec = selection.focusNode,
55
95
  so = selection.anchorOffset,
56
96
  eo = selection.focusOffset;
57
- const compareValue = domUtils.compareElements(sc, ec);
97
+ const compareValue = dom.query.compareElements(sc, ec);
58
98
  const rightDir = compareValue.ancestor && (compareValue.result === 0 ? so <= eo : compareValue.result > 1 ? true : false);
59
99
  return this.setRange(rightDir ? sc : ec, rightDir ? so : eo, rightDir ? ec : sc, rightDir ? eo : so);
60
100
  }
61
101
  },
62
102
 
63
103
  /**
104
+ * @this {SelectionThis}
64
105
  * @description Set current editor's range object and return.
65
- * @param {Node} startCon The startContainer property of the selection object.
66
- * @param {number} startOff The startOffset property of the selection object.
67
- * @param {Node} endCon The endContainer property of the selection object.
68
- * @param {number} endOff The endOffset property of the selection object.
69
- * @returns {Object} Range object.
106
+ * @param {Node|Range} startCon Range object or The startContainer property of the selection object
107
+ * @param {number} [startOff] The startOffset property of the selection object.
108
+ * @param {Node} [endCon] The endContainer property of the selection object.
109
+ * @param {number} [endOff] The endOffset property of the selection object.
110
+ * @returns {Range}
70
111
  */
71
112
  setRange(startCon, startOff, endCon, endOff) {
72
- if (!startCon || !endCon) return;
73
- if (startOff > startCon.textContent.length) startOff = startCon.textContent.length;
74
- if (endOff > endCon.textContent.length) endOff = endCon.textContent.length;
75
- if (this.format.isLine(startCon)) {
76
- startCon = startCon.childNodes[startOff > 0 ? startCon.childNodes.length - 1 : 0] || startCon;
77
- startOff = startOff > 0 ? (startCon.nodeType === 1 && !domUtils.isBreak(startCon) ? 1 : startCon.textContent ? startCon.textContent.length : 0) : 0;
113
+ /** @type {Node} */
114
+ let sc;
115
+ /** @type {number} */
116
+ let so;
117
+ /** @type {Node} */
118
+ let ec;
119
+ /** @type {number} */
120
+ let eo;
121
+
122
+ if (this.isRange(startCon)) {
123
+ const r = /** @type {Range} */ (startCon);
124
+ sc = r.startContainer;
125
+ so = r.startOffset;
126
+ ec = r.endContainer;
127
+ eo = r.endOffset;
128
+ } else {
129
+ sc = /** @type {Node} */ (startCon);
130
+ so = startOff;
131
+ ec = endCon;
132
+ eo = endOff;
78
133
  }
79
- if (this.format.isLine(endCon)) {
80
- endCon = endCon.childNodes[endOff > 0 ? endCon.childNodes.length - 1 : 0] || endCon;
81
- endOff = endOff > 0 ? (endCon.nodeType === 1 && !domUtils.isBreak(endCon) ? 1 : endCon.textContent ? endCon.textContent.length : 0) : 0;
134
+
135
+ if (!sc || !ec) return;
136
+ if ((dom.check.isBreak(sc) || sc.nodeType === 3) && so > sc.textContent.length) so = sc.textContent.length;
137
+ if ((dom.check.isBreak(ec) || ec.nodeType === 3) && eo > ec.textContent.length) eo = ec.textContent.length;
138
+ if (this.format.isLine(sc)) {
139
+ sc = sc.childNodes[so > 0 ? sc.childNodes.length - 1 : 0] || sc;
140
+ so = so > 0 ? (sc.nodeType === 1 && !dom.check.isBreak(sc) ? 1 : sc.textContent ? sc.textContent.length : 0) : 0;
141
+ }
142
+ if (this.format.isLine(ec)) {
143
+ ec = ec.childNodes[eo > 0 ? ec.childNodes.length - 1 : 0] || ec;
144
+ eo = eo > 0 ? (ec.nodeType === 1 && !dom.check.isBreak(ec) ? 1 : ec.textContent ? ec.textContent.length : 0) : 0;
82
145
  }
83
146
 
84
147
  const range = this.editor.frameContext.get('_wd').createRange();
85
148
 
86
149
  try {
87
- range.setStart(startCon, startOff);
88
- range.setEnd(endCon, endOff);
150
+ range.setStart(sc, so);
151
+ range.setEnd(ec, eo);
89
152
  } catch (error) {
90
153
  console.warn('[SUNEDITOR.selection.focus.warn]', error.message);
91
154
  this.editor._nativeFocus();
@@ -108,27 +171,55 @@ Selection.prototype = {
108
171
  },
109
172
 
110
173
  /**
174
+ * @this {SelectionThis}
111
175
  * @description Remove range object and button effect
112
176
  */
113
177
  removeRange() {
114
178
  this.status._range = null;
115
179
  this.selectionNode = null;
180
+ this.editor.effectNode = null;
116
181
  if (this.status.hasFocus) this.get().removeAllRanges();
117
182
  this.eventManager._setKeyEffect([]);
118
183
  },
119
184
 
120
185
  /**
186
+ * @this {SelectionThis}
187
+ * @description Returns the range (container and offset) near the given target node.
188
+ * - If the target node has a next sibling, it returns the next sibling with an offset of 0.
189
+ * - If there is no next sibling but a previous sibling exists, it returns the previous sibling with an offset of 1.
190
+ * @param {Node} target Target node whose neighboring range is to be determined.
191
+ * @returns {{container: Node, offset: number}|null} An object containing the nearest container node and its offset.
192
+ */
193
+ getNearRange(target) {
194
+ const next = target.nextSibling;
195
+ const prev = target.previousSibling;
196
+ if (next) {
197
+ return {
198
+ container: next,
199
+ offset: 0
200
+ };
201
+ } else if (prev) {
202
+ return {
203
+ container: prev,
204
+ offset: 1
205
+ };
206
+ }
207
+
208
+ return null;
209
+ },
210
+
211
+ /**
212
+ * @this {SelectionThis}
121
213
  * @description If the "range" object is a non-editable area, add a line at the top of the editor and update the "range" object.
122
- * Returns a new "range" or argument "range".
123
- * @param {Object} range core.getRange()
124
- * @param {Element|null} container If there is "container" argument, it creates a line in front of the container.
125
- * @returns {Object} range
214
+ * @param {Range} range core.getRange()
215
+ * @param {?Node=} container If there is "container" argument, it creates a line in front of the container.
216
+ * @returns {Range} a new "range" or argument "range".
126
217
  */
127
218
  getRangeAndAddLine(range, container) {
128
219
  if (this._isNone(range)) {
129
220
  const parent = container?.parentElement || this.editor.frameContext.get('wysiwyg');
130
- const op = domUtils.createElement(this.options.get('defaultLine'), null, '<br>');
131
- parent.insertBefore(op, container && container !== parent ? (!container.previousElementSibling ? container : container.nextElementSibling) : parent.firstElementChild);
221
+ const op = dom.utils.createElement(this.options.get('defaultLine'), null, '<br>');
222
+ parent.insertBefore(op, container && container !== parent ? (!(/** @type {HTMLElement} */ (container).previousElementSibling) ? container : /** @type {HTMLElement} */ (container).nextElementSibling) : parent.firstElementChild);
132
223
  this.setRange(op.firstElementChild, 0, op.firstElementChild, 1);
133
224
  range = this.status._range;
134
225
  }
@@ -136,19 +227,14 @@ Selection.prototype = {
136
227
  },
137
228
 
138
229
  /**
230
+ * @this {SelectionThis}
139
231
  * @description Get current select node
140
- * @returns {Node}
232
+ * @returns {HTMLElement|Text}
141
233
  */
142
234
  getNode() {
143
235
  if (!this.editor.frameContext.get('wysiwyg').contains(this.selectionNode)) this._init();
144
236
  if (!this.selectionNode) {
145
- const selectionNode = domUtils.getEdgeChild(
146
- this.editor.frameContext.get('wysiwyg').firstChild,
147
- function (current) {
148
- return current.childNodes.length === 0 || current.nodeType === 3;
149
- },
150
- false
151
- );
237
+ const selectionNode = /** @type {HTMLElement|Text} */ (dom.query.getEdgeChild(this.editor.frameContext.get('wysiwyg').firstChild, (current) => current.childNodes.length === 0 || current.nodeType === 3, false));
152
238
  if (!selectionNode) {
153
239
  this._init();
154
240
  } else {
@@ -160,27 +246,28 @@ Selection.prototype = {
160
246
  },
161
247
 
162
248
  /**
163
- * @description Get hte clientRects object.
164
- * @param {Range|Element|null} target Range object | Element | null
249
+ * @this {SelectionThis}
250
+ * @description Get the Rects object.
251
+ * @param {?Range|Node} target Range | Node | null
165
252
  * @param {"start"|"end"} position It is based on the position of the rect object to be returned in case of range selection.
166
- * @returns
253
+ * @returns {{rects: RectsInfo_selection, position: "start"|"end", scrollLeft: number, scrollTop: number}}
167
254
  */
168
255
  getRects(target, position) {
169
- const targetAbs = target?.nodeType === 1 ? this._w.getComputedStyle(target).position === 'absolute' : false;
170
- target = !target || target.nodeType === 3 ? this.getRange() : target;
256
+ const targetAbs = dom.check.isElement(/** @type {Node} */ (target)) ? this._w.getComputedStyle(target).position === 'absolute' : false;
257
+ target = /** @type {Range} */ (!target || dom.check.isText(/** @type {Node} */ (target)) ? this.getRange() : target);
171
258
  const globalScroll = this.offset.getGlobalScroll();
172
259
  let isStartPosition = position === 'start';
173
260
  let scrollLeft = globalScroll.left;
174
261
  let scrollTop = globalScroll.top;
175
262
 
176
- let rects = target.getClientRects();
263
+ let rects = /** @type {*} */ (target).getClientRects();
177
264
  rects = rects[isStartPosition ? 0 : rects.length - 1];
178
265
 
179
266
  if (!rects) {
180
267
  const node = this.getNode();
181
268
  if (this.format.isLine(node)) {
182
- const zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
183
- this.html.insertNode(zeroWidth, null, true);
269
+ const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
270
+ this.html.insertNode(zeroWidth, { afterNode: null, skipCharCount: true });
184
271
  this.setRange(zeroWidth, 1, zeroWidth, 1);
185
272
  this._init();
186
273
  rects = this.getRange().getClientRects();
@@ -192,8 +279,8 @@ Selection.prototype = {
192
279
  rects = {
193
280
  left: nodeOffset.left,
194
281
  top: nodeOffset.top,
195
- right: nodeOffset.right,
196
- bottom: nodeOffset.top + node.offsetHeight,
282
+ right: nodeOffset.left + /** @type {HTMLElement} */ (node).offsetWidth,
283
+ bottom: nodeOffset.top + /** @type {HTMLElement} */ (node).offsetHeight,
197
284
  noText: true
198
285
  };
199
286
  scrollLeft = 0;
@@ -222,26 +309,31 @@ Selection.prototype = {
222
309
  },
223
310
 
224
311
  /**
312
+ * @this {SelectionThis}
225
313
  * @description Get the custom range object of the event.
226
- * @returns {Event} e Event object
227
- * @returns {Object} {sc: startContainer, so: startOffset, ec: endContainer, eo: endOffset}
314
+ * @param {DragEvent} e Event object
315
+ * @returns {{sc: Node, so: number, ec: Node, eo: number}} {sc: startContainer, so: startOffset, ec: endContainer, eo: endOffset}
228
316
  */
229
- getEventLocationRange(e) {
230
- let sc, so, ec, eo;
231
- if (e.rangeParent) {
232
- sc = e.rangeParent;
233
- so = e.rangeOffset;
234
- ec = e.rangeParent;
235
- eo = e.rangeOffset;
236
- } else if (this.editor.frameContext.get('_wd').caretRangeFromPoint) {
237
- let r = this.editor.frameContext.get('_wd').caretRangeFromPoint(e.clientX, e.clientY);
238
- if (!r) r = this.getRange();
317
+ getDragEventLocationRange(e) {
318
+ const wd = this.editor.frameContext.get('_wd');
319
+ let r, sc, so, ec, eo;
320
+
321
+ if (wd.caretPositionFromPoint) {
322
+ r = wd.caretPositionFromPoint(e.clientX, e.clientY);
323
+ sc = r.offsetNode;
324
+ so = r.offset;
325
+ ec = r.offsetNode;
326
+ eo = r.offset;
327
+ } else if (wd.caretRangeFromPoint) {
328
+ r = wd.caretRangeFromPoint(e.clientX, e.clientY);
239
329
  sc = r.startContainer;
240
330
  so = r.startOffset;
241
331
  ec = r.endContainer;
242
332
  eo = r.endOffset;
243
- } else {
244
- const r = this.getRange();
333
+ }
334
+
335
+ if (!r) {
336
+ r = this.getRange();
245
337
  sc = r.startContainer;
246
338
  so = r.startOffset;
247
339
  ec = r.endContainer;
@@ -257,10 +349,12 @@ Selection.prototype = {
257
349
  },
258
350
 
259
351
  /**
352
+ * @this {SelectionThis}
260
353
  * @description Scroll to the corresponding selection or range position.
261
354
  * @param {Selection|Range|Node} ref selection or range object
355
+ * @param {?Object<string, *>=} scrollOption option of scrollTo
262
356
  */
263
- scrollTo(ref) {
357
+ scrollTo(ref, scrollOption) {
264
358
  if (ref instanceof Selection) {
265
359
  ref = ref.getRangeAt(0);
266
360
  } else if (ref instanceof Node) {
@@ -274,18 +368,21 @@ Selection.prototype = {
274
368
 
275
369
  if (isVisible) return;
276
370
 
277
- ref.startContainer?.scrollIntoView?.(this.options.get('scrollToOptions'));
371
+ const el = dom.query.getParentElement(ref.startContainer, (current) => current.nodeType === 1);
372
+ el?.scrollIntoView?.(scrollOption || this.options.get('scrollToOptions'));
278
373
  },
279
374
 
280
375
  /**
376
+ * @private
377
+ * @this {SelectionThis}
281
378
  * @description Returns true if there is no valid selection.
282
- * @param {Object} range selection.getRange()
379
+ * @param {Range} range selection.getRange()
283
380
  * @returns {boolean}
284
381
  */
285
382
  _isNone(range) {
286
- const comm = range.commonAncestorContainer;
383
+ const comm = /** @type {HTMLElement} */ (range.commonAncestorContainer);
287
384
  return (
288
- (domUtils.isWysiwygFrame(range.startContainer) && domUtils.isWysiwygFrame(range.endContainer)) ||
385
+ (dom.check.isWysiwygFrame(range.startContainer) && dom.check.isWysiwygFrame(range.endContainer)) ||
289
386
  /FIGURE/i.test(comm.nodeName) ||
290
387
  (this.editor._fileManager.regExp.test(comm.nodeName) && (!this.editor._fileManager.tagAttrs[comm.nodeName] || this.editor._fileManager.tagAttrs[comm.nodeName]?.every((v) => comm.hasAttribute(v)))) ||
291
388
  this.component.is(comm)
@@ -293,9 +390,10 @@ Selection.prototype = {
293
390
  },
294
391
 
295
392
  /**
296
- * @description Return the range object of editor's first child node
297
- * @returns {Object}
298
393
  * @private
394
+ * @this {SelectionThis}
395
+ * @description Return the range object of editor's first child node
396
+ * @returns {Range}
299
397
  */
300
398
  _createDefaultRange() {
301
399
  const wysiwyg = this.editor.frameContext.get('wysiwyg');
@@ -304,13 +402,13 @@ Selection.prototype = {
304
402
  let firstFormat = wysiwyg.firstElementChild;
305
403
  let focusEl = null;
306
404
  if (!firstFormat) {
307
- focusEl = domUtils.createElement('BR');
308
- firstFormat = domUtils.createElement(this.options.get('defaultLine'), null, focusEl);
405
+ focusEl = dom.utils.createElement('BR');
406
+ firstFormat = dom.utils.createElement(this.options.get('defaultLine'), null, focusEl);
309
407
  wysiwyg.appendChild(firstFormat);
310
408
  } else {
311
409
  focusEl = firstFormat.firstChild;
312
410
  if (!focusEl) {
313
- focusEl = domUtils.createElement('BR');
411
+ focusEl = dom.utils.createElement('BR');
314
412
  firstFormat.appendChild(focusEl);
315
413
  }
316
414
  }
@@ -322,31 +420,34 @@ Selection.prototype = {
322
420
  },
323
421
 
324
422
  /**
423
+ * @private
424
+ * @this {SelectionThis}
325
425
  * @description Set "range" and "selection" info.
326
- * @param {Object} range range object.
327
- * @param {Object} selection selection object.
426
+ * @param {Range} range range object.
427
+ * @param {Selection} selection selection object.
328
428
  */
329
429
  _rangeInfo(range, selection) {
330
430
  let selectionNode = null;
331
431
  this.status._range = range;
332
432
 
333
433
  if (range.collapsed) {
334
- if (domUtils.isWysiwygFrame(range.commonAncestorContainer)) selectionNode = range.commonAncestorContainer.children[range.startOffset] || range.commonAncestorContainer;
434
+ if (dom.check.isWysiwygFrame(range.commonAncestorContainer)) selectionNode = range.commonAncestorContainer.children[range.startOffset] || range.commonAncestorContainer;
335
435
  else selectionNode = range.commonAncestorContainer;
336
436
  } else {
337
- selectionNode = selection.extentNode || selection.anchorNode;
437
+ selectionNode = selection.anchorNode;
338
438
  }
339
439
 
340
- this.selectionNode = selectionNode;
440
+ this.selectionNode = /** @type {HTMLElement|Text} */ (selectionNode);
341
441
  },
342
442
 
343
443
  /**
344
- * @description Saving the range object and the currently selected node of editor
345
444
  * @private
445
+ * @this {SelectionThis}
446
+ * @description Saving the range object and the currently selected node of editor
346
447
  */
347
448
  _init() {
348
449
  const activeEl = this.editor.frameContext.get('_wd').activeElement;
349
- if (domUtils.isInputElement(activeEl)) {
450
+ if (dom.check.isInputElement(activeEl)) {
350
451
  this.selectionNode = activeEl;
351
452
  return activeEl;
352
453
  }
@@ -366,34 +467,42 @@ Selection.prototype = {
366
467
  },
367
468
 
368
469
  /**
369
- * @description Focus method
370
470
  * @private
471
+ * @this {SelectionThis}
472
+ * @description Focus method
371
473
  */
372
474
  __focus() {
373
- const caption = domUtils.getParentElement(this.getNode(), 'figcaption');
374
- if (caption) {
375
- caption.focus();
376
- } else {
377
- this.editor.frameContext.get('wysiwyg').focus();
475
+ try {
476
+ this.__iframeFocus = true;
477
+ const caption = dom.query.getParentElement(this.getNode(), 'figcaption');
478
+ if (caption) {
479
+ caption.focus();
480
+ } else {
481
+ this.editor.frameContext.get('wysiwyg').focus();
482
+ }
483
+ } finally {
484
+ env._w.setTimeout(() => (this.__iframeFocus = false), 0);
378
485
  }
379
486
  },
380
487
 
381
488
  /**
489
+ * @private
490
+ * @this {SelectionThis}
382
491
  * @description Reset range object to text node selected status.
383
492
  * @returns {boolean} Returns false if there is no valid selection.
384
- * @private
385
493
  */
386
494
  _resetRangeToTextNode() {
387
495
  let rangeObj = this.getRange();
388
496
  if (this._isNone(rangeObj)) {
389
- if (!domUtils.isWysiwygFrame(rangeObj.startContainer) || !domUtils.isWysiwygFrame(rangeObj.endContainer)) return false;
390
- const ww = rangeObj.commonAncestorContainer;
497
+ if (!dom.check.isWysiwygFrame(rangeObj.startContainer) || !dom.check.isWysiwygFrame(rangeObj.endContainer)) return false;
498
+ const ww = /** @type {HTMLElement} */ (rangeObj.commonAncestorContainer);
391
499
  const first = ww.children[rangeObj.startOffset];
392
500
  const end = ww.children[rangeObj.endOffset];
393
501
  if (!(rangeObj = this.setRange(first, 0, end, first === end ? 0 : 1))) return false;
394
502
  }
395
503
 
396
504
  const range = rangeObj;
505
+ const collapsed = range.collapsed;
397
506
  let startCon = range.startContainer;
398
507
  let startOff = range.startOffset;
399
508
  let endCon = range.endContainer;
@@ -418,18 +527,19 @@ Selection.prototype = {
418
527
  while (endCon?.nodeType === 1 && endCon.lastChild) {
419
528
  endCon = endCon.lastChild;
420
529
  }
421
- endOff = endCon.textContent.length;
530
+ if (collapsed) endOff = 0;
531
+ else if (endOff > 0) endOff = endCon.textContent.length;
422
532
  }
423
533
 
424
534
  // startContainer
425
- tempCon = domUtils.isWysiwygFrame(startCon) ? this.editor.frameContext.get('wysiwyg').firstChild : startCon;
535
+ tempCon = dom.check.isWysiwygFrame(startCon) ? this.editor.frameContext.get('wysiwyg').firstChild : startCon;
426
536
  tempOffset = startOff;
427
537
 
428
- if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
429
- const onlyBreak = domUtils.isBreak(tempCon);
538
+ if (dom.check.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
539
+ const onlyBreak = dom.check.isBreak(tempCon);
430
540
  if (!onlyBreak) {
431
541
  const tempConCache = tempCon;
432
- while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
542
+ while (tempCon && !dom.check.isBreak(tempCon) && tempCon.nodeType === 1) {
433
543
  tempChild = tempCon.childNodes;
434
544
  if (tempChild.length === 0) break;
435
545
  tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
@@ -439,14 +549,14 @@ Selection.prototype = {
439
549
  let format = this.format.getLine(tempCon, null);
440
550
  if (format === this.format.getBlock(format, null)) {
441
551
  tempCon = tempCon || tempConCache;
442
- format = domUtils.createElement(domUtils.getParentElement(tempCon, domUtils.isTableCell) ? 'DIV' : this.options.get('defaultLine'));
552
+ format = dom.utils.createElement(dom.query.getParentElement(tempCon, dom.check.isTableCell) ? 'DIV' : this.options.get('defaultLine'));
443
553
  tempCon.parentNode.insertBefore(format, tempCon);
444
554
  if (tempCon !== tempConCache) format.appendChild(tempCon);
445
555
  }
446
556
  }
447
557
 
448
- if (domUtils.isBreak(tempCon) || this.component.is(tempCon)) {
449
- const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
558
+ if (dom.check.isBreak(tempCon) || this.component.is(tempCon)) {
559
+ const emptyText = dom.utils.createTextNode(unicode.zeroWidthSpace);
450
560
  tempCon.parentNode.insertBefore(emptyText, tempCon);
451
561
  tempCon = emptyText;
452
562
  if (onlyBreak) {
@@ -463,13 +573,13 @@ Selection.prototype = {
463
573
  startOff = tempOffset;
464
574
 
465
575
  // endContainer
466
- tempCon = domUtils.isWysiwygFrame(endCon) ? this.editor.frameContext.get('wysiwyg').lastChild : endCon;
576
+ tempCon = dom.check.isWysiwygFrame(endCon) ? this.editor.frameContext.get('wysiwyg').lastChild : endCon;
467
577
  tempOffset = endOff;
468
578
 
469
- if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
470
- const onlyBreak = domUtils.isBreak(tempCon);
579
+ if (dom.check.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
580
+ const onlyBreak = dom.check.isBreak(tempCon);
471
581
  if (!onlyBreak) {
472
- while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
582
+ while (tempCon && !dom.check.isBreak(tempCon) && tempCon.nodeType === 1) {
473
583
  tempChild = tempCon.childNodes;
474
584
  if (tempChild.length === 0) break;
475
585
  tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
@@ -478,19 +588,19 @@ Selection.prototype = {
478
588
 
479
589
  let format = this.format.getLine(tempCon, null);
480
590
  if (format === this.format.getBlock(format, null)) {
481
- format = domUtils.createElement(domUtils.isTableCell(format) ? 'DIV' : this.options.get('defaultLine'));
591
+ format = dom.utils.createElement(dom.check.isTableCell(format) ? 'DIV' : this.options.get('defaultLine'));
482
592
  tempCon.parentNode.insertBefore(format, tempCon);
483
593
  format.appendChild(tempCon);
484
594
  }
485
595
  }
486
596
 
487
- if (domUtils.isBreak(tempCon)) {
488
- const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
597
+ if (dom.check.isBreak(tempCon)) {
598
+ const emptyText = dom.utils.createTextNode(unicode.zeroWidthSpace);
489
599
  tempCon.parentNode.insertBefore(emptyText, tempCon);
490
600
  tempCon = emptyText;
491
601
  tempOffset = 1;
492
602
  if (onlyBreak && !tempCon.previousSibling) {
493
- domUtils.removeItem(endCon);
603
+ dom.utils.removeItem(endCon);
494
604
  }
495
605
  }
496
606
  }
@@ -504,7 +614,7 @@ Selection.prototype = {
504
614
  return true;
505
615
  },
506
616
 
507
- constructor: Selection
617
+ constructor: Selection_
508
618
  };
509
619
 
510
- export default Selection;
620
+ export default Selection_;