suneditor 3.0.0-beta.3 → 3.0.0-beta.30

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 (241) hide show
  1. package/CONTRIBUTING.md +8 -8
  2. package/README.md +44 -49
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +95 -53
  6. package/src/assets/design/color.css +2 -2
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +16 -1
  9. package/src/assets/suneditor-contents.css +9 -8
  10. package/src/assets/suneditor.css +29 -26
  11. package/src/core/{section → base}/actives.js +20 -12
  12. package/src/core/base/history.js +4 -4
  13. package/src/core/class/char.js +10 -10
  14. package/src/core/class/component.js +146 -57
  15. package/src/core/class/format.js +94 -2458
  16. package/src/core/class/html.js +187 -129
  17. package/src/core/class/inline.js +1853 -0
  18. package/src/core/class/listFormat.js +582 -0
  19. package/src/core/class/menu.js +14 -3
  20. package/src/core/class/nodeTransform.js +9 -14
  21. package/src/core/class/offset.js +162 -197
  22. package/src/core/class/selection.js +137 -34
  23. package/src/core/class/toolbar.js +73 -52
  24. package/src/core/class/ui.js +11 -11
  25. package/src/core/class/viewer.js +56 -55
  26. package/src/core/config/context.js +122 -0
  27. package/src/core/config/frameContext.js +204 -0
  28. package/src/core/config/options.js +639 -0
  29. package/src/core/editor.js +181 -108
  30. package/src/core/event/actions/index.js +229 -0
  31. package/src/core/event/effects/common.registry.js +60 -0
  32. package/src/core/event/effects/keydown.registry.js +551 -0
  33. package/src/core/event/effects/ruleHelpers.js +145 -0
  34. package/src/core/{base → event}/eventManager.js +119 -201
  35. package/src/core/event/executor.js +21 -0
  36. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +4 -4
  37. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +2 -2
  38. package/src/core/event/handlers/handler_ww_input.js +77 -0
  39. package/src/core/event/handlers/handler_ww_key.js +228 -0
  40. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
  41. package/src/core/event/ports.js +211 -0
  42. package/src/core/event/reducers/keydown.reducer.js +89 -0
  43. package/src/core/event/rules/keydown.rule.arrow.js +54 -0
  44. package/src/core/event/rules/keydown.rule.backspace.js +202 -0
  45. package/src/core/event/rules/keydown.rule.delete.js +126 -0
  46. package/src/core/event/rules/keydown.rule.enter.js +144 -0
  47. package/src/core/event/rules/keydown.rule.tab.js +29 -0
  48. package/src/core/section/constructor.js +79 -388
  49. package/src/core/section/documentType.js +47 -26
  50. package/src/core/util/instanceCheck.js +59 -0
  51. package/src/editorInjector/_classes.js +4 -0
  52. package/src/editorInjector/_core.js +17 -7
  53. package/src/editorInjector/index.js +10 -2
  54. package/src/events.js +6 -0
  55. package/src/helper/clipboard.js +24 -10
  56. package/src/helper/converter.js +17 -12
  57. package/src/helper/dom/domCheck.js +22 -3
  58. package/src/helper/dom/domQuery.js +91 -45
  59. package/src/helper/dom/domUtils.js +93 -19
  60. package/src/helper/dom/index.js +4 -0
  61. package/src/helper/env.js +11 -7
  62. package/src/helper/keyCodeMap.js +4 -3
  63. package/src/langs/ckb.js +1 -1
  64. package/src/langs/cs.js +1 -1
  65. package/src/langs/da.js +1 -1
  66. package/src/langs/de.js +1 -1
  67. package/src/langs/en.js +1 -1
  68. package/src/langs/es.js +1 -1
  69. package/src/langs/fa.js +1 -1
  70. package/src/langs/fr.js +1 -1
  71. package/src/langs/he.js +1 -1
  72. package/src/langs/hu.js +1 -1
  73. package/src/langs/it.js +1 -1
  74. package/src/langs/ja.js +1 -1
  75. package/src/langs/km.js +1 -1
  76. package/src/langs/ko.js +1 -1
  77. package/src/langs/lv.js +1 -1
  78. package/src/langs/nl.js +1 -1
  79. package/src/langs/pl.js +1 -1
  80. package/src/langs/pt_br.js +10 -10
  81. package/src/langs/ro.js +1 -1
  82. package/src/langs/ru.js +1 -1
  83. package/src/langs/se.js +1 -1
  84. package/src/langs/tr.js +1 -1
  85. package/src/langs/uk.js +1 -1
  86. package/src/langs/ur.js +1 -1
  87. package/src/langs/zh_cn.js +1 -1
  88. package/src/modules/ApiManager.js +25 -18
  89. package/src/modules/Browser.js +52 -61
  90. package/src/modules/ColorPicker.js +37 -38
  91. package/src/modules/Controller.js +85 -79
  92. package/src/modules/Figure.js +275 -187
  93. package/src/modules/FileManager.js +86 -92
  94. package/src/modules/HueSlider.js +67 -35
  95. package/src/modules/Modal.js +84 -77
  96. package/src/modules/ModalAnchorEditor.js +62 -79
  97. package/src/modules/SelectMenu.js +89 -86
  98. package/src/plugins/browser/audioGallery.js +9 -5
  99. package/src/plugins/browser/fileBrowser.js +10 -6
  100. package/src/plugins/browser/fileGallery.js +9 -5
  101. package/src/plugins/browser/imageGallery.js +9 -5
  102. package/src/plugins/browser/videoGallery.js +11 -6
  103. package/src/plugins/command/blockquote.js +1 -0
  104. package/src/plugins/command/exportPDF.js +11 -8
  105. package/src/plugins/command/fileUpload.js +41 -29
  106. package/src/plugins/command/list_bulleted.js +2 -1
  107. package/src/plugins/command/list_numbered.js +2 -1
  108. package/src/plugins/dropdown/align.js +8 -2
  109. package/src/plugins/dropdown/backgroundColor.js +19 -11
  110. package/src/plugins/dropdown/font.js +15 -9
  111. package/src/plugins/dropdown/fontColor.js +19 -11
  112. package/src/plugins/dropdown/formatBlock.js +7 -2
  113. package/src/plugins/dropdown/hr.js +7 -3
  114. package/src/plugins/dropdown/layout.js +6 -2
  115. package/src/plugins/dropdown/lineHeight.js +8 -3
  116. package/src/plugins/dropdown/list.js +2 -1
  117. package/src/plugins/dropdown/paragraphStyle.js +15 -11
  118. package/src/plugins/dropdown/{table.js → table/index.js} +514 -362
  119. package/src/plugins/dropdown/template.js +6 -2
  120. package/src/plugins/dropdown/textStyle.js +7 -3
  121. package/src/plugins/field/mention.js +33 -27
  122. package/src/plugins/input/fontSize.js +44 -37
  123. package/src/plugins/input/pageNavigator.js +3 -2
  124. package/src/plugins/modal/audio.js +90 -85
  125. package/src/plugins/modal/drawing.js +58 -66
  126. package/src/plugins/modal/embed.js +193 -180
  127. package/src/plugins/modal/image.js +441 -439
  128. package/src/plugins/modal/link.js +31 -8
  129. package/src/plugins/modal/math.js +23 -22
  130. package/src/plugins/modal/video.js +233 -230
  131. package/src/plugins/popup/anchor.js +24 -18
  132. package/src/suneditor.js +69 -24
  133. package/src/typedef.js +42 -19
  134. package/types/assets/icons/defaultIcons.d.ts +8 -0
  135. package/types/core/class/char.d.ts +1 -1
  136. package/types/core/class/component.d.ts +29 -7
  137. package/types/core/class/format.d.ts +4 -354
  138. package/types/core/class/html.d.ts +13 -4
  139. package/types/core/class/inline.d.ts +263 -0
  140. package/types/core/class/listFormat.d.ts +135 -0
  141. package/types/core/class/menu.d.ts +10 -2
  142. package/types/core/class/offset.d.ts +24 -26
  143. package/types/core/class/selection.d.ts +2 -0
  144. package/types/core/class/toolbar.d.ts +24 -11
  145. package/types/core/class/ui.d.ts +1 -1
  146. package/types/core/class/viewer.d.ts +1 -1
  147. package/types/core/config/context.d.ts +157 -0
  148. package/types/core/config/frameContext.d.ts +367 -0
  149. package/types/core/config/options.d.ts +1119 -0
  150. package/types/core/editor.d.ts +101 -66
  151. package/types/core/event/actions/index.d.ts +47 -0
  152. package/types/core/event/effects/common.registry.d.ts +50 -0
  153. package/types/core/event/effects/keydown.registry.d.ts +73 -0
  154. package/types/core/event/effects/ruleHelpers.d.ts +31 -0
  155. package/types/core/{base → event}/eventManager.d.ts +15 -46
  156. package/types/core/event/executor.d.ts +6 -0
  157. package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
  158. package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -6
  159. package/types/core/event/ports.d.ts +255 -0
  160. package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
  161. package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
  162. package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
  163. package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
  164. package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
  165. package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
  166. package/types/core/section/constructor.d.ts +101 -631
  167. package/types/core/section/documentType.d.ts +14 -4
  168. package/types/core/util/instanceCheck.d.ts +50 -0
  169. package/types/editorInjector/_classes.d.ts +4 -0
  170. package/types/editorInjector/_core.d.ts +17 -7
  171. package/types/editorInjector/index.d.ts +10 -2
  172. package/types/events.d.ts +1 -0
  173. package/types/helper/clipboard.d.ts +2 -2
  174. package/types/helper/converter.d.ts +6 -9
  175. package/types/helper/dom/domCheck.d.ts +7 -0
  176. package/types/helper/dom/domQuery.d.ts +19 -8
  177. package/types/helper/dom/domUtils.d.ts +24 -2
  178. package/types/helper/dom/index.d.ts +86 -1
  179. package/types/helper/env.d.ts +6 -1
  180. package/types/helper/index.d.ts +7 -1
  181. package/types/helper/keyCodeMap.d.ts +3 -3
  182. package/types/index.d.ts +23 -117
  183. package/types/langs/index.d.ts +2 -2
  184. package/types/modules/ApiManager.d.ts +1 -8
  185. package/types/modules/Browser.d.ts +4 -62
  186. package/types/modules/ColorPicker.d.ts +4 -21
  187. package/types/modules/Controller.d.ts +8 -64
  188. package/types/modules/Figure.d.ts +54 -50
  189. package/types/modules/FileManager.d.ts +1 -13
  190. package/types/modules/HueSlider.d.ts +13 -3
  191. package/types/modules/Modal.d.ts +0 -43
  192. package/types/modules/ModalAnchorEditor.d.ts +0 -73
  193. package/types/modules/SelectMenu.d.ts +0 -85
  194. package/types/modules/index.d.ts +3 -3
  195. package/types/plugins/browser/audioGallery.d.ts +29 -18
  196. package/types/plugins/browser/fileBrowser.d.ts +38 -27
  197. package/types/plugins/browser/fileGallery.d.ts +29 -18
  198. package/types/plugins/browser/imageGallery.d.ts +24 -16
  199. package/types/plugins/browser/videoGallery.d.ts +29 -18
  200. package/types/plugins/command/blockquote.d.ts +1 -0
  201. package/types/plugins/command/exportPDF.d.ts +18 -18
  202. package/types/plugins/command/fileUpload.d.ts +65 -45
  203. package/types/plugins/command/list_bulleted.d.ts +1 -0
  204. package/types/plugins/command/list_numbered.d.ts +1 -0
  205. package/types/plugins/dropdown/align.d.ts +13 -8
  206. package/types/plugins/dropdown/backgroundColor.d.ts +30 -19
  207. package/types/plugins/dropdown/font.d.ts +13 -12
  208. package/types/plugins/dropdown/fontColor.d.ts +30 -19
  209. package/types/plugins/dropdown/formatBlock.d.ts +13 -8
  210. package/types/plugins/dropdown/hr.d.ts +15 -11
  211. package/types/plugins/dropdown/layout.d.ts +15 -11
  212. package/types/plugins/dropdown/lineHeight.d.ts +16 -11
  213. package/types/plugins/dropdown/list.d.ts +1 -0
  214. package/types/plugins/dropdown/paragraphStyle.d.ts +31 -27
  215. package/types/plugins/dropdown/table/index.d.ts +582 -0
  216. package/types/plugins/dropdown/table.d.ts +41 -86
  217. package/types/plugins/dropdown/template.d.ts +15 -11
  218. package/types/plugins/dropdown/textStyle.d.ts +19 -11
  219. package/types/plugins/field/mention.d.ts +58 -56
  220. package/types/plugins/index.d.ts +38 -38
  221. package/types/plugins/input/fontSize.d.ts +46 -50
  222. package/types/plugins/modal/audio.d.ts +26 -56
  223. package/types/plugins/modal/drawing.d.ts +0 -85
  224. package/types/plugins/modal/embed.d.ts +15 -79
  225. package/types/plugins/modal/image.d.ts +24 -136
  226. package/types/plugins/modal/link.d.ts +34 -15
  227. package/types/plugins/modal/math.d.ts +0 -16
  228. package/types/plugins/modal/video.d.ts +17 -86
  229. package/types/plugins/popup/anchor.d.ts +1 -8
  230. package/types/suneditor.d.ts +70 -19
  231. package/types/typedef.d.ts +60 -46
  232. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  233. package/src/core/section/context.js +0 -102
  234. package/types/core/section/context.d.ts +0 -45
  235. package/types/langs/_Lang.d.ts +0 -194
  236. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
  237. /package/types/core/{section → base}/actives.d.ts +0 -0
  238. /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
  239. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
  240. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
  241. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.d.ts +0 -0
