UNPKG

@ctrl/ngx-codemirror

Version:
258 lines (253 loc) 10.3 kB
import * as i0 from '@angular/core'; import { EventEmitter, forwardRef, Component, ChangeDetectionStrategy, Input, Output, ViewChild, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; function normalizeLineEndings(str) { if (!str) { return str; } return str.replace(/\r\n|\r/g, '\n'); } class CodemirrorComponent { _differs; _ngZone; /* class applied to the created textarea */ className = ''; /* name applied to the created textarea */ name = 'codemirror'; /* autofocus setting applied to the created textarea */ autoFocus = false; /** * set options for codemirror * @link http://codemirror.net/doc/manual.html#config */ set options(value) { this._options = value; if (!this._differ && value) { this._differ = this._differs.find(value).create(); } } /* preserve previous scroll position after updating value */ preserveScrollPosition = false; /* called when the text cursor is moved */ cursorActivity = new EventEmitter(); /* called when the editor is focused or loses focus */ focusChange = new EventEmitter(); /* called when the editor is scrolled */ // eslint-disable-next-line @angular-eslint/no-output-native scroll = new EventEmitter(); /* called when file(s) are dropped */ // eslint-disable-next-line @angular-eslint/no-output-native drop = new EventEmitter(); /* called when codeMirror instance is initiated on the component */ codeMirrorLoaded = new EventEmitter(); ref; value = ''; disabled = false; isFocused = false; codeMirror; /** * either global variable or required library */ _codeMirror; _differ; _options; constructor(_differs, _ngZone) { this._differs = _differs; this._ngZone = _ngZone; } get codeMirrorGlobal() { if (this._codeMirror) { return this._codeMirror; } // in order to allow for universal rendering, we import Codemirror runtime with `require` to prevent node errors this._codeMirror = typeof CodeMirror !== 'undefined' ? CodeMirror : import('codemirror'); return this._codeMirror; } ngAfterViewInit() { this._ngZone.runOutsideAngular(async () => { const codeMirrorObj = await this.codeMirrorGlobal; const codeMirror = codeMirrorObj?.default ? codeMirrorObj.default : codeMirrorObj; this.codeMirror = codeMirror.fromTextArea(this.ref.nativeElement, this._options); this.codeMirror.on('cursorActivity', cm => this._ngZone.run(() => this.cursorActive(cm))); this.codeMirror.on('scroll', this.scrollChanged.bind(this)); this.codeMirror.on('blur', () => this._ngZone.run(() => this.focusChanged(false))); this.codeMirror.on('focus', () => this._ngZone.run(() => this.focusChanged(true))); this.codeMirror.on('change', (cm, change) => this._ngZone.run(() => this.codemirrorValueChanged(cm, change))); this.codeMirror.on('drop', (cm, e) => { this._ngZone.run(() => this.dropFiles(cm, e)); }); this.codeMirror.setValue(this.value); this.codeMirrorLoaded.emit(this); }); } ngDoCheck() { if (!this._differ) { return; } // check options have not changed const changes = this._differ.diff(this._options); if (changes) { changes.forEachChangedItem(option => this.setOptionIfChanged(option.key, option.currentValue)); changes.forEachAddedItem(option => this.setOptionIfChanged(option.key, option.currentValue)); changes.forEachRemovedItem(option => this.setOptionIfChanged(option.key, option.currentValue)); } } ngOnDestroy() { // is there a lighter-weight way to remove the cm instance? if (this.codeMirror) { this.codeMirror.toTextArea(); } } codemirrorValueChanged(cm, change) { const cmVal = cm.getValue(); if (this.value !== cmVal) { this.value = cmVal; this.onChange(this.value); } } setOptionIfChanged(optionName, newValue) { if (!this.codeMirror) { return; } // cast to any to handle strictly typed option names // could possibly import settings strings available in the future this.codeMirror.setOption(optionName, newValue); } focusChanged(focused) { this.onTouched(); this.isFocused = focused; this.focusChange.emit(focused); } scrollChanged(cm) { this.scroll.emit(cm.getScrollInfo()); } cursorActive(cm) { this.cursorActivity.emit(cm); } dropFiles(cm, e) { this.drop.emit([cm, e]); } /** Implemented as part of ControlValueAccessor. */ writeValue(value) { if (value === null || value === undefined) { return; } if (!this.codeMirror) { this.value = value; return; } const cur = this.codeMirror.getValue(); if (value !== cur && normalizeLineEndings(cur) !== normalizeLineEndings(value)) { this.value = value; if (this.preserveScrollPosition) { const prevScrollPosition = this.codeMirror.getScrollInfo(); this.codeMirror.setValue(this.value); this.codeMirror.scrollTo(prevScrollPosition.left, prevScrollPosition.top); } else { this.codeMirror.setValue(this.value); } } } /** Implemented as part of ControlValueAccessor. */ registerOnChange(fn) { this.onChange = fn; } /** Implemented as part of ControlValueAccessor. */ registerOnTouched(fn) { this.onTouched = fn; } /** Implemented as part of ControlValueAccessor. */ setDisabledState(isDisabled) { this.disabled = isDisabled; this.setOptionIfChanged('readOnly', this.disabled); } /** Implemented as part of ControlValueAccessor. */ onChange = (_) => { }; /** Implemented as part of ControlValueAccessor. */ onTouched = () => { }; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorComponent, deps: [{ token: i0.KeyValueDiffers }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.1", type: CodemirrorComponent, selector: "ngx-codemirror", inputs: { className: "className", name: "name", autoFocus: "autoFocus", options: "options", preserveScrollPosition: "preserveScrollPosition" }, outputs: { cursorActivity: "cursorActivity", focusChange: "focusChange", scroll: "scroll", drop: "drop", codeMirrorLoaded: "codeMirrorLoaded" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CodemirrorComponent), multi: true, }, ], viewQueries: [{ propertyName: "ref", first: true, predicate: ["ref"], descendants: true }], ngImport: i0, template: ` <textarea [name]="name" class="ngx-codemirror {{ className }}" [class.ngx-codemirror--focused]="isFocused" autocomplete="off" [autofocus]="autoFocus" #ref > </textarea> `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-codemirror', template: ` <textarea [name]="name" class="ngx-codemirror {{ className }}" [class.ngx-codemirror--focused]="isFocused" autocomplete="off" [autofocus]="autoFocus" #ref > </textarea> `, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CodemirrorComponent), multi: true, }, ], preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: function () { return [{ type: i0.KeyValueDiffers }, { type: i0.NgZone }]; }, propDecorators: { className: [{ type: Input }], name: [{ type: Input }], autoFocus: [{ type: Input }], options: [{ type: Input }], preserveScrollPosition: [{ type: Input }], cursorActivity: [{ type: Output }], focusChange: [{ type: Output }], scroll: [{ type: Output }], drop: [{ type: Output }], codeMirrorLoaded: [{ type: Output }], ref: [{ type: ViewChild, args: ['ref'] }] } }); class CodemirrorModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorModule, declarations: [CodemirrorComponent], exports: [CodemirrorComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: CodemirrorModule, decorators: [{ type: NgModule, args: [{ exports: [CodemirrorComponent], declarations: [CodemirrorComponent], }] }] }); /** * Generated bundle index. Do not edit. */ export { CodemirrorComponent, CodemirrorModule }; //# sourceMappingURL=ctrl-ngx-codemirror.mjs.map