@schoolbelle/common
Version:
662 lines (649 loc) • 22.3 kB
JavaScript
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