@@ -43,10 +43,10 @@ import { _w, _d } from '../../helper/env';
43
43
  * @typedef {Object} OffsetGlobalInfo
44
44
  * @property {number} top - The top position of the element relative to the entire document.
45
45
  * @property {number} left - The left position of the element relative to the entire document.
46
+ * @property {number} fixedTop - The top position within the current viewport, without taking scrolling into account.
47
+ * @property {number} fixedLeft - The left position within the current viewport, without taking scrolling into account.
46
48
  * @property {number} width - The total width of the element, including its content, padding, and border.
47
49
  * @property {number} height - The total height of the element, including its content, padding, and border.
48
- * @property {number} scrollTop - The amount of vertical scrolling applied to the element.
49
- * @property {number} scrollLeft - The amount of horizontal scrolling applied to the element.
50
50
  */
51
51
 
52
52
  /**
@@ -85,12 +85,6 @@ import { _w, _d } from '../../helper/env';
85
85
  */
86
86
  function Offset(editor) {
87
87
  CoreInjector.call(this, editor);
88
-
89
- // members
90
- this._scrollEvent = null;
91
- this._elTop = 0;
92
- this._scrollY = 0;
93
- this._isFixed = false;
94
88
  }
95
89
 
96
90
  Offset.prototype = {
@@ -101,7 +95,7 @@ Offset.prototype = {
101
95
  * @returns {OffsetInfo} Position relative to the editor frame.
102
96
  */
103
97
  get(node) {
104
- const wFrame = this.editor.frameContext.get('wysiwygFrame');
98
+ const wFrame = this.frameContext.get('wysiwygFrame');
105
99
  const iframe = /iframe/i.test(wFrame?.nodeName);
106
100
  const off = this.getLocal(node);
107
101
 
@@ -135,75 +129,70 @@ Offset.prototype = {
135
129
  offsetElement = /** @type {HTMLElement} */ (offsetElement.offsetParent);
136
130
  }
137
131
 
138
- const wwFrame = this.editor.frameContext.get('wysiwygFrame');
139
- if (this.editor.frameContext.get('wysiwyg').contains(target)) {
132
+ const wwFrame = this.frameContext.get('wysiwygFrame');
133
+ if (this.frameContext.get('wysiwyg').contains(target)) {
140
134
  l = wwFrame.offsetLeft;
141
135
  t = wwFrame.offsetTop;
142
136
  r = wwFrame.parentElement.offsetWidth - (wwFrame.offsetLeft + wwFrame.offsetWidth);
143
137
  }
144
138
 
145
- const eventWysiwyg = this.editor.frameContext.get('eventWysiwyg');
146
- offsetLeft += l;
139
+ const eventWysiwyg = this.frameContext.get('eventWysiwyg');
140
+ offsetLeft += l - (wysiwyg ? wysiwyg.scrollLeft : 0);
147
141
  offsetTop += t - (wysiwyg ? wysiwyg.scrollTop : 0);
148
142
  return {
149
143
  left: offsetLeft,
150
144
  top: offsetTop,
151
145
  right: offsetElement?.offsetWidth ? offsetElement.offsetWidth - (offsetLeft - l + targetWidth) + r : 0,
152
- scrollX: eventWysiwyg.scrollX || eventWysiwyg.scrollLeft || 0,
153
- scrollY: eventWysiwyg.scrollY || eventWysiwyg.scrollTop || 0
146
+ scrollX: eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0,
147
+ scrollY: eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0
154
148
  };
155
149
  },
156
150
 
157
151
  /**
158
152
  * @this {OffsetThis}
159
153
  * @description Returns the position of the argument relative to the global document.
154
+ * This is a refactored version using getBoundingClientRect for better performance and accuracy.
160
155
  * @param {?Node=} node Target element.
161
156
  * @returns {OffsetGlobalInfo} Global position and scroll values.
162
157
  */
163
158
  getGlobal(node) {
164
- const topArea = this.editor.frameContext.get('topArea');
165
- const wFrame = this.editor.frameContext.get('wysiwygFrame');
159
+ const topArea = this.frameContext.get('topArea');
160
+ const wFrame = this.frameContext.get('wysiwygFrame');
166
161
 
167
- let isTop = false;
168
- let targetAbs = false;
169
- if (!node) node = topArea;
170
- if (node === topArea) isTop = true;
171
- if (!isTop && isElement(node)) {
172
- targetAbs = _w.getComputedStyle(node).position === 'absolute';
162
+ node ||= topArea;
163
+
164
+ if (!isElement(node)) {
165
+ return { top: 0, left: 0, fixedTop: 0, fixedLeft: 0, width: 0, height: 0 };
173
166
  }
174
167
 
175
- let element = /** @type {HTMLElement} */ (node);
176
- const w = element.offsetWidth;
177
- const h = element.offsetHeight;
178
- let t = 0,
179
- l = 0,
180
- st = 0,
181
- sl = 0;
182
-
183
- while (element) {
184
- t += element.offsetTop;
185
- l += element.offsetLeft;
186
- st += element.scrollTop;
187
- sl += element.scrollLeft;
188
- element = /** @type {HTMLElement} */ (element.offsetParent);
168
+ const element = /** @type {HTMLElement} */ (node);
169
+
170
+ const rect = element.getBoundingClientRect();
171
+
172
+ let top = rect.top;
173
+ let left = rect.left;
174
+
175
+ const isIframe = /^iframe$/i.test(wFrame.nodeName);
176
+ if (isIframe && wFrame.contentDocument.contains(element)) {
177
+ const iframeRect = wFrame.getBoundingClientRect();
178
+ top += iframeRect.top;
179
+ left += iframeRect.left;
189
180
  }
190
181
 
191
- if (!targetAbs && !isTop && /^iframe$/i.test(wFrame.nodeName) && this.editor.frameContext.get('wysiwyg').contains(element)) {
192
- element = this.editor.frameContext.get('wrapper');
193
- while (element) {
194
- t += element.offsetTop;
195
- l += element.offsetLeft;
196
- element = /** @type {HTMLElement} */ (element.offsetParent);
197
- }
182
+ let wy = 0;
183
+ let wx = 0;
184
+ if (!this.frameContext.get('isFullScreen')) {
185
+ wy += _w.scrollY;
186
+ wx += _w.scrollX;
198
187
  }
199
188
 
200
189
  return {
201
- top: t + st,
202
- left: l + sl,
203
- width: w,
204
- height: h,
205
- scrollTop: st,
206
- scrollLeft: sl
190
+ top: top + wy,
191
+ left: left + wx,
192
+ fixedTop: top,
193
+ fixedLeft: left,
194
+ width: element.offsetWidth,
195
+ height: element.offsetHeight
207
196
  };
208
197
  },
209
198
 
@@ -214,10 +203,10 @@ Offset.prototype = {
214
203
  * @returns {OffsetGlobalScrollInfo} Global scroll information.
215
204
  */
216
205
  getGlobalScroll(node) {
217
- const topArea = this.editor.frameContext.get('topArea');
206
+ const topArea = this.frameContext.get('topArea');
218
207
  let isTop = false;
219
208
  let targetAbs = false;
220
- if (!node) node = topArea;
209
+ node ||= topArea;
221
210
  if (node === topArea) isTop = true;
222
211
  if (!isTop && isElement(node)) {
223
212
  targetAbs = _w.getComputedStyle(node).position === 'absolute';
@@ -262,8 +251,8 @@ Offset.prototype = {
262
251
  el = el.parentElement;
263
252
  }
264
253
 
265
- if (!targetAbs && !isTop && /^iframe$/i.test(this.editor.frameContext.get('wysiwygFrame').nodeName)) {
266
- el = this.editor.frameContext.get('wrapper');
254
+ if (!targetAbs && !isTop && /^iframe$/i.test(this.frameContext.get('wysiwygFrame').nodeName)) {
255
+ el = this.frameContext.get('wrapper');
267
256
  ohOffsetEl = owOffsetEl = topArea;
268
257
  while (el) {
269
258
  t += el.scrollTop;
@@ -288,7 +277,7 @@ Offset.prototype = {
288
277
  }
289
278
  }
290
279
 
291
- el = /** @type {HTMLElement} */ (this._shadowRoot?.host);
280
+ el = /** @type {HTMLElement} */ (this.editor._shadowRoot?.host);
292
281
  if (el) ohOffsetEl = owOffsetEl = topArea;
293
282
  while (el) {
294
283
  t += el.scrollTop;
@@ -322,7 +311,7 @@ Offset.prototype = {
322
311
  oh = heightEditorRefer ? topArea.clientHeight : oh;
323
312
  ow = widthEditorRefer ? topArea.clientWidth : ow;
324
313
 
325
- const clientSize = getClientSize(this.editor.frameContext.get('_wd'));
314
+ const clientSize = getClientSize(this.frameContext.get('_wd'));
326
315
  return {
327
316
  top: t,
328
317
  left: l,
@@ -347,15 +336,15 @@ Offset.prototype = {
347
336
  * @returns {OffsetWWScrollInfo} Scroll information within the editor.
348
337
  */
349
338
  getWWScroll() {
350
- const eventWysiwyg = this.editor.frameContext.get('wysiwyg');
339
+ const eventWysiwyg = this.frameContext.get('wysiwyg');
351
340
  const rects = this.selection.getRects(eventWysiwyg, 'start').rects;
352
- const top = eventWysiwyg.scrollY || eventWysiwyg.scrollTop || 0;
353
- const height = eventWysiwyg.scrollHeight || 0;
341
+ const top = eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0;
342
+ const height = eventWysiwyg.scrollHeight || eventWysiwyg.document?.documentElement.scrollHeight || 0;
354
343
 
355
344
  return {
356
345
  top,
357
- left: eventWysiwyg.scrollX || eventWysiwyg.scrollLeft || 0,
358
- width: eventWysiwyg.scrollWidth || 0,
346
+ left: eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0,
347
+ width: eventWysiwyg.scrollWidth || eventWysiwyg.document?.documentElement.scrollWidth || 0,
359
348
  height,
360
349
  bottom: top + height,
361
350
  rects
@@ -369,30 +358,50 @@ Offset.prototype = {
369
358
  * @param {HTMLElement} e_container Element's root container
370
359
  * @param {HTMLElement} target Target element to position against
371
360
  * @param {HTMLElement} t_container Target's root container
372
- * @param {boolean} _reload Whether to reload position
373
361
  */
374
- setRelPosition(element, e_container, target, t_container, _reload) {
375
- this._scrollY = _w.scrollY;
376
- let wy = 0;
377
- let tCon = t_container;
378
- do {
379
- if ((this._isFixed = /^fixed$/i.test(_w.getComputedStyle(tCon).position))) {
380
- wy += this._scrollY;
381
- break;
382
- }
383
- } while (!hasClass(tCon, 'sun-editor') && (tCon = tCon.parentElement));
362
+ setRelPosition(element, e_container, target, t_container) {
363
+ const isFixedContainer = /^fixed$/i.test(_w.getComputedStyle(t_container).position);
364
+ const tGlobal = this.getGlobal(target);
365
+
366
+ // top
367
+ if (isFixedContainer) {
368
+ element.style.position = 'fixed';
369
+ element.style.top = `${tGlobal.fixedTop + tGlobal.height}px`;
370
+ } else {
371
+ element.style.position = '';
372
+
373
+ const isSameContainer = t_container.contains(element);
374
+ const containerTop = isSameContainer ? this.getGlobal(e_container).top : 0;
375
+ const elHeight = element.offsetHeight;
376
+ const scrollTop = this.getGlobalScroll().top;
377
+ const bt = tGlobal.top;
378
+
379
+ const menuHeight_bottom = getClientSize(_d).h - (containerTop - scrollTop + bt + target.offsetHeight);
380
+ if (menuHeight_bottom < elHeight) {
381
+ let menuTop = -1 * (elHeight - bt + 3);
382
+ const insTop = containerTop - scrollTop + menuTop;
383
+ const menuHeight_top = elHeight + (insTop < 0 ? insTop : 0);
384
+
385
+ if (menuHeight_top > menuHeight_bottom) {
386
+ element.style.height = `${menuHeight_top}px`;
387
+ menuTop = -1 * (menuHeight_top - bt + 3);
388
+ } else {
389
+ element.style.height = `${menuHeight_bottom}px`;
390
+ menuTop = bt + target.offsetHeight;
391
+ }
384
392
 
385
- if (!_reload) {
386
- this.__removeGlobalEvent();
387
- this._scrollEvent = this.editor.eventManager.addGlobalEvent('scroll', FixedScroll.bind(this, element, e_container, target, t_container), false);
393
+ element.style.top = `${menuTop}px`;
394
+ } else {
395
+ element.style.top = `${bt + target.offsetHeight}px`;
396
+ }
388
397
  }
389
398
 
399
+ // left
390
400
  const ew = element.offsetWidth;
391
401
  const tw = target.offsetWidth;
392
- const tl = this.getGlobal(target).left;
402
+ const tl = tGlobal.left;
393
403
  const tcleft = this.getGlobal(t_container).left;
394
404
 
395
- // left
396
405
  if (this.options.get('_rtl')) {
397
406
  const rtlW = ew > tw ? ew - tw : 0;
398
407
  const rtlL = rtlW > 0 ? 0 : tw - ew;
@@ -406,41 +415,6 @@ Offset.prototype = {
406
415
  if (overLeft < 0) element.style.left = `${tl + overLeft + tcleft}px`;
407
416
  else element.style.left = `${tl}px`;
408
417
  }
409
-
410
- // top
411
- const isSameContainer = t_container.contains(element);
412
- const containerTop = isSameContainer ? this.getGlobal(e_container).top : 0;
413
- const elHeight = element.offsetHeight;
414
- const scrollTop = this.getGlobalScroll().top;
415
- let bt = wy;
416
- let offsetEl = target;
417
- while (offsetEl && offsetEl !== e_container) {
418
- bt += offsetEl.offsetTop;
419
- offsetEl = /** @type {HTMLElement} */ (offsetEl.offsetParent);
420
- }
421
-
422
- const menuHeight_bottom = getClientSize(_d).h - (containerTop - scrollTop + bt + target.offsetHeight);
423
- if (menuHeight_bottom < elHeight) {
424
- let menuTop = -1 * (elHeight - bt + 3);
425
- const insTop = containerTop - scrollTop + menuTop;
426
- const menuHeight_top = elHeight + (insTop < 0 ? insTop : 0);
427
-
428
- if (menuHeight_top > menuHeight_bottom) {
429
- element.style.height = `${menuHeight_top}px`;
430
- menuTop = -1 * (menuHeight_top - bt + 3);
431
- } else {
432
- element.style.height = `${menuHeight_bottom}px`;
433
- menuTop = bt + target.offsetHeight;
434
- }
435
-
436
- element.style.top = `${menuTop}px`;
437
- } else {
438
- element.style.top = `${bt + target.offsetHeight}px`;
439
- }
440
-
441
- if (this._isFixed) {
442
- this._elTop = element.offsetTop;
443
- }
444
418
  },
445
419
 
446
420
  /**
@@ -453,6 +427,7 @@ Offset.prototype = {
453
427
  * @param {{left:number, top:number}} [params.addOffset={left:0, top:0}] Additional offset
454
428
  * @param {"bottom"|"top"} [params.position="bottom"] Position ('bottom'|'top')
455
429
  * @param {*} params.inst Instance object of caller
430
+ * @param {HTMLElement} [params.sibling] The sibling controller element
456
431
  * @returns {{position: "top" | "bottom"} | undefined} Success -> {position: current position}
457
432
  */
458
433
  setAbsPosition(element, target, params) {
@@ -469,55 +444,76 @@ Offset.prototype = {
469
444
  addOffset.left *= -1;
470
445
  }
471
446
 
472
- const isWWTarget = this.editor.frameContext.get('wrapper').contains(target) || params.isWWTarget;
473
- const isCtrlTarget = getParentElement(target, '.se-controller');
447
+ const isIframe = this.frameOptions.get('iframe');
448
+ const isWWTarget = this.frameContext.get('wrapper').contains(target) || params.isWWTarget || (isIframe ? this.frameContext.get('wysiwyg').contains(target) : false);
449
+
450
+ const isCtrlTarget = target.nodeType === 1;
474
451
  const isTargetAbs = isWWTarget && !isCtrlTarget;
452
+ const isInlineTarget = isCtrlTarget && /inline/.test(_w.getComputedStyle(target).display);
475
453
  const clientSize = getClientSize(_d);
476
454
  const wwScroll = isTargetAbs ? this.getWWScroll() : this._getWindowScroll();
477
- const targetRect = isCtrlTarget ? target.getBoundingClientRect() : this.selection.getRects(target, 'start').rects;
455
+ const targetRect = !isIframe && isCtrlTarget ? target.getBoundingClientRect() : this.selection.getRects(target, 'start').rects;
478
456
  const targetOffset = this.getGlobal(target);
479
457
  const arrow = /** @type {HTMLElement} */ (hasClass(element.firstElementChild, 'se-arrow') ? element.firstElementChild : null);
480
458
 
481
459
  // top ----------------------------------------------------------------------------------------------------
460
+ const siblingH = params.sibling?.offsetHeight || 0;
482
461
  const ah = arrow ? arrow.offsetHeight : 0;
483
462
  const elH = element.offsetHeight;
484
463
  const targetH = target.offsetHeight;
485
464
  // margin
486
465
  const tmtw = targetRect.top;
487
466
  const tmbw = clientSize.h - targetRect.bottom;
488
- const toolbarH = !this.editor.toolbar._sticky && (this.editor.isBalloon || this.editor.isInline) ? 0 : this.context.get('toolbar.main').offsetHeight;
467
+ const globalTop = this.getGlobal(this.frameContext.get('topArea')).top;
468
+ const wScrollY = _w.scrollY;
469
+ const th = this.context.get('toolbar_main').offsetHeight;
470
+ const containerToolbar = this.options.get('toolbar_container');
471
+ const headLess = this.editor.isBalloon || this.editor.isInline || containerToolbar;
472
+ const toolbarH = (containerToolbar && globalTop - wScrollY - th > 0) || (!this.editor.toolbar._sticky && headLess) ? 0 : th;
489
473
 
490
474
  // check margin
491
- const { rmt, rmb, rt } = this._getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll);
492
- if (isWWTarget && (rmb + targetH <= 0 || rmt + rt + targetH <= 0)) return;
475
+ const { rmt, rmb, bMargin, rt } = this._getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll);
476
+ if (isWWTarget && ((rmb > 0 ? bMargin : rmb) + targetH <= 0 || rmt + rt + targetH - (this.editor.toolbar._sticky && isInlineTarget ? toolbarH : 0) <= 0)) return;
493
477
 
478
+ const isSticky = this.editor.toolbar._sticky && this.context.get('toolbar_main').style.display !== 'none' && (!headLess || this.frameContext.get('topArea').getBoundingClientRect().top <= th);
479
+ const statusBarH = this.frameContext.get('statusbar')?.offsetHeight || 0;
494
480
  let t = addOffset.top;
495
481
  let y = 0;
496
482
  let arrowDir = '';
483
+
484
+ // [bottom] position
497
485
  if (position === 'bottom') {
486
+ let trmt = rmt - (isSticky && globalTop - wScrollY <= toolbarH ? toolbarH : 0);
487
+ if (isSticky && trmt + toolbarH < 0) trmt += toolbarH;
498
488
  arrowDir = 'up';
499
- t += targetRect.bottom + ah + _w.scrollY;
500
- y = rmb - (elH + ah);
501
- if (y < 0) {
489
+ t += targetRect.bottom + ah + wScrollY;
490
+ y = rmb - (elH + ah) - statusBarH;
491
+ // change to <top> position
492
+ if (y - siblingH < 0) {
502
493
  arrowDir = 'down';
503
494
  t -= targetH + elH + ah * 2;
504
- y = toolbarH + rmt - (elH + ah);
505
- if (y < 0) {
495
+ y = trmt - (elH + ah);
496
+ // sticky the <top> position
497
+ if (y - siblingH < 0) {
506
498
  arrowDir = '';
507
- t -= y;
499
+ t -= y - siblingH - Math.max(1, y + elH + ah) + (!isSticky && trmt < 0 ? toolbarH : 0) - (isSticky ? this.context.get('toolbar_main').offsetTop : 0);
508
500
  }
509
501
  }
510
- } else {
502
+ }
503
+ // <top> position
504
+ else {
511
505
  arrowDir = 'down';
512
- t += targetRect.top - elH - ah + _w.scrollY;
513
- y = rmt - (elH + ah);
514
- if (y < 0) {
506
+ t += targetRect.top - elH - ah + wScrollY;
507
+ y = (isSticky ? targetRect.top - toolbarH : rmt) - elH - ah;
508
+ // change to [bottom] position
509
+ if (y - siblingH < 0) {
515
510
  arrowDir = 'up';
516
511
  t += targetH + elH + ah * 2;
517
- y = rmb - (elH + ah);
518
- if (y < 0) {
512
+ y = (rmb > 0 ? bMargin : rmb) - (elH + ah) - statusBarH;
513
+ // sticky the [bottom] position
514
+ if (y - siblingH < 0) {
519
515
  arrowDir = '';
520
- t += y;
516
+ t += y - 2;
521
517
  }
522
518
  }
523
519
  }
@@ -534,7 +530,7 @@ Offset.prototype = {
534
530
  const tmlw = targetRect.left;
535
531
  const tmrw = clientSize.w - targetRect.right;
536
532
  let rml, rmr;
537
- if (this.editor.frameContext.get('isFullScreen')) {
533
+ if (this.frameContext.get('isFullScreen')) {
538
534
  rml = tmlw;
539
535
  rmr = tmrw;
540
536
  } else {
@@ -611,12 +607,12 @@ Offset.prototype = {
611
607
  element.style.display = 'block';
612
608
 
613
609
  let positionTop = position === 'top';
614
- range = range || this.selection.getRange();
610
+ range ||= this.selection.getRange();
615
611
  const rectsObj = this.selection.getRects(range, positionTop ? 'start' : 'end');
616
612
  positionTop = rectsObj.position === 'start';
617
613
 
618
- const isFullScreen = this.editor.frameContext.get('isFullScreen');
619
- const topArea = this.editor.frameContext.get('topArea');
614
+ const isFullScreen = this.frameContext.get('isFullScreen');
615
+ const topArea = this.frameContext.get('topArea');
620
616
  const rects = rectsObj.rects;
621
617
  const scrollLeft = isFullScreen ? 0 : rectsObj.scrollLeft;
622
618
  const scrollTop = isFullScreen ? 0 : rectsObj.scrollTop;
@@ -643,7 +639,7 @@ Offset.prototype = {
643
639
  const targetH = rects.height;
644
640
  const tmtw = rects.top;
645
641
  const tmbw = clientSize.h - rects.bottom;
646
- const toolbarH = !this.editor.toolbar._sticky && (this.editor.isBalloon || this.editor.isInline) ? 0 : this.context.get('toolbar.main').offsetHeight;
642
+ const toolbarH = !this.editor.toolbar._sticky && (this.editor.isBalloon || this.editor.isInline) ? 0 : this.context.get('toolbar_main').offsetHeight;
647
643
 
648
644
  const { rmt, rmb, rt } = this._getVMargin(tmtw, tmbw, toolbarH, clientSize, rects, isTargetAbs, wwScroll);
649
645
  if (rmb + targetH <= 0 || rmt + rt + targetH <= 0) return;
@@ -684,7 +680,7 @@ Offset.prototype = {
684
680
  const l = absoluteLeft < 0 ? padding : overRight < 0 ? absoluteLeft : absoluteLeft - overRight - padding - 1;
685
681
 
686
682
  let resetTop = false;
687
- const space = t + (isDirTop ? this.getGlobal(this.editor.frameContext.get('topArea')).top : element.offsetHeight - this.editor.frameContext.get('wysiwyg').offsetHeight);
683
+ const space = t + (isDirTop ? this.getGlobal(this.frameContext.get('topArea')).top : element.offsetHeight - this.frameContext.get('wysiwyg').offsetHeight);
688
684
  if (!isDirTop && space > 0 && this._getPageBottomSpace() < space) {
689
685
  isDirTop = true;
690
686
  resetTop = true;
@@ -717,7 +713,7 @@ Offset.prototype = {
717
713
  * @returns {number} Available space
718
714
  */
719
715
  _getPageBottomSpace() {
720
- const topArea = this.editor.frameContext.get('topArea');
716
+ const topArea = this.frameContext.get('topArea');
721
717
  return _d.documentElement.scrollHeight - (this.getGlobal(topArea).top + topArea.offsetHeight);
722
718
  },
723
719
 
@@ -734,59 +730,66 @@ Offset.prototype = {
734
730
  * @param {RectsInfo} targetRect Target rect object
735
731
  * @param {boolean} isTargetAbs Is target absolute position
736
732
  * @param {OffsetWWScrollInfo} wwScroll WYSIWYG scroll info
737
- * @returns {{rmt:number, rmb:number, rt:number}} Margin values (rmt: top margin, rmb: bottom margin, rt: Toolbar height offset adjustment)
733
+ * @returns {{rmt:number, rmb:number, rt:number, tMargin:number, bMargin:number}} Margin values
734
+ * - rmt: top margin to frame
735
+ * - rmb: bottom margin to frame
736
+ * - rt: Toolbar height offset adjustment
737
+ * - tMargin: top margin
738
+ * - bMargin: bottom margin
738
739
  */
739
740
  _getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTargetAbs, wwScroll) {
740
741
  let rmt = 0;
741
742
  let rmb = 0;
742
743
  let rt = 0;
743
- if (this.editor.frameContext.get('isFullScreen')) {
744
+ let tMargin = 0;
745
+ let bMargin = 0;
746
+
747
+ if (this.frameContext.get('isFullScreen')) {
744
748
  rmt = tmtw - toolbarH;
745
749
  rmb = tmbw;
746
750
  } else {
747
- const isIframe = isTargetAbs && this.editor.frameOptions.get('iframe');
748
- const tMargin = targetRect.top;
749
- const bMargin = clientSize.h - targetRect.bottom;
751
+ const isIframeAbs = isTargetAbs && this.frameOptions.get('iframe');
752
+ tMargin = targetRect.top;
753
+ bMargin = clientSize.h - targetRect.bottom;
750
754
  const editorOffset = this.getGlobal();
751
755
  const editorScroll = this.getGlobalScroll();
752
- const statusBarH = this.editor.frameContext.get('statusbar')?.offsetHeight || 0;
756
+ const statusBarH = this.frameContext.get('statusbar')?.offsetHeight || 0;
753
757
 
754
- if (isIframe) {
758
+ if (isIframeAbs) {
755
759
  const emt = editorOffset.top - editorScroll.top - editorScroll.ts;
756
- const editorH = this.editor.frameContext.get('topArea').offsetHeight;
760
+ const editorH = this.frameContext.get('topArea').offsetHeight;
757
761
  rmt = targetRect.top - emt;
758
762
  rmb = bMargin - (editorScroll.oh - (editorH + emt) + statusBarH);
759
763
  } else {
760
764
  rt = !this.editor.toolbar._sticky && !this.options.get('toolbar_container') ? toolbarH : 0;
761
- const wst = !isTargetAbs && /\d+/.test(this.editor.frameOptions.get('height')) ? editorOffset.top - _w.scrollY + rt : 0;
762
- const wsb = !isTargetAbs && /\d+/.test(this.editor.frameOptions.get('height')) ? _w.innerHeight - (editorOffset.top + editorOffset.height - _w.scrollY) : 0;
765
+ const wst = !isTargetAbs && /\d+/.test(this.frameOptions.get('height')) ? editorOffset.top - _w.scrollY + rt : 0;
766
+ const wsb = !isTargetAbs && /\d+/.test(this.frameOptions.get('height')) ? this.status.currentViewportHeight - (editorOffset.top + editorOffset.height - _w.scrollY) : 0;
763
767
  let st = wst;
764
768
  if (toolbarH > wst) {
765
769
  if (this.editor.toolbar._sticky) {
766
770
  st = toolbarH;
767
- toolbarH = 0;
768
771
  } else {
769
772
  st = wst + toolbarH;
770
773
  }
771
- } else if (this.options.get('toolbar_container')) {
774
+ } else if (this.options.get('toolbar_container') && !this.editor.toolbar._sticky) {
772
775
  toolbarH = 0;
773
776
  } else {
774
- st = wst + (this.editor.toolbar._sticky ? toolbarH : 0);
777
+ st = wst + toolbarH;
775
778
  }
776
779
 
777
- rmt = targetRect.top - st;
778
- rmb = wwScroll.rects.bottom - targetRect.bottom - wsb - statusBarH;
780
+ rmt = targetRect.top - wwScroll.rects.top - st + toolbarH;
781
+ rmb = wwScroll.rects.bottom - targetRect.bottom - wsb;
782
+ // display margin
783
+ rmt = rmt > 0 ? rmt : rmt - toolbarH;
779
784
  }
780
-
781
- // display margin
782
- rmt = (rmt > 0 ? tMargin : rmt) - toolbarH;
783
- rmb = rmb > 0 ? bMargin : rmb;
784
785
  }
785
786
 
786
787
  return {
787
788
  rmt,
788
789
  rmb,
789
- rt
790
+ rt,
791
+ tMargin,
792
+ bMargin
790
793
  };
791
794
  },
792
795
 
@@ -829,7 +832,6 @@ Offset.prototype = {
829
832
  * rects: RectsInfo
830
833
  * }} An object with scroll and viewport information.
831
834
  */
832
-
833
835
  _getWindowScroll() {
834
836
  const viewPort = getClientSize(_d);
835
837
  return {
@@ -842,50 +844,13 @@ Offset.prototype = {
842
844
  left: 0,
843
845
  top: 0,
844
846
  right: _w.innerWidth,
845
- bottom: _w.innerHeight,
847
+ bottom: this.status.currentViewportHeight || _w.innerHeight,
846
848
  noText: true
847
849
  }
848
850
  };
849
851
  },
850
852
 
851
- /**
852
- * @private
853
- * @this {OffsetThis}
854
- * @description Removes the global scroll event listener from the editor.
855
- * - Resets related scroll tracking properties.
856
- */
857
- __removeGlobalEvent() {
858
- if (this._scrollEvent) {
859
- this._scrollEvent = this.editor.eventManager.removeGlobalEvent(this._scrollEvent);
860
- this._scrollY = 0;
861
- this._elTop = null;
862
- }
863
- },
864
-
865
853
  constructor: Offset
866
854
  };
867
855
 
868
- /**
869
- * @private
870
- * @this {OffsetThis}
871
- * @param {HTMLElement} element - The element to check for a specific class name.
872
- * @param {HTMLElement} e_container - The root container of the element.
873
- * @param {HTMLElement} target - The target element to position against.
874
- * @param {HTMLElement} t_container - The root container of the target element.
875
- */
876
- function FixedScroll(element, e_container, target, t_container) {
877
- const isFixed = /^fixed$/i.test(_w.getComputedStyle(t_container).position);
878
- if (!this._isFixed) {
879
- if (isFixed) {
880
- this.setRelPosition(element, e_container, target, t_container, true);
881
- }
882
- return;
883
- } else if (!isFixed) {
884
- this.setRelPosition(element, e_container, target, t_container, true);
885
- return;
886
- }
887
-
888
- element.style.top = `${this._elTop - (this._scrollY - _w.scrollY - t_container.offsetTop)}px`;
889
- }
890
-
891
856
  export default Offset;