|
|
|
@ -5,10 +5,16 @@ |
|
|
|
* Copyright (c) Sebastian Stehle. All rights reserved |
|
|
|
*/ |
|
|
|
|
|
|
|
import { AfterViewInit, Component, forwardRef, ElementRef, OnDestroy, ViewChild, Output, EventEmitter } from '@angular/core'; |
|
|
|
import { AfterViewInit, Component, forwardRef, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; |
|
|
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder } from '@angular/forms'; |
|
|
|
|
|
|
|
import { MessageBus, AssetDragged, AssetsService, Types, ResourceLoaderService } from './../declarations-base'; |
|
|
|
import { |
|
|
|
AssetDto, |
|
|
|
AssetDragged, |
|
|
|
MessageBus, |
|
|
|
ResourceLoaderService, |
|
|
|
Types |
|
|
|
} from './../declarations-base'; |
|
|
|
|
|
|
|
declare var tinymce: any; |
|
|
|
|
|
|
|
@ -22,7 +28,7 @@ export const SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR: any = { |
|
|
|
templateUrl: './rich-editor.component.html', |
|
|
|
providers: [SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR] |
|
|
|
}) |
|
|
|
export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, OnDestroy { |
|
|
|
export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, OnInit, OnDestroy { |
|
|
|
private callChange = (v: any) => { /* NOOP */ }; |
|
|
|
private callTouched = () => { /* NOOP */ }; |
|
|
|
private tinyEditor: any; |
|
|
|
@ -45,32 +51,63 @@ export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, |
|
|
|
|
|
|
|
constructor(private readonly resourceLoader: ResourceLoaderService, |
|
|
|
private readonly formBuilder: FormBuilder, |
|
|
|
private readonly messageBus: MessageBus, |
|
|
|
private readonly assetsService: AssetsService |
|
|
|
private readonly messageBus: MessageBus |
|
|
|
) { |
|
|
|
this.assetDraggedSubscription = this.messageBus.of(AssetDragged).subscribe(message => { |
|
|
|
// only handle images for now
|
|
|
|
if (message.assetDto.isImage) { |
|
|
|
if (message.dragEvent === AssetDragged.DRAG_START) { |
|
|
|
this.draggedOver = true; |
|
|
|
} else { |
|
|
|
this.draggedOver = false; |
|
|
|
} |
|
|
|
|
|
|
|
public ngOnDestroy() { |
|
|
|
clearTimeout(this.tinyInitTimer); |
|
|
|
|
|
|
|
tinymce.remove(this.editor); |
|
|
|
|
|
|
|
this.assetDraggedSubscription.unsubscribe(); |
|
|
|
} |
|
|
|
|
|
|
|
public ngOnInit() { |
|
|
|
this.assetDraggedSubscription = |
|
|
|
this.messageBus.of(AssetDragged).subscribe(message => { |
|
|
|
if (message.assetDto.isImage) { |
|
|
|
if (message.dragEvent === AssetDragged.DRAG_START) { |
|
|
|
this.draggedOver = true; |
|
|
|
} else { |
|
|
|
this.draggedOver = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
public ngAfterViewInit() { |
|
|
|
const self = this; |
|
|
|
|
|
|
|
this.resourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.4/tinymce.min.js').then(() => { |
|
|
|
tinymce.init(self.getEditorOptions()); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private getEditorOptions() { |
|
|
|
const self = this; |
|
|
|
|
|
|
|
return { |
|
|
|
toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image media assets', |
|
|
|
plugins: 'code,image,media', |
|
|
|
file_picker_types: 'image', |
|
|
|
convert_fonts_to_spans: true, |
|
|
|
convert_urls: false, |
|
|
|
plugins: 'code image media', |
|
|
|
removed_menuitems: 'newdocument', |
|
|
|
resize: true, |
|
|
|
theme: 'modern', |
|
|
|
toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image media assets', |
|
|
|
setup: (editor: any) => { |
|
|
|
self.tinyEditor = editor; |
|
|
|
self.tinyEditor.setMode(this.isDisabled ? 'readonly' : 'design'); |
|
|
|
|
|
|
|
self.tinyEditor.addButton('assets', { |
|
|
|
text: '', |
|
|
|
icon: 'browse', |
|
|
|
tooltip: 'Insert Assets', |
|
|
|
onclick: (event: any) => { |
|
|
|
self.assetPluginClicked.emit(event); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
self.tinyEditor.on('change', () => { |
|
|
|
const value = editor.getContent(); |
|
|
|
|
|
|
|
@ -85,36 +122,14 @@ export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, |
|
|
|
self.callTouched(); |
|
|
|
}); |
|
|
|
|
|
|
|
editor.addButton('assets', { |
|
|
|
text: '', |
|
|
|
icon: 'browse', |
|
|
|
tooltip: 'Insert Assets', |
|
|
|
onclick: (event: any) => { |
|
|
|
self.assetPluginClicked.emit(event); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
self.tinyInitTimer = |
|
|
|
setTimeout(() => { |
|
|
|
self.tinyEditor.setContent(this.value || ''); |
|
|
|
}, 500); |
|
|
|
}, |
|
|
|
removed_menuitems: 'newdocument', target: this.editor.nativeElement |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public ngOnDestroy() { |
|
|
|
clearTimeout(this.tinyInitTimer); |
|
|
|
|
|
|
|
tinymce.remove(this.editor); |
|
|
|
this.assetDraggedSubscription.unsubscribe(); |
|
|
|
} |
|
|
|
|
|
|
|
public ngAfterViewInit() { |
|
|
|
const self = this; |
|
|
|
this.resourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.4/tinymce.min.js').then(() => { |
|
|
|
tinymce.init(self.getEditorOptions()); |
|
|
|
}); |
|
|
|
target: this.editor.nativeElement |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public writeValue(value: string) { |
|
|
|
@ -142,9 +157,14 @@ export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, |
|
|
|
} |
|
|
|
|
|
|
|
public onItemDropped(event: any) { |
|
|
|
let content = this.assetsService.buildDroppedAssetData(event.dragData, event.mouseEvent); |
|
|
|
if (content) { |
|
|
|
this.tinyEditor.execCommand('mceInsertContent', false, content); |
|
|
|
const content = event.dragData; |
|
|
|
|
|
|
|
if (content instanceof AssetDto) { |
|
|
|
const img = `<img src="${content.url}" alt="${content.fileName}" />`; |
|
|
|
|
|
|
|
this.tinyEditor.execCommand('mceInsertContent', false, img); |
|
|
|
} |
|
|
|
|
|
|
|
this.draggedOver = false; |
|
|
|
} |
|
|
|
} |