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
@@ -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
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, 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.selection.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.selection.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,14 +349,16 @@ 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) {
267
- ref = this.selection.setRange(ref, 1, ref, 1);
361
+ ref = this.setRange(ref, 1, ref, 1);
268
362
  } else if (typeof ref?.startContainer === 'undefined') {
269
363
  console.warn('[SUNEDITOR.html.scrollTo.warn] "selectionRange" must be Selection or Range or Node object.', ref);
270
364
  }
@@ -274,18 +368,21 @@ Selection.prototype = {
274
368
 
275
369
  if (isVisible) return;
276
370
 
277
- ref.startContainer?.scrollIntoView?.({ behavior: 'auto', block: 'nearest' });
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,32 +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.startContainer;
391
- rangeObj = this.setRange(ww.firstElementChild, 0, ww.lastElementChild, 1);
497
+ if (!dom.check.isWysiwygFrame(rangeObj.startContainer) || !dom.check.isWysiwygFrame(rangeObj.endContainer)) return false;
498
+ const ww = /** @type {HTMLElement} */ (rangeObj.commonAncestorContainer);
499
+ const first = ww.children[rangeObj.startOffset];
500
+ const end = ww.children[rangeObj.endOffset];
501
+ if (!(rangeObj = this.setRange(first, 0, end, first === end ? 0 : 1))) return false;
392
502
  }
393
503
 
394
504
  const range = rangeObj;
505
+ const collapsed = range.collapsed;
395
506
  let startCon = range.startContainer;
396
507
  let startOff = range.startOffset;
397
508
  let endCon = range.endContainer;
@@ -416,18 +527,19 @@ Selection.prototype = {
416
527
  while (endCon?.nodeType === 1 && endCon.lastChild) {
417
528
  endCon = endCon.lastChild;
418
529
  }
419
- endOff = endCon.textContent.length;
530
+ if (collapsed) endOff = 0;
531
+ else if (endOff > 0) endOff = endCon.textContent.length;
420
532
  }
421
533
 
422
534
  // startContainer
423
- tempCon = domUtils.isWysiwygFrame(startCon) ? this.editor.frameContext.get('wysiwyg').firstChild : startCon;
535
+ tempCon = dom.check.isWysiwygFrame(startCon) ? this.editor.frameContext.get('wysiwyg').firstChild : startCon;
424
536
  tempOffset = startOff;
425
537
 
426
- if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
427
- 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);
428
540
  if (!onlyBreak) {
429
541
  const tempConCache = tempCon;
430
- while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
542
+ while (tempCon && !dom.check.isBreak(tempCon) && tempCon.nodeType === 1) {
431
543
  tempChild = tempCon.childNodes;
432
544
  if (tempChild.length === 0) break;
433
545
  tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
@@ -437,14 +549,14 @@ Selection.prototype = {
437
549
  let format = this.format.getLine(tempCon, null);
438
550
  if (format === this.format.getBlock(format, null)) {
439
551
  tempCon = tempCon || tempConCache;
440
- 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'));
441
553
  tempCon.parentNode.insertBefore(format, tempCon);
442
554
  if (tempCon !== tempConCache) format.appendChild(tempCon);
443
555
  }
444
556
  }
445
557
 
446
- if (domUtils.isBreak(tempCon) || this.component.is(tempCon)) {
447
- const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
558
+ if (dom.check.isBreak(tempCon) || this.component.is(tempCon)) {
559
+ const emptyText = dom.utils.createTextNode(unicode.zeroWidthSpace);
448
560
  tempCon.parentNode.insertBefore(emptyText, tempCon);
449
561
  tempCon = emptyText;
450
562
  if (onlyBreak) {
@@ -461,13 +573,13 @@ Selection.prototype = {
461
573
  startOff = tempOffset;
462
574
 
463
575
  // endContainer
464
- tempCon = domUtils.isWysiwygFrame(endCon) ? this.editor.frameContext.get('wysiwyg').lastChild : endCon;
576
+ tempCon = dom.check.isWysiwygFrame(endCon) ? this.editor.frameContext.get('wysiwyg').lastChild : endCon;
465
577
  tempOffset = endOff;
466
578
 
467
- if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
468
- 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);
469
581
  if (!onlyBreak) {
470
- while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
582
+ while (tempCon && !dom.check.isBreak(tempCon) && tempCon.nodeType === 1) {
471
583
  tempChild = tempCon.childNodes;
472
584
  if (tempChild.length === 0) break;
473
585
  tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
@@ -476,19 +588,19 @@ Selection.prototype = {
476
588
 
477
589
  let format = this.format.getLine(tempCon, null);
478
590
  if (format === this.format.getBlock(format, null)) {
479
- 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'));
480
592
  tempCon.parentNode.insertBefore(format, tempCon);
481
593
  format.appendChild(tempCon);
482
594
  }
483
595
  }
484
596
 
485
- if (domUtils.isBreak(tempCon)) {
486
- const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
597
+ if (dom.check.isBreak(tempCon)) {
598
+ const emptyText = dom.utils.createTextNode(unicode.zeroWidthSpace);
487
599
  tempCon.parentNode.insertBefore(emptyText, tempCon);
488
600
  tempCon = emptyText;
489
601
  tempOffset = 1;
490
602
  if (onlyBreak && !tempCon.previousSibling) {
491
- domUtils.removeItem(endCon);
603
+ dom.utils.removeItem(endCon);
492
604
  }
493
605
  }
494
606
  }
@@ -502,7 +614,7 @@ Selection.prototype = {
502
614
  return true;
503
615
  },
504
616
 
505
- constructor: Selection
617
+ constructor: Selection_
506
618
  };
507
619
 
508
- export default Selection;
620
+ export default Selection_;