suneditor 2.46.2 → 3.0.0-alpha.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 (289) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +11 -1560
  6. package/package.json +94 -70
  7. package/src/assets/icons/_default.js +194 -0
  8. package/src/assets/suneditor-content.css +642 -0
  9. package/src/assets/suneditor.css +3378 -0
  10. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  11. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  12. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  13. package/src/core/base/eventHandlers/handler_ww_key_input.js +978 -0
  14. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  15. package/src/core/base/eventManager.js +1129 -0
  16. package/src/core/base/events.js +320 -0
  17. package/src/core/base/history.js +301 -0
  18. package/src/core/class/char.js +146 -0
  19. package/src/core/class/component.js +624 -0
  20. package/src/core/class/format.js +3255 -0
  21. package/src/core/class/html.js +1621 -0
  22. package/src/core/class/menu.js +260 -0
  23. package/src/core/class/nodeTransform.js +379 -0
  24. package/src/core/class/notice.js +42 -0
  25. package/src/core/class/offset.js +578 -0
  26. package/src/core/class/selection.js +508 -0
  27. package/src/core/class/shortcuts.js +38 -0
  28. package/src/core/class/toolbar.js +440 -0
  29. package/src/core/class/viewer.js +646 -0
  30. package/src/core/editor.js +1588 -0
  31. package/src/core/section/actives.js +107 -0
  32. package/src/core/section/constructor.js +1237 -0
  33. package/src/core/section/context.js +97 -0
  34. package/src/editorInjector/_classes.js +22 -0
  35. package/src/editorInjector/_core.js +28 -0
  36. package/src/editorInjector/index.js +13 -0
  37. package/src/helper/converter.js +313 -0
  38. package/src/helper/domUtils.js +1177 -0
  39. package/src/helper/env.js +250 -0
  40. package/src/helper/index.js +19 -0
  41. package/src/helper/numbers.js +68 -0
  42. package/src/helper/unicode.js +43 -0
  43. package/src/langs/ckb.js +161 -0
  44. package/src/langs/cs.js +161 -0
  45. package/src/langs/da.js +161 -0
  46. package/src/langs/de.js +162 -0
  47. package/src/langs/en.js +199 -0
  48. package/src/langs/es.js +162 -0
  49. package/src/langs/fa.js +159 -0
  50. package/src/langs/fr.js +161 -0
  51. package/src/langs/he.js +162 -0
  52. package/src/{lang → langs}/index.js +0 -2
  53. package/src/langs/it.js +162 -0
  54. package/src/langs/ja.js +162 -0
  55. package/src/langs/ko.js +162 -0
  56. package/src/langs/lv.js +162 -0
  57. package/src/langs/nl.js +162 -0
  58. package/src/langs/pl.js +162 -0
  59. package/src/langs/pt_br.js +162 -0
  60. package/src/langs/ro.js +162 -0
  61. package/src/langs/ru.js +162 -0
  62. package/src/langs/se.js +162 -0
  63. package/src/langs/tr.js +159 -0
  64. package/src/langs/ua.js +162 -0
  65. package/src/langs/ur.js +162 -0
  66. package/src/langs/zh_cn.js +162 -0
  67. package/src/modules/ApiManager.js +168 -0
  68. package/src/modules/ColorPicker.js +302 -0
  69. package/src/modules/Controller.js +315 -0
  70. package/src/modules/Figure.js +1174 -0
  71. package/src/modules/FileBrowser.js +271 -0
  72. package/src/modules/FileManager.js +290 -0
  73. package/src/modules/HueSlider.js +513 -0
  74. package/src/modules/Modal.js +177 -0
  75. package/src/modules/ModalAnchorEditor.js +494 -0
  76. package/src/modules/SelectMenu.js +447 -0
  77. package/src/modules/_DragHandle.js +16 -0
  78. package/src/modules/index.js +14 -0
  79. package/src/plugins/command/blockquote.js +47 -47
  80. package/src/plugins/command/exportPdf.js +168 -0
  81. package/src/plugins/command/fileUpload.js +389 -0
  82. package/src/plugins/command/list_bulleted.js +112 -0
  83. package/src/plugins/command/list_numbered.js +115 -0
  84. package/src/plugins/dropdown/align.js +143 -0
  85. package/src/plugins/dropdown/backgroundColor.js +73 -0
  86. package/src/plugins/dropdown/font.js +113 -0
  87. package/src/plugins/dropdown/fontColor.js +73 -0
  88. package/src/plugins/dropdown/formatBlock.js +141 -0
  89. package/src/plugins/dropdown/hr.js +111 -0
  90. package/src/plugins/dropdown/layout.js +72 -0
  91. package/src/plugins/dropdown/lineHeight.js +114 -0
  92. package/src/plugins/dropdown/list.js +107 -0
  93. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  94. package/src/plugins/dropdown/table.js +2810 -0
  95. package/src/plugins/dropdown/template.js +71 -0
  96. package/src/plugins/dropdown/textStyle.js +137 -0
  97. package/src/plugins/field/mention.js +172 -0
  98. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  99. package/src/plugins/index.js +86 -24
  100. package/src/plugins/input/fontSize.js +357 -0
  101. package/src/plugins/modal/audio.js +492 -0
  102. package/src/plugins/modal/image.js +1062 -0
  103. package/src/plugins/modal/link.js +211 -0
  104. package/src/plugins/modal/math.js +347 -0
  105. package/src/plugins/modal/video.js +870 -0
  106. package/src/suneditor.js +62 -67
  107. package/src/themes/test.css +61 -0
  108. package/typings/CommandPlugin.d.ts +8 -0
  109. package/typings/DialogPlugin.d.ts +20 -0
  110. package/typings/FileBrowserPlugin.d.ts +30 -0
  111. package/typings/Lang.d.ts +124 -0
  112. package/typings/Module.d.ts +15 -0
  113. package/typings/Plugin.d.ts +42 -0
  114. package/typings/SubmenuPlugin.d.ts +8 -0
  115. package/typings/_classes.d.ts +17 -0
  116. package/typings/_colorPicker.d.ts +60 -0
  117. package/typings/_core.d.ts +55 -0
  118. package/typings/align.d.ts +5 -0
  119. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  120. package/typings/backgroundColor.d.ts +5 -0
  121. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  122. package/typings/char.d.ts +39 -0
  123. package/typings/component.d.ts +38 -0
  124. package/typings/context.d.ts +39 -0
  125. package/typings/converter.d.ts +33 -0
  126. package/typings/dialog.d.ts +28 -0
  127. package/typings/domUtils.d.ts +361 -0
  128. package/typings/editor.d.ts +7 -0
  129. package/typings/editor.ts +542 -0
  130. package/typings/env.d.ts +70 -0
  131. package/typings/eventManager.d.ts +37 -0
  132. package/typings/events.d.ts +262 -0
  133. package/typings/fileBrowser.d.ts +42 -0
  134. package/typings/fileManager.d.ts +67 -0
  135. package/typings/font.d.ts +5 -0
  136. package/typings/fontColor.d.ts +5 -0
  137. package/typings/fontSize.d.ts +5 -0
  138. package/typings/format.d.ts +191 -0
  139. package/typings/formatBlock.d.ts +5 -0
  140. package/typings/history.d.ts +48 -0
  141. package/typings/horizontalRule.d.ts +5 -0
  142. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  143. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  144. package/typings/index.d.ts +21 -0
  145. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  146. package/typings/index.plugins.d.ts +58 -0
  147. package/typings/lineHeight.d.ts +5 -0
  148. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  149. package/typings/list.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  151. package/typings/mediaContainer.d.ts +25 -0
  152. package/typings/node.d.ts +57 -0
  153. package/typings/notice.d.ts +16 -0
  154. package/typings/numbers.d.ts +29 -0
  155. package/typings/offset.d.ts +24 -0
  156. package/typings/options.d.ts +589 -0
  157. package/typings/paragraphStyle.d.ts +5 -0
  158. package/typings/resizing.d.ts +141 -0
  159. package/typings/selection.d.ts +94 -0
  160. package/typings/shortcuts.d.ts +13 -0
  161. package/typings/suneditor.d.ts +9 -0
  162. package/typings/table.d.ts +5 -0
  163. package/typings/template.d.ts +5 -0
  164. package/typings/textStyle.d.ts +5 -0
  165. package/typings/toolbar.d.ts +32 -0
  166. package/typings/unicode.d.ts +25 -0
  167. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  168. package/dist/css/suneditor.min.css +0 -1
  169. package/dist/suneditor.min.js +0 -2
  170. package/src/assets/css/suneditor-contents.css +0 -562
  171. package/src/assets/css/suneditor.css +0 -566
  172. package/src/assets/defaultIcons.js +0 -103
  173. package/src/lang/Lang.d.ts +0 -144
  174. package/src/lang/ckb.d.ts +0 -5
  175. package/src/lang/ckb.js +0 -188
  176. package/src/lang/cs.d.ts +0 -5
  177. package/src/lang/cs.js +0 -188
  178. package/src/lang/da.d.ts +0 -5
  179. package/src/lang/da.js +0 -191
  180. package/src/lang/de.d.ts +0 -5
  181. package/src/lang/de.js +0 -188
  182. package/src/lang/en.d.ts +0 -5
  183. package/src/lang/en.js +0 -188
  184. package/src/lang/es.d.ts +0 -5
  185. package/src/lang/es.js +0 -188
  186. package/src/lang/fa.d.ts +0 -5
  187. package/src/lang/fa.js +0 -188
  188. package/src/lang/fr.d.ts +0 -5
  189. package/src/lang/fr.js +0 -188
  190. package/src/lang/he.d.ts +0 -5
  191. package/src/lang/he.js +0 -188
  192. package/src/lang/index.d.ts +0 -23
  193. package/src/lang/it.d.ts +0 -5
  194. package/src/lang/it.js +0 -188
  195. package/src/lang/ja.d.ts +0 -5
  196. package/src/lang/ja.js +0 -188
  197. package/src/lang/ko.d.ts +0 -5
  198. package/src/lang/ko.js +0 -188
  199. package/src/lang/lv.d.ts +0 -5
  200. package/src/lang/lv.js +0 -188
  201. package/src/lang/nl.d.ts +0 -5
  202. package/src/lang/nl.js +0 -188
  203. package/src/lang/pl.d.ts +0 -5
  204. package/src/lang/pl.js +0 -188
  205. package/src/lang/pt_br.d.ts +0 -5
  206. package/src/lang/pt_br.js +0 -189
  207. package/src/lang/ro.d.ts +0 -5
  208. package/src/lang/ro.js +0 -188
  209. package/src/lang/ru.d.ts +0 -5
  210. package/src/lang/ru.js +0 -188
  211. package/src/lang/se.d.ts +0 -5
  212. package/src/lang/se.js +0 -191
  213. package/src/lang/tr.d.ts +0 -5
  214. package/src/lang/tr.js +0 -191
  215. package/src/lang/ua.d.ts +0 -5
  216. package/src/lang/ua.js +0 -188
  217. package/src/lang/ur.d.ts +0 -5
  218. package/src/lang/ur.js +0 -188
  219. package/src/lang/zh_cn.d.ts +0 -5
  220. package/src/lang/zh_cn.js +0 -187
  221. package/src/lib/constructor.js +0 -954
  222. package/src/lib/context.d.ts +0 -42
  223. package/src/lib/context.js +0 -71
  224. package/src/lib/core.d.ts +0 -1135
  225. package/src/lib/core.js +0 -9395
  226. package/src/lib/history.d.ts +0 -48
  227. package/src/lib/history.js +0 -219
  228. package/src/lib/util.d.ts +0 -678
  229. package/src/lib/util.js +0 -2131
  230. package/src/options.d.ts +0 -608
  231. package/src/plugins/CommandPlugin.d.ts +0 -8
  232. package/src/plugins/DialogPlugin.d.ts +0 -20
  233. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  234. package/src/plugins/Module.d.ts +0 -15
  235. package/src/plugins/Plugin.d.ts +0 -42
  236. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  237. package/src/plugins/dialog/audio.js +0 -559
  238. package/src/plugins/dialog/image.js +0 -1126
  239. package/src/plugins/dialog/link.js +0 -223
  240. package/src/plugins/dialog/math.js +0 -295
  241. package/src/plugins/dialog/mention.js +0 -242
  242. package/src/plugins/dialog/video.js +0 -979
  243. package/src/plugins/index.d.ts +0 -79
  244. package/src/plugins/modules/_anchor.js +0 -461
  245. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  246. package/src/plugins/modules/_colorPicker.js +0 -201
  247. package/src/plugins/modules/_notice.d.ts +0 -21
  248. package/src/plugins/modules/_notice.js +0 -72
  249. package/src/plugins/modules/_selectMenu.js +0 -119
  250. package/src/plugins/modules/component.d.ts +0 -25
  251. package/src/plugins/modules/component.js +0 -81
  252. package/src/plugins/modules/dialog.d.ts +0 -28
  253. package/src/plugins/modules/dialog.js +0 -175
  254. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  255. package/src/plugins/modules/fileBrowser.js +0 -374
  256. package/src/plugins/modules/fileManager.d.ts +0 -67
  257. package/src/plugins/modules/fileManager.js +0 -326
  258. package/src/plugins/modules/index.js +0 -9
  259. package/src/plugins/modules/resizing.d.ts +0 -154
  260. package/src/plugins/modules/resizing.js +0 -903
  261. package/src/plugins/submenu/align.d.ts +0 -5
  262. package/src/plugins/submenu/align.js +0 -160
  263. package/src/plugins/submenu/font.d.ts +0 -5
  264. package/src/plugins/submenu/font.js +0 -123
  265. package/src/plugins/submenu/fontColor.d.ts +0 -5
  266. package/src/plugins/submenu/fontColor.js +0 -101
  267. package/src/plugins/submenu/fontSize.d.ts +0 -5
  268. package/src/plugins/submenu/fontSize.js +0 -112
  269. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  270. package/src/plugins/submenu/formatBlock.js +0 -273
  271. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  272. package/src/plugins/submenu/hiliteColor.js +0 -102
  273. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  274. package/src/plugins/submenu/horizontalRule.js +0 -98
  275. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  276. package/src/plugins/submenu/lineHeight.js +0 -104
  277. package/src/plugins/submenu/list.d.ts +0 -5
  278. package/src/plugins/submenu/list.js +0 -456
  279. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  280. package/src/plugins/submenu/paragraphStyle.js +0 -135
  281. package/src/plugins/submenu/table.d.ts +0 -5
  282. package/src/plugins/submenu/table.js +0 -1431
  283. package/src/plugins/submenu/template.d.ts +0 -5
  284. package/src/plugins/submenu/template.js +0 -72
  285. package/src/plugins/submenu/textStyle.d.ts +0 -5
  286. package/src/plugins/submenu/textStyle.js +0 -167
  287. package/src/suneditor.d.ts +0 -9
  288. package/src/suneditor_build.js +0 -18
  289. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,508 @@
