Use Terminal type in attach, fit and fullscreen

This commit is contained in:
Daniel Imms
2018-01-19 09:30:24 -08:00
parent 682eb2f861
commit ec17fb9179
9 changed files with 94 additions and 67 deletions
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
import { Terminal } from 'xterm';
export interface IAttachAddonTerminal extends Terminal {
__socket?: WebSocket;
__attachSocketBuffer?: string;
__getMessage?(ev: MessageEvent): void;
__flushBuffer?(): void;
__pushToBuffer?(data: string): void;
__sendData?(data: string): void;
}
+1 -1
View File
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('attach addon', () => {
describe('apply', () => {
it('should do register the `attach` and `detach` methods', () => {
attach.apply(MockTerminal);
attach.apply(<any>MockTerminal);
assert.equal(typeof (<any>MockTerminal).prototype.attach, 'function');
assert.equal(typeof (<any>MockTerminal).prototype.detach, 'function');
});
+45 -44
View File
@@ -5,38 +5,42 @@
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
/// <reference path="../../../typings/xterm.d.ts"/>
import { Terminal } from 'xterm';
import { IAttachAddonTerminal } from './Intefaces';
/**
* Attaches the given terminal to the given socket.
*
* @param {Terminal} term - The terminal to be attached to the given socket.
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
* @param term The terminal to be attached to the given socket.
* @param socket The socket to attach the current terminal.
* @param bidirectional Whether the terminal should send data to the socket as well.
* @param buffered Whether the rendering of incoming data should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
export function attach(term: any, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
const addonTerminal = <IAttachAddonTerminal>term;
bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional;
term.socket = socket;
addonTerminal.__socket = socket;
term._flushBuffer = () => {
term.write(term._attachSocketBuffer);
term._attachSocketBuffer = null;
addonTerminal.__flushBuffer = () => {
addonTerminal.write(addonTerminal.__attachSocketBuffer);
addonTerminal.__attachSocketBuffer = null;
};
term._pushToBuffer = (data: string) => {
if (term._attachSocketBuffer) {
term._attachSocketBuffer += data;
addonTerminal.__pushToBuffer = (data: string) => {
if (addonTerminal.__attachSocketBuffer) {
addonTerminal.__attachSocketBuffer += data;
} else {
term._attachSocketBuffer = data;
setTimeout(term._flushBuffer, 10);
addonTerminal.__attachSocketBuffer = data;
setTimeout(addonTerminal.__flushBuffer, 10);
}
};
let myTextDecoder;
term._getMessage = function(ev: MessageEvent): void {
addonTerminal.__getMessage = function(ev: MessageEvent): void {
let str;
if (typeof ev.data === 'object') {
if (ev.data instanceof ArrayBuffer) {
@@ -51,71 +55,68 @@ export function attach(term: any, socket: WebSocket, bidirectional: boolean, buf
}
if (buffered) {
term._pushToBuffer(str || ev.data);
addonTerminal.__pushToBuffer(str || ev.data);
} else {
term.write(str || ev.data);
addonTerminal.write(str || ev.data);
}
};
term._sendData = (data: string) => {
addonTerminal.__sendData = (data: string) => {
if (socket.readyState !== 1) {
return;
}
socket.send(data);
};
socket.addEventListener('message', term._getMessage);
socket.addEventListener('message', addonTerminal.__getMessage);
if (bidirectional) {
term.on('data', term._sendData);
addonTerminal.on('data', addonTerminal.__sendData);
}
socket.addEventListener('close', term.detach.bind(term, socket));
socket.addEventListener('error', term.detach.bind(term, socket));
socket.addEventListener('close', () => detach(addonTerminal, socket));
socket.addEventListener('error', () => detach(addonTerminal, socket));
}
/**
* Detaches the given terminal from the given socket
*
* @param {Terminal} term - The terminal to be detached from the given socket.
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
* @param term The terminal to be detached from the given socket.
* @param socket The socket from which to detach the current terminal.
*/
export function detach(term: any, socket: WebSocket): void {
term.off('data', term._sendData);
export function detach(term: Terminal, socket: WebSocket): void {
const addonTerminal = <IAttachAddonTerminal>term;
addonTerminal.off('data', addonTerminal.__sendData);
socket = (typeof socket === 'undefined') ? term.socket : socket;
socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket;
if (socket) {
socket.removeEventListener('message', term._getMessage);
socket.removeEventListener('message', addonTerminal.__getMessage);
}
delete term.socket;
delete addonTerminal.__socket;
}
export function apply(terminalConstructor: any): void {
export function apply(terminalConstructor: typeof Terminal): void {
/**
* Attaches the current terminal to the given socket
*
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
* @param socket The socket to attach the current terminal.
* @param bidirectional Whether the terminal should send data to the socket as well.
* @param buffered Whether the rendering of incoming data should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
terminalConstructor.prototype.attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
(<any>terminalConstructor.prototype).attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void {
attach(this, socket, bidirectional, buffered);
};
/**
* Detaches the current terminal from the given socket.
*
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
* @param socket The socket from which to detach the current terminal.
*/
terminalConstructor.prototype.detach = function (socket: WebSocket): void {
(<any>terminalConstructor.prototype).detach = function (socket: WebSocket): void {
detach(this, socket);
};
}
+1 -1
View File
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('fit addon', () => {
describe('apply', () => {
it('should do register the `proposeGeometry` and `fit` methods', () => {
fit.apply(MockTerminal);
fit.apply(<any>MockTerminal);
assert.equal(typeof (<any>MockTerminal).prototype.proposeGeometry, 'function');
assert.equal(typeof (<any>MockTerminal).prototype.fit, 'function');
});
+12 -8
View File
@@ -13,12 +13,16 @@
* row and truncate its width with the current number of columns).
*/
/// <reference path="../../../typings/xterm.d.ts"/>
import { Terminal } from 'xterm';
export interface IGeometry {
rows: number;
cols: number;
}
export function proposeGeometry(term: any): IGeometry {
export function proposeGeometry(term: Terminal): IGeometry {
if (!term.element.parentElement) {
return null;
}
@@ -31,30 +35,30 @@ export function proposeGeometry(term: any): IGeometry {
const availableHeight = parentElementHeight - elementPaddingVer;
const availableWidth = parentElementWidth - elementPaddingHor;
const geometry = {
cols: Math.floor(availableWidth / term.renderer.dimensions.actualCellWidth),
rows: Math.floor(availableHeight / term.renderer.dimensions.actualCellHeight)
cols: Math.floor(availableWidth / (<any>term).renderer.dimensions.actualCellWidth),
rows: Math.floor(availableHeight / (<any>term).renderer.dimensions.actualCellHeight)
};
return geometry;
}
export function fit(term: any): void {
export function fit(term: Terminal): void {
const geometry = proposeGeometry(term);
if (geometry) {
// Force a full render
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
term.renderer.clear();
(<any>term).renderer.clear();
term.resize(geometry.cols, geometry.rows);
}
}
}
export function apply(terminalConstructor: any): void {
terminalConstructor.prototype.proposeGeometry = function (): IGeometry {
export function apply(terminalConstructor: typeof Terminal): void {
(<any>terminalConstructor.prototype).proposeGeometry = function (): IGeometry {
return proposeGeometry(this);
};
terminalConstructor.prototype.fit = function (): void {
(<any>terminalConstructor.prototype).fit = function (): void {
fit(this);
};
}
+1 -1
View File
@@ -12,7 +12,7 @@ class MockTerminal {}
describe('fullscreen addon', () => {
describe('apply', () => {
it('should do register the `toggleFullscreen` method', () => {
fullscreen.apply(MockTerminal);
fullscreen.apply(<any>MockTerminal);
assert.equal(typeof (<any>MockTerminal).prototype.toggleFullScreen, 'function');
});
});
+10 -6
View File
@@ -3,13 +3,17 @@
* @license MIT
*/
/// <reference path="../../../typings/xterm.d.ts"/>
import { Terminal } from 'xterm';
/**
* Toggle the given terminal's fullscreen mode.
* @param {Terminal} term - The terminal to toggle full screen mode
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false)
* @param term The terminal to toggle full screen mode
* @param fullscreen Toggle fullscreen on (true) or off (false)
*/
export function toggleFullScreen(term: any, fullscreen: boolean): void {
let fn;
export function toggleFullScreen(term: Terminal, fullscreen: boolean): void {
let fn: string;
if (typeof fullscreen === 'undefined') {
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add';
@@ -22,8 +26,8 @@ export function toggleFullScreen(term: any, fullscreen: boolean): void {
term.element.classList[fn]('fullscreen');
}
export function apply(terminalConstructor: any): void {
terminalConstructor.prototype.toggleFullScreen = function (fullscreen: boolean): void {
export function apply(terminalConstructor: typeof Terminal): void {
(<any>terminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void {
toggleFullScreen(this, fullscreen);
};
}
+1 -1
View File
@@ -6,7 +6,7 @@
import { Terminal } from 'xterm';
export interface ISearchAddonTerminal extends Terminal {
__searchHelper: ISearchHelper;
__searchHelper?: ISearchHelper;
// TODO: Reuse ITerminal from core
buffer: any;
+5 -5
View File
@@ -16,7 +16,7 @@ import { ISearchAddonTerminal } from './Interfaces';
* @return Whether a result was found.
*/
export function findNext(terminal: Terminal, term: string): boolean {
const addonTerminal = (<ISearchAddonTerminal>terminal);
const addonTerminal = <ISearchAddonTerminal>terminal;
if (!addonTerminal.__searchHelper) {
addonTerminal.__searchHelper = new SearchHelper(addonTerminal);
}
@@ -30,19 +30,19 @@ export function findNext(terminal: Terminal, term: string): boolean {
* @return Whether a result was found.
*/
export function findPrevious(terminal: Terminal, term: string): boolean {
const addonTerminal = (<ISearchAddonTerminal>terminal);
const addonTerminal = <ISearchAddonTerminal>terminal;
if (!addonTerminal.__searchHelper) {
addonTerminal.__searchHelper = new SearchHelper(addonTerminal);
}
return addonTerminal.__searchHelper.findPrevious(term);
}
export function apply(terminalConstructor: any): void {
terminalConstructor.prototype.findNext = function(term: string): boolean {
export function apply(terminalConstructor: typeof Terminal): void {
(<any>terminalConstructor.prototype).findNext = function(term: string): boolean {
return findNext(this, term);
};
terminalConstructor.prototype.findPrevious = function(term: string): boolean {
(<any>terminalConstructor.prototype).findPrevious = function(term: string): boolean {
return findPrevious(this, term);
};
}