import * as i0 from '@angular/core'; import { Injectable, Inject, Directive, EventEmitter, HostBinding, Output, Input, HostListener, ContentChildren, Component, ChangeDetectionStrategy, TemplateRef, ContentChild, ViewContainerRef, ViewChild, SkipSelf, ViewEncapsulation, Optional, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import { Subject, fromEvent, BehaviorSubject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { __decorate } from 'tslib'; /** * Gets the width of the scrollbar. Nesc for windows * http://stackoverflow.com/a/13382873/888165 */ class ScrollbarHelper { constructor(document) { this.document = document; this.width = this.getWidth(); } getWidth() { const outer = this.document.createElement('div'); outer.style.visibility = 'hidden'; outer.style.width = '100px'; outer.style.msOverflowStyle = 'scrollbar'; this.document.body.appendChild(outer); const widthNoScroll = outer.offsetWidth; outer.style.overflow = 'scroll'; const inner = this.document.createElement('div'); inner.style.width = '100%'; outer.appendChild(inner); const widthWithScroll = inner.offsetWidth; outer.parentNode.removeChild(outer); return widthNoScroll - widthWithScroll; } } ScrollbarHelper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ScrollbarHelper, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); ScrollbarHelper.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ScrollbarHelper }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ScrollbarHelper, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; } }); /** * Gets the width of the scrollbar. Nesc for windows * http://stackoverflow.com/a/13382873/888165 */ class DimensionsHelper { getDimensions(element) { return element.getBoundingClientRect(); } } DimensionsHelper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DimensionsHelper, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DimensionsHelper.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DimensionsHelper }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DimensionsHelper, decorators: [{ type: Injectable }] }); /** * service to make DatatableComponent aware of changes to * input bindings of DataTableColumnDirective */ class ColumnChangesService { constructor() { this.columnInputChanges = new Subject(); } get columnInputChanges$() { return this.columnInputChanges.asObservable(); } onInputChange() { this.columnInputChanges.next(); } } ColumnChangesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ColumnChangesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ColumnChangesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ColumnChangesService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ColumnChangesService, decorators: [{ type: Injectable }] }); class DataTableFooterTemplateDirective { constructor(template) { this.template = template; } } DataTableFooterTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableFooterTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DataTableFooterTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DataTableFooterTemplateDirective, selector: "[ngx-datatable-footer-template]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableFooterTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-footer-template]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); /** * Visibility Observer Directive * * Usage: * *
*
* */ class VisibilityDirective { constructor(element, zone) { this.element = element; this.zone = zone; this.isVisible = false; this.visible = new EventEmitter(); } ngOnInit() { this.runCheck(); } ngOnDestroy() { clearTimeout(this.timeout); } onVisibilityChange() { // trigger zone recalc for columns this.zone.run(() => { this.isVisible = true; this.visible.emit(true); }); } runCheck() { const check = () => { // https://davidwalsh.name/offsetheight-visibility const { offsetHeight, offsetWidth } = this.element.nativeElement; if (offsetHeight && offsetWidth) { clearTimeout(this.timeout); this.onVisibilityChange(); } else { clearTimeout(this.timeout); this.zone.runOutsideAngular(() => { this.timeout = setTimeout(() => check(), 50); }); } }; this.timeout = setTimeout(() => check()); } } VisibilityDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: VisibilityDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); VisibilityDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: VisibilityDirective, selector: "[visibilityObserver]", outputs: { visible: "visible" }, host: { properties: { "class.visible": "this.isVisible" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: VisibilityDirective, decorators: [{ type: Directive, args: [{ selector: '[visibilityObserver]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { isVisible: [{ type: HostBinding, args: ['class.visible'] }], visible: [{ type: Output }] } }); /** * Draggable Directive for Angular2 * * Inspiration: * https://github.com/AngularClass/angular2-examples/blob/master/rx-draggable/directives/draggable.ts * http://stackoverflow.com/questions/35662530/how-to-implement-drag-and-drop-in-angular2 * */ class DraggableDirective { constructor(element) { this.dragX = true; this.dragY = true; this.dragStart = new EventEmitter(); this.dragging = new EventEmitter(); this.dragEnd = new EventEmitter(); this.isDragging = false; this.element = element.nativeElement; } ngOnChanges(changes) { if (changes['dragEventTarget'] && changes['dragEventTarget'].currentValue && this.dragModel.dragging) { this.onMousedown(changes['dragEventTarget'].currentValue); } } ngOnDestroy() { this._destroySubscription(); } onMouseup(event) { if (!this.isDragging) return; this.isDragging = false; this.element.classList.remove('dragging'); if (this.subscription) { this._destroySubscription(); this.dragEnd.emit({ event, element: this.element, model: this.dragModel }); } } onMousedown(event) { // we only want to drag the inner header text const isDragElm = event.target.classList.contains('draggable'); if (isDragElm && (this.dragX || this.dragY)) { event.preventDefault(); this.isDragging = true; const mouseDownPos = { x: event.clientX, y: event.clientY }; const mouseup = fromEvent(document, 'mouseup'); this.subscription = mouseup.subscribe((ev) => this.onMouseup(ev)); const mouseMoveSub = fromEvent(document, 'mousemove') .pipe(takeUntil(mouseup)) .subscribe((ev) => this.move(ev, mouseDownPos)); this.subscription.add(mouseMoveSub); this.dragStart.emit({ event, element: this.element, model: this.dragModel }); } } move(event, mouseDownPos) { if (!this.isDragging) return; const x = event.clientX - mouseDownPos.x; const y = event.clientY - mouseDownPos.y; if (this.dragX) this.element.style.left = `${x}px`; if (this.dragY) this.element.style.top = `${y}px`; this.element.classList.add('dragging'); this.dragging.emit({ event, element: this.element, model: this.dragModel }); } _destroySubscription() { if (this.subscription) { this.subscription.unsubscribe(); this.subscription = undefined; } } } DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DraggableDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); DraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DraggableDirective, selector: "[draggable]", inputs: { dragEventTarget: "dragEventTarget", dragModel: "dragModel", dragX: "dragX", dragY: "dragY" }, outputs: { dragStart: "dragStart", dragging: "dragging", dragEnd: "dragEnd" }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DraggableDirective, decorators: [{ type: Directive, args: [{ selector: '[draggable]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { dragEventTarget: [{ type: Input }], dragModel: [{ type: Input }], dragX: [{ type: Input }], dragY: [{ type: Input }], dragStart: [{ type: Output }], dragging: [{ type: Output }], dragEnd: [{ type: Output }] } }); class ResizeableDirective { constructor(element, renderer) { this.renderer = renderer; this.resizeEnabled = true; this.resize = new EventEmitter(); this.resizing = false; this.element = element.nativeElement; } ngAfterViewInit() { const renderer2 = this.renderer; this.resizeHandle = renderer2.createElement('span'); if (this.resizeEnabled) { renderer2.addClass(this.resizeHandle, 'resize-handle'); } else { renderer2.addClass(this.resizeHandle, 'resize-handle--not-resizable'); } renderer2.appendChild(this.element, this.resizeHandle); } ngOnDestroy() { this._destroySubscription(); if (this.renderer.destroyNode) { this.renderer.destroyNode(this.resizeHandle); } else if (this.resizeHandle) { this.renderer.removeChild(this.renderer.parentNode(this.resizeHandle), this.resizeHandle); } } onMouseup() { this.resizing = false; if (this.subscription && !this.subscription.closed) { this._destroySubscription(); this.resize.emit(this.element.clientWidth); } } onMousedown(event) { const isHandle = event.target.classList.contains('resize-handle'); const initialWidth = this.element.clientWidth; const mouseDownScreenX = event.screenX; if (isHandle) { event.stopPropagation(); this.resizing = true; const mouseup = fromEvent(document, 'mouseup'); this.subscription = mouseup.subscribe((ev) => this.onMouseup()); const mouseMoveSub = fromEvent(document, 'mousemove') .pipe(takeUntil(mouseup)) .subscribe((e) => this.move(e, initialWidth, mouseDownScreenX)); this.subscription.add(mouseMoveSub); } } move(event, initialWidth, mouseDownScreenX) { const movementX = event.screenX - mouseDownScreenX; const newWidth = initialWidth + movementX; const overMinWidth = !this.minWidth || newWidth >= this.minWidth; const underMaxWidth = !this.maxWidth || newWidth <= this.maxWidth; if (overMinWidth && underMaxWidth) { this.element.style.width = `${newWidth}px`; } } _destroySubscription() { if (this.subscription) { this.subscription.unsubscribe(); this.subscription = undefined; } } } ResizeableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ResizeableDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); ResizeableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: ResizeableDirective, selector: "[resizeable]", inputs: { resizeEnabled: "resizeEnabled", minWidth: "minWidth", maxWidth: "maxWidth" }, outputs: { resize: "resize" }, host: { listeners: { "mousedown": "onMousedown($event)" }, properties: { "class.resizeable": "resizeEnabled" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ResizeableDirective, decorators: [{ type: Directive, args: [{ selector: '[resizeable]', host: { '[class.resizeable]': 'resizeEnabled' } }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { resizeEnabled: [{ type: Input }], minWidth: [{ type: Input }], maxWidth: [{ type: Input }], resize: [{ type: Output }], onMousedown: [{ type: HostListener, args: ['mousedown', ['$event']] }] } }); class OrderableDirective { constructor(differs, document) { this.document = document; this.reorder = new EventEmitter(); this.targetChanged = new EventEmitter(); this.differ = differs.find({}).create(); } ngAfterContentInit() { // HACK: Investigate Better Way this.updateSubscriptions(); this.draggables.changes.subscribe(this.updateSubscriptions.bind(this)); } ngOnDestroy() { this.draggables.forEach(d => { d.dragStart.unsubscribe(); d.dragging.unsubscribe(); d.dragEnd.unsubscribe(); }); } updateSubscriptions() { const diffs = this.differ.diff(this.createMapDiffs()); if (diffs) { const subscribe = ({ currentValue, previousValue }) => { unsubscribe({ previousValue }); if (currentValue) { currentValue.dragStart.subscribe(this.onDragStart.bind(this)); currentValue.dragging.subscribe(this.onDragging.bind(this)); currentValue.dragEnd.subscribe(this.onDragEnd.bind(this)); } }; const unsubscribe = ({ previousValue }) => { if (previousValue) { previousValue.dragStart.unsubscribe(); previousValue.dragging.unsubscribe(); previousValue.dragEnd.unsubscribe(); } }; diffs.forEachAddedItem(subscribe); // diffs.forEachChangedItem(subscribe.bind(this)); diffs.forEachRemovedItem(unsubscribe); } } onDragStart() { this.positions = {}; let i = 0; for (const dragger of this.draggables.toArray()) { const elm = dragger.element; const left = parseInt(elm.offsetLeft.toString(), 0); this.positions[dragger.dragModel.prop] = { left, right: left + parseInt(elm.offsetWidth.toString(), 0), index: i++, element: elm }; } } onDragging({ element, model, event }) { const prevPos = this.positions[model.prop]; const target = this.isTarget(model, event); if (target) { if (this.lastDraggingIndex !== target.i) { this.targetChanged.emit({ prevIndex: this.lastDraggingIndex, newIndex: target.i, initialIndex: prevPos.index }); this.lastDraggingIndex = target.i; } } else if (this.lastDraggingIndex !== prevPos.index) { this.targetChanged.emit({ prevIndex: this.lastDraggingIndex, initialIndex: prevPos.index }); this.lastDraggingIndex = prevPos.index; } } onDragEnd({ element, model, event }) { const prevPos = this.positions[model.prop]; const target = this.isTarget(model, event); if (target) { this.reorder.emit({ prevIndex: prevPos.index, newIndex: target.i, model }); } this.lastDraggingIndex = undefined; element.style.left = 'auto'; } isTarget(model, event) { let i = 0; const x = event.x || event.clientX; const y = event.y || event.clientY; const targets = this.document.elementsFromPoint(x, y); for (const prop in this.positions) { // current column position which throws event. const pos = this.positions[prop]; // since we drag the inner span, we need to find it in the elements at the cursor if (model.prop !== prop && targets.find((el) => el === pos.element)) { return { pos, i }; } i++; } } createMapDiffs() { return this.draggables.toArray().reduce((acc, curr) => { acc[curr.dragModel.$$id] = curr; return acc; }, {}); } } OrderableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: OrderableDirective, deps: [{ token: i0.KeyValueDiffers }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive }); OrderableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: OrderableDirective, selector: "[orderable]", outputs: { reorder: "reorder", targetChanged: "targetChanged" }, queries: [{ propertyName: "draggables", predicate: DraggableDirective, descendants: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: OrderableDirective, decorators: [{ type: Directive, args: [{ selector: '[orderable]' }] }], ctorParameters: function () { return [{ type: i0.KeyValueDiffers }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { reorder: [{ type: Output }], targetChanged: [{ type: Output }], draggables: [{ type: ContentChildren, args: [DraggableDirective, { descendants: true }] }] } }); class LongPressDirective { constructor() { this.pressEnabled = true; this.duration = 500; this.longPressStart = new EventEmitter(); this.longPressing = new EventEmitter(); this.longPressEnd = new EventEmitter(); this.mouseX = 0; this.mouseY = 0; } get press() { return this.pressing; } get isLongPress() { return this.isLongPressing; } onMouseDown(event) { // don't do right/middle clicks if (event.which !== 1 || !this.pressEnabled) return; // don't start drag if its on resize handle const target = event.target; if (target.classList.contains('resize-handle')) return; this.mouseX = event.clientX; this.mouseY = event.clientY; this.pressing = true; this.isLongPressing = false; const mouseup = fromEvent(document, 'mouseup'); this.subscription = mouseup.subscribe((ev) => this.onMouseup()); this.timeout = setTimeout(() => { this.isLongPressing = true; this.longPressStart.emit({ event, model: this.pressModel }); this.subscription.add(fromEvent(document, 'mousemove') .pipe(takeUntil(mouseup)) .subscribe((mouseEvent) => this.onMouseMove(mouseEvent))); this.loop(event); }, this.duration); this.loop(event); } onMouseMove(event) { if (this.pressing && !this.isLongPressing) { const xThres = Math.abs(event.clientX - this.mouseX) > 10; const yThres = Math.abs(event.clientY - this.mouseY) > 10; if (xThres || yThres) { this.endPress(); } } } loop(event) { if (this.isLongPressing) { this.timeout = setTimeout(() => { this.longPressing.emit({ event, model: this.pressModel }); this.loop(event); }, 50); } } endPress() { clearTimeout(this.timeout); this.isLongPressing = false; this.pressing = false; this._destroySubscription(); this.longPressEnd.emit({ model: this.pressModel }); } onMouseup() { this.endPress(); } ngOnDestroy() { this._destroySubscription(); } _destroySubscription() { if (this.subscription) { this.subscription.unsubscribe(); this.subscription = undefined; } } } LongPressDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: LongPressDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); LongPressDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: LongPressDirective, selector: "[long-press]", inputs: { pressEnabled: "pressEnabled", pressModel: "pressModel", duration: "duration" }, outputs: { longPressStart: "longPressStart", longPressing: "longPressing", longPressEnd: "longPressEnd" }, host: { listeners: { "mousedown": "onMouseDown($event)" }, properties: { "class.press": "this.press", "class.longpress": "this.isLongPress" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: LongPressDirective, decorators: [{ type: Directive, args: [{ selector: '[long-press]' }] }], propDecorators: { pressEnabled: [{ type: Input }], pressModel: [{ type: Input }], duration: [{ type: Input }], longPressStart: [{ type: Output }], longPressing: [{ type: Output }], longPressEnd: [{ type: Output }], press: [{ type: HostBinding, args: ['class.press'] }], isLongPress: [{ type: HostBinding, args: ['class.longpress'] }], onMouseDown: [{ type: HostListener, args: ['mousedown', ['$event']] }] } }); class ScrollerComponent { constructor(ngZone, element, renderer) { this.ngZone = ngZone; this.renderer = renderer; this.scrollbarV = false; this.scrollbarH = false; this.scroll = new EventEmitter(); this.scrollYPos = 0; this.scrollXPos = 0; this.prevScrollYPos = 0; this.prevScrollXPos = 0; this._scrollEventListener = null; this.element = element.nativeElement; } ngOnInit() { // manual bind so we don't always listen if (this.scrollbarV || this.scrollbarH) { const renderer = this.renderer; this.parentElement = renderer.parentNode(renderer.parentNode(this.element)); this._scrollEventListener = this.onScrolled.bind(this); this.parentElement.addEventListener('scroll', this._scrollEventListener); } } ngOnDestroy() { if (this._scrollEventListener) { this.parentElement.removeEventListener('scroll', this._scrollEventListener); this._scrollEventListener = null; } } setOffset(offsetY) { if (this.parentElement) { this.parentElement.scrollTop = offsetY; } } onScrolled(event) { const dom = event.currentTarget; requestAnimationFrame(() => { this.scrollYPos = dom.scrollTop; this.scrollXPos = dom.scrollLeft; this.updateOffset(); }); } updateOffset() { let direction; if (this.scrollYPos < this.prevScrollYPos) { direction = 'down'; } else if (this.scrollYPos > this.prevScrollYPos) { direction = 'up'; } this.scroll.emit({ direction, scrollYPos: this.scrollYPos, scrollXPos: this.scrollXPos }); this.prevScrollYPos = this.scrollYPos; this.prevScrollXPos = this.scrollXPos; } } ScrollerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ScrollerComponent, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); ScrollerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: ScrollerComponent, selector: "datatable-scroller", inputs: { scrollbarV: "scrollbarV", scrollbarH: "scrollbarH", scrollHeight: "scrollHeight", scrollWidth: "scrollWidth" }, outputs: { scroll: "scroll" }, host: { properties: { "style.height.px": "this.scrollHeight", "style.width.px": "this.scrollWidth" }, classAttribute: "datatable-scroll" }, ngImport: i0, template: ` `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ScrollerComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-scroller', template: ` `, host: { class: 'datatable-scroll' }, changeDetection: ChangeDetectionStrategy.OnPush }] }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { scrollbarV: [{ type: Input }], scrollbarH: [{ type: Input }], scrollHeight: [{ type: HostBinding, args: ['style.height.px'] }, { type: Input }], scrollWidth: [{ type: HostBinding, args: ['style.width.px'] }, { type: Input }], scroll: [{ type: Output }] } }); class DatatableGroupHeaderTemplateDirective { constructor(template) { this.template = template; } } DatatableGroupHeaderTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableGroupHeaderTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DatatableGroupHeaderTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DatatableGroupHeaderTemplateDirective, selector: "[ngx-datatable-group-header-template]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableGroupHeaderTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-group-header-template]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); class DatatableGroupHeaderDirective { constructor() { /** * Row height is required when virtual scroll is enabled. */ this.rowHeight = 0; /** * Track toggling of group visibility */ this.toggle = new EventEmitter(); } get template() { return this._templateInput || this._templateQuery; } /** * Toggle the expansion of a group */ toggleExpandGroup(group) { this.toggle.emit({ type: 'group', value: group }); } /** * Expand all groups */ expandAllGroups() { this.toggle.emit({ type: 'all', value: true }); } /** * Collapse all groups */ collapseAllGroups() { this.toggle.emit({ type: 'all', value: false }); } } DatatableGroupHeaderDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableGroupHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); DatatableGroupHeaderDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DatatableGroupHeaderDirective, selector: "ngx-datatable-group-header", inputs: { rowHeight: "rowHeight", _templateInput: ["template", "_templateInput"] }, outputs: { toggle: "toggle" }, queries: [{ propertyName: "_templateQuery", first: true, predicate: DatatableGroupHeaderTemplateDirective, descendants: true, read: TemplateRef, static: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableGroupHeaderDirective, decorators: [{ type: Directive, args: [{ selector: 'ngx-datatable-group-header' }] }], propDecorators: { rowHeight: [{ type: Input }], _templateInput: [{ type: Input, args: ['template'] }], _templateQuery: [{ type: ContentChild, args: [DatatableGroupHeaderTemplateDirective, { read: TemplateRef, static: true }] }], toggle: [{ type: Output }] } }); /** * Always returns the empty string '' */ function emptyStringGetter() { return ''; } /** * Returns the appropriate getter function for this kind of prop. * If prop == null, returns the emptyStringGetter. */ function getterForProp(prop) { if (prop == null) { return emptyStringGetter; } if (typeof prop === 'number') { return numericIndexGetter; } else { // deep or simple if (prop.indexOf('.') !== -1) { return deepValueGetter; } else { return shallowValueGetter; } } } /** * Returns the value at this numeric index. * @param row array of values * @param index numeric index * @returns any or '' if invalid index */ function numericIndexGetter(row, index) { if (row == null) { return ''; } // mimic behavior of deepValueGetter if (!row || index == null) { return row; } const value = row[index]; if (value == null) { return ''; } return value; } /** * Returns the value of a field. * (more efficient than deepValueGetter) * @param obj object containing the field * @param fieldName field name string */ function shallowValueGetter(obj, fieldName) { if (obj == null) { return ''; } if (!obj || !fieldName) { return obj; } const value = obj[fieldName]; if (value == null) { return ''; } return value; } /** * Returns a deep object given a string. zoo['animal.type'] */ function deepValueGetter(obj, path) { if (obj == null) { return ''; } if (!obj || !path) { return obj; } // check if path matches a root-level field // { "a.b.c": 123 } let current = obj[path]; if (current !== undefined) { return current; } current = obj; const split = path.split('.'); if (split.length) { for (let i = 0; i < split.length; i++) { current = current[split[i]]; // if found undefined, return empty string if (current === undefined || current === null) { return ''; } } } return current; } function optionalGetterForProp(prop) { return prop && (row => getterForProp(prop)(row, prop)); } /** * This functions rearrange items by their parents * Also sets the level value to each of the items * * Note: Expecting each item has a property called parentId * Note: This algorithm will fail if a list has two or more items with same ID * NOTE: This algorithm will fail if there is a deadlock of relationship * * For example, * * Input * * id -> parent * 1 -> 0 * 2 -> 0 * 3 -> 1 * 4 -> 1 * 5 -> 2 * 7 -> 8 * 6 -> 3 * * * Output * id -> level * 1 -> 0 * --3 -> 1 * ----6 -> 2 * --4 -> 1 * 2 -> 0 * --5 -> 1 * 7 -> 8 * * * @param rows * */ function groupRowsByParents(rows, from, to) { if (from && to) { const nodeById = {}; const l = rows.length; let node = null; nodeById[0] = new TreeNode(); // that's the root node const uniqIDs = rows.reduce((arr, item) => { const toValue = to(item); if (arr.indexOf(toValue) === -1) { arr.push(toValue); } return arr; }, []); for (let i = 0; i < l; i++) { // make TreeNode objects for each item nodeById[to(rows[i])] = new TreeNode(rows[i]); } for (let i = 0; i < l; i++) { // link all TreeNode objects node = nodeById[to(rows[i])]; let parent = 0; const fromValue = from(node.row); if (!!fromValue && uniqIDs.indexOf(fromValue) > -1) { parent = fromValue; } node.parent = nodeById[parent]; node.row['level'] = node.parent.row['level'] + 1; node.parent.children.push(node); } let resolvedRows = []; nodeById[0].flatten(function () { resolvedRows = [...resolvedRows, this.row]; }, true); return resolvedRows; } else { return rows; } } class TreeNode { constructor(row = null) { if (!row) { row = { level: -1, treeStatus: 'expanded' }; } this.row = row; this.parent = null; this.children = []; } flatten(f, recursive) { if (this.row['treeStatus'] === 'expanded') { for (let i = 0, l = this.children.length; i < l; i++) { const child = this.children[i]; f.apply(child, Array.prototype.slice.call(arguments, 2)); if (recursive) child.flatten.apply(child, arguments); } } } } /** * Converts strings from something to camel case * http://stackoverflow.com/questions/10425287/convert-dash-separated-string-to-camelcase */ function camelCase(str) { // Replace special characters with a space str = str.replace(/[^a-zA-Z0-9 ]/g, ' '); // put a space before an uppercase letter str = str.replace(/([a-z](?=[A-Z]))/g, '$1 '); // Lower case first character and some other stuff str = str .replace(/([^a-zA-Z0-9 ])|^[0-9]+/g, '') .trim() .toLowerCase(); // uppercase characters preceded by a space or number str = str.replace(/([ 0-9]+)([a-zA-Z])/g, function (a, b, c) { return b.trim() + c.toUpperCase(); }); return str; } /** * Converts strings from camel case to words * http://stackoverflow.com/questions/7225407/convert-camelcasetext-to-camel-case-text */ function deCamelCase(str) { return str.replace(/([A-Z])/g, match => ` ${match}`).replace(/^./, match => match.toUpperCase()); } /** * Creates a unique object id. * http://stackoverflow.com/questions/6248666/how-to-generate-short-uid-like-ax4j9z-in-js */ function id() { return ('0000' + ((Math.random() * Math.pow(36, 4)) << 0).toString(36)).slice(-4); } /** * Sets the column defaults */ function setColumnDefaults(columns) { if (!columns) return; // Only one column should hold the tree view // Thus if multiple columns are provided with // isTreeColumn as true we take only the first one let treeColumnFound = false; for (const column of columns) { if (!column.$$id) { column.$$id = id(); } // prop can be numeric; zero is valid not a missing prop // translate name => prop if (isNullOrUndefined(column.prop) && column.name) { column.prop = camelCase(column.name); } if (!column.$$valueGetter) { column.$$valueGetter = getterForProp(column.prop); } // format props if no name passed if (!isNullOrUndefined(column.prop) && isNullOrUndefined(column.name)) { column.name = deCamelCase(String(column.prop)); } if (isNullOrUndefined(column.prop) && isNullOrUndefined(column.name)) { column.name = ''; // Fixes IE and Edge displaying `null` } if (!column.hasOwnProperty('resizeable')) { column.resizeable = true; } if (!column.hasOwnProperty('sortable')) { column.sortable = true; } if (!column.hasOwnProperty('draggable')) { column.draggable = true; } if (!column.hasOwnProperty('canAutoResize')) { column.canAutoResize = true; } if (!column.hasOwnProperty('width')) { column.width = 150; } if (!column.hasOwnProperty('isTreeColumn')) { column.isTreeColumn = false; } else { if (column.isTreeColumn && !treeColumnFound) { // If the first column with isTreeColumn is true found // we mark that treeCoulmn is found treeColumnFound = true; } else { // After that isTreeColumn property for any other column // will be set as false column.isTreeColumn = false; } } } } function isNullOrUndefined(value) { return value === null || value === undefined; } /** * Translates templates definitions to objects */ function translateTemplates(templates) { const result = []; for (const temp of templates) { const col = {}; const props = Object.getOwnPropertyNames(temp); for (const prop of props) { col[prop] = temp[prop]; } if (temp.headerTemplate) { col.headerTemplate = temp.headerTemplate; } if (temp.cellTemplate) { col.cellTemplate = temp.cellTemplate; } if (temp.summaryFunc) { col.summaryFunc = temp.summaryFunc; } if (temp.summaryTemplate) { col.summaryTemplate = temp.summaryTemplate; } result.push(col); } return result; } var ColumnMode; (function (ColumnMode) { ColumnMode["standard"] = "standard"; ColumnMode["flex"] = "flex"; ColumnMode["force"] = "force"; })(ColumnMode || (ColumnMode = {})); var SelectionType; (function (SelectionType) { SelectionType["single"] = "single"; SelectionType["multi"] = "multi"; SelectionType["multiClick"] = "multiClick"; SelectionType["cell"] = "cell"; SelectionType["checkbox"] = "checkbox"; })(SelectionType || (SelectionType = {})); var SortType; (function (SortType) { SortType["single"] = "single"; SortType["multi"] = "multi"; })(SortType || (SortType = {})); var ContextmenuType; (function (ContextmenuType) { ContextmenuType["header"] = "header"; ContextmenuType["body"] = "body"; })(ContextmenuType || (ContextmenuType = {})); class DataTableColumnHeaderDirective { constructor(template) { this.template = template; } } DataTableColumnHeaderDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnHeaderDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DataTableColumnHeaderDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DataTableColumnHeaderDirective, selector: "[ngx-datatable-header-template]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnHeaderDirective, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-header-template]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); class DataTableColumnCellDirective { constructor(template) { this.template = template; } } DataTableColumnCellDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DataTableColumnCellDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DataTableColumnCellDirective, selector: "[ngx-datatable-cell-template]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnCellDirective, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-cell-template]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); class DataTableColumnCellTreeToggle { constructor(template) { this.template = template; } } DataTableColumnCellTreeToggle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnCellTreeToggle, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DataTableColumnCellTreeToggle.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DataTableColumnCellTreeToggle, selector: "[ngx-datatable-tree-toggle]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnCellTreeToggle, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-tree-toggle]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); class DataTableColumnDirective { constructor(columnChangesService) { this.columnChangesService = columnChangesService; this.isFirstChange = true; } get cellTemplate() { return this._cellTemplateInput || this._cellTemplateQuery; } get headerTemplate() { return this._headerTemplateInput || this._headerTemplateQuery; } get treeToggleTemplate() { return this._treeToggleTemplateInput || this._treeToggleTemplateQuery; } ngOnChanges() { if (this.isFirstChange) { this.isFirstChange = false; } else { this.columnChangesService.onInputChange(); } } } DataTableColumnDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnDirective, deps: [{ token: ColumnChangesService }], target: i0.ɵɵFactoryTarget.Directive }); DataTableColumnDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DataTableColumnDirective, selector: "ngx-datatable-column", inputs: { name: "name", prop: "prop", frozenLeft: "frozenLeft", frozenRight: "frozenRight", flexGrow: "flexGrow", resizeable: "resizeable", comparator: "comparator", pipe: "pipe", sortable: "sortable", draggable: "draggable", canAutoResize: "canAutoResize", minWidth: "minWidth", width: "width", maxWidth: "maxWidth", checkboxable: "checkboxable", headerCheckboxable: "headerCheckboxable", headerClass: "headerClass", cellClass: "cellClass", isTreeColumn: "isTreeColumn", treeLevelIndent: "treeLevelIndent", summaryFunc: "summaryFunc", summaryTemplate: "summaryTemplate", _cellTemplateInput: ["cellTemplate", "_cellTemplateInput"], _headerTemplateInput: ["headerTemplate", "_headerTemplateInput"], _treeToggleTemplateInput: ["treeToggleTemplate", "_treeToggleTemplateInput"] }, queries: [{ propertyName: "_cellTemplateQuery", first: true, predicate: DataTableColumnCellDirective, descendants: true, read: TemplateRef, static: true }, { propertyName: "_headerTemplateQuery", first: true, predicate: DataTableColumnHeaderDirective, descendants: true, read: TemplateRef, static: true }, { propertyName: "_treeToggleTemplateQuery", first: true, predicate: DataTableColumnCellTreeToggle, descendants: true, read: TemplateRef, static: true }], usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableColumnDirective, decorators: [{ type: Directive, args: [{ selector: 'ngx-datatable-column' }] }], ctorParameters: function () { return [{ type: ColumnChangesService }]; }, propDecorators: { name: [{ type: Input }], prop: [{ type: Input }], frozenLeft: [{ type: Input }], frozenRight: [{ type: Input }], flexGrow: [{ type: Input }], resizeable: [{ type: Input }], comparator: [{ type: Input }], pipe: [{ type: Input }], sortable: [{ type: Input }], draggable: [{ type: Input }], canAutoResize: [{ type: Input }], minWidth: [{ type: Input }], width: [{ type: Input }], maxWidth: [{ type: Input }], checkboxable: [{ type: Input }], headerCheckboxable: [{ type: Input }], headerClass: [{ type: Input }], cellClass: [{ type: Input }], isTreeColumn: [{ type: Input }], treeLevelIndent: [{ type: Input }], summaryFunc: [{ type: Input }], summaryTemplate: [{ type: Input }], _cellTemplateInput: [{ type: Input, args: ['cellTemplate'] }], _cellTemplateQuery: [{ type: ContentChild, args: [DataTableColumnCellDirective, { read: TemplateRef, static: true }] }], _headerTemplateInput: [{ type: Input, args: ['headerTemplate'] }], _headerTemplateQuery: [{ type: ContentChild, args: [DataTableColumnHeaderDirective, { read: TemplateRef, static: true }] }], _treeToggleTemplateInput: [{ type: Input, args: ['treeToggleTemplate'] }], _treeToggleTemplateQuery: [{ type: ContentChild, args: [DataTableColumnCellTreeToggle, { read: TemplateRef, static: true }] }] } }); class DatatableRowDetailTemplateDirective { constructor(template) { this.template = template; } } DatatableRowDetailTemplateDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableRowDetailTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); DatatableRowDetailTemplateDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DatatableRowDetailTemplateDirective, selector: "[ngx-datatable-row-detail-template]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableRowDetailTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[ngx-datatable-row-detail-template]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); class DatatableRowDetailDirective { constructor() { /** * The detail row height is required especially * when virtual scroll is enabled. */ this.rowHeight = 0; /** * Row detail row visbility was toggled. */ this.toggle = new EventEmitter(); } get template() { return this._templateInput || this._templateQuery; } /** * Toggle the expansion of the row */ toggleExpandRow(row) { this.toggle.emit({ type: 'row', value: row }); } /** * API method to expand all the rows. */ expandAllRows() { this.toggle.emit({ type: 'all', value: true }); } /** * API method to collapse all the rows. */ collapseAllRows() { this.toggle.emit({ type: 'all', value: false }); } } DatatableRowDetailDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableRowDetailDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); DatatableRowDetailDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DatatableRowDetailDirective, selector: "ngx-datatable-row-detail", inputs: { rowHeight: "rowHeight", _templateInput: ["template", "_templateInput"] }, outputs: { toggle: "toggle" }, queries: [{ propertyName: "_templateQuery", first: true, predicate: DatatableRowDetailTemplateDirective, descendants: true, read: TemplateRef, static: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableRowDetailDirective, decorators: [{ type: Directive, args: [{ selector: 'ngx-datatable-row-detail' }] }], propDecorators: { rowHeight: [{ type: Input }], _templateInput: [{ type: Input, args: ['template'] }], _templateQuery: [{ type: ContentChild, args: [DatatableRowDetailTemplateDirective, { read: TemplateRef, static: true }] }], toggle: [{ type: Output }] } }); class DatatableFooterDirective { get template() { return this._templateInput || this._templateQuery; } } DatatableFooterDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); DatatableFooterDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.1.1", type: DatatableFooterDirective, selector: "ngx-datatable-footer", inputs: { footerHeight: "footerHeight", totalMessage: "totalMessage", selectedMessage: "selectedMessage", pagerLeftArrowIcon: "pagerLeftArrowIcon", pagerRightArrowIcon: "pagerRightArrowIcon", pagerPreviousIcon: "pagerPreviousIcon", pagerNextIcon: "pagerNextIcon", _templateInput: ["template", "_templateInput"] }, queries: [{ propertyName: "_templateQuery", first: true, predicate: DataTableFooterTemplateDirective, descendants: true, read: TemplateRef }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableFooterDirective, decorators: [{ type: Directive, args: [{ selector: 'ngx-datatable-footer' }] }], propDecorators: { footerHeight: [{ type: Input }], totalMessage: [{ type: Input }], selectedMessage: [{ type: Input }], pagerLeftArrowIcon: [{ type: Input }], pagerRightArrowIcon: [{ type: Input }], pagerPreviousIcon: [{ type: Input }], pagerNextIcon: [{ type: Input }], _templateInput: [{ type: Input, args: ['template'] }], _templateQuery: [{ type: ContentChild, args: [DataTableFooterTemplateDirective, { read: TemplateRef }] }] } }); /** * Returns the columns by pin. */ function columnsByPin(cols) { const ret = { left: [], center: [], right: [] }; if (cols) { for (const col of cols) { if (col.frozenLeft) { ret.left.push(col); } else if (col.frozenRight) { ret.right.push(col); } else { ret.center.push(col); } } } return ret; } /** * Returns the widths of all group sets of a column */ function columnGroupWidths(groups, all) { return { left: columnTotalWidth(groups.left), center: columnTotalWidth(groups.center), right: columnTotalWidth(groups.right), total: Math.floor(columnTotalWidth(all)) }; } /** * Calculates the total width of all columns and their groups */ function columnTotalWidth(columns, prop) { let totalWidth = 0; if (columns) { for (const c of columns) { const has = prop && c[prop]; const width = has ? c[prop] : c.width; totalWidth = totalWidth + parseFloat(width); } } return totalWidth; } /** * Calculates the total width of all columns and their groups */ function columnsTotalWidth(columns, prop) { let totalWidth = 0; for (const column of columns) { const has = prop && column[prop]; totalWidth = totalWidth + (has ? column[prop] : column.width); } return totalWidth; } function columnsByPinArr(val) { const colsByPinArr = []; const colsByPin = columnsByPin(val); colsByPinArr.push({ type: 'left', columns: colsByPin['left'] }); colsByPinArr.push({ type: 'center', columns: colsByPin['center'] }); colsByPinArr.push({ type: 'right', columns: colsByPin['right'] }); return colsByPinArr; } /** * This object contains the cache of the various row heights that are present inside * the data table. Its based on Fenwick tree data structure that helps with * querying sums that have time complexity of log n. * * Fenwick Tree Credits: http://petr-mitrichev.blogspot.com/2013/05/fenwick-tree-range-updates.html * https://github.com/mikolalysenko/fenwick-tree * */ class RowHeightCache { constructor() { /** * Tree Array stores the cumulative information of the row heights to perform efficient * range queries and updates. Currently the tree is initialized to the base row * height instead of the detail row height. */ this.treeArray = []; } /** * Clear the Tree array. */ clearCache() { this.treeArray = []; } /** * Initialize the Fenwick tree with row Heights. * * @param rows The array of rows which contain the expanded status. * @param rowHeight The row height. * @param detailRowHeight The detail row height. */ initCache(details) { const { rows, rowHeight, detailRowHeight, externalVirtual, rowCount, rowIndexes, rowExpansions } = details; const isFn = typeof rowHeight === 'function'; const isDetailFn = typeof detailRowHeight === 'function'; if (!isFn && isNaN(rowHeight)) { throw new Error(`Row Height cache initialization failed. Please ensure that 'rowHeight' is a valid number or function value: (${rowHeight}) when 'scrollbarV' is enabled.`); } // Add this additional guard in case detailRowHeight is set to 'auto' as it wont work. if (!isDetailFn && isNaN(detailRowHeight)) { throw new Error(`Row Height cache initialization failed. Please ensure that 'detailRowHeight' is a valid number or function value: (${detailRowHeight}) when 'scrollbarV' is enabled.`); } const n = externalVirtual ? rowCount : rows.length; this.treeArray = new Array(n); for (let i = 0; i < n; ++i) { this.treeArray[i] = 0; } for (let i = 0; i < n; ++i) { const row = rows[i]; let currentRowHeight = rowHeight; if (isFn) { currentRowHeight = rowHeight(row); } // Add the detail row height to the already expanded rows. // This is useful for the table that goes through a filter or sort. const expanded = rowExpansions.has(row); if (row && expanded) { if (isDetailFn) { const index = rowIndexes.get(row); currentRowHeight += detailRowHeight(row, index); } else { currentRowHeight += detailRowHeight; } } this.update(i, currentRowHeight); } } /** * Given the ScrollY position i.e. sum, provide the rowIndex * that is present in the current view port. Below handles edge cases. */ getRowIndex(scrollY) { if (scrollY === 0) return 0; return this.calcRowIndex(scrollY); } /** * When a row is expanded or rowHeight is changed, update the height. This can * be utilized in future when Angular Data table supports dynamic row heights. */ update(atRowIndex, byRowHeight) { if (!this.treeArray.length) { throw new Error(`Update at index ${atRowIndex} with value ${byRowHeight} failed: Row Height cache not initialized.`); } const n = this.treeArray.length; atRowIndex |= 0; while (atRowIndex < n) { this.treeArray[atRowIndex] += byRowHeight; atRowIndex |= atRowIndex + 1; } } /** * Range Sum query from 1 to the rowIndex */ query(atIndex) { if (!this.treeArray.length) { throw new Error(`query at index ${atIndex} failed: Fenwick tree array not initialized.`); } let sum = 0; atIndex |= 0; while (atIndex >= 0) { sum += this.treeArray[atIndex]; atIndex = (atIndex & (atIndex + 1)) - 1; } return sum; } /** * Find the total height between 2 row indexes */ queryBetween(atIndexA, atIndexB) { return this.query(atIndexB) - this.query(atIndexA - 1); } /** * Given the ScrollY position i.e. sum, provide the rowIndex * that is present in the current view port. */ calcRowIndex(sum) { if (!this.treeArray.length) return 0; let pos = -1; const dataLength = this.treeArray.length; // Get the highest bit for the block size. const highestBit = Math.pow(2, dataLength.toString(2).length - 1); for (let blockSize = highestBit; blockSize !== 0; blockSize >>= 1) { const nextPos = pos + blockSize; if (nextPos < dataLength && sum >= this.treeArray[nextPos]) { sum -= this.treeArray[nextPos]; pos = nextPos; } } return pos + 1; } } const cache = {}; const testStyle = typeof document !== 'undefined' ? document.createElement('div').style : undefined; // Get Prefix // http://davidwalsh.name/vendor-prefix const prefix = (function () { const styles = typeof window !== 'undefined' ? window.getComputedStyle(document.documentElement, '') : undefined; const match = typeof styles !== 'undefined' ? Array.prototype.slice .call(styles) .join('') .match(/-(moz|webkit|ms)-/) : null; const pre = match !== null ? match[1] : undefined; // tslint:disable-next-line: tsr-detect-non-literal-regexp const dom = typeof pre !== 'undefined' ? 'WebKit|Moz|MS|O'.match(new RegExp('(' + pre + ')', 'i'))[1] : undefined; return dom ? { dom, lowercase: pre, css: `-${pre}-`, js: pre[0].toUpperCase() + pre.substr(1) } : undefined; })(); function getVendorPrefixedName(property) { const name = camelCase(property); if (!cache[name]) { if (prefix !== undefined && testStyle[prefix.css + property] !== undefined) { cache[name] = prefix.css + property; } else if (testStyle[property] !== undefined) { cache[name] = property; } } return cache[name]; } // browser detection and prefixing tools const transform = typeof window !== 'undefined' ? getVendorPrefixedName('transform') : undefined; const backfaceVisibility = typeof window !== 'undefined' ? getVendorPrefixedName('backfaceVisibility') : undefined; const hasCSSTransforms = typeof window !== 'undefined' ? !!getVendorPrefixedName('transform') : undefined; const hasCSS3DTransforms = typeof window !== 'undefined' ? !!getVendorPrefixedName('perspective') : undefined; const ua = typeof window !== 'undefined' ? window.navigator.userAgent : 'Chrome'; const isSafari = /Safari\//.test(ua) && !/Chrome\//.test(ua); function translateXY(styles, x, y) { if (typeof transform !== 'undefined' && hasCSSTransforms) { if (!isSafari && hasCSS3DTransforms) { styles[transform] = `translate3d(${x}px, ${y}px, 0)`; styles[backfaceVisibility] = 'hidden'; } else { styles[camelCase(transform)] = `translate(${x}px, ${y}px)`; } } else { styles.top = `${y}px`; styles.left = `${x}px`; } } class ProgressBarComponent { } ProgressBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); ProgressBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: ProgressBarComponent, selector: "datatable-progress", ngImport: i0, template: `
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ProgressBarComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-progress', template: `
`, changeDetection: ChangeDetectionStrategy.OnPush }] }] }); function selectRows(selected, row, comparefn) { const selectedIndex = comparefn(row, selected); if (selectedIndex > -1) { selected.splice(selectedIndex, 1); } else { selected.push(row); } return selected; } function selectRowsBetween(selected, rows, index, prevIndex, comparefn) { const reverse = index < prevIndex; for (let i = 0; i < rows.length; i++) { const row = rows[i]; const greater = i >= prevIndex && i <= index; const lesser = i <= prevIndex && i >= index; let range = { start: 0, end: 0 }; if (reverse) { range = { start: index, end: prevIndex }; } else { range = { start: prevIndex, end: index + 1 }; } if ((reverse && lesser) || (!reverse && greater)) { // if in the positive range to be added to `selected`, and // not already in the selected array, add it if (i >= range.start && i <= range.end) { selected.push(row); } } } return selected; } var Keys; (function (Keys) { Keys[Keys["up"] = 38] = "up"; Keys[Keys["down"] = 40] = "down"; Keys[Keys["return"] = 13] = "return"; Keys[Keys["escape"] = 27] = "escape"; Keys[Keys["left"] = 37] = "left"; Keys[Keys["right"] = 39] = "right"; })(Keys || (Keys = {})); class DataTableSelectionComponent { constructor() { this.activate = new EventEmitter(); this.select = new EventEmitter(); } selectRow(event, index, row) { if (!this.selectEnabled) return; const chkbox = this.selectionType === SelectionType.checkbox; const multi = this.selectionType === SelectionType.multi; const multiClick = this.selectionType === SelectionType.multiClick; let selected = []; if (multi || chkbox || multiClick) { if (event.shiftKey) { selected = selectRowsBetween([], this.rows, index, this.prevIndex, this.getRowSelectedIdx.bind(this)); } else if (event.ctrlKey || event.metaKey || multiClick || chkbox) { selected = selectRows([...this.selected], row, this.getRowSelectedIdx.bind(this)); } else { selected = selectRows([], row, this.getRowSelectedIdx.bind(this)); } } else { selected = selectRows([], row, this.getRowSelectedIdx.bind(this)); } if (typeof this.selectCheck === 'function') { selected = selected.filter(this.selectCheck.bind(this)); } this.selected.splice(0, this.selected.length); this.selected.push(...selected); this.prevIndex = index; this.select.emit({ selected }); } onActivate(model, index) { const { type, event, row } = model; const chkbox = this.selectionType === SelectionType.checkbox; const select = (!chkbox && (type === 'click' || type === 'dblclick')) || (chkbox && type === 'checkbox'); if (select) { this.selectRow(event, index, row); } else if (type === 'keydown') { if (event.keyCode === Keys.return) { this.selectRow(event, index, row); } else { this.onKeyboardFocus(model); } } this.activate.emit(model); } onKeyboardFocus(model) { const { keyCode } = model.event; const shouldFocus = keyCode === Keys.up || keyCode === Keys.down || keyCode === Keys.right || keyCode === Keys.left; if (shouldFocus) { const isCellSelection = this.selectionType === SelectionType.cell; if (!model.cellElement || !isCellSelection) { this.focusRow(model.rowElement, keyCode); } else if (isCellSelection) { this.focusCell(model.cellElement, model.rowElement, keyCode, model.cellIndex); } } } focusRow(rowElement, keyCode) { const nextRowElement = this.getPrevNextRow(rowElement, keyCode); if (nextRowElement) nextRowElement.focus(); } getPrevNextRow(rowElement, keyCode) { const parentElement = rowElement.parentElement; if (parentElement) { let focusElement; if (keyCode === Keys.up) { focusElement = parentElement.previousElementSibling; } else if (keyCode === Keys.down) { focusElement = parentElement.nextElementSibling; } if (focusElement && focusElement.children.length) { return focusElement.children[0]; } } } focusCell(cellElement, rowElement, keyCode, cellIndex) { let nextCellElement; if (keyCode === Keys.left) { nextCellElement = cellElement.previousElementSibling; } else if (keyCode === Keys.right) { nextCellElement = cellElement.nextElementSibling; } else if (keyCode === Keys.up || keyCode === Keys.down) { const nextRowElement = this.getPrevNextRow(rowElement, keyCode); if (nextRowElement) { const children = nextRowElement.getElementsByClassName('datatable-body-cell'); if (children.length) nextCellElement = children[cellIndex]; } } if (nextCellElement) nextCellElement.focus(); } getRowSelected(row) { return this.getRowSelectedIdx(row, this.selected) > -1; } getRowSelectedIdx(row, selected) { if (!selected || !selected.length) return -1; const rowId = this.rowIdentity(row); return selected.findIndex(r => { const id = this.rowIdentity(r); return id === rowId; }); } } DataTableSelectionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableSelectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); DataTableSelectionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableSelectionComponent, selector: "datatable-selection", inputs: { rows: "rows", selected: "selected", selectEnabled: "selectEnabled", selectionType: "selectionType", rowIdentity: "rowIdentity", selectCheck: "selectCheck" }, outputs: { activate: "activate", select: "select" }, ngImport: i0, template: ` `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableSelectionComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-selection', template: ` `, changeDetection: ChangeDetectionStrategy.OnPush }] }], propDecorators: { rows: [{ type: Input }], selected: [{ type: Input }], selectEnabled: [{ type: Input }], selectionType: [{ type: Input }], rowIdentity: [{ type: Input }], selectCheck: [{ type: Input }], activate: [{ type: Output }], select: [{ type: Output }] } }); var SortDirection; (function (SortDirection) { SortDirection["asc"] = "asc"; SortDirection["desc"] = "desc"; })(SortDirection || (SortDirection = {})); class DataTableBodyCellComponent { constructor(element, cd) { this.cd = cd; this.activate = new EventEmitter(); this.treeAction = new EventEmitter(); this.isFocused = false; this.onCheckboxChangeFn = this.onCheckboxChange.bind(this); this.activateFn = this.activate.emit.bind(this.activate); this.cellContext = { onCheckboxChangeFn: this.onCheckboxChangeFn, activateFn: this.activateFn, row: this.row, group: this.group, value: this.value, column: this.column, rowHeight: this.rowHeight, isSelected: this.isSelected, rowIndex: this.rowIndex, treeStatus: this.treeStatus, onTreeAction: this.onTreeAction.bind(this) }; this._element = element.nativeElement; } set group(group) { this._group = group; this.cellContext.group = group; this.checkValueUpdates(); this.cd.markForCheck(); } get group() { return this._group; } set rowHeight(val) { this._rowHeight = val; this.cellContext.rowHeight = val; this.checkValueUpdates(); this.cd.markForCheck(); } get rowHeight() { return this._rowHeight; } set isSelected(val) { this._isSelected = val; this.cellContext.isSelected = val; this.cd.markForCheck(); } get isSelected() { return this._isSelected; } set expanded(val) { this._expanded = val; this.cellContext.expanded = val; this.cd.markForCheck(); } get expanded() { return this._expanded; } set rowIndex(val) { this._rowIndex = val; this.cellContext.rowIndex = val; this.checkValueUpdates(); this.cd.markForCheck(); } get rowIndex() { return this._rowIndex; } set column(column) { this._column = column; this.cellContext.column = column; this.checkValueUpdates(); this.cd.markForCheck(); } get column() { return this._column; } set row(row) { this._row = row; this.cellContext.row = row; this.checkValueUpdates(); this.cd.markForCheck(); } get row() { return this._row; } set sorts(val) { this._sorts = val; this.calcSortDir = this.calcSortDir(val); } get sorts() { return this._sorts; } set treeStatus(status) { if (status !== 'collapsed' && status !== 'expanded' && status !== 'loading' && status !== 'disabled') { this._treeStatus = 'collapsed'; } else { this._treeStatus = status; } this.cellContext.treeStatus = this._treeStatus; this.checkValueUpdates(); this.cd.markForCheck(); } get treeStatus() { return this._treeStatus; } get columnCssClasses() { let cls = 'datatable-body-cell'; if (this.column.cellClass) { if (typeof this.column.cellClass === 'string') { cls += ' ' + this.column.cellClass; } else if (typeof this.column.cellClass === 'function') { const res = this.column.cellClass({ row: this.row, group: this.group, column: this.column, value: this.value, rowHeight: this.rowHeight }); if (typeof res === 'string') { cls += ' ' + res; } else if (typeof res === 'object') { const keys = Object.keys(res); for (const k of keys) { if (res[k] === true) { cls += ` ${k}`; } } } } } if (!this.sortDir) { cls += ' sort-active'; } if (this.isFocused) { cls += ' active'; } if (this.sortDir === SortDirection.asc) { cls += ' sort-asc'; } if (this.sortDir === SortDirection.desc) { cls += ' sort-desc'; } return cls; } get width() { return this.column.width; } get minWidth() { return this.column.minWidth; } get maxWidth() { return this.column.maxWidth; } get height() { const height = this.rowHeight; if (isNaN(height)) { return height; } return height + 'px'; } ngDoCheck() { this.checkValueUpdates(); } ngOnDestroy() { if (this.cellTemplate) { this.cellTemplate.clear(); } } checkValueUpdates() { let value = ''; if (!this.row || !this.column) { value = ''; } else { const val = this.column.$$valueGetter(this.row, this.column.prop); const userPipe = this.column.pipe; if (userPipe) { value = userPipe.transform(val); } else if (value !== undefined) { value = val; } } if (this.value !== value) { this.value = value; this.cellContext.value = value; this.sanitizedValue = value !== null && value !== undefined ? this.stripHtml(value) : value; this.cd.markForCheck(); } } onFocus() { this.isFocused = true; } onBlur() { this.isFocused = false; } onClick(event) { this.activate.emit({ type: 'click', event, row: this.row, group: this.group, rowHeight: this.rowHeight, column: this.column, value: this.value, cellElement: this._element }); } onDblClick(event) { this.activate.emit({ type: 'dblclick', event, row: this.row, group: this.group, rowHeight: this.rowHeight, column: this.column, value: this.value, cellElement: this._element }); } onKeyDown(event) { const keyCode = event.keyCode; const isTargetCell = event.target === this._element; const isAction = keyCode === Keys.return || keyCode === Keys.down || keyCode === Keys.up || keyCode === Keys.left || keyCode === Keys.right; if (isAction && isTargetCell) { event.preventDefault(); event.stopPropagation(); this.activate.emit({ type: 'keydown', event, row: this.row, group: this.group, rowHeight: this.rowHeight, column: this.column, value: this.value, cellElement: this._element }); } } onCheckboxChange(event) { this.activate.emit({ type: 'checkbox', event, row: this.row, group: this.group, rowHeight: this.rowHeight, column: this.column, value: this.value, cellElement: this._element, treeStatus: 'collapsed' }); } calcSortDir(sorts) { if (!sorts) { return; } const sort = sorts.find((s) => { return s.prop === this.column.prop; }); if (sort) { return sort.dir; } } stripHtml(html) { if (!html.replace) { return html; } return html.replace(/<\/?[^>]+(>|$)/g, ''); } onTreeAction() { this.treeAction.emit(this.row); } calcLeftMargin(column, row) { const levelIndent = column.treeLevelIndent != null ? column.treeLevelIndent : 50; return column.isTreeColumn ? row.level * levelIndent : 0; } } DataTableBodyCellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyCellComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); DataTableBodyCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableBodyCellComponent, selector: "datatable-body-cell", inputs: { displayCheck: "displayCheck", group: "group", rowHeight: "rowHeight", isSelected: "isSelected", expanded: "expanded", rowIndex: "rowIndex", column: "column", row: "row", sorts: "sorts", treeStatus: "treeStatus" }, outputs: { activate: "activate", treeAction: "treeAction" }, host: { listeners: { "focus": "onFocus()", "blur": "onBlur()", "click": "onClick($event)", "dblclick": "onDblClick($event)", "keydown": "onKeyDown($event)" }, properties: { "class": "this.columnCssClasses", "style.width.px": "this.width", "style.minWidth.px": "this.minWidth", "style.maxWidth.px": "this.maxWidth", "style.height": "this.height" } }, viewQueries: [{ propertyName: "cellTemplate", first: true, predicate: ["cellTemplate"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
`, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyCellComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-body-cell', changeDetection: ChangeDetectionStrategy.OnPush, template: `
` }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { displayCheck: [{ type: Input }], group: [{ type: Input }], rowHeight: [{ type: Input }], isSelected: [{ type: Input }], expanded: [{ type: Input }], rowIndex: [{ type: Input }], column: [{ type: Input }], row: [{ type: Input }], sorts: [{ type: Input }], treeStatus: [{ type: Input }], activate: [{ type: Output }], treeAction: [{ type: Output }], cellTemplate: [{ type: ViewChild, args: ['cellTemplate', { read: ViewContainerRef, static: true }] }], columnCssClasses: [{ type: HostBinding, args: ['class'] }], width: [{ type: HostBinding, args: ['style.width.px'] }], minWidth: [{ type: HostBinding, args: ['style.minWidth.px'] }], maxWidth: [{ type: HostBinding, args: ['style.maxWidth.px'] }], height: [{ type: HostBinding, args: ['style.height'] }], onFocus: [{ type: HostListener, args: ['focus'] }], onBlur: [{ type: HostListener, args: ['blur'] }], onClick: [{ type: HostListener, args: ['click', ['$event']] }], onDblClick: [{ type: HostListener, args: ['dblclick', ['$event']] }], onKeyDown: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); class DataTableBodyRowComponent { constructor(differs, scrollbarHelper, cd, element) { this.differs = differs; this.scrollbarHelper = scrollbarHelper; this.cd = cd; this.treeStatus = 'collapsed'; this.activate = new EventEmitter(); this.treeAction = new EventEmitter(); this._groupStyles = { left: {}, center: {}, right: {} }; this._element = element.nativeElement; this._rowDiffer = differs.find({}).create(); } set columns(val) { this._columns = val; this.recalculateColumns(val); this.buildStylesByGroup(); } get columns() { return this._columns; } set innerWidth(val) { if (this._columns) { const colByPin = columnsByPin(this._columns); this._columnGroupWidths = columnGroupWidths(colByPin, this._columns); } this._innerWidth = val; this.recalculateColumns(); this.buildStylesByGroup(); } get innerWidth() { return this._innerWidth; } set offsetX(val) { this._offsetX = val; this.buildStylesByGroup(); } get offsetX() { return this._offsetX; } get cssClass() { let cls = 'datatable-body-row'; if (this.isSelected) { cls += ' active'; } if (this.rowIndex % 2 !== 0) { cls += ' datatable-row-odd'; } if (this.rowIndex % 2 === 0) { cls += ' datatable-row-even'; } if (this.rowClass) { const res = this.rowClass(this.row); if (typeof res === 'string') { cls += ` ${res}`; } else if (typeof res === 'object') { const keys = Object.keys(res); for (const k of keys) { if (res[k] === true) { cls += ` ${k}`; } } } } return cls; } get columnsTotalWidths() { return this._columnGroupWidths.total; } ngDoCheck() { if (this._rowDiffer.diff(this.row)) { this.cd.markForCheck(); } } trackByGroups(index, colGroup) { return colGroup.type; } columnTrackingFn(index, column) { return column.$$id; } buildStylesByGroup() { this._groupStyles.left = this.calcStylesByGroup('left'); this._groupStyles.center = this.calcStylesByGroup('center'); this._groupStyles.right = this.calcStylesByGroup('right'); this.cd.markForCheck(); } calcStylesByGroup(group) { const widths = this._columnGroupWidths; const offsetX = this.offsetX; const styles = { width: `${widths[group]}px` }; if (group === 'left') { translateXY(styles, offsetX, 0); } else if (group === 'right') { const bodyWidth = parseInt(this.innerWidth + '', 0); const totalDiff = widths.total - bodyWidth; const offsetDiff = totalDiff - offsetX; const offset = (offsetDiff + this.scrollbarHelper.width) * -1; translateXY(styles, offset, 0); } return styles; } onActivate(event, index) { event.cellIndex = index; event.rowElement = this._element; this.activate.emit(event); } onKeyDown(event) { const keyCode = event.keyCode; const isTargetRow = event.target === this._element; const isAction = keyCode === Keys.return || keyCode === Keys.down || keyCode === Keys.up || keyCode === Keys.left || keyCode === Keys.right; if (isAction && isTargetRow) { event.preventDefault(); event.stopPropagation(); this.activate.emit({ type: 'keydown', event, row: this.row, rowElement: this._element }); } } onMouseenter(event) { this.activate.emit({ type: 'mouseenter', event, row: this.row, rowElement: this._element }); } recalculateColumns(val = this.columns) { this._columns = val; const colsByPin = columnsByPin(this._columns); this._columnsByPin = columnsByPinArr(this._columns); this._columnGroupWidths = columnGroupWidths(colsByPin, this._columns); } onTreeAction() { this.treeAction.emit(); } } DataTableBodyRowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyRowComponent, deps: [{ token: i0.KeyValueDiffers }, { token: ScrollbarHelper, skipSelf: true }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); DataTableBodyRowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableBodyRowComponent, selector: "datatable-body-row", inputs: { columns: "columns", innerWidth: "innerWidth", expanded: "expanded", rowClass: "rowClass", row: "row", group: "group", isSelected: "isSelected", rowIndex: "rowIndex", displayCheck: "displayCheck", treeStatus: "treeStatus", offsetX: "offsetX", rowHeight: "rowHeight" }, outputs: { activate: "activate", treeAction: "treeAction" }, host: { listeners: { "keydown": "onKeyDown($event)", "mouseenter": "onMouseenter($event)" }, properties: { "class": "this.cssClass", "style.height.px": "this.rowHeight", "style.width.px": "this.columnsTotalWidths" } }, ngImport: i0, template: `
`, isInline: true, components: [{ type: DataTableBodyCellComponent, selector: "datatable-body-cell", inputs: ["displayCheck", "group", "rowHeight", "isSelected", "expanded", "rowIndex", "column", "row", "sorts", "treeStatus"], outputs: ["activate", "treeAction"] }], directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyRowComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-body-row', changeDetection: ChangeDetectionStrategy.OnPush, template: `
` }] }], ctorParameters: function () { return [{ type: i0.KeyValueDiffers }, { type: ScrollbarHelper, decorators: [{ type: SkipSelf }] }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { columns: [{ type: Input }], innerWidth: [{ type: Input }], expanded: [{ type: Input }], rowClass: [{ type: Input }], row: [{ type: Input }], group: [{ type: Input }], isSelected: [{ type: Input }], rowIndex: [{ type: Input }], displayCheck: [{ type: Input }], treeStatus: [{ type: Input }], offsetX: [{ type: Input }], cssClass: [{ type: HostBinding, args: ['class'] }], rowHeight: [{ type: HostBinding, args: ['style.height.px'] }, { type: Input }], columnsTotalWidths: [{ type: HostBinding, args: ['style.width.px'] }], activate: [{ type: Output }], treeAction: [{ type: Output }], onKeyDown: [{ type: HostListener, args: ['keydown', ['$event']] }], onMouseenter: [{ type: HostListener, args: ['mouseenter', ['$event']] }] } }); function defaultSumFunc(cells) { const cellsWithValues = cells.filter(cell => !!cell); if (!cellsWithValues.length) { return null; } if (cellsWithValues.some(cell => typeof cell !== 'number')) { return null; } return cellsWithValues.reduce((res, cell) => res + cell); } function noopSumFunc(cells) { return null; } class DataTableSummaryRowComponent { constructor() { this.summaryRow = {}; } ngOnChanges() { if (!this.columns || !this.rows) { return; } this.updateInternalColumns(); this.updateValues(); } updateInternalColumns() { this._internalColumns = this.columns.map(col => ({ ...col, cellTemplate: col.summaryTemplate })); } updateValues() { this.summaryRow = {}; this.columns .filter(col => !col.summaryTemplate) .forEach(col => { const cellsFromSingleColumn = this.rows.map(row => row[col.prop]); const sumFunc = this.getSummaryFunction(col); this.summaryRow[col.prop] = col.pipe ? col.pipe.transform(sumFunc(cellsFromSingleColumn)) : sumFunc(cellsFromSingleColumn); }); } getSummaryFunction(column) { if (column.summaryFunc === undefined) { return defaultSumFunc; } else if (column.summaryFunc === null) { return noopSumFunc; } else { return column.summaryFunc; } } } DataTableSummaryRowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableSummaryRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); DataTableSummaryRowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableSummaryRowComponent, selector: "datatable-summary-row", inputs: { rows: "rows", columns: "columns", rowHeight: "rowHeight", offsetX: "offsetX", innerWidth: "innerWidth" }, host: { classAttribute: "datatable-summary-row" }, usesOnChanges: true, ngImport: i0, template: ` `, isInline: true, components: [{ type: DataTableBodyRowComponent, selector: "datatable-body-row", inputs: ["columns", "innerWidth", "expanded", "rowClass", "row", "group", "isSelected", "rowIndex", "displayCheck", "treeStatus", "offsetX", "rowHeight"], outputs: ["activate", "treeAction"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableSummaryRowComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-summary-row', template: ` `, host: { class: 'datatable-summary-row' } }] }], propDecorators: { rows: [{ type: Input }], columns: [{ type: Input }], rowHeight: [{ type: Input }], offsetX: [{ type: Input }], innerWidth: [{ type: Input }] } }); class DataTableRowWrapperComponent { constructor(cd, differs) { this.cd = cd; this.differs = differs; this.rowContextmenu = new EventEmitter(false); this._expanded = false; this.groupContext = { group: this.row, expanded: this.expanded, rowIndex: this.rowIndex }; this.rowContext = { row: this.row, expanded: this.expanded, rowIndex: this.rowIndex }; this.rowDiffer = differs.find({}).create(); } set rowIndex(val) { this._rowIndex = val; this.rowContext.rowIndex = val; this.groupContext.rowIndex = val; this.cd.markForCheck(); } get rowIndex() { return this._rowIndex; } set expanded(val) { this._expanded = val; this.groupContext.expanded = val; this.rowContext.expanded = val; this.cd.markForCheck(); } get expanded() { return this._expanded; } ngDoCheck() { if (this.rowDiffer.diff(this.row)) { this.rowContext.row = this.row; this.groupContext.group = this.row; this.cd.markForCheck(); } } onContextmenu($event) { this.rowContextmenu.emit({ event: $event, row: this.row }); } getGroupHeaderStyle() { const styles = {}; styles['transform'] = 'translate3d(' + this.offsetX + 'px, 0px, 0px)'; styles['backface-visibility'] = 'hidden'; styles['width'] = this.innerWidth; return styles; } } DataTableRowWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableRowWrapperComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.KeyValueDiffers }], target: i0.ɵɵFactoryTarget.Component }); DataTableRowWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableRowWrapperComponent, selector: "datatable-row-wrapper", inputs: { innerWidth: "innerWidth", rowDetail: "rowDetail", groupHeader: "groupHeader", offsetX: "offsetX", detailRowHeight: "detailRowHeight", row: "row", groupedRows: "groupedRows", rowIndex: "rowIndex", expanded: "expanded" }, outputs: { rowContextmenu: "rowContextmenu" }, host: { listeners: { "contextmenu": "onContextmenu($event)" }, classAttribute: "datatable-row-wrapper" }, ngImport: i0, template: `
`, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableRowWrapperComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-row-wrapper', changeDetection: ChangeDetectionStrategy.OnPush, template: `
`, host: { class: 'datatable-row-wrapper' } }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.KeyValueDiffers }]; }, propDecorators: { innerWidth: [{ type: Input }], rowDetail: [{ type: Input }], groupHeader: [{ type: Input }], offsetX: [{ type: Input }], detailRowHeight: [{ type: Input }], row: [{ type: Input }], groupedRows: [{ type: Input }], rowContextmenu: [{ type: Output }], rowIndex: [{ type: Input }], expanded: [{ type: Input }], onContextmenu: [{ type: HostListener, args: ['contextmenu', ['$event']] }] } }); class DataTableBodyComponent { /** * Creates an instance of DataTableBodyComponent. */ constructor(cd) { this.cd = cd; this.selected = []; this.scroll = new EventEmitter(); this.page = new EventEmitter(); this.activate = new EventEmitter(); this.select = new EventEmitter(); this.detailToggle = new EventEmitter(); this.rowContextmenu = new EventEmitter(false); this.treeAction = new EventEmitter(); this.rowHeightsCache = new RowHeightCache(); this.temp = []; this.offsetY = 0; this.indexes = {}; this.rowIndexes = new WeakMap(); this.rowExpansions = []; /** * Get the height of the detail row. */ this.getDetailRowHeight = (row, index) => { if (!this.rowDetail) { return 0; } const rowHeight = this.rowDetail.rowHeight; return typeof rowHeight === 'function' ? rowHeight(row, index) : rowHeight; }; // declare fn here so we can get access to the `this` property this.rowTrackingFn = (index, row) => { const idx = this.getRowIndex(row); if (this.trackByProp) { return row[this.trackByProp]; } else { return idx; } }; } set pageSize(val) { this._pageSize = val; this.recalcLayout(); } get pageSize() { return this._pageSize; } set rows(val) { this._rows = val; this.recalcLayout(); } get rows() { return this._rows; } set columns(val) { this._columns = val; const colsByPin = columnsByPin(val); this.columnGroupWidths = columnGroupWidths(colsByPin, val); } get columns() { return this._columns; } set offset(val) { this._offset = val; if (!this.scrollbarV || (this.scrollbarV && !this.virtualization)) this.recalcLayout(); } get offset() { return this._offset; } set rowCount(val) { this._rowCount = val; this.recalcLayout(); } get rowCount() { return this._rowCount; } get bodyWidth() { if (this.scrollbarH) { return this.innerWidth + 'px'; } else { return '100%'; } } set bodyHeight(val) { if (this.scrollbarV) { this._bodyHeight = val + 'px'; } else { this._bodyHeight = 'auto'; } this.recalcLayout(); } get bodyHeight() { return this._bodyHeight; } /** * Returns if selection is enabled. */ get selectEnabled() { return !!this.selectionType; } /** * Property that would calculate the height of scroll bar * based on the row heights cache for virtual scroll and virtualization. Other scenarios * calculate scroll height automatically (as height will be undefined). */ get scrollHeight() { if (this.scrollbarV && this.virtualization && this.rowCount) { return this.rowHeightsCache.query(this.rowCount - 1); } // avoid TS7030: Not all code paths return a value. return undefined; } /** * Called after the constructor, initializing input properties */ ngOnInit() { if (this.rowDetail) { this.listener = this.rowDetail.toggle.subscribe(({ type, value }) => { if (type === 'row') { this.toggleRowExpansion(value); } if (type === 'all') { this.toggleAllRows(value); } // Refresh rows after toggle // Fixes #883 this.updateIndexes(); this.updateRows(); this.cd.markForCheck(); }); } if (this.groupHeader) { this.listener = this.groupHeader.toggle.subscribe(({ type, value }) => { if (type === 'group') { this.toggleRowExpansion(value); } if (type === 'all') { this.toggleAllRows(value); } // Refresh rows after toggle // Fixes #883 this.updateIndexes(); this.updateRows(); this.cd.markForCheck(); }); } } /** * Called once, before the instance is destroyed. */ ngOnDestroy() { if (this.rowDetail || this.groupHeader) { this.listener.unsubscribe(); } } /** * Updates the Y offset given a new offset. */ updateOffsetY(offset) { // scroller is missing on empty table if (!this.scroller) { return; } if (this.scrollbarV && this.virtualization && offset) { // First get the row Index that we need to move to. const rowIndex = this.pageSize * offset; offset = this.rowHeightsCache.query(rowIndex - 1); } else if (this.scrollbarV && !this.virtualization) { offset = 0; } this.scroller.setOffset(offset || 0); } /** * Body was scrolled, this is mainly useful for * when a user is server-side pagination via virtual scroll. */ onBodyScroll(event) { const scrollYPos = event.scrollYPos; const scrollXPos = event.scrollXPos; // if scroll change, trigger update // this is mainly used for header cell positions if (this.offsetY !== scrollYPos || this.offsetX !== scrollXPos) { this.scroll.emit({ offsetY: scrollYPos, offsetX: scrollXPos }); } this.offsetY = scrollYPos; this.offsetX = scrollXPos; this.updateIndexes(); this.updatePage(event.direction); this.updateRows(); } /** * Updates the page given a direction. */ updatePage(direction) { let offset = this.indexes.first / this.pageSize; if (direction === 'up') { offset = Math.ceil(offset); } else if (direction === 'down') { offset = Math.floor(offset); } if (direction !== undefined && !isNaN(offset)) { this.page.emit({ offset }); } } /** * Updates the rows in the view port */ updateRows() { const { first, last } = this.indexes; let rowIndex = first; let idx = 0; const temp = []; // if grouprowsby has been specified treat row paging // parameters as group paging parameters ie if limit 10 has been // specified treat it as 10 groups rather than 10 rows if (this.groupedRows) { let maxRowsPerGroup = 3; // if there is only one group set the maximum number of // rows per group the same as the total number of rows if (this.groupedRows.length === 1) { maxRowsPerGroup = this.groupedRows[0].value.length; } while (rowIndex < last && rowIndex < this.groupedRows.length) { // Add the groups into this page const group = this.groupedRows[rowIndex]; this.rowIndexes.set(group, rowIndex); if (group.value) { // add indexes for each group item group.value.forEach((g, i) => { const _idx = `${rowIndex}-${i}`; this.rowIndexes.set(g, _idx); }); } temp[idx] = group; idx++; // Group index in this context rowIndex++; } } else { while (rowIndex < last && rowIndex < this.rowCount) { const row = this.rows[rowIndex]; if (row) { // add indexes for each row this.rowIndexes.set(row, rowIndex); temp[idx] = row; } idx++; rowIndex++; } } this.temp = temp; } /** * Get the row height */ getRowHeight(row) { // if its a function return it if (typeof this.rowHeight === 'function') { return this.rowHeight(row); } return this.rowHeight; } /** * @param group the group with all rows */ getGroupHeight(group) { let rowHeight = 0; if (group.value) { for (let index = 0; index < group.value.length; index++) { rowHeight += this.getRowAndDetailHeight(group.value[index]); } } return rowHeight; } /** * Calculate row height based on the expanded state of the row. */ getRowAndDetailHeight(row) { let rowHeight = this.getRowHeight(row); const expanded = this.getRowExpanded(row); // Adding detail row height if its expanded. if (expanded) { rowHeight += this.getDetailRowHeight(row); } return rowHeight; } /** * Calculates the styles for the row so that the rows can be moved in 2D space * during virtual scroll inside the DOM. In the below case the Y position is * manipulated. As an example, if the height of row 0 is 30 px and row 1 is * 100 px then following styles are generated: * * transform: translate3d(0px, 0px, 0px); -> row0 * transform: translate3d(0px, 30px, 0px); -> row1 * transform: translate3d(0px, 130px, 0px); -> row2 * * Row heights have to be calculated based on the row heights cache as we wont * be able to determine which row is of what height before hand. In the above * case the positionY of the translate3d for row2 would be the sum of all the * heights of the rows before it (i.e. row0 and row1). * * @param rows the row that needs to be placed in the 2D space. * @returns the CSS3 style to be applied * * @memberOf DataTableBodyComponent */ getRowsStyles(rows) { const styles = {}; // only add styles for the group if there is a group if (this.groupedRows) { styles.width = this.columnGroupWidths.total; } if (this.scrollbarV && this.virtualization) { let idx = 0; if (this.groupedRows) { // Get the latest row rowindex in a group const row = rows[rows.length - 1]; idx = row ? this.getRowIndex(row) : 0; } else { idx = this.getRowIndex(rows); } // const pos = idx * rowHeight; // The position of this row would be the sum of all row heights // until the previous row position. const pos = this.rowHeightsCache.query(idx - 1); translateXY(styles, 0, pos); } return styles; } /** * Calculate bottom summary row offset for scrollbar mode. * For more information about cache and offset calculation * see description for `getRowsStyles` method * * @returns the CSS3 style to be applied * * @memberOf DataTableBodyComponent */ getBottomSummaryRowStyles() { if (!this.scrollbarV || !this.rows || !this.rows.length) { return null; } const styles = { position: 'absolute' }; const pos = this.rowHeightsCache.query(this.rows.length - 1); translateXY(styles, 0, pos); return styles; } /** * Hides the loading indicator */ hideIndicator() { setTimeout(() => (this.loadingIndicator = false), 500); } /** * Updates the index of the rows in the viewport */ updateIndexes() { let first = 0; let last = 0; if (this.scrollbarV) { if (this.virtualization) { // Calculation of the first and last indexes will be based on where the // scrollY position would be at. The last index would be the one // that shows up inside the view port the last. const height = parseInt(this.bodyHeight, 0); first = this.rowHeightsCache.getRowIndex(this.offsetY); last = this.rowHeightsCache.getRowIndex(height + this.offsetY) + 1; } else { // If virtual rows are not needed // We render all in one go first = 0; last = this.rowCount; } } else { // The server is handling paging and will pass an array that begins with the // element at a specified offset. first should always be 0 with external paging. if (!this.externalPaging) { first = Math.max(this.offset * this.pageSize, 0); } last = Math.min(first + this.pageSize, this.rowCount); } this.indexes = { first, last }; } /** * Refreshes the full Row Height cache. Should be used * when the entire row array state has changed. */ refreshRowHeightCache() { if (!this.scrollbarV || (this.scrollbarV && !this.virtualization)) { return; } // clear the previous row height cache if already present. // this is useful during sorts, filters where the state of the // rows array is changed. this.rowHeightsCache.clearCache(); // Initialize the tree only if there are rows inside the tree. if (this.rows && this.rows.length) { const rowExpansions = new Set(); for (const row of this.rows) { if (this.getRowExpanded(row)) { rowExpansions.add(row); } } this.rowHeightsCache.initCache({ rows: this.rows, rowHeight: this.rowHeight, detailRowHeight: this.getDetailRowHeight, externalVirtual: this.scrollbarV && this.externalPaging, rowCount: this.rowCount, rowIndexes: this.rowIndexes, rowExpansions }); } } /** * Gets the index for the view port */ getAdjustedViewPortIndex() { // Capture the row index of the first row that is visible on the viewport. // If the scroll bar is just below the row which is highlighted then make that as the // first index. const viewPortFirstRowIndex = this.indexes.first; if (this.scrollbarV && this.virtualization) { const offsetScroll = this.rowHeightsCache.query(viewPortFirstRowIndex - 1); return offsetScroll <= this.offsetY ? viewPortFirstRowIndex - 1 : viewPortFirstRowIndex; } return viewPortFirstRowIndex; } /** * Toggle the Expansion of the row i.e. if the row is expanded then it will * collapse and vice versa. Note that the expanded status is stored as * a part of the row object itself as we have to preserve the expanded row * status in case of sorting and filtering of the row set. */ toggleRowExpansion(row) { // Capture the row index of the first row that is visible on the viewport. const viewPortFirstRowIndex = this.getAdjustedViewPortIndex(); const rowExpandedIdx = this.getRowExpandedIdx(row, this.rowExpansions); const expanded = rowExpandedIdx > -1; // If the detailRowHeight is auto --> only in case of non-virtualized scroll if (this.scrollbarV && this.virtualization) { const detailRowHeight = this.getDetailRowHeight(row) * (expanded ? -1 : 1); // const idx = this.rowIndexes.get(row) || 0; const idx = this.getRowIndex(row); this.rowHeightsCache.update(idx, detailRowHeight); } // Update the toggled row and update thive nevere heights in the cache. if (expanded) { this.rowExpansions.splice(rowExpandedIdx, 1); } else { this.rowExpansions.push(row); } this.detailToggle.emit({ rows: [row], currentIndex: viewPortFirstRowIndex }); } /** * Expand/Collapse all the rows no matter what their state is. */ toggleAllRows(expanded) { // clear prev expansions this.rowExpansions = []; // Capture the row index of the first row that is visible on the viewport. const viewPortFirstRowIndex = this.getAdjustedViewPortIndex(); if (expanded) { for (const row of this.rows) { this.rowExpansions.push(row); } } if (this.scrollbarV) { // Refresh the full row heights cache since every row was affected. this.recalcLayout(); } // Emit all rows that have been expanded. this.detailToggle.emit({ rows: this.rows, currentIndex: viewPortFirstRowIndex }); } /** * Recalculates the table */ recalcLayout() { this.refreshRowHeightCache(); this.updateIndexes(); this.updateRows(); } /** * Tracks the column */ columnTrackingFn(index, column) { return column.$$id; } /** * Gets the row pinning group styles */ stylesByGroup(group) { const widths = this.columnGroupWidths; const offsetX = this.offsetX; const styles = { width: `${widths[group]}px` }; if (group === 'left') { translateXY(styles, offsetX, 0); } else if (group === 'right') { const bodyWidth = parseInt(this.innerWidth + '', 0); const totalDiff = widths.total - bodyWidth; const offsetDiff = totalDiff - offsetX; const offset = offsetDiff * -1; translateXY(styles, offset, 0); } return styles; } /** * Returns if the row was expanded and set default row expansion when row expansion is empty */ getRowExpanded(row) { if (this.rowExpansions.length === 0 && this.groupExpansionDefault) { for (const group of this.groupedRows) { this.rowExpansions.push(group); } } return this.getRowExpandedIdx(row, this.rowExpansions) > -1; } getRowExpandedIdx(row, expanded) { if (!expanded || !expanded.length) return -1; const rowId = this.rowIdentity(row); return expanded.findIndex(r => { const id = this.rowIdentity(r); return id === rowId; }); } /** * Gets the row index given a row */ getRowIndex(row) { return this.rowIndexes.get(row) || 0; } onTreeAction(row) { this.treeAction.emit({ row }); } } DataTableBodyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); DataTableBodyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableBodyComponent, selector: "datatable-body", inputs: { scrollbarV: "scrollbarV", scrollbarH: "scrollbarH", loadingIndicator: "loadingIndicator", externalPaging: "externalPaging", rowHeight: "rowHeight", offsetX: "offsetX", emptyMessage: "emptyMessage", selectionType: "selectionType", selected: "selected", rowIdentity: "rowIdentity", rowDetail: "rowDetail", groupHeader: "groupHeader", selectCheck: "selectCheck", displayCheck: "displayCheck", trackByProp: "trackByProp", rowClass: "rowClass", groupedRows: "groupedRows", groupExpansionDefault: "groupExpansionDefault", innerWidth: "innerWidth", groupRowsBy: "groupRowsBy", virtualization: "virtualization", summaryRow: "summaryRow", summaryPosition: "summaryPosition", summaryHeight: "summaryHeight", pageSize: "pageSize", rows: "rows", columns: "columns", offset: "offset", rowCount: "rowCount", bodyHeight: "bodyHeight" }, outputs: { scroll: "scroll", page: "page", activate: "activate", select: "select", detailToggle: "detailToggle", rowContextmenu: "rowContextmenu", treeAction: "treeAction" }, host: { properties: { "style.width": "this.bodyWidth", "style.height": "this.bodyHeight" }, classAttribute: "datatable-body" }, viewQueries: [{ propertyName: "scroller", first: true, predicate: ScrollerComponent, descendants: true }], ngImport: i0, template: `
`, isInline: true, components: [{ type: ProgressBarComponent, selector: "datatable-progress" }, { type: DataTableSelectionComponent, selector: "datatable-selection", inputs: ["rows", "selected", "selectEnabled", "selectionType", "rowIdentity", "selectCheck"], outputs: ["activate", "select"] }, { type: ScrollerComponent, selector: "datatable-scroller", inputs: ["scrollbarV", "scrollbarH", "scrollHeight", "scrollWidth"], outputs: ["scroll"] }, { type: DataTableSummaryRowComponent, selector: "datatable-summary-row", inputs: ["rows", "columns", "rowHeight", "offsetX", "innerWidth"] }, { type: DataTableRowWrapperComponent, selector: "datatable-row-wrapper", inputs: ["innerWidth", "rowDetail", "groupHeader", "offsetX", "detailRowHeight", "row", "groupedRows", "rowIndex", "expanded"], outputs: ["rowContextmenu"] }, { type: DataTableBodyRowComponent, selector: "datatable-body-row", inputs: ["columns", "innerWidth", "expanded", "rowClass", "row", "group", "isSelected", "rowIndex", "displayCheck", "treeStatus", "offsetX", "rowHeight"], outputs: ["activate", "treeAction"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableBodyComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-body', template: `
`, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'datatable-body' } }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { scrollbarV: [{ type: Input }], scrollbarH: [{ type: Input }], loadingIndicator: [{ type: Input }], externalPaging: [{ type: Input }], rowHeight: [{ type: Input }], offsetX: [{ type: Input }], emptyMessage: [{ type: Input }], selectionType: [{ type: Input }], selected: [{ type: Input }], rowIdentity: [{ type: Input }], rowDetail: [{ type: Input }], groupHeader: [{ type: Input }], selectCheck: [{ type: Input }], displayCheck: [{ type: Input }], trackByProp: [{ type: Input }], rowClass: [{ type: Input }], groupedRows: [{ type: Input }], groupExpansionDefault: [{ type: Input }], innerWidth: [{ type: Input }], groupRowsBy: [{ type: Input }], virtualization: [{ type: Input }], summaryRow: [{ type: Input }], summaryPosition: [{ type: Input }], summaryHeight: [{ type: Input }], pageSize: [{ type: Input }], rows: [{ type: Input }], columns: [{ type: Input }], offset: [{ type: Input }], rowCount: [{ type: Input }], bodyWidth: [{ type: HostBinding, args: ['style.width'] }], bodyHeight: [{ type: Input }, { type: HostBinding, args: ['style.height'] }], scroll: [{ type: Output }], page: [{ type: Output }], activate: [{ type: Output }], select: [{ type: Output }], detailToggle: [{ type: Output }], rowContextmenu: [{ type: Output }], treeAction: [{ type: Output }], scroller: [{ type: ViewChild, args: [ScrollerComponent] }] } }); /** * Gets the next sort direction */ function nextSortDir(sortType, current) { if (sortType === SortType.single) { if (current === SortDirection.asc) { return SortDirection.desc; } else { return SortDirection.asc; } } else { if (!current) { return SortDirection.asc; } else if (current === SortDirection.asc) { return SortDirection.desc; } else if (current === SortDirection.desc) { return undefined; } // avoid TS7030: Not all code paths return a value. return undefined; } } /** * Adapted from fueld-ui on 6/216 * https://github.com/FuelInteractive/fuel-ui/tree/master/src/pipes/OrderBy */ function orderByComparator(a, b) { if (a === null || typeof a === 'undefined') a = 0; if (b === null || typeof b === 'undefined') b = 0; if (a instanceof Date && b instanceof Date) { if (a < b) return -1; if (a > b) return 1; } else if (isNaN(parseFloat(a)) || !isFinite(a) || isNaN(parseFloat(b)) || !isFinite(b)) { // Convert to string in case of a=0 or b=0 a = String(a); b = String(b); // Isn't a number so lowercase the string to properly compare if (a.toLowerCase() < b.toLowerCase()) return -1; if (a.toLowerCase() > b.toLowerCase()) return 1; } else { // Parse strings as numbers to compare properly if (parseFloat(a) < parseFloat(b)) return -1; if (parseFloat(a) > parseFloat(b)) return 1; } // equal each other return 0; } /** * creates a shallow copy of the `rows` input and returns the sorted copy. this function * does not sort the `rows` argument in place */ function sortRows(rows, columns, dirs) { if (!rows) return []; if (!dirs || !dirs.length || !columns) return [...rows]; /** * record the row ordering of results from prior sort operations (if applicable) * this is necessary to guarantee stable sorting behavior */ const rowToIndexMap = new Map(); rows.forEach((row, index) => rowToIndexMap.set(row, index)); const temp = [...rows]; const cols = columns.reduce((obj, col) => { if (col.comparator && typeof col.comparator === 'function') { obj[col.prop] = col.comparator; } return obj; }, {}); // cache valueGetter and compareFn so that they // do not need to be looked-up in the sort function body const cachedDirs = dirs.map(dir => { const prop = dir.prop; return { prop, dir: dir.dir, valueGetter: getterForProp(prop), compareFn: cols[prop] || orderByComparator }; }); return temp.sort(function (rowA, rowB) { for (const cachedDir of cachedDirs) { // Get property and valuegetters for column to be sorted const { prop, valueGetter } = cachedDir; // Get A and B cell values from rows based on properties of the columns const propA = valueGetter(rowA, prop); const propB = valueGetter(rowB, prop); // Compare function gets five parameters: // Two cell values to be compared as propA and propB // Two rows corresponding to the cells as rowA and rowB // Direction of the sort for this column as SortDirection // Compare can be a standard JS comparison function (a,b) => -1|0|1 // as additional parameters are silently ignored. The whole row and sort // direction enable more complex sort logic. const comparison = cachedDir.dir !== SortDirection.desc ? cachedDir.compareFn(propA, propB, rowA, rowB, cachedDir.dir) : -cachedDir.compareFn(propA, propB, rowA, rowB, cachedDir.dir); // Don't return 0 yet in case of needing to sort by next property if (comparison !== 0) return comparison; } if (!(rowToIndexMap.has(rowA) && rowToIndexMap.has(rowB))) return 0; /** * all else being equal, preserve original order of the rows (stable sort) */ return rowToIndexMap.get(rowA) < rowToIndexMap.get(rowB) ? -1 : 1; }); } class DataTableHeaderCellComponent { constructor(cd) { this.cd = cd; this.sort = new EventEmitter(); this.select = new EventEmitter(); this.columnContextmenu = new EventEmitter(false); this.sortFn = this.onSort.bind(this); this.selectFn = this.select.emit.bind(this.select); this.cellContext = { column: this.column, sortDir: this.sortDir, sortFn: this.sortFn, allRowsSelected: this.allRowsSelected, selectFn: this.selectFn }; } set allRowsSelected(value) { this._allRowsSelected = value; this.cellContext.allRowsSelected = value; } get allRowsSelected() { return this._allRowsSelected; } set column(column) { this._column = column; this.cellContext.column = column; this.cd.markForCheck(); } get column() { return this._column; } set sorts(val) { this._sorts = val; this.sortDir = this.calcSortDir(val); this.cellContext.sortDir = this.sortDir; this.sortClass = this.calcSortClass(this.sortDir); this.cd.markForCheck(); } get sorts() { return this._sorts; } get columnCssClasses() { let cls = 'datatable-header-cell'; if (this.column.sortable) cls += ' sortable'; if (this.column.resizeable) cls += ' resizeable'; if (this.column.headerClass) { if (typeof this.column.headerClass === 'string') { cls += ' ' + this.column.headerClass; } else if (typeof this.column.headerClass === 'function') { const res = this.column.headerClass({ column: this.column }); if (typeof res === 'string') { cls += res; } else if (typeof res === 'object') { const keys = Object.keys(res); for (const k of keys) { if (res[k] === true) cls += ` ${k}`; } } } } const sortDir = this.sortDir; if (sortDir) { cls += ` sort-active sort-${sortDir}`; } return cls; } get name() { // guaranteed to have a value by setColumnDefaults() in column-helper.ts return this.column.headerTemplate === undefined ? this.column.name : undefined; } get minWidth() { return this.column.minWidth; } get maxWidth() { return this.column.maxWidth; } get width() { return this.column.width; } get isCheckboxable() { return this.column.checkboxable && this.column.headerCheckboxable && this.selectionType === SelectionType.checkbox; } onContextmenu($event) { this.columnContextmenu.emit({ event: $event, column: this.column }); } ngOnInit() { this.sortClass = this.calcSortClass(this.sortDir); } calcSortDir(sorts) { if (sorts && this.column) { const sort = sorts.find((s) => { return s.prop === this.column.prop; }); if (sort) return sort.dir; } } onSort() { if (!this.column.sortable) return; const newValue = nextSortDir(this.sortType, this.sortDir); this.sort.emit({ column: this.column, prevValue: this.sortDir, newValue }); } calcSortClass(sortDir) { if (!this.cellContext.column.sortable) return; if (sortDir === SortDirection.asc) { return `sort-btn sort-asc ${this.sortAscendingIcon}`; } else if (sortDir === SortDirection.desc) { return `sort-btn sort-desc ${this.sortDescendingIcon}`; } else { return `sort-btn ${this.sortUnsetIcon}`; } } } DataTableHeaderCellComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableHeaderCellComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); DataTableHeaderCellComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableHeaderCellComponent, selector: "datatable-header-cell", inputs: { sortType: "sortType", sortAscendingIcon: "sortAscendingIcon", sortDescendingIcon: "sortDescendingIcon", sortUnsetIcon: "sortUnsetIcon", isTarget: "isTarget", targetMarkerTemplate: "targetMarkerTemplate", targetMarkerContext: "targetMarkerContext", allRowsSelected: "allRowsSelected", selectionType: "selectionType", column: "column", headerHeight: "headerHeight", sorts: "sorts" }, outputs: { sort: "sort", select: "select", columnContextmenu: "columnContextmenu" }, host: { listeners: { "contextmenu": "onContextmenu($event)" }, properties: { "style.height.px": "this.headerHeight", "class": "this.columnCssClasses", "attr.title": "this.name", "style.minWidth.px": "this.minWidth", "style.maxWidth.px": "this.maxWidth", "style.width.px": "this.width" }, classAttribute: "datatable-header-cell" }, ngImport: i0, template: `
`, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableHeaderCellComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-header-cell', template: `
`, host: { class: 'datatable-header-cell' }, changeDetection: ChangeDetectionStrategy.OnPush }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { sortType: [{ type: Input }], sortAscendingIcon: [{ type: Input }], sortDescendingIcon: [{ type: Input }], sortUnsetIcon: [{ type: Input }], isTarget: [{ type: Input }], targetMarkerTemplate: [{ type: Input }], targetMarkerContext: [{ type: Input }], allRowsSelected: [{ type: Input }], selectionType: [{ type: Input }], column: [{ type: Input }], headerHeight: [{ type: HostBinding, args: ['style.height.px'] }, { type: Input }], sorts: [{ type: Input }], sort: [{ type: Output }], select: [{ type: Output }], columnContextmenu: [{ type: Output }], columnCssClasses: [{ type: HostBinding, args: ['class'] }], name: [{ type: HostBinding, args: ['attr.title'] }], minWidth: [{ type: HostBinding, args: ['style.minWidth.px'] }], maxWidth: [{ type: HostBinding, args: ['style.maxWidth.px'] }], width: [{ type: HostBinding, args: ['style.width.px'] }], onContextmenu: [{ type: HostListener, args: ['contextmenu', ['$event']] }] } }); class DataTableHeaderComponent { constructor(cd) { this.cd = cd; this.sort = new EventEmitter(); this.reorder = new EventEmitter(); this.resize = new EventEmitter(); this.select = new EventEmitter(); this.columnContextmenu = new EventEmitter(false); this._columnGroupWidths = { total: 100 }; this._styleByGroup = { left: {}, center: {}, right: {} }; this.destroyed = false; } set innerWidth(val) { this._innerWidth = val; setTimeout(() => { if (this._columns) { const colByPin = columnsByPin(this._columns); this._columnGroupWidths = columnGroupWidths(colByPin, this._columns); this.setStylesByGroup(); } }); } get innerWidth() { return this._innerWidth; } set headerHeight(val) { if (val !== 'auto') { this._headerHeight = `${val}px`; } else { this._headerHeight = val; } } get headerHeight() { return this._headerHeight; } set columns(val) { this._columns = val; const colsByPin = columnsByPin(val); this._columnsByPin = columnsByPinArr(val); setTimeout(() => { this._columnGroupWidths = columnGroupWidths(colsByPin, val); this.setStylesByGroup(); }); } get columns() { return this._columns; } set offsetX(val) { this._offsetX = val; this.setStylesByGroup(); } get offsetX() { return this._offsetX; } ngOnDestroy() { this.destroyed = true; } onLongPressStart({ event, model }) { model.dragging = true; this.dragEventTarget = event; } onLongPressEnd({ event, model }) { this.dragEventTarget = event; // delay resetting so sort can be // prevented if we were dragging setTimeout(() => { // datatable component creates copies from columns on reorder // set dragging to false on new objects const column = this._columns.find(c => c.$$id === model.$$id); if (column) { column.dragging = false; } }, 5); } get headerWidth() { if (this.scrollbarH) { return this.innerWidth + 'px'; } return '100%'; } trackByGroups(index, colGroup) { return colGroup.type; } columnTrackingFn(index, column) { return column.$$id; } onColumnResized(width, column) { if (width <= column.minWidth) { width = column.minWidth; } else if (width >= column.maxWidth) { width = column.maxWidth; } this.resize.emit({ column, prevValue: column.width, newValue: width }); } onColumnReordered({ prevIndex, newIndex, model }) { const column = this.getColumn(newIndex); column.isTarget = false; column.targetMarkerContext = undefined; this.reorder.emit({ column: model, prevValue: prevIndex, newValue: newIndex }); } onTargetChanged({ prevIndex, newIndex, initialIndex }) { if (prevIndex || prevIndex === 0) { const oldColumn = this.getColumn(prevIndex); oldColumn.isTarget = false; oldColumn.targetMarkerContext = undefined; } if (newIndex || newIndex === 0) { const newColumn = this.getColumn(newIndex); newColumn.isTarget = true; if (initialIndex !== newIndex) { newColumn.targetMarkerContext = { class: 'targetMarker '.concat(initialIndex > newIndex ? 'dragFromRight' : 'dragFromLeft') }; } } } getColumn(index) { const leftColumnCount = this._columnsByPin[0].columns.length; if (index < leftColumnCount) { return this._columnsByPin[0].columns[index]; } const centerColumnCount = this._columnsByPin[1].columns.length; if (index < leftColumnCount + centerColumnCount) { return this._columnsByPin[1].columns[index - leftColumnCount]; } return this._columnsByPin[2].columns[index - leftColumnCount - centerColumnCount]; } onSort({ column, prevValue, newValue }) { // if we are dragging don't sort! if (column.dragging) { return; } const sorts = this.calcNewSorts(column, prevValue, newValue); this.sort.emit({ sorts, column, prevValue, newValue }); } calcNewSorts(column, prevValue, newValue) { let idx = 0; if (!this.sorts) { this.sorts = []; } const sorts = this.sorts.map((s, i) => { s = { ...s }; if (s.prop === column.prop) { idx = i; } return s; }); if (newValue === undefined) { sorts.splice(idx, 1); } else if (prevValue) { sorts[idx].dir = newValue; } else { if (this.sortType === SortType.single) { sorts.splice(0, this.sorts.length); } sorts.push({ dir: newValue, prop: column.prop }); } return sorts; } setStylesByGroup() { this._styleByGroup.left = this.calcStylesByGroup('left'); this._styleByGroup.center = this.calcStylesByGroup('center'); this._styleByGroup.right = this.calcStylesByGroup('right'); if (!this.destroyed) { this.cd.detectChanges(); } } calcStylesByGroup(group) { const widths = this._columnGroupWidths; const offsetX = this.offsetX; const styles = { width: `${widths[group]}px` }; if (group === 'center') { translateXY(styles, offsetX * -1, 0); } else if (group === 'right') { const totalDiff = widths.total - this.innerWidth; const offset = totalDiff * -1; translateXY(styles, offset, 0); } return styles; } } DataTableHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableHeaderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); DataTableHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableHeaderComponent, selector: "datatable-header", inputs: { sortAscendingIcon: "sortAscendingIcon", sortDescendingIcon: "sortDescendingIcon", sortUnsetIcon: "sortUnsetIcon", scrollbarH: "scrollbarH", dealsWithGroup: "dealsWithGroup", targetMarkerTemplate: "targetMarkerTemplate", innerWidth: "innerWidth", sorts: "sorts", sortType: "sortType", allRowsSelected: "allRowsSelected", selectionType: "selectionType", reorderable: "reorderable", headerHeight: "headerHeight", columns: "columns", offsetX: "offsetX" }, outputs: { sort: "sort", reorder: "reorder", resize: "resize", select: "select", columnContextmenu: "columnContextmenu" }, host: { properties: { "style.height": "this.headerHeight", "style.width": "this.headerWidth" }, classAttribute: "datatable-header" }, ngImport: i0, template: `
`, isInline: true, components: [{ type: DataTableHeaderCellComponent, selector: "datatable-header-cell", inputs: ["sortType", "sortAscendingIcon", "sortDescendingIcon", "sortUnsetIcon", "isTarget", "targetMarkerTemplate", "targetMarkerContext", "allRowsSelected", "selectionType", "column", "headerHeight", "sorts"], outputs: ["sort", "select", "columnContextmenu"] }], directives: [{ type: OrderableDirective, selector: "[orderable]", outputs: ["reorder", "targetChanged"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: ResizeableDirective, selector: "[resizeable]", inputs: ["resizeEnabled", "minWidth", "maxWidth"], outputs: ["resize"] }, { type: LongPressDirective, selector: "[long-press]", inputs: ["pressEnabled", "pressModel", "duration"], outputs: ["longPressStart", "longPressing", "longPressEnd"] }, { type: DraggableDirective, selector: "[draggable]", inputs: ["dragEventTarget", "dragModel", "dragX", "dragY"], outputs: ["dragStart", "dragging", "dragEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableHeaderComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-header', template: `
`, host: { class: 'datatable-header' }, changeDetection: ChangeDetectionStrategy.OnPush }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { sortAscendingIcon: [{ type: Input }], sortDescendingIcon: [{ type: Input }], sortUnsetIcon: [{ type: Input }], scrollbarH: [{ type: Input }], dealsWithGroup: [{ type: Input }], targetMarkerTemplate: [{ type: Input }], innerWidth: [{ type: Input }], sorts: [{ type: Input }], sortType: [{ type: Input }], allRowsSelected: [{ type: Input }], selectionType: [{ type: Input }], reorderable: [{ type: Input }], headerHeight: [{ type: HostBinding, args: ['style.height'] }, { type: Input }], columns: [{ type: Input }], offsetX: [{ type: Input }], sort: [{ type: Output }], reorder: [{ type: Output }], resize: [{ type: Output }], select: [{ type: Output }], columnContextmenu: [{ type: Output }], headerWidth: [{ type: HostBinding, args: ['style.width'] }] } }); /** * Throttle a function */ function throttle(func, wait, options) { options = options || {}; let context; let args; let result; let timeout = null; let previous = 0; function later() { previous = options.leading === false ? 0 : +new Date(); timeout = null; result = func.apply(context, args); } return function () { const now = +new Date(); if (!previous && options.leading === false) { previous = now; } const remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; } /** * Throttle decorator * * class MyClass { * throttleable(10) * myFn() { ... } * } */ function throttleable(duration, options) { return function innerDecorator(target, key, descriptor) { return { configurable: true, enumerable: descriptor.enumerable, get: function getter() { Object.defineProperty(this, key, { configurable: true, enumerable: descriptor.enumerable, value: throttle(descriptor.value, duration, options) }); return this[key]; } }; }; } /** * Calculates the Total Flex Grow */ function getTotalFlexGrow(columns) { let totalFlexGrow = 0; for (const c of columns) { totalFlexGrow += c.flexGrow || 0; } return totalFlexGrow; } /** * Adjusts the column widths. * Inspired by: https://github.com/facebook/fixed-data-table/blob/master/src/FixedDataTableWidthHelper.js */ function adjustColumnWidths(allColumns, expectedWidth) { const columnsWidth = columnsTotalWidth(allColumns); const totalFlexGrow = getTotalFlexGrow(allColumns); const colsByGroup = columnsByPin(allColumns); if (columnsWidth !== expectedWidth) { scaleColumns(colsByGroup, expectedWidth, totalFlexGrow); } } /** * Resizes columns based on the flexGrow property, while respecting manually set widths */ function scaleColumns(colsByGroup, maxWidth, totalFlexGrow) { // calculate total width and flexgrow points for coulumns that can be resized for (const attr in colsByGroup) { for (const column of colsByGroup[attr]) { if (!column.canAutoResize) { maxWidth -= column.width; totalFlexGrow -= column.flexGrow ? column.flexGrow : 0; } else { column.width = 0; } } } const hasMinWidth = {}; let remainingWidth = maxWidth; // resize columns until no width is left to be distributed do { const widthPerFlexPoint = remainingWidth / totalFlexGrow; remainingWidth = 0; for (const attr in colsByGroup) { for (const column of colsByGroup[attr]) { // if the column can be resize and it hasn't reached its minimum width yet if (column.canAutoResize && !hasMinWidth[column.prop]) { const newWidth = column.width + column.flexGrow * widthPerFlexPoint; if (column.minWidth !== undefined && newWidth < column.minWidth) { remainingWidth += newWidth - column.minWidth; column.width = column.minWidth; hasMinWidth[column.prop] = true; } else { column.width = newWidth; } } } } } while (remainingWidth !== 0); } /** * Forces the width of the columns to * distribute equally but overflowing when necessary * * Rules: * * - If combined withs are less than the total width of the grid, * proportion the widths given the min / max / normal widths to fill the width. * * - If the combined widths, exceed the total width of the grid, * use the standard widths. * * - If a column is resized, it should always use that width * * - The proportional widths should never fall below min size if specified. * * - If the grid starts off small but then becomes greater than the size ( + / - ) * the width should use the original width; not the newly proportioned widths. */ function forceFillColumnWidths(allColumns, expectedWidth, startIdx, allowBleed, defaultColWidth = 300) { const columnsToResize = allColumns.slice(startIdx + 1, allColumns.length).filter(c => { return c.canAutoResize !== false; }); for (const column of columnsToResize) { if (!column.$$oldWidth) { column.$$oldWidth = column.width; } } let additionWidthPerColumn = 0; let exceedsWindow = false; let contentWidth = getContentWidth(allColumns, defaultColWidth); let remainingWidth = expectedWidth - contentWidth; const columnsProcessed = []; const remainingWidthLimit = 1; // when to stop // This loop takes care of the do { additionWidthPerColumn = remainingWidth / columnsToResize.length; exceedsWindow = contentWidth >= expectedWidth; for (const column of columnsToResize) { if (exceedsWindow && allowBleed) { column.width = column.$$oldWidth || column.width || defaultColWidth; } else { const newSize = (column.width || defaultColWidth) + additionWidthPerColumn; if (column.minWidth && newSize < column.minWidth) { column.width = column.minWidth; columnsProcessed.push(column); } else if (column.maxWidth && newSize > column.maxWidth) { column.width = column.maxWidth; columnsProcessed.push(column); } else { column.width = newSize; } } column.width = Math.max(0, column.width); } contentWidth = getContentWidth(allColumns); remainingWidth = expectedWidth - contentWidth; removeProcessedColumns(columnsToResize, columnsProcessed); } while (remainingWidth > remainingWidthLimit && columnsToResize.length !== 0); } /** * Remove the processed columns from the current active columns. */ function removeProcessedColumns(columnsToResize, columnsProcessed) { for (const column of columnsProcessed) { const index = columnsToResize.indexOf(column); columnsToResize.splice(index, 1); } } /** * Gets the width of the columns */ function getContentWidth(allColumns, defaultColWidth = 300) { let contentWidth = 0; for (const column of allColumns) { contentWidth += column.width || defaultColWidth; } return contentWidth; } class DataTablePagerComponent { constructor() { this.change = new EventEmitter(); this._count = 0; this._page = 1; this._size = 0; } set size(val) { this._size = val; this.pages = this.calcPages(); } get size() { return this._size; } set count(val) { this._count = val; this.pages = this.calcPages(); } get count() { return this._count; } set page(val) { this._page = val; this.pages = this.calcPages(); } get page() { return this._page; } get totalPages() { const count = this.size < 1 ? 1 : Math.ceil(this.count / this.size); return Math.max(count || 0, 1); } canPrevious() { return this.page > 1; } canNext() { return this.page < this.totalPages; } prevPage() { this.selectPage(this.page - 1); } nextPage() { this.selectPage(this.page + 1); } selectPage(page) { if (page > 0 && page <= this.totalPages && page !== this.page) { this.page = page; this.change.emit({ page }); } } calcPages(page) { const pages = []; let startPage = 1; let endPage = this.totalPages; const maxSize = 5; const isMaxSized = maxSize < this.totalPages; page = page || this.page; if (isMaxSized) { startPage = page - Math.floor(maxSize / 2); endPage = page + Math.floor(maxSize / 2); if (startPage < 1) { startPage = 1; endPage = Math.min(startPage + maxSize - 1, this.totalPages); } else if (endPage > this.totalPages) { startPage = Math.max(this.totalPages - maxSize + 1, 1); endPage = this.totalPages; } } for (let num = startPage; num <= endPage; num++) { pages.push({ number: num, text: num }); } return pages; } } DataTablePagerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTablePagerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); DataTablePagerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTablePagerComponent, selector: "datatable-pager", inputs: { pagerLeftArrowIcon: "pagerLeftArrowIcon", pagerRightArrowIcon: "pagerRightArrowIcon", pagerPreviousIcon: "pagerPreviousIcon", pagerNextIcon: "pagerNextIcon", size: "size", count: "count", page: "page" }, outputs: { change: "change" }, host: { classAttribute: "datatable-pager" }, ngImport: i0, template: ` `, isInline: true, directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTablePagerComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-pager', template: ` `, host: { class: 'datatable-pager' }, changeDetection: ChangeDetectionStrategy.OnPush }] }], propDecorators: { pagerLeftArrowIcon: [{ type: Input }], pagerRightArrowIcon: [{ type: Input }], pagerPreviousIcon: [{ type: Input }], pagerNextIcon: [{ type: Input }], size: [{ type: Input }], count: [{ type: Input }], page: [{ type: Input }], change: [{ type: Output }] } }); class DataTableFooterComponent { constructor() { this.selectedCount = 0; this.page = new EventEmitter(); } get isVisible() { return this.rowCount / this.pageSize > 1; } get curPage() { return this.offset + 1; } } DataTableFooterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); DataTableFooterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DataTableFooterComponent, selector: "datatable-footer", inputs: { footerHeight: "footerHeight", rowCount: "rowCount", pageSize: "pageSize", offset: "offset", pagerLeftArrowIcon: "pagerLeftArrowIcon", pagerRightArrowIcon: "pagerRightArrowIcon", pagerPreviousIcon: "pagerPreviousIcon", pagerNextIcon: "pagerNextIcon", totalMessage: "totalMessage", footerTemplate: "footerTemplate", selectedCount: "selectedCount", selectedMessage: "selectedMessage" }, outputs: { page: "page" }, host: { classAttribute: "datatable-footer" }, ngImport: i0, template: ` `, isInline: true, components: [{ type: DataTablePagerComponent, selector: "datatable-pager", inputs: ["pagerLeftArrowIcon", "pagerRightArrowIcon", "pagerPreviousIcon", "pagerNextIcon", "size", "count", "page"], outputs: ["change"] }], directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DataTableFooterComponent, decorators: [{ type: Component, args: [{ selector: 'datatable-footer', template: ` `, host: { class: 'datatable-footer' }, changeDetection: ChangeDetectionStrategy.OnPush }] }], propDecorators: { footerHeight: [{ type: Input }], rowCount: [{ type: Input }], pageSize: [{ type: Input }], offset: [{ type: Input }], pagerLeftArrowIcon: [{ type: Input }], pagerRightArrowIcon: [{ type: Input }], pagerPreviousIcon: [{ type: Input }], pagerNextIcon: [{ type: Input }], totalMessage: [{ type: Input }], footerTemplate: [{ type: Input }], selectedCount: [{ type: Input }], selectedMessage: [{ type: Input }], page: [{ type: Output }] } }); class DatatableComponent { constructor(scrollbarHelper, dimensionsHelper, cd, element, differs, columnChangesService, configuration) { this.scrollbarHelper = scrollbarHelper; this.dimensionsHelper = dimensionsHelper; this.cd = cd; this.columnChangesService = columnChangesService; this.configuration = configuration; /** * List of row objects that should be * represented as selected in the grid. * Default value: `[]` */ this.selected = []; /** * Enable vertical scrollbars */ this.scrollbarV = false; /** * Enable horz scrollbars */ this.scrollbarH = false; /** * The row height; which is necessary * to calculate the height for the lazy rendering. */ this.rowHeight = 30; /** * Type of column width distribution formula. * Example: flex, force, standard */ this.columnMode = ColumnMode.standard; /** * The minimum header height in pixels. * Pass a falsey for no header */ this.headerHeight = 30; /** * The minimum footer height in pixels. * Pass falsey for no footer */ this.footerHeight = 0; /** * If the table should use external paging * otherwise its assumed that all data is preloaded. */ this.externalPaging = false; /** * If the table should use external sorting or * the built-in basic sorting. */ this.externalSorting = false; /** * Show the linear loading bar. * Default value: `false` */ this.loadingIndicator = false; /** * Enable/Disable ability to re-order columns * by dragging them. */ this.reorderable = true; /** * Swap columns on re-order columns or * move them. */ this.swapColumns = true; /** * The type of sorting */ this.sortType = SortType.single; /** * Array of sorted columns by property and type. * Default value: `[]` */ this.sorts = []; /** * Css class overrides */ this.cssClasses = { sortAscending: 'datatable-icon-up', sortDescending: 'datatable-icon-down', sortUnset: 'datatable-icon-sort-unset', pagerLeftArrow: 'datatable-icon-left', pagerRightArrow: 'datatable-icon-right', pagerPrevious: 'datatable-icon-prev', pagerNext: 'datatable-icon-skip' }; /** * Message overrides for localization * * emptyMessage [default] = 'No data to display' * totalMessage [default] = 'total' * selectedMessage [default] = 'selected' */ this.messages = { // Message to show when array is presented // but contains no values emptyMessage: 'No data to display', // Footer total message totalMessage: 'total', // Footer selected message selectedMessage: 'selected' }; /** * A boolean you can use to set the detault behaviour of rows and groups * whether they will start expanded or not. If ommited the default is NOT expanded. * */ this.groupExpansionDefault = false; /** * Property to which you can use for determining select all * rows on current page or not. * * @memberOf DatatableComponent */ this.selectAllRowsOnPage = false; /** * A flag for row virtualization on / off */ this.virtualization = true; /** * A flag for switching summary row on / off */ this.summaryRow = false; /** * A height of summary row */ this.summaryHeight = 30; /** * A property holds a summary row position: top/bottom */ this.summaryPosition = 'top'; /** * Body was scrolled typically in a `scrollbarV:true` scenario. */ this.scroll = new EventEmitter(); /** * A cell or row was focused via keyboard or mouse click. */ this.activate = new EventEmitter(); /** * A cell or row was selected. */ this.select = new EventEmitter(); /** * Column sort was invoked. */ this.sort = new EventEmitter(); /** * The table was paged either triggered by the pager or the body scroll. */ this.page = new EventEmitter(); /** * Columns were re-ordered. */ this.reorder = new EventEmitter(); /** * Column was resized. */ this.resize = new EventEmitter(); /** * The context menu was invoked on the table. * type indicates whether the header or the body was clicked. * content contains either the column or the row that was clicked. */ this.tableContextmenu = new EventEmitter(false); /** * A row was expanded ot collapsed for tree */ this.treeAction = new EventEmitter(); this.rowCount = 0; this._offsetX = new BehaviorSubject(0); this._count = 0; this._offset = 0; this._subscriptions = []; /** * This will be used when displaying or selecting rows. * when tracking/comparing them, we'll use the value of this fn, * * (`fn(x) === fn(y)` instead of `x === y`) */ this.rowIdentity = (x) => { if (this._groupRowsBy) { // each group in groupedRows are stored as {key, value: [rows]}, // where key is the groupRowsBy index return x.key; } else { return x; } }; // get ref to elm for measuring this.element = element.nativeElement; this.rowDiffer = differs.find({}).create(); // apply global settings from Module.forRoot if (this.configuration && this.configuration.messages) { this.messages = { ...this.configuration.messages }; } } /** * Rows that are displayed in the table. */ set rows(val) { this._rows = val; if (val) { this._internalRows = [...val]; } // auto sort on new updates if (!this.externalSorting) { this.sortInternalRows(); } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); // recalculate sizes/etc this.recalculate(); if (this._rows && this._groupRowsBy) { // If a column has been specified in _groupRowsBy created a new array with the data grouped by that row this.groupedRows = this.groupArrayBy(this._rows, this._groupRowsBy); } this.cd.markForCheck(); } /** * Gets the rows. */ get rows() { return this._rows; } /** * This attribute allows the user to set the name of the column to group the data with */ set groupRowsBy(val) { if (val) { this._groupRowsBy = val; if (this._rows && this._groupRowsBy) { // cretes a new array with the data grouped this.groupedRows = this.groupArrayBy(this._rows, this._groupRowsBy); } } } get groupRowsBy() { return this._groupRowsBy; } /** * Columns to be displayed. */ set columns(val) { if (val) { this._internalColumns = [...val]; setColumnDefaults(this._internalColumns); this.recalculateColumns(); } this._columns = val; } /** * Get the columns. */ get columns() { return this._columns; } /** * The page size to be shown. * Default value: `undefined` */ set limit(val) { this._limit = val; // recalculate sizes/etc this.recalculate(); } /** * Gets the limit. */ get limit() { return this._limit; } /** * The total count of all rows. * Default value: `0` */ set count(val) { this._count = val; // recalculate sizes/etc this.recalculate(); } /** * Gets the count. */ get count() { return this._count; } /** * The current offset ( page - 1 ) shown. * Default value: `0` */ set offset(val) { this._offset = val; } get offset() { return Math.max(Math.min(this._offset, Math.ceil(this.rowCount / this.pageSize) - 1), 0); } /** * CSS class applied if the header height if fixed height. */ get isFixedHeader() { const headerHeight = this.headerHeight; return typeof headerHeight === 'string' ? headerHeight !== 'auto' : true; } /** * CSS class applied to the root element if * the row heights are fixed heights. */ get isFixedRow() { return this.rowHeight !== 'auto'; } /** * CSS class applied to root element if * vertical scrolling is enabled. */ get isVertScroll() { return this.scrollbarV; } /** * CSS class applied to root element if * virtualization is enabled. */ get isVirtualized() { return this.virtualization; } /** * CSS class applied to the root element * if the horziontal scrolling is enabled. */ get isHorScroll() { return this.scrollbarH; } /** * CSS class applied to root element is selectable. */ get isSelectable() { return this.selectionType !== undefined; } /** * CSS class applied to root is checkbox selection. */ get isCheckboxSelection() { return this.selectionType === SelectionType.checkbox; } /** * CSS class applied to root if cell selection. */ get isCellSelection() { return this.selectionType === SelectionType.cell; } /** * CSS class applied to root if single select. */ get isSingleSelection() { return this.selectionType === SelectionType.single; } /** * CSS class added to root element if mulit select */ get isMultiSelection() { return this.selectionType === SelectionType.multi; } /** * CSS class added to root element if mulit click select */ get isMultiClickSelection() { return this.selectionType === SelectionType.multiClick; } /** * Column templates gathered from `ContentChildren` * if described in your markup. */ set columnTemplates(val) { this._columnTemplates = val; this.translateColumns(val); } /** * Returns the column templates. */ get columnTemplates() { return this._columnTemplates; } /** * Returns if all rows are selected. */ get allRowsSelected() { let allRowsSelected = this.rows && this.selected && this.selected.length === this.rows.length; if (this.bodyComponent && this.selectAllRowsOnPage) { const indexes = this.bodyComponent.indexes; const rowsOnPage = indexes.last - indexes.first; allRowsSelected = this.selected.length === rowsOnPage; } return this.selected && this.rows && this.rows.length !== 0 && allRowsSelected; } /** * Lifecycle hook that is called after data-bound * properties of a directive are initialized. */ ngOnInit() { // need to call this immediatly to size // if the table is hidden the visibility // listener will invoke this itself upon show this.recalculate(); } /** * Lifecycle hook that is called after a component's * view has been fully initialized. */ ngAfterViewInit() { if (!this.externalSorting) { this.sortInternalRows(); } // this has to be done to prevent the change detection // tree from freaking out because we are readjusting if (typeof requestAnimationFrame === 'undefined') { return; } requestAnimationFrame(() => { this.recalculate(); // emit page for virtual server-side kickoff if (this.externalPaging && this.scrollbarV) { this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: 0 }); } }); } /** * Lifecycle hook that is called after a component's * content has been fully initialized. */ ngAfterContentInit() { this.columnTemplates.changes.subscribe(v => this.translateColumns(v)); this.listenForColumnInputChanges(); } /** * Translates the templates to the column objects */ translateColumns(val) { if (val) { const arr = val.toArray(); if (arr.length) { this._internalColumns = translateTemplates(arr); setColumnDefaults(this._internalColumns); this.recalculateColumns(); this.sortInternalRows(); this.cd.markForCheck(); } } } /** * Creates a map with the data grouped by the user choice of grouping index * * @param originalArray the original array passed via parameter * @param groupByIndex the index of the column to group the data by */ groupArrayBy(originalArray, groupBy) { // create a map to hold groups with their corresponding results const map = new Map(); let i = 0; originalArray.forEach((item) => { const key = item[groupBy]; if (!map.has(key)) { map.set(key, [item]); } else { map.get(key).push(item); } i++; }); const addGroup = (key, value) => { return { key, value }; }; // convert map back to a simple array of objects return Array.from(map, x => addGroup(x[0], x[1])); } /* * Lifecycle hook that is called when Angular dirty checks a directive. */ ngDoCheck() { if (this.rowDiffer.diff(this.rows)) { if (!this.externalSorting) { this.sortInternalRows(); } else { this._internalRows = [...this.rows]; } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); this.recalculatePages(); this.cd.markForCheck(); } } /** * Recalc's the sizes of the grid. * * Updated automatically on changes to: * * - Columns * - Rows * - Paging related * * Also can be manually invoked or upon window resize. */ recalculate() { this.recalculateDims(); this.recalculateColumns(); this.cd.markForCheck(); } /** * Window resize handler to update sizes. */ onWindowResize() { this.recalculate(); } /** * Recalulcates the column widths based on column width * distribution mode and scrollbar offsets. */ recalculateColumns(columns = this._internalColumns, forceIdx = -1, allowBleed = this.scrollbarH) { if (!columns) return undefined; let width = this._innerWidth; if (this.scrollbarV) { width = width - this.scrollbarHelper.width; } if (this.columnMode === ColumnMode.force) { forceFillColumnWidths(columns, width, forceIdx, allowBleed); } else if (this.columnMode === ColumnMode.flex) { adjustColumnWidths(columns, width); } return columns; } /** * Recalculates the dimensions of the table size. * Internally calls the page size and row count calcs too. * */ recalculateDims() { const dims = this.dimensionsHelper.getDimensions(this.element); this._innerWidth = Math.floor(dims.width); if (this.scrollbarV) { let height = dims.height; if (this.headerHeight) height = height - this.headerHeight; if (this.footerHeight) height = height - this.footerHeight; this.bodyHeight = height; } this.recalculatePages(); } /** * Recalculates the pages after a update. */ recalculatePages() { this.pageSize = this.calcPageSize(); this.rowCount = this.calcRowCount(); } /** * Body triggered a page event. */ onBodyPage({ offset }) { // Avoid pagination caming from body events like scroll when the table // has no virtualization and the external paging is enable. // This means, let's the developer handle pagination by my him(her) self if (this.externalPaging && !this.virtualization) { return; } this.offset = offset; this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: this.offset }); } /** * The body triggered a scroll event. */ onBodyScroll(event) { this._offsetX.next(event.offsetX); this.scroll.emit(event); this.cd.detectChanges(); } /** * The footer triggered a page event. */ onFooterPage(event) { this.offset = event.page - 1; this.bodyComponent.updateOffsetY(this.offset); this.page.emit({ count: this.count, pageSize: this.pageSize, limit: this.limit, offset: this.offset }); if (this.selectAllRowsOnPage) { this.selected = []; this.select.emit({ selected: this.selected }); } } /** * Recalculates the sizes of the page */ calcPageSize(val = this.rows) { // Keep the page size constant even if the row has been expanded. // This is because an expanded row is still considered to be a child of // the original row. Hence calculation would use rowHeight only. if (this.scrollbarV && this.virtualization) { const size = Math.ceil(this.bodyHeight / this.rowHeight); return Math.max(size, 0); } // if limit is passed, we are paging if (this.limit !== undefined) { return this.limit; } // otherwise use row length if (val) { return val.length; } // other empty :( return 0; } /** * Calculates the row count. */ calcRowCount(val = this.rows) { if (!this.externalPaging) { if (!val) return 0; if (this.groupedRows) { return this.groupedRows.length; } else if (this.treeFromRelation != null && this.treeToRelation != null) { return this._internalRows.length; } else { return val.length; } } return this.count; } /** * The header triggered a contextmenu event. */ onColumnContextmenu({ event, column }) { this.tableContextmenu.emit({ event, type: ContextmenuType.header, content: column }); } /** * The body triggered a contextmenu event. */ onRowContextmenu({ event, row }) { this.tableContextmenu.emit({ event, type: ContextmenuType.body, content: row }); } /** * The header triggered a column resize event. */ onColumnResize({ column, newValue }) { /* Safari/iOS 10.2 workaround */ if (column === undefined) { return; } let idx; const cols = this._internalColumns.map((c, i) => { c = { ...c }; if (c.$$id === column.$$id) { idx = i; c.width = newValue; // set this so we can force the column // width distribution to be to this value c.$$oldWidth = newValue; } return c; }); this.recalculateColumns(cols, idx); this._internalColumns = cols; this.resize.emit({ column, newValue }); } /** * The header triggered a column re-order event. */ onColumnReorder({ column, newValue, prevValue }) { const cols = this._internalColumns.map(c => { return { ...c }; }); if (this.swapColumns) { const prevCol = cols[newValue]; cols[newValue] = column; cols[prevValue] = prevCol; } else { if (newValue > prevValue) { const movedCol = cols[prevValue]; for (let i = prevValue; i < newValue; i++) { cols[i] = cols[i + 1]; } cols[newValue] = movedCol; } else { const movedCol = cols[prevValue]; for (let i = prevValue; i > newValue; i--) { cols[i] = cols[i - 1]; } cols[newValue] = movedCol; } } this._internalColumns = cols; this.reorder.emit({ column, newValue, prevValue }); } /** * The header triggered a column sort event. */ onColumnSort(event) { // clean selected rows if (this.selectAllRowsOnPage) { this.selected = []; this.select.emit({ selected: this.selected }); } this.sorts = event.sorts; // this could be optimized better since it will resort // the rows again on the 'push' detection... if (this.externalSorting === false) { // don't use normal setter so we don't resort this.sortInternalRows(); } // auto group by parent on new update this._internalRows = groupRowsByParents(this._internalRows, optionalGetterForProp(this.treeFromRelation), optionalGetterForProp(this.treeToRelation)); // Always go to first page when sorting to see the newly sorted data this.offset = 0; this.bodyComponent.updateOffsetY(this.offset); this.sort.emit(event); } /** * Toggle all row selection */ onHeaderSelect(event) { if (this.bodyComponent && this.selectAllRowsOnPage) { // before we splice, chk if we currently have all selected const first = this.bodyComponent.indexes.first; const last = this.bodyComponent.indexes.last; const allSelected = this.selected.length === last - first; // remove all existing either way this.selected = []; // do the opposite here if (!allSelected) { this.selected.push(...this._internalRows.slice(first, last)); } } else { // before we splice, chk if we currently have all selected const allSelected = this.selected.length === this.rows.length; // remove all existing either way this.selected = []; // do the opposite here if (!allSelected) { this.selected.push(...this.rows); } } this.select.emit({ selected: this.selected }); } /** * A row was selected from body */ onBodySelect(event) { this.select.emit(event); } /** * A row was expanded or collapsed for tree */ onTreeAction(event) { const row = event.row; // TODO: For duplicated items this will not work const rowIndex = this._rows.findIndex(r => r[this.treeToRelation] === event.row[this.treeToRelation]); this.treeAction.emit({ row, rowIndex }); } ngOnDestroy() { this._subscriptions.forEach(subscription => subscription.unsubscribe()); } /** * listen for changes to input bindings of all DataTableColumnDirective and * trigger the columnTemplates.changes observable to emit */ listenForColumnInputChanges() { this._subscriptions.push(this.columnChangesService.columnInputChanges$.subscribe(() => { if (this.columnTemplates) { this.columnTemplates.notifyOnChanges(); } })); } sortInternalRows() { this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts); } } DatatableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableComponent, deps: [{ token: ScrollbarHelper, skipSelf: true }, { token: DimensionsHelper, skipSelf: true }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.KeyValueDiffers }, { token: ColumnChangesService }, { token: 'configuration', optional: true }], target: i0.ɵɵFactoryTarget.Component }); DatatableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: DatatableComponent, selector: "ngx-datatable", inputs: { targetMarkerTemplate: "targetMarkerTemplate", rows: "rows", groupRowsBy: "groupRowsBy", groupedRows: "groupedRows", columns: "columns", selected: "selected", scrollbarV: "scrollbarV", scrollbarH: "scrollbarH", rowHeight: "rowHeight", columnMode: "columnMode", headerHeight: "headerHeight", footerHeight: "footerHeight", externalPaging: "externalPaging", externalSorting: "externalSorting", limit: "limit", count: "count", offset: "offset", loadingIndicator: "loadingIndicator", selectionType: "selectionType", reorderable: "reorderable", swapColumns: "swapColumns", sortType: "sortType", sorts: "sorts", cssClasses: "cssClasses", messages: "messages", rowClass: "rowClass", selectCheck: "selectCheck", displayCheck: "displayCheck", groupExpansionDefault: "groupExpansionDefault", trackByProp: "trackByProp", selectAllRowsOnPage: "selectAllRowsOnPage", virtualization: "virtualization", treeFromRelation: "treeFromRelation", treeToRelation: "treeToRelation", summaryRow: "summaryRow", summaryHeight: "summaryHeight", summaryPosition: "summaryPosition", rowIdentity: "rowIdentity" }, outputs: { scroll: "scroll", activate: "activate", select: "select", sort: "sort", page: "page", reorder: "reorder", resize: "resize", tableContextmenu: "tableContextmenu", treeAction: "treeAction" }, host: { listeners: { "window:resize": "onWindowResize()" }, properties: { "class.fixed-header": "this.isFixedHeader", "class.fixed-row": "this.isFixedRow", "class.scroll-vertical": "this.isVertScroll", "class.virtualized": "this.isVirtualized", "class.scroll-horz": "this.isHorScroll", "class.selectable": "this.isSelectable", "class.checkbox-selection": "this.isCheckboxSelection", "class.cell-selection": "this.isCellSelection", "class.single-selection": "this.isSingleSelection", "class.multi-selection": "this.isMultiSelection", "class.multi-click-selection": "this.isMultiClickSelection" }, classAttribute: "ngx-datatable" }, queries: [{ propertyName: "rowDetail", first: true, predicate: DatatableRowDetailDirective, descendants: true }, { propertyName: "groupHeader", first: true, predicate: DatatableGroupHeaderDirective, descendants: true }, { propertyName: "footer", first: true, predicate: DatatableFooterDirective, descendants: true }, { propertyName: "columnTemplates", predicate: DataTableColumnDirective }], viewQueries: [{ propertyName: "bodyComponent", first: true, predicate: DataTableBodyComponent, descendants: true }, { propertyName: "headerComponent", first: true, predicate: DataTableHeaderComponent, descendants: true }], ngImport: i0, template: "
\n \n \n \n \n \n \n
\n", styles: [".ngx-datatable{display:block;overflow:hidden;justify-content:center;position:relative;transform:translate(0)}.ngx-datatable [hidden]{display:none!important}.ngx-datatable *,.ngx-datatable *:before,.ngx-datatable *:after{box-sizing:border-box}.ngx-datatable.scroll-vertical .datatable-body{overflow-y:auto}.ngx-datatable.scroll-vertical.virtualized .datatable-body .datatable-row-wrapper{position:absolute}.ngx-datatable.scroll-horz .datatable-body{overflow-x:auto;-webkit-overflow-scrolling:touch}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner{white-space:nowrap}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner .datatable-header-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-datatable.fixed-row .datatable-scroll,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row{white-space:nowrap}.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-cell,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-group-cell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ngx-datatable .datatable-body-row,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-header-inner{display:flex;flex-direction:row;-o-flex-flow:row;flex-flow:row}.ngx-datatable .datatable-body-cell,.ngx-datatable .datatable-header-cell{overflow-x:hidden;vertical-align:top;display:inline-block;line-height:1.625}.ngx-datatable .datatable-body-cell:focus,.ngx-datatable .datatable-header-cell:focus{outline:none}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-right{z-index:9}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-row-group,.ngx-datatable .datatable-row-right{position:relative}.ngx-datatable .datatable-header{display:block;overflow:hidden}.ngx-datatable .datatable-header .datatable-header-inner{align-items:stretch;-webkit-align-items:stretch}.ngx-datatable .datatable-header .datatable-header-cell{position:relative;display:inline-block}.ngx-datatable .datatable-header .datatable-header-cell.sortable .datatable-header-cell-wrapper{cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell.longpress .datatable-header-cell-wrapper{cursor:move}.ngx-datatable .datatable-header .datatable-header-cell .sort-btn{line-height:100%;vertical-align:middle;display:inline-block;cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell .resize-handle--not-resizable{display:inline-block;position:absolute;right:0;top:0;bottom:0;width:5px;padding:0 4px;visibility:hidden}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle{cursor:ew-resize}.ngx-datatable .datatable-header .datatable-header-cell.resizeable:hover .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell:hover .resize-handle--not-resizable{visibility:visible}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker{position:absolute;top:0;bottom:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromLeft{right:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromRight{left:0}.ngx-datatable .datatable-header .datatable-header-cell .datatable-header-cell-template-wrap{height:inherit}.ngx-datatable .datatable-body{position:relative;z-index:10;display:block}.ngx-datatable .datatable-body .datatable-scroll{display:inline-block}.ngx-datatable .datatable-body .datatable-row-detail{overflow-y:hidden}.ngx-datatable .datatable-body .datatable-row-wrapper{display:flex;flex-direction:column}.ngx-datatable .datatable-body .datatable-body-row{outline:none}.ngx-datatable .datatable-body .datatable-body-row>div{display:flex}.ngx-datatable .datatable-footer{display:block;width:100%;overflow:auto}.ngx-datatable .datatable-footer .datatable-footer-inner{display:flex;align-items:center;width:100%}.ngx-datatable .datatable-footer .selected-count .page-count{flex:1 1 40%}.ngx-datatable .datatable-footer .selected-count .datatable-pager{flex:1 1 60%}.ngx-datatable .datatable-footer .page-count{flex:1 1 20%}.ngx-datatable .datatable-footer .datatable-pager{flex:1 1 80%;text-align:right}.ngx-datatable .datatable-footer .datatable-pager .pager,.ngx-datatable .datatable-footer .datatable-pager .pager li{padding:0;margin:0;display:inline-block;list-style:none}.ngx-datatable .datatable-footer .datatable-pager .pager li,.ngx-datatable .datatable-footer .datatable-pager .pager li a{outline:none}.ngx-datatable .datatable-footer .datatable-pager .pager li a{cursor:pointer;display:inline-block}.ngx-datatable .datatable-footer .datatable-pager .pager li.disabled a{cursor:not-allowed}\n"], components: [{ type: DataTableHeaderComponent, selector: "datatable-header", inputs: ["sortAscendingIcon", "sortDescendingIcon", "sortUnsetIcon", "scrollbarH", "dealsWithGroup", "targetMarkerTemplate", "innerWidth", "sorts", "sortType", "allRowsSelected", "selectionType", "reorderable", "headerHeight", "columns", "offsetX"], outputs: ["sort", "reorder", "resize", "select", "columnContextmenu"] }, { type: DataTableBodyComponent, selector: "datatable-body", inputs: ["scrollbarV", "scrollbarH", "loadingIndicator", "externalPaging", "rowHeight", "offsetX", "emptyMessage", "selectionType", "selected", "rowIdentity", "rowDetail", "groupHeader", "selectCheck", "displayCheck", "trackByProp", "rowClass", "groupedRows", "groupExpansionDefault", "innerWidth", "groupRowsBy", "virtualization", "summaryRow", "summaryPosition", "summaryHeight", "pageSize", "rows", "columns", "offset", "rowCount", "bodyHeight"], outputs: ["scroll", "page", "activate", "select", "detailToggle", "rowContextmenu", "treeAction"] }, { type: DataTableFooterComponent, selector: "datatable-footer", inputs: ["footerHeight", "rowCount", "pageSize", "offset", "pagerLeftArrowIcon", "pagerRightArrowIcon", "pagerPreviousIcon", "pagerNextIcon", "totalMessage", "footerTemplate", "selectedCount", "selectedMessage"], outputs: ["page"] }], directives: [{ type: VisibilityDirective, selector: "[visibilityObserver]", outputs: ["visible"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i1.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); __decorate([ throttleable(5) ], DatatableComponent.prototype, "onWindowResize", null); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: DatatableComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-datatable', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'ngx-datatable' }, template: "
\n \n \n \n \n \n \n
\n", styles: [".ngx-datatable{display:block;overflow:hidden;justify-content:center;position:relative;transform:translate(0)}.ngx-datatable [hidden]{display:none!important}.ngx-datatable *,.ngx-datatable *:before,.ngx-datatable *:after{box-sizing:border-box}.ngx-datatable.scroll-vertical .datatable-body{overflow-y:auto}.ngx-datatable.scroll-vertical.virtualized .datatable-body .datatable-row-wrapper{position:absolute}.ngx-datatable.scroll-horz .datatable-body{overflow-x:auto;-webkit-overflow-scrolling:touch}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner{white-space:nowrap}.ngx-datatable.fixed-header .datatable-header .datatable-header-inner .datatable-header-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-datatable.fixed-row .datatable-scroll,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row{white-space:nowrap}.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-cell,.ngx-datatable.fixed-row .datatable-scroll .datatable-body-row .datatable-body-group-cell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ngx-datatable .datatable-body-row,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-header-inner{display:flex;flex-direction:row;-o-flex-flow:row;flex-flow:row}.ngx-datatable .datatable-body-cell,.ngx-datatable .datatable-header-cell{overflow-x:hidden;vertical-align:top;display:inline-block;line-height:1.625}.ngx-datatable .datatable-body-cell:focus,.ngx-datatable .datatable-header-cell:focus{outline:none}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-right{z-index:9}.ngx-datatable .datatable-row-left,.ngx-datatable .datatable-row-center,.ngx-datatable .datatable-row-group,.ngx-datatable .datatable-row-right{position:relative}.ngx-datatable .datatable-header{display:block;overflow:hidden}.ngx-datatable .datatable-header .datatable-header-inner{align-items:stretch;-webkit-align-items:stretch}.ngx-datatable .datatable-header .datatable-header-cell{position:relative;display:inline-block}.ngx-datatable .datatable-header .datatable-header-cell.sortable .datatable-header-cell-wrapper{cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell.longpress .datatable-header-cell-wrapper{cursor:move}.ngx-datatable .datatable-header .datatable-header-cell .sort-btn{line-height:100%;vertical-align:middle;display:inline-block;cursor:pointer}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell .resize-handle--not-resizable{display:inline-block;position:absolute;right:0;top:0;bottom:0;width:5px;padding:0 4px;visibility:hidden}.ngx-datatable .datatable-header .datatable-header-cell .resize-handle{cursor:ew-resize}.ngx-datatable .datatable-header .datatable-header-cell.resizeable:hover .resize-handle,.ngx-datatable .datatable-header .datatable-header-cell:hover .resize-handle--not-resizable{visibility:visible}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker{position:absolute;top:0;bottom:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromLeft{right:0}.ngx-datatable .datatable-header .datatable-header-cell .targetMarker.dragFromRight{left:0}.ngx-datatable .datatable-header .datatable-header-cell .datatable-header-cell-template-wrap{height:inherit}.ngx-datatable .datatable-body{position:relative;z-index:10;display:block}.ngx-datatable .datatable-body .datatable-scroll{display:inline-block}.ngx-datatable .datatable-body .datatable-row-detail{overflow-y:hidden}.ngx-datatable .datatable-body .datatable-row-wrapper{display:flex;flex-direction:column}.ngx-datatable .datatable-body .datatable-body-row{outline:none}.ngx-datatable .datatable-body .datatable-body-row>div{display:flex}.ngx-datatable .datatable-footer{display:block;width:100%;overflow:auto}.ngx-datatable .datatable-footer .datatable-footer-inner{display:flex;align-items:center;width:100%}.ngx-datatable .datatable-footer .selected-count .page-count{flex:1 1 40%}.ngx-datatable .datatable-footer .selected-count .datatable-pager{flex:1 1 60%}.ngx-datatable .datatable-footer .page-count{flex:1 1 20%}.ngx-datatable .datatable-footer .datatable-pager{flex:1 1 80%;text-align:right}.ngx-datatable .datatable-footer .datatable-pager .pager,.ngx-datatable .datatable-footer .datatable-pager .pager li{padding:0;margin:0;display:inline-block;list-style:none}.ngx-datatable .datatable-footer .datatable-pager .pager li,.ngx-datatable .datatable-footer .datatable-pager .pager li a{outline:none}.ngx-datatable .datatable-footer .datatable-pager .pager li a{cursor:pointer;display:inline-block}.ngx-datatable .datatable-footer .datatable-pager .pager li.disabled a{cursor:not-allowed}\n"] }] }], ctorParameters: function () { return [{ type: ScrollbarHelper, decorators: [{ type: SkipSelf }] }, { type: DimensionsHelper, decorators: [{ type: SkipSelf }] }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.KeyValueDiffers }, { type: ColumnChangesService }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: ['configuration'] }] }]; }, propDecorators: { targetMarkerTemplate: [{ type: Input }], rows: [{ type: Input }], groupRowsBy: [{ type: Input }], groupedRows: [{ type: Input }], columns: [{ type: Input }], selected: [{ type: Input }], scrollbarV: [{ type: Input }], scrollbarH: [{ type: Input }], rowHeight: [{ type: Input }], columnMode: [{ type: Input }], headerHeight: [{ type: Input }], footerHeight: [{ type: Input }], externalPaging: [{ type: Input }], externalSorting: [{ type: Input }], limit: [{ type: Input }], count: [{ type: Input }], offset: [{ type: Input }], loadingIndicator: [{ type: Input }], selectionType: [{ type: Input }], reorderable: [{ type: Input }], swapColumns: [{ type: Input }], sortType: [{ type: Input }], sorts: [{ type: Input }], cssClasses: [{ type: Input }], messages: [{ type: Input }], rowClass: [{ type: Input }], selectCheck: [{ type: Input }], displayCheck: [{ type: Input }], groupExpansionDefault: [{ type: Input }], trackByProp: [{ type: Input }], selectAllRowsOnPage: [{ type: Input }], virtualization: [{ type: Input }], treeFromRelation: [{ type: Input }], treeToRelation: [{ type: Input }], summaryRow: [{ type: Input }], summaryHeight: [{ type: Input }], summaryPosition: [{ type: Input }], scroll: [{ type: Output }], activate: [{ type: Output }], select: [{ type: Output }], sort: [{ type: Output }], page: [{ type: Output }], reorder: [{ type: Output }], resize: [{ type: Output }], tableContextmenu: [{ type: Output }], treeAction: [{ type: Output }], isFixedHeader: [{ type: HostBinding, args: ['class.fixed-header'] }], isFixedRow: [{ type: HostBinding, args: ['class.fixed-row'] }], isVertScroll: [{ type: HostBinding, args: ['class.scroll-vertical'] }], isVirtualized: [{ type: HostBinding, args: ['class.virtualized'] }], isHorScroll: [{ type: HostBinding, args: ['class.scroll-horz'] }], isSelectable: [{ type: HostBinding, args: ['class.selectable'] }], isCheckboxSelection: [{ type: HostBinding, args: ['class.checkbox-selection'] }], isCellSelection: [{ type: HostBinding, args: ['class.cell-selection'] }], isSingleSelection: [{ type: HostBinding, args: ['class.single-selection'] }], isMultiSelection: [{ type: HostBinding, args: ['class.multi-selection'] }], isMultiClickSelection: [{ type: HostBinding, args: ['class.multi-click-selection'] }], columnTemplates: [{ type: ContentChildren, args: [DataTableColumnDirective] }], rowDetail: [{ type: ContentChild, args: [DatatableRowDetailDirective] }], groupHeader: [{ type: ContentChild, args: [DatatableGroupHeaderDirective] }], footer: [{ type: ContentChild, args: [DatatableFooterDirective] }], bodyComponent: [{ type: ViewChild, args: [DataTableBodyComponent] }], headerComponent: [{ type: ViewChild, args: [DataTableHeaderComponent] }], rowIdentity: [{ type: Input }], onWindowResize: [{ type: HostListener, args: ['window:resize'] }] } }); class NgxDatatableModule { /** * Configure global configuration via INgxDatatableConfig * @param configuration */ static forRoot(configuration) { return { ngModule: NgxDatatableModule, providers: [{ provide: 'configuration', useValue: configuration }] }; } } NgxDatatableModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDatatableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NgxDatatableModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDatatableModule, declarations: [DataTableFooterTemplateDirective, VisibilityDirective, DraggableDirective, ResizeableDirective, OrderableDirective, LongPressDirective, ScrollerComponent, DatatableComponent, DataTableColumnDirective, DataTableHeaderComponent, DataTableHeaderCellComponent, DataTableBodyComponent, DataTableFooterComponent, DataTablePagerComponent, ProgressBarComponent, DataTableBodyRowComponent, DataTableRowWrapperComponent, DatatableRowDetailDirective, DatatableGroupHeaderDirective, DatatableRowDetailTemplateDirective, DataTableBodyCellComponent, DataTableSelectionComponent, DataTableColumnHeaderDirective, DataTableColumnCellDirective, DataTableColumnCellTreeToggle, DatatableFooterDirective, DatatableGroupHeaderTemplateDirective, DataTableSummaryRowComponent], imports: [CommonModule], exports: [DatatableComponent, DatatableRowDetailDirective, DatatableGroupHeaderDirective, DatatableRowDetailTemplateDirective, DataTableColumnDirective, DataTableColumnHeaderDirective, DataTableColumnCellDirective, DataTableColumnCellTreeToggle, DataTableFooterTemplateDirective, DatatableFooterDirective, DataTablePagerComponent, DatatableGroupHeaderTemplateDirective] }); NgxDatatableModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDatatableModule, providers: [ScrollbarHelper, DimensionsHelper, ColumnChangesService], imports: [[CommonModule]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDatatableModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], providers: [ScrollbarHelper, DimensionsHelper, ColumnChangesService], declarations: [ DataTableFooterTemplateDirective, VisibilityDirective, DraggableDirective, ResizeableDirective, OrderableDirective, LongPressDirective, ScrollerComponent, DatatableComponent, DataTableColumnDirective, DataTableHeaderComponent, DataTableHeaderCellComponent, DataTableBodyComponent, DataTableFooterComponent, DataTablePagerComponent, ProgressBarComponent, DataTableBodyRowComponent, DataTableRowWrapperComponent, DatatableRowDetailDirective, DatatableGroupHeaderDirective, DatatableRowDetailTemplateDirective, DataTableBodyCellComponent, DataTableSelectionComponent, DataTableColumnHeaderDirective, DataTableColumnCellDirective, DataTableColumnCellTreeToggle, DatatableFooterDirective, DatatableGroupHeaderTemplateDirective, DataTableSummaryRowComponent ], exports: [ DatatableComponent, DatatableRowDetailDirective, DatatableGroupHeaderDirective, DatatableRowDetailTemplateDirective, DataTableColumnDirective, DataTableColumnHeaderDirective, DataTableColumnCellDirective, DataTableColumnCellTreeToggle, DataTableFooterTemplateDirective, DatatableFooterDirective, DataTablePagerComponent, DatatableGroupHeaderTemplateDirective ] }] }] }); var ClickType; (function (ClickType) { ClickType["single"] = "single"; ClickType["double"] = "double"; })(ClickType || (ClickType = {})); if (typeof document !== 'undefined' && !document.elementsFromPoint) { document.elementsFromPoint = elementsFromPoint; } /*tslint:disable*/ /** * Polyfill for `elementsFromPoint` * * https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint * https://gist.github.com/iddan/54d5d9e58311b0495a91bf06de661380 * https://gist.github.com/oslego/7265412 */ function elementsFromPoint(x, y) { const elements = []; const previousPointerEvents = []; let current; // TODO: window.getComputedStyle should be used with inferred type (Element) let i; let d; //if (document === undefined) return elements; // get all elements via elementFromPoint, and remove them from hit-testing in order while ((current = document.elementFromPoint(x, y)) && elements.indexOf(current) === -1 && current != null) { // push the element and its current style elements.push(current); previousPointerEvents.push({ value: current.style.getPropertyValue('pointer-events'), priority: current.style.getPropertyPriority('pointer-events') }); // add "pointer-events: none", to get to the underlying element current.style.setProperty('pointer-events', 'none', 'important'); } // restore the previous pointer-events values for (i = previousPointerEvents.length; (d = previousPointerEvents[--i]);) { elements[i].style.setProperty('pointer-events', d.value ? d.value : '', d.priority); } // return our results return elements; } /*tslint:enable*/ /* * Public API Surface of ngx-datatable */ /** * Generated bundle index. Do not edit. */ export { ClickType, ColumnChangesService, ColumnMode, ContextmenuType, DataTableBodyCellComponent, DataTableBodyComponent, DataTableBodyRowComponent, DataTableColumnCellDirective, DataTableColumnCellTreeToggle, DataTableColumnDirective, DataTableColumnHeaderDirective, DataTableFooterComponent, DataTableFooterTemplateDirective, DataTableHeaderCellComponent, DataTableHeaderComponent, DataTablePagerComponent, DataTableRowWrapperComponent, DataTableSelectionComponent, DataTableSummaryRowComponent, DatatableComponent, DatatableFooterDirective, DatatableGroupHeaderDirective, DatatableGroupHeaderTemplateDirective, DatatableRowDetailDirective, DatatableRowDetailTemplateDirective, DimensionsHelper, DraggableDirective, Keys, LongPressDirective, NgxDatatableModule, OrderableDirective, ProgressBarComponent, ResizeableDirective, RowHeightCache, ScrollbarHelper, ScrollerComponent, SelectionType, SortDirection, SortType, VisibilityDirective, adjustColumnWidths, camelCase, columnGroupWidths, columnTotalWidth, columnsByPin, columnsByPinArr, columnsTotalWidth, deCamelCase, deepValueGetter, elementsFromPoint, emptyStringGetter, forceFillColumnWidths, getTotalFlexGrow, getVendorPrefixedName, getterForProp, groupRowsByParents, id, isNullOrUndefined, nextSortDir, numericIndexGetter, optionalGetterForProp, orderByComparator, selectRows, selectRowsBetween, setColumnDefaults, shallowValueGetter, sortRows, throttle, throttleable, translateTemplates, translateXY }; //# sourceMappingURL=swimlane-ngx-datatable.mjs.map