mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1398 lines
48 KiB
1398 lines
48 KiB
import * as i0 from '@angular/core';
|
|
import { InjectionToken, forwardRef, Directive, Input, inject, NgZone, RendererFactory2, Injectable, ElementRef, Renderer2, DOCUMENT, ChangeDetectorRef, signal, Injector, effect, ApplicationRef, DestroyRef, untracked, afterNextRender, booleanAttribute, Component, ViewEncapsulation, ChangeDetectionStrategy, Output, ViewChild, ViewContainerRef, TemplateRef, IterableDiffers, NgModule } from '@angular/core';
|
|
import { Subject, of, Observable, Subscription, animationFrameScheduler, asapScheduler, isObservable } from 'rxjs';
|
|
import { distinctUntilChanged, auditTime, filter, startWith, takeUntil, pairwise, switchMap, shareReplay } from 'rxjs/operators';
|
|
import { coerceNumberProperty, coerceElement } from './_element-chunk.mjs';
|
|
import { Platform } from './_platform-chunk.mjs';
|
|
import { Directionality } from './_directionality-chunk.mjs';
|
|
import { getRtlScrollAxisType, RtlScrollAxisType, supportsScrollBehavior } from './_scrolling-chunk.mjs';
|
|
import { BidiModule } from './bidi.mjs';
|
|
export { Dir as ɵɵDir } from './bidi.mjs';
|
|
import { _RecycleViewRepeaterStrategy, ArrayDataSource } from './_recycle-view-repeater-strategy-chunk.mjs';
|
|
import { isDataSource } from './_data-source-chunk.mjs';
|
|
import '@angular/common';
|
|
|
|
const VIRTUAL_SCROLL_STRATEGY = new InjectionToken('VIRTUAL_SCROLL_STRATEGY');
|
|
|
|
class FixedSizeVirtualScrollStrategy {
|
|
_scrolledIndexChange = new Subject();
|
|
scrolledIndexChange = this._scrolledIndexChange.pipe(distinctUntilChanged());
|
|
_viewport = null;
|
|
_itemSize;
|
|
_minBufferPx;
|
|
_maxBufferPx;
|
|
constructor(itemSize, minBufferPx, maxBufferPx) {
|
|
this._itemSize = itemSize;
|
|
this._minBufferPx = minBufferPx;
|
|
this._maxBufferPx = maxBufferPx;
|
|
}
|
|
attach(viewport) {
|
|
this._viewport = viewport;
|
|
this._updateTotalContentSize();
|
|
this._updateRenderedRange();
|
|
}
|
|
detach() {
|
|
this._scrolledIndexChange.complete();
|
|
this._viewport = null;
|
|
}
|
|
updateItemAndBufferSize(itemSize, minBufferPx, maxBufferPx) {
|
|
if (maxBufferPx < minBufferPx && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx');
|
|
}
|
|
this._itemSize = itemSize;
|
|
this._minBufferPx = minBufferPx;
|
|
this._maxBufferPx = maxBufferPx;
|
|
this._updateTotalContentSize();
|
|
this._updateRenderedRange();
|
|
}
|
|
onContentScrolled() {
|
|
this._updateRenderedRange();
|
|
}
|
|
onDataLengthChanged() {
|
|
this._updateTotalContentSize();
|
|
this._updateRenderedRange();
|
|
}
|
|
onContentRendered() {}
|
|
onRenderedOffsetChanged() {}
|
|
scrollToIndex(index, behavior) {
|
|
if (this._viewport) {
|
|
this._viewport.scrollToOffset(index * this._itemSize, behavior);
|
|
}
|
|
}
|
|
_updateTotalContentSize() {
|
|
if (!this._viewport) {
|
|
return;
|
|
}
|
|
this._viewport.setTotalContentSize(this._viewport.getDataLength() * this._itemSize);
|
|
}
|
|
_updateRenderedRange() {
|
|
if (!this._viewport) {
|
|
return;
|
|
}
|
|
const renderedRange = this._viewport.getRenderedRange();
|
|
const newRange = {
|
|
start: renderedRange.start,
|
|
end: renderedRange.end
|
|
};
|
|
const viewportSize = this._viewport.getViewportSize();
|
|
const dataLength = this._viewport.getDataLength();
|
|
let scrollOffset = this._viewport.measureScrollOffset();
|
|
let firstVisibleIndex = this._itemSize > 0 ? scrollOffset / this._itemSize : 0;
|
|
if (newRange.end > dataLength) {
|
|
const maxVisibleItems = Math.ceil(viewportSize / this._itemSize);
|
|
const newVisibleIndex = Math.max(0, Math.min(firstVisibleIndex, dataLength - maxVisibleItems));
|
|
if (firstVisibleIndex != newVisibleIndex) {
|
|
firstVisibleIndex = newVisibleIndex;
|
|
scrollOffset = newVisibleIndex * this._itemSize;
|
|
newRange.start = Math.floor(firstVisibleIndex);
|
|
}
|
|
newRange.end = Math.max(0, Math.min(dataLength, newRange.start + maxVisibleItems));
|
|
}
|
|
const startBuffer = scrollOffset - newRange.start * this._itemSize;
|
|
if (startBuffer < this._minBufferPx && newRange.start != 0) {
|
|
const expandStart = Math.ceil((this._maxBufferPx - startBuffer) / this._itemSize);
|
|
newRange.start = Math.max(0, newRange.start - expandStart);
|
|
newRange.end = Math.min(dataLength, Math.ceil(firstVisibleIndex + (viewportSize + this._minBufferPx) / this._itemSize));
|
|
} else {
|
|
const endBuffer = newRange.end * this._itemSize - (scrollOffset + viewportSize);
|
|
if (endBuffer < this._minBufferPx && newRange.end != dataLength) {
|
|
const expandEnd = Math.ceil((this._maxBufferPx - endBuffer) / this._itemSize);
|
|
if (expandEnd > 0) {
|
|
newRange.end = Math.min(dataLength, newRange.end + expandEnd);
|
|
newRange.start = Math.max(0, Math.floor(firstVisibleIndex - this._minBufferPx / this._itemSize));
|
|
}
|
|
}
|
|
}
|
|
this._viewport.setRenderedRange(newRange);
|
|
this._viewport.setRenderedContentOffset(Math.round(this._itemSize * newRange.start));
|
|
this._scrolledIndexChange.next(Math.floor(firstVisibleIndex));
|
|
}
|
|
}
|
|
function _fixedSizeVirtualScrollStrategyFactory(fixedSizeDir) {
|
|
return fixedSizeDir._scrollStrategy;
|
|
}
|
|
class CdkFixedSizeVirtualScroll {
|
|
get itemSize() {
|
|
return this._itemSize;
|
|
}
|
|
set itemSize(value) {
|
|
this._itemSize = coerceNumberProperty(value);
|
|
}
|
|
_itemSize = 20;
|
|
get minBufferPx() {
|
|
return this._minBufferPx;
|
|
}
|
|
set minBufferPx(value) {
|
|
this._minBufferPx = coerceNumberProperty(value);
|
|
}
|
|
_minBufferPx = 100;
|
|
get maxBufferPx() {
|
|
return this._maxBufferPx;
|
|
}
|
|
set maxBufferPx(value) {
|
|
this._maxBufferPx = coerceNumberProperty(value);
|
|
}
|
|
_maxBufferPx = 200;
|
|
_scrollStrategy = new FixedSizeVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx);
|
|
ngOnChanges() {
|
|
this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkFixedSizeVirtualScroll,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkFixedSizeVirtualScroll,
|
|
isStandalone: true,
|
|
selector: "cdk-virtual-scroll-viewport[itemSize]",
|
|
inputs: {
|
|
itemSize: "itemSize",
|
|
minBufferPx: "minBufferPx",
|
|
maxBufferPx: "maxBufferPx"
|
|
},
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLL_STRATEGY,
|
|
useFactory: _fixedSizeVirtualScrollStrategyFactory,
|
|
deps: [forwardRef(() => CdkFixedSizeVirtualScroll)]
|
|
}],
|
|
usesOnChanges: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkFixedSizeVirtualScroll,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: 'cdk-virtual-scroll-viewport[itemSize]',
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLL_STRATEGY,
|
|
useFactory: _fixedSizeVirtualScrollStrategyFactory,
|
|
deps: [forwardRef(() => CdkFixedSizeVirtualScroll)]
|
|
}]
|
|
}]
|
|
}],
|
|
propDecorators: {
|
|
itemSize: [{
|
|
type: Input
|
|
}],
|
|
minBufferPx: [{
|
|
type: Input
|
|
}],
|
|
maxBufferPx: [{
|
|
type: Input
|
|
}]
|
|
}
|
|
});
|
|
|
|
const DEFAULT_SCROLL_TIME = 20;
|
|
class ScrollDispatcher {
|
|
_ngZone = inject(NgZone);
|
|
_platform = inject(Platform);
|
|
_renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
_cleanupGlobalListener;
|
|
constructor() {}
|
|
_scrolled = new Subject();
|
|
_scrolledCount = 0;
|
|
scrollContainers = new Map();
|
|
register(scrollable) {
|
|
if (!this.scrollContainers.has(scrollable)) {
|
|
this.scrollContainers.set(scrollable, scrollable.elementScrolled().subscribe(() => this._scrolled.next(scrollable)));
|
|
}
|
|
}
|
|
deregister(scrollable) {
|
|
const scrollableReference = this.scrollContainers.get(scrollable);
|
|
if (scrollableReference) {
|
|
scrollableReference.unsubscribe();
|
|
this.scrollContainers.delete(scrollable);
|
|
}
|
|
}
|
|
scrolled(auditTimeInMs = DEFAULT_SCROLL_TIME) {
|
|
if (!this._platform.isBrowser) {
|
|
return of();
|
|
}
|
|
return new Observable(observer => {
|
|
if (!this._cleanupGlobalListener) {
|
|
this._cleanupGlobalListener = this._ngZone.runOutsideAngular(() => this._renderer.listen('document', 'scroll', () => this._scrolled.next()));
|
|
}
|
|
const subscription = auditTimeInMs > 0 ? this._scrolled.pipe(auditTime(auditTimeInMs)).subscribe(observer) : this._scrolled.subscribe(observer);
|
|
this._scrolledCount++;
|
|
return () => {
|
|
subscription.unsubscribe();
|
|
this._scrolledCount--;
|
|
if (!this._scrolledCount) {
|
|
this._cleanupGlobalListener?.();
|
|
this._cleanupGlobalListener = undefined;
|
|
}
|
|
};
|
|
});
|
|
}
|
|
ngOnDestroy() {
|
|
this._cleanupGlobalListener?.();
|
|
this._cleanupGlobalListener = undefined;
|
|
this.scrollContainers.forEach((_, container) => this.deregister(container));
|
|
this._scrolled.complete();
|
|
}
|
|
ancestorScrolled(elementOrElementRef, auditTimeInMs) {
|
|
const ancestors = this.getAncestorScrollContainers(elementOrElementRef);
|
|
return this.scrolled(auditTimeInMs).pipe(filter(target => !target || ancestors.indexOf(target) > -1));
|
|
}
|
|
getAncestorScrollContainers(elementOrElementRef) {
|
|
const scrollingContainers = [];
|
|
this.scrollContainers.forEach((_subscription, scrollable) => {
|
|
if (this._scrollableContainsElement(scrollable, elementOrElementRef)) {
|
|
scrollingContainers.push(scrollable);
|
|
}
|
|
});
|
|
return scrollingContainers;
|
|
}
|
|
_scrollableContainsElement(scrollable, elementOrElementRef) {
|
|
let element = coerceElement(elementOrElementRef);
|
|
let scrollableElement = scrollable.getElementRef().nativeElement;
|
|
do {
|
|
if (element == scrollableElement) {
|
|
return true;
|
|
}
|
|
} while (element = element.parentElement);
|
|
return false;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollDispatcher,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollDispatcher,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollDispatcher,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class CdkScrollable {
|
|
elementRef = inject(ElementRef);
|
|
scrollDispatcher = inject(ScrollDispatcher);
|
|
ngZone = inject(NgZone);
|
|
dir = inject(Directionality, {
|
|
optional: true
|
|
});
|
|
_scrollElement = this.elementRef.nativeElement;
|
|
_destroyed = new Subject();
|
|
_renderer = inject(Renderer2);
|
|
_cleanupScroll;
|
|
_elementScrolled = new Subject();
|
|
constructor() {}
|
|
ngOnInit() {
|
|
this._cleanupScroll = this.ngZone.runOutsideAngular(() => this._renderer.listen(this._scrollElement, 'scroll', event => this._elementScrolled.next(event)));
|
|
this.scrollDispatcher.register(this);
|
|
}
|
|
ngOnDestroy() {
|
|
this._cleanupScroll?.();
|
|
this._elementScrolled.complete();
|
|
this.scrollDispatcher.deregister(this);
|
|
this._destroyed.next();
|
|
this._destroyed.complete();
|
|
}
|
|
elementScrolled() {
|
|
return this._elementScrolled;
|
|
}
|
|
getElementRef() {
|
|
return this.elementRef;
|
|
}
|
|
scrollTo(options) {
|
|
const el = this.elementRef.nativeElement;
|
|
const isRtl = this.dir && this.dir.value == 'rtl';
|
|
if (options.left == null) {
|
|
options.left = isRtl ? options.end : options.start;
|
|
}
|
|
if (options.right == null) {
|
|
options.right = isRtl ? options.start : options.end;
|
|
}
|
|
if (options.bottom != null) {
|
|
options.top = el.scrollHeight - el.clientHeight - options.bottom;
|
|
}
|
|
if (isRtl && getRtlScrollAxisType() != RtlScrollAxisType.NORMAL) {
|
|
if (options.left != null) {
|
|
options.right = el.scrollWidth - el.clientWidth - options.left;
|
|
}
|
|
if (getRtlScrollAxisType() == RtlScrollAxisType.INVERTED) {
|
|
options.left = options.right;
|
|
} else if (getRtlScrollAxisType() == RtlScrollAxisType.NEGATED) {
|
|
options.left = options.right ? -options.right : options.right;
|
|
}
|
|
} else {
|
|
if (options.right != null) {
|
|
options.left = el.scrollWidth - el.clientWidth - options.right;
|
|
}
|
|
}
|
|
this._applyScrollToOptions(options);
|
|
}
|
|
_applyScrollToOptions(options) {
|
|
const el = this.elementRef.nativeElement;
|
|
if (supportsScrollBehavior()) {
|
|
el.scrollTo(options);
|
|
} else {
|
|
if (options.top != null) {
|
|
el.scrollTop = options.top;
|
|
}
|
|
if (options.left != null) {
|
|
el.scrollLeft = options.left;
|
|
}
|
|
}
|
|
}
|
|
measureScrollOffset(from) {
|
|
const LEFT = 'left';
|
|
const RIGHT = 'right';
|
|
const el = this.elementRef.nativeElement;
|
|
if (from == 'top') {
|
|
return el.scrollTop;
|
|
}
|
|
if (from == 'bottom') {
|
|
return el.scrollHeight - el.clientHeight - el.scrollTop;
|
|
}
|
|
const isRtl = this.dir && this.dir.value == 'rtl';
|
|
if (from == 'start') {
|
|
from = isRtl ? RIGHT : LEFT;
|
|
} else if (from == 'end') {
|
|
from = isRtl ? LEFT : RIGHT;
|
|
}
|
|
if (isRtl && getRtlScrollAxisType() == RtlScrollAxisType.INVERTED) {
|
|
if (from == LEFT) {
|
|
return el.scrollWidth - el.clientWidth - el.scrollLeft;
|
|
} else {
|
|
return el.scrollLeft;
|
|
}
|
|
} else if (isRtl && getRtlScrollAxisType() == RtlScrollAxisType.NEGATED) {
|
|
if (from == LEFT) {
|
|
return el.scrollLeft + el.scrollWidth - el.clientWidth;
|
|
} else {
|
|
return -el.scrollLeft;
|
|
}
|
|
} else {
|
|
if (from == LEFT) {
|
|
return el.scrollLeft;
|
|
} else {
|
|
return el.scrollWidth - el.clientWidth - el.scrollLeft;
|
|
}
|
|
}
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollable,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkScrollable,
|
|
isStandalone: true,
|
|
selector: "[cdk-scrollable], [cdkScrollable]",
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollable,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdk-scrollable], [cdkScrollable]'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
const DEFAULT_RESIZE_TIME = 20;
|
|
class ViewportRuler {
|
|
_platform = inject(Platform);
|
|
_listeners;
|
|
_viewportSize = null;
|
|
_change = new Subject();
|
|
_document = inject(DOCUMENT);
|
|
constructor() {
|
|
const ngZone = inject(NgZone);
|
|
const renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
ngZone.runOutsideAngular(() => {
|
|
if (this._platform.isBrowser) {
|
|
const changeListener = event => this._change.next(event);
|
|
this._listeners = [renderer.listen('window', 'resize', changeListener), renderer.listen('window', 'orientationchange', changeListener)];
|
|
}
|
|
this.change().subscribe(() => this._viewportSize = null);
|
|
});
|
|
}
|
|
ngOnDestroy() {
|
|
this._listeners?.forEach(cleanup => cleanup());
|
|
this._change.complete();
|
|
}
|
|
getViewportSize() {
|
|
if (!this._viewportSize) {
|
|
this._updateViewportSize();
|
|
}
|
|
const output = {
|
|
width: this._viewportSize.width,
|
|
height: this._viewportSize.height
|
|
};
|
|
if (!this._platform.isBrowser) {
|
|
this._viewportSize = null;
|
|
}
|
|
return output;
|
|
}
|
|
getViewportRect() {
|
|
const scrollPosition = this.getViewportScrollPosition();
|
|
const {
|
|
width,
|
|
height
|
|
} = this.getViewportSize();
|
|
return {
|
|
top: scrollPosition.top,
|
|
left: scrollPosition.left,
|
|
bottom: scrollPosition.top + height,
|
|
right: scrollPosition.left + width,
|
|
height,
|
|
width
|
|
};
|
|
}
|
|
getViewportScrollPosition() {
|
|
if (!this._platform.isBrowser) {
|
|
return {
|
|
top: 0,
|
|
left: 0
|
|
};
|
|
}
|
|
const document = this._document;
|
|
const window = this._getWindow();
|
|
const documentElement = document.documentElement;
|
|
const documentRect = documentElement.getBoundingClientRect();
|
|
const top = -documentRect.top || document.body?.scrollTop || window.scrollY || documentElement.scrollTop || 0;
|
|
const left = -documentRect.left || document.body?.scrollLeft || window.scrollX || documentElement.scrollLeft || 0;
|
|
return {
|
|
top,
|
|
left
|
|
};
|
|
}
|
|
change(throttleTime = DEFAULT_RESIZE_TIME) {
|
|
return throttleTime > 0 ? this._change.pipe(auditTime(throttleTime)) : this._change;
|
|
}
|
|
_getWindow() {
|
|
return this._document.defaultView || window;
|
|
}
|
|
_updateViewportSize() {
|
|
const window = this._getWindow();
|
|
this._viewportSize = this._platform.isBrowser ? {
|
|
width: window.innerWidth,
|
|
height: window.innerHeight
|
|
} : {
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ViewportRuler,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Injectable
|
|
});
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ViewportRuler,
|
|
providedIn: 'root'
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ViewportRuler,
|
|
decorators: [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: 'root'
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
const VIRTUAL_SCROLLABLE = new InjectionToken('VIRTUAL_SCROLLABLE');
|
|
class CdkVirtualScrollable extends CdkScrollable {
|
|
constructor() {
|
|
super();
|
|
}
|
|
measureViewportSize(orientation) {
|
|
const viewportEl = this.elementRef.nativeElement;
|
|
return orientation === 'horizontal' ? viewportEl.clientWidth : viewportEl.clientHeight;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollable,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkVirtualScrollable,
|
|
isStandalone: true,
|
|
usesInheritance: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollable,
|
|
decorators: [{
|
|
type: Directive
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
function rangesEqual(r1, r2) {
|
|
return r1.start == r2.start && r1.end == r2.end;
|
|
}
|
|
const SCROLL_SCHEDULER = typeof requestAnimationFrame !== 'undefined' ? animationFrameScheduler : asapScheduler;
|
|
const CDK_VIRTUAL_SCROLL_VIEWPORT = new InjectionToken('CDK_VIRTUAL_SCROLL_VIEWPORT');
|
|
class CdkVirtualScrollViewport extends CdkVirtualScrollable {
|
|
elementRef = inject(ElementRef);
|
|
_changeDetectorRef = inject(ChangeDetectorRef);
|
|
_scrollStrategy = inject(VIRTUAL_SCROLL_STRATEGY, {
|
|
optional: true
|
|
});
|
|
scrollable = inject(VIRTUAL_SCROLLABLE, {
|
|
optional: true
|
|
});
|
|
_platform = inject(Platform);
|
|
_detachedSubject = new Subject();
|
|
_renderedRangeSubject = new Subject();
|
|
_renderedContentOffsetSubject = new Subject();
|
|
get orientation() {
|
|
return this._orientation;
|
|
}
|
|
set orientation(orientation) {
|
|
if (this._orientation !== orientation) {
|
|
this._orientation = orientation;
|
|
this._calculateSpacerSize();
|
|
}
|
|
}
|
|
_orientation = 'vertical';
|
|
appendOnly = false;
|
|
scrolledIndexChange = new Observable(observer => this._scrollStrategy.scrolledIndexChange.subscribe(index => Promise.resolve().then(() => this.ngZone.run(() => observer.next(index)))));
|
|
_contentWrapper;
|
|
renderedRangeStream = this._renderedRangeSubject;
|
|
renderedContentOffset = this._renderedContentOffsetSubject.pipe(filter(offset => offset !== null), distinctUntilChanged());
|
|
_totalContentSize = 0;
|
|
_totalContentWidth = signal('', ...(ngDevMode ? [{
|
|
debugName: "_totalContentWidth"
|
|
}] : []));
|
|
_totalContentHeight = signal('', ...(ngDevMode ? [{
|
|
debugName: "_totalContentHeight"
|
|
}] : []));
|
|
_renderedContentTransform;
|
|
_renderedRange = {
|
|
start: 0,
|
|
end: 0
|
|
};
|
|
_dataLength = 0;
|
|
_viewportSize = 0;
|
|
_forOf = null;
|
|
_renderedContentOffset = 0;
|
|
_renderedContentOffsetNeedsRewrite = false;
|
|
_changeDetectionNeeded = signal(false, ...(ngDevMode ? [{
|
|
debugName: "_changeDetectionNeeded"
|
|
}] : []));
|
|
_runAfterChangeDetection = [];
|
|
_viewportChanges = Subscription.EMPTY;
|
|
_injector = inject(Injector);
|
|
_isDestroyed = false;
|
|
constructor() {
|
|
super();
|
|
const viewportRuler = inject(ViewportRuler);
|
|
if (!this._scrollStrategy && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.');
|
|
}
|
|
this._viewportChanges = viewportRuler.change().subscribe(() => {
|
|
this.checkViewportSize();
|
|
});
|
|
if (!this.scrollable) {
|
|
this.elementRef.nativeElement.classList.add('cdk-virtual-scrollable');
|
|
this.scrollable = this;
|
|
}
|
|
const ref = effect(() => {
|
|
if (this._changeDetectionNeeded()) {
|
|
this._doChangeDetection();
|
|
}
|
|
}, {
|
|
...(ngDevMode ? {
|
|
debugName: "ref"
|
|
} : {}),
|
|
injector: inject(ApplicationRef).injector
|
|
});
|
|
inject(DestroyRef).onDestroy(() => void ref.destroy());
|
|
}
|
|
ngOnInit() {
|
|
if (!this._platform.isBrowser) {
|
|
return;
|
|
}
|
|
if (this.scrollable === this) {
|
|
super.ngOnInit();
|
|
}
|
|
this.ngZone.runOutsideAngular(() => Promise.resolve().then(() => {
|
|
this._measureViewportSize();
|
|
this._scrollStrategy.attach(this);
|
|
this.scrollable.elementScrolled().pipe(startWith(null), auditTime(0, SCROLL_SCHEDULER), takeUntil(this._destroyed)).subscribe(() => this._scrollStrategy.onContentScrolled());
|
|
this._markChangeDetectionNeeded();
|
|
}));
|
|
}
|
|
ngOnDestroy() {
|
|
this.detach();
|
|
this._scrollStrategy.detach();
|
|
this._renderedRangeSubject.complete();
|
|
this._detachedSubject.complete();
|
|
this._viewportChanges.unsubscribe();
|
|
this._isDestroyed = true;
|
|
super.ngOnDestroy();
|
|
}
|
|
attach(forOf) {
|
|
if (this._forOf && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error('CdkVirtualScrollViewport is already attached.');
|
|
}
|
|
this.ngZone.runOutsideAngular(() => {
|
|
this._forOf = forOf;
|
|
this._forOf.dataStream.pipe(takeUntil(this._detachedSubject)).subscribe(data => {
|
|
const newLength = data.length;
|
|
if (newLength !== this._dataLength) {
|
|
this._dataLength = newLength;
|
|
this._scrollStrategy.onDataLengthChanged();
|
|
}
|
|
this._doChangeDetection();
|
|
});
|
|
});
|
|
}
|
|
detach() {
|
|
this._forOf = null;
|
|
this._detachedSubject.next();
|
|
}
|
|
getDataLength() {
|
|
return this._dataLength;
|
|
}
|
|
getViewportSize() {
|
|
return this._viewportSize;
|
|
}
|
|
getRenderedRange() {
|
|
return this._renderedRange;
|
|
}
|
|
measureBoundingClientRectWithScrollOffset(from) {
|
|
return this.getElementRef().nativeElement.getBoundingClientRect()[from];
|
|
}
|
|
setTotalContentSize(size) {
|
|
if (this._totalContentSize !== size) {
|
|
this._totalContentSize = size;
|
|
this._calculateSpacerSize();
|
|
this._markChangeDetectionNeeded();
|
|
}
|
|
}
|
|
setRenderedRange(range) {
|
|
if (!rangesEqual(this._renderedRange, range)) {
|
|
if (this.appendOnly) {
|
|
range = {
|
|
start: 0,
|
|
end: Math.max(this._renderedRange.end, range.end)
|
|
};
|
|
}
|
|
this._renderedRangeSubject.next(this._renderedRange = range);
|
|
this._markChangeDetectionNeeded(() => this._scrollStrategy.onContentRendered());
|
|
}
|
|
}
|
|
getOffsetToRenderedContentStart() {
|
|
return this._renderedContentOffsetNeedsRewrite ? null : this._renderedContentOffset;
|
|
}
|
|
setRenderedContentOffset(offset, to = 'to-start') {
|
|
offset = this.appendOnly && to === 'to-start' ? 0 : offset;
|
|
const isRtl = this.dir && this.dir.value == 'rtl';
|
|
const isHorizontal = this.orientation == 'horizontal';
|
|
const axis = isHorizontal ? 'X' : 'Y';
|
|
const axisDirection = isHorizontal && isRtl ? -1 : 1;
|
|
let transform = `translate${axis}(${Number(axisDirection * offset)}px)`;
|
|
this._renderedContentOffset = offset;
|
|
if (to === 'to-end') {
|
|
transform += ` translate${axis}(-100%)`;
|
|
this._renderedContentOffsetNeedsRewrite = true;
|
|
}
|
|
if (this._renderedContentTransform != transform) {
|
|
this._renderedContentTransform = transform;
|
|
this._markChangeDetectionNeeded(() => {
|
|
if (this._renderedContentOffsetNeedsRewrite) {
|
|
this._renderedContentOffset -= this.measureRenderedContentSize();
|
|
this._renderedContentOffsetNeedsRewrite = false;
|
|
this.setRenderedContentOffset(this._renderedContentOffset);
|
|
} else {
|
|
this._scrollStrategy.onRenderedOffsetChanged();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
scrollToOffset(offset, behavior = 'auto') {
|
|
const options = {
|
|
behavior
|
|
};
|
|
if (this.orientation === 'horizontal') {
|
|
options.start = offset;
|
|
} else {
|
|
options.top = offset;
|
|
}
|
|
this.scrollable.scrollTo(options);
|
|
}
|
|
scrollToIndex(index, behavior = 'auto') {
|
|
this._scrollStrategy.scrollToIndex(index, behavior);
|
|
}
|
|
measureScrollOffset(from) {
|
|
let measureScrollOffset;
|
|
if (this.scrollable == this) {
|
|
measureScrollOffset = _from => super.measureScrollOffset(_from);
|
|
} else {
|
|
measureScrollOffset = _from => this.scrollable.measureScrollOffset(_from);
|
|
}
|
|
return Math.max(0, measureScrollOffset(from ?? (this.orientation === 'horizontal' ? 'start' : 'top')) - this.measureViewportOffset());
|
|
}
|
|
measureViewportOffset(from) {
|
|
let fromRect;
|
|
const LEFT = 'left';
|
|
const RIGHT = 'right';
|
|
const isRtl = this.dir?.value == 'rtl';
|
|
if (from == 'start') {
|
|
fromRect = isRtl ? RIGHT : LEFT;
|
|
} else if (from == 'end') {
|
|
fromRect = isRtl ? LEFT : RIGHT;
|
|
} else if (from) {
|
|
fromRect = from;
|
|
} else {
|
|
fromRect = this.orientation === 'horizontal' ? 'left' : 'top';
|
|
}
|
|
const scrollerClientRect = this.scrollable.measureBoundingClientRectWithScrollOffset(fromRect);
|
|
const viewportClientRect = this.elementRef.nativeElement.getBoundingClientRect()[fromRect];
|
|
return viewportClientRect - scrollerClientRect;
|
|
}
|
|
measureRenderedContentSize() {
|
|
const contentEl = this._contentWrapper.nativeElement;
|
|
return this.orientation === 'horizontal' ? contentEl.offsetWidth : contentEl.offsetHeight;
|
|
}
|
|
measureRangeSize(range) {
|
|
if (!this._forOf) {
|
|
return 0;
|
|
}
|
|
return this._forOf.measureRangeSize(range, this.orientation);
|
|
}
|
|
checkViewportSize() {
|
|
this._measureViewportSize();
|
|
this._scrollStrategy.onDataLengthChanged();
|
|
}
|
|
_measureViewportSize() {
|
|
this._viewportSize = this.scrollable.measureViewportSize(this.orientation);
|
|
}
|
|
_markChangeDetectionNeeded(runAfter) {
|
|
if (runAfter) {
|
|
this._runAfterChangeDetection.push(runAfter);
|
|
}
|
|
if (untracked(this._changeDetectionNeeded)) {
|
|
return;
|
|
}
|
|
this.ngZone.runOutsideAngular(() => {
|
|
Promise.resolve().then(() => {
|
|
this.ngZone.run(() => {
|
|
this._changeDetectionNeeded.set(true);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
_doChangeDetection() {
|
|
if (this._isDestroyed) {
|
|
return;
|
|
}
|
|
this.ngZone.run(() => {
|
|
this._changeDetectorRef.markForCheck();
|
|
this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
|
|
this._renderedContentOffsetSubject.next(this.getOffsetToRenderedContentStart());
|
|
afterNextRender(() => {
|
|
this._changeDetectionNeeded.set(false);
|
|
const runAfterChangeDetection = this._runAfterChangeDetection;
|
|
this._runAfterChangeDetection = [];
|
|
for (const fn of runAfterChangeDetection) {
|
|
fn();
|
|
}
|
|
}, {
|
|
injector: this._injector
|
|
});
|
|
});
|
|
}
|
|
_calculateSpacerSize() {
|
|
this._totalContentHeight.set(this.orientation === 'horizontal' ? '' : `${this._totalContentSize}px`);
|
|
this._totalContentWidth.set(this.orientation === 'horizontal' ? `${this._totalContentSize}px` : '');
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollViewport,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Component
|
|
});
|
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
minVersion: "16.1.0",
|
|
version: "21.0.3",
|
|
type: CdkVirtualScrollViewport,
|
|
isStandalone: true,
|
|
selector: "cdk-virtual-scroll-viewport",
|
|
inputs: {
|
|
orientation: "orientation",
|
|
appendOnly: ["appendOnly", "appendOnly", booleanAttribute]
|
|
},
|
|
outputs: {
|
|
scrolledIndexChange: "scrolledIndexChange"
|
|
},
|
|
host: {
|
|
properties: {
|
|
"class.cdk-virtual-scroll-orientation-horizontal": "orientation === \"horizontal\"",
|
|
"class.cdk-virtual-scroll-orientation-vertical": "orientation !== \"horizontal\""
|
|
},
|
|
classAttribute: "cdk-virtual-scroll-viewport"
|
|
},
|
|
providers: [{
|
|
provide: CdkScrollable,
|
|
useFactory: () => inject(VIRTUAL_SCROLLABLE, {
|
|
optional: true
|
|
}) || inject(CdkVirtualScrollViewport)
|
|
}, {
|
|
provide: CDK_VIRTUAL_SCROLL_VIEWPORT,
|
|
useExisting: CdkVirtualScrollViewport
|
|
}],
|
|
viewQueries: [{
|
|
propertyName: "_contentWrapper",
|
|
first: true,
|
|
predicate: ["contentWrapper"],
|
|
descendants: true,
|
|
static: true
|
|
}],
|
|
usesInheritance: true,
|
|
ngImport: i0,
|
|
template: "<!--\n Wrap the rendered content in an element that will be used to offset it based on the scroll\n position.\n-->\n<div #contentWrapper class=\"cdk-virtual-scroll-content-wrapper\">\n <ng-content></ng-content>\n</div>\n<!--\n Spacer used to force the scrolling container to the correct size for the *total* number of items\n so that the scrollbar captures the size of the entire data set.\n-->\n<div class=\"cdk-virtual-scroll-spacer\"\n [style.width]=\"_totalContentWidth()\" [style.height]=\"_totalContentHeight()\"></div>\n",
|
|
styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}\n"],
|
|
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
encapsulation: i0.ViewEncapsulation.None
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollViewport,
|
|
decorators: [{
|
|
type: Component,
|
|
args: [{
|
|
selector: 'cdk-virtual-scroll-viewport',
|
|
host: {
|
|
'class': 'cdk-virtual-scroll-viewport',
|
|
'[class.cdk-virtual-scroll-orientation-horizontal]': 'orientation === "horizontal"',
|
|
'[class.cdk-virtual-scroll-orientation-vertical]': 'orientation !== "horizontal"'
|
|
},
|
|
encapsulation: ViewEncapsulation.None,
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
providers: [{
|
|
provide: CdkScrollable,
|
|
useFactory: () => inject(VIRTUAL_SCROLLABLE, {
|
|
optional: true
|
|
}) || inject(CdkVirtualScrollViewport)
|
|
}, {
|
|
provide: CDK_VIRTUAL_SCROLL_VIEWPORT,
|
|
useExisting: CdkVirtualScrollViewport
|
|
}],
|
|
template: "<!--\n Wrap the rendered content in an element that will be used to offset it based on the scroll\n position.\n-->\n<div #contentWrapper class=\"cdk-virtual-scroll-content-wrapper\">\n <ng-content></ng-content>\n</div>\n<!--\n Spacer used to force the scrolling container to the correct size for the *total* number of items\n so that the scrollbar captures the size of the entire data set.\n-->\n<div class=\"cdk-virtual-scroll-spacer\"\n [style.width]=\"_totalContentWidth()\" [style.height]=\"_totalContentHeight()\"></div>\n",
|
|
styles: ["cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}\n"]
|
|
}]
|
|
}],
|
|
ctorParameters: () => [],
|
|
propDecorators: {
|
|
orientation: [{
|
|
type: Input
|
|
}],
|
|
appendOnly: [{
|
|
type: Input,
|
|
args: [{
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
scrolledIndexChange: [{
|
|
type: Output
|
|
}],
|
|
_contentWrapper: [{
|
|
type: ViewChild,
|
|
args: ['contentWrapper', {
|
|
static: true
|
|
}]
|
|
}]
|
|
}
|
|
});
|
|
|
|
function getOffset(orientation, direction, node) {
|
|
const el = node;
|
|
if (!el.getBoundingClientRect) {
|
|
return 0;
|
|
}
|
|
const rect = el.getBoundingClientRect();
|
|
if (orientation === 'horizontal') {
|
|
return direction === 'start' ? rect.left : rect.right;
|
|
}
|
|
return direction === 'start' ? rect.top : rect.bottom;
|
|
}
|
|
class CdkVirtualForOf {
|
|
_viewContainerRef = inject(ViewContainerRef);
|
|
_template = inject(TemplateRef);
|
|
_differs = inject(IterableDiffers);
|
|
_viewRepeater = new _RecycleViewRepeaterStrategy();
|
|
_viewport = inject(CDK_VIRTUAL_SCROLL_VIEWPORT, {
|
|
skipSelf: true
|
|
});
|
|
viewChange = new Subject();
|
|
_dataSourceChanges = new Subject();
|
|
get cdkVirtualForOf() {
|
|
return this._cdkVirtualForOf;
|
|
}
|
|
set cdkVirtualForOf(value) {
|
|
this._cdkVirtualForOf = value;
|
|
if (isDataSource(value)) {
|
|
this._dataSourceChanges.next(value);
|
|
} else {
|
|
this._dataSourceChanges.next(new ArrayDataSource(isObservable(value) ? value : Array.from(value || [])));
|
|
}
|
|
}
|
|
_cdkVirtualForOf;
|
|
get cdkVirtualForTrackBy() {
|
|
return this._cdkVirtualForTrackBy;
|
|
}
|
|
set cdkVirtualForTrackBy(fn) {
|
|
this._needsUpdate = true;
|
|
this._cdkVirtualForTrackBy = fn ? (index, item) => fn(index + (this._renderedRange ? this._renderedRange.start : 0), item) : undefined;
|
|
}
|
|
_cdkVirtualForTrackBy;
|
|
set cdkVirtualForTemplate(value) {
|
|
if (value) {
|
|
this._needsUpdate = true;
|
|
this._template = value;
|
|
}
|
|
}
|
|
get cdkVirtualForTemplateCacheSize() {
|
|
return this._viewRepeater.viewCacheSize;
|
|
}
|
|
set cdkVirtualForTemplateCacheSize(size) {
|
|
this._viewRepeater.viewCacheSize = coerceNumberProperty(size);
|
|
}
|
|
dataStream = this._dataSourceChanges.pipe(startWith(null), pairwise(), switchMap(([prev, cur]) => this._changeDataSource(prev, cur)), shareReplay(1));
|
|
_differ = null;
|
|
_data = [];
|
|
_renderedItems = [];
|
|
_renderedRange = {
|
|
start: 0,
|
|
end: 0
|
|
};
|
|
_needsUpdate = false;
|
|
_destroyed = new Subject();
|
|
constructor() {
|
|
const ngZone = inject(NgZone);
|
|
this.dataStream.subscribe(data => {
|
|
this._data = data;
|
|
this._onRenderedDataChange();
|
|
});
|
|
this._viewport.renderedRangeStream.pipe(takeUntil(this._destroyed)).subscribe(range => {
|
|
this._renderedRange = range;
|
|
if (this.viewChange.observers.length) {
|
|
ngZone.run(() => this.viewChange.next(this._renderedRange));
|
|
}
|
|
this._onRenderedDataChange();
|
|
});
|
|
this._viewport.attach(this);
|
|
}
|
|
measureRangeSize(range, orientation) {
|
|
if (range.start >= range.end) {
|
|
return 0;
|
|
}
|
|
if ((range.start < this._renderedRange.start || range.end > this._renderedRange.end) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
throw Error(`Error: attempted to measure an item that isn't rendered.`);
|
|
}
|
|
const renderedStartIndex = range.start - this._renderedRange.start;
|
|
const rangeLen = range.end - range.start;
|
|
let firstNode;
|
|
let lastNode;
|
|
for (let i = 0; i < rangeLen; i++) {
|
|
const view = this._viewContainerRef.get(i + renderedStartIndex);
|
|
if (view && view.rootNodes.length) {
|
|
firstNode = lastNode = view.rootNodes[0];
|
|
break;
|
|
}
|
|
}
|
|
for (let i = rangeLen - 1; i > -1; i--) {
|
|
const view = this._viewContainerRef.get(i + renderedStartIndex);
|
|
if (view && view.rootNodes.length) {
|
|
lastNode = view.rootNodes[view.rootNodes.length - 1];
|
|
break;
|
|
}
|
|
}
|
|
return firstNode && lastNode ? getOffset(orientation, 'end', lastNode) - getOffset(orientation, 'start', firstNode) : 0;
|
|
}
|
|
ngDoCheck() {
|
|
if (this._differ && this._needsUpdate) {
|
|
const changes = this._differ.diff(this._renderedItems);
|
|
if (!changes) {
|
|
this._updateContext();
|
|
} else {
|
|
this._applyChanges(changes);
|
|
}
|
|
this._needsUpdate = false;
|
|
}
|
|
}
|
|
ngOnDestroy() {
|
|
this._viewport.detach();
|
|
this._dataSourceChanges.next(undefined);
|
|
this._dataSourceChanges.complete();
|
|
this.viewChange.complete();
|
|
this._destroyed.next();
|
|
this._destroyed.complete();
|
|
this._viewRepeater.detach();
|
|
}
|
|
_onRenderedDataChange() {
|
|
if (!this._renderedRange) {
|
|
return;
|
|
}
|
|
this._renderedItems = this._data.slice(this._renderedRange.start, this._renderedRange.end);
|
|
if (!this._differ) {
|
|
this._differ = this._differs.find(this._renderedItems).create((index, item) => {
|
|
return this.cdkVirtualForTrackBy ? this.cdkVirtualForTrackBy(index, item) : item;
|
|
});
|
|
}
|
|
this._needsUpdate = true;
|
|
}
|
|
_changeDataSource(oldDs, newDs) {
|
|
if (oldDs) {
|
|
oldDs.disconnect(this);
|
|
}
|
|
this._needsUpdate = true;
|
|
return newDs ? newDs.connect(this) : of();
|
|
}
|
|
_updateContext() {
|
|
const count = this._data.length;
|
|
let i = this._viewContainerRef.length;
|
|
while (i--) {
|
|
const view = this._viewContainerRef.get(i);
|
|
view.context.index = this._renderedRange.start + i;
|
|
view.context.count = count;
|
|
this._updateComputedContextProperties(view.context);
|
|
view.detectChanges();
|
|
}
|
|
}
|
|
_applyChanges(changes) {
|
|
this._viewRepeater.applyChanges(changes, this._viewContainerRef, (record, _adjustedPreviousIndex, currentIndex) => this._getEmbeddedViewArgs(record, currentIndex), record => record.item);
|
|
changes.forEachIdentityChange(record => {
|
|
const view = this._viewContainerRef.get(record.currentIndex);
|
|
view.context.$implicit = record.item;
|
|
});
|
|
const count = this._data.length;
|
|
let i = this._viewContainerRef.length;
|
|
while (i--) {
|
|
const view = this._viewContainerRef.get(i);
|
|
view.context.index = this._renderedRange.start + i;
|
|
view.context.count = count;
|
|
this._updateComputedContextProperties(view.context);
|
|
}
|
|
}
|
|
_updateComputedContextProperties(context) {
|
|
context.first = context.index === 0;
|
|
context.last = context.index === context.count - 1;
|
|
context.even = context.index % 2 === 0;
|
|
context.odd = !context.even;
|
|
}
|
|
_getEmbeddedViewArgs(record, index) {
|
|
return {
|
|
templateRef: this._template,
|
|
context: {
|
|
$implicit: record.item,
|
|
cdkVirtualForOf: this._cdkVirtualForOf,
|
|
index: -1,
|
|
count: -1,
|
|
first: false,
|
|
last: false,
|
|
odd: false,
|
|
even: false
|
|
},
|
|
index
|
|
};
|
|
}
|
|
static ngTemplateContextGuard(directive, context) {
|
|
return true;
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualForOf,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkVirtualForOf,
|
|
isStandalone: true,
|
|
selector: "[cdkVirtualFor][cdkVirtualForOf]",
|
|
inputs: {
|
|
cdkVirtualForOf: "cdkVirtualForOf",
|
|
cdkVirtualForTrackBy: "cdkVirtualForTrackBy",
|
|
cdkVirtualForTemplate: "cdkVirtualForTemplate",
|
|
cdkVirtualForTemplateCacheSize: "cdkVirtualForTemplateCacheSize"
|
|
},
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualForOf,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdkVirtualFor][cdkVirtualForOf]'
|
|
}]
|
|
}],
|
|
ctorParameters: () => [],
|
|
propDecorators: {
|
|
cdkVirtualForOf: [{
|
|
type: Input
|
|
}],
|
|
cdkVirtualForTrackBy: [{
|
|
type: Input
|
|
}],
|
|
cdkVirtualForTemplate: [{
|
|
type: Input
|
|
}],
|
|
cdkVirtualForTemplateCacheSize: [{
|
|
type: Input
|
|
}]
|
|
}
|
|
});
|
|
|
|
class CdkVirtualScrollableElement extends CdkVirtualScrollable {
|
|
constructor() {
|
|
super();
|
|
}
|
|
measureBoundingClientRectWithScrollOffset(from) {
|
|
return this.getElementRef().nativeElement.getBoundingClientRect()[from] - this.measureScrollOffset(from);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollableElement,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkVirtualScrollableElement,
|
|
isStandalone: true,
|
|
selector: "[cdkVirtualScrollingElement]",
|
|
host: {
|
|
classAttribute: "cdk-virtual-scrollable"
|
|
},
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLLABLE,
|
|
useExisting: CdkVirtualScrollableElement
|
|
}],
|
|
usesInheritance: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollableElement,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: '[cdkVirtualScrollingElement]',
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLLABLE,
|
|
useExisting: CdkVirtualScrollableElement
|
|
}],
|
|
host: {
|
|
'class': 'cdk-virtual-scrollable'
|
|
}
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class CdkVirtualScrollableWindow extends CdkVirtualScrollable {
|
|
constructor() {
|
|
super();
|
|
const document = inject(DOCUMENT);
|
|
this.elementRef = new ElementRef(document.documentElement);
|
|
this._scrollElement = document;
|
|
}
|
|
measureBoundingClientRectWithScrollOffset(from) {
|
|
return this.getElementRef().nativeElement.getBoundingClientRect()[from];
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollableWindow,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.Directive
|
|
});
|
|
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
type: CdkVirtualScrollableWindow,
|
|
isStandalone: true,
|
|
selector: "cdk-virtual-scroll-viewport[scrollWindow]",
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLLABLE,
|
|
useExisting: CdkVirtualScrollableWindow
|
|
}],
|
|
usesInheritance: true,
|
|
ngImport: i0
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkVirtualScrollableWindow,
|
|
decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: 'cdk-virtual-scroll-viewport[scrollWindow]',
|
|
providers: [{
|
|
provide: VIRTUAL_SCROLLABLE,
|
|
useExisting: CdkVirtualScrollableWindow
|
|
}]
|
|
}]
|
|
}],
|
|
ctorParameters: () => []
|
|
});
|
|
|
|
class CdkScrollableModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollableModule,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.NgModule
|
|
});
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollableModule,
|
|
imports: [CdkScrollable],
|
|
exports: [CdkScrollable]
|
|
});
|
|
static ɵinj = i0.ɵɵngDeclareInjector({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollableModule
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: CdkScrollableModule,
|
|
decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
exports: [CdkScrollable],
|
|
imports: [CdkScrollable]
|
|
}]
|
|
}]
|
|
});
|
|
class ScrollingModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollingModule,
|
|
deps: [],
|
|
target: i0.ɵɵFactoryTarget.NgModule
|
|
});
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({
|
|
minVersion: "14.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollingModule,
|
|
imports: [BidiModule, CdkScrollableModule, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollableWindow, CdkVirtualScrollableElement],
|
|
exports: [BidiModule, CdkScrollableModule, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport, CdkVirtualScrollableWindow, CdkVirtualScrollableElement]
|
|
});
|
|
static ɵinj = i0.ɵɵngDeclareInjector({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollingModule,
|
|
imports: [BidiModule, CdkScrollableModule, BidiModule, CdkScrollableModule]
|
|
});
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({
|
|
minVersion: "12.0.0",
|
|
version: "21.0.3",
|
|
ngImport: i0,
|
|
type: ScrollingModule,
|
|
decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [BidiModule, CdkScrollableModule, CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollableWindow, CdkVirtualScrollableElement],
|
|
exports: [BidiModule, CdkScrollableModule, CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport, CdkVirtualScrollableWindow, CdkVirtualScrollableElement]
|
|
}]
|
|
}]
|
|
});
|
|
|
|
export { CDK_VIRTUAL_SCROLL_VIEWPORT, CdkFixedSizeVirtualScroll, CdkScrollable, CdkScrollableModule, CdkVirtualForOf, CdkVirtualScrollViewport, CdkVirtualScrollable, CdkVirtualScrollableElement, CdkVirtualScrollableWindow, DEFAULT_RESIZE_TIME, DEFAULT_SCROLL_TIME, FixedSizeVirtualScrollStrategy, ScrollDispatcher, ScrollingModule, VIRTUAL_SCROLLABLE, VIRTUAL_SCROLL_STRATEGY, ViewportRuler, _fixedSizeVirtualScrollStrategyFactory };
|
|
//# sourceMappingURL=scrolling.mjs.map
|
|
|