inspec/www/tutorial/app/xterm-terminal/xterm-terminal.component.ts
2016-09-01 22:33:41 +01:00

141 lines
4.1 KiB
TypeScript

import { Component, OnInit, Input, Output, EventEmitter, SimpleChange } from '@angular/core';
declare var Terminal: any;
@Component({
selector: 'xterm-terminal',
templateUrl: 'app/xterm-terminal/xterm-terminal.component.html',
styleUrls: ['app/xterm-terminal/xterm-terminal.component.css']
})
export class XtermTerminalComponent implements OnInit {
@Input() response: string;
@Input() responsesArray: any;
@Input() shell: string;
@Output() command: EventEmitter<string> = new EventEmitter<string>();
previousCommands: any = [];
last: number;
currentResponse: string;
shellStatus: string;
buffer: string = '';
// xterm variables
terminalContainer: any;
term: any;
optionElements: any;
cols: string;
rows: string;
shellprompt: string = '$ ';
ngOnInit() {
this.terminalContainer = document.getElementById('terminal-container'),
this.optionElements = {
cursorBlink: true
},
this.cols = '70',
this.rows = '70';
this.createTerminal();
}
ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
if (changes['response'] && this.term) {
this.currentResponse = changes['response'].currentValue;
this.term.writeln(this.currentResponse);
this.setPrompt();
}
}
createTerminal() {
while (this.terminalContainer.children.length) {
this.terminalContainer.removeChild(this.terminalContainer.children[0]);
}
this.term = new Terminal({
cursorBlink: true
});
this.term.open(this.terminalContainer);
this.term.fit();
var initialGeometry = this.term.proposeGeometry(),
cols = initialGeometry.cols,
rows = initialGeometry.rows;
this.cols = cols;
this.rows = rows;
this.runFakeTerminal()
}
runFakeTerminal() {
if (this.term._initialized) {
return;
}
this.term._initialized = true;
this.setPrompt();
}
setPrompt() {
this.buffer = '';
if (this.shell === 'inspec-shell') {
this.term.write('\r\ninspec> ');
} else {
this.term.write('\r\n' + this.shellprompt);
}
}
onKey(ev) {
var shell = null
var printable = ['Alt', 'Control', 'Meta', 'Shift', 'CapsLock', 'Tab', 'Escape'].indexOf(ev.key) == -1
// on enter, save command to array and send current value of buffer
// to parent component (app). if the command is the same as the previous command
// entered, we just diplay the currentResponse. the reason this is being done here and
// not in the app component is because the ngOnChanges that tracks the value of the
// emitted event won't recognize that there has been a change if it is the same
if (ev.keyCode == 13) {
this.previousCommands.push(this.buffer);
this.term.write('\r\n');
if (this.previousCommands.length > 1) {
this.last = this.previousCommands.length - 2
}
if (this.buffer === this.previousCommands[this.last]) {
// if the command is next or last, we still want to emit
// the value, since the parent component is responsible
// for interpreting that value and displaying the correct instructions
if (this.buffer.match(/^next\s*/) || this.buffer.match(/^prev\s*/)) {
this.command.emit(this.buffer);
} else {
this.term.writeln(this.currentResponse);
this.setPrompt();
}
}
else {
this.command.emit(this.buffer);
}
}
// on backspace, pop characters from buffer
else if (ev.keyCode == 8) {
if (this.term.x > 2) {
this.buffer = this.buffer.substr(0, this.buffer.length-1);
this.term.write('\b \b');
}
}
// on up arrow, delete anything on line and print previous command
else if (ev.keyCode === 38) {
let last;
if (this.previousCommands.length > 0) {
last = this.previousCommands.pop();
} else {
last = '';
}
let letters = this.term.x - 2;
for (var i = 0; i < letters; i++) {
this.term.write('\b \b');
}
this.term.write(last);
}
// write each character on prompt line
else if (printable) {
this.term.write(ev.key);
this.buffer += ev.key;
}
}
}