suneditor 3.0.0-rc.5 → 3.0.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.
- package/README.md +3 -2
- package/dist/suneditor-contents.min.css +1 -1
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +3 -3
- package/src/assets/design/color.css +14 -2
- package/src/assets/design/typography.css +5 -0
- package/src/assets/icons/defaultIcons.js +22 -4
- package/src/assets/suneditor-contents.css +1 -1
- package/src/assets/suneditor.css +312 -18
- package/src/core/config/eventManager.js +6 -9
- package/src/core/editor.js +1 -1
- package/src/core/event/actions/index.js +5 -0
- package/src/core/event/effects/keydown.registry.js +25 -0
- package/src/core/event/eventOrchestrator.js +69 -2
- package/src/core/event/handlers/handler_ww_mouse.js +1 -0
- package/src/core/event/rules/keydown.rule.backspace.js +9 -1
- package/src/core/kernel/coreKernel.js +4 -0
- package/src/core/kernel/store.js +2 -0
- package/src/core/logic/dom/html.js +110 -11
- package/src/core/logic/dom/offset.js +89 -35
- package/src/core/logic/dom/selection.js +46 -19
- package/src/core/logic/panel/finder.js +982 -0
- package/src/core/logic/panel/menu.js +8 -6
- package/src/core/logic/panel/toolbar.js +112 -19
- package/src/core/logic/panel/viewer.js +214 -43
- package/src/core/logic/shell/_commandExecutor.js +7 -1
- package/src/core/logic/shell/commandDispatcher.js +1 -1
- package/src/core/logic/shell/component.js +5 -7
- package/src/core/logic/shell/history.js +24 -0
- package/src/core/logic/shell/shortcuts.js +5 -3
- package/src/core/logic/shell/ui.js +25 -26
- package/src/core/schema/frameContext.js +15 -1
- package/src/core/schema/options.js +75 -16
- package/src/core/section/constructor.js +62 -21
- package/src/core/section/documentType.js +1 -1
- package/src/events.js +12 -0
- package/src/helper/clipboard.js +1 -1
- package/src/helper/dom/domUtils.js +5 -14
- package/src/helper/index.js +3 -0
- package/src/helper/markdown.js +876 -0
- package/src/langs/ckb.js +9 -0
- package/src/langs/cs.js +9 -0
- package/src/langs/da.js +9 -0
- package/src/langs/de.js +9 -0
- package/src/langs/en.js +9 -0
- package/src/langs/es.js +9 -0
- package/src/langs/fa.js +9 -0
- package/src/langs/fr.js +9 -0
- package/src/langs/he.js +9 -0
- package/src/langs/hu.js +9 -0
- package/src/langs/it.js +9 -0
- package/src/langs/ja.js +9 -0
- package/src/langs/km.js +9 -0
- package/src/langs/ko.js +9 -0
- package/src/langs/lv.js +9 -0
- package/src/langs/nl.js +9 -0
- package/src/langs/pl.js +9 -0
- package/src/langs/pt_br.js +9 -0
- package/src/langs/ro.js +9 -0
- package/src/langs/ru.js +9 -0
- package/src/langs/se.js +9 -0
- package/src/langs/tr.js +9 -0
- package/src/langs/uk.js +9 -0
- package/src/langs/ur.js +9 -0
- package/src/langs/zh_cn.js +9 -0
- package/src/modules/contract/Controller.js +50 -39
- package/src/modules/manager/ApiManager.js +27 -4
- package/src/modules/manager/FileManager.js +1 -1
- package/src/modules/ui/SelectMenu.js +22 -11
- package/src/plugins/command/codeBlock.js +324 -0
- package/src/plugins/command/exportPDF.js +15 -3
- package/src/plugins/dropdown/blockStyle.js +1 -1
- package/src/plugins/dropdown/paragraphStyle.js +1 -2
- package/src/plugins/dropdown/table/render/table.html.js +1 -1
- package/src/plugins/dropdown/table/services/table.grid.js +16 -8
- package/src/plugins/dropdown/table/services/table.style.js +5 -9
- package/src/plugins/index.js +3 -0
- package/src/plugins/input/fontSize.js +4 -2
- package/src/plugins/modal/audio.js +2 -1
- package/src/plugins/modal/image/index.js +2 -1
- package/src/plugins/modal/math.js +2 -1
- package/src/plugins/modal/video/index.js +2 -1
- package/src/themes/cobalt.css +13 -4
- package/src/themes/cream.css +44 -35
- package/src/themes/dark.css +13 -4
- package/src/themes/midnight.css +13 -4
- package/src/typedef.js +4 -4
- package/types/assets/icons/defaultIcons.d.ts +12 -1
- package/types/core/config/eventManager.d.ts +6 -8
- package/types/core/event/actions/index.d.ts +1 -0
- package/types/core/event/effects/keydown.registry.d.ts +2 -0
- package/types/core/event/eventOrchestrator.d.ts +2 -1
- package/types/core/kernel/coreKernel.d.ts +5 -0
- package/types/core/kernel/store.d.ts +5 -0
- package/types/core/logic/dom/offset.d.ts +16 -3
- package/types/core/logic/dom/selection.d.ts +3 -3
- package/types/core/logic/panel/finder.d.ts +83 -0
- package/types/core/logic/panel/toolbar.d.ts +14 -1
- package/types/core/logic/panel/viewer.d.ts +22 -2
- package/types/core/logic/shell/shortcuts.d.ts +1 -1
- package/types/core/schema/frameContext.d.ts +22 -0
- package/types/core/schema/options.d.ts +153 -31
- package/types/events.d.ts +11 -0
- package/types/helper/dom/domUtils.d.ts +2 -2
- package/types/helper/index.d.ts +5 -0
- package/types/helper/markdown.d.ts +27 -0
- package/types/langs/_Lang.d.ts +9 -0
- package/types/modules/contract/Controller.d.ts +8 -1
- package/types/modules/ui/SelectMenu.d.ts +12 -0
- package/types/plugins/command/codeBlock.d.ts +53 -0
- package/types/plugins/index.d.ts +3 -0
- package/types/plugins/input/fontSize.d.ts +6 -2
- package/types/plugins/modal/audio.d.ts +4 -2
- package/types/plugins/modal/image/index.d.ts +3 -1
- package/types/plugins/modal/math.d.ts +3 -1
- package/types/plugins/modal/video/index.d.ts +3 -1
- package/types/typedef.d.ts +5 -2
|
@@ -358,15 +358,21 @@ class Offset {
|
|
|
358
358
|
* @param {HTMLElement} e_container Element's root container
|
|
359
359
|
* @param {HTMLElement} target Target element to position against
|
|
360
360
|
* @param {HTMLElement} t_container Target's root container
|
|
361
|
+
* @param {Object} [opts] Options
|
|
362
|
+
* @param {boolean} [opts.preferUp=false] Open upward by default (for bottom toolbar)
|
|
361
363
|
*/
|
|
362
|
-
setRelPosition(element, e_container, target, t_container) {
|
|
364
|
+
setRelPosition(element, e_container, target, t_container, { preferUp } = {}) {
|
|
363
365
|
const isFixedContainer = /^fixed$/i.test(_w.getComputedStyle(t_container).position);
|
|
364
366
|
const tGlobal = this.getGlobal(target);
|
|
365
367
|
|
|
366
368
|
// top
|
|
367
369
|
if (isFixedContainer) {
|
|
368
370
|
element.style.position = 'fixed';
|
|
369
|
-
|
|
371
|
+
if (preferUp) {
|
|
372
|
+
element.style.top = `${tGlobal.fixedTop - element.offsetHeight}px`;
|
|
373
|
+
} else {
|
|
374
|
+
element.style.top = `${tGlobal.fixedTop + tGlobal.height}px`;
|
|
375
|
+
}
|
|
370
376
|
} else {
|
|
371
377
|
element.style.position = '';
|
|
372
378
|
|
|
@@ -376,23 +382,43 @@ class Offset {
|
|
|
376
382
|
const scrollTop = _w.scrollY;
|
|
377
383
|
const bt = tGlobal.top;
|
|
378
384
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
if (preferUp) {
|
|
386
|
+
// Try to open above
|
|
387
|
+
const menuHeight_top = containerTop - scrollTop + bt;
|
|
388
|
+
if (menuHeight_top < elHeight) {
|
|
389
|
+
// Not enough space above — try below
|
|
390
|
+
const menuHeight_bottom = getClientSize(_d).h - (containerTop - scrollTop + bt + target.offsetHeight);
|
|
391
|
+
if (menuHeight_bottom >= elHeight) {
|
|
392
|
+
element.style.top = `${bt + target.offsetHeight}px`;
|
|
393
|
+
} else if (menuHeight_bottom > menuHeight_top) {
|
|
394
|
+
element.style.height = `${menuHeight_bottom}px`;
|
|
395
|
+
element.style.top = `${bt + target.offsetHeight}px`;
|
|
396
|
+
} else {
|
|
397
|
+
element.style.height = `${menuHeight_top}px`;
|
|
398
|
+
element.style.top = `${-1 * (menuHeight_top - bt + 3)}px`;
|
|
399
|
+
}
|
|
388
400
|
} else {
|
|
389
|
-
element.style.
|
|
390
|
-
menuTop = bt + target.offsetHeight;
|
|
401
|
+
element.style.top = `${bt - elHeight}px`;
|
|
391
402
|
}
|
|
392
|
-
|
|
393
|
-
element.style.top = `${menuTop}px`;
|
|
394
403
|
} else {
|
|
395
|
-
|
|
404
|
+
const menuHeight_bottom = getClientSize(_d).h - (containerTop - scrollTop + bt + target.offsetHeight);
|
|
405
|
+
if (menuHeight_bottom < elHeight) {
|
|
406
|
+
let menuTop = -1 * (elHeight - bt + 3);
|
|
407
|
+
const insTop = containerTop - scrollTop + menuTop;
|
|
408
|
+
const menuHeight_top = elHeight + (insTop < 0 ? insTop : 0);
|
|
409
|
+
|
|
410
|
+
if (menuHeight_top > menuHeight_bottom) {
|
|
411
|
+
element.style.height = `${menuHeight_top}px`;
|
|
412
|
+
menuTop = -1 * (menuHeight_top - bt + 3);
|
|
413
|
+
} else {
|
|
414
|
+
element.style.height = `${menuHeight_bottom}px`;
|
|
415
|
+
menuTop = bt + target.offsetHeight;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
element.style.top = `${menuTop}px`;
|
|
419
|
+
} else {
|
|
420
|
+
element.style.top = `${bt + target.offsetHeight}px`;
|
|
421
|
+
}
|
|
396
422
|
}
|
|
397
423
|
}
|
|
398
424
|
|
|
@@ -426,19 +452,20 @@ class Offset {
|
|
|
426
452
|
* @param {HTMLElement} target Target element
|
|
427
453
|
* @param {Object} params Position parameters
|
|
428
454
|
* @param {boolean} [params.isWWTarget=false] Whether the target is within the editor's WYSIWYG area
|
|
429
|
-
* @param {{left:number, top:number}} [params.addOffset={left:0, top:0}] Additional offset
|
|
455
|
+
* @param {{left:number, right:number, top:number}} [params.addOffset={left:0, right:0, top:0}] Additional offset
|
|
430
456
|
* @param {"bottom"|"top"} [params.position="bottom"] Position ('bottom'|'top')
|
|
431
457
|
* @param {*} params.inst Instance object of caller
|
|
432
458
|
* @param {HTMLElement} [params.sibling=null] The sibling controller element
|
|
433
459
|
* @returns {{position: "top" | "bottom"} | undefined} Success -> {position: current position}
|
|
434
460
|
* @example
|
|
435
461
|
* const result = editor.$.offset.setAbsPosition(controller, targetElement, {
|
|
436
|
-
* position: 'bottom', inst: this, addOffset: { left: 0, top: 0 }
|
|
462
|
+
* position: 'bottom', inst: this, addOffset: { left: 0, right: 0, top: 0 }
|
|
437
463
|
* });
|
|
438
464
|
*/
|
|
439
465
|
setAbsPosition(element, target, params) {
|
|
440
466
|
const addOffset = {
|
|
441
467
|
left: 0,
|
|
468
|
+
right: 0,
|
|
442
469
|
top: 0,
|
|
443
470
|
...params.addOffset,
|
|
444
471
|
};
|
|
@@ -483,7 +510,9 @@ class Offset {
|
|
|
483
510
|
const { rmt, rmb, bMargin, rt } = this.#getVMargin(tmtw, tmbw, toolbarH, clientSize, targetRect, isTextSelection, isToolbarTarget);
|
|
484
511
|
if ((isWWTarget && (rmb - statusBarH + targetH <= 0 || rmt + rt + targetH - (this.#$.toolbar.isSticky && isInlineTarget ? toolbarH : 0) <= 0)) || rmt + targetH < 0) return;
|
|
485
512
|
|
|
486
|
-
const
|
|
513
|
+
const topAreaRect = this.#frameContext.get('topArea').getBoundingClientRect();
|
|
514
|
+
const isStickyVisible = this.#store.mode.isBottom ? topAreaRect.bottom >= _w.innerHeight - th : topAreaRect.top <= th;
|
|
515
|
+
const isSticky = this.#$.toolbar.isSticky && this.#context.get('toolbar_main').style.display !== 'none' && (!headLess || isStickyVisible);
|
|
487
516
|
let t = addOffset.top;
|
|
488
517
|
let y = 0;
|
|
489
518
|
let arrowDir = '';
|
|
@@ -509,7 +538,7 @@ class Offset {
|
|
|
509
538
|
else {
|
|
510
539
|
arrowDir = 'down';
|
|
511
540
|
t += targetRect.top - elH - ah + wScrollY;
|
|
512
|
-
y = (isSticky ? targetRect.top - toolbarH : rmt) - elH - ah;
|
|
541
|
+
y = (isSticky && !this.#store.mode.isBottom ? targetRect.top - toolbarH : rmt) - elH - ah;
|
|
513
542
|
// change to [bottom] position
|
|
514
543
|
if (y - siblingH < 0) {
|
|
515
544
|
arrowDir = 'up';
|
|
@@ -541,7 +570,7 @@ class Offset {
|
|
|
541
570
|
arrow.style.right = '';
|
|
542
571
|
}
|
|
543
572
|
|
|
544
|
-
let l = addOffset.left;
|
|
573
|
+
let l = addOffset.left || (addOffset.right ? (isLTR ? addOffset.right - element.offsetWidth : element.offsetWidth - addOffset.right) : 0);
|
|
545
574
|
let x = 0;
|
|
546
575
|
let ax = 0;
|
|
547
576
|
let awLimit = 0;
|
|
@@ -742,33 +771,58 @@ class Offset {
|
|
|
742
771
|
bMargin = clientSize.h - targetRect.bottom;
|
|
743
772
|
const editorOffset = this.getGlobal();
|
|
744
773
|
|
|
774
|
+
const isBottom = this.#store.mode.isBottom;
|
|
745
775
|
if (!isTextSelection) {
|
|
746
776
|
const emt = editorOffset.fixedTop > 0 ? editorOffset.fixedTop : 0;
|
|
747
777
|
const emb = _w.innerHeight - (editorOffset.fixedTop + editorOffset.height);
|
|
748
778
|
rt = !isToolbarTarget && (this.#$.toolbar.isSticky || !this.#$.toolbar.isBalloonMode) ? toolbarH : 0;
|
|
749
|
-
|
|
750
|
-
|
|
779
|
+
if (isBottom) {
|
|
780
|
+
rmt = tMargin - (!isToolbarTarget ? emt : 0);
|
|
781
|
+
rmb = bMargin - (emb > 0 ? emb : 0) - rt;
|
|
782
|
+
} else {
|
|
783
|
+
rmt = tMargin - (!isToolbarTarget ? emt : 0) - rt;
|
|
784
|
+
rmb = bMargin - (emb > 0 ? emb : 0);
|
|
785
|
+
}
|
|
751
786
|
} else {
|
|
752
787
|
rt = !isToolbarTarget && !this.#$.toolbar.isSticky && !this.#options.get('toolbar_container') ? toolbarH : 0;
|
|
753
788
|
const wst = !isIframe ? editorOffset.top - _w.scrollY + rt : 0;
|
|
754
789
|
const wsb = !isIframe ? this.#store.get('currentViewportHeight') - (editorOffset.top + editorOffset.height - _w.scrollY) : 0;
|
|
755
790
|
let st = wst;
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
791
|
+
let sb = wsb;
|
|
792
|
+
if (isBottom) {
|
|
793
|
+
if (toolbarH > wsb) {
|
|
794
|
+
if (this.#$.toolbar.isSticky) {
|
|
795
|
+
sb = toolbarH;
|
|
796
|
+
} else {
|
|
797
|
+
sb = wsb + toolbarH;
|
|
798
|
+
}
|
|
799
|
+
} else if (this.#options.get('toolbar_container') && !this.#$.toolbar.isSticky) {
|
|
800
|
+
toolbarH = 0;
|
|
759
801
|
} else {
|
|
760
|
-
|
|
802
|
+
sb = wsb + toolbarH;
|
|
761
803
|
}
|
|
762
|
-
|
|
763
|
-
|
|
804
|
+
|
|
805
|
+
rmt = targetRect.top - (wwRects.top - wst);
|
|
806
|
+
rmb = wwRects.bottom - (targetRect.bottom - sb) + toolbarH;
|
|
807
|
+
rmb = rmb > 0 ? rmb : rmb - toolbarH;
|
|
764
808
|
} else {
|
|
765
|
-
|
|
766
|
-
|
|
809
|
+
if (toolbarH > wst) {
|
|
810
|
+
if (this.#$.toolbar.isSticky) {
|
|
811
|
+
st = toolbarH;
|
|
812
|
+
} else {
|
|
813
|
+
st = wst + toolbarH;
|
|
814
|
+
}
|
|
815
|
+
} else if (this.#options.get('toolbar_container') && !this.#$.toolbar.isSticky) {
|
|
816
|
+
toolbarH = 0;
|
|
817
|
+
} else {
|
|
818
|
+
st = wst + toolbarH;
|
|
819
|
+
}
|
|
767
820
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
821
|
+
rmt = targetRect.top - (wwRects.top - st) + toolbarH;
|
|
822
|
+
rmb = wwRects.bottom - (targetRect.bottom - wsb);
|
|
823
|
+
// display margin
|
|
824
|
+
rmt = rmt > 0 ? rmt : rmt - toolbarH;
|
|
825
|
+
}
|
|
772
826
|
}
|
|
773
827
|
|
|
774
828
|
return {
|
|
@@ -378,7 +378,7 @@ class Selection_ {
|
|
|
378
378
|
/**
|
|
379
379
|
* @description Scroll to the corresponding selection or range position.
|
|
380
380
|
* @param {Selection|Range|Node} ref selection or range object
|
|
381
|
-
* @param {
|
|
381
|
+
* @param {ScrollIntoViewOptions & {noFocus?: boolean}} [scrollOption] Scroll options. Extends `ScrollIntoViewOptions` (`behavior`, `block`, `inline`) with `noFocus` to prevent focus change.
|
|
382
382
|
* @example
|
|
383
383
|
* // Scroll to current selection smoothly
|
|
384
384
|
* editor.selection.scrollTo(editor.selection.get());
|
|
@@ -394,10 +394,18 @@ class Selection_ {
|
|
|
394
394
|
* });
|
|
395
395
|
*/
|
|
396
396
|
scrollTo(ref, scrollOption) {
|
|
397
|
+
const noFocus = scrollOption?.noFocus;
|
|
398
|
+
|
|
397
399
|
if (this.#instanceCheck.isSelection(ref)) {
|
|
398
400
|
ref = ref.getRangeAt(0);
|
|
399
401
|
} else if (this.#instanceCheck.isNode(ref)) {
|
|
400
|
-
|
|
402
|
+
if (noFocus) {
|
|
403
|
+
const range = this.#frameContext.get('_wd').createRange();
|
|
404
|
+
range.selectNodeContents(ref);
|
|
405
|
+
ref = range;
|
|
406
|
+
} else {
|
|
407
|
+
ref = this.setRange(ref, 1, ref, 1);
|
|
408
|
+
}
|
|
401
409
|
} else if (typeof ref?.startContainer === 'undefined') {
|
|
402
410
|
console.warn('[SUNEDITOR.html.scrollTo.warn] "selectionRange" must be Selection or Range or Node object.', ref);
|
|
403
411
|
}
|
|
@@ -406,6 +414,7 @@ class Selection_ {
|
|
|
406
414
|
if (!el) return;
|
|
407
415
|
|
|
408
416
|
scrollOption = { behavior: 'smooth', block: 'nearest', inline: 'nearest', ...scrollOption };
|
|
417
|
+
delete scrollOption.noFocus;
|
|
409
418
|
|
|
410
419
|
const ww = this.#frameContext.get('_ww');
|
|
411
420
|
const wwFrame = this.#frameContext.get('wysiwygFrame');
|
|
@@ -413,6 +422,7 @@ class Selection_ {
|
|
|
413
422
|
const isAutoHeight = !this.#store.get('isScrollable')(this.#frameContext);
|
|
414
423
|
const viewportHeight = this.#store.get('currentViewportHeight');
|
|
415
424
|
const scrollY = isAutoHeight ? _w.scrollY : isIframe ? ww.scrollY : wwFrame.scrollTop;
|
|
425
|
+
const isBottom = this.#store.mode.isBottom;
|
|
416
426
|
const realToolbarHeight = this.#context.get('toolbar_main').offsetHeight;
|
|
417
427
|
const toolbarHeight = this.#$.toolbar.isSticky ? realToolbarHeight : 0;
|
|
418
428
|
const positionToolbarHeight = this.#$.toolbar.isSticky ? toolbarHeight + this.#options.get('toolbar_sticky') : toolbarHeight;
|
|
@@ -422,8 +432,18 @@ class Selection_ {
|
|
|
422
432
|
el?.scrollIntoView(scrollOption);
|
|
423
433
|
|
|
424
434
|
if (scrollOption?.behavior === 'auto' && scrollY !== _w.scrollY) {
|
|
425
|
-
if (positionToolbarHeight
|
|
426
|
-
|
|
435
|
+
if (positionToolbarHeight) {
|
|
436
|
+
if (isBottom) {
|
|
437
|
+
// bottom toolbar covers the bottom — scroll down more so the element clears the toolbar
|
|
438
|
+
if (scrollY < _w.scrollY) {
|
|
439
|
+
_w.scrollBy(0, positionToolbarHeight);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
// top toolbar covers the top — scroll up more so the element clears the toolbar
|
|
443
|
+
if (scrollY > _w.scrollY) {
|
|
444
|
+
_w.scrollBy(0, -positionToolbarHeight);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
427
447
|
} else if (isAutoHeight) {
|
|
428
448
|
_w.scrollBy(0, statusbarHeight);
|
|
429
449
|
}
|
|
@@ -434,55 +454,62 @@ class Selection_ {
|
|
|
434
454
|
|
|
435
455
|
// --- When there is no upper scroll and it is an iframe ---
|
|
436
456
|
const PADDING = this.#scrollMargin;
|
|
437
|
-
|
|
438
|
-
const
|
|
457
|
+
// Reduce effective viewport height by toolbar+offset when bottom toolbar is sticky
|
|
458
|
+
const viewHeight = isAutoHeight ? viewportHeight - (isBottom ? positionToolbarHeight : 0) : wwFrame.offsetHeight;
|
|
459
|
+
|
|
460
|
+
// Use range rect for accurate height — el.offsetHeight includes nested children (e.g. nested lists)
|
|
461
|
+
const refRect = ref?.getBoundingClientRect?.();
|
|
462
|
+
const elH = (refRect?.height > 0 ? refRect.height : el.offsetHeight) || 0;
|
|
439
463
|
|
|
440
464
|
const behavior = scrollOption?.behavior;
|
|
465
|
+
const topToolbarH = isBottom ? 0 : positionToolbarHeight;
|
|
441
466
|
if (isAutoHeight) {
|
|
442
467
|
if (isIframe) {
|
|
443
468
|
const rect = this.getRects(ref, 'end').rects;
|
|
444
|
-
const topMargin = rect.top + elH -
|
|
469
|
+
const topMargin = rect.top + elH - topToolbarH;
|
|
445
470
|
const bottomMargin = viewHeight - PADDING - (rect.top + elH);
|
|
446
471
|
if (topMargin >= 0 && bottomMargin >= 0) return;
|
|
447
472
|
|
|
448
473
|
const newScrollTop = scrollY - (topMargin < 0 ? -(topMargin - PADDING) : bottomMargin);
|
|
449
474
|
_w.scrollTo({
|
|
450
|
-
top: newScrollTop < scrollY ? newScrollTop -
|
|
475
|
+
top: newScrollTop < scrollY ? newScrollTop - topToolbarH : newScrollTop,
|
|
451
476
|
behavior,
|
|
452
477
|
});
|
|
453
478
|
} else {
|
|
454
479
|
const rect = this.#$.offset.getGlobal(el);
|
|
455
480
|
const scrollMargin = viewHeight + scrollY - rect.top - elH;
|
|
456
481
|
|
|
457
|
-
if (scrollMargin - PADDING > 0 && viewHeight > scrollMargin + PADDING +
|
|
482
|
+
if (scrollMargin - PADDING > 0 && viewHeight > scrollMargin + PADDING + topToolbarH) return;
|
|
458
483
|
|
|
459
484
|
const newScrollTop = scrollMargin <= PADDING ? scrollY - scrollMargin + PADDING + statusbarHeight : scrollY - scrollMargin + (viewHeight - elH - PADDING);
|
|
460
485
|
_w.scrollTo({
|
|
461
|
-
top: newScrollTop < scrollY ? newScrollTop -
|
|
486
|
+
top: newScrollTop < scrollY ? newScrollTop - topToolbarH : newScrollTop,
|
|
462
487
|
behavior,
|
|
463
488
|
});
|
|
464
489
|
}
|
|
465
490
|
} else {
|
|
466
|
-
// local scroll
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
const innerTop =
|
|
491
|
+
// local scroll — use range rect for accurate position (el.getBoundingClientRect includes nested children)
|
|
492
|
+
const hasRefRect = refRect?.height > 0;
|
|
493
|
+
const targetTop = hasRefRect ? refRect.top : el.getBoundingClientRect().top;
|
|
494
|
+
const innerTop = isIframe ? targetTop : targetTop - wwFrame.getBoundingClientRect().top;
|
|
470
495
|
|
|
471
496
|
const keepLocalScroll = innerTop - PADDING > 0 && innerTop + PADDING <= viewHeight;
|
|
472
|
-
const rectScroll = innerTop - PADDING > 0 ? innerTop + PADDING - viewHeight : innerTop - (toolbarHeight + elH);
|
|
497
|
+
const rectScroll = isBottom ? (innerTop - PADDING > 0 ? innerTop + PADDING - viewHeight + toolbarHeight : innerTop - elH) : innerTop - PADDING > 0 ? innerTop + PADDING - viewHeight : innerTop - (toolbarHeight + elH);
|
|
473
498
|
let newScrollTop = scrollY + rectScroll;
|
|
474
499
|
|
|
475
500
|
// frame scroll
|
|
476
501
|
const gy = _w.scrollY;
|
|
477
502
|
const globalRect = this.#$.offset.getGlobal();
|
|
478
|
-
const
|
|
479
|
-
const
|
|
503
|
+
const topToolbarFrame = isBottom ? 0 : realToolbarHeight;
|
|
504
|
+
const bottomToolbarFrame = isBottom ? realToolbarHeight : 0;
|
|
505
|
+
const topMargin = gy - globalRect.top + topToolbarFrame;
|
|
506
|
+
const bottomMargin = globalRect.top + globalRect.height - (gy + viewportHeight) + bottomToolbarFrame;
|
|
480
507
|
|
|
481
508
|
// set frame scroll
|
|
482
509
|
if (topMargin > 0) {
|
|
483
510
|
const newFrameY = (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) - elH - PADDING - topMargin;
|
|
484
511
|
if (newFrameY < 0) {
|
|
485
|
-
newScrollTop +=
|
|
512
|
+
newScrollTop += topToolbarFrame;
|
|
486
513
|
_w.scrollTo({
|
|
487
514
|
top: gy + newFrameY,
|
|
488
515
|
behavior: 'smooth',
|
|
@@ -492,7 +519,7 @@ class Selection_ {
|
|
|
492
519
|
if (bottomMargin > 0) {
|
|
493
520
|
const newFrameY = (keepLocalScroll ? innerTop : innerTop + scrollY - newScrollTop) + elH + PADDING - (globalRect.height - bottomMargin);
|
|
494
521
|
if (newFrameY > 0) {
|
|
495
|
-
newScrollTop += statusbarHeight;
|
|
522
|
+
newScrollTop += isBottom ? bottomToolbarFrame : statusbarHeight;
|
|
496
523
|
_w.scrollTo({
|
|
497
524
|
top: gy + newFrameY,
|
|
498
525
|
behavior: 'smooth',
|