Add WYSIWYG column to database (#30)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
Garrett Mills 2020-11-10 08:35:29 -06:00
parent c76fc2e82a
commit 138723929e
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
9 changed files with 146 additions and 2 deletions

View File

@ -34,6 +34,8 @@ import {VersionModalComponent} from './version-modal/version-modal.component';
import {EditorPageRoutingModule} from '../pages/editor/editor-routing.module'; import {EditorPageRoutingModule} from '../pages/editor/editor-routing.module';
import {EditorPage} from '../pages/editor/editor.page'; import {EditorPage} from '../pages/editor/editor.page';
import {WysiwygComponent} from './wysiwyg/wysiwyg.component'; import {WysiwygComponent} from './wysiwyg/wysiwyg.component';
import {WysiwygEditorComponent} from './editor/database/editors/wysiwyg/wysiwyg-editor.component';
import {WysiwygModalComponent} from './editor/database/editors/wysiwyg/wysiwyg-modal.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -63,6 +65,8 @@ import {WysiwygComponent} from './wysiwyg/wysiwyg.component';
VersionModalComponent, VersionModalComponent,
EditorPage, EditorPage,
WysiwygComponent, WysiwygComponent,
WysiwygEditorComponent,
WysiwygModalComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -103,6 +107,8 @@ import {WysiwygComponent} from './wysiwyg/wysiwyg.component';
VersionModalComponent, VersionModalComponent,
EditorPage, EditorPage,
WysiwygComponent, WysiwygComponent,
WysiwygEditorComponent,
WysiwygModalComponent,
], ],
exports: [ exports: [
NodePickerComponent, NodePickerComponent,
@ -131,6 +137,8 @@ import {WysiwygComponent} from './wysiwyg/wysiwyg.component';
VersionModalComponent, VersionModalComponent,
EditorPage, EditorPage,
WysiwygComponent, WysiwygComponent,
WysiwygEditorComponent,
WysiwygModalComponent,
] ]
}) })
export class ComponentsModule {} export class ComponentsModule {}

View File

@ -28,6 +28,7 @@
<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="paragraph">Paragraph</ion-select-option> <ion-select-option value="paragraph">Paragraph</ion-select-option>
<ion-select-option value="wysiwyg">Rich-Text</ion-select-option>
<ion-select-option value="boolean">Boolean</ion-select-option> <ion-select-option value="boolean">Boolean</ion-select-option>
<ion-select-option value="select">Select</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="multiselect">Multi-Select</ion-select-option>

View File

@ -14,6 +14,7 @@ import {CurrencyRendererComponent} from './renderers/currency-renderer.component
import {BooleanRendererComponent} from './renderers/boolean-renderer.component'; import {BooleanRendererComponent} from './renderers/boolean-renderer.component';
import {EditorNodeContract} from '../../nodes/EditorNode.contract'; import {EditorNodeContract} from '../../nodes/EditorNode.contract';
import {EditorService} from '../../../service/editor.service'; import {EditorService} from '../../../service/editor.service';
import {WysiwygEditorComponent} from './editors/wysiwyg/wysiwyg-editor.component';
@Component({ @Component({
selector: 'editor-database', selector: 'editor-database',
@ -171,6 +172,8 @@ export class DatabaseComponent extends EditorNodeContract implements OnInit {
x.cellRendererFramework = CurrencyRendererComponent; x.cellRendererFramework = CurrencyRendererComponent;
} else if ( x.Type === 'index' ) { } else if ( x.Type === 'index' ) {
x.editable = false; x.editable = false;
} else if ( x.Type === 'wysiwyg' ) {
x.cellEditorFramework = WysiwygEditorComponent;
} }
return x; return x;

View File

@ -0,0 +1,61 @@
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 {WysiwygModalComponent} from './wysiwyg-modal.component';
@Component({
selector: 'cell-editor-wysiwyg',
template: `<input #input [(ngModel)]="value" readonly>`,
styles: [
`input {
width: 100%;
border: 1px solid grey;
}`
],
})
export class WysiwygEditorComponent implements ICellEditorAngularComp, AfterViewInit {
private params: ICellEditorParams;
public value: string;
@ViewChild('input') 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: WysiwygModalComponent,
componentProps: {
title: this.params.colDef.headerName,
value: this.value,
}
}).then(modal => {
modal.onDidDismiss().then(value => {
if ( typeof value.data === 'undefined' ) {
return;
}
this.value = String(value.data);
this.finishEdit();
});
modal.present();
});
});
}
finishEdit() {
this.params.stopEditing();
}
}

