|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild, ViewChildren} from '@angular/core';
|
|
|
|
|
import {Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild, ViewChildren} from '@angular/core';
|
|
|
|
|
import HostRecord from '../../../structures/HostRecord';
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
@ -19,7 +19,18 @@ export class HostComponent implements OnInit {
|
|
|
|
|
|
|
|
|
|
constructor() { }
|
|
|
|
|
|
|
|
|
|
ngOnInit() {}
|
|
|
|
|
ngOnInit() {
|
|
|
|
|
if ( this.record.type === 'ul' ) {
|
|
|
|
|
const values = JSON.parse(this.record.value);
|
|
|
|
|
values.forEach(group => this.listLines.push(group.value));
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
values.forEach((group, i) => {
|
|
|
|
|
const el = this.liItems.toArray()[i].nativeElement;
|
|
|
|
|
el.className += ` node-indentation-level-num-${group.indentationLevel}`;
|
|
|
|
|
});
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onRecordChange($event) {
|
|
|
|
|
this.recordChange.emit($event);
|
|
|
|
@ -27,13 +38,13 @@ export class HostComponent implements OnInit {
|
|
|
|
|
|
|
|
|
|
onKeyUp($event) {
|
|
|
|
|
const innerText = this.hostContainer.nativeElement.innerText.trim()
|
|
|
|
|
if ( $event.code === 'Enter'
|
|
|
|
|
if ( $event.code === 'Enter' && this.record.isNorm() && !$event.shiftKey
|
|
|
|
|
&& ( this.record.type !== 'block_code'
|
|
|
|
|
|| (innerText.endsWith('```') && (innerText.match(/`/g) || []).length >= 6)
|
|
|
|
|
|| (innerText.endsWith('```') && (innerText.match(/`/g) || []).length >= 6) // TODO don't add new if cursor in block
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
this.newHostRequested.emit(this);
|
|
|
|
|
this.hostContainer.nativeElement.innerText = this.hostContainer.nativeElement.innerText.trim();
|
|
|
|
|
this.newHostRequested.emit(this);
|
|
|
|
|
} else if ( $event.code === 'Backspace' && !this.hostContainer.nativeElement.innerText.trim() ) {
|
|
|
|
|
this.destroyHostRequested.emit(this);
|
|
|
|
|
}
|
|
|
|
@ -50,60 +61,119 @@ export class HostComponent implements OnInit {
|
|
|
|
|
this.record.type = 'block_code';
|
|
|
|
|
} else if ( innerText.startsWith('http') ) {
|
|
|
|
|
this.record.type = 'click_link';
|
|
|
|
|
} else if ( false && innerText.startsWith('-') || innerText.startsWith(' -') ) {
|
|
|
|
|
// this.record.type = 'ul';
|
|
|
|
|
} else if ( innerText === '---' ) {
|
|
|
|
|
this.record.type = 'page_sep';
|
|
|
|
|
} else if ( innerText.startsWith('-') || innerText.startsWith(' -') ) {
|
|
|
|
|
this.record.type = 'ul';
|
|
|
|
|
this.listLines = [this.record.value];
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
const item = this.liItems.toArray()[0].nativeElement;
|
|
|
|
|
const s = window.getSelection();
|
|
|
|
|
const r = document.createRange();
|
|
|
|
|
r.setStart(item, 0);
|
|
|
|
|
r.setEnd(item, 0);
|
|
|
|
|
s.removeAllRanges();
|
|
|
|
|
s.addRange(r);
|
|
|
|
|
this.focusStart(this.liItems.toArray()[0].nativeElement);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onRequestDelete($event) {
|
|
|
|
|
this.destroyHostRequested.emit(this);
|
|
|
|
|
onUlKeyDown($event, index) {
|
|
|
|
|
if ( $event.code === 'Tab' ) {
|
|
|
|
|
$event.preventDefault();
|
|
|
|
|
const elem = this.liItems.toArray()[index];
|
|
|
|
|
let currentLevel = 0;
|
|
|
|
|
|
|
|
|
|
elem.nativeElement.className.split(' ').some(x => {
|
|
|
|
|
if ( x.startsWith('node-indentation-level-num-') ) {
|
|
|
|
|
currentLevel = Number(x.replace('node-indentation-level-num-', ''));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const newLevel = $event.shiftKey ? currentLevel - 1 : currentLevel + 1;
|
|
|
|
|
if ( newLevel <= 5 && newLevel >= 0 ) {
|
|
|
|
|
const existing = elem.nativeElement.className.split(' ').filter(x => !x.startsWith('node-indentation-level-num-'));
|
|
|
|
|
existing.push(`node-indentation-level-num-${newLevel}`);
|
|
|
|
|
|
|
|
|
|
elem.nativeElement.className = existing.join(' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onLIKeyUp($event, i) {
|
|
|
|
|
if ( $event.code === 'Enter' ) {
|
|
|
|
|
/*const newListLines = [];
|
|
|
|
|
this.liItems.forEach((li, index) => {
|
|
|
|
|
newListLines.push(li.nativeElement.innerText.trim());
|
|
|
|
|
if ( index === i ) {
|
|
|
|
|
newListLines.push('');
|
|
|
|
|
onUlKeyUp($event, i) {
|
|
|
|
|
if ( $event.code === 'Enter' && !$event.shiftKey ) {
|
|
|
|
|
const e = this.liItems.toArray()[i].nativeElement;
|
|
|
|
|
e.innerText = e.innerText.trim();
|
|
|
|
|
if ( this.liItems.toArray()[i].nativeElement.innerText.trim() === '' ) {
|
|
|
|
|
this.newHostRequested.emit(this);
|
|
|
|
|
} else {
|
|
|
|
|
this.listLines.push('');
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.focusStart(this.liItems.toArray()[i + 1].nativeElement);
|
|
|
|
|
|
|
|
|
|
let newLevel = 0;
|
|
|
|
|
this.liItems.toArray()[i].nativeElement.className.split(' ').some(x => {
|
|
|
|
|
if ( x.startsWith('node-indentation-level-num-') ) {
|
|
|
|
|
newLevel = Number(x.replace('node-indentation-level-num-', ''));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const classes = this.liItems.toArray()[i + 1].nativeElement.className
|
|
|
|
|
.split(' ')
|
|
|
|
|
.filter(x => !x.startsWith('node-indentation-level-num-'));
|
|
|
|
|
classes.push(`node-indentation-level-num-${newLevel}`);
|
|
|
|
|
this.liItems.toArray()[i + 1].nativeElement.className = classes.join(' ');
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
} else if ( $event.code === 'Backspace' && this.liItems.toArray()[i].nativeElement.innerText.trim() === '' ) {
|
|
|
|
|
const newLines = [];
|
|
|
|
|
this.liItems.toArray().forEach((elem, index) => {
|
|
|
|
|
if ( index !== i ) {
|
|
|
|
|
newLines.push(elem.innerText ? elem.innerText.trim() : '');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.listLines = newListLines;*/
|
|
|
|
|
// this.listLines[i] = this.liItems[i].innerText.trim()
|
|
|
|
|
// const newLines = []
|
|
|
|
|
// this.listLines.forEach((rec, x) => {
|
|
|
|
|
// newLines.push(rec.trim());
|
|
|
|
|
// if ( i === x ) {
|
|
|
|
|
// newLines.push('');
|
|
|
|
|
// }
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this.listLines = newLines;
|
|
|
|
|
|
|
|
|
|
// setTimeout(() => {
|
|
|
|
|
// const item = this.liItems.toArray()[i + 1].nativeElement;
|
|
|
|
|
// const s = window.getSelection();
|
|
|
|
|
// const r = document.createRange();
|
|
|
|
|
// r.setStart(item, 0);
|
|
|
|
|
// r.setEnd(item, 0);
|
|
|
|
|
// s.removeAllRanges();
|
|
|
|
|
// s.addRange(r);
|
|
|
|
|
// }, 10);
|
|
|
|
|
this.listLines = newLines;
|
|
|
|
|
|
|
|
|
|
if ( i === 0 && this.listLines.length === 0 ) {
|
|
|
|
|
this.destroyHostRequested.emit(this);
|
|
|
|
|
} else {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.focusEnd(this.liItems.toArray()[i - 1].nativeElement);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
} else if ( $event.code === 'ArrowDown' ) {
|
|
|
|
|
const liArr = this.liItems.toArray();
|
|
|
|
|
if ( liArr.length > i + 1 ) {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.focusStart(this.liItems.toArray()[i + 1].nativeElement);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
} else if ( $event.code === 'ArrowUp' ) {
|
|
|
|
|
if ( i !== 0 ) {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
this.focusStart(this.liItems.toArray()[i - 1].nativeElement);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const recordValue = this.liItems.toArray().map(item => {
|
|
|
|
|
const elem = item.nativeElement;
|
|
|
|
|
const value = elem.innerText.trim();
|
|
|
|
|
let indentationLevel = 0;
|
|
|
|
|
elem.className.split(' ').some(x => {
|
|
|
|
|
if ( x.startsWith('node-indentation-level-num-') ) {
|
|
|
|
|
indentationLevel = x.replace('node-indentation-level-num-', '');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {value, indentationLevel};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.record.value = JSON.stringify(recordValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onRequestDelete($event) {
|
|
|
|
|
this.destroyHostRequested.emit(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onRequestParentSave($event) {
|
|
|
|
|
this.saveHostRequested.emit(this);
|
|
|
|
|
}
|
|
|
|
@ -114,4 +184,48 @@ export class HostComponent implements OnInit {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
takeFocus(fromTop = true) {
|
|
|
|
|
if ( this.record.type === 'ul' ) {
|
|
|
|
|
if ( fromTop ) {
|
|
|
|
|
this.focusStart(this.liItems.toArray()[0].nativeElement);
|
|
|
|
|
} else {
|
|
|
|
|
this.focusEnd(this.liItems.toArray().reverse()[0].nativeElement);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ( fromTop ) {
|
|
|
|
|
this.focusStart(this.hostContainer.nativeElement);
|
|
|
|
|
} else {
|
|
|
|
|
this.focusEnd(this.hostContainer.nativeElement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO return an observable here, probably
|
|
|
|
|
focusEnd(item) {
|
|
|
|
|
const s = window.getSelection();
|
|
|
|
|
const r = document.createRange();
|
|
|
|
|
r.setStart(item, 0);
|
|
|
|
|
r.setEnd(item, 0);
|
|
|
|
|
s.removeAllRanges();
|
|
|
|
|
s.addRange(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO return an observable here, probably
|
|
|
|
|
focusStart(item) {
|
|
|
|
|
const s = window.getSelection();
|
|
|
|
|
const r = document.createRange();
|
|
|
|
|
r.setStart(item, 0);
|
|
|
|
|
r.setEnd(item, 0);
|
|
|
|
|
s.removeAllRanges();
|
|
|
|
|
s.addRange(r);
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
const r2 = document.createRange();
|
|
|
|
|
r2.selectNodeContents(item);
|
|
|
|
|
r2.collapse(false);
|
|
|
|
|
const s2 = window.getSelection();
|
|
|
|
|
s2.removeAllRanges();
|
|
|
|
|
s2.addRange(r2);
|
|
|
|
|
}, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|