Add VSCode editor component
This commit is contained in:
parent
b5d2f64fd3
commit
f4c86a06e2
@ -29,6 +29,11 @@
|
|||||||
"glob": "**/*.svg",
|
"glob": "**/*.svg",
|
||||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||||
"output": "./svg"
|
"output": "./svg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "node_modules/ngx-monaco-editor/assets/monaco",
|
||||||
|
"output": "./assets/monaco/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@ -7099,6 +7099,14 @@
|
|||||||
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
|
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ngx-monaco-editor": {
|
||||||
|
"version": "8.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ngx-monaco-editor/-/ngx-monaco-editor-8.1.1.tgz",
|
||||||
|
"integrity": "sha512-SmUGFG5m2HHWybHD6qXdB1FrtC/XySSHm5O/E1cDGW7moIWzJGqiitCKLJdSh9D2hsoe8oBNEg74vYF1UGznsQ==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^1.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
@ -10369,8 +10377,7 @@
|
|||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"validate-npm-package-license": {
|
"validate-npm-package-license": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
|
@ -27,8 +27,10 @@
|
|||||||
"ag-grid-community": "^22.1.1",
|
"ag-grid-community": "^22.1.1",
|
||||||
"angular-tree-component": "^8.5.2",
|
"angular-tree-component": "^8.5.2",
|
||||||
"core-js": "^2.5.4",
|
"core-js": "^2.5.4",
|
||||||
|
"ngx-monaco-editor": "^8.1.1",
|
||||||
"rxjs": "~6.5.1",
|
"rxjs": "~6.5.1",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
|
"uuid": "^3.4.0",
|
||||||
"zone.js": "~0.9.1"
|
"zone.js": "~0.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -12,6 +12,7 @@ import { HttpClientModule } from '@angular/common/http';
|
|||||||
import { ComponentsModule } from './components/components.module';
|
import { ComponentsModule } from './components/components.module';
|
||||||
import { TreeModule } from 'angular-tree-component';
|
import { TreeModule } from 'angular-tree-component';
|
||||||
import {AgGridModule} from 'ag-grid-angular';
|
import {AgGridModule} from 'ag-grid-angular';
|
||||||
|
import {MonacoEditorModule} from 'ngx-monaco-editor';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
@ -24,6 +25,7 @@ import {AgGridModule} from 'ag-grid-angular';
|
|||||||
ComponentsModule,
|
ComponentsModule,
|
||||||
TreeModule.forRoot(),
|
TreeModule.forRoot(),
|
||||||
AgGridModule.withComponents([]),
|
AgGridModule.withComponents([]),
|
||||||
|
MonacoEditorModule.forRoot(),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
StatusBar,
|
StatusBar,
|
||||||
|
@ -7,11 +7,13 @@ import {DatabaseComponent} from './editor/database/database.component';
|
|||||||
import {AgGridModule} from 'ag-grid-angular';
|
import {AgGridModule} from 'ag-grid-angular';
|
||||||
import {ColumnsComponent} from './editor/database/columns/columns.component';
|
import {ColumnsComponent} from './editor/database/columns/columns.component';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {CodeComponent} from './editor/code/code.component';
|
||||||
|
import {MonacoEditorModule} from 'ngx-monaco-editor';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent],
|
declarations: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent],
|
||||||
imports: [CommonModule, IonicModule, AgGridModule, FormsModule],
|
imports: [CommonModule, IonicModule, AgGridModule, FormsModule, MonacoEditorModule],
|
||||||
entryComponents: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent],
|
entryComponents: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent],
|
||||||
exports: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent]
|
exports: [HostComponent, NodePickerComponent, DatabaseComponent, ColumnsComponent, CodeComponent]
|
||||||
})
|
})
|
||||||
export class ComponentsModule {}
|
export class ComponentsModule {}
|
||||||
|
24
src/app/components/editor/code/code.component.html
Normal file
24
src/app/components/editor/code/code.component.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<div class="code-wrapper" style="width: 100%; height: 600px; margin-top: 10px;">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">Language</ion-label>
|
||||||
|
<ion-select style="min-width: 40px;" [(ngModel)]="editorOptions.language" (ionChange)="onSelectChange()">
|
||||||
|
<ion-select-option *ngFor="let lang of languageOptions" [value]="lang.toLowerCase()">{{lang}}</ion-select-option>
|
||||||
|
</ion-select>
|
||||||
|
</ion-item>
|
||||||
|
</ion-toolbar>
|
||||||
|
<div class="ed-wrapper" style="width: 100%; height: 480px;">
|
||||||
|
<ngx-monaco-editor style="width: 100%; height: 100%;"
|
||||||
|
[options]="editorOptions"
|
||||||
|
[(ngModel)]="editorValue"
|
||||||
|
(ngModelChange)="onEditorModelChange($event)"
|
||||||
|
#theEditor
|
||||||
|
></ngx-monaco-editor>
|
||||||
|
</div>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button (click)="onDropClick()"><ion-icon name="alert" color="danger"></ion-icon> Drop Editor</ion-button>
|
||||||
|
<ion-button (click)="onSaveClick()"><ion-icon name="save" [color]="dirty ? 'warning' : 'success'"></ion-icon> Save Changes</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</div>
|
4
src/app/components/editor/code/code.component.scss
Normal file
4
src/app/components/editor/code/code.component.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
div.code-wrapper {
|
||||||
|
border: 2px solid #8c8c8c;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
198
src/app/components/editor/code/code.component.ts
Normal file
198
src/app/components/editor/code/code.component.ts
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
|
||||||
|
import {v4} from 'uuid';
|
||||||
|
import HostRecord from '../../../structures/HostRecord';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {ApiService} from '../../../service/api.service';
|
||||||
|
import {AlertController, LoadingController} from '@ionic/angular';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'editor-code',
|
||||||
|
templateUrl: './code.component.html',
|
||||||
|
styleUrls: ['./code.component.scss'],
|
||||||
|
})
|
||||||
|
export class CodeComponent implements OnInit {
|
||||||
|
@Input() hostRecord: HostRecord;
|
||||||
|
@Output() hostRecordChange = new EventEmitter<HostRecord>();
|
||||||
|
@Output() requestParentSave = new EventEmitter<CodeComponent>();
|
||||||
|
@Output() requestParentDelete = new EventEmitter<CodeComponent>();
|
||||||
|
@ViewChild('theEditor', {static: false}) theEditor;
|
||||||
|
|
||||||
|
public dirty = false;
|
||||||
|
public pendingSetup = true;
|
||||||
|
protected dbRecord: any = {};
|
||||||
|
|
||||||
|
public languageOptions: Array<string> = [
|
||||||
|
'ABAP',
|
||||||
|
'AES',
|
||||||
|
'Apex',
|
||||||
|
'AZCLI',
|
||||||
|
'Bat',
|
||||||
|
'C',
|
||||||
|
'Cameligo',
|
||||||
|
'Clojure',
|
||||||
|
'CoffeeScript',
|
||||||
|
'Cpp',
|
||||||
|
'Csharp',
|
||||||
|
'CSP',
|
||||||
|
'CSS',
|
||||||
|
'Dockerfile',
|
||||||
|
'Fsharp',
|
||||||
|
'Go',
|
||||||
|
'GraphQL',
|
||||||
|
'Handlebars',
|
||||||
|
'HTML',
|
||||||
|
'INI',
|
||||||
|
'Java',
|
||||||
|
'JavaScript',
|
||||||
|
'JSON',
|
||||||
|
'Kotlin',
|
||||||
|
'LeSS',
|
||||||
|
'Lua',
|
||||||
|
'Markdown',
|
||||||
|
'MiPS',
|
||||||
|
'MSDAX',
|
||||||
|
'MySQL',
|
||||||
|
'Objective-C',
|
||||||
|
'Pascal',
|
||||||
|
'Pascaligo',
|
||||||
|
'Perl',
|
||||||
|
'pgSQL',
|
||||||
|
'PHP',
|
||||||
|
'Plaintext',
|
||||||
|
'Postiats',
|
||||||
|
'PowerQuery',
|
||||||
|
'PowerShell',
|
||||||
|
'Pug',
|
||||||
|
'Python',
|
||||||
|
'R',
|
||||||
|
'Razor',
|
||||||
|
'Redis',
|
||||||
|
'RedShift',
|
||||||
|
'RestructuredText',
|
||||||
|
'Ruby',
|
||||||
|
'Rust',
|
||||||
|
'SB',
|
||||||
|
'Scheme',
|
||||||
|
'SCSS',
|
||||||
|
'Shell',
|
||||||
|
'SOL',
|
||||||
|
'SQL',
|
||||||
|
'St',
|
||||||
|
'Swift',
|
||||||
|
'TCL',
|
||||||
|
'Twig',
|
||||||
|
'TypeScript',
|
||||||
|
'VB',
|
||||||
|
'XML',
|
||||||
|
'YAML',
|
||||||
|
];
|
||||||
|
|
||||||
|
public editorOptions = {
|
||||||
|
language: 'javascript',
|
||||||
|
uri: v4(),
|
||||||
|
};
|
||||||
|
public editorValue = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected api: ApiService,
|
||||||
|
protected loader: LoadingController,
|
||||||
|
protected alerts: AlertController,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.loader.create({message: 'Loading code...'}).then(loader => {
|
||||||
|
loader.present().then(() => {
|
||||||
|
this.getInitObservable().subscribe(() => {
|
||||||
|
this.editorOptions.language = this.dbRecord.language;
|
||||||
|
this.onSelectChange(false);
|
||||||
|
loader.dismiss();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitObservable(): Observable<any> {
|
||||||
|
return new Observable<any>(sub => {
|
||||||
|
if ( this.hostRecord && this.pendingSetup ) {
|
||||||
|
if ( !this.hostRecord.Value ) {
|
||||||
|
this.hostRecord.Value = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !this.hostRecord.Value.Value ) {
|
||||||
|
this.api.post(`/code/${this.hostRecord.PageId}/${this.hostRecord.UUID}/create`).subscribe(res => {
|
||||||
|
this.dbRecord = res.data;
|
||||||
|
this.hostRecord.Value.Mode = 'code';
|
||||||
|
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(`/code/${this.hostRecord.PageId}/${this.hostRecord.UUID}/get/${this.hostRecord.Value.Value}`).subscribe(res => {
|
||||||
|
this.dbRecord = res.data;
|
||||||
|
this.editorValue = this.dbRecord.code;
|
||||||
|
this.editorOptions.language = this.dbRecord.language;
|
||||||
|
this.pendingSetup = false;
|
||||||
|
sub.next(true);
|
||||||
|
sub.complete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.pendingSetup = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
this.dbRecord.code = this.editorValue;
|
||||||
|
this.dbRecord.language = this.editorOptions.language;
|
||||||
|
this.api.post(`/code/${this.hostRecord.PageId}/${this.hostRecord.UUID}/set/${this.hostRecord.Value.Value}`, this.dbRecord)
|
||||||
|
.subscribe(res => {
|
||||||
|
this.dbRecord = res.data;
|
||||||
|
this.editorOptions.language = this.dbRecord.language;
|
||||||
|
this.editorValue = this.dbRecord.code;
|
||||||
|
this.dirty = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onDropClick() {
|
||||||
|
const alert = await this.alerts.create({
|
||||||
|
header: 'Are you sure?',
|
||||||
|
message: `You are about to delete this code. This action cannot be undone.`,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: 'Keep It',
|
||||||
|
role: 'cancel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Delete It',
|
||||||
|
handler: async () => {
|
||||||
|
this.api.post(`/code/${this.hostRecord.PageId}/${this.hostRecord.UUID}/delete/${this.hostRecord.Value.Value}`)
|
||||||
|
.subscribe(res => {
|
||||||
|
this.requestParentDelete.emit(this);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEditorModelChange($event) {
|
||||||
|
if ( this.editorValue !== this.dbRecord.code ) {
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectChange(updateDbRecord = true) {
|
||||||
|
if ( updateDbRecord ) {
|
||||||
|
this.dbRecord.language = this.editorOptions.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editorOptions = {...this.editorOptions};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -203,6 +203,9 @@ export class DatabaseComponent implements OnInit {
|
|||||||
getInitObservable(): Observable<any> {
|
getInitObservable(): Observable<any> {
|
||||||
return new Observable<any>(sub => {
|
return new Observable<any>(sub => {
|
||||||
if ( this.hostRecord && this.pendingSetup ) {
|
if ( this.hostRecord && this.pendingSetup ) {
|
||||||
|
if ( !this.hostRecord.Value ) {
|
||||||
|
this.hostRecord.Value = {};
|
||||||
|
}
|
||||||
if ( !this.hostRecord.Value.Value ) {
|
if ( !this.hostRecord.Value.Value ) {
|
||||||
this.api.post(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/create`).subscribe(res => {
|
this.api.post(`/db/${this.hostRecord.PageId}/${this.hostRecord.UUID}/create`).subscribe(res => {
|
||||||
this.dbRecord = res.data;
|
this.dbRecord = res.data;
|
||||||
|
@ -34,4 +34,12 @@
|
|||||||
(requestParentDelete)="onRequestDelete($event)"
|
(requestParentDelete)="onRequestDelete($event)"
|
||||||
></editor-database>
|
></editor-database>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="code-wrapper" *ngIf="record.type === 'code_ref'">
|
||||||
|
<editor-code
|
||||||
|
[hostRecord]="record"
|
||||||
|
(hostRecordChange)="onRecordChange($event)"
|
||||||
|
(requestParentSave)="onRequestParentSave($event)"
|
||||||
|
(requestParentDelete)="onRequestDelete($event)"
|
||||||
|
></editor-code>
|
||||||
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -22,7 +22,6 @@ export class HostComponent implements OnInit {
|
|||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
onRecordChange($event) {
|
onRecordChange($event) {
|
||||||
console.log({$event});
|
|
||||||
this.recordChange.emit($event);
|
this.recordChange.emit($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<ion-label>Heading 4</ion-label>
|
<ion-label>Heading 4</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item button (click)="onSelect('block_code')">
|
<ion-item button (click)="onSelect('block_code')">
|
||||||
<ion-icon slot="start" name="code"></ion-icon>
|
<ion-icon slot="start" name="information"></ion-icon>
|
||||||
<ion-label>Monospace Block</ion-label>
|
<ion-label>Monospace Block</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item button (click)="onSelect('click_link')">
|
<ion-item button (click)="onSelect('click_link')">
|
||||||
@ -31,4 +31,8 @@
|
|||||||
<ion-icon slot="start" name="analytics"></ion-icon>
|
<ion-icon slot="start" name="analytics"></ion-icon>
|
||||||
<ion-label>Database</ion-label>
|
<ion-label>Database</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item button (click)="onSelect('code_ref')">
|
||||||
|
<ion-icon slot="start" name="code"></ion-icon>
|
||||||
|
<ion-label>Code Editor</ion-label>
|
||||||
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export default class HostRecord {
|
export default class HostRecord {
|
||||||
public value = '';
|
public value = '';
|
||||||
public type: 'paragraph'|'header1'|'header2'|'header3'|'header4'|'block_code'|'click_link'|'database_ref'|'ul' = 'paragraph';
|
public type: 'paragraph'|'header1'|'header2'|'header3'|'header4'|'block_code'|'click_link'|'database_ref'|'ul'|'code_ref' = 'paragraph';
|
||||||
|
|
||||||
public CreatedAt: string;
|
public CreatedAt: string;
|
||||||
public PageId: string;
|
public PageId: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user