1
+ /**
2
+ * @fileoverview Selection class
3
+ */
4
+
5
+ import CoreInjector from '../../editorInjector/_core';
6
+ import { domUtils, unicode } from '../../helper';
7
+
8
+ const Selection = function (editor) {
9
+ CoreInjector.call(this, editor);
10
+
11
+ // members
12
+ this.range = null;
13
+ this.selectionNode = null;
14
+ };
15
+
16
+ Selection.prototype = {
17
+ /**
18
+ * @description Get window selection obejct
19
+ * @returns {Object}
20
+ */
21
+ get() {
22
+ const selection = this._shadowRoot?.getSelection() || this.editor.frameContext.get('_ww').getSelection();
23
+ if (!selection) return null;
24
+ if (!this.status._range && !this.editor.frameContext.get('wysiwyg').contains(selection.focusNode)) {
25
+ selection.removeAllRanges();
26
+ selection.addRange(this._createDefaultRange());
27
+ }
28
+ return selection;
29
+ },
30
+
31
+ /**
32
+ * @description Get current editor's range object
33
+ * @returns {Object}
34
+ */
35
+ getRange() {
36
+ const range = this.status._range || this._createDefaultRange();
37
+ const selection = this.get();
38
+ if (range.collapsed === selection.isCollapsed || !this.editor.frameContext.get('wysiwyg').contains(selection.focusNode)) {
39
+ if (this.component.is(range.startContainer)) {
40
+ const compInfo = this.component.get(range.startContainer);
41
+ const container = compInfo?.container;
42
+ if (!container) return range;
43
+ return this.setRange(container, 0, container, 1);
44
+ }
45
+
46
+ return range;
47
+ }
48
+
49
+ if (selection.rangeCount > 0) {
50
+ this.status._range = selection.getRangeAt(0);
51
+ return this.status._range;
52
+ } else {
53
+ const sc = selection.anchorNode,
54
+ ec = selection.focusNode,
55
+ so = selection.anchorOffset,
56
+ eo = selection.focusOffset;
57
+ const compareValue = domUtils.compareElements(sc, ec);
58
+ const rightDir = compareValue.ancestor && (compareValue.result === 0 ? so <= eo : compareValue.result > 1 ? true : false);
59
+ return this.setRange(rightDir ? sc : ec, rightDir ? so : eo, rightDir ? ec : sc, rightDir ? eo : so);
60
+ }
61
+ },
62
+
63
+ /**
64
+ * @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.
70
+ */
71
+ 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;
78
+ }
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;
82
+ }
83
+
84
+ const range = this.editor.frameContext.get('_wd').createRange();
85
+
86
+ try {
87
+ range.setStart(startCon, startOff);
88
+ range.setEnd(endCon, endOff);
89
+ } catch (error) {
90
+ console.warn('[SUNEDITOR.selection.focus.warn]', error.message);
91
+ this.editor._nativeFocus();
92
+ return;
93
+ }
94
+
95
+ const selection = this.get();
96
+
97
+ if (selection.removeAllRanges) {
98
+ selection.removeAllRanges();
99
+ }
100
+
101
+ selection.addRange(range);
102
+ this.status._range = range;
103
+ this._rangeInfo(range, this.get());
104
+
105
+ if (this.editor.frameOptions.get('iframe')) this.__focus();
106
+
107
+ return range;
108
+ },
109
+
110
+ /**
111
+ * @description Remove range object and button effect
112
+ */
113
+ removeRange() {
114
+ this.status._range = null;
115
+ this.selectionNode = null;
116
+ if (this.status.hasFocus) this.get().removeAllRanges();
117
+ this.eventManager._setKeyEffect([]);
118
+ },
119
+
120
+ /**
121
+ * @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
126
+ */
127
+ getRangeAndAddLine(range, container) {
128
+ if (this._isNone(range)) {
129
+ 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);
132
+ this.setRange(op.firstElementChild, 0, op.firstElementChild, 1);
133
+ range = this.status._range;
134
+ }
135
+ return range;
136
+ },
137
+
138
+ /**
139
+ * @description Get current select node
140
+ * @returns {Node}
141
+ */
142
+ getNode() {
143
+ if (!this.editor.frameContext.get('wysiwyg').contains(this.selectionNode)) this._init();
144
+ 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
+ );
152
+ if (!selectionNode) {
153
+ this._init();
154
+ } else {
155
+ this.selectionNode = selectionNode;
156
+ return selectionNode;
157
+ }
158
+ }
159
+ return this.selectionNode;
160
+ },
161
+
162
+ /**
163
+ * @description Get hte clientRects object.
164
+ * @param {Range|Element|null} target Range object | Element | null
165
+ * @param {"start"|"end"} position It is based on the position of the rect object to be returned in case of range selection.
166
+ * @returns
167
+ */
168
+ 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;
171
+ const globalScroll = this.offset.getGlobalScroll();
172
+ let isStartPosition = position === 'start';
173
+ let scrollLeft = globalScroll.left;
174
+ let scrollTop = globalScroll.top;
175
+
176
+ let rects = target.getClientRects();
177
+ rects = rects[isStartPosition ? 0 : rects.length - 1];
178
+
179
+ if (!rects) {
180
+ const node = this.getNode();
181
+ if (this.format.isLine(node)) {
182
+ const zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
183
+ this.html.insertNode(zeroWidth, null, true);
184
+ this.setRange(zeroWidth, 1, zeroWidth, 1);
185
+ this._init();
186
+ rects = this.getRange().getClientRects();
187
+ rects = rects[isStartPosition ? 0 : rects.length - 1];
188
+ }
189
+
190
+ if (!rects) {
191
+ const nodeOffset = this.offset.get(node);
192
+ rects = {
193
+ left: nodeOffset.left,
194
+ top: nodeOffset.top,
195
+ right: nodeOffset.right,
196
+ bottom: nodeOffset.top + node.offsetHeight,
197
+ noText: true
198
+ };
199
+ scrollLeft = 0;
200
+ scrollTop = 0;
201
+ }
202
+
203
+ isStartPosition = true;
204
+ }
205
+
206
+ const iframeRects = /^iframe$/i.test(this.editor.frameContext.get('wysiwygFrame').nodeName) ? this.editor.frameContext.get('wysiwygFrame').getClientRects()[0] : null;
207
+ if (!targetAbs && iframeRects) {
208
+ rects = {
209
+ left: rects.left + iframeRects.left,
210
+ top: rects.top + iframeRects.top,
211
+ right: rects.right + iframeRects.right - iframeRects.width,
212
+ bottom: rects.bottom + iframeRects.bottom - iframeRects.height
213
+ };
214
+ }
215
+
216
+ return {
217
+ rects: rects,
218
+ position: isStartPosition ? 'start' : 'end',
219
+ scrollLeft: scrollLeft,
220
+ scrollTop: scrollTop
221
+ };
222
+ },
223
+
224
+ /**
225
+ * @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}
228
+ */
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();
239
+ sc = r.startContainer;
240
+ so = r.startOffset;
241
+ ec = r.endContainer;
242
+ eo = r.endOffset;
243
+ } else {
244
+ const r = this.selection.getRange();
245
+ sc = r.startContainer;
246
+ so = r.startOffset;
247
+ ec = r.endContainer;
248
+ eo = r.endOffset;
249
+ }
250
+
251
+ return {
252
+ sc,
253
+ so,
254
+ ec,
255
+ eo
256
+ };
257
+ },
258
+
259
+ /**
260
+ * @description Scroll to the corresponding selection or range position.
261
+ * @param {Selection|Range|Node} ref selection or range object
262
+ */
263
+ scrollTo(ref) {
264
+ if (ref instanceof Selection) {
265
+ ref = ref.getRangeAt(0);
266
+ } else if (ref instanceof Node) {
267
+ ref = this.selection.setRange(ref, 1, ref, 1);
268
+ } else if (typeof ref?.startContainer === 'undefined') {
269
+ console.warn('[SUNEDITOR.html.scrollTo.warn] "selectionRange" must be Selection or Range or Node object.', ref);
270
+ }
271
+
272
+ const rect = ref.getBoundingClientRect();
273
+ const isVisible = rect.top >= 0 && rect.bottom <= this.editor.frameContext.get('wysiwygFrame').innerHeight;
274
+
275
+ if (isVisible) return;
276
+
277
+ ref.startContainer?.scrollIntoView?.({ behavior: 'auto', block: 'nearest' });
278
+ },
279
+
280
+ /**
281
+ * @description Returns true if there is no valid selection.
282
+ * @param {Object} range selection.getRange()
283
+ * @returns {boolean}
284
+ */
285
+ _isNone(range) {
286
+ const comm = range.commonAncestorContainer;
287
+ return (
288
+ (domUtils.isWysiwygFrame(range.startContainer) && domUtils.isWysiwygFrame(range.endContainer)) ||
289
+ /FIGURE/i.test(comm.nodeName) ||
290
+ (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
+ this.component.is(comm)
292
+ );
293
+ },
294
+
295
+ /**
296
+ * @description Return the range object of editor's first child node
297
+ * @returns {Object}
298
+ * @private
299
+ */
300
+ _createDefaultRange() {
301
+ const wysiwyg = this.editor.frameContext.get('wysiwyg');
302
+ const range = this.editor.frameContext.get('_wd').createRange();
303
+
304
+ let firstFormat = wysiwyg.firstElementChild;
305
+ let focusEl = null;
306
+ if (!firstFormat) {
307
+ focusEl = domUtils.createElement('BR');
308
+ firstFormat = domUtils.createElement(this.options.get('defaultLine'), null, focusEl);
309
+ wysiwyg.appendChild(firstFormat);
310
+ } else {
311
+ focusEl = firstFormat.firstChild;
312
+ if (!focusEl) {
313
+ focusEl = domUtils.createElement('BR');
314
+ firstFormat.appendChild(focusEl);
315
+ }
316
+ }
317
+
318
+ range.setStart(focusEl, 0);
319
+ range.setEnd(focusEl, 0);
320
+
321
+ return range;
322
+ },
323
+
324
+ /**
325
+ * @description Set "range" and "selection" info.
326
+ * @param {Object} range range object.
327
+ * @param {Object} selection selection object.
328
+ */
329
+ _rangeInfo(range, selection) {
330
+ let selectionNode = null;
331
+ this.status._range = range;
332
+
333
+ if (range.collapsed) {
334
+ if (domUtils.isWysiwygFrame(range.commonAncestorContainer)) selectionNode = range.commonAncestorContainer.children[range.startOffset] || range.commonAncestorContainer;
335
+ else selectionNode = range.commonAncestorContainer;
336
+ } else {
337
+ selectionNode = selection.extentNode || selection.anchorNode;
338
+ }
339
+
340
+ this.selectionNode = selectionNode;
341
+ },
342
+
343
+ /**
344
+ * @description Saving the range object and the currently selected node of editor
345
+ * @private
346
+ */
347
+ _init() {
348
+ const activeEl = this.editor.frameContext.get('_wd').activeElement;
349
+ if (domUtils.isInputElement(activeEl)) {
350
+ this.selectionNode = activeEl;
351
+ return activeEl;
352
+ }
353
+
354
+ const selection = this.get();
355
+
356
+ if (!selection) return null;
357
+ let range = null;
358
+
359
+ if (selection.rangeCount > 0) {
360
+ range = selection.getRangeAt(0);
361
+ } else {
362
+ range = this._createDefaultRange();
363
+ }
364
+
365
+ this._rangeInfo(range, selection);
366
+ },
367
+
368
+ /**
369
+ * @description Focus method
370
+ * @private
371
+ */
372
+ __focus() {
373
+ const caption = domUtils.getParentElement(this.getNode(), 'figcaption');
374
+ if (caption) {
375
+ caption.focus();
376
+ } else {
377
+ this.editor.frameContext.get('wysiwyg').focus();
378
+ }
379
+ },
380
+
381
+ /**
382
+ * @description Reset range object to text node selected status.
383
+ * @returns {boolean} Returns false if there is no valid selection.
384
+ * @private
385
+ */
386
+ _resetRangeToTextNode() {
387
+ let rangeObj = this.getRange();
388
+ 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);
392
+ }
393
+
394
+ const range = rangeObj;
395
+ let startCon = range.startContainer;
396
+ let startOff = range.startOffset;
397
+ let endCon = range.endContainer;
398
+ let endOff = range.endOffset;
399
+ let tempCon, tempOffset, tempChild;
400
+
401
+ if (this.format.isLine(startCon)) {
402
+ if (!startCon.childNodes[startOff]) {
403
+ startCon = startCon.lastChild || startCon;
404
+ startOff = startCon.textContent.length;
405
+ } else {
406
+ startCon = startCon.childNodes[startOff] || startCon;
407
+ startOff = 0;
408
+ }
409
+ while (startCon?.nodeType === 1 && startCon.firstChild) {
410
+ startCon = startCon.firstChild || startCon;
411
+ startOff = 0;
412
+ }
413
+ }
414
+ if (this.format.isLine(endCon)) {
415
+ endCon = endCon.childNodes[endOff] || endCon.lastChild || endCon;
416
+ while (endCon?.nodeType === 1 && endCon.lastChild) {
417
+ endCon = endCon.lastChild;
418
+ }
419
+ endOff = endCon.textContent.length;
420
+ }
421
+
422
+ // startContainer
423
+ tempCon = domUtils.isWysiwygFrame(startCon) ? this.editor.frameContext.get('wysiwyg').firstChild : startCon;
424
+ tempOffset = startOff;
425
+
426
+ if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
427
+ const onlyBreak = domUtils.isBreak(tempCon);
428
+ if (!onlyBreak) {
429
+ const tempConCache = tempCon;
430
+ while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
431
+ tempChild = tempCon.childNodes;
432
+ if (tempChild.length === 0) break;
433
+ tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
434
+ tempOffset = tempOffset > 0 ? tempCon.textContent.length : tempOffset;
435
+ }
436
+
437
+ let format = this.format.getLine(tempCon, null);
438
+ if (format === this.format.getBlock(format, null)) {
439
+ tempCon = tempCon || tempConCache;
440
+ format = domUtils.createElement(domUtils.getParentElement(tempCon, domUtils.isTableCell) ? 'DIV' : this.options.get('defaultLine'));
441
+ tempCon.parentNode.insertBefore(format, tempCon);
442
+ if (tempCon !== tempConCache) format.appendChild(tempCon);
443
+ }
444
+ }
445
+
446
+ if (domUtils.isBreak(tempCon) || this.component.is(tempCon)) {
447
+ const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
448
+ tempCon.parentNode.insertBefore(emptyText, tempCon);
449
+ tempCon = emptyText;
450
+ if (onlyBreak) {
451
+ if (startCon === endCon) {
452
+ endCon = tempCon;
453
+ endOff = 1;
454
+ }
455
+ }
456
+ }
457
+ }
458
+
459
+ // set startContainer
460
+ startCon = tempCon;
461
+ startOff = tempOffset;
462
+
463
+ // endContainer
464
+ tempCon = domUtils.isWysiwygFrame(endCon) ? this.editor.frameContext.get('wysiwyg').lastChild : endCon;
465
+ tempOffset = endOff;
466
+
467
+ if (domUtils.isBreak(tempCon) || (tempCon.nodeType === 1 && tempCon.childNodes.length > 0)) {
468
+ const onlyBreak = domUtils.isBreak(tempCon);
469
+ if (!onlyBreak) {
470
+ while (tempCon && !domUtils.isBreak(tempCon) && tempCon.nodeType === 1) {
471
+ tempChild = tempCon.childNodes;
472
+ if (tempChild.length === 0) break;
473
+ tempCon = tempChild[tempOffset > 0 ? tempOffset - 1 : tempOffset] || !/FIGURE/i.test(tempChild[0].nodeName) ? tempChild[0] : tempCon.previousElementSibling || tempCon.previousSibling || startCon;
474
+ tempOffset = tempOffset > 0 ? tempCon.textContent.length : tempOffset;
475
+ }
476
+
477
+ let format = this.format.getLine(tempCon, null);
478
+ if (format === this.format.getBlock(format, null)) {
479
+ format = domUtils.createElement(domUtils.isTableCell(format) ? 'DIV' : this.options.get('defaultLine'));
480
+ tempCon.parentNode.insertBefore(format, tempCon);
481
+ format.appendChild(tempCon);
482
+ }
483
+ }
484
+
485
+ if (domUtils.isBreak(tempCon)) {
486
+ const emptyText = domUtils.createTextNode(unicode.zeroWidthSpace);
487
+ tempCon.parentNode.insertBefore(emptyText, tempCon);
488
+ tempCon = emptyText;
489
+ tempOffset = 1;
490
+ if (onlyBreak && !tempCon.previousSibling) {
491
+ domUtils.removeItem(endCon);
492
+ }
493
+ }
494
+ }
495
+
496
+ // set endContainer
497
+ endCon = tempCon;
498
+ endOff = tempOffset;
499
+
500
+ // set Range
501
+ this.setRange(startCon, startOff, endCon, endOff);
502
+ return true;
503
+ },
504
+
505
+ constructor: Selection
506
+ };
507
+
508
+ export default Selection;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview Shortcuts class
3
+ */
4
+
5
+ const Shortcuts = function (editor) {
6
+ this.editor = editor;
7
+ this.isDisabled = false;
8
+ };
9
+
10
+ Shortcuts.prototype = {
11
+ /**
12
+ * @description If there is a shortcut function, run it.
13
+ * @param {number} keyCode event.keyCode
14
+ * @param {boolean} shift Whether to press shift key
15
+ * @returns {boolean} Whether to execute shortcuts
16
+ */
17
+ command(keyCode, shift) {
18
+ if (this.isDisabled) return false;
19
+
20
+ const info = this.editor.shortcutsKeyMap.get(keyCode + (shift ? 1000 : 0));
21
+ if (!info || (!shift && info.s)) return false;
22
+
23
+ this.editor.run(info.c, info.t, info.e);
24
+ return true;
25
+ },
26
+
27
+ disable() {
28
+ this.isDisabled = true;
29
+ },
30
+
31
+ enable() {
32
+ this.isDisabled = false;
33
+ },
34
+
35
+ constructor: Shortcuts
36
+ };
37
+
38
+ export default Shortcuts;