suneditor 2.46.2 → 3.0.0-alpha.1

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 (290) 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 +174 -805
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +96 -69
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-content.css +646 -0
  11. package/src/assets/suneditor.css +3378 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  17. package/src/core/base/eventManager.js +1115 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +146 -0
  21. package/src/core/class/component.js +627 -0
  22. package/src/core/class/format.js +3255 -0
  23. package/src/core/class/html.js +1621 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +379 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +578 -0
  28. package/src/core/class/selection.js +508 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1593 -0
  33. package/src/core/section/actives.js +107 -0
  34. package/src/core/section/constructor.js +1237 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +313 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +199 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +162 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +315 -0
  72. package/src/modules/Figure.js +1160 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +290 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +73 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +73 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +172 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +510 -0
  104. package/src/plugins/modal/image.js +1062 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +347 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /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;