diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 4492c90..4c1d05a 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -102,7 +102,7 @@ export class AppComponent implements OnInit { component: OptionMenuComponent, componentProps: { 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, diff --git a/src/app/components/components.module.ts b/src/app/components/components.module.ts index f77d0a2..7beeaaf 100644 --- a/src/app/components/components.module.ts +++ b/src/app/components/components.module.ts @@ -14,6 +14,10 @@ import {OptionPickerComponent} from './option-picker/option-picker.component'; import {HostOptionsComponent} from './editor/host-options/host-options.component'; import {OptionMenuComponent} from './option-menu/option-menu.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({ declarations: [ @@ -27,6 +31,10 @@ import {SelectorComponent} from './sharing/selector/selector.component'; HostOptionsComponent, OptionMenuComponent, SelectorComponent, + NumericEditorComponent, + ParagraphEditorComponent, + ParagraphModalComponent, + BooleanEditorComponent, ], imports: [ CommonModule, @@ -46,6 +54,10 @@ import {SelectorComponent} from './sharing/selector/selector.component'; HostOptionsComponent, OptionMenuComponent, SelectorComponent, + NumericEditorComponent, + ParagraphEditorComponent, + ParagraphModalComponent, + BooleanEditorComponent, ], exports: [ HostComponent, @@ -58,6 +70,10 @@ import {SelectorComponent} from './sharing/selector/selector.component'; HostOptionsComponent, OptionMenuComponent, SelectorComponent, + NumericEditorComponent, + ParagraphEditorComponent, + ParagraphModalComponent, + BooleanEditorComponent, ] }) export class ComponentsModule {} diff --git a/src/app/components/editor/database/columns/columns.component.html b/src/app/components/editor/database/columns/columns.component.html index e9043ed..2893015 100644 --- a/src/app/components/editor/database/columns/columns.component.html +++ b/src/app/components/editor/database/columns/columns.component.html @@ -32,7 +32,15 @@ Text Number - Text-Area + Paragraph + True/False + + + + + + + diff --git a/src/app/components/editor/database/database.component.ts b/src/app/components/editor/database/database.component.ts index a90a795..a3f9ed4 100644 --- a/src/app/components/editor/database/database.component.ts +++ b/src/app/components/editor/database/database.component.ts @@ -5,6 +5,9 @@ import {Observable} from 'rxjs'; import {AlertController, LoadingController, ModalController} from '@ionic/angular'; import {ColumnsComponent} from './columns/columns.component'; 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({ selector: 'editor-database', @@ -67,27 +70,11 @@ export class DatabaseComponent implements OnInit { modal.onDidDismiss().then(result => { if ( result.data ) { - this.columnDefs = result.data.map(x => { - 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` - this.api.post(endpoint, {columns: this.columnDefs}).subscribe(res => { - // this.columnDefs = res.data; + this.setColumns(result.data).subscribe(() => { + 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.columnDefs = res.data; + }); }); } }); @@ -199,30 +186,39 @@ export class DatabaseComponent implements OnInit { getColumnLoadObservable(): Observable { return new Observable(sub => { this.api.get(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}/columns`).subscribe(res => { - this.columnDefs = res.data.map(x => { - 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; + this.setColumns(res.data).subscribe(() => { + sub.next(); + sub.complete(); }); - sub.next(); - sub.complete(); }); }); } + setColumns(data): Observable { + return new Observable(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 { return new Observable(sub => { if ( this.hostRecord.UUID && this.pendingSetup ) { diff --git a/src/app/components/editor/database/editors/boolean/boolean-editor.component.ts b/src/app/components/editor/database/editors/boolean/boolean-editor.component.ts new file mode 100644 index 0000000..b633757 --- /dev/null +++ b/src/app/components/editor/database/editors/boolean/boolean-editor.component.ts @@ -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: ``, + 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'; + } + } +} diff --git a/src/app/components/editor/database/editors/numeric/numeric-editor.component.ts b/src/app/components/editor/database/editors/numeric/numeric-editor.component.ts new file mode 100644 index 0000000..a6c1aab --- /dev/null +++ b/src/app/components/editor/database/editors/numeric/numeric-editor.component.ts @@ -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: ``, + 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; + } +} diff --git a/src/app/components/editor/database/editors/paragraph/paragraph-editor.component.ts b/src/app/components/editor/database/editors/paragraph/paragraph-editor.component.ts new file mode 100644 index 0000000..322782a --- /dev/null +++ b/src/app/components/editor/database/editors/paragraph/paragraph-editor.component.ts @@ -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: ``, + 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(); + }); + }); + } +} diff --git a/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.html b/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.html new file mode 100644 index 0000000..5e950a9 --- /dev/null +++ b/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.html @@ -0,0 +1,27 @@ + + + {{ title }} + + + + + + + + + + + + + + Content + + + + + + + + +   Save + diff --git a/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.scss b/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.ts b/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.ts new file mode 100644 index 0000000..d07fa06 --- /dev/null +++ b/src/app/components/editor/database/editors/paragraph/paragraph-modal.component.ts @@ -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); + } +} diff --git a/src/app/pages/editor/editor.page.html b/src/app/pages/editor/editor.page.html index f29c233..07d438b 100644 --- a/src/app/pages/editor/editor.page.html +++ b/src/app/pages/editor/editor.page.html @@ -19,7 +19,7 @@