UNPKG

ngx-jodit

Version:

Angular wrapper for jodit WYSIWYG editor

232 lines (228 loc) 9.63 kB
import { CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { EventEmitter, forwardRef, Component, ChangeDetectionStrategy, ViewChild, Input, Output } from '@angular/core'; import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms'; import { Jodit } from 'jodit'; import { BehaviorSubject, combineLatest, distinctUntilChanged, filter, withLatestFrom, delay } from 'rxjs'; class NgxJoditComponent { set options(value) { this._options = value; if (value) { this.initJoditContainer(); } } 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; // 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.value = text; } }); } isHTML(text) { const elem = document.createElement('div'); elem.innerHTML = text; return (text && elem.childNodes.length > 0 && elem.childNodes.item(0).nodeType !== 3); } ngAfterViewInit() { this.initJoditContainer(); } ngOnDestroy() { this.valueSubscription?.unsubscribe(); this.jodit?.destruct(); } initJoditContainer() { if (this.joditContainer) { if (this.jodit) { this.jodit.destruct(); this.joditInitializedSubject.next(false); } this.jodit = Jodit.make(this.joditContainer.nativeElement, this._options); this.jodit.value = 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: NgxJoditComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: NgxJoditComponent, isStandalone: true, selector: "ngx-jodit", 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(() => NgxJoditComponent), 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: NgxJoditComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-jodit', standalone: true, imports: [CommonModule, FormsModule], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxJoditComponent), multi: true, }, ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<textarea class=\"ngx-jodit-container\" #joditContainer></textarea>\n" }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { joditContainer: [{ type: ViewChild, args: ['joditContainer'] }], 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 { NgxJoditComponent }; //# sourceMappingURL=ngx-jodit.mjs.map