UNPKG

@transunion-ui/tablejs

Version:
1,036 lines (1,021 loc) 285 kB
import * as i0 from '@angular/core'; import { Component, ViewEncapsulation, ViewContainerRef, ViewChild, Injectable, Directive, Input, EventEmitter, Inject, ContentChild, Output, InjectionToken, ElementRef, Injector, HostListener, NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import * as i1 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import { BehaviorSubject, Subject, take } from 'rxjs'; import { ResizeSensor } from 'css-element-queries'; import * as i3 from '@angular/cdk/overlay'; import { OverlayConfig } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import { BrowserModule } from '@angular/platform-browser'; class HorizResizeGripComponent { constructor() { } } HorizResizeGripComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: HorizResizeGripComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); HorizResizeGripComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.3", type: HorizResizeGripComponent, selector: "tablejs-horiz-resize-grip", host: { classAttribute: "resize-grip" }, ngImport: i0, template: "<i class=\"fas fa-angle-left fa-xs\"></i><i class=\"fas fa-angle-right fa-xs\"></i>", styles: [".resize-grip{cursor:ew-resize;position:absolute;right:0;top:0;height:100%;width:30px;padding:0;margin:0;display:block}.resize-grip i{left:.5px;color:#fff;position:relative;top:50%;transform:translateY(-8px)}\n"], encapsulation: i0.ViewEncapsulation.None }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: HorizResizeGripComponent, decorators: [{ type: Component, args: [{ selector: 'tablejs-horiz-resize-grip', host: { class: 'resize-grip' }, encapsulation: ViewEncapsulation.None, template: "<i class=\"fas fa-angle-left fa-xs\"></i><i class=\"fas fa-angle-right fa-xs\"></i>", styles: [".resize-grip{cursor:ew-resize;position:absolute;right:0;top:0;height:100%;width:30px;padding:0;margin:0;display:block}.resize-grip i{left:.5px;color:#fff;position:relative;top:50%;transform:translateY(-8px)}\n"] }] }], ctorParameters: function () { return []; } }); class ReorderGripComponent { constructor() { } } ReorderGripComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ReorderGripComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); ReorderGripComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.3", type: ReorderGripComponent, selector: "tablejs-reorder-grip", host: { classAttribute: "col-dots-container" }, ngImport: i0, template: "<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>", styles: ["@charset \"UTF-8\";.col-dots-container{cursor:move;cursor:grab;position:absolute;display:block;left:0;top:0;height:100%;width:30px;z-index:5}.col-dots-container .dots-3{display:inline-block;opacity:.5}th:hover .dots-3{display:inline-block;opacity:1}.dots-3{position:relative;top:50%;width:4px;display:inline-block;overflow:hidden;transform:translateY(-50%)}.dots-3:after{content:\"\\2807\";font-size:14px}\n"], encapsulation: i0.ViewEncapsulation.None }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ReorderGripComponent, decorators: [{ type: Component, args: [{ selector: 'tablejs-reorder-grip', host: { class: 'col-dots-container' }, encapsulation: ViewEncapsulation.None, template: "<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>\n<span class=\"dots-3\"></span>", styles: ["@charset \"UTF-8\";.col-dots-container{cursor:move;cursor:grab;position:absolute;display:block;left:0;top:0;height:100%;width:30px;z-index:5}.col-dots-container .dots-3{display:inline-block;opacity:.5}th:hover .dots-3{display:inline-block;opacity:1}.dots-3{position:relative;top:50%;width:4px;display:inline-block;overflow:hidden;transform:translateY(-50%)}.dots-3:after{content:\"\\2807\";font-size:14px}\n"] }] }], ctorParameters: function () { return []; } }); class DragAndDropGhostComponent { constructor(viewContainerRef, cdr) { this.viewContainerRef = viewContainerRef; this.cdr = cdr; this.left = 0; this.top = 0; this._contextToLoad = null; } ngAfterViewInit() { this.ref.clear(); if (this._templateToLoad) { this.ref.createEmbeddedView(this._templateToLoad, this._contextToLoad); this.cdr.detectChanges(); } } updateView(template, context = null) { this._templateToLoad = template; this._contextToLoad = context; } getTransform() { return 'translate(' + this.left + 'px, ' + this.top + 'px'; } } DragAndDropGhostComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: DragAndDropGhostComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); DragAndDropGhostComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.3", type: DragAndDropGhostComponent, selector: "tablejs-drag-and-drop-ghost", host: { classAttribute: "drag-and-drop-ghost" }, viewQueries: [{ propertyName: "ref", first: true, predicate: ["ref"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<div class=\"drag-and-drop-ghost\" [ngStyle]=\"{ 'transform': getTransform() }\">\n <div #ref style=\"display: none;\"></div>\n</div>\n", styles: [".drag-and-drop-ghost{position:fixed;display:block;width:100%;height:100px;top:0;left:0;padding:0;margin:0;align-items:center;cursor:move!important;font-size:14px;overflow:visible;text-overflow:ellipsis;-webkit-user-select:none;user-select:none;z-index:10;opacity:1}.drag-and-drop-ghost img{pointer-events:none;position:inherit;border:1px solid #dddddd}\n"], directives: [{ type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], encapsulation: i0.ViewEncapsulation.None }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: DragAndDropGhostComponent, decorators: [{ type: Component, args: [{ selector: 'tablejs-drag-and-drop-ghost', encapsulation: ViewEncapsulation.None, host: { class: 'drag-and-drop-ghost' }, template: "<div class=\"drag-and-drop-ghost\" [ngStyle]=\"{ 'transform': getTransform() }\">\n <div #ref style=\"display: none;\"></div>\n</div>\n", styles: [".drag-and-drop-ghost{position:fixed;display:block;width:100%;height:100px;top:0;left:0;padding:0;margin:0;align-items:center;cursor:move!important;font-size:14px;overflow:visible;text-overflow:ellipsis;-webkit-user-select:none;user-select:none;z-index:10;opacity:1}.drag-and-drop-ghost img{pointer-events:none;position:inherit;border:1px solid #dddddd}\n"] }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { ref: [{ type: ViewChild, args: ['ref', { read: ViewContainerRef }] }] } }); class TablejsGridProxy { constructor() { } } TablejsGridProxy.GRID_COUNT = 0; class ColumnReorderEvent { constructor() { } } ColumnReorderEvent.ON_REORDER = 'onReorder'; ColumnReorderEvent.ON_REORDER_START = 'onReorderStart'; ColumnReorderEvent.ON_REORDER_END = 'onReorderEnd'; class ColumnResizeEvent { } ColumnResizeEvent.ON_RESIZE = 'onResize'; ColumnResizeEvent.ON_RESIZE_START = 'onResizeStart'; ColumnResizeEvent.ON_RESIZE_END = 'onResizeEnd'; class GridEvent { } GridEvent.ON_INITIALIZED = 'onInitialized'; class GridService { constructor() { this.linkedDirectiveObjs = {}; this.containsInitialWidthSettings = new BehaviorSubject(undefined); } getParentTablejsGridDirective(el) { while (el !== null && el.getAttribute('tablejsGrid') === null) { el = el.parentElement; } return el; } triggerHasInitialWidths(hasWidths) { this.containsInitialWidthSettings.next(hasWidths); } } GridService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: GridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); GridService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: GridService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: GridService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return []; } }); class DirectiveRegistrationService { constructor(gridService) { this.gridService = gridService; this.nexuses = []; } setVirtualNexus(virtualForDirective, scrollViewportDirective) { const nexus = { scrollViewportDirective, virtualForDirective }; this.nexuses.push(nexus); return nexus; } clearVirtualNexus(nexus) { if (!nexus) { return; } nexus.scrollViewportDirective = null; nexus.virtualForDirective = null; const index = this.nexuses.indexOf(nexus); if (index === -1) { return; } this.nexuses.splice(index, 1); } getVirtualNexusFromViewport(scrollViewportDirective) { return this.nexuses.filter((nexus) => nexus.scrollViewportDirective === scrollViewportDirective)[0]; } registerNodeAttributes(node) { if (node.getAttribute) { if (node.getAttribute('reordergrip') !== null) { this.registerReorderGripOnGridDirective(node, true); } if (node.getAttribute('resizablegrip') !== null) { this.registerResizableGripOnGridDirective(node, true); } if (node.getAttribute('tablejsDataColClasses') !== null) { this.registerDataColClassesOnGridDirective(node, true); } if (node.getAttribute('tablejsDataColClass') !== null) { this.registerDataColClassOnGridDirective(node, true); } if (node.getAttribute('tablejsGridRow') !== null) { this.registerRowsOnGridDirective(node, true); } } } registerReorderGripOnGridDirective(node, fromMutation = false) { const el = this.gridService.getParentTablejsGridDirective(node); if (el !== null) { el['gridDirective'].addReorderGrip(node, fromMutation); } } registerResizableGripOnGridDirective(node, fromMutation = false) { const el = this.gridService.getParentTablejsGridDirective(node); if (el !== null) { el['gridDirective'].addResizableGrip(node, fromMutation); } } registerDataColClassesOnGridDirective(node, fromMutation = false) { const el = this.gridService.getParentTablejsGridDirective(node); node.dataClasses = node.getAttribute('tablejsdatacolclasses').replace(new RegExp(' ', 'g'), '').split(','); el['gridDirective'].addColumnsWithDataClasses(node, fromMutation); } registerDataColClassOnGridDirective(node, fromMutation = false) { const el = this.gridService.getParentTablejsGridDirective(node); if (!el) { return; } const cls = node.getAttribute('tablejsDataColClass'); if (cls) { node.classList.add(cls); } const initialWidth = node.getAttribute('initialWidth'); this.gridService.triggerHasInitialWidths(initialWidth ? true : false); el['gridDirective'].initialWidths[cls] = initialWidth; } registerRowsOnGridDirective(node, fromMutation = false) { node.classList.add('reorderable-table-row'); const el = this.gridService.getParentTablejsGridDirective(node); if (el !== null) { el['gridDirective'].addRow(node, fromMutation); } } registerViewportOnGridDirective(node) { const el = this.gridService.getParentTablejsGridDirective(node); if (el !== null) { el['gridDirective'].infiniteScrollViewports = [node]; } } } DirectiveRegistrationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: DirectiveRegistrationService, deps: [{ token: GridService }], target: i0.ɵɵFactoryTarget.Injectable }); DirectiveRegistrationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: DirectiveRegistrationService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: DirectiveRegistrationService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: GridService }]; } }); class TablejsForOfContext { constructor($implicit, tablejsVirtualForOf, index, count) { this.$implicit = $implicit; this.tablejsVirtualForOf = tablejsVirtualForOf; this.index = index; this.count = count; } get first() { return this.index === 0; } get last() { return this.index === this.count - 1; } get even() { return this.index % 2 === 0; } get odd() { return !this.even; } } class VirtualForDirective { constructor(_viewContainer, _template, _differs, elementRef, directiveRegistrationService) { this._viewContainer = _viewContainer; this._template = _template; this._differs = _differs; this.elementRef = elementRef; this.directiveRegistrationService = directiveRegistrationService; this.changes = new Subject(); this._tablejsForOf = null; this._differ = null; this._parent = this._viewContainer.element.nativeElement.parentElement; while (this._parent !== null && this._parent !== undefined && this._parent.scrollViewportDirective === undefined) { this._parent = this._parent.parentElement; } if (this._parent === null || this._parent === undefined) { throw Error('No scrollViewportDirective found for tablejsForOf. Declare a scrollViewport using the scrollViewportDirective.'); } else { this._scrollViewportDirective = this._parent.scrollViewportDirective; this.directiveRegistrationService.setVirtualNexus(this, this._scrollViewportDirective); this._lastRange = this._scrollViewportDirective.range; this.rangeUpdatedSubscription$ = this._scrollViewportDirective.rangeUpdated.subscribe(rangeObj => { if (this.rangeIsDifferent(this._lastRange, rangeObj.range)) { this._lastRange = rangeObj.range; this._renderedItems = Array.from(this._tablejsForOf).slice(this._lastRange.extendedStartIndex, this._lastRange.extendedEndIndex); this._onRenderedDataChange(false); } }); } } set tablejsVirtualForOf(tablejsVirtualForOf) { this._tablejsForOf = tablejsVirtualForOf; this._onRenderedDataChange(); } /** * Asserts the correct type of the context for the template that `TablejsForOf` will render. * * The presence of this method is a signal to the Ivy template type-check compiler that the * `TablejsForOf` structural directive renders its template with a specific context type. */ static ngTemplateContextGuard(dir, ctx) { return true; } /** * A reference to the template that is stamped out for each item in the iterable. * @see [template reference variable](guide/template-reference-variables) */ set tablejsVirtualForTemplate(value) { if (value) { this._template = value; } } get template() { return this._template; } get tablejsVirtualForTrackBy() { return this._tablejsVirtualForTrackBy; } set tablejsVirtualForTrackBy(fn) { this._tablejsVirtualForTrackBy = fn ? (index, item) => fn(index + (this._lastRange ? this._lastRange.extendedStartIndex : 0), item) : undefined; this._onRenderedDataChange(); } rangeIsDifferent(range1, range2) { return range1.endIndex === range2.endIndex && range1.extendedEndIndex === range2.extendedEndIndex && range1.startIndex === range2.startIndex && range1.extendedStartIndex === range2.extendedStartIndex; } renderedItemsNeedUpdate() { return this._renderedItems.length !== this._lastRange.extendedEndIndex - this._lastRange.extendedStartIndex; } _onRenderedDataChange(updateRenderedItems = true) { if (!this._renderedItems) { return; } if (updateRenderedItems) { this._renderedItems = Array.from(this._tablejsForOf).slice(this._lastRange.extendedStartIndex, this._lastRange.extendedEndIndex); } if (!this._differ) { this._differ = this._differs.find(this._renderedItems).create((index, item) => { return this.tablejsVirtualForTrackBy ? this.tablejsVirtualForTrackBy(index, item) : item; }); } } ngDoCheck() { this.updateItems(); } updateItems() { if (this._differ) { const scrollToOrigin = this._tablejsForOf !== this._lastTablejsForOf; let diffChanges = null; if (this.renderedItemsNeedUpdate()) { this._onRenderedDataChange(); } try { diffChanges = this._differ.diff(this._renderedItems); } catch { this._differ = this._differs.find(this._renderedItems).create((index, item) => { return this.tablejsVirtualForTrackBy ? this.tablejsVirtualForTrackBy(index, item) : item; }); } if (scrollToOrigin) { this._lastTablejsForOf = this._tablejsForOf; } if (diffChanges || scrollToOrigin) { this.changes.next({ tablejsForOf: this._tablejsForOf, scrollToOrigin }); } } } ngOnDestroy() { this._lastTablejsForOf = null; this._tablejsForOf = null; this._differ = null; this._scrollViewportDirective = null; this._renderedItems = []; this._template = null; this._tablejsVirtualForTrackBy = null; if (this._parent) { this._parent.scrollViewportDirective = null; this._parent = null; } if (this.rangeUpdatedSubscription$) { this.rangeUpdatedSubscription$.unsubscribe(); } } } VirtualForDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: VirtualForDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.TemplateRef }, { token: i0.IterableDiffers }, { token: i0.ElementRef }, { token: DirectiveRegistrationService }], target: i0.ɵɵFactoryTarget.Directive }); VirtualForDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.3", type: VirtualForDirective, selector: "[tablejsVirtualFor][tablejsVirtualForOf]", inputs: { tablejsVirtualForOf: "tablejsVirtualForOf", tablejsVirtualForTemplate: "tablejsVirtualForTemplate", tablejsVirtualForTrackBy: "tablejsVirtualForTrackBy" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: VirtualForDirective, decorators: [{ type: Directive, args: [{ selector: '[tablejsVirtualFor][tablejsVirtualForOf]' }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.TemplateRef }, { type: i0.IterableDiffers }, { type: i0.ElementRef }, { type: DirectiveRegistrationService }]; }, propDecorators: { tablejsVirtualForOf: [{ type: Input }], tablejsVirtualForTemplate: [{ type: Input }], tablejsVirtualForTrackBy: [{ type: Input }] } }); class ScrollPrevSpacerComponent { constructor(elementRef) { this.elementRef = elementRef; } ngOnDestroy() { this.template = null; } } ScrollPrevSpacerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ScrollPrevSpacerComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ScrollPrevSpacerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.3", type: ScrollPrevSpacerComponent, selector: "tablejs-scroll-prev-spacer", viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true, static: true }], ngImport: i0, template: "\n<ng-template #template>\n <tr tablejsPrevSpacer style=\"display: block; position: relative;\"></tr>\n</ng-template>\n", styles: [""] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ScrollPrevSpacerComponent, decorators: [{ type: Component, args: [{ selector: 'tablejs-scroll-prev-spacer', template: "\n<ng-template #template>\n <tr tablejsPrevSpacer style=\"display: block; position: relative;\"></tr>\n</ng-template>\n", styles: [""] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { template: [{ type: ViewChild, args: ['template', { static: true }] }] } }); class ScrollViewportEvent { } ScrollViewportEvent.ON_ITEM_ADDED = 'onItemAdded'; ScrollViewportEvent.ON_ITEM_REMOVED = 'onItemRemoved'; ScrollViewportEvent.ON_ITEM_UPDATED = 'onItemUpdated'; ScrollViewportEvent.ON_RANGE_UPDATED = 'onRangeUpdated'; ScrollViewportEvent.ON_VIEWPORT_SCROLLED = 'onViewportScrolled'; ScrollViewportEvent.ON_VIEWPORT_READY = 'onViewportReady'; ScrollViewportEvent.ON_VIEWPORT_INITIALIZED = 'onViewportInitialized'; class ScrollDispatcherService { constructor() { } dispatchAddItemEvents(eventEmitter, element, i, viewport, viewportElement) { eventEmitter.emit({ element, index: i, viewport, viewportElement }); const itemAddedEvent = new CustomEvent(ScrollViewportEvent.ON_ITEM_ADDED, { detail: { element, index: i, viewport, viewportElement } }); viewportElement.dispatchEvent(itemAddedEvent); } dispatchUpdateItemEvents(eventEmitter, element, index, viewport, viewportElement) { eventEmitter.emit({ element, index, viewport, viewportElement }); const itemUpdatedEvent = new CustomEvent(ScrollViewportEvent.ON_ITEM_UPDATED, { detail: { element, index, viewport, viewportElement } }); viewportElement.dispatchEvent(itemUpdatedEvent); } dispatchRemoveItemEvents(eventEmitter, element, i, viewport, viewportElement) { eventEmitter.emit({ element, index: i, viewport, viewportElement }); const itemRemovedEvent = new CustomEvent(ScrollViewportEvent.ON_ITEM_REMOVED, { detail: { element, index: i, viewport, viewportElement } }); viewportElement.dispatchEvent(itemRemovedEvent); } dispatchViewportReadyEvents(eventEmitter, viewport, viewportElement) { eventEmitter.emit({ viewport, viewportElement }); const viewportReadyEvent = new CustomEvent(ScrollViewportEvent.ON_VIEWPORT_READY, { detail: { viewport, viewportElement } }); viewportElement.dispatchEvent(viewportReadyEvent); } dispatchViewportInitializedEvents(eventEmitter, viewport, viewportElement) { eventEmitter.emit({ viewport, viewportElement }); const viewportInitializedEvent = new CustomEvent(ScrollViewportEvent.ON_VIEWPORT_INITIALIZED, { detail: { viewport, viewportElement } }); viewportElement.dispatchEvent(viewportInitializedEvent); } dispatchRangeUpdateEvents(eventEmitter, range, viewport, viewportElement) { eventEmitter.emit({ range, viewport, viewportElement }); const rangeUpdatedEvent = new CustomEvent(ScrollViewportEvent.ON_ITEM_ADDED, { detail: { range, viewport, viewportElement } }); viewportElement.dispatchEvent(rangeUpdatedEvent); } dispatchViewportScrolledEvents(eventEmitter, scrollTop, overflow, viewport, viewportElement) { eventEmitter.emit({ scrollTop, firstItemOverflow: overflow, viewport, viewportElement }); const viewportScrolledEvent = new CustomEvent(ScrollViewportEvent.ON_ITEM_ADDED, { detail: { scrollTop, firstItemOverflow: overflow, viewport, viewportElement } }); viewportElement.dispatchEvent(viewportScrolledEvent); } } ScrollDispatcherService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ScrollDispatcherService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ScrollDispatcherService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ScrollDispatcherService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: ScrollDispatcherService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return []; } }); class OperatingSystemService { constructor() { } getOS() { const userAgent = window.navigator.userAgent; const platform = window.navigator.platform; const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']; const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']; const iosPlatforms = ['iPhone', 'iPad', 'iPod']; let os = null; if (macosPlatforms.indexOf(platform) !== -1) { os = 'Mac OS'; } else if (iosPlatforms.indexOf(platform) !== -1) { os = 'iOS'; } else if (windowsPlatforms.indexOf(platform) !== -1) { os = 'Windows'; } else if (/Android/.test(userAgent)) { os = 'Android'; } else if (!os && /Linux/.test(platform)) { os = 'Linux'; } return os; } isMac() { return this.getOS() === 'Mac OS' || this.getOS() === 'iOS'; } isPC() { return this.getOS() === 'Windows'; } } OperatingSystemService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: OperatingSystemService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); OperatingSystemService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: OperatingSystemService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.3", ngImport: i0, type: OperatingSystemService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return []; } }); class ScrollViewportDirective { constructor(elementRef, gridService, document, directiveRegistrationService, scrollDispatcherService, operatingSystem, cdr, rendererFactory) { this.elementRef = elementRef; this.gridService = gridService; this.document = document; this.directiveRegistrationService = directiveRegistrationService; this.scrollDispatcherService = scrollDispatcherService; this.operatingSystem = operatingSystem; this.cdr = cdr; this.rendererFactory = rendererFactory; this.templateRef = null; this.templateID = ''; this.generateCloneMethod = null; this._arrowUpSpeed = 1; this._arrowDownSpeed = 1; this._preItemOverflow = 1; this._postItemOverflow = 1; this._itemLoadLimit = Infinity; this.items = null; // Custom Elements Inputs this.templateid = null; this.preitemoverflow = 1; this.postitemoverflow = 1; this.arrowupspeed = 1; this.arrowdownspeed = 1; this.itemloadlimit = Infinity; this.itemAdded = new EventEmitter(); this.itemRemoved = new EventEmitter(); this.itemUpdated = new EventEmitter(); this.rangeUpdated = new EventEmitter(); this.viewportScrolled = new EventEmitter(); this.viewportReady = new EventEmitter(); this.viewportInitialized = new EventEmitter(); this.containerHeight = null; this.heightLookup = {}; this.itemVisibilityLookup = {}; this.listElm = null; this.listContent = null; this.prevSpacer = null; this.postSpacer = null; this.gridDirective = null; this.pauseViewportRenderUpdates = false; this.range = { startIndex: 0, endIndex: 1, extendedStartIndex: 0, extendedEndIndex: 1 }; this.lastRange = { startIndex: this.range.startIndex, endIndex: this.range.endIndex, extendedStartIndex: this.range.extendedStartIndex, extendedEndIndex: this.range.extendedEndIndex }; this.lastScrollTop = 0; this.currentScrollTop = 0; this.currentScrollChange = 0; this.template = null; this.estimatedFullContentHeight = 0; this.estimatedPreListHeight = 0; this.estimatedPostListHeight = 0; this.totalItemsCounted = 0; this.totalHeightCount = 0; this.itemName = ''; this.overflowHeightCount = 0; this.scrollChangeByFirstIndexedItem = 0; this.lastVisibleItemHeight = Infinity; this.adjustedStartIndex = null; this.forcedEndIndex = undefined; this.placeholderObject = {}; this.postItemOverflowCount = -1; this.preItemOverflowCount = -1; this.lastVisibleItemOverflow = 0; this.preOverflowHeight = 0; this.mouseIsOverViewport = false; this.lastHeight = 0; this.observer = null; this.handleMouseOver = null; this.handleMouseOut = null; this.handleKeyDown = null; this.cloneFromTemplateRef = false; this.viewportHasScrolled = false; this.templateContext = null; this.virtualNexus = null; this._cloneMethod = null; this.onTransitionEnd = (e) => { }; this.onTransitionRun = (e) => { }; this.onTransitionStart = (e) => { }; this.onTransitionCancel = (e) => { }; this.renderer = this.rendererFactory.createRenderer(null, null); this.elementRef.nativeElement.scrollViewportDirective = this; } get arrowUpSpeed() { return Number(this._arrowUpSpeed); } set arrowUpSpeed(value) { this._arrowUpSpeed = Number(value); } get arrowDownSpeed() { return Number(this._arrowDownSpeed); } set arrowDownSpeed(value) { this._arrowDownSpeed = Number(value); } get preItemOverflow() { return Number(this._preItemOverflow); } set preItemOverflow(value) { this._preItemOverflow = Number(value); } get postItemOverflow() { return Number(this._postItemOverflow); } set postItemOverflow(value) { this._postItemOverflow = Number(value); } get itemLoadLimit() { return Number(this._itemLoadLimit); } set itemLoadLimit(value) { this._itemLoadLimit = Number(value); } handleScroll(e) { e.preventDefault(); this.currentScrollTop = this.listContent.scrollTop; this.currentScrollChange = this.currentScrollTop - this.lastScrollTop; this.scrollChangeByFirstIndexedItem += this.currentScrollChange; this.lastVisibleItemOverflow -= this.currentScrollChange; const newRange = this.getRangeChange(this.scrollChangeByFirstIndexedItem); this.updateScrollFromRange(newRange); this.scrollDispatcherService.dispatchViewportScrolledEvents(this.viewportScrolled, this.lastScrollTop, this.scrollChangeByFirstIndexedItem, this, this.elementRef.nativeElement); } registerViewportToElement() { this.elementRef.nativeElement.scrollViewport = this; } attachMutationObserver() { const ths = this; this.observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { ths.updateMutations(mutation); }); }); this.observer.observe(this.listContent, { // configure it to listen to attribute changes attributes: true, subtree: true, childList: true }); } updateMutations(mutation) { if (mutation.type === 'childList') { const addedNodes = Array.from(mutation.addedNodes); addedNodes.forEach(node => { this.directiveRegistrationService.registerNodeAttributes(node); this.getChildNodes(node); }); } } getChildNodes(node) { node.childNodes.forEach(childNode => { this.directiveRegistrationService.registerNodeAttributes(childNode); if (childNode.childNodes) { this.getChildNodes(childNode); } }); } registerCustomElementsInputs(viewport) { this.templateID = viewport.getAttribute('templateID'); this.preItemOverflow = Number(viewport.getAttribute('preItemOverflow')); this.postItemOverflow = Number(viewport.getAttribute('postItemOverflow')); this.itemLoadLimit = Number(viewport.getAttribute('itemLoadLimit')); this.arrowUpSpeed = Number(viewport.getAttribute('arrowUpSpeed')); this.arrowDownSpeed = Number(viewport.getAttribute('arrowDownSpeed')); this.fillViewportScrolling = viewport.getAttribute('fillViewportScrolling'); } convertCustomElementsVariables() { if (this.templateid) { this.templateID = this.templateid; } if (this.preitemoverflow) { this.preItemOverflow = Number(this.preitemoverflow); } if (this.postitemoverflow) { this.postItemOverflow = Number(this.postitemoverflow); } if (this.arrowdownspeed) { this.arrowDownSpeed = Number(this.arrowdownspeed); } if (this.arrowupspeed) { this.arrowUpSpeed = Number(this.arrowupspeed); } if (this.itemloadlimit !== null) { this.itemLoadLimit = Number(this.itemloadlimit); } } createTBodies() { this.listElm = this.elementRef.nativeElement; let body = this.listElm.getElementsByTagName('tbody')[0]; if (body) { body = body.getAttribute('tablejsViewport') !== null ? body : null; } this.listContent = body ? body : document.createElement('tbody'); this.listContent.setAttribute('tablejsListContent', ''); this.listContent.setAttribute('tablejsViewport', ''); this.listContent.style.display = 'block'; this.listContent.style.position = 'relative'; this.listContent.style.height = '350px'; this.listContent.style.overflowY = 'auto'; this.listElm.appendChild(this.listContent); if (this.fillViewportScrolling !== undefined && this.fillViewportScrolling !== null) { const coverBody = document.createElement('tbody'); coverBody.style.display = 'block'; coverBody.style.position = 'absolute'; coverBody.style.width = '100%'; coverBody.style.height = '100%'; coverBody.style.overflow = 'auto'; coverBody.style.pointerEvents = 'none'; coverBody.style.visibility = 'false'; this.listElm.appendChild(coverBody); } this.directiveRegistrationService.registerViewportOnGridDirective(this.listContent); const componentRef = this.virtualNexus.virtualForDirective._viewContainer.createComponent(ScrollPrevSpacerComponent); this.virtualNexus.virtualForDirective._viewContainer.detach(0); const ref = this.virtualNexus.virtualForDirective._viewContainer.createEmbeddedView(componentRef.instance.template, undefined, 0); componentRef.destroy(); this.prevSpacer = ref.rootNodes[0]; this.postSpacer = document.createElement('tr'); this.postSpacer.setAttribute('tablejsPostSpacer', ''); this.postSpacer.style.display = 'block'; this.postSpacer.style.position = 'relative'; this.listContent.appendChild(this.postSpacer); } addScrollHandler() { this.listContent.addEventListener('scroll', this.handleListContentScroll = (e) => { this.handleScroll(e); }); } rerenderRowAt(index, updateScrollPosition = false) { if (!this.viewportHasScrolled) { return; } const ind = index - this.adjustedStartIndex; const itemName = 'item' + index; if (ind > this.items.length - 1 || this.itemVisibilityLookup[this.itemName] !== true) { return; } const indexMap = {}; for (let i = 1; i < this.virtualNexus.virtualForDirective._viewContainer.length; i++) { indexMap[this.virtualNexus.virtualForDirective._viewContainer.get(i).rootNodes[0].index] = i; } ; const detachedRef = this.virtualNexus.virtualForDirective._viewContainer.detach(indexMap[index]); const child = detachedRef.rootNodes[0]; detachedRef.destroy(); this.templateContext = new TablejsForOfContext(this.items[index], this.virtualNexus.virtualForDirective._tablejsForOf, index, this.items.length); const ref = this.virtualNexus.virtualForDirective._viewContainer.createEmbeddedView(this.virtualNexus.virtualForDirective._template, this.templateContext, indexMap[index]); this.virtualNexus.virtualForDirective._viewContainer.move(ref, indexMap[index]); let clone = ref.rootNodes[0]; clone.index = index; this.cdr.detectChanges(); this.scrollDispatcherService.dispatchRemoveItemEvents(this.itemRemoved, child, index, this, this.elementRef.nativeElement); const lookupHeight = clone.offsetHeight; const oldHeight = this.heightLookup[itemName]; this.heightLookup[itemName] = lookupHeight; clone.lastHeight = lookupHeight; this.addResizeSensor(clone, index); if (oldHeight) { this.updateEstimatedHeightFromResize(oldHeight, lookupHeight); } else { this.updateEstimatedHeight(lookupHeight); } if (updateScrollPosition) { this.refreshViewport(); } this.scrollDispatcherService.dispatchUpdateItemEvents(this.itemUpdated, clone, index, this, this.elementRef.nativeElement); this.scrollDispatcherService.dispatchAddItemEvents(this.itemAdded, clone, index, this, this.elementRef.nativeElement); } viewportRendered() { this.virtualNexus = this.directiveRegistrationService.getVirtualNexusFromViewport(this); if (this.virtualNexus && this.virtualNexus.virtualForDirective) { this.items = this.virtualNexus.virtualForDirective._tablejsForOf; this.virtualForChangesSubscription$ = this.virtualNexus.virtualForDirective.changes.subscribe(item => { const isTheSameArray = this.items === item.tablejsForOf; this.items = item.tablejsForOf; const scrollToOptions = { index: 0, scrollAfterIndexedItem: 0 }; if (isTheSameArray) { scrollToOptions.index = this.range.startIndex; scrollToOptions.scrollAfterIndexedItem = this.scrollChangeByFirstIndexedItem; // array has changed...rerender current elements const listChildren = Array.from(this.listContent.childNodes); } else { this.updateItems(item.tablejsForOf, scrollToOptions); } }); } this.createTBodies(); this.addScrollHandler(); if (this.items && (this.generateCloneMethod || this.virtualNexus.virtualForDirective._template)) { this.initScroll({ items: this.items, generateCloneMethod: this._cloneMethod }); } this.scrollDispatcherService.dispatchViewportReadyEvents(this.viewportReady, this, this.elementRef.nativeElement); } scrollToBottom() { this.range.startIndex = this.items.length; this.scrollToExact(this.range.startIndex, 0); } scrollToTop() { this.scrollToExact(0, 0); } pageUp() { let heightCount = this.scrollChangeByFirstIndexedItem; if (this.range.startIndex === 0) { this.scrollToExact(0, 0); return; } for (let i = this.range.startIndex - 1; i >= 0; i--) { const lookupHeight = this.heightLookup['item' + i] ? this.heightLookup['item' + i] : this.avgItemHeight; heightCount += lookupHeight; if (heightCount >= this.containerHeight || i === 0) { const overflowDifference = heightCount >= this.containerHeight ? heightCount - this.containerHeight : 0; this.scrollToExact(i, overflowDifference); break; } } } pageDown() { this.range.startIndex = this.range.endIndex - 1; const overflowDifference = this.heightLookup['item' + (this.range.endIndex - 1).toString()] - this.lastVisibleItemOverflow; this.scrollToExact(this.range.startIndex, overflowDifference); } addArrowListeners() { this.elementRef.nativeElement.addEventListener('mouseenter', this.handleMouseOver = (e) => { this.mouseIsOverViewport = true; }); this.elementRef.nativeElement.addEventListener('mouseleave', this.handleMouseOut = (e) => { this.mouseIsOverViewport = false; }); document.addEventListener('keydown', this.handleKeyDown = (e) => { if (this.mouseIsOverViewport) { const isMac = this.operatingSystem.isMac(); switch (e.code) { case 'ArrowDown': if (isMac && e.metaKey) { e.preventDefault(); this.scrollToBottom(); } else { e.preventDefault(); this.range.startIndex += Number(this.arrowDownSpeed); this.scrollToExact(this.range.startIndex, 0); } break; case 'ArrowUp': if (isMac && e.metaKey) { e.preventDefault(); this.scrollToTop(); } else { if (this.scrollChangeByFirstIndexedItem === 0) { e.preventDefault(); this.range.startIndex -= Number(this.arrowUpSpeed); this.scrollToExact(this.range.startIndex, 0); } else { e.preventDefault(); this.scrollChangeByFirstIndexedItem = 0; this.scrollToExact(this.range.startIndex, 0); } } break; case 'PageDown': e.preventDefault(); this.pageDown(); break; case 'PageUp': e.preventDefault(); this.pageUp(); break; case 'End': e.preventDefault(); this.scrollToBottom(); break; case 'Home': e.preventDefault(); this.scrollToTop(); break; } } }); } ngAfterViewInit() { this.gridDirective = this.gridService.getParentTablejsGridDirective(this.elementRef.nativeElement)['gridDirective']; this.gridDirective.scrollViewportDirective = this; this.preGridInitializeSubscription$ = this.gridDirective.preGridInitialize.pipe(take(1)).subscribe(res => { this.cdr.detectChanges(); this.refreshContainerHeight(); this.refreshViewport(); // placeholder object is used only to initialize first grid render if (this.items[0] === this.placeholderObject) { this.items.shift(); } }); this.viewportRendered(); this.addArrowListeners(); } ngOnInit() { this.registerViewportToElement(); this._cloneMethod = this.generateCloneMethod; } ngOnDestroy() { this.listElm = null; if (this.virtualNexus && this.virtualNexus.virtualForDirective) { this.virtualNexus.virtualForDirective._viewContainer.detach(0); this.virtualNexus.virtualForDirective._viewContainer.clear(); } this.items = []; this.elementRef.nativeElement.scrollViewport = null; this.templateRef = null; this._cloneMethod = null; this.generateCloneMethod = null; if (this.virtualNexus) { this.directiveRegistrationService.clearVirtualNexus(this.virtualNexus); this.virtualNexus.virtualForDirective = null; this.virtualNexus.scrollViewportDirective = null; this.virtualNexus = null; } clearTimeout(this.timeoutID); this.elementRef.nativeElement.removeEventListener('mouseenter', this.handleMouseOver); this.elementRef.nativeElement.removeEventListener('mouseleave', this.handleMouseOut); if (this.listContent) { this.listContent.removeEventListener('scroll', this.handleListContentScroll); } this.handleListContentScroll = null; document.removeEventListener('keydown', this.handleKeyDown); if (this.virtualForChangesSubscription$) { this.virtualForChangesSubscription$.unsubscribe(); } if (this.preGridInitializeSubscription$) { this.preGridInitializeSubscription$.unsubscribe(); } this.elementRef.nativeElement.scrollViewportDirective = null; } setScrollSpacers() { const numItemsAfterShownList = this.items.length - this.range.extendedEndIndex; const numItemsBeforeShownList = this.adjustedStartIndex; const totalUnshownItems = numItemsBeforeShownList + numItemsAfterShownList; const beforeItemHeightPercent = totalUnshownItems !== 0 ? numItemsBeforeShownList / totalUnshownItems : 0; const afterItemHeightPercent = totalUnshownItems !== 0 ? numItemsAfterShownList / totalUnshownItems : 0; const remainingHeight = this.estimatedFullContentHeight - this.lastHeight; this.estimatedPreListHeight = Math.round(beforeItemHeightPercent * remainingHeight); this.estimatedPostListHeight = Math.round(afterItemHeightPercent * remainingHeight); // account for rounding both up this.estimatedPostListHeight = this.estimatedPostListHeight - (afterItemHeightPercent * remainingHeight) === 0.5 ? this.estimatedPostListHeight - 1 : this.estimatedPostListHeight; if (this.forcedEndIndex) { this.estimatedPreListHeight = 0; this.estimatedPostListHeight = 0; } this.prevSpacer.style.height = this.estimatedPreListHeight.toString() + 'px'; this.postSpacer.style.height = this.estimatedPostListHeight.toString() + 'px'; } setHeightByListHeightDifference(liHeight, listHeight) { return liHeight - listHeight; } removePreScrollItems(lastIndex, index) { if (lastIndex < index) { for (let i = lastIndex; i < index; i++) { const firstRef = this.virtualNexus.virtualForDirective._viewContainer.get(1); if (firstRef) { const firstChild = firstRef.rootNodes[0]; const itemName = 'item' + i; this.itemVisibilityLookup[itemName] = false; const detachedRef = this.virtualNexus.virtualForDirective._viewContainer.detach(1); detachedRef.destroy(); this.cdr.detectChanges(); this.removeResizeSensor(firstChild, i); this.lastHeight -= this.heightLookup[itemName];