@obliczeniowo/elementary
Version:
Library made in Angular version 20
292 lines (284 loc) • 20.7 kB
JavaScript
import * as i0 from '@angular/core';
import { model, input, effect, HostListener, HostBinding, Component, Pipe, TemplateRef, EventEmitter, Output, Input, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i4 from '@obliczeniowo/elementary/buttons';
import { ButtonsModule } from '@obliczeniowo/elementary/buttons';
import * as i5 from '@obliczeniowo/elementary/scroller-nav';
import { PageControllerRecordAdapter, ScrollerNavModule } from '@obliczeniowo/elementary/scroller-nav';
import * as i3 from '@obliczeniowo/elementary/icons';
import { IconsModule } from '@obliczeniowo/elementary/icons';
import * as i1 from '@obliczeniowo/elementary/input';
import { InputModule } from '@obliczeniowo/elementary/input';
import { ElementaryMath } from '@obliczeniowo/elementary/math';
import * as i1$1 from '@obliczeniowo/elementary/files';
import { Csv } from '@obliczeniowo/elementary/files';
import { FormsModule } from '@angular/forms';
class EditableCellComponent {
elementRef;
value = model.required();
editable = input(true);
type = 'none';
inputValue;
focus = false;
get isNumber() {
return this.type === 'number';
}
get isText() {
return this.type === 'string';
}
clicked() {
if (this.editable()) {
this.focus = true;
}
}
blur(event) {
console.log(event.target.value);
this.value.set(event.target.value);
this.focus = false;
}
constructor(elementRef) {
this.elementRef = elementRef;
effect(() => {
this.value();
this.changed();
}, {
allowSignalWrites: true
});
}
ngAfterViewChecked() {
if (this.focus) {
const input = this.elementRef.nativeElement.querySelector('input');
if (input) {
input.focus();
}
}
}
changed() {
const value = this.value();
const isString = typeof value === 'string';
if (isString || typeof value === 'number') {
if (isString && ElementaryMath.isNumeric(value, true)) {
this.value.set(parseFloat(value));
}
this.type = typeof value;
this.inputValue = value;
}
else if (value === undefined) {
this.type = 'none';
this.inputValue = '';
}
else {
this.type = 'json';
this.inputValue = 'object';
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: EditableCellComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: EditableCellComponent, isStandalone: false, selector: "td[obl-editable-cell]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "click": "clicked()" }, properties: { "class.focus": "this.focus", "class.number": "this.isNumber", "class.string": "this.isText" } }, ngImport: i0, template: "@if (editable() && focus && (type === 'string' || type === 'number')) {\n <obl-input-wrapper\n display=\"none\"\n >\n <input oblInput type=\"text\" [value]=\"inputValue\" (blur)=\"blur($event)\" />\n </obl-input-wrapper>\n} @else {\n {{ inputValue }}\n}\n", styles: ["obl-input-wrapper{width:100%}input{min-width:100px}:host:not(.focus){padding:13px 10px}:host:not(.focus).number{text-align:right}:host:not(.focus).string{word-break:break-all;min-width:100px}\n"], dependencies: [{ kind: "directive", type: i1.InputDirective, selector: "input[oblInput]", inputs: ["outlined"], exportAs: ["oblInput"] }, { kind: "component", type: i1.InputWrapperComponent, selector: "obl-input-wrapper", inputs: ["label", "display", "cancellable", "step", "errors", "translations", "labelAnimation", "small"], outputs: ["loaded"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: EditableCellComponent, decorators: [{
type: Component,
args: [{ selector: 'td[obl-editable-cell]', standalone: false, template: "@if (editable() && focus && (type === 'string' || type === 'number')) {\n <obl-input-wrapper\n display=\"none\"\n >\n <input oblInput type=\"text\" [value]=\"inputValue\" (blur)=\"blur($event)\" />\n </obl-input-wrapper>\n} @else {\n {{ inputValue }}\n}\n", styles: ["obl-input-wrapper{width:100%}input{min-width:100px}:host:not(.focus){padding:13px 10px}:host:not(.focus).number{text-align:right}:host:not(.focus).string{word-break:break-all;min-width:100px}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { focus: [{
type: HostBinding,
args: ['class.focus']
}], isNumber: [{
type: HostBinding,
args: ['class.number']
}], isText: [{
type: HostBinding,
args: ['class.string']
}], clicked: [{
type: HostListener,
args: ['click']
}] } });
class IsPipe {
transform(value, ...args) {
// eslint-disable-next-line valid-typeof
return typeof value === args[0];
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: IsPipe, isStandalone: false, name: "is" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IsPipe, decorators: [{
type: Pipe,
args: [{
name: 'is',
standalone: false
}]
}] });
class IsTemplatePipe {
transform(value, ...args) {
return value instanceof TemplateRef && value || undefined;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IsTemplatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: IsTemplatePipe, isStandalone: false, name: "isTemplate" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: IsTemplatePipe, decorators: [{
type: Pipe,
args: [{
name: 'isTemplate',
standalone: false
}]
}] });
/**
* Component prepared to display raw data like text/numbers as a quick formatted table
*/
class ArrayToTableComponent {
elementRef;
change;
file;
/**
* Array of elements to display number/string/table of number/string
*/
array = [];
/** */
headers = input([]);
/**
* Caption text of table to display
*/
caption = input();
/**
* Maximum number of columns in one line, if number of columns is greater then this value
* then it will split data in new record line
*/
maxLength = input();
/** */
editable = input(false);
/** */
display = input({
index: true,
download: 'csv',
});
arrayChanged = new EventEmitter();
/**
* Prepared to display data
*/
records = [];
/**
* body of table reference for scroller
*/
tbody = null;
/**
* y table wrapper reference for scroller
*/
yWrapper = null;
pageAdapter = new PageControllerRecordAdapter(this.records.length);
constructor(elementRef, change, file) {
this.elementRef = elementRef;
this.change = change;
this.file = file;
}
ngOnChanges(changes) {
if (changes.array || changes.maxLength) {
this.array = this.array.map((v) => {
if (v instanceof Array) {
return v;
}
return [v];
});
this.records =
this.convert().reduce((p, c) => {
const copy = [...c];
while (this.maxLength() && copy.length > (this.maxLength() || 0)) {
p.push(copy.splice(0, this.maxLength()));
}
if (copy.length) {
p.push(copy);
}
return p;
}, []) || [];
this.pageAdapter.setMax(this.records.length);
}
}
ngAfterViewInit() {
setTimeout(() => {
this.tbody = this.elementRef.nativeElement.querySelector('tbody');
this.yWrapper = this.elementRef.nativeElement.querySelector('.y-wrapper');
});
}
downloadCsv(name = 'Table') {
if (this.array.length) {
const converted = this.convert();
const csv = Csv.fromArray(converted.map((v) => v.map((v) => v.value)), this.headers());
this.file.saveTextFile(csv.prepare(), name, 'text/csv');
}
}
downloadJson(name = 'Table') {
if (this.array.length) {
const converted = this.convert();
const csv = Csv.fromArray(converted.map((v) => v.map((v) => v.value)), this.headers());
this.file.saveTextFile(JSON.stringify(csv.toJson(), undefined, ' '), name, 'text/json');
}
}
changed(value, record, index) {
if (ElementaryMath.isNumeric(value, true)) {
value = parseFloat(value);
this.records[record][index].value = value;
this.array[this.records[record][index].y][this.records[record][index].x] = value;
}
else {
this.records[record][index].value = value;
this.array[this.records[record][index].y][this.records[record][index].x] = value;
}
this.arrayChanged.emit(this.array);
}
convert() {
return this.array.map((v, y) => v.map((value, x) => ({ x, y, value })));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1$1.OblFileService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ArrayToTableComponent, isStandalone: false, selector: "obl-array-to-table", inputs: { array: { classPropertyName: "array", publicName: "array", isSignal: false, isRequired: false, transformFunction: null }, headers: { classPropertyName: "headers", publicName: "headers", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, display: { classPropertyName: "display", publicName: "display", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { arrayChanged: "arrayChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"table-wrapper\">\n <div class=\"y-wrapper\">\n <table>\n @if (caption()) {\n <caption>\n @if (caption() | is: 'string') {\n {{ caption() }}\n } @else {\n <ng-container *ngTemplateOutlet=\"(caption() | isTemplate) || captionRef\"></ng-container>\n }\n </caption>\n }\n\n <tbody>\n @if (!maxLength() && headers()?.length) {\n @if (!maxLength() && headers()?.length) {\n <tr>\n @if (display().index) {\n <th class=\"index\"></th>\n }\n @for ( header of headers(); track header) {\n <th>{{ header }}</th>\n }\n </tr>\n }\n }\n @for(record of records; track $index; let vIndex = $index) { \n @if (\n vIndex >= pageAdapter.position &&\n vIndex < pageAdapter.page.jump + pageAdapter.position\n ) {\n <tr>\n @if (display().index) {\n <td class=\"index\">{{ vIndex + 1 }}</td>\n }\n @for (value of record; track value) {\n <td\n obl-editable-cell\n [value]=\"value.value\"\n [editable]=\"editable()\"\n (valueChanged)=\"changed($event, vIndex, $index)\"\n ></td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n <div class=\"buttons-vertical\">\n @if (pageAdapter.getMax() > pageAdapter.page.jump) {\n <obl-scroller-nav\n [horizontal]=\"false\"\n [pageController]=\"pageAdapter\"\n [element]=\"tbody\"\n ></obl-scroller-nav>\n }\n\n @if (display().download === 'csv') {\n <button oblButton (click)=\"downloadCsv()\">\n <obl-icon [name]=\"'csv-file'\"></obl-icon>\n </button>\n }\n\n @if (display().download === 'json') {\n <button oblButton (click)=\"downloadJson()\">\n <obl-icon [name]=\"'json-file'\"></obl-icon>\n </button>\n }\n\n <ng-content></ng-content>\n </div>\n</div>\n\n<obl-scroller-nav [element]=\"yWrapper\"></obl-scroller-nav>\n\n<ng-template #captionRef></ng-template>", styles: [":host{display:flex;width:100%;flex-direction:column}table{border-collapse:collapse}caption{padding:5px}td,th{border:1px solid;padding:5px;min-width:40px;max-width:300px}.buttons-vertical{display:flex;flex-direction:column;justify-content:flex-end}.buttons-horizontal{display:flex;flex-direction:row}.table-wrapper{display:flex;width:100%}.y-wrapper{max-width:calc(100% - 45px);overflow:hidden}.index{text-align:right;font-weight:800}table th.index{background-image:linear-gradient(to bottom left,transparent calc(50% - 1px),var(--default-border-color),transparent calc(50% + 1px))}\n"], dependencies: [{ kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.IconComponent, selector: "obl-icon", inputs: ["name", "width"] }, { kind: "directive", type: i4.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "component", type: i5.ScrollerNavComponent, selector: "obl-scroller-nav", inputs: ["element", "show", "horizontal", "pageController"] }, { kind: "component", type: EditableCellComponent, selector: "td[obl-editable-cell]", inputs: ["value", "editable"], outputs: ["valueChange"] }, { kind: "pipe", type: IsPipe, name: "is" }, { kind: "pipe", type: IsTemplatePipe, name: "isTemplate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableComponent, decorators: [{
type: Component,
args: [{ selector: 'obl-array-to-table', standalone: false, template: "<div class=\"table-wrapper\">\n <div class=\"y-wrapper\">\n <table>\n @if (caption()) {\n <caption>\n @if (caption() | is: 'string') {\n {{ caption() }}\n } @else {\n <ng-container *ngTemplateOutlet=\"(caption() | isTemplate) || captionRef\"></ng-container>\n }\n </caption>\n }\n\n <tbody>\n @if (!maxLength() && headers()?.length) {\n @if (!maxLength() && headers()?.length) {\n <tr>\n @if (display().index) {\n <th class=\"index\"></th>\n }\n @for ( header of headers(); track header) {\n <th>{{ header }}</th>\n }\n </tr>\n }\n }\n @for(record of records; track $index; let vIndex = $index) { \n @if (\n vIndex >= pageAdapter.position &&\n vIndex < pageAdapter.page.jump + pageAdapter.position\n ) {\n <tr>\n @if (display().index) {\n <td class=\"index\">{{ vIndex + 1 }}</td>\n }\n @for (value of record; track value) {\n <td\n obl-editable-cell\n [value]=\"value.value\"\n [editable]=\"editable()\"\n (valueChanged)=\"changed($event, vIndex, $index)\"\n ></td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n <div class=\"buttons-vertical\">\n @if (pageAdapter.getMax() > pageAdapter.page.jump) {\n <obl-scroller-nav\n [horizontal]=\"false\"\n [pageController]=\"pageAdapter\"\n [element]=\"tbody\"\n ></obl-scroller-nav>\n }\n\n @if (display().download === 'csv') {\n <button oblButton (click)=\"downloadCsv()\">\n <obl-icon [name]=\"'csv-file'\"></obl-icon>\n </button>\n }\n\n @if (display().download === 'json') {\n <button oblButton (click)=\"downloadJson()\">\n <obl-icon [name]=\"'json-file'\"></obl-icon>\n </button>\n }\n\n <ng-content></ng-content>\n </div>\n</div>\n\n<obl-scroller-nav [element]=\"yWrapper\"></obl-scroller-nav>\n\n<ng-template #captionRef></ng-template>", styles: [":host{display:flex;width:100%;flex-direction:column}table{border-collapse:collapse}caption{padding:5px}td,th{border:1px solid;padding:5px;min-width:40px;max-width:300px}.buttons-vertical{display:flex;flex-direction:column;justify-content:flex-end}.buttons-horizontal{display:flex;flex-direction:row}.table-wrapper{display:flex;width:100%}.y-wrapper{max-width:calc(100% - 45px);overflow:hidden}.index{text-align:right;font-weight:800}table th.index{background-image:linear-gradient(to bottom left,transparent calc(50% - 1px),var(--default-border-color),transparent calc(50% + 1px))}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1$1.OblFileService }], propDecorators: { array: [{
type: Input
}], arrayChanged: [{
type: Output
}] } });
class ArrayToTableModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableModule, declarations: [ArrayToTableComponent,
EditableCellComponent,
IsPipe,
IsTemplatePipe], imports: [CommonModule,
FormsModule,
IconsModule,
ButtonsModule,
ScrollerNavModule,
InputModule], exports: [ArrayToTableComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableModule, imports: [CommonModule,
FormsModule,
IconsModule,
ButtonsModule,
ScrollerNavModule,
InputModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArrayToTableModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ArrayToTableComponent,
EditableCellComponent,
IsPipe,
IsTemplatePipe,
],
imports: [
CommonModule,
FormsModule,
IconsModule,
ButtonsModule,
ScrollerNavModule,
InputModule,
],
exports: [
ArrayToTableComponent
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ArrayToTableComponent, ArrayToTableModule };
//# sourceMappingURL=obliczeniowo-elementary-array-to-table.mjs.map