UNPKG

@covalent/code-editor

Version:

Teradata UI Platform Code Editor Module

394 lines (389 loc) 16.1 kB
import * as i0 from '@angular/core'; import { EventEmitter, PLATFORM_ID, forwardRef, Component, Inject, ViewChild, Output, Input, NgModule } from '@angular/core'; import { isPlatformServer, CommonModule } from '@angular/common'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { of, Subject, merge, fromEvent, timer } from 'rxjs'; import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { editor, languages } from 'monaco-editor'; import { mixinControlValueAccessor, mixinDisabled } from '@covalent/core/common'; const noop = () => { // empty method }; // counter for ids to allow for multiple editors on one page let uniqueCounter = 0; class TdCodeEditorBase { constructor(_changeDetectorRef) { this._changeDetectorRef = _changeDetectorRef; } } const _TdCodeEditorMixinBase = mixinControlValueAccessor(mixinDisabled(TdCodeEditorBase), []); class TdCodeEditorComponent extends _TdCodeEditorMixinBase { /** * value?: string */ set value(value) { this._value = value; if (this._componentInitialized) { this.applyValue(); } } get value() { return this._value; } applyValue() { if (!this._fromEditor) { this._editor.setValue(this._value || ''); } this._fromEditor = false; this.propagateChange(this._value); this.editorValueChange.emit(); } registerOnChange(fn) { this.propagateChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } /** * getEditorContent?: function * Returns the content within the editor */ getValue() { if (!this._componentInitialized) { return of(''); } setTimeout(() => { this._subject.next(this._value); this._subject.complete(); this._subject = new Subject(); }); return this._subject.asObservable(); } /** * language?: string * language used in editor */ set language(language) { this._language = language; if (this._componentInitialized) { this.applyLanguage(); } } get language() { return this._language; } applyLanguage() { if (this._language) { editor.setModelLanguage(this._editor.getModel(), this._language); this.editorLanguageChanged.emit(); } } /** * registerLanguage?: function * Registers a custom Language within the editor */ registerLanguage(language) { if (this._componentInitialized) { languages.register({ id: language.id }); this._disposables.push(languages.setMonarchTokensProvider(language.id, { tokenizer: { root: language.monarchTokensProvider, }, })); // Define a new theme that constains only rules that match this language editor.defineTheme(language.customTheme.id, language.customTheme.theme); this._theme = language.customTheme.id; this._disposables.push(languages.registerCompletionItemProvider(language.id, { provideCompletionItems: () => { return language.completionItemProvider; }, })); const css = document.createElement('style'); css.type = 'text/css'; css.innerHTML = language.monarchTokensProviderCSS; document.body.appendChild(css); this.editorConfigurationChanged.emit(); this._registeredLanguagesStyles = [ ...this._registeredLanguagesStyles, css, ]; } } /** * style?: string * css style of the editor on the page */ set editorStyle(editorStyle) { this._editorStyle = editorStyle; if (this._componentInitialized) { this.applyStyle(); } } get editorStyle() { return this._editorStyle; } applyStyle() { if (this._editorStyle) { const containerDiv = this._editorContainer.nativeElement; containerDiv.setAttribute('style', this._editorStyle); } } /** * theme?: string * Theme to be applied to editor */ set theme(theme) { this._theme = theme; if (this._componentInitialized) { this._editor.updateOptions({ theme }); this.editorConfigurationChanged.emit(); } } get theme() { return this._theme; } /** * fullScreenKeyBinding?: number * See here for key bindings https://microsoft.github.io/monaco-editor/api/enums/keycode.html * Sets the KeyCode for shortcutting to Fullscreen mode */ set fullScreenKeyBinding(keycode) { this._keycode = keycode; } get fullScreenKeyBinding() { return this._keycode; } /** * editorOptions?: object * Options used on editor instantiation. Available options listed here: * https://microsoft.github.io/monaco-editor/api/interfaces/editor.ieditoroptions.html */ set editorOptions(editorOptions) { this._editorOptions = editorOptions; if (this._componentInitialized) { this._editor.updateOptions(editorOptions); this.editorConfigurationChanged.emit(); } } get editorOptions() { return this._editorOptions; } /** * layout method that calls layout method of editor and instructs the editor to remeasure its container */ layout() { if (this._componentInitialized) { this._editor.layout(); } } /** * Returns if in Full Screen Mode or not */ get isFullScreen() { return this._isFullScreen; } // tslint:disable-next-line:member-ordering constructor(_changeDetectorRef, _elementRef, _ngZone, platformId) { super(_changeDetectorRef); this._elementRef = _elementRef; this._ngZone = _ngZone; this.platformId = platformId; this._destroy = new Subject(); this._widthSubject = new Subject(); this._heightSubject = new Subject(); this._editorStyle = 'width:100%;height:100%;'; this._value = ''; this._theme = 'vs'; this._language = 'javascript'; this._subject = new Subject(); this._editorInnerContainer = 'editorInnerContainer' + uniqueCounter++; this._fromEditor = false; this._componentInitialized = false; this._editorOptions = {}; this._isFullScreen = false; this._registeredLanguagesStyles = []; this._disposables = []; /** * editorInitialized: function($event) * Event emitted when editor is first initialized */ this.editorInitialized = new EventEmitter(); /** * editorConfigurationChanged: function($event) * Event emitted when editor's configuration changes */ this.editorConfigurationChanged = new EventEmitter(); /** * editorLanguageChanged: function($event) * Event emitted when editor's Language changes */ this.editorLanguageChanged = new EventEmitter(); /** * editorValueChange: function($event) * Event emitted any time something changes the editor value */ this.editorValueChange = new EventEmitter(); this.propagateChange = (_) => noop; } ngOnInit() { if (isPlatformServer(this.platformId)) { return; } const containerDiv = this._editorContainer.nativeElement; containerDiv.id = this._editorInnerContainer; this._editor = editor.create(containerDiv, Object.assign({ value: this._value, language: this.language, theme: this._theme, }, this.editorOptions)); this._componentInitialized = true; setTimeout(() => { this.applyLanguage(); this._fromEditor = true; this.applyValue(); this.applyStyle(); this.editorInitialized.emit(this._editor); this.editorConfigurationChanged.emit(); }); // The `onDidChangeContent` returns a disposable object (an object with `dispose()` method) which will cleanup // the listener. The callback, that we pass to `onDidChangeContent`, captures `this`. This leads to a circular reference // (`td-code-editor -> monaco -> td-code-editor`) and prevents the `td-code-editor` from being GC'd. this._disposables.push(this._editor.getModel().onDidChangeContent(() => { this._fromEditor = true; this.writeValue(this._editor.getValue()); this.layout(); })); this.addFullScreenModeCommand(); this._ngZone.runOutsideAngular(() => merge(fromEvent(window, 'resize').pipe(debounceTime(100)), this._widthSubject.asObservable().pipe(distinctUntilChanged()), this._heightSubject.asObservable().pipe(distinctUntilChanged())) .pipe(debounceTime(100), takeUntil(this._destroy)) .subscribe(() => { // Note: this is being called outside of the Angular zone since we don't have to // run change detection whenever the editor resizes itself. this.layout(); })); this._ngZone.runOutsideAngular(() => timer(500, 250) .pipe(takeUntil(this._destroy)) .subscribe(() => { const { width, height } = this._elementRef.nativeElement.getBoundingClientRect(); this._widthSubject.next(width); this._heightSubject.next(height); })); } ngOnDestroy() { var _a; this._changeDetectorRef.detach(); this._registeredLanguagesStyles.forEach((style) => style.remove()); while (this._disposables.length) { (_a = this._disposables.pop()) === null || _a === void 0 ? void 0 : _a.dispose(); } if (this._editor) { this._editor.dispose(); } this._destroy.next(true); this._destroy.unsubscribe(); } /** * showFullScreenEditor request for full screen of Code Editor based on its browser type. */ showFullScreenEditor() { if (this._componentInitialized) { const codeEditorElement = this._editorContainer .nativeElement; codeEditorElement.requestFullscreen(); } this._isFullScreen = true; } /** * exitFullScreenEditor request to exit full screen of Code Editor based on its browser type. */ exitFullScreenEditor() { if (this._componentInitialized) { document.exitFullscreen(); } this._isFullScreen = false; } /** * addFullScreenModeCommand used to add the fullscreen option to the context menu */ addFullScreenModeCommand() { this._disposables.push(this._editor.addAction({ // An unique identifier of the contributed action. id: 'fullScreen', // A label of the action that will be presented to the user. label: 'Full Screen', // An optional array of keybindings for the action. contextMenuGroupId: 'navigation', keybindings: this._keycode, contextMenuOrder: 1.5, // Method that will be executed when the action is triggered. run: () => { this.showFullScreenEditor(); }, })); } } TdCodeEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TdCodeEditorComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); TdCodeEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TdCodeEditorComponent, selector: "td-code-editor", inputs: { value: "value", language: "language", editorStyle: "editorStyle", theme: "theme", fullScreenKeyBinding: "fullScreenKeyBinding", editorOptions: "editorOptions" }, outputs: { editorInitialized: "editorInitialized", editorConfigurationChanged: "editorConfigurationChanged", editorLanguageChanged: "editorLanguageChanged", editorValueChange: "editorValueChange" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TdCodeEditorComponent), multi: true, }, ], viewQueries: [{ propertyName: "_editorContainer", first: true, predicate: ["editorContainer"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"editor-container\" #editorContainer></div>\n", styles: [":host{display:block;position:relative}:host .editor-container{position:absolute;inset:0}::ng-deep .monaco-aria-container{display:none}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TdCodeEditorComponent, decorators: [{ type: Component, args: [{ selector: 'td-code-editor', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TdCodeEditorComponent), multi: true, }, ], template: "<div class=\"editor-container\" #editorContainer></div>\n", styles: [":host{display:block;position:relative}:host .editor-container{position:absolute;inset:0}::ng-deep .monaco-aria-container{display:none}\n"] }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { _editorContainer: [{ type: ViewChild, args: ['editorContainer', { static: true }] }], editorInitialized: [{ type: Output }], editorConfigurationChanged: [{ type: Output }], editorLanguageChanged: [{ type: Output }], editorValueChange: [{ type: Output }], value: [{ type: Input }], language: [{ type: Input }], editorStyle: [{ type: Input }], theme: [{ type: Input }], fullScreenKeyBinding: [{ type: Input }], editorOptions: [{ type: Input }] } }); class CovalentCodeEditorModule { } CovalentCodeEditorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CovalentCodeEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); CovalentCodeEditorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: CovalentCodeEditorModule, bootstrap: [TdCodeEditorComponent], declarations: [TdCodeEditorComponent], imports: [CommonModule], exports: [TdCodeEditorComponent] }); CovalentCodeEditorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CovalentCodeEditorModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: CovalentCodeEditorModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [TdCodeEditorComponent], exports: [TdCodeEditorComponent], bootstrap: [TdCodeEditorComponent], }] }] }); /** * Generated bundle index. Do not edit. */ export { CovalentCodeEditorModule, TdCodeEditorComponent }; //# sourceMappingURL=covalent-code-editor.mjs.map