From dc0d7c81d91a5ed770d3680f6cd90bf2d3c4ec5d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 26 Dec 2025 04:24:07 -0800 Subject: [PATCH] Add terminal and addon refs to all windows --- demo/client.ts | 12 +++--- demo/components/controlBar.ts | 6 +++ demo/components/window/addonsWindow.ts | 4 +- demo/components/window/baseWindow.ts | 29 +++++++++++++ demo/components/window/gpuWindow.ts | 3 +- demo/components/window/optionsWindow.ts | 56 ++++++++++++------------- demo/components/window/styleWindow.ts | 3 +- demo/components/window/testWindow.ts | 8 ++-- demo/components/window/vtWindow.ts | 3 +- 9 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 demo/components/window/baseWindow.ts diff --git a/demo/client.ts b/demo/client.ts index 8500386b..e1f3f065 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -206,21 +206,21 @@ if (document.location.pathname === '/test') { const typedTerm = createTerminal(); controlBar = new ControlBar(document.getElementById('sidebar'), document.querySelector('.banner-tabs'), []); - addonsWindow = new AddonsWindow(); + addonsWindow = new AddonsWindow(typedTerm, addons); controlBar.registerWindow(addonsWindow); actionElements = { findNext: addonsWindow.findNextInput, findPrevious: addonsWindow.findPreviousInput, findResults: addonsWindow.findResultsSpan }; - gpuWindow = new GpuWindow(); + gpuWindow = new GpuWindow(typedTerm, addons); controlBar.registerWindow(gpuWindow, { afterId: 'addons', hidden: true, smallTab: true }); - optionsWindow = new OptionsWindow(updateTerminalSize, updateTerminalContainerBackground); - const styleWindow = controlBar.registerWindow(new StyleWindow()); + optionsWindow = new OptionsWindow(typedTerm, addons, { updateTerminalSize, updateTerminalContainerBackground }); + const styleWindow = controlBar.registerWindow(new StyleWindow(typedTerm, addons)); paddingElement = styleWindow.paddingElement; controlBar.registerWindow(optionsWindow); controlBar.registerWindow(new TestWindow(typedTerm, addons, { disposeRecreateButtonHandler, createNewWindowButtonHandler })); - vtWindow = new VtWindow(); + vtWindow = new VtWindow(typedTerm, addons); controlBar.registerWindow(vtWindow); vtWindow.initTerminal(term); controlBar.activateDefaultTab(); @@ -351,7 +351,7 @@ function createTerminal(): Terminal { // fit is called within a setTimeout, cols and rows need this. setTimeout(async () => { - optionsWindow.initOptions(term, addDomListener); + optionsWindow.initOptions(addDomListener); // Set terminal size again to set the specific dimensions on the demo updateTerminalSize(); diff --git a/demo/components/controlBar.ts b/demo/components/controlBar.ts index fba37af5..1d695f60 100644 --- a/demo/components/controlBar.ts +++ b/demo/components/controlBar.ts @@ -3,6 +3,11 @@ * @license MIT */ +/// + +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 { diff --git a/demo/components/window/addonsWindow.ts b/demo/components/window/addonsWindow.ts index c94a6f03..415dd5a4 100644 --- a/demo/components/window/addonsWindow.ts +++ b/demo/components/window/addonsWindow.ts @@ -3,10 +3,10 @@ * @license MIT */ -import type { Terminal } from '@xterm/xterm'; +import { BaseWindow } from './baseWindow'; import type { IControlWindow } from '../controlBar'; -export class AddonsWindow implements IControlWindow { +export class AddonsWindow extends BaseWindow implements IControlWindow { public readonly id = 'addons'; public readonly label = 'Addons'; diff --git a/demo/components/window/baseWindow.ts b/demo/components/window/baseWindow.ts new file mode 100644 index 00000000..c541977c --- /dev/null +++ b/demo/components/window/baseWindow.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2025 The xterm.js authors. All rights reserved. + * @license MIT + */ + +/// + +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; +} \ No newline at end of file diff --git a/demo/components/window/gpuWindow.ts b/demo/components/window/gpuWindow.ts index 4fa74ff8..95d178fa 100644 --- a/demo/components/window/gpuWindow.ts +++ b/demo/components/window/gpuWindow.ts @@ -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'; diff --git a/demo/components/window/optionsWindow.ts b/demo/components/window/optionsWindow.ts index 7a5a24fc..1e3d1622 100644 --- a/demo/components/window/optionsWindow.ts +++ b/demo/components/window/optionsWindow.ts @@ -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 += '
'; booleanOptions.forEach(o => { - html += `
`; + html += `
`; }); html += '
'; numberOptions.forEach(o => { - html += `
`; + html += `
`; }); html += '
'; Object.keys(stringOptions).forEach(o => { if (o === 'colsRows') { html += `
`; } else if (stringOptions[o]) { - const selectedOption = o === 'theme' ? 'xtermjs' : term.options[o]; + const selectedOption = o === 'theme' ? 'xtermjs' : this._terminal.options[o]; html += `
`; } else { - html += `
`; + html += `
`; } }); html += '
'; @@ -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(); } }); }); diff --git a/demo/components/window/styleWindow.ts b/demo/components/window/styleWindow.ts index 7f9811b9..cc36dd7c 100644 --- a/demo/components/window/styleWindow.ts +++ b/demo/components/window/styleWindow.ts @@ -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'; diff --git a/demo/components/window/testWindow.ts b/demo/components/window/testWindow.ts index b711e18b..bbd1c3d0 100644 --- a/demo/components/window/testWindow.ts +++ b/demo/components/window/testWindow.ts @@ -7,21 +7,23 @@ import { writeUnicodeTable } from 'unicodeTable'; import type { IControlWindow } from '../controlBar'; +import { BaseWindow } from './baseWindow'; import type { IDisposable, Terminal } from '@xterm/xterm'; import type { AddonCollection } from 'types'; -export class TestWindow implements IControlWindow { +export class TestWindow extends BaseWindow implements IControlWindow { public readonly id = 'test'; public readonly label = 'Test'; constructor( - private readonly _terminal: Terminal, - private readonly _addons: AddonCollection, + terminal: Terminal, + addons: AddonCollection, private readonly _handlers: { disposeRecreateButtonHandler: () => void, createNewWindowButtonHandler: () => void, }, ) { + super(terminal, addons); } public build(container: HTMLElement): void { diff --git a/demo/components/window/vtWindow.ts b/demo/components/window/vtWindow.ts index 18614e55..787c4b86 100644 --- a/demo/components/window/vtWindow.ts +++ b/demo/components/window/vtWindow.ts @@ -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';