diff --git a/html/src/components/app.tsx b/html/src/components/app.tsx
index dfe4b1e..a899b7f 100644
--- a/html/src/components/app.tsx
+++ b/html/src/components/app.tsx
@@ -1,7 +1,7 @@
import { h, Component } from 'preact';
import { ITerminalOptions, ITheme } from 'xterm';
-import { Xterm } from './terminal';
+import { ClientOptions, Xterm } from './terminal';
if ((module as any).hot) {
// tslint:disable-next-line:no-var-requires
@@ -12,6 +12,12 @@ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const path = window.location.pathname.replace(/[\/]+$/, '');
const wsUrl = [protocol, '//', window.location.host, path, '/ws', window.location.search].join('');
const tokenUrl = [window.location.protocol, '//', window.location.host, path, '/token'].join('');
+const clientOptions = {
+ rendererType: 'webgl',
+ disableLeaveAlert: false,
+ disableResizeOverlay: false,
+ titleFixed: null,
+} as ClientOptions;
const termOptions = {
fontSize: 13,
fontFamily: 'Menlo For Powerline,Consolas,Liberation Mono,Menlo,Courier,monospace',
@@ -40,6 +46,14 @@ const termOptions = {
export class App extends Component {
render() {
- return ;
+ return (
+
+ );
}
}
diff --git a/html/src/components/terminal/index.tsx b/html/src/components/terminal/index.tsx
index 870261f..8d5ec14 100644
--- a/html/src/components/terminal/index.tsx
+++ b/html/src/components/terminal/index.tsx
@@ -32,11 +32,19 @@ const enum Command {
RESIZE_TERMINAL = '1',
}
+export interface ClientOptions {
+ rendererType: 'dom' | 'canvas' | 'webgl';
+ disableLeaveAlert: boolean;
+ disableResizeOverlay: boolean;
+ titleFixed: string;
+}
+
interface Props {
id: string;
wsUrl: string;
tokenUrl: string;
- options: ITerminalOptions;
+ clientOptions: ClientOptions;
+ termOptions: ITerminalOptions;
}
export class Xterm extends Component {
@@ -44,9 +52,11 @@ export class Xterm extends Component {
private textDecoder: TextDecoder;
private container: HTMLElement;
private terminal: Terminal;
+
private fitAddon: FitAddon;
private overlayAddon: OverlayAddon;
private zmodemAddon: ZmodemAddon;
+
private socket: WebSocket;
private token: string;
private title: string;
@@ -149,7 +159,7 @@ export class Xterm extends Component {
@bind
private openTerminal() {
- this.terminal = new Terminal(this.props.options);
+ this.terminal = new Terminal(this.props.termOptions);
const { terminal, container, fitAddon, overlayAddon } = this;
window.term = terminal as TtydTerminal;
window.term.fit = () => {
@@ -190,6 +200,54 @@ export class Xterm extends Component {
socket.onerror = this.onSocketError;
}
+ @bind
+ private applyOptions(options: any) {
+ const { terminal, fitAddon } = this;
+ const isWebGL2Available = () => {
+ try {
+ const canvas = document.createElement('canvas');
+ return !!(window.WebGL2RenderingContext && canvas.getContext('webgl2'));
+ } catch (e) {
+ return false;
+ }
+ };
+
+ Object.keys(options).forEach(key => {
+ const value = options[key];
+ switch (key) {
+ case 'rendererType':
+ if (value === 'webgl' && isWebGL2Available()) {
+ terminal.loadAddon(new WebglAddon());
+ console.log(`[ttyd] WebGL renderer enabled`);
+ }
+ break;
+ case 'disableLeaveAlert':
+ if (value) {
+ window.removeEventListener('beforeunload', this.onWindowUnload);
+ console.log('[ttyd] Leave site alert disabled');
+ }
+ break;
+ case 'disableResizeOverlay':
+ if (value) {
+ console.log(`[ttyd] Resize overlay disabled`);
+ this.resizeOverlay = false;
+ }
+ break;
+ case 'titleFixed':
+ if (!value || value === '') return;
+ console.log(`[ttyd] setting fixed title: ${value}`);
+ this.titleFixed = value;
+ document.title = value;
+ break;
+ default:
+ console.log(`[ttyd] option: ${key}=${value}`);
+ terminal.setOption(key, value);
+ if (key.indexOf('font') === 0) fitAddon.fit();
+ break;
+ }
+ });
+ }
+
@bind
private onSocketOpen() {
console.log('[ttyd] websocket connection opened');
@@ -208,6 +266,8 @@ export class Xterm extends Component {
fitAddon.fit();
}
+ this.applyOptions(this.props.clientOptions);
+
terminal.focus();
}
@@ -235,7 +295,7 @@ export class Xterm extends Component {
@bind
private onSocketData(event: MessageEvent) {
- const { terminal, textDecoder, zmodemAddon, fitAddon } = this;
+ const { textDecoder, zmodemAddon } = this;
const rawData = event.data as ArrayBuffer;
const cmd = String.fromCharCode(new Uint8Array(rawData)[0]);
const data = rawData.slice(1);
@@ -249,44 +309,7 @@ export class Xterm extends Component {
document.title = this.title;
break;
case Command.SET_PREFERENCES:
- const preferences = JSON.parse(textDecoder.decode(data));
- Object.keys(preferences).forEach(key => {
- const value = preferences[key];
- switch (key) {
- case 'rendererType':
- if (preferences[key] === 'webgl') {
- terminal.loadAddon(new WebglAddon());
- console.log(`[ttyd] WebGL renderer enabled`);
- }
- break;
- case 'disableLeaveAlert':
- if (preferences[key]) {
- window.removeEventListener('beforeunload', this.onWindowUnload);
- console.log('[ttyd] Leave site alert disabled');
- }
- break;
- case 'disableResizeOverlay':
- if (preferences[key]) {
- console.log(`[ttyd] disabled resize overlay`);
- this.resizeOverlay = false;
- }
- break;
- case 'fontSize':
- console.log(`[ttyd] setting font size to ${value}`);
- terminal.setOption(key, value);
- fitAddon.fit();
- break;
- case 'titleFixed':
- console.log(`[ttyd] setting fixed title: ${value}`);
- this.titleFixed = value;
- document.title = value;
- break;
- default:
- console.log(`[ttyd] option: ${key}=${value}`);
- terminal.setOption(key, value);
- break;
- }
- });
+ this.applyOptions(JSON.parse(textDecoder.decode(data)));
break;
default:
console.warn(`[ttyd] unknown command: ${cmd}`);