mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
+50
-919
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,11 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/// <reference path="../../typings/xterm.d.ts"/>
|
||||
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
import type { AddonCollection } from 'types';
|
||||
|
||||
export interface ITabConfig {
|
||||
id: string;
|
||||
label: string;
|
||||
@@ -12,6 +17,7 @@ export interface IControlWindow {
|
||||
readonly id: string;
|
||||
readonly label: string;
|
||||
build(container: HTMLElement): void;
|
||||
setTerminal(terminal: Terminal): void;
|
||||
}
|
||||
|
||||
export class ControlBar {
|
||||
@@ -146,7 +152,7 @@ export class ControlBar {
|
||||
}
|
||||
}
|
||||
|
||||
public registerWindow(window: IControlWindow, options?: { afterId?: string; hidden?: boolean; smallTab?: boolean }): void {
|
||||
public registerWindow<T extends IControlWindow>(window: T, options?: { afterId?: string; hidden?: boolean; smallTab?: boolean }): T {
|
||||
// Create button
|
||||
const button = document.createElement('button');
|
||||
button.id = `${window.id}button`;
|
||||
@@ -187,6 +193,8 @@ export class ControlBar {
|
||||
window.build(content);
|
||||
|
||||
this._tabs.set(window.id, { button, content });
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public setTabVisible(tabId: string, visible: boolean): void {
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
/// <reference path="../../../typings/xterm.d.ts"/>
|
||||
|
||||
export class AddonsWindow implements IControlWindow {
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
import type { AddonCollection } from 'types';
|
||||
import type { IImageAddonOptions } from '@xterm/addon-image';
|
||||
|
||||
export class AddonsWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'addons';
|
||||
public readonly label = 'Addons';
|
||||
|
||||
@@ -141,6 +146,7 @@ export class AddonsWindow implements IControlWindow {
|
||||
const serializeBtn = document.createElement('button');
|
||||
serializeBtn.id = 'serialize';
|
||||
serializeBtn.textContent = 'Serialize the content of terminal';
|
||||
serializeBtn.addEventListener('click', () => serializeButtonHandler(this._terminal, this._addons));
|
||||
wrapper.appendChild(serializeBtn);
|
||||
|
||||
// Write to terminal checkbox
|
||||
@@ -163,6 +169,7 @@ export class AddonsWindow implements IControlWindow {
|
||||
const htmlSerializeBtn = document.createElement('button');
|
||||
htmlSerializeBtn.id = 'htmlserialize';
|
||||
htmlSerializeBtn.textContent = 'Serialize the content of terminal in HTML';
|
||||
htmlSerializeBtn.addEventListener('click', () => htmlSerializeButtonHandler(this._terminal, this._addons));
|
||||
wrapper.appendChild(htmlSerializeBtn);
|
||||
|
||||
// HTML serialize result
|
||||
@@ -244,3 +251,30 @@ export class AddonsWindow implements IControlWindow {
|
||||
return this._findResultsSpan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function serializeButtonHandler(term: Terminal, addons: AddonCollection): void {
|
||||
const output = addons.serialize.instance.serialize();
|
||||
const outputString = JSON.stringify(output);
|
||||
|
||||
document.getElementById('serialize-output').innerText = outputString;
|
||||
if ((document.getElementById('write-to-terminal') as HTMLInputElement).checked) {
|
||||
term.reset();
|
||||
term.write(output);
|
||||
}
|
||||
}
|
||||
|
||||
function htmlSerializeButtonHandler(term: Terminal, addons: AddonCollection): void {
|
||||
const output = addons.serialize.instance.serializeAsHTML();
|
||||
document.getElementById('htmlserialize-output').innerText = output;
|
||||
|
||||
// Deprecated, but the most supported for now.
|
||||
function listener(e: any): void {
|
||||
e.clipboardData.setData('text/html', output);
|
||||
e.preventDefault();
|
||||
}
|
||||
document.addEventListener('copy', listener);
|
||||
document.execCommand('copy');
|
||||
document.removeEventListener('copy', listener);
|
||||
document.getElementById('htmlserialize-output-result').innerText = 'Copied to clipboard';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2025 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/// <reference path="../../../typings/xterm.d.ts"/>
|
||||
|
||||
import type { AddonCollection } from '../../types';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
|
||||
export abstract class BaseWindow implements IControlWindow {
|
||||
protected get _terminal(): Terminal { return this.__terminal; }
|
||||
|
||||
constructor(
|
||||
private __terminal: Terminal,
|
||||
protected readonly _addons: AddonCollection,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
setTerminal(terminal: Terminal): void {
|
||||
this.__terminal = terminal;
|
||||
}
|
||||
|
||||
abstract id: string;
|
||||
abstract label: string;
|
||||
abstract build(container: HTMLElement): void;
|
||||
}
|
||||
@@ -3,9 +3,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
|
||||
export class GpuWindow implements IControlWindow {
|
||||
export class GpuWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'gpu';
|
||||
public readonly label = 'GPU';
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { Terminal, ITheme } from '@xterm/xterm';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
import type { AddonCollection } from 'types';
|
||||
|
||||
const xtermjsTheme: ITheme = {
|
||||
foreground: '#F8F8F8',
|
||||
@@ -29,23 +31,23 @@ const xtermjsTheme: ITheme = {
|
||||
brightWhite: '#FFFFFF'
|
||||
};
|
||||
|
||||
export class OptionsWindow implements IControlWindow {
|
||||
export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'options';
|
||||
public readonly label = 'Options';
|
||||
|
||||
private _container: HTMLElement;
|
||||
private _optionsContainer: HTMLElement;
|
||||
private _term: Terminal;
|
||||
private _autoResize: boolean = true;
|
||||
private _updateTerminalSize: () => void;
|
||||
private _updateTerminalContainerBackground: () => void;
|
||||
|
||||
constructor(
|
||||
updateTerminalSize: () => void,
|
||||
updateTerminalContainerBackground: () => void
|
||||
terminal: Terminal,
|
||||
addons: AddonCollection,
|
||||
private readonly _handlers: {
|
||||
updateTerminalSize: () => void,
|
||||
updateTerminalContainerBackground: () => void
|
||||
},
|
||||
) {
|
||||
this._updateTerminalSize = updateTerminalSize;
|
||||
this._updateTerminalContainerBackground = updateTerminalContainerBackground;
|
||||
super(terminal, addons)
|
||||
}
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
@@ -64,9 +66,7 @@ export class OptionsWindow implements IControlWindow {
|
||||
container.appendChild(this._optionsContainer);
|
||||
}
|
||||
|
||||
public initOptions(term: Terminal, addDomListener: (el: HTMLElement, type: string, handler: (...args: any[]) => any) => void): void {
|
||||
this._term = term;
|
||||
|
||||
public initOptions(addDomListener: (el: HTMLElement, type: string, handler: (...args: any[]) => any) => void): void {
|
||||
const blacklistedOptions = [
|
||||
'cancelEvents',
|
||||
'convertEol',
|
||||
@@ -91,11 +91,11 @@ export class OptionsWindow implements IControlWindow {
|
||||
wordSeparator: null,
|
||||
colsRows: null
|
||||
};
|
||||
const options = Object.getOwnPropertyNames(term.options);
|
||||
const options = Object.getOwnPropertyNames(this._terminal.options);
|
||||
const booleanOptions: string[] = [];
|
||||
const numberOptions: string[] = [];
|
||||
options.filter(o => blacklistedOptions.indexOf(o) === -1).forEach(o => {
|
||||
switch (typeof term.options[o]) {
|
||||
switch (typeof this._terminal.options[o]) {
|
||||
case 'boolean':
|
||||
booleanOptions.push(o);
|
||||
break;
|
||||
@@ -112,21 +112,21 @@ export class OptionsWindow implements IControlWindow {
|
||||
let html = '';
|
||||
html += '<div class="option-group">';
|
||||
booleanOptions.forEach(o => {
|
||||
html += `<div class="option"><label><input id="opt-${o}" type="checkbox" ${term.options[o] ? 'checked' : ''}/> ${o}</label></div>`;
|
||||
html += `<div class="option"><label><input id="opt-${o}" type="checkbox" ${this._terminal.options[o] ? 'checked' : ''}/> ${o}</label></div>`;
|
||||
});
|
||||
html += '</div><div class="option-group">';
|
||||
numberOptions.forEach(o => {
|
||||
html += `<div class="option"><label>${o} <input id="opt-${o}" type="number" value="${term.options[o] ?? ''}" step="${o === 'lineHeight' || o === 'scrollSensitivity' ? '0.1' : '1'}"/></label></div>`;
|
||||
html += `<div class="option"><label>${o} <input id="opt-${o}" type="number" value="${this._terminal.options[o] ?? ''}" step="${o === 'lineHeight' || o === 'scrollSensitivity' ? '0.1' : '1'}"/></label></div>`;
|
||||
});
|
||||
html += '</div><div class="option-group">';
|
||||
Object.keys(stringOptions).forEach(o => {
|
||||
if (o === 'colsRows') {
|
||||
html += `<div class="option"><label>size (<var>cols</var><code>x</code><var>rows</var> or <code>auto</code>) <input id="opt-${o}" type="text" value="auto"/></label></div>`;
|
||||
} else if (stringOptions[o]) {
|
||||
const selectedOption = o === 'theme' ? 'xtermjs' : term.options[o];
|
||||
const selectedOption = o === 'theme' ? 'xtermjs' : this._terminal.options[o];
|
||||
html += `<div class="option"><label>${o} <select id="opt-${o}">${stringOptions[o]!.map(v => `<option ${v === selectedOption ? 'selected' : ''}>${v}</option>`).join('')}</select></label></div>`;
|
||||
} else {
|
||||
html += `<div class="option"><label>${o} <input id="opt-${o}" type="text" value="${term.options[o]}"/></label></div>`;
|
||||
html += `<div class="option"><label>${o} <input id="opt-${o}" type="text" value="${this._terminal.options[o]}"/></label></div>`;
|
||||
}
|
||||
});
|
||||
html += '</div>';
|
||||
@@ -138,7 +138,7 @@ export class OptionsWindow implements IControlWindow {
|
||||
const input = document.getElementById(`opt-${o}`) as HTMLInputElement;
|
||||
addDomListener(input, 'change', () => {
|
||||
console.log('change', o, input.checked);
|
||||
term.options[o] = input.checked;
|
||||
this._terminal.options[o] = input.checked;
|
||||
});
|
||||
});
|
||||
numberOptions.forEach(o => {
|
||||
@@ -146,16 +146,16 @@ export class OptionsWindow implements IControlWindow {
|
||||
addDomListener(input, 'change', () => {
|
||||
console.log('change', o, input.value);
|
||||
if (o === 'lineHeight') {
|
||||
term.options.lineHeight = parseFloat(input.value);
|
||||
this._terminal.options.lineHeight = parseFloat(input.value);
|
||||
} else if (o === 'scrollSensitivity') {
|
||||
term.options.scrollSensitivity = parseFloat(input.value);
|
||||
this._terminal.options.scrollSensitivity = parseFloat(input.value);
|
||||
} else if (o === 'scrollback') {
|
||||
term.options.scrollback = parseInt(input.value);
|
||||
setTimeout(() => this._updateTerminalSize(), 5);
|
||||
this._terminal.options.scrollback = parseInt(input.value);
|
||||
setTimeout(() => this._handlers.updateTerminalSize(), 5);
|
||||
} else {
|
||||
term.options[o] = parseInt(input.value);
|
||||
this._terminal.options[o] = parseInt(input.value);
|
||||
}
|
||||
this._updateTerminalSize();
|
||||
this._handlers.updateTerminalSize();
|
||||
});
|
||||
});
|
||||
Object.keys(stringOptions).forEach(o => {
|
||||
@@ -167,11 +167,11 @@ export class OptionsWindow implements IControlWindow {
|
||||
const m = input.value.match(/^([0-9]+)x([0-9]+)$/);
|
||||
if (m) {
|
||||
this._autoResize = false;
|
||||
term.resize(parseInt(m[1]), parseInt(m[2]));
|
||||
this._terminal.resize(parseInt(m[1]), parseInt(m[2]));
|
||||
} else {
|
||||
this._autoResize = true;
|
||||
input.value = 'auto';
|
||||
this._updateTerminalSize();
|
||||
this._handlers.updateTerminalSize();
|
||||
}
|
||||
} else if (o === 'theme') {
|
||||
switch (input.value) {
|
||||
@@ -232,9 +232,9 @@ export class OptionsWindow implements IControlWindow {
|
||||
break;
|
||||
}
|
||||
}
|
||||
term.options[o] = value;
|
||||
this._terminal.options[o] = value;
|
||||
if (o === 'theme') {
|
||||
this._updateTerminalContainerBackground();
|
||||
this._handlers.updateTerminalContainerBackground();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
|
||||
export class StyleWindow implements IControlWindow {
|
||||
export class StyleWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'style';
|
||||
public readonly label = 'Style';
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,11 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
|
||||
export class VtWindow implements IControlWindow {
|
||||
export class VtWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'vt';
|
||||
public readonly label = 'VT';
|
||||
|
||||
@@ -23,16 +24,6 @@ export class VtWindow implements IControlWindow {
|
||||
const vtContainer = document.createElement('div');
|
||||
vtContainer.id = 'vt-container';
|
||||
container.appendChild(vtContainer);
|
||||
}
|
||||
|
||||
public initTerminal(term: Terminal): void {
|
||||
this._term = term;
|
||||
this._addVtButtons();
|
||||
}
|
||||
|
||||
private _addVtButtons(): void {
|
||||
const vtContainer = this._container.querySelector('#vt-container');
|
||||
if (!vtContainer) return;
|
||||
|
||||
const vtFragment = document.createDocumentFragment();
|
||||
const buttonSpecs: { [key: string]: { label: string; description: string; paramCount?: number } } = {
|
||||
|
||||
+6
-2
@@ -9,9 +9,13 @@ body {
|
||||
grid-template-rows: 24px 1fr;
|
||||
}
|
||||
|
||||
/* Top banner */
|
||||
body:not(#test) {
|
||||
height: initial;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#banner {
|
||||
background: #2D2E2C;
|
||||
background: #161716;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
+14
-2
@@ -3,9 +3,21 @@
|
||||
<head>
|
||||
<title>xterm.js integration test fixture</title>
|
||||
<link rel="stylesheet" href="/xterm.css" />
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<style>
|
||||
body {
|
||||
font-family: helvetica, sans-serif, arial;
|
||||
font-size: 1em;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
height: 60%;
|
||||
margin: 0 auto;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body id="test">
|
||||
<div id="terminal-container"></div>
|
||||
<script src="/dist/client-bundle.js" defer></script>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* This file is the entry point for browserify.
|
||||
*/
|
||||
|
||||
import type { ImageAddon } from '@xterm/addon-image';
|
||||
import type { AttachAddon } from '@xterm/addon-attach';
|
||||
import type { ClipboardAddon } from '@xterm/addon-clipboard';
|
||||
import type { FitAddon } from '@xterm/addon-fit';
|
||||
import type { LigaturesAddon } from '@xterm/addon-ligatures';
|
||||
import type { ProgressAddon } from '@xterm/addon-progress';
|
||||
import type { SearchAddon } from '@xterm/addon-search';
|
||||
import type { SerializeAddon } from '@xterm/addon-serialize';
|
||||
import type { UnicodeGraphemesAddon } from '@xterm/addon-unicode-graphemes';
|
||||
import type { Unicode11Addon } from '@xterm/addon-unicode11';
|
||||
import type { WebLinksAddon } from '@xterm/addon-web-links';
|
||||
import type { WebglAddon } from '@xterm/addon-webgl';
|
||||
|
||||
export type AddonType = 'attach' | 'clipboard' | 'fit' | 'image' | 'progress' | 'search' | 'serialize' | 'unicode11' | 'unicodeGraphemes' | 'webLinks' | 'webgl' | 'ligatures';
|
||||
|
||||
export interface IDemoAddon<T extends AddonType> {
|
||||
name: T;
|
||||
canChange: boolean;
|
||||
ctor: (
|
||||
T extends 'attach' ? typeof AttachAddon :
|
||||
T extends 'clipboard' ? typeof ClipboardAddon :
|
||||
T extends 'fit' ? typeof FitAddon :
|
||||
T extends 'image' ? typeof ImageAddon :
|
||||
T extends 'ligatures' ? typeof LigaturesAddon :
|
||||
T extends 'progress' ? typeof ProgressAddon :
|
||||
T extends 'search' ? typeof SearchAddon :
|
||||
T extends 'serialize' ? typeof SerializeAddon :
|
||||
T extends 'webLinks' ? typeof WebLinksAddon :
|
||||
T extends 'unicode11' ? typeof Unicode11Addon :
|
||||
T extends 'unicodeGraphemes' ? typeof UnicodeGraphemesAddon :
|
||||
T extends 'webgl' ? typeof WebglAddon :
|
||||
never
|
||||
);
|
||||
instance?: (
|
||||
T extends 'attach' ? AttachAddon :
|
||||
T extends 'clipboard' ? ClipboardAddon :
|
||||
T extends 'fit' ? FitAddon :
|
||||
T extends 'image' ? ImageAddon :
|
||||
T extends 'ligatures' ? LigaturesAddon :
|
||||
T extends 'progress' ? ProgressAddon :
|
||||
T extends 'search' ? SearchAddon :
|
||||
T extends 'serialize' ? SerializeAddon :
|
||||
T extends 'webLinks' ? WebLinksAddon :
|
||||
T extends 'unicode11' ? Unicode11Addon :
|
||||
T extends 'unicodeGraphemes' ? UnicodeGraphemesAddon :
|
||||
T extends 'webgl' ? WebglAddon :
|
||||
never
|
||||
);
|
||||
}
|
||||
|
||||
export type AddonCollection = { [T in AddonType]: IDemoAddon<T> };
|
||||
Reference in New Issue
Block a user