| import { CommonModule } from '@angular/common'; |
| import { TemplatePortalDirective } from '@angular/cdk/portal'; |
| import { Directive, TemplateRef, ViewContainerRef, Component, Input, Output, EventEmitter, ContentChild, ChangeDetectionStrategy, ChangeDetectorRef, ViewChildren, ElementRef, HostListener, Renderer2, NgModule } from '@angular/core'; |
| import { DomSanitizer } from '@angular/platform-browser'; |
| import { Subject } from 'rxjs'; |
| import { debounceTime } from 'rxjs/operators'; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| class TdVirtualScrollRowDirective extends TemplatePortalDirective { |
| /** |
| * @param {?} templateRef |
| * @param {?} viewContainerRef |
| */ |
| constructor(templateRef, viewContainerRef) { |
| super(templateRef, viewContainerRef); |
| } |
| } |
| TdVirtualScrollRowDirective.decorators = [ |
| { type: Directive, args: [{ selector: '[tdVirtualScrollRow]' },] } |
| ]; |
| /** @nocollapse */ |
| TdVirtualScrollRowDirective.ctorParameters = () => [ |
| { type: TemplateRef }, |
| { type: ViewContainerRef } |
| ]; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| /** @type {?} */ |
| const TD_VIRTUAL_OFFSET = 2; |
| /** @type {?} */ |
| const SCROLL_DEBOUNCE = 200; |
| class TdVirtualScrollContainerComponent { |
| /** |
| * @param {?} _elementRef |
| * @param {?} _domSanitizer |
| * @param {?} _renderer |
| * @param {?} _changeDetectorRef |
| */ |
| constructor(_elementRef, _domSanitizer, _renderer, _changeDetectorRef) { |
| this._elementRef = _elementRef; |
| this._domSanitizer = _domSanitizer; |
| this._renderer = _renderer; |
| this._changeDetectorRef = _changeDetectorRef; |
| this._subs = []; |
| this._bottom = new Subject(); |
| this._initialized = false; |
| this._totalHeight = 0; |
| this._hostHeight = 0; |
| this._scrollVerticalOffset = 0; |
| this._fromRow = 0; |
| this._toRow = 0; |
| /** |
| * bottom: function |
| * Method to be executed when user scrolled to the last item of the list. |
| * An [ITdVirtualScrollBottomEvent] event is emitted |
| */ |
| this.bottom = new EventEmitter(); |
| /** |
| * trackBy?: TrackByFunction |
| * This accepts the same trackBy function [ngFor] does. |
| * https://angular.io/api/core/TrackByFunction |
| */ |
| this.trackBy = (index, item) => { |
| return item; |
| }; |
| } |
| /** |
| * data: any[] |
| * List of items to virtually iterate on. |
| * @param {?} data |
| * @return {?} |
| */ |
| set data(data) { |
| this._data = data; |
| if (this._initialized) { |
| this._calculateVirtualRows(); |
| } |
| this._changeDetectorRef.markForCheck(); |
| } |
| /** |
| * @return {?} |
| */ |
| get data() { |
| return this._data; |
| } |
| /** |
| * @return {?} |
| */ |
| get virtualData() { |
| return this._virtualData; |
| } |
| /** |
| * @return {?} |
| */ |
| get rowHeight() { |
| if (this._rows && this._rows.toArray()[0]) { |
| return this._rows.toArray()[0].nativeElement.getBoundingClientRect().height; |
| } |
| return 0; |
| } |
| /** |
| * @return {?} |
| */ |
| get totalHeight() { |
| return this._totalHeight; |
| } |
| /** |
| * @return {?} |
| */ |
| get fromRow() { |
| return this._fromRow; |
| } |
| /** |
| * @return {?} |
| */ |
| get toRow() { |
| return this._toRow; |
| } |
| /** |
| * @return {?} |
| */ |
| get offsetTransform() { |
| return this._offsetTransform; |
| } |
| /** |
| * @return {?} |
| */ |
| ngAfterViewInit() { |
| this._subs.push(this._rows.changes.subscribe(() => { |
| this._calculateVirtualRows(); |
| })); |
| this._initialized = true; |
| this._calculateVirtualRows(); |
| this._subs.push(this._bottom.pipe(debounceTime(SCROLL_DEBOUNCE)).subscribe(() => { |
| this.bottom.emit({ |
| lastRow: this._data[this._data.length - 1], |
| lastIndex: this.toRow, |
| }); |
| })); |
| } |
| /** |
| * @return {?} |
| */ |
| ngAfterViewChecked() { |
| /** @type {?} */ |
| let newHostHeight = this._elementRef.nativeElement.getBoundingClientRect().height; |
| if (this._hostHeight !== newHostHeight) { |
| this._hostHeight = newHostHeight; |
| if (this._initialized) { |
| this._calculateVirtualRows(); |
| } |
| } |
| } |
| /** |
| * @return {?} |
| */ |
| ngOnDestroy() { |
| if (this._subs) { |
| this._subs.forEach((sub) => { |
| sub.unsubscribe(); |
| }); |
| } |
| } |
| /** |
| * @param {?} event |
| * @return {?} |
| */ |
| handleScroll(event) { |
| /** @type {?} */ |
| let element = ((/** @type {?} */ (event.target))); |
| if (element) { |
| /** @type {?} */ |
| let verticalScroll = element.scrollTop; |
| if (this._scrollVerticalOffset !== verticalScroll) { |
| this._scrollVerticalOffset = verticalScroll; |
| if (this._initialized) { |
| this._calculateVirtualRows(); |
| } |
| } |
| if (this._initialized) { |
| // check to see if bottom was hit to throw the bottom event |
| if ((this._data.length * this.rowHeight) - (verticalScroll + this._hostHeight) === 0) { |
| this._bottom.next(); |
| } |
| } |
| } |
| } |
| /** |
| * Method to refresh and recalculate the virtual rows |
| * e.g. after changing the [data] content |
| * @return {?} |
| */ |
| refresh() { |
| this._calculateVirtualRows(); |
| } |
| /** |
| * Method to scroll to a specific row of the list. |
| * @param {?} row |
| * @return {?} |
| */ |
| scrollTo(row) { |
| this._elementRef.nativeElement.scrollTop = row * this.rowHeight; |
| this._changeDetectorRef.markForCheck(); |
| } |
| /** |
| * Method to scroll to the start of the list. |
| * @return {?} |
| */ |
| scrollToStart() { |
| this.scrollTo(0); |
| this._changeDetectorRef.markForCheck(); |
| } |
| /** |
| * Method to scroll to the end of the list. |
| * @return {?} |
| */ |
| scrollToEnd() { |
| this.scrollTo(this.totalHeight / this.rowHeight); |
| this._changeDetectorRef.markForCheck(); |
| } |
| /** |
| * @return {?} |
| */ |
| _calculateVirtualRows() { |
| if (this._data) { |
| this._totalHeight = this._data.length * this.rowHeight; |
| /** @type {?} */ |
| let fromRow = Math.floor((this._scrollVerticalOffset / this.rowHeight)) - TD_VIRTUAL_OFFSET; |
| this._fromRow = fromRow > 0 ? fromRow : 0; |
| /** @type {?} */ |
| let range = Math.floor((this._hostHeight / this.rowHeight)) + (TD_VIRTUAL_OFFSET * 2); |
| /** @type {?} */ |
| let toRow = range + this.fromRow; |
| if (isFinite(toRow) && toRow > this._data.length) { |
| toRow = this._data.length; |
| } |
| else if (!isFinite(toRow)) { |
| toRow = TD_VIRTUAL_OFFSET; |
| } |
| this._toRow = toRow; |
| } |
| else { |
| this._totalHeight = 0; |
| this._fromRow = 0; |
| this._toRow = 0; |
| } |
| /** @type {?} */ |
| let offset = 0; |
| if (this._scrollVerticalOffset > (TD_VIRTUAL_OFFSET * this.rowHeight)) { |
| offset = this.fromRow * this.rowHeight; |
| } |
| this._offsetTransform = this._domSanitizer.bypassSecurityTrustStyle('translateY(' + (offset - this.totalHeight) + 'px)'); |
| if (this._data) { |
| this._virtualData = this.data.slice(this.fromRow, this.toRow); |
| } |
| // mark for check at the end of the queue so we are sure |
| // that the changes will be marked |
| Promise.resolve().then(() => { |
| this._changeDetectorRef.markForCheck(); |
| }); |
| } |
| } |
| TdVirtualScrollContainerComponent.decorators = [ |
| { type: Component, args: [{ |
| selector: 'td-virtual-scroll-container', |
| template: "<div [style.height.px]=\"totalHeight\"></div>\n<div [style.transform]=\"offsetTransform\"\n [style.position]=\"'absolute'\"\n [style.width.%]=\"100\">\n <ng-template let-row\n let-index=\"index\"\n ngFor\n [ngForOf]=\"virtualData\"\n [ngForTrackBy]=\"trackBy\">\n <div #rowElement\n [style.width.%]=\"100\">\n <ng-template *ngIf=\"_rowTemplate\"\n [ngTemplateOutlet]=\"_rowTemplate.templateRef\"\n [ngTemplateOutletContext]=\"{row: row,\n index: (fromRow + index),\n first: (fromRow + index) === 0,\n last: (fromRow + index) === (data.length - 1),\n odd: ((fromRow + index + 1) % 2) === 1,\n even: ((fromRow + index + 1) % 2) === 0}\">\n </ng-template>\n </div>\n </ng-template>\n</div>", |
| changeDetection: ChangeDetectionStrategy.OnPush, |
| styles: [":host{display:block;height:100%;width:100%;overflow:auto;position:relative}"] |
| }] } |
| ]; |
| /** @nocollapse */ |
| TdVirtualScrollContainerComponent.ctorParameters = () => [ |
| { type: ElementRef }, |
| { type: DomSanitizer }, |
| { type: Renderer2 }, |
| { type: ChangeDetectorRef } |
| ]; |
| TdVirtualScrollContainerComponent.propDecorators = { |
| data: [{ type: Input, args: ['data',] }], |
| bottom: [{ type: Output }], |
| _rows: [{ type: ViewChildren, args: ['rowElement',] }], |
| _rowTemplate: [{ type: ContentChild, args: [TdVirtualScrollRowDirective,] }], |
| trackBy: [{ type: Input, args: ['trackBy',] }], |
| handleScroll: [{ type: HostListener, args: ['scroll', ['$event'],] }] |
| }; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| /** @type {?} */ |
| const TD_VIRTUAL_SCROLL = [ |
| TdVirtualScrollRowDirective, |
| TdVirtualScrollContainerComponent, |
| ]; |
| class CovalentVirtualScrollModule { |
| } |
| CovalentVirtualScrollModule.decorators = [ |
| { type: NgModule, args: [{ |
| imports: [ |
| CommonModule, |
| ], |
| declarations: [ |
| TD_VIRTUAL_SCROLL, |
| ], |
| exports: [ |
| TD_VIRTUAL_SCROLL, |
| ], |
| },] } |
| ]; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc |
| */ |
| |
| export { CovalentVirtualScrollModule, TdVirtualScrollContainerComponent, TdVirtualScrollRowDirective }; |
| |
| //# sourceMappingURL=covalent-core-virtual-scroll.js.map |