diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index b464e7d..70e847d 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -14,6 +14,10 @@ const routes: Routes = [
{
path: 'list',
loadChildren: () => import('./list/list.module').then(m => m.ListPageModule)
+ },
+ {
+ path: 'editor',
+ loadChildren: () => import('./pages/editor/editor.module').then( m => m.EditorPageModule)
}
];
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index c013bef..b5cd3cc 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -20,6 +20,11 @@ export class AppComponent {
title: 'List',
url: '/list',
icon: 'list'
+ },
+ {
+ title: 'Editor',
+ url: '/editor',
+ icon: 'edit'
}
];
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 0726cf5..5b66ac9 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -9,6 +9,7 @@ import { StatusBar } from '@ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import {HttpClientModule} from '@angular/common/http';
+import {ComponentsModule} from './components/components.module';
@NgModule({
declarations: [AppComponent],
@@ -18,6 +19,7 @@ import {HttpClientModule} from '@angular/common/http';
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule,
+ ComponentsModule,
],
providers: [
StatusBar,
diff --git a/src/app/components/components.module.ts b/src/app/components/components.module.ts
new file mode 100644
index 0000000..c2e123b
--- /dev/null
+++ b/src/app/components/components.module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import {HostComponent} from './editor/host/host.component';
+
+@NgModule({
+ declarations: [HostComponent],
+ imports: [
+ CommonModule
+ ],
+ entryComponents: [HostComponent],
+ exports: [
+ HostComponent
+ ]
+})
+export class ComponentsModule { }
diff --git a/src/app/components/editor/host/host.component.html b/src/app/components/editor/host/host.component.html
new file mode 100644
index 0000000..c42ebd0
--- /dev/null
+++ b/src/app/components/editor/host/host.component.html
@@ -0,0 +1,13 @@
+
+
+ {{ record.value }}
+
+
diff --git a/src/app/components/editor/host/host.component.scss b/src/app/components/editor/host/host.component.scss
new file mode 100644
index 0000000..2d6a910
--- /dev/null
+++ b/src/app/components/editor/host/host.component.scss
@@ -0,0 +1,26 @@
+.host-host.header1 {
+ font-weight: bold;
+ font-size: 24pt;
+}
+
+.host-host.header2 {
+ font-weight: bold;
+ font-size: 21pt;
+}
+
+.host-host.header3 {
+ font-weight: bold;
+ font-size: 18pt;
+}
+
+.host-host.header4 {
+ font-weight: bold;
+ font-size: 16pt;
+}
+
+.host-host.block_code {
+ font-family: monospace;
+ font-size: 12pt;
+ background-color: #ddd;
+ margin-bottom: 15px;
+}
diff --git a/src/app/components/editor/host/host.component.spec.ts b/src/app/components/editor/host/host.component.spec.ts
new file mode 100644
index 0000000..5eb2e63
--- /dev/null
+++ b/src/app/components/editor/host/host.component.spec.ts
@@ -0,0 +1,24 @@
+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;
+
+ 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();
+ });
+});
diff --git a/src/app/components/editor/host/host.component.ts b/src/app/components/editor/host/host.component.ts
new file mode 100644
index 0000000..3cdcca5
--- /dev/null
+++ b/src/app/components/editor/host/host.component.ts
@@ -0,0 +1,48 @@
+import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
+import HostRecord from '../../../structures/HostRecord';
+
+@Component({
+ selector: 'editor-host',
+ templateUrl: './host.component.html',
+ styleUrls: ['./host.component.scss'],
+})
+export class HostComponent implements OnInit {
+ @Input() record: HostRecord;
+ @Output() recordChange = new EventEmitter();
+ @Output() newHostRequested = new EventEmitter();
+ @Output() destroyHostRequested = new EventEmitter();
+ @ViewChild('hostContainer', {static: false}) hostContainer: ElementRef;
+
+ constructor() { }
+
+ ngOnInit() {}
+
+ onKeyUp($event) {
+ const innerText = this.hostContainer.nativeElement.innerText.trim()
+ if ( $event.code === 'Enter'
+ && ( this.record.type !== 'block_code'
+ || (innerText.endsWith('```') && (innerText.match(/`/g) || []).length >= 6)
+ )
+ ) {
+ this.newHostRequested.emit(this);
+ this.hostContainer.nativeElement.innerText = this.hostContainer.nativeElement.innerText.trim();
+ } else if ( $event.code === 'Backspace' && !this.hostContainer.nativeElement.innerText.trim() ) {
+ this.destroyHostRequested.emit(this);
+ }
+
+ if ( innerText.startsWith('# ') ) {
+ this.record.type = 'header1';
+ } else if ( innerText.startsWith('## ') ) {
+ this.record.type = 'header2';
+ } else if ( innerText.startsWith('### ') ) {
+ this.record.type = 'header3';
+ } else if ( innerText.startsWith('#### ') ) {
+ this.record.type = 'header4';
+ } else if ( innerText.startsWith('```') ) {
+ this.record.type = 'block_code';
+ } else {
+ this.record.type = 'paragraph';
+ }
+ }
+
+}
diff --git a/src/app/components/editor/paragraph/paragraph.component.html b/src/app/components/editor/paragraph/paragraph.component.html
new file mode 100644
index 0000000..b1c4c67
--- /dev/null
+++ b/src/app/components/editor/paragraph/paragraph.component.html
@@ -0,0 +1,3 @@
+
+ paragraph works!
+
diff --git a/src/app/components/editor/paragraph/paragraph.component.scss b/src/app/components/editor/paragraph/paragraph.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/components/editor/paragraph/paragraph.component.spec.ts b/src/app/components/editor/paragraph/paragraph.component.spec.ts
new file mode 100644
index 0000000..c0ffa47
--- /dev/null
+++ b/src/app/components/editor/paragraph/paragraph.component.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { ParagraphComponent } from './paragraph.component';
+
+describe('ParagraphComponent', () => {
+ let component: ParagraphComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ParagraphComponent ],
+ imports: [IonicModule.forRoot()]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(ParagraphComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ }));
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/components/editor/paragraph/paragraph.component.ts b/src/app/components/editor/paragraph/paragraph.component.ts
new file mode 100644
index 0000000..7cc1ff6
--- /dev/null
+++ b/src/app/components/editor/paragraph/paragraph.component.ts
@@ -0,0 +1,14 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-paragraph',
+ templateUrl: './paragraph.component.html',
+ styleUrls: ['./paragraph.component.scss'],
+})
+export class ParagraphComponent implements OnInit {
+
+ constructor() { }
+
+ ngOnInit() {}
+
+}
diff --git a/src/app/pages/editor/editor-routing.module.ts b/src/app/pages/editor/editor-routing.module.ts
new file mode 100644
index 0000000..46c1429
--- /dev/null
+++ b/src/app/pages/editor/editor-routing.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { EditorPage } from './editor.page';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: EditorPage
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class EditorPageRoutingModule {}
diff --git a/src/app/pages/editor/editor.module.ts b/src/app/pages/editor/editor.module.ts
new file mode 100644
index 0000000..eb4263e
--- /dev/null
+++ b/src/app/pages/editor/editor.module.ts
@@ -0,0 +1,22 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { EditorPageRoutingModule } from './editor-routing.module';
+
+import { EditorPage } from './editor.page';
+import {ComponentsModule} from '../../components/components.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ IonicModule,
+ EditorPageRoutingModule,
+ ComponentsModule
+ ],
+ declarations: [EditorPage]
+})
+export class EditorPageModule {}
diff --git a/src/app/pages/editor/editor.page.html b/src/app/pages/editor/editor.page.html
new file mode 100644
index 0000000..4fe70b8
--- /dev/null
+++ b/src/app/pages/editor/editor.page.html
@@ -0,0 +1,26 @@
+
+
+ Note Editor
+
+
+
+
+
+
+ Save
+
+
+ Hello, world!
+
+
+
+
+
+
+
diff --git a/src/app/pages/editor/editor.page.scss b/src/app/pages/editor/editor.page.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/pages/editor/editor.page.spec.ts b/src/app/pages/editor/editor.page.spec.ts
new file mode 100644
index 0000000..d854864
--- /dev/null
+++ b/src/app/pages/editor/editor.page.spec.ts
@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { EditorPage } from './editor.page';
+
+describe('EditorPage', () => {
+ let component: EditorPage;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ EditorPage ],
+ imports: [IonicModule.forRoot()]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(EditorPage);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ }));
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/pages/editor/editor.page.ts b/src/app/pages/editor/editor.page.ts
new file mode 100644
index 0000000..5d6f13e
--- /dev/null
+++ b/src/app/pages/editor/editor.page.ts
@@ -0,0 +1,90 @@
+import {Component, OnInit, ViewChildren} from '@angular/core';
+import HostRecord from '../../structures/HostRecord';
+
+@Component({
+ selector: 'app-editor',
+ templateUrl: './editor.page.html',
+ styleUrls: ['./editor.page.scss'],
+})
+export class EditorPage implements OnInit {
+ public hostRecords: Array = [new HostRecord('I am a record.')];
+
+ @ViewChildren('editorHosts') editorHosts;
+
+ constructor() { }
+
+ ngOnInit() {
+ console.log('Editor component: ', this);
+ }
+
+ onNewHostRequested($event) {
+ const insertAfter = this.getIndexFromRecord($event.record);
+ const record = new HostRecord('');
+ const newHosts = []
+ this.hostRecords.forEach((rec, i) => {
+ newHosts.push(rec);
+ if ( i === insertAfter ) {
+ newHosts.push(record);
+ }
+ })
+
+ this.hostRecords = newHosts;
+
+ setTimeout(() => {
+ const host = this.editorHosts.toArray()[insertAfter + 1].hostContainer.nativeElement;
+ const s = window.getSelection();
+ const r = document.createRange();
+ r.setStart(host, 0);
+ r.setEnd(host, 0);
+ s.removeAllRanges();
+ s.addRange(r);
+ }, 0);
+
+ }
+
+ onDestroyHostRequested($event) {
+ let removedIndex = 0;
+ const newHostRecords = this.editorHosts.filter((host, i) => {
+ if ( $event.record === host.record ) {
+ removedIndex = i;
+ }
+ return host.record !== $event.record;
+ });
+
+ const removedHost = this.editorHosts[removedIndex];
+
+ const hostRecords = newHostRecords.map(host => host.record);
+ this.hostRecords = hostRecords;
+
+ setTimeout(() => {
+ let focusIndex;
+ if ( removedIndex === 0 && this.editorHosts.toArray().length ) {
+ focusIndex = 0;
+ } else if ( removedIndex !== 0 ) {
+ focusIndex = removedIndex - 1;
+ }
+
+ if ( focusIndex >= 0 ) {
+ const host = this.editorHosts.toArray()[focusIndex].hostContainer.nativeElement;
+ const s = window.getSelection();
+ const r = document.createRange();
+ r.setStart(host, 0);
+ r.setEnd(host, 0);
+ s.removeAllRanges();
+ s.addRange(r);
+ }
+ }, 0);
+ }
+
+ protected getIndexFromRecord(record) {
+ let index;
+ this.editorHosts.toArray().forEach((host, i) => {
+ if ( host.record === record ) {
+ index = i;
+ }
+ });
+
+ return index;
+ }
+
+}
diff --git a/src/app/structures/HostRecord.ts b/src/app/structures/HostRecord.ts
new file mode 100644
index 0000000..82d591a
--- /dev/null
+++ b/src/app/structures/HostRecord.ts
@@ -0,0 +1,9 @@
+export default class HostRecord {
+ public value = '';
+
+ public type: 'paragraph'|'header1'|'header2'|'header3'|'header4'|'block_code' = 'paragraph';
+
+ constructor(value = '') {
+ this.value = value;
+ }
+}