editor-refactor #18
15
package-lock.json
generated
15
package-lock.json
generated
@ -1935,6 +1935,21 @@
|
|||||||
"schema-utils": "^2.7.0"
|
"schema-utils": "^2.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ng-stack/contenteditable": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ng-stack/contenteditable/-/contenteditable-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-bmu0PFWNgAw+shTDlQQV6gBiUcbp6VEwl51fGCUci5GAhKtLwYEe/biPA6Q6tsqSP4l1/XV/HUvroKek1+csOg==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@ngtools/webpack": {
|
"@ngtools/webpack": {
|
||||||
"version": "10.1.6",
|
"version": "10.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.1.6.tgz",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"@ionic-native/splash-screen": "^5.0.0",
|
"@ionic-native/splash-screen": "^5.0.0",
|
||||||
"@ionic-native/status-bar": "^5.0.0",
|
"@ionic-native/status-bar": "^5.0.0",
|
||||||
"@ionic/angular": "^5.3.5",
|
"@ionic/angular": "^5.3.5",
|
||||||
|
"@ng-stack/contenteditable": "^1.1.0",
|
||||||
"ag-grid-angular": "^22.1.1",
|
"ag-grid-angular": "^22.1.1",
|
||||||
"ag-grid-community": "^22.1.1",
|
"ag-grid-community": "^22.1.1",
|
||||||
"core-js": "^2.5.4",
|
"core-js": "^2.5.4",
|
||||||
|
@ -6,7 +6,8 @@ import {IonicModule} from '@ionic/angular';
|
|||||||
import {DatabaseComponent} from './editor/database/database.component';
|
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, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {ContenteditableModule} from '@ng-stack/contenteditable';
|
||||||
import {CodeComponent} from './editor/code/code.component';
|
import {CodeComponent} from './editor/code/code.component';
|
||||||
import {MonacoEditorModule} from 'ngx-monaco-editor';
|
import {MonacoEditorModule} from 'ngx-monaco-editor';
|
||||||
import {FilesComponent} from './editor/files/files.component';
|
import {FilesComponent} from './editor/files/files.component';
|
||||||
@ -27,6 +28,7 @@ import {BooleanRendererComponent} from './editor/database/renderers/boolean-rend
|
|||||||
import {SearchComponent} from './search/Search.component';
|
import {SearchComponent} from './search/Search.component';
|
||||||
|
|
||||||
import {NormComponent} from './nodes/norm/norm.component';
|
import {NormComponent} from './nodes/norm/norm.component';
|
||||||
|
import {DirectivesModule} from '../directives/directives.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -59,7 +61,10 @@ import {NormComponent} from './nodes/norm/norm.component';
|
|||||||
IonicModule,
|
IonicModule,
|
||||||
AgGridModule,
|
AgGridModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MonacoEditorModule
|
ReactiveFormsModule,
|
||||||
|
ContenteditableModule,
|
||||||
|
MonacoEditorModule,
|
||||||
|
DirectivesModule,
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
HostComponent,
|
HostComponent,
|
||||||
|
@ -3,6 +3,7 @@ import PageRecord from '../../structures/PageRecord';
|
|||||||
export abstract class EditorNodeContract {
|
export abstract class EditorNodeContract {
|
||||||
protected pageRec!: PageRecord;
|
protected pageRec!: PageRecord;
|
||||||
protected nodeRec!: any; // TODO
|
protected nodeRec!: any; // TODO
|
||||||
|
protected initialValue: any;
|
||||||
|
|
||||||
get page() {
|
get page() {
|
||||||
return this.pageRec;
|
return this.pageRec;
|
||||||
|
@ -1,66 +1,68 @@
|
|||||||
<div class="container"
|
<div class="container"
|
||||||
(focusin)="onFocusIn($event)"
|
(focusin)="onFocusIn($event)"
|
||||||
(focusout)="onFocusOut($event)">
|
(focusout)="onFocusIn($event)">
|
||||||
<div class="toolbar-base" *ngIf="isFocused">
|
<div class="toolbar-base" *ngIf="isFocused">
|
||||||
<div class="toolbar-button" title="Bold">
|
<button class="toolbar-button" title="Bold" (click)="documentCommand('bold')">
|
||||||
<i class="icon fa fa-bold"></i>
|
<i class="icon fa fa-bold"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Italic">
|
<button class="toolbar-button" title="Italic" (click)="documentCommand('italic')">
|
||||||
<i class="icon fa fa-italic"></i>
|
<i class="icon fa fa-italic"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Underline">
|
<button class="toolbar-button" title="Underline" (click)="documentCommand('underline')">
|
||||||
<i class="icon fa fa-underline"></i>
|
<i class="icon fa fa-underline"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Strikethrough">
|
<button class="toolbar-button" title="Strikethrough" (click)="documentCommand('strikeThrough')">
|
||||||
<i class="icon fa fa-strikethrough"></i>
|
<i class="icon fa fa-strikethrough"></i>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<div class="toolbar-button" title="Align Right">
|
<button class="toolbar-button" title="Align Left" (click)="documentCommand('justifyLeft')">
|
||||||
<i class="icon fa fa-align-right"></i>
|
|
||||||
</div>
|
|
||||||
<div class="toolbar-button" title="Align Center">
|
|
||||||
<i class="icon fa fa-align-center"></i>
|
|
||||||
</div>
|
|
||||||
<div class="toolbar-button" title="Align Left">
|
|
||||||
<i class="icon fa fa-align-left"></i>
|
<i class="icon fa fa-align-left"></i>
|
||||||
</div>
|
</button>
|
||||||
|
<button class="toolbar-button" title="Align Center" (click)="documentCommand('justifyCenter')">
|
||||||
|
<i class="icon fa fa-align-center"></i>
|
||||||
|
</button>
|
||||||
|
<button class="toolbar-button" title="Align Right" (click)="documentCommand('justifyRight')">
|
||||||
|
<i class="icon fa fa-align-right"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<div class="toolbar-button" title="Undo">
|
<button class="toolbar-button" title="Undo" (click)="documentCommand('undo')">
|
||||||
<i class="icon fa fa-undo"></i>
|
<i class="icon fa fa-undo"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Redo">
|
<button class="toolbar-button" title="Redo" (click)="documentCommand('redo')">
|
||||||
<i class="icon fa fa-redo"></i>
|
<i class="icon fa fa-redo"></i>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<div class="toolbar-button" title="Increase Heading Level">
|
<button class="toolbar-button" title="Increase Heading Level">
|
||||||
<i class="icon fa fa-heading"></i>
|
<i class="icon fa fa-heading"></i>
|
||||||
<i class="icon fa fa-long-arrow-alt-up"></i>
|
<i class="icon fa fa-long-arrow-alt-up"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Decrease Heading Level">
|
<button class="toolbar-button" title="Decrease Heading Level">
|
||||||
<i class="icon fa fa-heading"></i>
|
<i class="icon fa fa-heading"></i>
|
||||||
<i class="icon fa fa-long-arrow-alt-down"></i>
|
<i class="icon fa fa-long-arrow-alt-down"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="toolbar-button" title="Format Monospace">
|
<button class="toolbar-button" title="Format Monospace">
|
||||||
<i class="icon fa fa-code"></i>
|
<i class="icon fa fa-code"></i>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
<div class="toolbar-sep"></div>
|
<div class="toolbar-sep"></div>
|
||||||
|
|
||||||
<div class="toolbar-button" title="Begin Bulleted List">
|
<button class="toolbar-button" title="Begin Bulleted List">
|
||||||
<i class="icon fa fa-list-ul"></i>
|
<i class="icon fa fa-list-ul"></i>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="editable-base"
|
class="editable-base"
|
||||||
[ngClass]="isFocused ? 'focused' : ''"
|
[ngClass]="isFocused ? 'focused' : ''"
|
||||||
contenteditable
|
contenteditable
|
||||||
>
|
appDomChange
|
||||||
Content editable!
|
[innerHTML]="initialValue"
|
||||||
</div>
|
#editable
|
||||||
|
(domChange)="onContentsChanged($event)"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
@ -1,4 +1,4 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component, ViewChild} from '@angular/core';
|
||||||
import {EditorNodeContract} from '../EditorNode.contract';
|
import {EditorNodeContract} from '../EditorNode.contract';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -7,10 +7,20 @@ import {EditorNodeContract} from '../EditorNode.contract';
|
|||||||
styleUrls: ['./norm.component.scss'],
|
styleUrls: ['./norm.component.scss'],
|
||||||
})
|
})
|
||||||
export class NormComponent extends EditorNodeContract {
|
export class NormComponent extends EditorNodeContract {
|
||||||
|
@ViewChild('editable') editable;
|
||||||
public isFocused = false;
|
public isFocused = false;
|
||||||
|
public initialValue = 'Content editable now...';
|
||||||
|
public contents = '';
|
||||||
|
private dirtyOverride = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
console.log('norm compt', this);
|
||||||
|
this.contents = this.initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
public isDirty(): boolean | Promise<boolean> {
|
public isDirty(): boolean | Promise<boolean> {
|
||||||
return false; // TODO implement
|
return this.dirtyOverride || this.contents !== this.initialValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocusIn(event: MouseEvent) {
|
onFocusIn(event: MouseEvent) {
|
||||||
@ -20,4 +30,16 @@ export class NormComponent extends EditorNodeContract {
|
|||||||
onFocusOut(event: MouseEvent) {
|
onFocusOut(event: MouseEvent) {
|
||||||
this.isFocused = false;
|
this.isFocused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
documentCommand(cmd: string) {
|
||||||
|
// Yes, technically this is deprecated, but it'll be poly-filled if necessary. Bite me.
|
||||||
|
document.execCommand(cmd, false, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
onContentsChanged(contents: string) {
|
||||||
|
const innerHTML = this.editable.nativeElement.innerHTML;
|
||||||
|
if ( this.contents !== innerHTML ) {
|
||||||
|
this.contents = innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
9
src/app/directives/directives.module.ts
Normal file
9
src/app/directives/directives.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {DomChangeDirective} from './dom-change.directive';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [],
|
||||||
|
exports: [DomChangeDirective],
|
||||||
|
declarations: [DomChangeDirective],
|
||||||
|
})
|
||||||
|
export class DirectivesModule {}
|
30
src/app/directives/dom-change.directive.ts
Normal file
30
src/app/directives/dom-change.directive.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import {Directive, ElementRef, EventEmitter, OnDestroy, Output} from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[appDomChange]'
|
||||||
|
})
|
||||||
|
export class DomChangeDirective implements OnDestroy {
|
||||||
|
private changes: MutationObserver;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
public domChange = new EventEmitter();
|
||||||
|
|
||||||
|
constructor(private elementRef: ElementRef) {
|
||||||
|
const element = this.elementRef.nativeElement;
|
||||||
|
|
||||||
|
this.changes = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach(mutation => this.domChange.emit(mutation));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.changes.observe(element, {
|
||||||
|
attributes: true,
|
||||||
|
childList: true,
|
||||||
|
characterData: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.changes.disconnect();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user