raonkeditor-angular
Version:
Angular component for RAON K Editor.
400 lines (394 loc) • 15.3 kB
JavaScript
import { EventEmitter, Component, forwardRef, ElementRef, NgZone, Input, Output, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { getRaonwizComponentNamespace } from 'raonwiz-integrations-common';
/**
* @license Copyright (c) 2003-2022, RAONWIZ DevTeam. All rights reserved.
*/
class RaonkEditorComponent {
constructor(elementRef, ngZone) {
this.elementRef = elementRef;
this.ngZone = ngZone;
/**
* The id of the component
*/
this.id = "";
/**
* The component type
*/
this.componentType = 'RAONKEDITOR';
/**
* RAON K Editor script url address. Script will be loaded only if RAONKEDITOR namespace is missing.
*/
this.componentUrl = '/raonkeditor/js/raonkeditor.js';
/**
* Tag name of the component.
*
* The default tag is `div`.
*/
this.tagName = 'div';
/**
* The runtimes of the component interface.
*/
this.runtimes = "html5" /* HTML5 */;
/**
* Fired when the component namespace
* is loaded. It only triggers once, no matter how many components are initialised.
*/
this.namespaceLoaded = new EventEmitter();
this.change = new EventEmitter();
/**
* event.
*/
this.creationComplete = new EventEmitter();
this.afterChangeMode = new EventEmitter();
this.onError = new EventEmitter();
this.onLanguageDefinition = new EventEmitter();
this.afterPopupShow = new EventEmitter();
this.agentInstall = new EventEmitter();
this.beforeInsertUrl = new EventEmitter();
this.mouse = new EventEmitter();
this.command = new EventEmitter();
this.key = new EventEmitter();
this.resized = new EventEmitter();
this.documentEditComplete = new EventEmitter();
this.pasteImage = new EventEmitter();
this.wordCount = new EventEmitter();
this.beforePaste = new EventEmitter();
this.customAction = new EventEmitter();
this.fullScreen = new EventEmitter();
this.setComplete = new EventEmitter();
this.setInsertComplete = new EventEmitter();
this.closeInstallPopup = new EventEmitter();
this.setForbiddenWordComplete = new EventEmitter();
this.drag = new EventEmitter();
this.focus = new EventEmitter();
this.dialogLoaded = new EventEmitter();
this.beforeInsertHyperlink = new EventEmitter();
/**
* If the component is view-mode before the component instance is created, it remembers that state,
* so the component can become view-mode once it is ready.
*/
this._readOnly = null;
this._viewMode = null;
this._data = null;
this._destroyed = false;
}
/**
* Keeps track of the component's data.
*
* It's also decorated as an input which is useful when not using the ngModel.
*
* See https://angular.io/api/forms/NgModel to learn more.
*/
set data(data) {
console.log("this.id: " + this.id + ", data : " + data);
if (data === this._data) {
return;
}
if (this.instance) {
RAONKEDITOR.SetHtmlContents(data, this.id);
return;
}
this._data = data;
}
get data() {
return this._data;
}
/**
* When set to `true`, the editor becomes readonly mode.
*/
set readOnly(isReadOnly) {
if (this.instance) {
RAONKEDITOR.SetReadOnly(isReadOnly, '', this.id);
return;
}
// Delay setting mode
this._readOnly = isReadOnly;
}
get readOnly() {
if (this.instance) {
return RAONKEDITOR.GetEditorByName(this.id)._BODY.contentEditable;
}
return this._readOnly;
}
/**
* When set to `true`, the editor becomes view mode.
*/
set viewMode(isViewMode) {
if (this.instance) {
RAONKEDITOR.SetEditorMode(isViewMode ? 'view' : 'edit', this.id);
return;
}
// Delay setting mode
this._viewMode = isViewMode;
}
get viewMode() {
if (this.instance) {
let retValue;
switch (RAONKEDITOR.GetEditorByName(this.id)._config.mode.toLowerCase()) {
case 'edit':
retValue = false;
break;
default:
retValue = true;
break;
}
return retValue;
}
return this._viewMode;
}
ngAfterViewInit() {
getRaonwizComponentNamespace(this.componentType, this.componentUrl, namespace => {
this.namespaceLoaded.emit(namespace);
}).then((namespace) => {
// Check if component instance was destroyed before `ngAfterViewInit` call (#110).
// Here, `this.instance` is still not initialized and so additional flag is needed.
if (this._destroyed) {
return;
}
this.ngZone.runOutsideAngular(this.createComponent.bind(this, namespace));
}).catch(window.console.error);
}
ngOnDestroy() {
this._destroyed = true;
this.ngZone.runOutsideAngular(() => {
if (this.instance) {
if (RAONKEDITOR._ExternalComponentMap.has(this.id)) {
RAONKEDITOR._ExternalComponentMap.delete(this.id);
}
if (RAONKEDITOR._ExternalEventRetValueMap.has(this.id)) {
RAONKEDITOR._ExternalEventRetValueMap.delete(this.id);
}
RAONKEDITOR.Destroy(this.id, false);
this.instance = null;
}
});
}
writeValue(value) {
this.data = value;
}
registerOnChange(callback) {
this.onChange = callback;
}
registerOnTouched(callback) {
this.onTouched = callback;
}
getComponentUniqueName() {
return "raonkeditor_" + Math.random()
.toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
}
createComponent(namespace) {
let _uniqueName = this.getComponentUniqueName();
(typeof this.id === 'undefined') && (this.id = _uniqueName);
const element = document.createElement(this.tagName);
element.id = "componentHolder_" + _uniqueName;
this.elementRef.nativeElement.appendChild(element);
// view state may change during instance initialization.
(this._viewMode !== null) && (this.viewMode = this._viewMode);
// default config
let _compConfig = {
Id: this.id,
EditorHolder: element.id,
Runtimes: this.runtimes,
Mode: this._viewMode ? 'view' : 'edit',
ReturnEventKeyboard: '1',
ReturnEventFocus: '1',
ReturnEventCommand: '1',
Event: this.subscribe()
};
_compConfig = namespace.util.objectExtend(true, this.config, _compConfig);
// for event callback
(typeof namespace._ExternalComponentMap === 'undefined') && (namespace._ExternalComponentMap = new Map());
namespace._ExternalComponentMap.set(this.id, this);
(typeof namespace._ExternalEventRetValueMap === 'undefined') && (namespace._ExternalEventRetValueMap = new Map());
var _componentObject = new RAONKEditor(_compConfig);
_componentObject.name = element.id;
this.instance = _componentObject;
}
subscribe() {
let _configEvent = {};
const ComponentEvents = [
'CreationComplete',
'AfterChangeMode',
'OnError',
'OnLanguageDefinition',
'AfterPopupShow',
'AgentInstall',
'BeforeInsertUrl',
'Mouse',
'Command',
'Key',
'Resized',
'DocumentEditComplete',
'PasteImage',
'WordCount',
'BeforePaste',
'CustomAction',
'FullScreen',
'SetComplete',
'SetInsertComplete',
'CloseInstallPopup',
'SetForbiddenWordComplete',
'Drag',
'Focus',
'DialogLoaded',
'BeforeInsertHyperlink'
];
ComponentEvents.forEach(function (evtName) {
_configEvent[evtName] = (componentName, paramObj) => {
// Set default value
switch (evtName) {
case 'BeforePaste':
RAONKEDITOR._ExternalEventRetValueMap.set(componentName, paramObj.strHtml);
break;
case 'BeforeInsertUrl':
RAONKEDITOR._ExternalEventRetValueMap.set(componentName, paramObj.strUrl);
break;
case 'BeforeInsertHyperlink':
RAONKEDITOR._ExternalEventRetValueMap.set(componentName, paramObj); // url
break;
}
if (RAONKEDITOR._ExternalComponentMap.has(componentName)) {
let _this = RAONKEDITOR._ExternalComponentMap.get(componentName);
_this.ngZone.run(() => {
switch (evtName) {
case 'Focus':
if (_this.onTouched) {
_this.onTouched();
}
break;
case 'Command':
_this.propagateChange(evtName, { componentName: componentName, paramObj: paramObj });
break;
case 'Key':
if (paramObj.strEventName === 'keyup') {
_this.propagateChange(evtName, { componentName: componentName, paramObj: paramObj });
}
break;
case 'CreationComplete':
if (_this.data && typeof _this.data !== 'undefined' && _this.data !== '') {
RAONKEDITOR.SetHtmlContents(_this.data, _this.id);
}
// Data may be changed by content filtering.
_this._data = RAONKEDITOR.GetEditorByName(_this.id)._BODY.innerHTML;
break;
case 'SetComplete':
// Data may be changed by content filtering.
_this._data = RAONKEDITOR.GetEditorByName(_this.id)._BODY.innerHTML;
break;
}
_this[_this.capitalize(evtName)].emit({ componentName: componentName, paramObj: paramObj });
});
}
// return event
let _retValue = "";
switch (evtName) {
case 'BeforePaste':
case 'BeforeInsertUrl':
case 'BeforeInsertHyperlink':
if (RAONKEDITOR._ExternalEventRetValueMap.has(componentName)) {
_retValue = RAONKEDITOR._ExternalEventRetValueMap.get(componentName);
RAONKEDITOR._ExternalEventRetValueMap.delete(componentName); // Initialization
return _retValue;
}
break;
}
};
});
return _configEvent;
}
capitalize(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
propagateChange(eventName, eventParams) {
this.ngZone.run(() => {
const newData = RAONKEDITOR.GetEditorByName(this.id)._BODY.innerHTML;
this.change.emit(eventParams);
if (newData === this.data) {
return;
}
this._data = newData;
if (this.onChange) {
this.onChange(newData);
}
});
}
}
RaonkEditorComponent.decorators = [
{ type: Component, args: [{
selector: 'RaonkEditor',
template: '<ng-template></ng-template>',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RaonkEditorComponent),
multi: true,
}
]
},] }
];
RaonkEditorComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: NgZone }
];
RaonkEditorComponent.propDecorators = {
id: [{ type: Input }],
config: [{ type: Input }],
componentType: [{ type: Input }],
componentUrl: [{ type: Input }],
tagName: [{ type: Input }],
runtimes: [{ type: Input }],
data: [{ type: Input }],
readOnly: [{ type: Input }],
viewMode: [{ type: Input }],
namespaceLoaded: [{ type: Output }],
change: [{ type: Output }],
creationComplete: [{ type: Output }],
afterChangeMode: [{ type: Output }],
onError: [{ type: Output }],
onLanguageDefinition: [{ type: Output }],
afterPopupShow: [{ type: Output }],
agentInstall: [{ type: Output }],
beforeInsertUrl: [{ type: Output }],
mouse: [{ type: Output }],
command: [{ type: Output }],
key: [{ type: Output }],
resized: [{ type: Output }],
documentEditComplete: [{ type: Output }],
pasteImage: [{ type: Output }],
wordCount: [{ type: Output }],
beforePaste: [{ type: Output }],
customAction: [{ type: Output }],
fullScreen: [{ type: Output }],
setComplete: [{ type: Output }],
setInsertComplete: [{ type: Output }],
closeInstallPopup: [{ type: Output }],
setForbiddenWordComplete: [{ type: Output }],
drag: [{ type: Output }],
focus: [{ type: Output }],
dialogLoaded: [{ type: Output }],
beforeInsertHyperlink: [{ type: Output }]
};
/**
* @license Copyright (c) 2003-2022, RAONWIZ DevTean. All rights reserved.
*/
/**
* @license Copyright (c) 2003-2022, RAONWIZ DevTeam. All rights reserved.
*/
class RaonkEditorModule {
}
RaonkEditorModule.decorators = [
{ type: NgModule, args: [{
imports: [FormsModule, CommonModule],
declarations: [RaonkEditorComponent],
exports: [RaonkEditorComponent]
},] }
];
/**
* Generated bundle index. Do not edit.
*/
export { RaonkEditorComponent, RaonkEditorModule };
//# sourceMappingURL=raonkeditor-angular.js.map