UNPKG

ngx-tinymce

Version:
246 lines (240 loc) 10.7 kB
import * as i0 from '@angular/core'; import { inject, signal, input, booleanAttribute, TemplateRef, numberAttribute, output, afterNextRender, effect, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component, makeEnvironmentProviders } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { NuLazyService } from '@ng-util/lazy'; import { DOCUMENT, NgTemplateOutlet } from '@angular/common'; class TinymceOptions { /** 指定tinymce目录路径,默认:`./assets/tinymce/` */ baseURL = './assets/tinymce/'; /** 指定tinymce文件名,默认:`tinymce.min.js` */ fileName = 'tinymce.min.js'; /** 默认配置项,对全局 Tinymce 有效 */ config; /** 延迟加载(单位:毫秒),默认:`0` */ delay; } const isSSR = !(typeof document === 'object' && !!document); /** * Angular for tinymce, You can modify the global configuration via `provideTinymce` */ class TinymceComponent { defConfig = inject(TinymceOptions, { optional: true }); lazySrv = inject(NuLazyService); doc = inject(DOCUMENT); _instance; value = ''; load = signal(true, { ...(ngDevMode ? { debugName: "load" } : {}) }); id = `_tinymce-${Math.random().toString(36).substring(2)}`; onChange; onTouched; config = input(null, { ...(ngDevMode ? { debugName: "config" } : {}) }); placeholder = input('', { ...(ngDevMode ? { debugName: "placeholder" } : {}) }); inline = input(false, { ...(ngDevMode ? { debugName: "inline" } : {}), transform: booleanAttribute }); disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute }); _disabled = signal(false, { ...(ngDevMode ? { debugName: "_disabled" } : {}) }); _loading = signal(null, { ...(ngDevMode ? { debugName: "_loading" } : {}) }); _loadingTpl = signal(null, { ...(ngDevMode ? { debugName: "_loadingTpl" } : {}) }); loading = input(null, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: (value) => { if (value instanceof TemplateRef) { this._loading.set(null); this._loadingTpl.set(value); } else { this._loading.set(value); } return value; } }); /** 延迟初始化 */ delay = input(0, { ...(ngDevMode ? { debugName: "delay" } : {}), transform: numberAttribute }); ready = output(); get instance() { return this._instance; } constructor() { afterNextRender(() => { if (isSSR) { return; } // 已经存在对象无须进入懒加载模式 if (this.win.tinymce) { this.initDelay(); return; } const { defConfig } = this; const baseURL = defConfig && defConfig.baseURL; const fileName = defConfig && defConfig.fileName; const url = (baseURL ?? './assets/tinymce/') + (fileName ?? 'tinymce.min.js'); this.lazySrv.monitor(url).subscribe(() => this.initDelay()); this.lazySrv.load(url); }); effect(() => { const cfg = this.config(); if (!this._instance) return; this.destroy(); if (cfg) this.initDelay(); }); } get win() { return this.doc.defaultView ?? window; } initDelay() { if (isSSR) { return; } setTimeout(() => this.init(), Math.max(0, this.delay())); } init() { const win = this.win; if (!win.tinymce) { throw new Error('tinymce js文件加载失败'); } const { defConfig, config, id, inline } = this; if (this._instance) { return; } if (defConfig?.baseURL) { let url = '' + defConfig.baseURL; if (url.endsWith('/')) { url = url.substring(0, url.length - 1); } win.tinymce.baseURL = url; } const userOptions = { ...defConfig?.config, ...config() }; const options = { selector: `#` + id, inline: inline(), ...defConfig?.config, ...config(), setup: (editor) => { this._instance = editor; if (this.onChange) { editor.on('change keyup', () => { this.value = editor.getContent(); this.onChange(this.value); }); } 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(editor); }, }; if (userOptions.auto_focus) { options.auto_focus = id; } win.tinymce.init(options); this.load.set(false); } destroy() { if (this._instance == null) { return; } this._instance.off(); this._instance.remove(); this._instance = null; } setDisabled() { if (!this._instance) { return; } const mode = this.disabled() || this._disabled() ? 'readonly' : 'design'; // Compatible with 5 const setMode5 = this._instance.setMode; if (typeof setMode5 === 'function') { setMode5(mode); } else { this._instance.mode.set(mode); } } ngOnDestroy() { this.destroy(); } writeValue(value) { // value should be NOT NULL this.value = value ?? ''; this._instance?.setContent(this.value); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this._disabled.set(isDisabled); this.setDisabled(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TinymceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: TinymceComponent, isStandalone: true, selector: "tinymce", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { ready: "ready" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TinymceComponent), multi: true, }, ], exportAs: ["tinymce"], ngImport: i0, template: ` @if (inline()) { <div [attr.id]="id"><ng-content /></div> } @else { <textarea [attr.id]="id" [attr.placeholder]="placeholder()" class="tinymce-selector"></textarea> } @if (load()) { <div class="loading"> @if (_loading()) { {{ _loading() }} } @else { <ng-template [ngTemplateOutlet]="_loadingTpl()" /> } </div> } `, isInline: true, styles: ["tinymce .tinymce-selector{display:none}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: TinymceComponent, decorators: [{ type: Component, args: [{ selector: 'tinymce', exportAs: 'tinymce', template: ` @if (inline()) { <div [attr.id]="id"><ng-content /></div> } @else { <textarea [attr.id]="id" [attr.placeholder]="placeholder()" class="tinymce-selector"></textarea> } @if (load()) { <div class="loading"> @if (_loading()) { {{ _loading() }} } @else { <ng-template [ngTemplateOutlet]="_loadingTpl()" /> } </div> } `, imports: [NgTemplateOutlet], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TinymceComponent), multi: true, }, ], preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["tinymce .tinymce-selector{display:none}\n"] }] }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], ready: [{ type: i0.Output, args: ["ready"] }] } }); /** * Sets up providers necessary to config for the Tinymce. * @example * bootstrapApplication(AppComponent, { * providers: [provideTinymce({baseURL: '//cdn.tiny.cloud/1/no-api-key/tinymce/6/'})] * }); */ function provideTinymce(options) { return makeEnvironmentProviders([{ provide: TinymceOptions, useValue: options }]); } /** * Generated bundle index. Do not edit. */ export { TinymceComponent, TinymceOptions, provideTinymce }; //# sourceMappingURL=ngx-tinymce.mjs.map