View File

@ -0,0 +1,24 @@
<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">
<wysiwyg-editor [contents]="value" (contentsChanged)="onContentsChanged($event)" [editonly]="true"></wysiwyg-editor>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
<ion-footer>
<ion-button fill="invisible" (click)="dismissModal()"><ion-icon name="save"></ion-icon>&nbsp;&nbsp;Save</ion-button>
</ion-footer>

View File

@ -0,0 +1,26 @@
import {Component, Input} from '@angular/core';
import {ModalController} from '@ionic/angular';
@Component({
selector: 'editor-wysiwyg-modal',
templateUrl: './wysiwyg-modal.component.html',
styleUrls: ['./wysiwyg-modal.component.scss'],
})
export class WysiwygModalComponent {
@Input() value = '';
@Input() title: string;
constructor(
protected modals: ModalController,
) {}
dismissModal() {
this.modals.dismiss(this.value);
}
onContentsChanged(contents: string) {
if ( this.value !== contents ) {
this.value = contents;
}
}
}

View File

@ -7,15 +7,17 @@
} }
.toolbar-base { .toolbar-base {
height: 40px; min-height: 40px;
border: 1px solid lightgray; border: 1px solid lightgray;
border-radius: 5px; border-radius: 5px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
.toolbar-button { .toolbar-button {
height: calc(100% - 6px); height: calc(100% - 6px);
min-width: 30px; min-width: 30px;
min-height: 40px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -29,6 +31,7 @@
.toolbar-sep { .toolbar-sep {
height: 100%; height: 100%;
min-height: 40px;
width: 1px; width: 1px;
border: 1px solid lightgrey; border: 1px solid lightgrey;
margin: 0 5px; margin: 0 5px;

View File

@ -14,9 +14,23 @@ export class WysiwygComponent implements OnInit {
public isFocused = false; public isFocused = false;
protected hadOneFocusOut = false; protected hadOneFocusOut = false;
public initialValue = ''; public initialValue = '';
protected isEditOnly = false;
public get editonly() {
return this.isEditOnly;
}
@Input()
public set editonly(val: boolean) {
this.isEditOnly = val;
if ( this.isEditOnly && !this.readonly ) {
this.isFocused = true;
}
}
public get displayContents() { public get displayContents() {
return this.contents.replace(/</g, '\n<').replace(/(https?:\/\/[^\s]+)/g, (val) => `<a href="${val}" target="_blank">${val}</a>`); return (this.contents || 'Double-click to edit...').replace(/</g, '\n<')
.replace(/(https?:\/\/[^\s]+)/g, (val) => `<a href="${val}" target="_blank">${val}</a>`);
} }
public isDark() { public isDark() {
@ -34,6 +48,10 @@ export class WysiwygComponent implements OnInit {
@HostListener('document:keyup.escape', ['$event']) @HostListener('document:keyup.escape', ['$event'])
onFocusOut(event) { onFocusOut(event) {
if ( this.isEditOnly ) {
return;
}
if ( !this.hadOneFocusOut ) { if ( !this.hadOneFocusOut ) {
this.hadOneFocusOut = true; this.hadOneFocusOut = true;
setTimeout(() => { setTimeout(() => {