ngx-jodit-pro
Version:
Angular wrapper for Jodit Pro WYSIWYG editor
231 lines (227 loc) • 9.94 kB
JavaScript
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