finish database implementation
This commit is contained in:
parent
e2dd56ab72
commit
e97c19f19d
@ -3,11 +3,15 @@ import { CommonModule } from '@angular/common';
|
||||
import { HostComponent } from './editor/host/host.component';
|
||||
import {NodePickerComponent} from './editor/node-picker/node-picker.component';
|
||||
import {IonicModule} from '@ionic/angular';
|
||||
import {DatabaseComponent} from './editor/database/database.component';
|
||||
import {AgGridModule} from 'ag-grid-angular';
|
||||
import {ColumnsComponent} from './editor/database/columns/columns.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
declarations: [HostComponent, NodePickerComponent],
|
||||
imports: [CommonModule, IonicModule],
|
||||
entryComponents: [HostComponent, NodePickerComponent],
|
||||
exports: [HostComponent, NodePickerComponent]
|
||||
declarations: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent],
|
||||
imports: [CommonModule, IonicModule, AgGridModule, FormsModule],
|
||||
entryComponents: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent],
|
||||
exports: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent]
|
||||
})
|
||||
export class ComponentsModule {}
|
||||
|
@ -0,0 +1,46 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Manage Database Columns</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="dismissModal(false)">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col size="12">
|
||||
<ion-button (click)="onAddColumnClick()" fill="outline">Add Column</ion-button>
|
||||
<ion-button (click)="dismissModal(true)" color="success" fill="outline">Save</ion-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row
|
||||
*ngFor="let colSet of columnSets; let i = index"
|
||||
>
|
||||
<ion-col size="5">
|
||||
<ion-item>
|
||||
<ion-label position="floating">Field Label</ion-label>
|
||||
<ion-input type="text" required [(ngModel)]="columnSets[i].headerName"></ion-input>
|
||||
</ion-item>
|
||||
</ion-col>
|
||||
<ion-col size="5">
|
||||
<ion-item>
|
||||
<ion-label position="floating">Data Type</ion-label>
|
||||
<ion-select interface="popover" [(ngModel)]="columnSets[i].Type">
|
||||
<ion-select-option value="text">Text</ion-select-option>
|
||||
<ion-select-option value="number">Number</ion-select-option>
|
||||
<ion-select-option value="textarea">Text-Area</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
</ion-col>
|
||||
<ion-col size="2" align-items-center>
|
||||
<ion-button fill="outline" color="light" (click)="onDeleteClick(i)">
|
||||
<ion-icon color="danger" name="trash"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-content>
|
@ -0,0 +1,41 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {ModalController} from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'editor-database-columns',
|
||||
templateUrl: './columns.component.html',
|
||||
styleUrls: ['./columns.component.scss'],
|
||||
})
|
||||
export class ColumnsComponent implements OnInit {
|
||||
@Input() columnSets: Array<{headerName: string, field: string, Type: string}> = [];
|
||||
|
||||
constructor(
|
||||
protected modals: ModalController
|
||||
) { }
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onAddColumnClick() {
|
||||
this.columnSets.push({headerName: '', field: '', Type: ''});
|
||||
}
|
||||
|
||||
dismissModal(doSave = true) {
|
||||
if ( doSave ) {
|
||||
this.columnSets = this.columnSets.map(x => {
|
||||
x.field = x.headerName;
|
||||
return x;
|
||||
})
|
||||
this.modals.dismiss(this.columnSets);
|
||||
} else {
|
||||
this.modals.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
onDeleteClick(i) {
|
||||
const newSets = this.columnSets.filter((x, index) => {
|
||||
return index !== i;
|
||||
});
|
||||
this.columnSets = newSets;
|
||||
}
|
||||
|
||||
}
|
22
src/app/components/editor/database/database.component.html
Normal file
22
src/app/components/editor/database/database.component.html
Normal file
@ -0,0 +1,22 @@
|
||||
<div class="database-wrapper">
|
||||
<ion-toolbar>
|
||||
<ion-buttons>
|
||||
<ion-button (click)="onManageColumns()"><ion-icon name="build" color="primary"></ion-icon> Manage Columns</ion-button>
|
||||
<ion-button (click)="onInsertRow()"><ion-icon name="add-circle" color="success"></ion-icon> Insert Row</ion-button>
|
||||
<ion-button (click)="onRemoveRow()" [disabled]="lastClickRow < 0"><ion-icon name="remove-circle" color="danger"></ion-icon> Delete Row</ion-button>
|
||||
<ion-button (click)="onSyncRecords()"><ion-icon name="save" [color]="dirty ? 'warning' : 'success'"></ion-icon> Sync Records</ion-button>
|
||||
<ion-button (click)="onDropDatabase()"><ion-icon name="alert" color="danger"></ion-icon> Drop Database</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
<div class="grid-wrapper">
|
||||
<ag-grid-angular
|
||||
style="width: 100%; height: 500px;"
|
||||
class="ag-theme-balham"
|
||||
[rowData]="rowData"
|
||||
[columnDefs]="columnDefs"
|
||||
(rowClicked)="onRowClicked($event)"
|
||||
(cellValueChanged)="onCellValueChanged()"
|
||||
#agGridElement
|
||||
></ag-grid-angular>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,4 @@
|
||||
div.database-wrapper {
|
||||
border: 2px solid #8c8c8c;
|
||||
border-radius: 3px;
|
||||
}
|
219
src/app/components/editor/database/database.component.ts
Normal file
219
src/app/components/editor/database/database.component.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
|
||||
import HostRecord from '../../../structures/HostRecord';
|
||||
import {ApiService} from '../../../service/api.service';
|
||||
import {Observable} from 'rxjs';
|
||||
import {AlertController, ModalController} from '@ionic/angular';
|
||||
import {ColumnsComponent} from './columns/columns.component';
|
||||
import {AgGridAngular} from 'ag-grid-angular';
|
||||
|
||||
@Component({
|
||||
selector: 'editor-database',
|
||||
templateUrl: './database.component.html',
|
||||
styleUrls: ['./database.component.scss'],
|
||||
})
|
||||
export class DatabaseComponent implements OnInit {
|
||||
@Input() hostRecord: HostRecord;
|
||||
@Output() hostRecordChange = new EventEmitter<HostRecord>();
|
||||
@Output() requestParentSave = new EventEmitter<DatabaseComponent>();
|
||||
@Output() requestParentDelete = new EventEmitter<DatabaseComponent>();
|
||||
@ViewChild('agGridElement', {static: false}) agGridElement: AgGridAngular;
|
||||
|
||||
public dbRecord: any;
|
||||
public pendingSetup = true;
|
||||
public dirty = false;
|
||||
protected lastClickRow = -1;
|
||||
|
||||
constructor(
|
||||
protected api: ApiService,
|
||||
protected modals: ModalController,
|
||||
protected alerts: AlertController,
|
||||
) { }
|
||||
|
||||
title = 'app';
|
||||
columnDefs = [];
|
||||
rowData = [];
|
||||
|
||||
ngOnInit() {
|
||||
this.getInitObservable().subscribe(() => {
|
||||
this.getColumnLoadObservable().subscribe(() => {
|
||||
this.getDataLoadObservable().subscribe(() => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onCellValueChanged() {
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
async onManageColumns() {
|
||||
const modal = await this.modals.create({
|
||||
component: ColumnsComponent,
|
||||
componentProps: {columnSets: this.columnDefs},
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await modal.present();
|
||||
}
|
||||
|
||||
onInsertRow() {
|
||||
this.rowData.push({});
|
||||
this.agGridElement.api.setRowData(this.rowData);
|
||||
}
|
||||
|
||||
async onRemoveRow() {
|
||||
const alert = await this.alerts.create({
|
||||
header: 'Are you sure?',
|
||||
message: `You are about to delete row ${this.lastClickRow + 1}. This cannot be undone.`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Keep It',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Delete It',
|
||||
handler: () => {
|
||||
const newRows = this.rowData.filter((x, i) => {
|
||||
return i !== this.lastClickRow;
|
||||
});
|
||||
|
||||
this.rowData = newRows;
|
||||
this.agGridElement.api.setRowData(this.rowData);
|
||||
this.lastClickRow = -1;
|
||||
},
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
}
|
||||
|
||||
async onDropDatabase() {
|
||||
const alert = await this.alerts.create({
|
||||
header: 'Are you sure?',
|
||||
message: `You are about to delete this database and all its entries. This action cannot be undone.`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Keep It',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Delete It',
|
||||
handler: async () => {
|
||||
this.api.post(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/drop/${this.hostRecord.Value.Value}`).subscribe();
|
||||
this.requestParentDelete.emit(this);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
}
|
||||
|
||||
onRowClicked($event) {
|
||||
this.lastClickRow = $event.rowIndex;
|
||||
}
|
||||
|
||||
getDataLoadObservable(): Observable<any> {
|
||||
return new Observable<any>(sub => {
|
||||
this.api.get(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}/data`).subscribe(res => {
|
||||
this.rowData = res.data.map(x => x.RowData);
|
||||
this.agGridElement.api.setRowData(this.rowData);
|
||||
sub.next();
|
||||
sub.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onSyncRecords() {
|
||||
this.api.post(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}/data`, this.rowData)
|
||||
.subscribe(res => {
|
||||
this.rowData = res.data.map(x => x.RowData);
|
||||
this.agGridElement.api.setRowData(this.rowData);
|
||||
this.dirty = false;
|
||||
});
|
||||
}
|
||||
|
||||
getColumnLoadObservable(): Observable<any> {
|
||||
return new Observable<any>(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 = 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;
|
||||
});
|
||||
sub.next();
|
||||
sub.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getInitObservable(): Observable<any> {
|
||||
return new Observable<any>(sub => {
|
||||
if ( this.hostRecord && this.pendingSetup ) {
|
||||
if ( !this.hostRecord.Value.Value ) {
|
||||
this.api.post(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/create`).subscribe(res => {
|
||||
this.dbRecord = res.data;
|
||||
this.hostRecord.Value.Mode = 'database';
|
||||
this.hostRecord.Value.Value = res.data.UUID;
|
||||
this.hostRecord.value = res.data.UUID;
|
||||
this.hostRecordChange.emit(this.hostRecord);
|
||||
this.pendingSetup = false;
|
||||
sub.next(true);
|
||||
sub.complete();
|
||||
});
|
||||
} else {
|
||||
this.api.get(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}`).subscribe(res => {
|
||||
this.dbRecord = res.data;
|
||||
this.pendingSetup = false;
|
||||
sub.next(true);
|
||||
sub.complete();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.pendingSetup = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -23,4 +23,15 @@
|
||||
[innerHTML]="listLines[i]"
|
||||
></li>
|
||||
</ul>
|
||||
<div
|
||||
*ngIf="record.type === 'database_ref'"
|
||||
class="db-wrapper"
|
||||
>
|
||||
<editor-database
|
||||
[hostRecord]="record"
|
||||
(hostRecordChange)="onRecordChange($event)"
|
||||
(requestParentSave)="onRequestParentSave($event)"
|
||||
(requestParentDelete)="onRequestDelete($event)"
|
||||
></editor-database>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@ -1,24 +0,0 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { HostComponent } from './host.component';
|
||||
|
||||
describe('HostComponent', () => {
|
||||
let component: HostComponent;
|
||||
let fixture: ComponentFixture<HostComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ HostComponent ],
|
||||
imports: [IonicModule.forRoot()]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HostComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -11,6 +11,7 @@ export class HostComponent implements OnInit {
|
||||
@Output() recordChange = new EventEmitter<HostRecord>();
|
||||
@Output() newHostRequested = new EventEmitter<HostComponent>();
|
||||
@Output() destroyHostRequested = new EventEmitter<HostComponent>();
|
||||
@Output() saveHostRequested = new EventEmitter<HostComponent>();
|
||||
@ViewChild('hostContainer', {static: false}) hostContainer: ElementRef;
|
||||
@ViewChildren('liItems') liItems;
|
||||
|
||||
@ -20,6 +21,11 @@ export class HostComponent implements OnInit {
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onRecordChange($event) {
|
||||
console.log({$event});
|
||||
this.recordChange.emit($event);
|
||||
}
|
||||
|
||||
onKeyUp($event) {
|
||||
const innerText = this.hostContainer.nativeElement.innerText.trim()
|
||||
if ( $event.code === 'Enter'
|
||||
@ -45,8 +51,8 @@ export class HostComponent implements OnInit {
|
||||
this.record.type = 'block_code';
|
||||
} else if ( innerText.startsWith('http') ) {
|
||||
this.record.type = 'click_link';
|
||||
} else if ( innerText.startsWith('-') || innerText.startsWith(' -') ) {
|
||||
this.record.type = 'ul';
|
||||
} else if ( false && innerText.startsWith('-') || innerText.startsWith(' -') ) {
|
||||
// this.record.type = 'ul';
|
||||
this.listLines = [this.record.value];
|
||||
setTimeout(() => {
|
||||
const item = this.liItems.toArray()[0].nativeElement;
|
||||
@ -57,15 +63,17 @@ export class HostComponent implements OnInit {
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
}, 0);
|
||||
} else {
|
||||
this.record.type = 'paragraph';
|
||||
}
|
||||
}
|
||||
|
||||
onRequestDelete($event) {
|
||||
this.destroyHostRequested.emit(this);
|
||||
}
|
||||
|
||||
onLIKeyUp($event, i) {
|
||||
console.log({$event});
|
||||
if ( $event.code === 'Enter' ) {
|
||||
const newListLines = [];
|
||||
/*const newListLines = [];
|
||||
this.liItems.forEach((li, index) => {
|
||||
newListLines.push(li.nativeElement.innerText.trim());
|
||||
if ( index === i ) {
|
||||
@ -73,7 +81,7 @@ export class HostComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
|
||||
this.listLines = newListLines;
|
||||
this.listLines = newListLines;*/
|
||||
// this.listLines[i] = this.liItems[i].innerText.trim()
|
||||
// const newLines = []
|
||||
// this.listLines.forEach((rec, x) => {
|
||||
@ -98,6 +106,10 @@ export class HostComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
onRequestParentSave($event) {
|
||||
this.saveHostRequested.emit(this);
|
||||
}
|
||||
|
||||
onHostDblClick() {
|
||||
if ( this.record.type === 'click_link' ) {
|
||||
window.open(this.record.value.trim(), '_blank');
|
||||
|
@ -1,33 +1,33 @@
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('paragraph')">
|
||||
<ion-icon slot="start" name="menu"></ion-icon>
|
||||
<ion-label>Paragraph</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('header1')">
|
||||
<ion-icon slot="start" name="alert"></ion-icon>
|
||||
<ion-label>Heading 1</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('header2')">
|
||||
<ion-icon slot="start" name="alert"></ion-icon>
|
||||
<ion-label>Heading 2</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('header3')">
|
||||
<ion-icon slot="start" name="alert"></ion-icon>
|
||||
<ion-label>Heading 3</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('header4')">
|
||||
<ion-icon slot="start" name="alert"></ion-icon>
|
||||
<ion-label>Heading 4</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('block_code')">
|
||||
<ion-icon slot="start" name="code"></ion-icon>
|
||||
<ion-label>Monospace Block</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('click_link')">
|
||||
<ion-icon slot="start" name="link"></ion-icon>
|
||||
<ion-label>Hyperlink</ion-label>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-item button (click)="onSelect('database_ref')">
|
||||
<ion-icon slot="start" name="analytics"></ion-icon>
|
||||
<ion-label>Database</ion-label>
|
||||
</ion-item>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {PopoverController} from '@ionic/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'editor-node-picker',
|
||||
@ -7,8 +8,14 @@ import { Component, OnInit } from '@angular/core';
|
||||
})
|
||||
export class NodePickerComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
constructor(
|
||||
private popover: PopoverController,
|
||||
) { }
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
onSelect(value: string) {
|
||||
this.popover.dismiss(value).then(() => {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,14 +18,15 @@
|
||||
<ng-container>
|
||||
<div class="editor-root ion-padding">
|
||||
<div class="host-container ion-padding">
|
||||
<editor-host #editorHosts *ngFor="let record of hostRecords; let i = index" [(record)]="hostRecords[i]"
|
||||
(newHostRequested)="onNewHostRequested($event)" (destroyHostRequested)="onDestroyHostRequested($event)">
|
||||
<editor-host #editorHosts *ngFor="let record of hostRecords; let i = index" [record]="hostRecords[i]" (recordChange)="onHostRecordChange($event, i)"
|
||||
(newHostRequested)="onNewHostRequested($event)" (destroyHostRequested)="onDestroyHostRequested($event)"
|
||||
(saveHostRequested)="onSaveClick()">
|
||||
</editor-host>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-buttons">
|
||||
<ion-button (click)="onAddClick($event)" class="ion-padding ion-margin" fill="outline" color="medium">Add Node</ion-button>
|
||||
<ion-button (click)="onSaveClick()" class="ion-padding ion-margin" fill="outline" color="medium">Save</ion-button>
|
||||
<ion-button (click)="onAddClick($event)" class="ion-padding ion-margin-start" fill="outline" color="medium">Add Node</ion-button>
|
||||
<ion-button (click)="onSaveClick()" class="ion-padding" fill="outline" color="medium">Save</ion-button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ion-content>
|
||||
|
@ -28,6 +28,8 @@ export class EditorPage implements OnInit {
|
||||
this.route.params.subscribe(params => {
|
||||
this.pageId = params.id;
|
||||
});
|
||||
|
||||
console.log('editor page', this);
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
@ -45,18 +47,9 @@ export class EditorPage implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
/*onAddClick() {
|
||||
this.hostRecords.push(new HostRecord(''));
|
||||
setTimeout(() => {
|
||||
const host = this.editorHosts.toArray().reverse()[0].hostContainer.nativeElement;
|
||||
const s = window.getSelection();
|
||||
const r = document.createRange();
|
||||
r.setStart(host, 0);
|
||||
r.setEnd(host, 0);
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
}, 0);
|
||||
}*/
|
||||
onHostRecordChange($event, i) {
|
||||
this.hostRecords[i] = $event;
|
||||
}
|
||||
|
||||
async onAddClick($event) {
|
||||
const popover = await this.popover.create({
|
||||
@ -64,9 +57,52 @@ export class EditorPage implements OnInit {
|
||||
event: $event,
|
||||
});
|
||||
|
||||
popover.onDidDismiss().then(arg => {
|
||||
console.log({arg});
|
||||
const defValue = this.getDefaultValue(arg.data);
|
||||
const hostRec = new HostRecord(defValue);
|
||||
console.log({hostRec});
|
||||
hostRec.type = arg.data;
|
||||
hostRec.PageId = this.pageRecord.UUID;
|
||||
this.hostRecords.push(hostRec);
|
||||
if ( hostRec.isNorm() ) {
|
||||
setTimeout(() => {
|
||||
const host = this.editorHosts.toArray().reverse()[0].hostContainer.nativeElement;
|
||||
const s = window.getSelection();
|
||||
const r = document.createRange();
|
||||
r.setStart(host, defValue.length);
|
||||
r.setEnd(host, defValue.length);
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
}, 0);
|
||||
} else {
|
||||
this.onSaveClick();
|
||||
}
|
||||
});
|
||||
|
||||
await popover.present();
|
||||
}
|
||||
|
||||
getDefaultValue(type: string) {
|
||||
if ( type === 'paragraph' ) {
|
||||
return '';
|
||||
} else if ( type === 'header1' ) {
|
||||
return '# ';
|
||||
} else if ( type === 'header2' ) {
|
||||
return '## ';
|
||||
} else if ( type === 'header3' ) {
|
||||
return '### ';
|
||||
} else if ( type === 'header4' ) {
|
||||
return '#### ';
|
||||
} else if ( type === 'block_code' ) {
|
||||
return '```';
|
||||
} else if ( type === 'click_link' ) {
|
||||
return 'https://';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
onNewHostRequested($event) {
|
||||
const insertAfter = this.getIndexFromRecord($event.record);
|
||||
const record = new HostRecord('');
|
||||
|
@ -52,6 +52,7 @@ export class PageService {
|
||||
}
|
||||
|
||||
save_nodes(page: PageRecord, nodes: Array<HostRecord>): Observable<Array<HostRecord>> {
|
||||
console.log('save nodes', {nodes})
|
||||
return new Observable<Array<HostRecord>>(sub => {
|
||||
nodes = nodes.map(x => {
|
||||
x.PageId = page.UUID;
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default class HostRecord {
|
||||
public value = '';
|
||||
public type: 'paragraph'|'header1'|'header2'|'header3'|'header4'|'block_code'|'click_link'|'ul' = 'paragraph';
|
||||
public type: 'paragraph'|'header1'|'header2'|'header3'|'header4'|'block_code'|'click_link'|'database_ref' = 'paragraph';
|
||||
|
||||
public CreatedAt: string;
|
||||
public PageId: string;
|
||||
@ -12,6 +12,10 @@ export default class HostRecord {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public isNorm() {
|
||||
return ['paragraph', 'header1', 'header2', 'header3', 'header4', 'block_code', 'click_link'].includes(this.type);
|
||||
}
|
||||
|
||||
load(data: any) {
|
||||
this.type = data.Type;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user