Add new cell editors; refactor editor framework
This commit is contained in:
parent
407d26eb05
commit
1bd3795a4a
@ -102,7 +102,7 @@ export class AppComponent implements OnInit {
|
|||||||
component: OptionMenuComponent,
|
component: OptionMenuComponent,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
menuItems: [
|
menuItems: [
|
||||||
...(this.menuTarget.data.level === 'view' ? [] : [{name: 'Share Sub-Tree', icon: 'person-add', value: 'share'}]),
|
...(this.menuTarget.data.level !== 'manage' ? [] : [{name: 'Share Sub-Tree', icon: 'person-add', value: 'share'}]),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
event: $event,
|
event: $event,
|
||||||
|
@ -14,6 +14,10 @@ import {OptionPickerComponent} from './option-picker/option-picker.component';
|
|||||||
import {HostOptionsComponent} from './editor/host-options/host-options.component';
|
import {HostOptionsComponent} from './editor/host-options/host-options.component';
|
||||||
import {OptionMenuComponent} from './option-menu/option-menu.component';
|
import {OptionMenuComponent} from './option-menu/option-menu.component';
|
||||||
import {SelectorComponent} from './sharing/selector/selector.component';
|
import {SelectorComponent} from './sharing/selector/selector.component';
|
||||||
|
import {NumericEditorComponent} from './editor/database/editors/numeric/numeric-editor.component';
|
||||||
|
import {ParagraphEditorComponent} from './editor/database/editors/paragraph/paragraph-editor.component';
|
||||||
|
import {ParagraphModalComponent} from './editor/database/editors/paragraph/paragraph-modal.component';
|
||||||
|
import {BooleanEditorComponent} from './editor/database/editors/boolean/boolean-editor.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -27,6 +31,10 @@ import {SelectorComponent} from './sharing/selector/selector.component';
|
|||||||
HostOptionsComponent,
|
HostOptionsComponent,
|
||||||
OptionMenuComponent,
|
OptionMenuComponent,
|
||||||
SelectorComponent,
|
SelectorComponent,
|
||||||
|
NumericEditorComponent,
|
||||||
|
ParagraphEditorComponent,
|
||||||
|
ParagraphModalComponent,
|
||||||
|
BooleanEditorComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -46,6 +54,10 @@ import {SelectorComponent} from './sharing/selector/selector.component';
|
|||||||
HostOptionsComponent,
|
HostOptionsComponent,
|
||||||
OptionMenuComponent,
|
OptionMenuComponent,
|
||||||
SelectorComponent,
|
SelectorComponent,
|
||||||
|
NumericEditorComponent,
|
||||||
|
ParagraphEditorComponent,
|
||||||
|
ParagraphModalComponent,
|
||||||
|
BooleanEditorComponent,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
HostComponent,
|
HostComponent,
|
||||||
@ -58,6 +70,10 @@ import {SelectorComponent} from './sharing/selector/selector.component';
|
|||||||
HostOptionsComponent,
|
HostOptionsComponent,
|
||||||
OptionMenuComponent,
|
OptionMenuComponent,
|
||||||
SelectorComponent,
|
SelectorComponent,
|
||||||
|
NumericEditorComponent,
|
||||||
|
ParagraphEditorComponent,
|
||||||
|
ParagraphModalComponent,
|
||||||
|
BooleanEditorComponent,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ComponentsModule {}
|
export class ComponentsModule {}
|
||||||
|
@ -32,7 +32,15 @@
|
|||||||
<ion-select interface="popover" [(ngModel)]="columnSets[i].Type">
|
<ion-select interface="popover" [(ngModel)]="columnSets[i].Type">
|
||||||
<ion-select-option value="text">Text</ion-select-option>
|
<ion-select-option value="text">Text</ion-select-option>
|
||||||
<ion-select-option value="number">Number</ion-select-option>
|
<ion-select-option value="number">Number</ion-select-option>
|
||||||
<ion-select-option value="textarea">Text-Area</ion-select-option>
|
<ion-select-option value="paragraph">Paragraph</ion-select-option>
|
||||||
|
<ion-select-option value="boolean">True/False</ion-select-option>
|
||||||
|
<!-- <ion-select-option value="currency">Currency</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="datetime">Date-Time</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="select">Select</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="multiselect">Multi-Select</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="person">Person</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="url">URL</ion-select-option>-->
|
||||||
|
<!-- <ion-select-option value="email">E-Mail</ion-select-option>-->
|
||||||
</ion-select>
|
</ion-select>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
@ -5,6 +5,9 @@ import {Observable} from 'rxjs';
|
|||||||
import {AlertController, LoadingController, ModalController} from '@ionic/angular';
|
import {AlertController, LoadingController, ModalController} from '@ionic/angular';
|
||||||
import {ColumnsComponent} from './columns/columns.component';
|
import {ColumnsComponent} from './columns/columns.component';
|
||||||
import {AgGridAngular} from 'ag-grid-angular';
|
import {AgGridAngular} from 'ag-grid-angular';
|
||||||
|
import {NumericEditorComponent} from './editors/numeric/numeric-editor.component';
|
||||||
|
import {ParagraphEditorComponent} from './editors/paragraph/paragraph-editor.component';
|
||||||
|
import {BooleanEditorComponent} from './editors/boolean/boolean-editor.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'editor-database',
|
selector: 'editor-database',
|
||||||
@ -67,28 +70,12 @@ export class DatabaseComponent implements OnInit {
|
|||||||
|
|
||||||
modal.onDidDismiss().then(result => {
|
modal.onDidDismiss().then(result => {
|
||||||
if ( result.data ) {
|
if ( result.data ) {
|
||||||
this.columnDefs = result.data.map(x => {
|
this.setColumns(result.data).subscribe(() => {
|
||||||
x.editable = true;
|
|
||||||
if ( x.Type === 'text' ) {
|
|
||||||
x.editor = 'agTextCellEditor';
|
|
||||||
} else if ( x.Type === 'number' ) {
|
|
||||||
x.valueFormatter = (value) => {
|
|
||||||
const num = parseFloat(value.value);
|
|
||||||
if ( !isNaN(num) ) {
|
|
||||||
return num;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if ( x.Type === 'textarea' ) {
|
|
||||||
x.editor = 'agPopupTextCellEditor';
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
});
|
|
||||||
const endpoint = `/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}/columns`
|
const endpoint = `/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}/columns`
|
||||||
this.api.post(endpoint, {columns: this.columnDefs}).subscribe(res => {
|
this.api.post(endpoint, {columns: this.columnDefs}).subscribe(res => {
|
||||||
// this.columnDefs = res.data;
|
// this.columnDefs = res.data;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -199,28 +186,37 @@ export class DatabaseComponent implements OnInit {
|
|||||||
getColumnLoadObservable(): Observable<any> {
|
getColumnLoadObservable(): Observable<any> {
|
||||||
return new Observable<any>(sub => {
|
return new Observable<any>(sub => {
|
||||||
this.api.get(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}/columns`).subscribe(res => {
|
this.api.get(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}/columns`).subscribe(res => {
|
||||||
this.columnDefs = res.data.map(x => {
|
this.setColumns(res.data).subscribe(() => {
|
||||||
x.editable = !this.readonly;
|
|
||||||
if ( x.Type === 'text' ) {
|
|
||||||
x.editor = 'agTextCellEditor';
|
|
||||||
} else if ( x.Type === 'number' ) {
|
|
||||||
x.valueFormatter = (value) => {
|
|
||||||
const num = parseFloat(value.value);
|
|
||||||
if ( !isNaN(num) ) {
|
|
||||||
return num;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if ( x.Type === 'textarea' ) {
|
|
||||||
x.editor = 'agPopupTextCellEditor';
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
});
|
|
||||||
sub.next();
|
sub.next();
|
||||||
sub.complete();
|
sub.complete();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setColumns(data): Observable<any> {
|
||||||
|
return new Observable<any>(sub => {
|
||||||
|
this.columnDefs = data.map(x => {
|
||||||
|
x.editable = !this.readonly;
|
||||||
|
|
||||||
|
// Set editors and renderers for different types
|
||||||
|
if ( x.Type === 'text' ) {
|
||||||
|
x.editor = 'agTextCellEditor';
|
||||||
|
} else if ( x.Type === 'number' ) {
|
||||||
|
x.cellEditorFramework = NumericEditorComponent;
|
||||||
|
} else if ( x.Type === 'paragraph' ) {
|
||||||
|
x.cellEditorFramework = ParagraphEditorComponent;
|
||||||
|
} else if ( x.Type === 'boolean' ) {
|
||||||
|
x.cellEditorFramework = BooleanEditorComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log({x});
|
||||||
|
return x;
|
||||||
|
});
|
||||||
|
|
||||||
|
sub.next();
|
||||||
|
sub.complete();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getInitObservable(): Observable<any> {
|
getInitObservable(): Observable<any> {
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
import {ICellEditorAngularComp} from 'ag-grid-angular';
|
||||||
|
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
|
||||||
|
import {ICellEditorParams} from 'ag-grid-community';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cell-editor-paragraph',
|
||||||
|
template: `<input #input [(ngModel)]="value" readonly (click)="onClick()">`,
|
||||||
|
styles: [
|
||||||
|
`input {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid grey;
|
||||||
|
}`
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class BooleanEditorComponent implements ICellEditorAngularComp, AfterViewInit {
|
||||||
|
private params: ICellEditorParams;
|
||||||
|
public value: string;
|
||||||
|
|
||||||
|
@ViewChild('input', {static: false}) input: ElementRef;
|
||||||
|
|
||||||
|
agInit(params: ICellEditorParams): void {
|
||||||
|
this.params = params;
|
||||||
|
this.value = this.params.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): any {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.onClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
if ( this.value === 'True' ) {
|
||||||
|
this.value = 'False';
|
||||||
|
} else if ( this.value === 'False' ) {
|
||||||
|
this.value = '';
|
||||||
|
} else {
|
||||||
|
this.value = 'True';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
import {ICellEditorAngularComp} from 'ag-grid-angular';
|
||||||
|
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
|
||||||
|
import {ICellEditorParams} from 'ag-grid-community';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cell-editor-numeric',
|
||||||
|
template: `<input #input (keydown)="onKeyDown($event)" [(ngModel)]="value">`,
|
||||||
|
styles: [
|
||||||
|
`input {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid grey;
|
||||||
|
}`
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class NumericEditorComponent implements ICellEditorAngularComp, AfterViewInit {
|
||||||
|
private params: ICellEditorParams;
|
||||||
|
public value: number;
|
||||||
|
private cancelBeforeStart = false;
|
||||||
|
|
||||||
|
@ViewChild('input', {static: false}) input: ElementRef;
|
||||||
|
|
||||||
|
agInit(params: ICellEditorParams): void {
|
||||||
|
this.params = params;
|
||||||
|
this.value = this.params.value;
|
||||||
|
|
||||||
|
// Only cancel before start if the pressed key is numeric
|
||||||
|
this.cancelBeforeStart = params.charPress && ('1234567890'.indexOf(params.charPress) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): any {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCancelBeforeStart(): boolean {
|
||||||
|
return this.cancelBeforeStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown($event) {
|
||||||
|
if ( !this.isKeyPressedAllowed($event) ) {
|
||||||
|
if ($event.preventDefault) {
|
||||||
|
$event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.input.nativeElement.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCharCodeFromEvent(event): any {
|
||||||
|
return (typeof event.which === 'undefined') ? event.keyCode : event.which;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isCharNumeric(charStr): boolean {
|
||||||
|
return !!/\d/.test(charStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isKeyPressedAllowed(event): boolean {
|
||||||
|
const charCode = this.getCharCodeFromEvent(event);
|
||||||
|
const charStr = event.key ? event.key : String.fromCharCode(charCode);
|
||||||
|
if (this.isCharNumeric(charStr)) {
|
||||||
|
return true;
|
||||||
|
} else if ( charStr === '.' && this.value % 1 === 0 ) {
|
||||||
|
return true;
|
||||||
|
} else if ( ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight'].includes(event.code) ) {
|
||||||
|
return true;
|
||||||
|
} else if ( charStr === 'a' && event.ctrlKey ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import {ICellEditorAngularComp} from 'ag-grid-angular';
|
||||||
|
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
|
||||||
|
import {ICellEditorParams} from 'ag-grid-community';
|
||||||
|
import {ModalController} from '@ionic/angular';
|
||||||
|
import {ParagraphModalComponent} from './paragraph-modal.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cell-editor-paragraph',
|
||||||
|
template: `<input #input [(ngModel)]="value" readonly>`,
|
||||||
|
styles: [
|
||||||
|
`input {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid grey;
|
||||||
|
}`
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ParagraphEditorComponent implements ICellEditorAngularComp, AfterViewInit {
|
||||||
|
private params: ICellEditorParams;
|
||||||
|
public value: string;
|
||||||
|
|
||||||
|
@ViewChild('input', {static: false}) input: ElementRef;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected modals: ModalController,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
agInit(params: ICellEditorParams): void {
|
||||||
|
this.params = params;
|
||||||
|
this.value = this.params.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): any {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.modals.create({
|
||||||
|
component: ParagraphModalComponent,
|
||||||
|
componentProps: {
|
||||||
|
title: this.params.colDef.headerName,
|
||||||
|
value: this.value,
|
||||||
|
}
|
||||||
|
}).then(modal => {
|
||||||
|
modal.onDidDismiss().then(value => {
|
||||||
|
this.value = String(value.data);
|
||||||
|
});
|
||||||
|
modal.present();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title>{{ title }}</ion-title>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button (click)="dismissModal()">
|
||||||
|
<ion-icon name="close"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="12">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">Content</ion-label>
|
||||||
|
<ion-textarea [(ngModel)]="value" rows="15"></ion-textarea>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</ion-content>
|
||||||
|
|
||||||
|
<ion-footer>
|
||||||
|
<ion-button fill="invisible" (click)="dismissModal()"><ion-icon name="save"></ion-icon> Save</ion-button>
|
||||||
|
</ion-footer>
|
@ -0,0 +1,21 @@
|
|||||||
|
import {Component, Input} from '@angular/core';
|
||||||
|
import {ModalController} from '@ionic/angular';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'editor-paragraph-modal',
|
||||||
|
templateUrl: './paragraph-modal.component.html',
|
||||||
|
styleUrls: ['./paragraph-modal.component.scss'],
|
||||||
|
})
|
||||||
|
export class ParagraphModalComponent {
|
||||||
|
@Input() value = '';
|
||||||
|
@Input() title: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected modals: ModalController,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
dismissModal() {
|
||||||
|
console.log(this.value);
|
||||||
|
this.modals.dismiss(this.value);
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
<div class="editor-root ion-padding">
|
<div class="editor-root ion-padding">
|
||||||
<div
|
<div
|
||||||
*ngFor="let record of hostRecords; let i = index"
|
*ngFor="let record of hostRecords; let i = index"
|
||||||
class="host-container ion-padding" style="display: flex;"
|
class="host-container" style="display: flex;"
|
||||||
(mouseenter)="makeVisible(i)"
|
(mouseenter)="makeVisible(i)"
|
||||||
(mouseleave)="makeInvisible(i)"
|
(mouseleave)="makeInvisible(i)"
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user