UNPKG

@schoolbelle/common

Version:

662 lines (649 loc) 22.3 kB
import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { isMatch as isMatch$1 } from 'lodash'; import { Injectable, Component, ElementRef, Output, EventEmitter, Input, ComponentRef, ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, HostListener, Renderer2, NgModule } from '@angular/core'; import { defaults, isMatch, times } from 'lodash-es'; import { VirtualScrollerComponent, VirtualScrollerModule } from 'ngx-virtual-scroller'; import { Subject, Subscription, fromEvent } from 'rxjs'; import { distinctUntilChanged, map, startWith, filter } from 'rxjs/operators'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TableResizerService { constructor() { this._selected = { x: undefined, y: undefined }; this.focusedEvent = new Subject(); this.action = new Subject(); } /** * @return {?} */ get selected() { return this._selected; } /** * @return {?} */ get onSelected() { return this.focusedEvent.asObservable(); } /** * @param {?} cordinations * @return {?} */ select(cordinations) { cordinations = defaults(cordinations, { x: undefined, y: undefined }); if (isMatch(this._selected, cordinations)) return; this._selected = cordinations; this.focusedEvent.next(this._selected); this.action.next({ type: 'click', cordinations: this._selected }); } } TableResizerService.decorators = [ { type: Injectable } ]; /** @nocollapse */ TableResizerService.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TableResizerComponent { /** * @param {?} resizer * @param {?} cdRef */ constructor(resizer, cdRef) { this.resizer = resizer; this.cdRef = cdRef; this.action = new EventEmitter(); this.scrollContainerQuery = 'table'; this.x = 0; this.y = 0; this.disableIndexCellFn = (/** * @return {?} */ () => { return false; }); this.classIndexCellFn = (/** * @return {?} */ () => { return ''; }); this.selectedClass = 'bg-warning text-white'; this.subscription = new Subscription(); this.scrollTop = 0; this.scrollLeft = 0; } /** * @param {?} cord * @return {?} */ set selected(cord) { if (cord) this.resizer.select(cord); } /** * @return {?} */ ngOnInit() { this.subscription.add(this.resizer.action.subscribe((/** * @param {?} e * @return {?} */ e => { this.action.next(e); }))); } /** * @return {?} */ ngAfterViewInit() { setTimeout((/** * @return {?} */ () => { this.setScrollContainer(); })); } /** * @private * @return {?} */ setScrollContainer() { if (this.scrollContainerQuery) { /** @type {?} */ const contentDiv = this.content.nativeElement; if (typeof this.scrollContainerQuery === 'string') this.scrollContainer = contentDiv.parentElement.querySelector(this.scrollContainerQuery); else if (this.scrollContainerQuery instanceof ComponentRef) this.scrollContainer = this.scrollContainerQuery.location.nativeElement; else this.scrollContainer = this.scrollContainerQuery; this.cdRef.detectChanges(); } } /** * @param {?} index * @return {?} */ trackByIndex(index) { return index; } /** * @return {?} */ ngOnDestroy() { this.subscription.unsubscribe(); } } TableResizerComponent.decorators = [ { type: Component, args: [{ selector: 'app-table-resizer', template: "<div class=\"position-relative\">\n <app-top-ruler [x]=\"x\" \n [childWidth]=\"childWidth\" \n [classIndexCellFn]=\"classIndexCellFn\"\n [disableIndexCellFn]=\"disableIndexCellFn\"\n [selectedClass]=\"selectedClass\"\n ></app-top-ruler> \n <div class=\"position-absolute px-2\" style=\"right: -43px; top: 0;\" range-dropdown-cell [x]=\"x\"></div>\n</div>\n<div class=\"position-relative\" style=\"padding-left:57px;\">\n \n <div class=\"position-absolute border-top\" style=\"width:57px; left:0;\">\n <app-left-ruler [y]=\"y\"\n [childHeight]=\"childHeight\" \n [scrollTop]=\"scrollTop\" \n [classIndexCellFn]=\"classIndexCellFn\"\n [disableIndexCellFn]=\"disableIndexCellFn\"\n [selectedClass]=\"selectedClass\"\n [scrollContainer]=\"scrollContainer\"\n ></app-left-ruler> \n <div class=\"py-2 text-center\" range-dropdown-cell [y]=\"y\"></div>\n </div>\n \n <div #content>\n <ng-content></ng-content>\n </div>\n</div>\n", providers: [TableResizerService], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host div[range-dropdown-cell]{opacity:0;transition:opacity .2s ease-in-out}:host:hover [range-dropdown-cell]{opacity:1}"] }] } ]; /** @nocollapse */ TableResizerComponent.ctorParameters = () => [ { type: TableResizerService }, { type: ChangeDetectorRef } ]; TableResizerComponent.propDecorators = { content: [{ type: ViewChild, args: ['content',] }], action: [{ type: Output }], scrollContainerQuery: [{ type: Input, args: ['scrollContainer',] }], x: [{ type: Input }], y: [{ type: Input }], childHeight: [{ type: Input }], childWidth: [{ type: Input }], selected: [{ type: Input }], disableIndexCellFn: [{ type: Input }], classIndexCellFn: [{ type: Input }], selectedClass: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class RangeDropdownCellComponent { /** * @param {?} resizer */ constructor(resizer) { this.resizer = resizer; } /** * @return {?} */ get value() { return typeof this.x !== 'undefined' ? this.x : this.y; } /** * @return {?} */ ngOnInit() { } /** * @param {?} v * @return {?} */ setLength(v) { if (typeof this.x !== 'undefined') { this.x = v; this.resizer.action.next({ type: 'resize', cordinations: { x: v } }); } else { this.y = v; this.resizer.action.next({ type: 'resize', cordinations: { y: v } }); } } } RangeDropdownCellComponent.decorators = [ { type: Component, args: [{ selector: 'td[range-dropdown-cell],[range-dropdown-cell]', template: "<div class=\"position-relative\" style=\"z-index:5;\" dropdown container=\"body\" [placement]=\"y === undefined ? 'bottom right':'right top'\">\n <button class=\"btn btn-secondary btn-sm\" dropdownToggle tabindex=\"-1\">\n <i class=\"fa fa-sort\" [ngClass]=\"{'fa-rotate-90':y === undefined}\" aria-hidden=\"true\"></i>\n </button>\n <div class=\"dropdown-menu p-0\" [ngClass]=\"{'dropdown-menu-right':y === undefined}\" style=\"max-width:4rem;\" *dropdownMenu>\n <div class=\"input-group\">\n <input type=\"number\" class=\"form-control\"\n [class.is-invalid]=\"lengthInput.invalid\"\n [ngModel]=\"value\" [min]=\"min\" [max]=\"max\" #lengthInput=\"ngModel\"\n autofocus\n (click)=\"$event.stopPropagation()\">\n <div class=\"input-group-append\">\n <button class=\"btn btn-info\" (click)=\"setLength(lengthInput.value)\" type=\"button\" i18n>Apply</button>\n </div>\n </div>\n </div>\n</div>\n", changeDetection: ChangeDetectionStrategy.OnPush }] } ]; /** @nocollapse */ RangeDropdownCellComponent.ctorParameters = () => [ { type: TableResizerService } ]; RangeDropdownCellComponent.propDecorators = { x: [{ type: Input }], y: [{ type: Input }], min: [{ type: Input }], max: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @param {?} n * @return {?} */ function numberToAlphabet(n) { if (typeof n !== 'number') return null; if (n > 255) throw new Error('cannot go over 255'); /** @type {?} */ let a = 'A'.charCodeAt(0); /** @type {?} */ let answer = Math.floor(n / 26); /** @type {?} */ let remainder = Math.floor(n % 26); return (answer !== 0 ? String.fromCharCode(a + answer) : '') + String.fromCharCode(a + remainder); } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class IndexCellComponent { /** * @param {?} resizer * @param {?} elRef * @param {?} renderer */ constructor(resizer, elRef, renderer) { this.resizer = resizer; this.elRef = elRef; this.renderer = renderer; this.disabled = false; this.subscription = new Subscription(); } /** * @return {?} */ get value() { if (typeof this.x !== 'undefined') return numberToAlphabet(this.x); else return this.y + 1; } /** * @return {?} */ ngOnInit() { this.subscription.add(this.resizer.onSelected.pipe(startWith(this.resizer.selected), map((/** * @param {?} cord * @return {?} */ (cord) => isMatch$1(cord, { x: this.x, y: this.y }))), distinctUntilChanged()) .subscribe((/** * @param {?} bool * @return {?} */ (bool) => { this.toggleClass(this.selectedClass, bool); }))); } /** * @protected * @param {?} classnames * @param {?} bool * @return {?} */ toggleClass(classnames, bool) { /** @type {?} */ const el = this.elRef.nativeElement; if (typeof classnames === 'string') { classnames.split(' ').forEach((/** * @param {?} classname * @return {?} */ classname => { if (bool) this.renderer.addClass(el, classname); else this.renderer.removeClass(el, classname); })); } } /** * @return {?} */ toggleFocus() { if (this.disabled) return console.debug('This is a disabled ruller cell.'); this.resizer.select({ x: this.x, y: this.y }); } /** * @return {?} */ remove() { this.resizer.action.next({ type: 'remove', cordinations: { x: this.x, y: this.y } }); } /** * @return {?} */ addBefore() { this.resizer.action.next({ type: 'add', cordinations: { x: this.x, y: this.y } }); } /** * @return {?} */ addAfter() { this.resizer.action.next({ type: 'add', cordinations: { x: typeof this.x !== 'undefined' ? this.x + 1 : undefined, y: typeof this.y !== 'undefined' ? this.y + 1 : undefined } }); } } IndexCellComponent.decorators = [ { type: Component, args: [{ selector: 'td[index-cell],[index-cell]', exportAs: 'indexCell', template: "{{ value }}\n<div *ngIf=\"!disabled\" class=\"position-absolute\" style=\"top:0;bottom:0;right:0;\" dropdown container=\"body\" [placement]=\"y === undefined ? 'bottom right':'right top'\"> \n <button class=\"btn btn-sm rounded-0 h-100 bg-transparent\" dropdownToggle tabindex=\"-1\">\n <i class=\"fa fa-caret-down\" aria-hidden=\"true\"></i>\n </button> \n <div class=\"dropdown-menu\" [ngClass]=\"{'dropdown-menu-right':y === undefined}\" *dropdownMenu>\n <button class=\"dropdown-item\" (click)=\"remove()\" i18n>Remove</button> \n <button class=\"dropdown-item\" (click)=\"addBefore()\" i18n>Add before</button>\n <button class=\"dropdown-item\" (click)=\"addAfter()\" i18n>Add after</button> \n </div> \n</div>", host: { class: 'user-select-none cursor-pointer position-relative' }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [` :host { display: flex; align-items: center; justify-content:center; } `] }] } ]; /** @nocollapse */ IndexCellComponent.ctorParameters = () => [ { type: TableResizerService }, { type: ElementRef }, { type: Renderer2 } ]; IndexCellComponent.propDecorators = { x: [{ type: Input }], y: [{ type: Input }], disabled: [{ type: Input }], selectedClass: [{ type: Input }], toggleFocus: [{ type: HostListener, args: ['click', [],] }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TopRulerComponent { constructor() { this._x = 0; this.colIndexList = []; } /** * @param {?} new_v * @return {?} */ set x(new_v) { /** @type {?} */ const old_v = this._x; if (old_v !== new_v) { this._x = new_v; this.colIndexList = times(new_v); } } /** * @return {?} */ get x() { return this._x; } /** * @return {?} */ ngOnInit() { } } TopRulerComponent.decorators = [ { type: Component, args: [{ selector: 'app-top-ruler', template: "\n<div class=\"d-flex position-relative border-right border-bottom\" [style.width]=\"childWidth? childWidth + 'px' : ''\">\n <div class=\"border-left border-top\" style=\"width:57px;\"></div>\n <div class=\"flex-grow-1 text-center p-1 border-left border-top\" \n style=\"flex-basis: 0;\" \n *ngFor=\"let i of colIndexList\" \n id=\"x-{{i}}\" \n index-cell\n [disabled]=\"disableIndexCellFn(i, undefined)\" [x]=\"i\" \n [selectedClass]=\"selectedClass\"\n [ngClass]=\"classIndexCellFn(i, undefined)\"></div>\n</div>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: [""] }] } ]; /** @nocollapse */ TopRulerComponent.ctorParameters = () => []; TopRulerComponent.propDecorators = { childWidth: [{ type: Input }], disabled: [{ type: Input }], disableIndexCellFn: [{ type: Input }], classIndexCellFn: [{ type: Input }], selectedClass: [{ type: Input }], x: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class LeftRulerComponent { /** * @param {?} elRef * @param {?} cdRef * @param {?} resizer */ constructor(elRef, cdRef, resizer) { this.elRef = elRef; this.cdRef = cdRef; this.resizer = resizer; this.disableIndexCellFn = (/** * @param {?} x * @param {?} y * @return {?} */ (x, y) => { return false; }); this.classIndexCellFn = (/** * @param {?} x * @param {?} y * @return {?} */ (x, y) => { return ''; }); this._y = 0; this.height = 0; this._scrollTop = 0; this.rowIndexList = []; this.subscription = new Subscription(); } /** * @param {?} v * @return {?} */ set scrollContainer(v) { if (v !== this._scrollContainer) { this._scrollContainer = v; this.resizeHeight(); this.watchScroll(); } } ; /** * @return {?} */ get scrollContainer() { return this._scrollContainer; } /** * @param {?} new_v * @return {?} */ set y(new_v) { /** @type {?} */ const old_v = this._y; if (old_v !== new_v) { this._y = new_v; this.rowIndexList = times(new_v); setTimeout((/** * @return {?} */ () => this.resizeHeight()), 100); } } /** * @return {?} */ get y() { return this._y; } /** * @param {?} new_v * @return {?} */ set scrollTop(new_v) { /** @type {?} */ const old_v = this._scrollTop; if (old_v !== new_v) { this._scrollTop = new_v; this.scroller.scrollToPosition(new_v, 0); } } /** * @return {?} */ get scrollTop() { return this._scrollTop; } /** * @return {?} */ ngOnInit() { this.subscription.add(this.resizer.action.pipe(filter((/** * @param {?} e * @return {?} */ e => e.type === 'click'))) .subscribe((/** * @return {?} */ () => { this.cdRef.detectChanges(); }))); } /** * @return {?} */ ngOnDestroy() { if (this.subscription) this.subscription.unsubscribe(); if (this.scrollSubscription) this.scrollSubscription.unsubscribe(); } /** * @private * @return {?} */ watchScroll() { if (this.scrollSubscription) this.scrollSubscription.unsubscribe(); if (this.scrollContainer) this.scrollSubscription = fromEvent(this.scrollContainer, 'scroll').subscribe((/** * @return {?} */ () => this.resetScroll())); } /** * @private * @return {?} */ resetScroll() { if (this.scrollContainer) { this.scrollTop = this.scrollContainer.scrollTop; this.cdRef.detectChanges(); } } /** * @private * @return {?} */ resizeHeight() { if (this.scrollContainer) { /** @type {?} */ const scroll = this.elRef.nativeElement.querySelector('#scroll'); scroll.style.height = `${this.scrollContainer.offsetHeight}px`; this.cdRef.detectChanges(); this.scroller.refresh(); // setTimeout(()=>{ // this.cdRef.detectChanges(); // this.scroller.refresh(); // }, 100); } } /** * @param {?} index * @param {?} item * @return {?} */ trackByFn(index, item) { return item; } } LeftRulerComponent.decorators = [ { type: Component, args: [{ selector: 'app-left-ruler', template: "<div id=\"scroll\" class=\"flex-column\" \n [style.height]=\"height + 'px'\"\n virtualScroller \n [bufferAmount]=\"5\"\n [scrollDebounceTime]=\"10\"\n #scroll \n [items]=\"rowIndexList\">\n\n <div *ngFor=\"let i of scroll.viewPortItems;trackBy:trackByFn\" \n class=\"border-bottom border-left p-1 w-100\" \n [ngClass]=\"classIndexCellFn(undefined, i)\" \n index-cell\n [selectedClass]=\"selectedClass\"\n [disabled]=\"disableIndexCellFn(undefined, i)\"\n [y]=\"i\"\n [style.height]=\"childHeight? childHeight + 'px':''\" \n ></div>\n</div>\n", changeDetection: ChangeDetectionStrategy.OnPush, styles: ["#scroll{overflow:hidden;min-width:57px}"] }] } ]; /** @nocollapse */ LeftRulerComponent.ctorParameters = () => [ { type: ElementRef }, { type: ChangeDetectorRef }, { type: TableResizerService } ]; LeftRulerComponent.propDecorators = { scroller: [{ type: ViewChild, args: [VirtualScrollerComponent,] }], childHeight: [{ type: Input }], disableIndexCellFn: [{ type: Input }], classIndexCellFn: [{ type: Input }], selectedClass: [{ type: Input }], scrollContainer: [{ type: Input }], y: [{ type: Input }], scrollTop: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TableResizerModule { } TableResizerModule.decorators = [ { type: NgModule, args: [{ declarations: [ TableResizerComponent, RangeDropdownCellComponent, IndexCellComponent, TopRulerComponent, LeftRulerComponent, ], imports: [ CommonModule, FormsModule, VirtualScrollerModule, BsDropdownModule.forRoot(), ], // providers:[TableResizerService], exports: [TableResizerComponent], entryComponents: [ RangeDropdownCellComponent, IndexCellComponent, ], },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { TableResizerModule, TableResizerComponent, TableResizerService, IndexCellComponent as ɵb, LeftRulerComponent as ɵd, RangeDropdownCellComponent as ɵa, TopRulerComponent as ɵc }; //# sourceMappingURL=schoolbelle-common-table-resizer.js.map