@transunion-ui/tablejs
Version:
Tablejs ========
1,036 lines (1,021 loc) • 285 kB
JavaScript
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 (_a) {
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[itemN