2020-11-10 14:20:22 +00:00
|
|
|
import {Component, EventEmitter, HostListener, Input, OnInit, Output, ViewChild} from '@angular/core';
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'wysiwyg-editor',
|
|
|
|
templateUrl: './wysiwyg.component.html',
|
|
|
|
styleUrls: ['./wysiwyg.component.scss'],
|
|
|
|
})
|
|
|
|
export class WysiwygComponent implements OnInit {
|
|
|
|
@ViewChild('editable') editable;
|
|
|
|
@Input() readonly = false;
|
2020-11-13 03:16:18 +00:00
|
|
|
@Input() set contents(val: string) {
|
|
|
|
if ( this.currentContents !== val ) {
|
|
|
|
this.currentContents = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get contents(): string {
|
|
|
|
return this.currentContents;
|
|
|
|
}
|
|
|
|
|
2020-11-10 14:20:22 +00:00
|
|
|
@Output() contentsChanged: EventEmitter<string> = new EventEmitter<string>();
|
|
|
|
|
2020-11-13 03:16:18 +00:00
|
|
|
public currentContents = '';
|
|
|
|
|
2020-11-10 14:20:22 +00:00
|
|
|
public isFocused = false;
|
|
|
|
protected hadOneFocusOut = false;
|
2020-11-10 14:35:29 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2020-11-10 14:20:22 +00:00
|
|
|
|
|
|
|
public get displayContents() {
|
2020-11-10 14:35:29 +00:00
|
|
|
return (this.contents || 'Double-click to edit...').replace(/</g, '\n<')
|
|
|
|
.replace(/(https?:\/\/[^\s]+)/g, (val) => `<a href="${val}" target="_blank">${val}</a>`);
|
2020-11-10 14:20:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public isDark() {
|
|
|
|
return document.body.classList.contains('dark');
|
|
|
|
}
|
|
|
|
|
2020-11-13 03:16:18 +00:00
|
|
|
ngOnInit() { }
|
2020-11-10 14:20:22 +00:00
|
|
|
|
|
|
|
onFocusIn(event: MouseEvent) {
|
|
|
|
console.log('on focus in', event);
|
|
|
|
this.isFocused = !this.readonly;
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keyup.escape', ['$event'])
|
|
|
|
onFocusOut(event) {
|
2020-11-10 14:35:29 +00:00
|
|
|
if ( this.isEditOnly ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-10 14:20:22 +00:00
|
|
|
if ( !this.hadOneFocusOut ) {
|
|
|
|
this.hadOneFocusOut = true;
|
|
|
|
setTimeout(() => {
|
|
|
|
this.hadOneFocusOut = false;
|
|
|
|
}, 500);
|
|
|
|
} else {
|
|
|
|
this.isFocused = false;
|
|
|
|
this.hadOneFocusOut = 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;
|
|
|
|
this.contentsChanged.emit(innerHTML);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.tab', ['$event'])
|
|
|
|
onIndent(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('indent');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.shift.tab', ['$event'])
|
|
|
|
onOutdent(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('outdent');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.control.b', ['$event'])
|
|
|
|
onBold(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('bold');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.control.i', ['$event'])
|
|
|
|
onItalic(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('italic');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.control.u', ['$event'])
|
|
|
|
onUnderline(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('underline');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.control.z', ['$event'])
|
|
|
|
onUndo(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('undo');
|
|
|
|
}
|
|
|
|
|
|
|
|
@HostListener('document:keydown.control.shift.z', ['$event'])
|
|
|
|
onRedo(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.documentCommand('redo');
|
|
|
|
}
|
|
|
|
}
|