import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
forwardRef,
HostListener,
Input,
OnChanges,
OnDestroy,
Output,
SimpleChanges,
ViewChild
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/publish';
import { FileConfig } from '../interfaces/file-config';
import { MonacoConfigService } from '../services/monaco-config.service';
import { PresentationComponent } from '../../presentation/presentation/presentation.component';
declare const monaco: any;
declare const require: any;
@Component({
selector: 'slides-editor',
template: `
`,
styleUrls: ['editor.component.css'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => EditorComponent),
multi: true
}
],
})
export class EditorComponent implements AfterViewInit, OnChanges, OnDestroy {
editSubscription: Subscription;
public editor: any;
@Input() public file: FileConfig;
@Input() fontSize = 12;
@Input() minLines = 6;
private actialFontSize = 12;
@ViewChild('editor') editorContent: ElementRef;
@Output() onCodeChange = new EventEmitter();
private editSub: Subject = new Subject();
autorun: BehaviorSubject = new BehaviorSubject(true);
height = 0;
public code = '';
ngOnChanges(changes: SimpleChanges): void {
if (changes.fontSize && this.editor) {
this.resize();
}
if (changes.file && changes.file.currentValue.code !== this.code) {
this.loadCode(changes.file.currentValue.code);
}
}
calcHeight(lines): number {
const lineHeight = this.actialFontSize * 1.6;
return Math.max(lines * lineHeight, lineHeight * this.minLines);
}
constructor(public monacoConfigService: MonacoConfigService, public presentation: PresentationComponent) {
this.editSubscription = this.editSub.publish(A => this.autorun.switchMap(a => a ? A.debounceTime(1000) : A))
.subscribe(this.onCodeChange);
}
loadCode(code: string) {
this.code = code;
if (this.editor) {
this.editor.getModel().setValue(code);
this.updateHeight(code);
}
}
@HostListener('window:resize')
resize() {
this.calcActualFontSize();
this.editor.updateOptions({fontSize: this.actialFontSize});
this.updateHeight(this.code);
}
calcActualFontSize() {
this.actialFontSize = this.fontSize * document.documentElement.clientWidth / 1800;
}
ngAfterViewInit(): void {
// TODO: This will not work on resize
this.calcActualFontSize();
if (!this.code) {
// tslint:disable-next-line:no-debugger
debugger;
}
const myDiv: HTMLDivElement = this.editorContent.nativeElement;
const model = this.monacoConfigService.monaco.editor.getModel(this.file.path);
this.code = this.file.code;
this.editor = this.monacoConfigService.monaco.editor.create(myDiv,
{
model: model,
scrollBeyondLastLine: true,
readOnly: this.file.readonly,
tabCompletion: true,
wordBasedSuggestions: true,
lineNumbersMinChars: 3,
automaticLayout: true,
fontSize: this.actialFontSize,
lineNumbers: 'off'
});
this.editor.getModel().onDidChangeContent(() => {
this.updateValue(this.editor.getModel().getValue());
});
// Re-running the code on Ctrl + Enter
// TODO
/* tslint:disable */
this.editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
() => this.updateValue(this.editor.getModel().getValue()));
/* tslint:enable */
this.updateHeight(this.file.code);
}
updateHeight(value: string) {
const height = this.calcHeight(value.split('\n').length);
if (this.height !== height) {
this.height = height;
this.editorContent.nativeElement.style.height = height + 'px';
this.editor.layout();
}
}
ngOnDestroy() {
this.editSubscription.unsubscribe();
this.onCodeChange.unsubscribe();
this.editSub.unsubscribe();
}
updateValue(value: string) {
if (this.code !== value) {
this.code = value;
this.updateHeight(value);
this.editSub.next(value);
}
}
ping() {
// TODO: Find a better way.
const model = this.editor.getModel();
const oldFullModelRange = model.getFullModelRange();
const oldModelValueLength = model.getValueLengthInRange(oldFullModelRange);
const endLineNumber = model.getLineCount();
const endColumn = model.getLineMaxColumn(endLineNumber);
model._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, model.getValue(), false, false);
}
}