198 lines
5.7 KiB
TypeScript
198 lines
5.7 KiB
TypeScript
|
import {
|
||
|
Component,
|
||
|
OnInit,
|
||
|
ElementRef,
|
||
|
ViewChild,
|
||
|
AfterViewInit,
|
||
|
HostListener
|
||
|
} from '@angular/core';
|
||
|
|
||
|
@Component({
|
||
|
selector: 'ucap-message-editor',
|
||
|
templateUrl: './message-editor.component.html',
|
||
|
styleUrls: ['./message-editor.component.scss']
|
||
|
})
|
||
|
export class MessageEditorComponent implements OnInit, AfterViewInit {
|
||
|
@ViewChild('fileInput', { static: false })
|
||
|
fileInput: ElementRef<HTMLInputElement>;
|
||
|
|
||
|
@ViewChild('contentArea', { static: true }) contentArea: ElementRef;
|
||
|
|
||
|
attachFileType: string;
|
||
|
|
||
|
fileIndex = 0;
|
||
|
attachFiles: { file: File; idx: number }[] = [];
|
||
|
imageFiles: { file: File; idx: number }[] = [];
|
||
|
|
||
|
constructor() {}
|
||
|
|
||
|
ngOnInit() {}
|
||
|
|
||
|
ngAfterViewInit(): void {
|
||
|
setTimeout(() => {
|
||
|
this.contentArea.nativeElement.focus();
|
||
|
|
||
|
document
|
||
|
.querySelector('#contentArea')
|
||
|
.addEventListener('paste', (event: ClipboardEvent) => {
|
||
|
event.stopPropagation();
|
||
|
event.preventDefault();
|
||
|
|
||
|
const clipboardData = event.clipboardData;
|
||
|
let pastedData = clipboardData.getData('Text');
|
||
|
pastedData = this.convertHtmltoEntity(pastedData);
|
||
|
clipboardData.setData('Text', pastedData);
|
||
|
const div = document.createElement('div');
|
||
|
div.innerHTML = pastedData;
|
||
|
|
||
|
this.attachElementNextFocused(div);
|
||
|
});
|
||
|
|
||
|
document
|
||
|
.querySelector('#contentArea')
|
||
|
.addEventListener('keyup', event => {
|
||
|
if (
|
||
|
document.querySelector('#contentArea').innerHTML === '' ||
|
||
|
document.querySelector('#contentArea').innerHTML === '<br>'
|
||
|
) {
|
||
|
const div = document.createElement('div');
|
||
|
div.innerHTML = ' <br>';
|
||
|
document.querySelector('#contentArea').innerHTML = '';
|
||
|
this.attachElementNextFocused(div);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// init..
|
||
|
if (document.querySelector('#contentArea').innerHTML === '') {
|
||
|
const div = document.createElement('div');
|
||
|
div.innerHTML = ' <br>';
|
||
|
this.attachElementNextFocused(div);
|
||
|
}
|
||
|
}, 700);
|
||
|
}
|
||
|
|
||
|
onClickFileInput(type: string) {
|
||
|
this.attachFileType = type;
|
||
|
if (type === 'attach') {
|
||
|
this.fileInput.nativeElement.setAttribute('multiple', 'true');
|
||
|
this.fileInput.nativeElement.setAttribute('accept', '*.*');
|
||
|
} else {
|
||
|
this.fileInput.nativeElement.removeAttribute('multiple');
|
||
|
this.fileInput.nativeElement.setAttribute('accept', 'image/*');
|
||
|
}
|
||
|
this.fileInput.nativeElement.click();
|
||
|
}
|
||
|
|
||
|
onChangeFileInput() {
|
||
|
const files: FileList = this.fileInput.nativeElement.files;
|
||
|
|
||
|
// tslint:disable-next-line: prefer-for-of
|
||
|
for (let i = 0; i < files.length; i++) {
|
||
|
if (this.attachFileType === 'attach') {
|
||
|
this.attachFiles.push({ file: files[i], idx: this.fileIndex });
|
||
|
} else {
|
||
|
this.imageFiles.push({ file: files[i], idx: this.fileIndex });
|
||
|
this.addImageInInputField(files[i], this.fileIndex);
|
||
|
}
|
||
|
this.fileIndex++;
|
||
|
}
|
||
|
this.fileInput.nativeElement.value = '';
|
||
|
}
|
||
|
|
||
|
getContents(): string {
|
||
|
return 'this is contents';
|
||
|
}
|
||
|
|
||
|
addImageInInputField(image: File, index: number) {
|
||
|
const reader = new FileReader();
|
||
|
reader.readAsDataURL(image);
|
||
|
reader.onloadend = () => {
|
||
|
const img = document.createElement('img');
|
||
|
img.setAttribute('src', reader.result.toString());
|
||
|
img.setAttribute('data-seq', index.toString());
|
||
|
|
||
|
this.attachElementNextFocused(img);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
attachElementNextFocused(el: HTMLElement) {
|
||
|
if (window.getSelection) {
|
||
|
const sel = window.getSelection();
|
||
|
const selAnchorNode: Node = sel.anchorNode;
|
||
|
const focusedEl = selAnchorNode.parentElement;
|
||
|
|
||
|
if (this.isParentIdCheck(focusedEl, 'contentArea')) {
|
||
|
if (sel.rangeCount) {
|
||
|
const range = sel.getRangeAt(0);
|
||
|
|
||
|
if (selAnchorNode.nodeType === Node.TEXT_NODE) {
|
||
|
const content: string = focusedEl.textContent;
|
||
|
|
||
|
focusedEl.innerText =
|
||
|
content.substr(0, range.startOffset) +
|
||
|
el.textContent +
|
||
|
content.substr(range.endOffset);
|
||
|
} else if (
|
||
|
selAnchorNode.nodeType === Node.ELEMENT_NODE &&
|
||
|
focusedEl.id === 'contentArea'
|
||
|
) {
|
||
|
const selEl = selAnchorNode as HTMLElement;
|
||
|
const content: string = selEl.textContent;
|
||
|
|
||
|
selEl.innerText =
|
||
|
content.substr(0, range.startOffset) +
|
||
|
el.textContent +
|
||
|
content.substr(range.endOffset);
|
||
|
} else {
|
||
|
focusedEl.append(el);
|
||
|
}
|
||
|
} else {
|
||
|
focusedEl.append(el);
|
||
|
}
|
||
|
} else {
|
||
|
this.contentArea.nativeElement.appendChild(el);
|
||
|
}
|
||
|
} else {
|
||
|
this.contentArea.nativeElement.appendChild(el);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
isParentIdCheck(el: HTMLElement, id: string): boolean {
|
||
|
if (el.id === id) {
|
||
|
return true;
|
||
|
} else {
|
||
|
if (el.tagName === 'BODY' || el.tagName === 'body') {
|
||
|
return false;
|
||
|
} else {
|
||
|
return this.isParentIdCheck(el.parentElement, id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
test(): void {
|
||
|
if (!!this.contentArea) {
|
||
|
const els: HTMLCollection = this.contentArea.nativeElement.children;
|
||
|
|
||
|
// tslint:disable-next-line: prefer-for-of
|
||
|
for (let i = 0; i < els.length; i++) {
|
||
|
console.log(this.convertEntitytoHtml(els[i].textContent));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
convertHtmltoEntity(str: string): string {
|
||
|
return str
|
||
|
.replace(/ /g, ' ')
|
||
|
.replace(/</g, '<')
|
||
|
.replace(/>/g, '>')
|
||
|
.replace(/\n/g, '<br>');
|
||
|
}
|
||
|
convertEntitytoHtml(str: string): string {
|
||
|
return str
|
||
|
.replace(/ /g, ' ')
|
||
|
.replace(/</g, '<')
|
||
|
.replace(/>/g, '>')
|
||
|
.replace(/<br>/g, ' \n');
|
||
|
}
|
||
|
}
|