slate-angular 20.2.13 → 20.2.15
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/fesm2022/slate-angular.mjs +626 -589
- package/fesm2022/slate-angular.mjs.map +1 -1
- package/index.d.ts +20 -19
- package/package.json +1 -1
|
@@ -1498,6 +1498,9 @@ const ELEMENT_KEY_TO_HEIGHTS = new WeakMap();
|
|
|
1498
1498
|
const EDITOR_TO_BUSINESS_TOP = new WeakMap();
|
|
1499
1499
|
const EDITOR_TO_ROOT_NODE_WIDTH = new WeakMap();
|
|
1500
1500
|
const EDITOR_TO_IS_FROM_SCROLL_TO = new WeakMap();
|
|
1501
|
+
const isValidNumber = (value) => {
|
|
1502
|
+
return typeof value === 'number' && !Number.isNaN(value);
|
|
1503
|
+
};
|
|
1501
1504
|
const debugLog = (type, ...args) => {
|
|
1502
1505
|
const doc = document;
|
|
1503
1506
|
VirtualScrollDebugOverlay.log(doc, type, ...args);
|
|
@@ -1506,7 +1509,7 @@ const cacheHeightByElement = (editor, element, height) => {
|
|
|
1506
1509
|
if (!AngularEditor.isEnabledVirtualScroll(editor)) {
|
|
1507
1510
|
return;
|
|
1508
1511
|
}
|
|
1509
|
-
if (
|
|
1512
|
+
if (!isValidNumber(height)) {
|
|
1510
1513
|
console.error('cacheHeightByElement: height must be number', height);
|
|
1511
1514
|
return;
|
|
1512
1515
|
}
|
|
@@ -1565,9 +1568,11 @@ const measureHeightByIndics = (editor, indics, force = false) => {
|
|
|
1565
1568
|
}
|
|
1566
1569
|
return;
|
|
1567
1570
|
}
|
|
1568
|
-
hasChanged = true;
|
|
1569
1571
|
const currentHeight = calcHeightByElement(editor, element);
|
|
1570
|
-
if (
|
|
1572
|
+
if (isValidNumber(currentHeight) && currentHeight !== preHeight) {
|
|
1573
|
+
hasChanged = true;
|
|
1574
|
+
}
|
|
1575
|
+
if (isDebug && isValidNumber(currentHeight)) {
|
|
1571
1576
|
debugLog('log', 'measureHeightByIndics: height not equal, index: ', index, 'preHeight: ', preHeight, 'height: ', currentHeight);
|
|
1572
1577
|
}
|
|
1573
1578
|
});
|
|
@@ -3503,663 +3508,695 @@ class SlateEditable {
|
|
|
3503
3508
|
this.addEventListener(event.name, () => { });
|
|
3504
3509
|
});
|
|
3505
3510
|
}
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3511
|
+
isEnabledVirtualScroll() {
|
|
3512
|
+
return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
|
|
3513
|
+
}
|
|
3514
|
+
initializeVirtualScroll() {
|
|
3515
|
+
if (this.virtualScrollInitialized) {
|
|
3516
|
+
return;
|
|
3517
|
+
}
|
|
3518
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3519
|
+
this.virtualScrollInitialized = true;
|
|
3520
|
+
this.virtualTopHeightElement = document.createElement('div');
|
|
3521
|
+
this.virtualTopHeightElement.classList.add('virtual-top-height');
|
|
3522
|
+
this.virtualTopHeightElement.contentEditable = 'false';
|
|
3523
|
+
this.virtualBottomHeightElement = document.createElement('div');
|
|
3524
|
+
this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
|
|
3525
|
+
this.virtualBottomHeightElement.contentEditable = 'false';
|
|
3526
|
+
this.virtualCenterOutlet = document.createElement('div');
|
|
3527
|
+
this.virtualCenterOutlet.classList.add('virtual-center-outlet');
|
|
3528
|
+
this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
|
|
3529
|
+
this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
|
|
3530
|
+
this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
|
|
3531
|
+
let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect().width;
|
|
3532
|
+
EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, this.virtualTopHeightElement.offsetWidth);
|
|
3533
|
+
this.editorResizeObserver = new ResizeObserver(entries => {
|
|
3534
|
+
if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
|
|
3535
|
+
editorResizeObserverRectWidth = entries[0].contentRect.width;
|
|
3536
|
+
this.keyHeightMap.clear();
|
|
3537
|
+
let target = this.virtualTopHeightElement;
|
|
3538
|
+
if (this.inViewportChildren[0]) {
|
|
3539
|
+
const firstElement = this.inViewportChildren[0];
|
|
3540
|
+
const firstDomElement = AngularEditor.toDOMNode(this.editor, firstElement);
|
|
3541
|
+
target = firstDomElement;
|
|
3542
|
+
}
|
|
3543
|
+
EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, target.offsetWidth);
|
|
3544
|
+
updatePreRenderingElementWidth(this.editor);
|
|
3545
|
+
if (isDebug) {
|
|
3546
|
+
debugLog('log', 'editorResizeObserverRectWidth: ', editorResizeObserverRectWidth, 'EDITOR_TO_ROOT_NODE_WIDTH: ', EDITOR_TO_ROOT_NODE_WIDTH.get(this.editor));
|
|
3547
|
+
}
|
|
3526
3548
|
}
|
|
3527
|
-
|
|
3528
|
-
|
|
3549
|
+
});
|
|
3550
|
+
this.editorResizeObserver.observe(this.elementRef.nativeElement);
|
|
3551
|
+
let pendingRemeasureIndics = [];
|
|
3552
|
+
this.indicsOfNeedBeMeasured$
|
|
3553
|
+
.pipe(tap((previousValue) => {
|
|
3554
|
+
previousValue.forEach((index) => {
|
|
3555
|
+
if (!pendingRemeasureIndics.includes(index)) {
|
|
3556
|
+
pendingRemeasureIndics.push(index);
|
|
3557
|
+
}
|
|
3558
|
+
});
|
|
3559
|
+
}), debounceTime(500), filter(() => pendingRemeasureIndics.length > 0))
|
|
3560
|
+
.subscribe(() => {
|
|
3561
|
+
const changed = measureHeightByIndics(this.editor, pendingRemeasureIndics, true);
|
|
3562
|
+
if (changed) {
|
|
3563
|
+
this.tryUpdateVirtualViewport();
|
|
3529
3564
|
if (isDebug) {
|
|
3530
|
-
debugLog('log',
|
|
3565
|
+
debugLog('log', 'exist pendingRemeasureIndics: ', pendingRemeasureIndics, 'will try to update virtual viewport');
|
|
3531
3566
|
}
|
|
3532
|
-
return intersectedSelection;
|
|
3533
3567
|
}
|
|
3534
|
-
|
|
3568
|
+
pendingRemeasureIndics = [];
|
|
3569
|
+
});
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
getChangedIndics(previousValue) {
|
|
3573
|
+
const remeasureIndics = [];
|
|
3574
|
+
this.inViewportChildren.forEach((child, index) => {
|
|
3575
|
+
if (previousValue.indexOf(child) === -1) {
|
|
3576
|
+
remeasureIndics.push(this.inViewportIndics[index]);
|
|
3535
3577
|
}
|
|
3578
|
+
});
|
|
3579
|
+
return remeasureIndics;
|
|
3580
|
+
}
|
|
3581
|
+
setVirtualSpaceHeight(topHeight, bottomHeight) {
|
|
3582
|
+
if (!this.virtualScrollInitialized) {
|
|
3583
|
+
return;
|
|
3584
|
+
}
|
|
3585
|
+
this.virtualTopHeightElement.style.height = `${topHeight}px`;
|
|
3586
|
+
if (bottomHeight !== undefined) {
|
|
3587
|
+
this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
|
|
3536
3588
|
}
|
|
3537
|
-
EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
|
|
3538
|
-
return selection;
|
|
3539
3589
|
}
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
return !anchorElement || !focusElement || !this.editor.isVisible(anchorElement) || !this.editor.isVisible(focusElement);
|
|
3590
|
+
getActualVirtualTopHeight() {
|
|
3591
|
+
if (!this.virtualScrollInitialized) {
|
|
3592
|
+
return 0;
|
|
3593
|
+
}
|
|
3594
|
+
return parseFloat(this.virtualTopHeightElement.style.height.replace('px', ''));
|
|
3546
3595
|
}
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
const
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
const hasDomSelection = domSelection.type !== 'None';
|
|
3560
|
-
// If the DOM selection is properly unset, we're done.
|
|
3561
|
-
if (!selection && !hasDomSelection) {
|
|
3562
|
-
return;
|
|
3596
|
+
handlePreRendering(visibleStates) {
|
|
3597
|
+
let preRenderingCount = 0;
|
|
3598
|
+
const childrenWithPreRendering = [...this.inViewportChildren];
|
|
3599
|
+
const childrenWithPreRenderingIndics = [...this.inViewportIndics];
|
|
3600
|
+
const firstIndex = this.inViewportIndics[0];
|
|
3601
|
+
for (let index = firstIndex - 1; index >= 0; index--) {
|
|
3602
|
+
const element = this.editor.children[index];
|
|
3603
|
+
if (visibleStates[index]) {
|
|
3604
|
+
childrenWithPreRendering.unshift(element);
|
|
3605
|
+
childrenWithPreRenderingIndics.unshift(index);
|
|
3606
|
+
preRenderingCount = 1;
|
|
3607
|
+
break;
|
|
3563
3608
|
}
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
if (
|
|
3569
|
-
|
|
3609
|
+
}
|
|
3610
|
+
const lastIndex = this.inViewportIndics[this.inViewportIndics.length - 1];
|
|
3611
|
+
for (let index = lastIndex + 1; index < this.editor.children.length; index++) {
|
|
3612
|
+
const element = this.editor.children[index];
|
|
3613
|
+
if (visibleStates[index]) {
|
|
3614
|
+
childrenWithPreRendering.push(element);
|
|
3615
|
+
childrenWithPreRenderingIndics.push(index);
|
|
3616
|
+
break;
|
|
3570
3617
|
}
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3618
|
+
}
|
|
3619
|
+
return { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics };
|
|
3620
|
+
}
|
|
3621
|
+
tryUpdateVirtualViewport() {
|
|
3622
|
+
if (isDebug) {
|
|
3623
|
+
debugLog('log', 'tryUpdateVirtualViewport');
|
|
3624
|
+
}
|
|
3625
|
+
const isFromScrollTo = EDITOR_TO_IS_FROM_SCROLL_TO.get(this.editor);
|
|
3626
|
+
if (this.inViewportIndics.length > 0 && !isFromScrollTo) {
|
|
3627
|
+
const topHeight = this.getActualVirtualTopHeight();
|
|
3628
|
+
const visibleStates = this.editor.getAllVisibleStates();
|
|
3629
|
+
const refreshVirtualTopHeight = calculateVirtualTopHeight(this.editor, this.inViewportIndics[0], visibleStates);
|
|
3630
|
+
if (topHeight !== refreshVirtualTopHeight) {
|
|
3631
|
+
if (isDebug) {
|
|
3632
|
+
debugLog('log', 'update top height since dirty state(正数减去高度,负数代表增加高度): ', topHeight - refreshVirtualTopHeight);
|
|
3579
3633
|
}
|
|
3580
|
-
|
|
3581
|
-
// prevent updating native selection when active element is void element
|
|
3582
|
-
if (isTargetInsideVoid(this.editor, activeElement)) {
|
|
3634
|
+
this.setVirtualSpaceHeight(refreshVirtualTopHeight);
|
|
3583
3635
|
return;
|
|
3584
3636
|
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3591
|
-
return;
|
|
3637
|
+
}
|
|
3638
|
+
this.tryUpdateVirtualViewportAnimId && cancelAnimationFrame(this.tryUpdateVirtualViewportAnimId);
|
|
3639
|
+
this.tryUpdateVirtualViewportAnimId = requestAnimationFrame(() => {
|
|
3640
|
+
if (isDebug) {
|
|
3641
|
+
debugLog('log', 'tryUpdateVirtualViewport Anim start');
|
|
3592
3642
|
}
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
|
|
3643
|
+
const visibleStates = this.editor.getAllVisibleStates();
|
|
3644
|
+
let virtualView = this.calculateVirtualViewport(visibleStates);
|
|
3645
|
+
let diff = this.diffVirtualViewport(virtualView);
|
|
3646
|
+
if (diff.isDifferent && diff.needRemoveOnTop && !isFromScrollTo) {
|
|
3647
|
+
const remeasureIndics = diff.changedIndexesOfTop;
|
|
3648
|
+
const changed = measureHeightByIndics(this.editor, remeasureIndics);
|
|
3649
|
+
if (changed) {
|
|
3650
|
+
virtualView = this.calculateVirtualViewport(visibleStates);
|
|
3651
|
+
diff = this.diffVirtualViewport(virtualView, 'second');
|
|
3603
3652
|
}
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3653
|
+
}
|
|
3654
|
+
if (diff.isDifferent) {
|
|
3655
|
+
this.applyVirtualView(virtualView);
|
|
3656
|
+
if (this.listRender.initialized) {
|
|
3657
|
+
const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
|
|
3658
|
+
this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
|
|
3659
|
+
if (diff.needAddOnTop && !isFromScrollTo) {
|
|
3660
|
+
const remeasureAddedIndics = diff.changedIndexesOfTop;
|
|
3661
|
+
if (isDebug) {
|
|
3662
|
+
debugLog('log', 'needAddOnTop to remeasure heights: ', remeasureAddedIndics);
|
|
3663
|
+
}
|
|
3664
|
+
const startIndexBeforeAdd = diff.changedIndexesOfTop[diff.changedIndexesOfTop.length - 1] + 1;
|
|
3665
|
+
const topHeightBeforeAdd = virtualView.accumulatedHeights[startIndexBeforeAdd];
|
|
3666
|
+
const changed = measureHeightByIndics(this.editor, remeasureAddedIndics);
|
|
3667
|
+
if (changed) {
|
|
3668
|
+
const newHeights = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
|
|
3669
|
+
const actualTopHeightAfterAdd = newHeights.accumulatedHeights[startIndexBeforeAdd];
|
|
3670
|
+
const newTopHeight = virtualView.top - (actualTopHeightAfterAdd - topHeightBeforeAdd);
|
|
3671
|
+
this.setVirtualSpaceHeight(newTopHeight);
|
|
3672
|
+
if (isDebug) {
|
|
3673
|
+
debugLog('log', `update top height since will add element in top(正数减去高度,负数代表增加高度): ${actualTopHeightAfterAdd - topHeightBeforeAdd}`);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
if (this.editor.selection) {
|
|
3678
|
+
this.toNativeSelection(false);
|
|
3679
|
+
}
|
|
3607
3680
|
}
|
|
3608
3681
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3682
|
+
if (isDebug) {
|
|
3683
|
+
debugLog('log', 'tryUpdateVirtualViewport Anim end');
|
|
3611
3684
|
}
|
|
3612
|
-
|
|
3613
|
-
if (this.isEnabledVirtualScroll() &&
|
|
3614
|
-
!selection &&
|
|
3615
|
-
this.editor.selection &&
|
|
3616
|
-
autoScroll &&
|
|
3617
|
-
this.virtualScrollConfig.scrollContainer) {
|
|
3618
|
-
this.virtualScrollConfig.scrollContainer.scrollTop = this.virtualScrollConfig.scrollContainer.scrollTop + 100;
|
|
3619
|
-
this.isUpdatingSelection = false;
|
|
3620
|
-
return;
|
|
3621
|
-
}
|
|
3622
|
-
else {
|
|
3623
|
-
// handle scrolling in setTimeout because of
|
|
3624
|
-
// dom should not have updated immediately after listRender's updating
|
|
3625
|
-
newDomRange && autoScroll && this.scrollSelectionIntoView(this.editor, newDomRange);
|
|
3626
|
-
// COMPAT: In Firefox, it's not enough to create a range, you also need
|
|
3627
|
-
// to focus the contenteditable element too. (2016/11/16)
|
|
3628
|
-
if (newDomRange && IS_FIREFOX) {
|
|
3629
|
-
el.focus();
|
|
3630
|
-
}
|
|
3631
|
-
}
|
|
3632
|
-
this.isUpdatingSelection = false;
|
|
3633
|
-
});
|
|
3634
|
-
}
|
|
3635
|
-
catch (error) {
|
|
3636
|
-
this.editor.onError({
|
|
3637
|
-
code: SlateErrorCode.ToNativeSelectionError,
|
|
3638
|
-
nativeError: error
|
|
3639
|
-
});
|
|
3640
|
-
this.isUpdatingSelection = false;
|
|
3641
|
-
}
|
|
3642
|
-
}
|
|
3643
|
-
onChange() {
|
|
3644
|
-
this.forceRender();
|
|
3645
|
-
this.onChangeCallback(this.editor.children);
|
|
3685
|
+
});
|
|
3646
3686
|
}
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3687
|
+
calculateVirtualViewport(visibleStates) {
|
|
3688
|
+
const children = (this.editor.children || []);
|
|
3689
|
+
if (!children.length || !this.isEnabledVirtualScroll()) {
|
|
3690
|
+
return {
|
|
3691
|
+
inViewportChildren: children,
|
|
3692
|
+
inViewportIndics: [],
|
|
3693
|
+
top: 0,
|
|
3694
|
+
bottom: 0,
|
|
3695
|
+
heights: []
|
|
3696
|
+
};
|
|
3653
3697
|
}
|
|
3654
|
-
|
|
3655
|
-
|
|
3698
|
+
const scrollTop = this.virtualScrollConfig.scrollTop;
|
|
3699
|
+
let viewportHeight = this.virtualScrollConfig.viewportHeight ?? 0;
|
|
3700
|
+
if (!viewportHeight) {
|
|
3701
|
+
return {
|
|
3702
|
+
inViewportChildren: [],
|
|
3703
|
+
inViewportIndics: [],
|
|
3704
|
+
top: 0,
|
|
3705
|
+
bottom: 0,
|
|
3706
|
+
heights: []
|
|
3707
|
+
};
|
|
3656
3708
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
// so isComposing needs to be corrected
|
|
3661
|
-
// need exec after this.cdr.detectChanges() to render HTML
|
|
3662
|
-
// need exec before this.toNativeSelection() to correct native selection
|
|
3663
|
-
if (this.isComposing) {
|
|
3664
|
-
// Composition input text be not rendered when user composition input with selection is expanded
|
|
3665
|
-
// At this time, the following matching conditions are met, assign isComposing to false, and the status is wrong
|
|
3666
|
-
// this time condition is true and isComposing is assigned false
|
|
3667
|
-
// Therefore, need to wait for the composition input text to be rendered before performing condition matching
|
|
3709
|
+
const elementLength = children.length;
|
|
3710
|
+
if (!EDITOR_TO_BUSINESS_TOP.has(this.editor)) {
|
|
3711
|
+
EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
|
|
3668
3712
|
setTimeout(() => {
|
|
3669
|
-
const
|
|
3670
|
-
const
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
if (text.startsWith(zeroChar)) {
|
|
3678
|
-
text = text.slice(1);
|
|
3679
|
-
}
|
|
3680
|
-
if (text.endsWith(zeroChar)) {
|
|
3681
|
-
text = text.slice(0, text.length - 1);
|
|
3682
|
-
}
|
|
3683
|
-
textContent += text;
|
|
3684
|
-
});
|
|
3685
|
-
if (Node.string(textNode).endsWith(textContent)) {
|
|
3686
|
-
this.isComposing = false;
|
|
3713
|
+
const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
|
|
3714
|
+
const businessTop = Math.ceil(virtualTopBoundingTop) +
|
|
3715
|
+
Math.ceil(this.virtualScrollConfig.scrollTop) -
|
|
3716
|
+
Math.floor(this.virtualScrollConfig.viewportBoundingTop);
|
|
3717
|
+
EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
|
|
3718
|
+
if (isDebug) {
|
|
3719
|
+
debugLog('log', 'businessTop', businessTop);
|
|
3720
|
+
this.virtualTopHeightElement.setAttribute('data-business-top', businessTop.toString());
|
|
3687
3721
|
}
|
|
3688
|
-
},
|
|
3689
|
-
}
|
|
3690
|
-
if (this.editor.selection && this.isSelectionInvisible(this.editor.selection)) {
|
|
3691
|
-
Transforms.deselect(this.editor);
|
|
3692
|
-
return;
|
|
3722
|
+
}, 100);
|
|
3693
3723
|
}
|
|
3694
|
-
|
|
3695
|
-
|
|
3724
|
+
const businessTop = getBusinessTop(this.editor);
|
|
3725
|
+
const { heights, accumulatedHeights } = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
|
|
3726
|
+
const totalHeight = accumulatedHeights[elementLength] + businessTop;
|
|
3727
|
+
let startPosition = Math.max(scrollTop - businessTop, 0);
|
|
3728
|
+
let endPosition = startPosition + viewportHeight;
|
|
3729
|
+
if (scrollTop < businessTop) {
|
|
3730
|
+
endPosition = startPosition + viewportHeight - (businessTop - scrollTop);
|
|
3696
3731
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
const
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3732
|
+
let accumulatedOffset = 0;
|
|
3733
|
+
let inViewportStartIndex = -1;
|
|
3734
|
+
const visible = [];
|
|
3735
|
+
const inViewportIndics = [];
|
|
3736
|
+
for (let i = 0; i < elementLength && accumulatedOffset < endPosition; i++) {
|
|
3737
|
+
const currentHeight = heights[i];
|
|
3738
|
+
const nextOffset = accumulatedOffset + currentHeight;
|
|
3739
|
+
const isVisible = visibleStates[i];
|
|
3740
|
+
if (!isVisible) {
|
|
3741
|
+
accumulatedOffset = nextOffset;
|
|
3742
|
+
continue;
|
|
3703
3743
|
}
|
|
3704
|
-
|
|
3705
|
-
|
|
3744
|
+
// 可视区域有交集,加入渲染
|
|
3745
|
+
if (nextOffset > startPosition && accumulatedOffset < endPosition) {
|
|
3746
|
+
if (inViewportStartIndex === -1)
|
|
3747
|
+
inViewportStartIndex = i; // 第一个相交起始位置
|
|
3748
|
+
visible.push(children[i]);
|
|
3749
|
+
inViewportIndics.push(i);
|
|
3706
3750
|
}
|
|
3751
|
+
accumulatedOffset = nextOffset;
|
|
3707
3752
|
}
|
|
3753
|
+
const inViewportEndIndex = inViewportStartIndex === -1 ? elementLength - 1 : (inViewportIndics[inViewportIndics.length - 1] ?? inViewportStartIndex);
|
|
3754
|
+
const top = inViewportStartIndex === -1 ? 0 : accumulatedHeights[inViewportStartIndex];
|
|
3755
|
+
const bottom = totalHeight - accumulatedHeights[inViewportEndIndex + 1];
|
|
3756
|
+
return {
|
|
3757
|
+
inViewportChildren: visible.length ? visible : children,
|
|
3758
|
+
inViewportIndics,
|
|
3759
|
+
top,
|
|
3760
|
+
bottom,
|
|
3761
|
+
heights,
|
|
3762
|
+
accumulatedHeights
|
|
3763
|
+
};
|
|
3708
3764
|
}
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
virtualView = this.calculateVirtualViewport(visibleStates);
|
|
3719
|
-
diff = this.diffVirtualViewport(virtualView, 'second');
|
|
3765
|
+
applyVirtualView(virtualView) {
|
|
3766
|
+
this.inViewportChildren = virtualView.inViewportChildren;
|
|
3767
|
+
this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
|
|
3768
|
+
this.inViewportIndics = virtualView.inViewportIndics;
|
|
3769
|
+
}
|
|
3770
|
+
diffVirtualViewport(virtualView, stage = 'first') {
|
|
3771
|
+
if (!this.inViewportChildren.length) {
|
|
3772
|
+
if (isDebug) {
|
|
3773
|
+
debugLog('log', 'diffVirtualViewport', stage, 'empty inViewportChildren', virtualView.inViewportIndics);
|
|
3720
3774
|
}
|
|
3775
|
+
return {
|
|
3776
|
+
isDifferent: true,
|
|
3777
|
+
changedIndexesOfTop: [],
|
|
3778
|
+
changedIndexesOfBottom: []
|
|
3779
|
+
};
|
|
3721
3780
|
}
|
|
3722
|
-
this.
|
|
3723
|
-
const
|
|
3724
|
-
|
|
3725
|
-
const
|
|
3726
|
-
|
|
3727
|
-
|
|
3781
|
+
const oldIndexesInViewport = [...this.inViewportIndics];
|
|
3782
|
+
const newIndexesInViewport = [...virtualView.inViewportIndics];
|
|
3783
|
+
const firstNewIndex = newIndexesInViewport[0];
|
|
3784
|
+
const lastNewIndex = newIndexesInViewport[newIndexesInViewport.length - 1];
|
|
3785
|
+
const firstOldIndex = oldIndexesInViewport[0];
|
|
3786
|
+
const lastOldIndex = oldIndexesInViewport[oldIndexesInViewport.length - 1];
|
|
3787
|
+
const isSameViewport = oldIndexesInViewport.length === newIndexesInViewport.length &&
|
|
3788
|
+
oldIndexesInViewport.every((index, i) => index === newIndexesInViewport[i]);
|
|
3789
|
+
if (firstNewIndex === firstOldIndex && lastNewIndex === lastOldIndex) {
|
|
3790
|
+
return {
|
|
3791
|
+
isDifferent: !isSameViewport,
|
|
3792
|
+
changedIndexesOfTop: [],
|
|
3793
|
+
changedIndexesOfBottom: []
|
|
3794
|
+
};
|
|
3728
3795
|
}
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3796
|
+
if (firstNewIndex !== firstOldIndex || lastNewIndex !== lastOldIndex) {
|
|
3797
|
+
const changedIndexesOfTop = [];
|
|
3798
|
+
const changedIndexesOfBottom = [];
|
|
3799
|
+
const needRemoveOnTop = firstNewIndex !== firstOldIndex && firstNewIndex > firstOldIndex;
|
|
3800
|
+
const needAddOnTop = firstNewIndex !== firstOldIndex && firstNewIndex < firstOldIndex;
|
|
3801
|
+
const needRemoveOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex > lastNewIndex;
|
|
3802
|
+
const needAddOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex < lastNewIndex;
|
|
3803
|
+
if (needRemoveOnTop || needAddOnBottom) {
|
|
3804
|
+
// 向下
|
|
3805
|
+
for (let index = 0; index < oldIndexesInViewport.length; index++) {
|
|
3806
|
+
const element = oldIndexesInViewport[index];
|
|
3807
|
+
if (!newIndexesInViewport.includes(element)) {
|
|
3808
|
+
changedIndexesOfTop.push(element);
|
|
3809
|
+
}
|
|
3810
|
+
else {
|
|
3811
|
+
break;
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
for (let index = newIndexesInViewport.length - 1; index >= 0; index--) {
|
|
3815
|
+
const element = newIndexesInViewport[index];
|
|
3816
|
+
if (!oldIndexesInViewport.includes(element)) {
|
|
3817
|
+
changedIndexesOfBottom.push(element);
|
|
3818
|
+
}
|
|
3819
|
+
else {
|
|
3820
|
+
break;
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
else if (needAddOnTop || needRemoveOnBottom) {
|
|
3825
|
+
// 向上
|
|
3826
|
+
for (let index = 0; index < newIndexesInViewport.length; index++) {
|
|
3827
|
+
const element = newIndexesInViewport[index];
|
|
3828
|
+
if (!oldIndexesInViewport.includes(element)) {
|
|
3829
|
+
changedIndexesOfTop.push(element);
|
|
3830
|
+
}
|
|
3831
|
+
else {
|
|
3832
|
+
break;
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
for (let index = oldIndexesInViewport.length - 1; index >= 0; index--) {
|
|
3836
|
+
const element = oldIndexesInViewport[index];
|
|
3837
|
+
if (!newIndexesInViewport.includes(element)) {
|
|
3838
|
+
changedIndexesOfBottom.push(element);
|
|
3839
|
+
}
|
|
3840
|
+
else {
|
|
3841
|
+
break;
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
if (isDebug) {
|
|
3846
|
+
debugLog('log', `====== diffVirtualViewport stage: ${stage} ======`);
|
|
3847
|
+
debugLog('log', 'oldIndexesInViewport:', oldIndexesInViewport);
|
|
3848
|
+
debugLog('log', 'newIndexesInViewport:', newIndexesInViewport);
|
|
3849
|
+
// this.editor.children[index] will be undefined when it is removed
|
|
3850
|
+
debugLog('log', 'changedIndexesOfTop:', needRemoveOnTop ? '-' : needAddOnTop ? '+' : '-', changedIndexesOfTop, changedIndexesOfTop.map(index => (this.editor.children[index] &&
|
|
3851
|
+
getCachedHeightByElement(this.editor, this.editor.children[index])) ||
|
|
3852
|
+
0));
|
|
3853
|
+
debugLog('log', 'changedIndexesOfBottom:', needAddOnBottom ? '+' : needRemoveOnBottom ? '-' : '+', changedIndexesOfBottom, changedIndexesOfBottom.map(index => (this.editor.children[index] &&
|
|
3854
|
+
getCachedHeightByElement(this.editor, this.editor.children[index])) ||
|
|
3855
|
+
0));
|
|
3856
|
+
const needTop = virtualView.heights.slice(0, newIndexesInViewport[0]).reduce((acc, height) => acc + height, 0);
|
|
3857
|
+
const needBottom = virtualView.heights
|
|
3858
|
+
.slice(newIndexesInViewport[newIndexesInViewport.length - 1] + 1)
|
|
3859
|
+
.reduce((acc, height) => acc + height, 0);
|
|
3860
|
+
debugLog('log', needTop - parseFloat(this.virtualTopHeightElement.style.height), 'newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
|
|
3861
|
+
debugLog('log', 'newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
|
|
3862
|
+
debugLog('warn', '=========== Dividing line ===========');
|
|
3863
|
+
}
|
|
3864
|
+
return {
|
|
3865
|
+
isDifferent: true,
|
|
3866
|
+
needRemoveOnTop,
|
|
3867
|
+
needAddOnTop,
|
|
3868
|
+
needRemoveOnBottom,
|
|
3869
|
+
needAddOnBottom,
|
|
3870
|
+
changedIndexesOfTop,
|
|
3871
|
+
changedIndexesOfBottom
|
|
3742
3872
|
};
|
|
3743
|
-
return true;
|
|
3744
3873
|
}
|
|
3745
|
-
return
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
parent: this.editor,
|
|
3750
|
-
selection: this.editor.selection,
|
|
3751
|
-
decorations: this.generateDecorations(),
|
|
3752
|
-
decorate: this.decorate,
|
|
3753
|
-
readonly: this.readonly
|
|
3874
|
+
return {
|
|
3875
|
+
isDifferent: false,
|
|
3876
|
+
changedIndexesOfTop: [],
|
|
3877
|
+
changedIndexesOfBottom: []
|
|
3754
3878
|
};
|
|
3755
3879
|
}
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
};
|
|
3880
|
+
//#region event proxy
|
|
3881
|
+
addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
|
|
3882
|
+
this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
|
|
3883
|
+
const beforeInputEvent = extractBeforeInputEvent(event.type, null, event, event.target);
|
|
3884
|
+
if (beforeInputEvent) {
|
|
3885
|
+
this.onFallbackBeforeInput(beforeInputEvent);
|
|
3886
|
+
}
|
|
3887
|
+
listener(event);
|
|
3888
|
+
}));
|
|
3765
3889
|
}
|
|
3766
|
-
|
|
3767
|
-
if (
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3890
|
+
calculateVirtualScrollSelection(selection) {
|
|
3891
|
+
if (selection) {
|
|
3892
|
+
const isBlockCardCursor = AngularEditor.isBlockCardLeftCursor(this.editor) || AngularEditor.isBlockCardRightCursor(this.editor);
|
|
3893
|
+
const indics = this.inViewportIndics;
|
|
3894
|
+
if (indics.length > 0) {
|
|
3895
|
+
const currentVisibleRange = {
|
|
3896
|
+
anchor: Editor.start(this.editor, [indics[0]]),
|
|
3897
|
+
focus: Editor.end(this.editor, [indics[indics.length - 1]])
|
|
3898
|
+
};
|
|
3899
|
+
const [start, end] = Range.edges(selection);
|
|
3900
|
+
let forwardSelection = { anchor: start, focus: end };
|
|
3901
|
+
if (!isBlockCardCursor) {
|
|
3902
|
+
forwardSelection = { anchor: start, focus: end };
|
|
3777
3903
|
}
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
else {
|
|
3781
|
-
return [];
|
|
3782
|
-
}
|
|
3783
|
-
}
|
|
3784
|
-
generateDecorations() {
|
|
3785
|
-
const decorations = this.decorate([this.editor, []]);
|
|
3786
|
-
const placeholderDecorations = this.isComposing ? [] : this.composePlaceholderDecorate(this.editor);
|
|
3787
|
-
decorations.push(...placeholderDecorations);
|
|
3788
|
-
return decorations;
|
|
3789
|
-
}
|
|
3790
|
-
isEnabledVirtualScroll() {
|
|
3791
|
-
return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
|
|
3792
|
-
}
|
|
3793
|
-
initializeVirtualScroll() {
|
|
3794
|
-
if (this.virtualScrollInitialized) {
|
|
3795
|
-
return;
|
|
3796
|
-
}
|
|
3797
|
-
if (this.isEnabledVirtualScroll()) {
|
|
3798
|
-
this.virtualScrollInitialized = true;
|
|
3799
|
-
this.virtualTopHeightElement = document.createElement('div');
|
|
3800
|
-
this.virtualTopHeightElement.classList.add('virtual-top-height');
|
|
3801
|
-
this.virtualTopHeightElement.contentEditable = 'false';
|
|
3802
|
-
this.virtualBottomHeightElement = document.createElement('div');
|
|
3803
|
-
this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
|
|
3804
|
-
this.virtualBottomHeightElement.contentEditable = 'false';
|
|
3805
|
-
this.virtualCenterOutlet = document.createElement('div');
|
|
3806
|
-
this.virtualCenterOutlet.classList.add('virtual-center-outlet');
|
|
3807
|
-
this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
|
|
3808
|
-
this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
|
|
3809
|
-
this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
|
|
3810
|
-
let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect().width;
|
|
3811
|
-
EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, this.virtualTopHeightElement.offsetWidth);
|
|
3812
|
-
this.editorResizeObserver = new ResizeObserver(entries => {
|
|
3813
|
-
if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
|
|
3814
|
-
editorResizeObserverRectWidth = entries[0].contentRect.width;
|
|
3815
|
-
this.keyHeightMap.clear();
|
|
3816
|
-
let target = this.virtualTopHeightElement;
|
|
3817
|
-
if (this.inViewportChildren[0]) {
|
|
3818
|
-
const firstElement = this.inViewportChildren[0];
|
|
3819
|
-
const firstDomElement = AngularEditor.toDOMNode(this.editor, firstElement);
|
|
3820
|
-
target = firstDomElement;
|
|
3821
|
-
}
|
|
3822
|
-
EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, target.offsetWidth);
|
|
3823
|
-
updatePreRenderingElementWidth(this.editor);
|
|
3824
|
-
if (isDebug) {
|
|
3825
|
-
debugLog('log', 'editorResizeObserverRectWidth: ', editorResizeObserverRectWidth, 'EDITOR_TO_ROOT_NODE_WIDTH: ', EDITOR_TO_ROOT_NODE_WIDTH.get(this.editor));
|
|
3826
|
-
}
|
|
3904
|
+
else {
|
|
3905
|
+
forwardSelection = { anchor: { path: start.path, offset: 0 }, focus: { path: end.path, offset: 0 } };
|
|
3827
3906
|
}
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
.
|
|
3833
|
-
|
|
3834
|
-
if (
|
|
3835
|
-
|
|
3907
|
+
const intersectedSelection = Range.intersection(forwardSelection, currentVisibleRange);
|
|
3908
|
+
if (intersectedSelection && isBlockCardCursor) {
|
|
3909
|
+
return selection;
|
|
3910
|
+
}
|
|
3911
|
+
EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, intersectedSelection);
|
|
3912
|
+
if (!intersectedSelection || !Range.equals(intersectedSelection, forwardSelection)) {
|
|
3913
|
+
if (isDebug) {
|
|
3914
|
+
debugLog('log', `selection is not in visible range, selection: ${JSON.stringify(selection)}, currentVisibleRange: ${JSON.stringify(currentVisibleRange)}, intersectedSelection: ${JSON.stringify(intersectedSelection)}`);
|
|
3836
3915
|
}
|
|
3837
|
-
|
|
3838
|
-
}), debounceTime(500), filter(() => pendingRemeasureIndics.length > 0))
|
|
3839
|
-
.subscribe(() => {
|
|
3840
|
-
measureHeightByIndics(this.editor, pendingRemeasureIndics, true);
|
|
3841
|
-
pendingRemeasureIndics = [];
|
|
3842
|
-
if (isDebug) {
|
|
3843
|
-
debugLog('log', 'exist pendingRemeasureIndics: ', pendingRemeasureIndics, 'will try to update virtual viewport');
|
|
3916
|
+
return intersectedSelection;
|
|
3844
3917
|
}
|
|
3845
|
-
|
|
3846
|
-
});
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
getChangedIndics(previousValue) {
|
|
3850
|
-
const remeasureIndics = [];
|
|
3851
|
-
this.inViewportChildren.forEach((child, index) => {
|
|
3852
|
-
if (previousValue.indexOf(child) === -1) {
|
|
3853
|
-
remeasureIndics.push(this.inViewportIndics[index]);
|
|
3918
|
+
return selection;
|
|
3854
3919
|
}
|
|
3855
|
-
});
|
|
3856
|
-
return remeasureIndics;
|
|
3857
|
-
}
|
|
3858
|
-
setVirtualSpaceHeight(topHeight, bottomHeight) {
|
|
3859
|
-
if (!this.virtualScrollInitialized) {
|
|
3860
|
-
return;
|
|
3861
|
-
}
|
|
3862
|
-
this.virtualTopHeightElement.style.height = `${topHeight}px`;
|
|
3863
|
-
if (bottomHeight !== undefined) {
|
|
3864
|
-
this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
|
|
3865
3920
|
}
|
|
3921
|
+
EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
|
|
3922
|
+
return selection;
|
|
3866
3923
|
}
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3924
|
+
isSelectionInvisible(selection) {
|
|
3925
|
+
const anchorIndex = selection.anchor.path[0];
|
|
3926
|
+
const focusIndex = selection.focus.path[0];
|
|
3927
|
+
const anchorElement = this.editor.children[anchorIndex];
|
|
3928
|
+
const focusElement = this.editor.children[focusIndex];
|
|
3929
|
+
return !anchorElement || !focusElement || !this.editor.isVisible(anchorElement) || !this.editor.isVisible(focusElement);
|
|
3872
3930
|
}
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
for (let index = firstIndex - 1; index >= 0; index--) {
|
|
3879
|
-
const element = this.editor.children[index];
|
|
3880
|
-
if (visibleStates[index]) {
|
|
3881
|
-
childrenWithPreRendering.unshift(element);
|
|
3882
|
-
childrenWithPreRenderingIndics.unshift(index);
|
|
3883
|
-
preRenderingCount = 1;
|
|
3884
|
-
break;
|
|
3931
|
+
toNativeSelection(autoScroll = true) {
|
|
3932
|
+
try {
|
|
3933
|
+
let { selection } = this.editor;
|
|
3934
|
+
if (this.isEnabledVirtualScroll()) {
|
|
3935
|
+
selection = this.calculateVirtualScrollSelection(selection);
|
|
3885
3936
|
}
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
childrenWithPreRendering.push(element);
|
|
3892
|
-
childrenWithPreRenderingIndics.push(index);
|
|
3893
|
-
break;
|
|
3937
|
+
const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
|
|
3938
|
+
const { activeElement } = root;
|
|
3939
|
+
const domSelection = root.getSelection();
|
|
3940
|
+
if ((this.isComposing && !IS_ANDROID) || !domSelection) {
|
|
3941
|
+
return;
|
|
3894
3942
|
}
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
tryUpdateVirtualViewport() {
|
|
3899
|
-
if (isDebug) {
|
|
3900
|
-
debugLog('log', 'tryUpdateVirtualViewport');
|
|
3901
|
-
}
|
|
3902
|
-
const isFromScrollTo = EDITOR_TO_IS_FROM_SCROLL_TO.get(this.editor);
|
|
3903
|
-
if (this.inViewportIndics.length > 0 && !isFromScrollTo) {
|
|
3904
|
-
const topHeight = this.getActualVirtualTopHeight();
|
|
3905
|
-
const visibleStates = this.editor.getAllVisibleStates();
|
|
3906
|
-
const refreshVirtualTopHeight = calculateVirtualTopHeight(this.editor, this.inViewportIndics[0], visibleStates);
|
|
3907
|
-
if (topHeight !== refreshVirtualTopHeight) {
|
|
3908
|
-
if (isDebug) {
|
|
3909
|
-
debugLog('log', 'update top height since dirty state(正数减去高度,负数代表增加高度): ', topHeight - refreshVirtualTopHeight);
|
|
3910
|
-
}
|
|
3911
|
-
this.setVirtualSpaceHeight(refreshVirtualTopHeight);
|
|
3943
|
+
const hasDomSelection = domSelection.type !== 'None';
|
|
3944
|
+
// If the DOM selection is properly unset, we're done.
|
|
3945
|
+
if (!selection && !hasDomSelection) {
|
|
3912
3946
|
return;
|
|
3913
3947
|
}
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3948
|
+
// If the DOM selection is already correct, we're done.
|
|
3949
|
+
// verify that the dom selection is in the editor
|
|
3950
|
+
const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
|
|
3951
|
+
let hasDomSelectionInEditor = false;
|
|
3952
|
+
if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
|
|
3953
|
+
hasDomSelectionInEditor = true;
|
|
3919
3954
|
}
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
if (
|
|
3927
|
-
|
|
3928
|
-
diff = this.diffVirtualViewport(virtualView, 'second');
|
|
3955
|
+
// If the DOM selection is in the editor and the editor selection is already correct, we're done.
|
|
3956
|
+
if (hasDomSelection && hasDomSelectionInEditor && selection && hasStringTarget(domSelection)) {
|
|
3957
|
+
const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
|
|
3958
|
+
exactMatch: false,
|
|
3959
|
+
suppressThrow: true
|
|
3960
|
+
});
|
|
3961
|
+
if (rangeFromDOMSelection && Range.equals(rangeFromDOMSelection, selection)) {
|
|
3962
|
+
return;
|
|
3929
3963
|
}
|
|
3930
3964
|
}
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3965
|
+
// prevent updating native selection when active element is void element
|
|
3966
|
+
if (isTargetInsideVoid(this.editor, activeElement)) {
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
// when <Editable/> is being controlled through external value
|
|
3970
|
+
// then its children might just change - DOM responds to it on its own
|
|
3971
|
+
// but Slate's value is not being updated through any operation
|
|
3972
|
+
// and thus it doesn't transform selection on its own
|
|
3973
|
+
if (selection && !AngularEditor.hasRange(this.editor, selection)) {
|
|
3974
|
+
this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
|
|
3975
|
+
return;
|
|
3976
|
+
}
|
|
3977
|
+
// Otherwise the DOM selection is out of sync, so update it.
|
|
3978
|
+
const el = AngularEditor.toDOMNode(this.editor, this.editor);
|
|
3979
|
+
this.isUpdatingSelection = true;
|
|
3980
|
+
const newDomRange = selection && AngularEditor.toDOMRange(this.editor, selection);
|
|
3981
|
+
if (newDomRange) {
|
|
3982
|
+
// COMPAT: Since the DOM range has no concept of backwards/forwards
|
|
3983
|
+
// we need to check and do the right thing here.
|
|
3984
|
+
if (Range.isBackward(selection)) {
|
|
3985
|
+
// eslint-disable-next-line max-len
|
|
3986
|
+
domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
|
|
3987
|
+
}
|
|
3988
|
+
else {
|
|
3989
|
+
// eslint-disable-next-line max-len
|
|
3990
|
+
domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
|
|
3957
3991
|
}
|
|
3958
3992
|
}
|
|
3959
|
-
|
|
3960
|
-
|
|
3993
|
+
else {
|
|
3994
|
+
domSelection.removeAllRanges();
|
|
3961
3995
|
}
|
|
3962
|
-
|
|
3996
|
+
setTimeout(() => {
|
|
3997
|
+
if (this.isEnabledVirtualScroll() &&
|
|
3998
|
+
!selection &&
|
|
3999
|
+
this.editor.selection &&
|
|
4000
|
+
autoScroll &&
|
|
4001
|
+
this.virtualScrollConfig.scrollContainer) {
|
|
4002
|
+
this.virtualScrollConfig.scrollContainer.scrollTop = this.virtualScrollConfig.scrollContainer.scrollTop + 100;
|
|
4003
|
+
this.isUpdatingSelection = false;
|
|
4004
|
+
return;
|
|
4005
|
+
}
|
|
4006
|
+
else {
|
|
4007
|
+
// handle scrolling in setTimeout because of
|
|
4008
|
+
// dom should not have updated immediately after listRender's updating
|
|
4009
|
+
newDomRange && autoScroll && this.scrollSelectionIntoView(this.editor, newDomRange);
|
|
4010
|
+
// COMPAT: In Firefox, it's not enough to create a range, you also need
|
|
4011
|
+
// to focus the contenteditable element too. (2016/11/16)
|
|
4012
|
+
if (newDomRange && IS_FIREFOX) {
|
|
4013
|
+
el.focus();
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
this.isUpdatingSelection = false;
|
|
4017
|
+
});
|
|
4018
|
+
}
|
|
4019
|
+
catch (error) {
|
|
4020
|
+
this.editor.onError({
|
|
4021
|
+
code: SlateErrorCode.ToNativeSelectionError,
|
|
4022
|
+
nativeError: error
|
|
4023
|
+
});
|
|
4024
|
+
this.isUpdatingSelection = false;
|
|
4025
|
+
}
|
|
3963
4026
|
}
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
4027
|
+
onChange() {
|
|
4028
|
+
this.forceRender();
|
|
4029
|
+
this.onChangeCallback(this.editor.children);
|
|
4030
|
+
}
|
|
4031
|
+
ngAfterViewChecked() { }
|
|
4032
|
+
ngDoCheck() { }
|
|
4033
|
+
forceRender() {
|
|
4034
|
+
this.updateContext();
|
|
4035
|
+
if (this.isEnabledVirtualScroll()) {
|
|
4036
|
+
this.updateListRenderAndRemeasureHeights();
|
|
4037
|
+
}
|
|
4038
|
+
else {
|
|
4039
|
+
this.listRender.update(this.editor.children, this.editor, this.context);
|
|
4040
|
+
}
|
|
4041
|
+
// repair collaborative editing when Chinese input is interrupted by other users' cursors
|
|
4042
|
+
// when the DOMElement where the selection is located is removed
|
|
4043
|
+
// the compositionupdate and compositionend events will no longer be fired
|
|
4044
|
+
// so isComposing needs to be corrected
|
|
4045
|
+
// need exec after this.cdr.detectChanges() to render HTML
|
|
4046
|
+
// need exec before this.toNativeSelection() to correct native selection
|
|
4047
|
+
if (this.isComposing) {
|
|
4048
|
+
// Composition input text be not rendered when user composition input with selection is expanded
|
|
4049
|
+
// At this time, the following matching conditions are met, assign isComposing to false, and the status is wrong
|
|
4050
|
+
// this time condition is true and isComposing is assigned false
|
|
4051
|
+
// Therefore, need to wait for the composition input text to be rendered before performing condition matching
|
|
4052
|
+
setTimeout(() => {
|
|
4053
|
+
const textNode = Node.get(this.editor, this.editor.selection.anchor.path);
|
|
4054
|
+
const textDOMNode = AngularEditor.toDOMNode(this.editor, textNode);
|
|
4055
|
+
let textContent = '';
|
|
4056
|
+
// skip decorate text
|
|
4057
|
+
textDOMNode.querySelectorAll('[editable-text]').forEach(stringDOMNode => {
|
|
4058
|
+
let text = stringDOMNode.textContent;
|
|
4059
|
+
const zeroChar = '\uFEFF';
|
|
4060
|
+
// remove zero with char
|
|
4061
|
+
if (text.startsWith(zeroChar)) {
|
|
4062
|
+
text = text.slice(1);
|
|
4063
|
+
}
|
|
4064
|
+
if (text.endsWith(zeroChar)) {
|
|
4065
|
+
text = text.slice(0, text.length - 1);
|
|
4066
|
+
}
|
|
4067
|
+
textContent += text;
|
|
4068
|
+
});
|
|
4069
|
+
if (Node.string(textNode).endsWith(textContent)) {
|
|
4070
|
+
this.isComposing = false;
|
|
4071
|
+
}
|
|
4072
|
+
}, 0);
|
|
3974
4073
|
}
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
return {
|
|
3979
|
-
inViewportChildren: [],
|
|
3980
|
-
inViewportIndics: [],
|
|
3981
|
-
top: 0,
|
|
3982
|
-
bottom: 0,
|
|
3983
|
-
heights: []
|
|
3984
|
-
};
|
|
4074
|
+
if (this.editor.selection && this.isSelectionInvisible(this.editor.selection)) {
|
|
4075
|
+
Transforms.deselect(this.editor);
|
|
4076
|
+
return;
|
|
3985
4077
|
}
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
|
|
3989
|
-
setTimeout(() => {
|
|
3990
|
-
const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
|
|
3991
|
-
const businessTop = Math.ceil(virtualTopBoundingTop) +
|
|
3992
|
-
Math.ceil(this.virtualScrollConfig.scrollTop) -
|
|
3993
|
-
Math.floor(this.virtualScrollConfig.viewportBoundingTop);
|
|
3994
|
-
EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
|
|
3995
|
-
if (isDebug) {
|
|
3996
|
-
debugLog('log', 'businessTop', businessTop);
|
|
3997
|
-
}
|
|
3998
|
-
}, 100);
|
|
4078
|
+
else {
|
|
4079
|
+
this.toNativeSelection();
|
|
3999
4080
|
}
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
const
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
let accumulatedOffset = 0;
|
|
4007
|
-
let inViewportStartIndex = -1;
|
|
4008
|
-
const visible = [];
|
|
4009
|
-
const inViewportIndics = [];
|
|
4010
|
-
for (let i = 0; i < elementLength && accumulatedOffset < viewBottom; i++) {
|
|
4011
|
-
const currentHeight = heights[i];
|
|
4012
|
-
const nextOffset = accumulatedOffset + currentHeight;
|
|
4013
|
-
const isVisible = visibleStates[i];
|
|
4014
|
-
if (!isVisible) {
|
|
4015
|
-
accumulatedOffset = nextOffset;
|
|
4016
|
-
continue;
|
|
4081
|
+
}
|
|
4082
|
+
render() {
|
|
4083
|
+
const changed = this.updateContext();
|
|
4084
|
+
if (changed) {
|
|
4085
|
+
if (this.isEnabledVirtualScroll()) {
|
|
4086
|
+
this.updateListRenderAndRemeasureHeights();
|
|
4017
4087
|
}
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
if (inViewportStartIndex === -1)
|
|
4021
|
-
inViewportStartIndex = i; // 第一个相交起始位置
|
|
4022
|
-
visible.push(children[i]);
|
|
4023
|
-
inViewportIndics.push(i);
|
|
4088
|
+
else {
|
|
4089
|
+
this.listRender.update(this.editor.children, this.editor, this.context);
|
|
4024
4090
|
}
|
|
4025
|
-
accumulatedOffset = nextOffset;
|
|
4026
4091
|
}
|
|
4027
|
-
const inViewportEndIndex = inViewportStartIndex === -1 ? elementLength - 1 : (inViewportIndics[inViewportIndics.length - 1] ?? inViewportStartIndex);
|
|
4028
|
-
const top = inViewportStartIndex === -1 ? 0 : accumulatedHeights[inViewportStartIndex];
|
|
4029
|
-
const bottom = totalHeight - accumulatedHeights[inViewportEndIndex + 1];
|
|
4030
|
-
return {
|
|
4031
|
-
inViewportChildren: visible.length ? visible : children,
|
|
4032
|
-
inViewportIndics,
|
|
4033
|
-
top,
|
|
4034
|
-
bottom,
|
|
4035
|
-
heights,
|
|
4036
|
-
accumulatedHeights
|
|
4037
|
-
};
|
|
4038
|
-
}
|
|
4039
|
-
applyVirtualView(virtualView) {
|
|
4040
|
-
this.inViewportChildren = virtualView.inViewportChildren;
|
|
4041
|
-
this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
|
|
4042
|
-
this.inViewportIndics = virtualView.inViewportIndics;
|
|
4043
4092
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4093
|
+
updateListRenderAndRemeasureHeights() {
|
|
4094
|
+
const operations = this.editor.operations;
|
|
4095
|
+
const firstIndex = this.inViewportIndics[0];
|
|
4096
|
+
const operationsOfFirstElementMerged = operations.filter(op => op.type === 'merge_node' && op.path.length === 1 && firstIndex === op.path[0] - 1);
|
|
4097
|
+
const operationsOfFirstElementSplitted = operations.filter(op => op.type === 'split_node' && op.path.length === 1 && firstIndex === op.path[0]);
|
|
4098
|
+
const mutationOfFirstElementHeight = operationsOfFirstElementSplitted.length > 0 || operationsOfFirstElementMerged.length > 0;
|
|
4099
|
+
const visibleStates = this.editor.getAllVisibleStates();
|
|
4100
|
+
const previousInViewportChildren = [...this.inViewportChildren];
|
|
4101
|
+
// the first element height will reset to default height when split or merge
|
|
4102
|
+
// if the most top content of the first element is not in viewport, the change of height will cause the viewport to scroll
|
|
4103
|
+
// to keep viewport stable, we need to use the current inViewportIndics temporarily
|
|
4104
|
+
if (mutationOfFirstElementHeight) {
|
|
4105
|
+
const newInViewportIndics = [];
|
|
4106
|
+
const newInViewportChildren = [];
|
|
4107
|
+
this.inViewportIndics.forEach(index => {
|
|
4108
|
+
const element = this.editor.children[index];
|
|
4109
|
+
const isVisible = visibleStates[index];
|
|
4110
|
+
if (isVisible) {
|
|
4111
|
+
newInViewportIndics.push(index);
|
|
4112
|
+
newInViewportChildren.push(element);
|
|
4113
|
+
}
|
|
4114
|
+
});
|
|
4115
|
+
this.inViewportIndics = newInViewportIndics;
|
|
4116
|
+
this.inViewportChildren = newInViewportChildren;
|
|
4046
4117
|
if (isDebug) {
|
|
4047
|
-
debugLog('log', '
|
|
4118
|
+
debugLog('log', 'updateListRenderAndRemeasureHeights', 'mutationOfFirstElementHeight', 'newInViewportIndics', newInViewportIndics);
|
|
4048
4119
|
}
|
|
4049
|
-
return {
|
|
4050
|
-
isDifferent: true,
|
|
4051
|
-
changedIndexesOfTop: [],
|
|
4052
|
-
changedIndexesOfBottom: []
|
|
4053
|
-
};
|
|
4054
|
-
}
|
|
4055
|
-
const oldIndexesInViewport = [...this.inViewportIndics];
|
|
4056
|
-
const newIndexesInViewport = [...virtualView.inViewportIndics];
|
|
4057
|
-
const firstNewIndex = newIndexesInViewport[0];
|
|
4058
|
-
const lastNewIndex = newIndexesInViewport[newIndexesInViewport.length - 1];
|
|
4059
|
-
const firstOldIndex = oldIndexesInViewport[0];
|
|
4060
|
-
const lastOldIndex = oldIndexesInViewport[oldIndexesInViewport.length - 1];
|
|
4061
|
-
const isSameViewport = oldIndexesInViewport.length === newIndexesInViewport.length &&
|
|
4062
|
-
oldIndexesInViewport.every((index, i) => index === newIndexesInViewport[i]);
|
|
4063
|
-
if (firstNewIndex === firstOldIndex && lastNewIndex === lastOldIndex) {
|
|
4064
|
-
return {
|
|
4065
|
-
isDifferent: !isSameViewport,
|
|
4066
|
-
changedIndexesOfTop: [],
|
|
4067
|
-
changedIndexesOfBottom: []
|
|
4068
|
-
};
|
|
4069
4120
|
}
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
for (let index = 0; index < oldIndexesInViewport.length; index++) {
|
|
4080
|
-
const element = oldIndexesInViewport[index];
|
|
4081
|
-
if (!newIndexesInViewport.includes(element)) {
|
|
4082
|
-
changedIndexesOfTop.push(element);
|
|
4083
|
-
}
|
|
4084
|
-
else {
|
|
4085
|
-
break;
|
|
4086
|
-
}
|
|
4087
|
-
}
|
|
4088
|
-
for (let index = newIndexesInViewport.length - 1; index >= 0; index--) {
|
|
4089
|
-
const element = newIndexesInViewport[index];
|
|
4090
|
-
if (!oldIndexesInViewport.includes(element)) {
|
|
4091
|
-
changedIndexesOfBottom.push(element);
|
|
4092
|
-
}
|
|
4093
|
-
else {
|
|
4094
|
-
break;
|
|
4095
|
-
}
|
|
4096
|
-
}
|
|
4097
|
-
}
|
|
4098
|
-
else if (needAddOnTop || needRemoveOnBottom) {
|
|
4099
|
-
// 向上
|
|
4100
|
-
for (let index = 0; index < newIndexesInViewport.length; index++) {
|
|
4101
|
-
const element = newIndexesInViewport[index];
|
|
4102
|
-
if (!oldIndexesInViewport.includes(element)) {
|
|
4103
|
-
changedIndexesOfTop.push(element);
|
|
4104
|
-
}
|
|
4105
|
-
else {
|
|
4106
|
-
break;
|
|
4107
|
-
}
|
|
4108
|
-
}
|
|
4109
|
-
for (let index = oldIndexesInViewport.length - 1; index >= 0; index--) {
|
|
4110
|
-
const element = oldIndexesInViewport[index];
|
|
4111
|
-
if (!newIndexesInViewport.includes(element)) {
|
|
4112
|
-
changedIndexesOfBottom.push(element);
|
|
4113
|
-
}
|
|
4114
|
-
else {
|
|
4115
|
-
break;
|
|
4116
|
-
}
|
|
4121
|
+
else {
|
|
4122
|
+
let virtualView = this.calculateVirtualViewport(visibleStates);
|
|
4123
|
+
let diff = this.diffVirtualViewport(virtualView, 'onChange');
|
|
4124
|
+
if (diff.isDifferent && diff.needRemoveOnTop) {
|
|
4125
|
+
const remeasureIndics = diff.changedIndexesOfTop;
|
|
4126
|
+
const changed = measureHeightByIndics(this.editor, remeasureIndics);
|
|
4127
|
+
if (changed) {
|
|
4128
|
+
virtualView = this.calculateVirtualViewport(visibleStates);
|
|
4129
|
+
diff = this.diffVirtualViewport(virtualView, 'second');
|
|
4117
4130
|
}
|
|
4118
4131
|
}
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
needRemoveOnTop,
|
|
4141
|
-
needAddOnTop,
|
|
4142
|
-
needRemoveOnBottom,
|
|
4143
|
-
needAddOnBottom,
|
|
4144
|
-
changedIndexesOfTop,
|
|
4145
|
-
changedIndexesOfBottom
|
|
4132
|
+
this.applyVirtualView(virtualView);
|
|
4133
|
+
}
|
|
4134
|
+
const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
|
|
4135
|
+
this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
|
|
4136
|
+
const remeasureIndics = this.getChangedIndics(previousInViewportChildren);
|
|
4137
|
+
if (remeasureIndics.length) {
|
|
4138
|
+
this.indicsOfNeedBeMeasured$.next(remeasureIndics);
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
updateContext() {
|
|
4142
|
+
const decorations = this.generateDecorations();
|
|
4143
|
+
if (this.context.selection !== this.editor.selection ||
|
|
4144
|
+
this.context.decorate !== this.decorate ||
|
|
4145
|
+
this.context.readonly !== this.readonly ||
|
|
4146
|
+
!isDecoratorRangeListEqual(this.context.decorations, decorations)) {
|
|
4147
|
+
this.context = {
|
|
4148
|
+
parent: this.editor,
|
|
4149
|
+
selection: this.editor.selection,
|
|
4150
|
+
decorations: decorations,
|
|
4151
|
+
decorate: this.decorate,
|
|
4152
|
+
readonly: this.readonly
|
|
4146
4153
|
};
|
|
4154
|
+
return true;
|
|
4147
4155
|
}
|
|
4148
|
-
return
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4156
|
+
return false;
|
|
4157
|
+
}
|
|
4158
|
+
initializeContext() {
|
|
4159
|
+
this.context = {
|
|
4160
|
+
parent: this.editor,
|
|
4161
|
+
selection: this.editor.selection,
|
|
4162
|
+
decorations: this.generateDecorations(),
|
|
4163
|
+
decorate: this.decorate,
|
|
4164
|
+
readonly: this.readonly
|
|
4152
4165
|
};
|
|
4153
4166
|
}
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
}
|
|
4167
|
+
initializeViewContext() {
|
|
4168
|
+
this.viewContext = {
|
|
4169
|
+
editor: this.editor,
|
|
4170
|
+
renderElement: this.renderElement,
|
|
4171
|
+
renderLeaf: this.renderLeaf,
|
|
4172
|
+
renderText: this.renderText,
|
|
4173
|
+
trackBy: this.trackBy,
|
|
4174
|
+
isStrictDecorate: this.isStrictDecorate
|
|
4175
|
+
};
|
|
4176
|
+
}
|
|
4177
|
+
composePlaceholderDecorate(editor) {
|
|
4178
|
+
if (this.placeholderDecorate) {
|
|
4179
|
+
return this.placeholderDecorate(editor) || [];
|
|
4180
|
+
}
|
|
4181
|
+
if (this.placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '') {
|
|
4182
|
+
const start = Editor.start(editor, []);
|
|
4183
|
+
return [
|
|
4184
|
+
{
|
|
4185
|
+
placeholder: this.placeholder,
|
|
4186
|
+
anchor: start,
|
|
4187
|
+
focus: start
|
|
4188
|
+
}
|
|
4189
|
+
];
|
|
4190
|
+
}
|
|
4191
|
+
else {
|
|
4192
|
+
return [];
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
generateDecorations() {
|
|
4196
|
+
const decorations = this.decorate([this.editor, []]);
|
|
4197
|
+
const placeholderDecorations = this.isComposing ? [] : this.composePlaceholderDecorate(this.editor);
|
|
4198
|
+
decorations.push(...placeholderDecorations);
|
|
4199
|
+
return decorations;
|
|
4163
4200
|
}
|
|
4164
4201
|
toSlateSelection() {
|
|
4165
4202
|
if ((!this.isComposing || IS_ANDROID) && !this.isUpdatingSelection && !this.isDraggingInternally) {
|
|
@@ -5373,5 +5410,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
5373
5410
|
* Generated bundle index. Do not edit.
|
|
5374
5411
|
*/
|
|
5375
5412
|
|
|
5376
|
-
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_BUSINESS_TOP, EDITOR_TO_IS_FROM_SCROLL_TO, EDITOR_TO_ROOT_NODE_WIDTH, EDITOR_TO_VIRTUAL_SCROLL_SELECTION, ELEMENT_KEY_TO_HEIGHTS, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_ENABLED_VIRTUAL_SCROLL, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SLATE_DEBUG_KEY_SCROLL_TOP, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, SlateString, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, cacheHeightByElement, calcHeightByElement, calculateVirtualTopHeight, check, clearMinHeightByElement, completeTable, createClipboardData, createText, createThrottleRAF, debugLog, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCachedHeightByElement, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDebug, isDebugScrollTop, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, measureHeightByIndics, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setMinHeightByElement, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
5413
|
+
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_BUSINESS_TOP, EDITOR_TO_IS_FROM_SCROLL_TO, EDITOR_TO_ROOT_NODE_WIDTH, EDITOR_TO_VIRTUAL_SCROLL_SELECTION, ELEMENT_KEY_TO_HEIGHTS, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_ENABLED_VIRTUAL_SCROLL, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SLATE_DEBUG_KEY_SCROLL_TOP, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, SlateString, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, cacheHeightByElement, calcHeightByElement, calculateVirtualTopHeight, check, clearMinHeightByElement, completeTable, createClipboardData, createText, createThrottleRAF, debugLog, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCachedHeightByElement, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDebug, isDebugScrollTop, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, isValidNumber, measureHeightByIndics, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setMinHeightByElement, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
5377
5414
|
//# sourceMappingURL=slate-angular.mjs.map
|