ngx-tinymce
Version:
Angular for tinymce
287 lines (280 loc) • 9.21 kB
JavaScript
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs';
import { Injectable, Inject, Component, forwardRef, Input, ChangeDetectionStrategy, ChangeDetectorRef, TemplateRef, ViewEncapsulation, Output, EventEmitter, NgModule } from '@angular/core';
import { DOCUMENT, CommonModule } from '@angular/common';
class TinymceOptions {
constructor() {
/** 指定tinymce目录路径,默认:`./assets/tinymce/` */
this.baseURL = './assets/tinymce/';
/** 指定tinymce文件名,默认:`tinymce.min.js` */
this.fileName = 'tinymce.min.js';
}
}
class ScriptService {
constructor(doc) {
this.doc = doc;
this.loaded = false;
this.list = {};
this.emitter = new Subject();
}
getChangeEmitter() {
return this.emitter;
}
load(path) {
if (this.loaded) {
return this;
}
this.loaded = true;
const promises = [];
[path].forEach(script => promises.push(this.loadScript(script)));
Promise.all(promises).then(res => {
this.emitter.next(true);
});
return this;
}
loadScript(path) {
return new Promise((resolve, reject) => {
if (this.list[path] === true) {
resolve({
path: path,
loaded: true,
status: 'Loaded',
});
return;
}
this.list[path] = true;
const node = this.doc.createElement('script');
node.type = 'text/javascript';
node.src = path;
node.charset = 'utf-8';
if (node.readyState) {
// IE
node.onreadystatechange = () => {
if (node.readyState === 'loaded' ||
node.readyState === 'complete') {
node.onreadystatechange = null;
resolve({
path: path,
loaded: true,
status: 'Loaded',
});
}
};
}
else {
node.onload = () => {
resolve({
path: path,
loaded: true,
status: 'Loaded',
});
};
}
node.onerror = (error) => resolve({
path: path,
loaded: false,
status: 'Loaded',
});
this.doc.getElementsByTagName('head')[0].appendChild(node);
});
}
}
ScriptService.decorators = [
{ type: Injectable }
];
/** @nocollapse */
ScriptService.ctorParameters = () => [
{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
];
class TinymceComponent {
constructor(defConfig, ss, cd) {
this.defConfig = defConfig;
this.ss = ss;
this.cd = cd;
this.load = true;
this.id = `_tinymce-${Math.random().toString(36).substring(2)}`;
this._disabled = false;
/** 延迟初始化 */
this.delay = 0;
this.ready = new EventEmitter();
}
set disabled(value) {
this._disabled = value;
this.setDisabled();
}
set loading(value) {
if (value instanceof TemplateRef) {
this._loading = null;
this._loadingTpl = value;
}
else {
this._loading = value;
}
}
get instance() {
return this._instance;
}
initDelay() {
if (this.delay > 0) {
setTimeout(() => this.init(), this.delay);
}
else {
this.init();
}
}
init() {
if (!window.tinymce)
throw new Error('tinymce js文件加载失败');
const { defConfig, config, id } = this;
if (this._instance)
return;
if (defConfig.baseURL) {
let url = '' + defConfig.baseURL;
if (url.endsWith('/'))
url = url.substr(0, url.length - 1);
tinymce.baseURL = url;
}
const userOptions = Object.assign({}, defConfig.config, config);
const options = Object.assign({
selector: `#` + id,
}, defConfig.config, config, {
setup: (editor) => {
this._instance = editor;
editor.on('change keyup', () => {
this.value = editor.getContent();
this.onChange(this.value);
this.cd.detectChanges();
});
if (typeof userOptions.setup === 'function') {
userOptions.setup(editor);
}
},
init_instance_callback: (editor) => {
if (editor && this.value)
editor.setContent(this.value);
this.setDisabled();
if (typeof userOptions.init_instance_callback === 'function') {
userOptions.init_instance_callback(editor);
}
this.ready.emit(this._instance);
},
});
if (userOptions.auto_focus) {
options.auto_focus = id;
}
tinymce.init(options);
this.load = false;
this.cd.detectChanges();
}
destroy() {
if (!this._instance) {
return;
}
this._instance.off();
this._instance.remove('#' + this.id);
this._instance = null;
}
setDisabled() {
if (!this._instance)
return;
this._instance.setMode(this._disabled ? 'readonly' : 'design');
}
ngAfterViewInit() {
// 已经存在对象无须进入懒加载模式
if (window.tinymce) {
this.initDelay();
return;
}
const { defConfig } = this;
const baseURL = defConfig && defConfig.baseURL;
const fileName = defConfig && defConfig.fileName;
this.ss
.load((baseURL || './assets/tinymce/') + (fileName || 'tinymce.min.js'))
.getChangeEmitter()
.subscribe(() => this.initDelay());
}
ngOnChanges(changes) {
if (this._instance && changes.config) {
this.destroy();
this.initDelay();
}
}
ngOnDestroy() {
this.destroy();
}
// reuse-tab: http://ng-alain.com/components/reuse-tab#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F
_onReuseInit() {
this.destroy();
this.initDelay();
}
writeValue(value) {
// value should be NOT NULL
this.value = value || '';
if (this._instance) {
this._instance.setContent(this.value);
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.setDisabled();
}
}
TinymceComponent.decorators = [
{ type: Component, args: [{
selector: 'tinymce',
template: "<textarea id=\"{{id}}\" [placeholder]=\"placeholder\" class=\"tinymce-selector\"></textarea>\n<div class=\"loading\" *ngIf=\"load\">\n <ng-container *ngIf=\"_loading; else _loadingTpl\">{{_loading}}</ng-container>\n</div>\n",
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TinymceComponent),
multi: true,
},
],
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [`tinymce .tinymce-selector { display: none; }`]
}] }
];
/** @nocollapse */
TinymceComponent.ctorParameters = () => [
{ type: TinymceOptions },
{ type: ScriptService },
{ type: ChangeDetectorRef }
];
TinymceComponent.propDecorators = {
config: [{ type: Input }],
placeholder: [{ type: Input }],
disabled: [{ type: Input }],
loading: [{ type: Input }],
delay: [{ type: Input }],
ready: [{ type: Output }]
};
class NgxTinymceModule {
static forRoot(options) {
return {
ngModule: NgxTinymceModule,
providers: [
ScriptService,
{ provide: TinymceOptions, useValue: options },
],
};
}
}
NgxTinymceModule.decorators = [
{ type: NgModule, args: [{
imports: [CommonModule],
declarations: [TinymceComponent],
exports: [TinymceComponent],
},] }
];
/**
* Generated bundle index. Do not edit.
*/
export { ScriptService as ɵa, TinymceComponent, TinymceOptions, NgxTinymceModule };
//# sourceMappingURL=ngx-tinymce.js.map