slate-angular 20.1.0 → 20.2.0-next.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/fesm2022/slate-angular.mjs +356 -60
- package/fesm2022/slate-angular.mjs.map +1 -1
- package/index.d.ts +51 -5
- package/package.json +1 -1
- package/styles/index.scss +1 -1
|
@@ -470,6 +470,9 @@ const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
|
|
|
470
470
|
globalThis.InputEvent &&
|
|
471
471
|
// @ts-ignore The `getTargetRanges` property isn't recognized.
|
|
472
472
|
typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
|
|
473
|
+
const VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT = 3;
|
|
474
|
+
const VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT = 40;
|
|
475
|
+
const SLATE_DEBUG_KEY = '__SLATE_DEBUG__';
|
|
473
476
|
|
|
474
477
|
/**
|
|
475
478
|
* Hotkey mappings for each platform.
|
|
@@ -1683,6 +1686,50 @@ class BaseFlavour {
|
|
|
1683
1686
|
}
|
|
1684
1687
|
}
|
|
1685
1688
|
|
|
1689
|
+
const SLATE_BLOCK_CARD_CLASS_NAME = 'slate-block-card';
|
|
1690
|
+
class SlateBlockCard {
|
|
1691
|
+
onInit() {
|
|
1692
|
+
const nativeElement = document.createElement('div');
|
|
1693
|
+
nativeElement.classList.add(SLATE_BLOCK_CARD_CLASS_NAME);
|
|
1694
|
+
this.nativeElement = nativeElement;
|
|
1695
|
+
this.createContent();
|
|
1696
|
+
}
|
|
1697
|
+
createContent() {
|
|
1698
|
+
const leftCaret = document.createElement('span');
|
|
1699
|
+
leftCaret.setAttribute(`card-target`, 'card-left');
|
|
1700
|
+
leftCaret.classList.add('card-left');
|
|
1701
|
+
leftCaret.appendChild(getZeroTextNode());
|
|
1702
|
+
const rightCaret = document.createElement('span');
|
|
1703
|
+
rightCaret.setAttribute(`card-target`, 'card-right');
|
|
1704
|
+
rightCaret.classList.add('card-right');
|
|
1705
|
+
rightCaret.appendChild(getZeroTextNode());
|
|
1706
|
+
const center = document.createElement('div');
|
|
1707
|
+
center.setAttribute(`card-target`, 'card-center');
|
|
1708
|
+
this.nativeElement.appendChild(leftCaret);
|
|
1709
|
+
this.nativeElement.appendChild(center);
|
|
1710
|
+
this.nativeElement.appendChild(rightCaret);
|
|
1711
|
+
this.centerContainer = center;
|
|
1712
|
+
}
|
|
1713
|
+
append() {
|
|
1714
|
+
this.centerRootNodes.forEach(rootNode => !this.centerContainer.contains(rootNode) && this.centerContainer.appendChild(rootNode));
|
|
1715
|
+
}
|
|
1716
|
+
initializeCenter(rootNodes) {
|
|
1717
|
+
this.centerRootNodes = rootNodes;
|
|
1718
|
+
this.append();
|
|
1719
|
+
}
|
|
1720
|
+
onDestroy() {
|
|
1721
|
+
this.nativeElement.remove();
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
const getBlockCardByNativeElement = (nativeElement) => {
|
|
1725
|
+
const blockCardElement = nativeElement?.parentElement?.parentElement;
|
|
1726
|
+
if (blockCardElement && blockCardElement.classList.contains(SLATE_BLOCK_CARD_CLASS_NAME)) {
|
|
1727
|
+
return blockCardElement;
|
|
1728
|
+
}
|
|
1729
|
+
return null;
|
|
1730
|
+
};
|
|
1731
|
+
|
|
1732
|
+
const DEFAULT_ELEMENT_HEIGHT = 24;
|
|
1686
1733
|
class BaseElementFlavour extends BaseFlavour {
|
|
1687
1734
|
constructor() {
|
|
1688
1735
|
super(...arguments);
|
|
@@ -1777,6 +1824,12 @@ class BaseElementFlavour extends BaseFlavour {
|
|
|
1777
1824
|
readonly: this._context.readonly
|
|
1778
1825
|
};
|
|
1779
1826
|
}
|
|
1827
|
+
getRealHeight() {
|
|
1828
|
+
const blockCard = getBlockCardByNativeElement(this.nativeElement);
|
|
1829
|
+
const target = blockCard || this.nativeElement;
|
|
1830
|
+
const computedStyle = getComputedStyle(target);
|
|
1831
|
+
return Promise.resolve(target.offsetHeight + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom));
|
|
1832
|
+
}
|
|
1780
1833
|
}
|
|
1781
1834
|
|
|
1782
1835
|
class DefaultElementFlavour extends BaseElementFlavour {
|
|
@@ -2203,49 +2256,6 @@ const createText = (text) => {
|
|
|
2203
2256
|
return { nativeElement };
|
|
2204
2257
|
};
|
|
2205
2258
|
|
|
2206
|
-
const SLATE_BLOCK_CARD_CLASS_NAME = 'slate-block-card';
|
|
2207
|
-
class SlateBlockCard {
|
|
2208
|
-
onInit() {
|
|
2209
|
-
const nativeElement = document.createElement('div');
|
|
2210
|
-
nativeElement.classList.add(SLATE_BLOCK_CARD_CLASS_NAME);
|
|
2211
|
-
this.nativeElement = nativeElement;
|
|
2212
|
-
this.createContent();
|
|
2213
|
-
}
|
|
2214
|
-
createContent() {
|
|
2215
|
-
const leftCaret = document.createElement('span');
|
|
2216
|
-
leftCaret.setAttribute(`card-target`, 'card-left');
|
|
2217
|
-
leftCaret.classList.add('card-left');
|
|
2218
|
-
leftCaret.appendChild(getZeroTextNode());
|
|
2219
|
-
const rightCaret = document.createElement('span');
|
|
2220
|
-
rightCaret.setAttribute(`card-target`, 'card-right');
|
|
2221
|
-
rightCaret.classList.add('card-right');
|
|
2222
|
-
rightCaret.appendChild(getZeroTextNode());
|
|
2223
|
-
const center = document.createElement('div');
|
|
2224
|
-
center.setAttribute(`card-target`, 'card-center');
|
|
2225
|
-
this.nativeElement.appendChild(leftCaret);
|
|
2226
|
-
this.nativeElement.appendChild(center);
|
|
2227
|
-
this.nativeElement.appendChild(rightCaret);
|
|
2228
|
-
this.centerContainer = center;
|
|
2229
|
-
}
|
|
2230
|
-
append() {
|
|
2231
|
-
this.centerRootNodes.forEach(rootNode => !this.centerContainer.contains(rootNode) && this.centerContainer.appendChild(rootNode));
|
|
2232
|
-
}
|
|
2233
|
-
initializeCenter(rootNodes) {
|
|
2234
|
-
this.centerRootNodes = rootNodes;
|
|
2235
|
-
this.append();
|
|
2236
|
-
}
|
|
2237
|
-
onDestroy() {
|
|
2238
|
-
this.nativeElement.remove();
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
const getBlockCardByNativeElement = (nativeElement) => {
|
|
2242
|
-
const blockCardElement = nativeElement?.parentElement?.parentElement;
|
|
2243
|
-
if (blockCardElement && blockCardElement.classList.contains(SLATE_BLOCK_CARD_CLASS_NAME)) {
|
|
2244
|
-
return blockCardElement;
|
|
2245
|
-
}
|
|
2246
|
-
return null;
|
|
2247
|
-
};
|
|
2248
|
-
|
|
2249
2259
|
class ListRender {
|
|
2250
2260
|
constructor(viewContext, viewContainerRef, getOutletParent, getOutletElement) {
|
|
2251
2261
|
this.viewContext = viewContext;
|
|
@@ -2262,11 +2272,13 @@ class ListRender {
|
|
|
2262
2272
|
initialize(children, parent, childrenContext) {
|
|
2263
2273
|
this.initialized = true;
|
|
2264
2274
|
this.children = children;
|
|
2275
|
+
const isRoot = parent === this.viewContext.editor;
|
|
2276
|
+
const firstIndex = isRoot ? this.viewContext.editor.children.indexOf(children[0]) : 0;
|
|
2265
2277
|
const parentPath = AngularEditor.findPath(this.viewContext.editor, parent);
|
|
2266
|
-
children.forEach((descendant,
|
|
2267
|
-
NODE_TO_INDEX.set(descendant,
|
|
2278
|
+
children.forEach((descendant, _index) => {
|
|
2279
|
+
NODE_TO_INDEX.set(descendant, firstIndex + _index);
|
|
2268
2280
|
NODE_TO_PARENT.set(descendant, parent);
|
|
2269
|
-
const context = getContext(
|
|
2281
|
+
const context = getContext(firstIndex + _index, descendant, parentPath, childrenContext, this.viewContext);
|
|
2270
2282
|
const viewType = getViewType(descendant, parent, this.viewContext);
|
|
2271
2283
|
const view = createEmbeddedViewOrComponentOrFlavour(viewType, context, this.viewContext, this.viewContainerRef);
|
|
2272
2284
|
const blockCard = createBlockCard(descendant, view, this.viewContext);
|
|
@@ -2294,6 +2306,8 @@ class ListRender {
|
|
|
2294
2306
|
const outletParent = this.getOutletParent();
|
|
2295
2307
|
const diffResult = this.differ.diff(children);
|
|
2296
2308
|
const parentPath = AngularEditor.findPath(this.viewContext.editor, parent);
|
|
2309
|
+
const isRoot = parent === this.viewContext.editor;
|
|
2310
|
+
const firstIndex = isRoot ? this.viewContext.editor.children.indexOf(children[0]) : 0;
|
|
2297
2311
|
if (diffResult) {
|
|
2298
2312
|
let firstRootNode = getRootNodes(this.views[0], this.blockCards[0])[0];
|
|
2299
2313
|
const newContexts = [];
|
|
@@ -2301,9 +2315,10 @@ class ListRender {
|
|
|
2301
2315
|
const newViews = [];
|
|
2302
2316
|
const newBlockCards = [];
|
|
2303
2317
|
diffResult.forEachItem(record => {
|
|
2304
|
-
|
|
2318
|
+
const currentIndex = firstIndex + record.currentIndex;
|
|
2319
|
+
NODE_TO_INDEX.set(record.item, currentIndex);
|
|
2305
2320
|
NODE_TO_PARENT.set(record.item, parent);
|
|
2306
|
-
let context = getContext(
|
|
2321
|
+
let context = getContext(currentIndex, record.item, parentPath, childrenContext, this.viewContext);
|
|
2307
2322
|
const viewType = getViewType(record.item, parent, this.viewContext);
|
|
2308
2323
|
newViewTypes.push(viewType);
|
|
2309
2324
|
let view;
|
|
@@ -2371,16 +2386,16 @@ class ListRender {
|
|
|
2371
2386
|
}
|
|
2372
2387
|
else {
|
|
2373
2388
|
const newContexts = [];
|
|
2374
|
-
this.children.forEach((child,
|
|
2375
|
-
NODE_TO_INDEX.set(child,
|
|
2389
|
+
this.children.forEach((child, _index) => {
|
|
2390
|
+
NODE_TO_INDEX.set(child, firstIndex + _index);
|
|
2376
2391
|
NODE_TO_PARENT.set(child, parent);
|
|
2377
|
-
let context = getContext(
|
|
2378
|
-
const previousContext = this.contexts[
|
|
2392
|
+
let context = getContext(firstIndex + _index, child, parentPath, childrenContext, this.viewContext);
|
|
2393
|
+
const previousContext = this.contexts[_index];
|
|
2379
2394
|
if (memoizedContext(this.viewContext, child, previousContext, context)) {
|
|
2380
2395
|
context = previousContext;
|
|
2381
2396
|
}
|
|
2382
2397
|
else {
|
|
2383
|
-
updateContext(this.views[
|
|
2398
|
+
updateContext(this.views[_index], context, this.viewContext);
|
|
2384
2399
|
}
|
|
2385
2400
|
newContexts.push(context);
|
|
2386
2401
|
});
|
|
@@ -2538,9 +2553,25 @@ function executeAfterViewInit(editor) {
|
|
|
2538
2553
|
clearAfterViewInitQueue(editor);
|
|
2539
2554
|
}
|
|
2540
2555
|
|
|
2556
|
+
const JUST_NOW_UPDATED_VIRTUAL_VIEW = new WeakMap();
|
|
2541
2557
|
// not correctly clipboardData on beforeinput
|
|
2542
2558
|
const forceOnDOMPaste = IS_SAFARI;
|
|
2543
2559
|
class SlateEditable {
|
|
2560
|
+
set virtualScroll(config) {
|
|
2561
|
+
this.virtualConfig = config;
|
|
2562
|
+
this.refreshVirtualViewAnimId && cancelAnimationFrame(this.refreshVirtualViewAnimId);
|
|
2563
|
+
this.refreshVirtualViewAnimId = requestAnimationFrame(() => {
|
|
2564
|
+
const virtualView = this.refreshVirtualView();
|
|
2565
|
+
const diff = this.diffVirtualView(virtualView);
|
|
2566
|
+
if (diff) {
|
|
2567
|
+
this.applyVirtualView(virtualView);
|
|
2568
|
+
if (this.listRender.initialized) {
|
|
2569
|
+
this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
|
|
2570
|
+
}
|
|
2571
|
+
this.scheduleMeasureVisibleHeights();
|
|
2572
|
+
}
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2544
2575
|
get hasBeforeInputSupport() {
|
|
2545
2576
|
return HAS_BEFORE_INPUT_SUPPORT;
|
|
2546
2577
|
}
|
|
@@ -2576,6 +2607,24 @@ class SlateEditable {
|
|
|
2576
2607
|
this.getOutletParent = () => {
|
|
2577
2608
|
return this.elementRef.nativeElement;
|
|
2578
2609
|
};
|
|
2610
|
+
this.getOutletElement = () => {
|
|
2611
|
+
if (this.virtualScrollInitialized) {
|
|
2612
|
+
return this.virtualCenterOutlet;
|
|
2613
|
+
}
|
|
2614
|
+
else {
|
|
2615
|
+
return null;
|
|
2616
|
+
}
|
|
2617
|
+
};
|
|
2618
|
+
this.virtualConfig = {
|
|
2619
|
+
enabled: false,
|
|
2620
|
+
scrollTop: 0,
|
|
2621
|
+
viewportHeight: 0
|
|
2622
|
+
};
|
|
2623
|
+
this.renderedChildren = [];
|
|
2624
|
+
this.virtualVisibleIndexes = new Set();
|
|
2625
|
+
this.measuredHeights = new Map();
|
|
2626
|
+
this.measurePending = false;
|
|
2627
|
+
this.virtualScrollInitialized = false;
|
|
2579
2628
|
}
|
|
2580
2629
|
ngOnInit() {
|
|
2581
2630
|
this.editor.injector = this.injector;
|
|
@@ -2599,7 +2648,8 @@ class SlateEditable {
|
|
|
2599
2648
|
// add browser class
|
|
2600
2649
|
let browserClass = IS_FIREFOX ? 'firefox' : IS_SAFARI ? 'safari' : '';
|
|
2601
2650
|
browserClass && this.elementRef.nativeElement.classList.add(browserClass);
|
|
2602
|
-
this.
|
|
2651
|
+
this.initializeVirtualScrolling();
|
|
2652
|
+
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletParent, this.getOutletElement);
|
|
2603
2653
|
}
|
|
2604
2654
|
ngOnChanges(simpleChanges) {
|
|
2605
2655
|
if (!this.initialized) {
|
|
@@ -2630,12 +2680,16 @@ class SlateEditable {
|
|
|
2630
2680
|
if (value && value.length) {
|
|
2631
2681
|
this.editor.children = value;
|
|
2632
2682
|
this.initializeContext();
|
|
2683
|
+
const virtualView = this.refreshVirtualView();
|
|
2684
|
+
this.applyVirtualView(virtualView);
|
|
2685
|
+
const childrenForRender = virtualView.renderedChildren;
|
|
2633
2686
|
if (!this.listRender.initialized) {
|
|
2634
|
-
this.listRender.initialize(
|
|
2687
|
+
this.listRender.initialize(childrenForRender, this.editor, this.context);
|
|
2635
2688
|
}
|
|
2636
2689
|
else {
|
|
2637
|
-
this.listRender.update(
|
|
2690
|
+
this.listRender.update(childrenForRender, this.editor, this.context);
|
|
2638
2691
|
}
|
|
2692
|
+
this.scheduleMeasureVisibleHeights();
|
|
2639
2693
|
this.cdr.markForCheck();
|
|
2640
2694
|
}
|
|
2641
2695
|
}
|
|
@@ -2756,7 +2810,10 @@ class SlateEditable {
|
|
|
2756
2810
|
ngDoCheck() { }
|
|
2757
2811
|
forceRender() {
|
|
2758
2812
|
this.updateContext();
|
|
2759
|
-
|
|
2813
|
+
const virtualView = this.refreshVirtualView();
|
|
2814
|
+
this.applyVirtualView(virtualView);
|
|
2815
|
+
this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
|
|
2816
|
+
this.scheduleMeasureVisibleHeights();
|
|
2760
2817
|
// repair collaborative editing when Chinese input is interrupted by other users' cursors
|
|
2761
2818
|
// when the DOMElement where the selection is located is removed
|
|
2762
2819
|
// the compositionupdate and compositionend events will no longer be fired
|
|
@@ -2795,7 +2852,10 @@ class SlateEditable {
|
|
|
2795
2852
|
render() {
|
|
2796
2853
|
const changed = this.updateContext();
|
|
2797
2854
|
if (changed) {
|
|
2798
|
-
|
|
2855
|
+
const virtualView = this.refreshVirtualView();
|
|
2856
|
+
this.applyVirtualView(virtualView);
|
|
2857
|
+
this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
|
|
2858
|
+
this.scheduleMeasureVisibleHeights();
|
|
2799
2859
|
}
|
|
2800
2860
|
}
|
|
2801
2861
|
updateContext() {
|
|
@@ -2858,6 +2918,234 @@ class SlateEditable {
|
|
|
2858
2918
|
decorations.push(...placeholderDecorations);
|
|
2859
2919
|
return decorations;
|
|
2860
2920
|
}
|
|
2921
|
+
shouldUseVirtual() {
|
|
2922
|
+
return !!(this.virtualConfig && this.virtualConfig.enabled);
|
|
2923
|
+
}
|
|
2924
|
+
initializeVirtualScrolling() {
|
|
2925
|
+
if (this.virtualScrollInitialized) {
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2928
|
+
if (this.virtualConfig && this.virtualConfig.enabled) {
|
|
2929
|
+
this.virtualScrollInitialized = true;
|
|
2930
|
+
this.virtualTopHeightElement = document.createElement('div');
|
|
2931
|
+
this.virtualTopHeightElement.classList.add('virtual-top-height');
|
|
2932
|
+
this.virtualBottomHeightElement = document.createElement('div');
|
|
2933
|
+
this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
|
|
2934
|
+
this.virtualCenterOutlet = document.createElement('div');
|
|
2935
|
+
this.virtualCenterOutlet.classList.add('virtual-center-outlet');
|
|
2936
|
+
this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
|
|
2937
|
+
this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
|
|
2938
|
+
this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
changeVirtualHeight(topHeight, bottomHeight) {
|
|
2942
|
+
if (!this.virtualScrollInitialized) {
|
|
2943
|
+
return;
|
|
2944
|
+
}
|
|
2945
|
+
this.virtualTopHeightElement.style.height = `${topHeight}px`;
|
|
2946
|
+
this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
|
|
2947
|
+
}
|
|
2948
|
+
refreshVirtualView() {
|
|
2949
|
+
const children = (this.editor.children || []);
|
|
2950
|
+
if (!children.length || !this.shouldUseVirtual()) {
|
|
2951
|
+
return {
|
|
2952
|
+
renderedChildren: children,
|
|
2953
|
+
visibleIndexes: new Set(),
|
|
2954
|
+
top: 0,
|
|
2955
|
+
bottom: 0,
|
|
2956
|
+
heights: []
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2959
|
+
const scrollTop = this.virtualConfig.scrollTop ?? 0;
|
|
2960
|
+
const viewportHeight = this.virtualConfig.viewportHeight ?? 0;
|
|
2961
|
+
if (!viewportHeight) {
|
|
2962
|
+
// 已经启用虚拟滚动,但可视区域高度还未获取到,先置空不渲染
|
|
2963
|
+
return {
|
|
2964
|
+
renderedChildren: [],
|
|
2965
|
+
visibleIndexes: new Set(),
|
|
2966
|
+
top: 0,
|
|
2967
|
+
bottom: 0,
|
|
2968
|
+
heights: []
|
|
2969
|
+
};
|
|
2970
|
+
}
|
|
2971
|
+
const bufferCount = this.virtualConfig.bufferCount ?? VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT;
|
|
2972
|
+
const heights = children.map((_, idx) => this.getBlockHeight(idx));
|
|
2973
|
+
const accumulatedHeights = this.buildAccumulatedHeight(heights);
|
|
2974
|
+
let visibleStart = 0;
|
|
2975
|
+
// 按真实或估算高度往后累加,找到滚动起点所在块
|
|
2976
|
+
while (visibleStart < heights.length && accumulatedHeights[visibleStart + 1] <= scrollTop) {
|
|
2977
|
+
visibleStart++;
|
|
2978
|
+
}
|
|
2979
|
+
// 向上预留 bufferCount 块
|
|
2980
|
+
const startIndex = Math.max(0, visibleStart - bufferCount);
|
|
2981
|
+
const top = accumulatedHeights[startIndex];
|
|
2982
|
+
const bufferBelowHeight = this.getBufferBelowHeight(viewportHeight, visibleStart, bufferCount);
|
|
2983
|
+
const targetHeight = accumulatedHeights[visibleStart] - top + viewportHeight + bufferBelowHeight;
|
|
2984
|
+
const visible = [];
|
|
2985
|
+
const visibleIndexes = [];
|
|
2986
|
+
let accumulated = 0;
|
|
2987
|
+
let cursor = startIndex;
|
|
2988
|
+
// 循环累计高度超出目标高度(可视高度 + 上下 buffer)
|
|
2989
|
+
while (cursor < children.length && accumulated < targetHeight) {
|
|
2990
|
+
visible.push(children[cursor]);
|
|
2991
|
+
visibleIndexes.push(cursor);
|
|
2992
|
+
accumulated += this.getBlockHeight(cursor);
|
|
2993
|
+
cursor++;
|
|
2994
|
+
}
|
|
2995
|
+
const bottom = heights.slice(cursor).reduce((acc, height) => acc + height, 0);
|
|
2996
|
+
const renderedChildren = visible.length ? visible : children;
|
|
2997
|
+
const visibleIndexesSet = new Set(visibleIndexes);
|
|
2998
|
+
return {
|
|
2999
|
+
renderedChildren,
|
|
3000
|
+
visibleIndexes: visibleIndexesSet,
|
|
3001
|
+
top,
|
|
3002
|
+
bottom,
|
|
3003
|
+
heights
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
applyVirtualView(virtualView) {
|
|
3007
|
+
this.renderedChildren = virtualView.renderedChildren;
|
|
3008
|
+
this.changeVirtualHeight(virtualView.top, virtualView.bottom);
|
|
3009
|
+
this.virtualVisibleIndexes = virtualView.visibleIndexes;
|
|
3010
|
+
}
|
|
3011
|
+
diffVirtualView(virtualView) {
|
|
3012
|
+
if (!this.renderedChildren.length) {
|
|
3013
|
+
return true;
|
|
3014
|
+
}
|
|
3015
|
+
const oldVisibleIndexes = [...this.virtualVisibleIndexes];
|
|
3016
|
+
const newVisibleIndexes = [...virtualView.visibleIndexes];
|
|
3017
|
+
if (newVisibleIndexes[0] !== oldVisibleIndexes[0] ||
|
|
3018
|
+
newVisibleIndexes[newVisibleIndexes.length - 1] !== oldVisibleIndexes[oldVisibleIndexes.length - 1]) {
|
|
3019
|
+
if (localStorage.getItem(SLATE_DEBUG_KEY) === 'true') {
|
|
3020
|
+
const diffTopRenderedIndexes = [];
|
|
3021
|
+
const diffBottomRenderedIndexes = [];
|
|
3022
|
+
let direction = '';
|
|
3023
|
+
if (newVisibleIndexes[0] > oldVisibleIndexes[0]) {
|
|
3024
|
+
// 向下
|
|
3025
|
+
direction = 'down';
|
|
3026
|
+
for (let index = 0; index < oldVisibleIndexes.length; index++) {
|
|
3027
|
+
const element = oldVisibleIndexes[index];
|
|
3028
|
+
if (!newVisibleIndexes.includes(element)) {
|
|
3029
|
+
diffTopRenderedIndexes.push(element);
|
|
3030
|
+
}
|
|
3031
|
+
else {
|
|
3032
|
+
break;
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
for (let index = newVisibleIndexes.length - 1; index >= 0; index--) {
|
|
3036
|
+
const element = newVisibleIndexes[index];
|
|
3037
|
+
if (!oldVisibleIndexes.includes(element)) {
|
|
3038
|
+
diffBottomRenderedIndexes.push(element);
|
|
3039
|
+
}
|
|
3040
|
+
else {
|
|
3041
|
+
break;
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
else {
|
|
3046
|
+
// 向上
|
|
3047
|
+
direction = 'up';
|
|
3048
|
+
for (let index = 0; index < newVisibleIndexes.length; index++) {
|
|
3049
|
+
const element = newVisibleIndexes[index];
|
|
3050
|
+
if (!oldVisibleIndexes.includes(element)) {
|
|
3051
|
+
diffTopRenderedIndexes.push(element);
|
|
3052
|
+
}
|
|
3053
|
+
else {
|
|
3054
|
+
break;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
for (let index = oldVisibleIndexes.length - 1; index >= 0; index--) {
|
|
3058
|
+
const element = oldVisibleIndexes[index];
|
|
3059
|
+
if (!newVisibleIndexes.includes(element)) {
|
|
3060
|
+
diffBottomRenderedIndexes.push(element);
|
|
3061
|
+
}
|
|
3062
|
+
else {
|
|
3063
|
+
break;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
console.log('oldVisibleIndexes:', oldVisibleIndexes);
|
|
3068
|
+
console.log('newVisibleIndexes:', newVisibleIndexes);
|
|
3069
|
+
const directionStr = direction === 'down' ? '+' : '-';
|
|
3070
|
+
console.log('diffTopRenderedIndexes:', directionStr, diffTopRenderedIndexes, diffTopRenderedIndexes.map(index => virtualView.heights[index]));
|
|
3071
|
+
console.log('diffBottomRenderedIndexes:', directionStr, diffBottomRenderedIndexes, diffBottomRenderedIndexes.map(index => virtualView.heights[index]));
|
|
3072
|
+
const needTop = virtualView.heights.slice(0, newVisibleIndexes[0]).reduce((acc, height) => acc + height, 0);
|
|
3073
|
+
const needBottom = virtualView.heights
|
|
3074
|
+
.slice(newVisibleIndexes[newVisibleIndexes.length - 1] + 1)
|
|
3075
|
+
.reduce((acc, height) => acc + height, 0);
|
|
3076
|
+
console.log('newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
|
|
3077
|
+
console.log('newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
|
|
3078
|
+
console.warn('=========== Dividing line ===========');
|
|
3079
|
+
}
|
|
3080
|
+
return true;
|
|
3081
|
+
}
|
|
3082
|
+
return false;
|
|
3083
|
+
}
|
|
3084
|
+
getBlockHeight(index) {
|
|
3085
|
+
const node = this.editor.children[index];
|
|
3086
|
+
if (!node) {
|
|
3087
|
+
return VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT;
|
|
3088
|
+
}
|
|
3089
|
+
const key = AngularEditor.findKey(this.editor, node);
|
|
3090
|
+
return this.measuredHeights.get(key.id) ?? VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT;
|
|
3091
|
+
}
|
|
3092
|
+
buildAccumulatedHeight(heights) {
|
|
3093
|
+
const accumulatedHeights = new Array(heights.length + 1).fill(0);
|
|
3094
|
+
for (let i = 0; i < heights.length; i++) {
|
|
3095
|
+
// 存储前 i 个的累计高度
|
|
3096
|
+
accumulatedHeights[i + 1] = accumulatedHeights[i] + heights[i];
|
|
3097
|
+
}
|
|
3098
|
+
return accumulatedHeights;
|
|
3099
|
+
}
|
|
3100
|
+
getBufferBelowHeight(viewportHeight, visibleStart, bufferCount) {
|
|
3101
|
+
let blockHeight = 0;
|
|
3102
|
+
let start = visibleStart;
|
|
3103
|
+
// 循环累计高度超出视图高度代表找到向下缓冲区的起始位置
|
|
3104
|
+
while (blockHeight < viewportHeight) {
|
|
3105
|
+
blockHeight += this.getBlockHeight(start);
|
|
3106
|
+
start++;
|
|
3107
|
+
}
|
|
3108
|
+
let bufferHeight = 0;
|
|
3109
|
+
for (let i = start; i < start + bufferCount; i++) {
|
|
3110
|
+
bufferHeight += this.getBlockHeight(i);
|
|
3111
|
+
}
|
|
3112
|
+
return bufferHeight;
|
|
3113
|
+
}
|
|
3114
|
+
scheduleMeasureVisibleHeights() {
|
|
3115
|
+
if (!this.shouldUseVirtual()) {
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
if (this.measurePending) {
|
|
3119
|
+
return;
|
|
3120
|
+
}
|
|
3121
|
+
this.measurePending = true;
|
|
3122
|
+
this.measureVisibleHeightsAnimId && cancelAnimationFrame(this.measureVisibleHeightsAnimId);
|
|
3123
|
+
this.measureVisibleHeightsAnimId = requestAnimationFrame(() => {
|
|
3124
|
+
this.measureVisibleHeights();
|
|
3125
|
+
this.measurePending = false;
|
|
3126
|
+
});
|
|
3127
|
+
}
|
|
3128
|
+
measureVisibleHeights() {
|
|
3129
|
+
const children = (this.editor.children || []);
|
|
3130
|
+
this.virtualVisibleIndexes.forEach(index => {
|
|
3131
|
+
const node = children[index];
|
|
3132
|
+
if (!node) {
|
|
3133
|
+
return;
|
|
3134
|
+
}
|
|
3135
|
+
const key = AngularEditor.findKey(this.editor, node);
|
|
3136
|
+
// 跳过已测过的块
|
|
3137
|
+
if (this.measuredHeights.has(key.id)) {
|
|
3138
|
+
return;
|
|
3139
|
+
}
|
|
3140
|
+
const view = ELEMENT_TO_COMPONENT.get(node);
|
|
3141
|
+
if (!view) {
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
view.getRealHeight()?.then(height => {
|
|
3145
|
+
this.measuredHeights.set(key.id, height);
|
|
3146
|
+
});
|
|
3147
|
+
});
|
|
3148
|
+
}
|
|
2861
3149
|
//#region event proxy
|
|
2862
3150
|
addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
|
|
2863
3151
|
this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
|
|
@@ -3557,7 +3845,7 @@ class SlateEditable {
|
|
|
3557
3845
|
EDITOR_TO_ON_CHANGE.delete(this.editor);
|
|
3558
3846
|
}
|
|
3559
3847
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: SlateEditable, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3560
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.12", type: SlateEditable, isStandalone: true, selector: "slate-editable", inputs: { editor: "editor", renderElement: "renderElement", renderLeaf: "renderLeaf", renderText: "renderText", decorate: "decorate", placeholderDecorate: "placeholderDecorate", scrollSelectionIntoView: "scrollSelectionIntoView", isStrictDecorate: "isStrictDecorate", trackBy: "trackBy", readonly: "readonly", placeholder: "placeholder", beforeInput: "beforeInput", blur: "blur", click: "click", compositionEnd: "compositionEnd", compositionUpdate: "compositionUpdate", compositionStart: "compositionStart", copy: "copy", cut: "cut", dragOver: "dragOver", dragStart: "dragStart", dragEnd: "dragEnd", drop: "drop", focus: "focus", keydown: "keydown", paste: "paste", spellCheck: "spellCheck", autoCorrect: "autoCorrect", autoCapitalize: "autoCapitalize" }, host: { properties: { "attr.contenteditable": "readonly ? undefined : true", "attr.role": "readonly ? undefined : 'textbox'", "attr.spellCheck": "!hasBeforeInputSupport ? false : spellCheck", "attr.autoCorrect": "!hasBeforeInputSupport ? 'false' : autoCorrect", "attr.autoCapitalize": "!hasBeforeInputSupport ? 'false' : autoCapitalize", "attr.data-slate-editor": "this.dataSlateEditor", "attr.data-slate-node": "this.dataSlateNode", "attr.data-gramm": "this.dataGramm" }, classAttribute: "slate-editable-container" }, providers: [
|
|
3848
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.12", type: SlateEditable, isStandalone: true, selector: "slate-editable", inputs: { editor: "editor", renderElement: "renderElement", renderLeaf: "renderLeaf", renderText: "renderText", decorate: "decorate", placeholderDecorate: "placeholderDecorate", scrollSelectionIntoView: "scrollSelectionIntoView", isStrictDecorate: "isStrictDecorate", trackBy: "trackBy", readonly: "readonly", placeholder: "placeholder", virtualScroll: "virtualScroll", beforeInput: "beforeInput", blur: "blur", click: "click", compositionEnd: "compositionEnd", compositionUpdate: "compositionUpdate", compositionStart: "compositionStart", copy: "copy", cut: "cut", dragOver: "dragOver", dragStart: "dragStart", dragEnd: "dragEnd", drop: "drop", focus: "focus", keydown: "keydown", paste: "paste", spellCheck: "spellCheck", autoCorrect: "autoCorrect", autoCapitalize: "autoCapitalize" }, host: { properties: { "attr.contenteditable": "readonly ? undefined : true", "attr.role": "readonly ? undefined : 'textbox'", "attr.spellCheck": "!hasBeforeInputSupport ? false : spellCheck", "attr.autoCorrect": "!hasBeforeInputSupport ? 'false' : autoCorrect", "attr.autoCapitalize": "!hasBeforeInputSupport ? 'false' : autoCapitalize", "attr.data-slate-editor": "this.dataSlateEditor", "attr.data-slate-node": "this.dataSlateNode", "attr.data-gramm": "this.dataGramm" }, classAttribute: "slate-editable-container" }, providers: [
|
|
3561
3849
|
{
|
|
3562
3850
|
provide: NG_VALUE_ACCESSOR,
|
|
3563
3851
|
useExisting: forwardRef(() => SlateEditable),
|
|
@@ -3610,6 +3898,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
3610
3898
|
type: Input
|
|
3611
3899
|
}], placeholder: [{
|
|
3612
3900
|
type: Input
|
|
3901
|
+
}], virtualScroll: [{
|
|
3902
|
+
type: Input
|
|
3613
3903
|
}], beforeInput: [{
|
|
3614
3904
|
type: Input
|
|
3615
3905
|
}], blur: [{
|
|
@@ -3887,6 +4177,12 @@ class BaseElementComponent extends BaseComponent {
|
|
|
3887
4177
|
readonly: this._context.readonly
|
|
3888
4178
|
};
|
|
3889
4179
|
}
|
|
4180
|
+
getRealHeight() {
|
|
4181
|
+
const blockCard = getBlockCardByNativeElement(this.nativeElement);
|
|
4182
|
+
const target = blockCard || this.nativeElement;
|
|
4183
|
+
const computedStyle = getComputedStyle(target);
|
|
4184
|
+
return Promise.resolve(target.offsetHeight + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom));
|
|
4185
|
+
}
|
|
3890
4186
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: BaseElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3891
4187
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.12", type: BaseElementComponent, isStandalone: true, viewQueries: [{ propertyName: "childrenOutletInstance", first: true, predicate: SlateChildrenOutlet, descendants: true, static: true }], usesInheritance: true, ngImport: i0 }); }
|
|
3892
4188
|
}
|
|
@@ -4041,5 +4337,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
4041
4337
|
* Generated bundle index. Do not edit.
|
|
4042
4338
|
*/
|
|
4043
4339
|
|
|
4044
|
-
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, 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_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, VoidTextFlavour, blobAsString, buildHTMLText, check, completeTable, createClipboardData, createText, createThrottleRAF, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, 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, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, normalize, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
4340
|
+
export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, 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_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, JUST_NOW_UPDATED_VIRTUAL_VIEW, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT, VoidTextFlavour, blobAsString, buildHTMLText, check, completeTable, createClipboardData, createText, createThrottleRAF, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, 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, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, normalize, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
|
|
4045
4341
|
//# sourceMappingURL=slate-angular.mjs.map
|