aboutsummaryrefslogtreecommitdiffstats
path: root/webapp/src/app/pages/targets/terminals/terminal.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/app/pages/targets/terminals/terminal.component.ts')
-rw-r--r--webapp/src/app/pages/targets/terminals/terminal.component.ts135
1 files changed, 135 insertions, 0 deletions
diff --git a/webapp/src/app/pages/targets/terminals/terminal.component.ts b/webapp/src/app/pages/targets/terminals/terminal.component.ts
new file mode 100644
index 0000000..0478a08
--- /dev/null
+++ b/webapp/src/app/pages/targets/terminals/terminal.component.ts
@@ -0,0 +1,135 @@
+/**
+* @license
+* Copyright (C) 2018 "IoT.bzh"
+* Author Sebastien Douheret <sebastien@iot.bzh>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { Component, ElementRef, ViewChild, Input, Output, HostListener, EventEmitter, AfterViewInit } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+
+import { Terminal } from 'xterm';
+import * as fit from 'xterm/lib/addons/fit/fit';
+
+export interface ITerminalFont {
+ fontFamily: string;
+ fontSize: string;
+ lineHeight: number;
+ charWidth: number;
+ charHeight: number;
+}
+
+
+@Component({
+ selector: 'xds-terminal',
+ styles: [],
+ template: `
+ <div #terminalContainer></div>
+ `,
+})
+export class TerminalComponent implements AfterViewInit {
+
+ private _xterm: Terminal;
+ private _initDone: boolean;
+
+ @ViewChild('terminalContainer') termContainer: ElementRef;
+
+ @Output() stdin = new EventEmitter<any>();
+ @Output() resize = new EventEmitter<{ cols: number, rows: number }>();
+
+
+ constructor() {
+ this._initDone = false;
+ Terminal.applyAddon(fit);
+
+ this._xterm = new Terminal({
+ cursorBlink: true,
+ // useStyle: true,
+ scrollback: 1000,
+ rows: 24,
+ cols: 80,
+ });
+ }
+
+ // getting the nativeElement only possible after view init
+ ngAfterViewInit() {
+
+ // this now finds the #terminal element
+ this._xterm.open(this.termContainer.nativeElement);
+
+ // the number of rows will determine the size of the terminal screen
+ (<any>this._xterm).fit();
+
+ // Bind input key
+ this._xterm.on('data', (data) => {
+ // console.log(data.charCodeAt(0));
+ this.stdin.emit(this._sanitizeInput(data));
+ return false;
+ });
+
+ this._initDone = true;
+ }
+
+ @Input('stdout')
+ set writeData(data) {
+ if (this._initDone && data !== undefined) {
+ this._xterm.write(data);
+ }
+ }
+
+ @Input('disable')
+ set disable(value: boolean) {
+ if (!this._initDone) {
+ return;
+ }
+
+ this._xterm.setOption('disableStdin', value);
+
+ if (value) {
+ this._xterm.blur();
+ } else {
+ this._xterm.focus();
+ }
+ this._resize();
+ }
+
+ @HostListener('window:resize', ['$event'])
+ onWindowResize(event) {
+ this._resize();
+ }
+
+ /*** Private functions ***/
+
+ private _sanitizeInput(d) {
+ // TODO sanitize ?
+ return d;
+ }
+
+ private _resize() {
+ const geom = fit.proposeGeometry(this._xterm);
+
+ // console.log('DEBUG cols ' + String(geom.cols) + ' rows ' + String(geom.rows));
+
+ if (geom.cols < 0 || geom.cols > 2000 || geom.rows < 0 || geom.rows > 2000) {
+ return;
+ }
+
+ // Update xterm size
+ this._xterm.resize(geom.cols, geom.rows);
+
+ // Send resize event to update remote terminal
+ this.resize.emit({ cols: geom.cols, rows: geom.rows });
+ }
+
+}