UNPKG

ngx-jodit-pro

Version:

Angular wrapper for Jodit Pro WYSIWYG editor

231 lines (227 loc) 9.94 kB
import * as i0 from '@angular/core'; import { EventEmitter, forwardRef, Component, ChangeDetectionStrategy, ViewChild, Input, Output } from '@angular/core'; import { CommonModule } from '@angular/common'; import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import { BehaviorSubject, combineLatest, distinctUntilChanged, filter, withLatestFrom, delay } from 'rxjs'; class NgxJoditProComponent { set options(value) { this._options = value; if (value) { this.initJoditContainer().then(); } } set value(value) { const sanitizedText = this.prepareText(value); if (!this.internValueChange) { this.valueSubject.next(sanitizedText); } else { this.internValueChange = false; } this.onChange(sanitizedText); } get value() { return this.valueSubject.getValue(); } constructor(cdr) { this.cdr = cdr; /** * options for jodit pro. It's of type partial because Config is imported from jodit packge and doesn't contain jodit-pro options. * You can add more supported options even Typescript doesn't suggest the options. */ this._options = {}; // value property (subject) this.valueSubject = new BehaviorSubject(''); this.valueChange = new EventEmitter(); //events this.joditChange = new EventEmitter(); this.joditKeyDown = new EventEmitter(); this.joditKeyUp = new EventEmitter(); this.joditMousedown = new EventEmitter(); this.joditMouseup = new EventEmitter(); this.joditClick = new EventEmitter(); this.joditFocus = new EventEmitter(); this.joditPaste = new EventEmitter(); this.joditResize = new EventEmitter(); this.joditBeforeEnter = new EventEmitter(); this.joditBeforeCommand = new EventEmitter(); this.joditAfterExec = new EventEmitter(); this.joditAfterPaste = new EventEmitter(); this.joditChangeSelection = new EventEmitter(); // Used for delay value assignment to wait for jodit to be initialized this.joditInitializedSubject = new BehaviorSubject(false); this.internValueChange = false; /* FUNCTIONS RELEVANT FOR ANGULAR FORMS */ this.onChange = (text) => { // implemented by user }; this.onTouched = () => { // implemented by user }; this.valueSubscription = combineLatest([ // Handle value changes ... this.valueSubject.asObservable().pipe(distinctUntilChanged()), // ...additionally ensuring that the value is reapplied if the editor was not initialized when value was set this.joditInitializedSubject.pipe(distinctUntilChanged(), filter(initialized => initialized)) ]).pipe( // Pass through the latest value in case of editor initialization withLatestFrom(this.valueSubject), // Prevent ExpressionChangedAfterItHasBeenCheckedError delay(0)).subscribe(([[_, initialized], text]) => { if (this.jodit && initialized) { this.jodit.setEditorValue(text); } }); } isHTML(text) { const elem = document.createElement('div'); elem.innerHTML = text; return (text && elem.childNodes.length > 0 && elem.childNodes.item(0).nodeType !== 3); } async ngAfterViewInit() { await this.initJoditContainer(); } ngOnDestroy() { this.valueSubscription?.unsubscribe(); this.jodit?.events.destruct(); } async initJoditContainer() { if (this.joditContainer?.nativeElement) { if (this.jodit) { this.jodit.destruct(); this.joditInitializedSubject.next(false); } this.jodit = Jodit.make(this.joditContainer.nativeElement, this._options); await this.jodit.waitForReady(); this.jodit.setEditorValue(this.valueSubject.getValue()); this.jodit.events.on('change', (text) => { this.internValueChange = true; this.changeValue(text); this.joditChange.emit(text); this.onChange(text); }); this.jodit.events.on('keydown', (a) => { this.joditKeyDown.emit(a); }); this.jodit.events.on('keyup', (a) => { this.joditKeyUp.emit(a); }); this.jodit.events.on('mousedown', (a) => { this.joditMousedown.emit(a); }); this.jodit.events.on('mouseup', (a) => { this.joditMouseup.emit(a); }); this.jodit.events.on('click', (a) => { this.joditClick.emit(a); this.onTouched(); }); this.jodit.events.on('focus', (a) => { this.joditFocus.emit(a); }); this.jodit.events.on('paste', (a) => { this.joditPaste.emit(a); }); this.jodit.events.on('resize', () => { this.joditResize.emit(); }); this.jodit.events.on('beforeEnter', (a) => { this.joditBeforeEnter.emit(a); }); this.jodit.events.on('beforeCommand', (a) => { this.joditBeforeCommand.emit(a); }); this.jodit.events.on('afterExec', () => { this.joditAfterExec.emit(); }); this.jodit.events.on('afterPaste', (a) => { this.joditAfterPaste.emit(a); }); this.jodit.events.on('changeSelection', () => { this.joditChangeSelection.emit(); }); this.joditInitializedSubject.next(true); } } changeValue(value) { this.valueChange.emit(value); } writeValue(text) { this.valueSubject.next(this.prepareText(text)); } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.options = { ...this._options, disabled: isDisabled }; } prepareText(text) { return this.isHTML(text) ? text : `<p>${text}</p>`; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NgxJoditProComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: NgxJoditProComponent, isStandalone: true, selector: "ngx-jodit-pro", inputs: { options: "options", value: "value" }, outputs: { valueChange: "valueChange", joditChange: "joditChange", joditKeyDown: "joditKeyDown", joditKeyUp: "joditKeyUp", joditMousedown: "joditMousedown", joditMouseup: "joditMouseup", joditClick: "joditClick", joditFocus: "joditFocus", joditPaste: "joditPaste", joditResize: "joditResize", joditBeforeEnter: "joditBeforeEnter", joditBeforeCommand: "joditBeforeCommand", joditAfterExec: "joditAfterExec", joditAfterPaste: "joditAfterPaste", joditChangeSelection: "joditChangeSelection" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxJoditProComponent), multi: true }], viewQueries: [{ propertyName: "joditContainer", first: true, predicate: ["joditContainer"], descendants: true }], ngImport: i0, template: "<textarea class=\"ngx-jodit-container\" #joditContainer></textarea>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: NgxJoditProComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-jodit-pro', standalone: true, imports: [CommonModule, FormsModule], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxJoditProComponent), multi: true }], changeDetection: ChangeDetectionStrategy.OnPush, template: "<textarea class=\"ngx-jodit-container\" #joditContainer></textarea>\n" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { joditContainer: [{ type: ViewChild, args: ['joditContainer', { static: false }] }], options: [{ type: Input }], value: [{ type: Input }], valueChange: [{ type: Output }], joditChange: [{ type: Output }], joditKeyDown: [{ type: Output }], joditKeyUp: [{ type: Output }], joditMousedown: [{ type: Output }], joditMouseup: [{ type: Output }], joditClick: [{ type: Output }], joditFocus: [{ type: Output }], joditPaste: [{ type: Output }], joditResize: [{ type: Output }], joditBeforeEnter: [{ type: Output }], joditBeforeCommand: [{ type: Output }], joditAfterExec: [{ type: Output }], joditAfterPaste: [{ type: Output }], joditChangeSelection: [{ type: Output }] } }); /** * Generated bundle index. Do not edit. */ export { NgxJoditProComponent }; //# sourceMappingURL=ngx-jodit-pro.mjs.map