Demo: Add addon tabs, shuffle order

This commit is contained in:
Daniel Imms
2025-12-27 06:47:17 -08:00
parent 97c435862b
commit 82f24ad5a5
8 changed files with 376 additions and 268 deletions
+40 -21
View File
@@ -15,9 +15,12 @@ if ('WebAssembly' in window) {
import { Terminal, ITerminalOptions, type ITheme } from '@xterm/xterm';
import { AttachAddon } from '@xterm/addon-attach';
import { AddonImageWindow } from './components/window/addonImageWindow';
import { AddonSearchWindow } from './components/window/addonSearchWindow';
import { AddonSerializeWindow } from './components/window/addonSerializeWindow';
import { AddonsWindow } from './components/window/addonsWindow';
import { ControlBar } from './components/controlBar';
import { GpuWindow } from './components/window/gpuWindow';
import { WebglWindow } from './components/window/webglWindow';
import { OptionsWindow } from './components/window/optionsWindow';
import { StyleWindow } from './components/window/styleWindow';
import { TestWindow } from './components/window/testWindow';
@@ -59,7 +62,8 @@ let socket;
let pid;
let controlBar: ControlBar;
let addonsWindow: AddonsWindow;
let gpuWindow: GpuWindow;
let addonSearchWindow: AddonSearchWindow;
let addonWebglWindow: WebglWindow;
let optionsWindow: OptionsWindow;
const addons: AddonCollection = {
@@ -200,27 +204,33 @@ if (document.location.pathname === '/test') {
const typedTerm = createTerminal();
controlBar = new ControlBar(document.getElementById('sidebar'), document.querySelector('.banner-tabs'), []);
addonsWindow = controlBar.registerWindow(new AddonsWindow(typedTerm, addons));
actionElements = {
findNext: addonsWindow.findNextInput,
findPrevious: addonsWindow.findPreviousInput,
findResults: addonsWindow.findResultsSpan
};
gpuWindow = controlBar.registerWindow(new GpuWindow(typedTerm, addons), { afterId: 'addons', hidden: true, smallTab: true });
const styleWindow = controlBar.registerWindow(new StyleWindow(typedTerm, addons));
optionsWindow = controlBar.registerWindow(new OptionsWindow(typedTerm, addons, { updateTerminalSize, updateTerminalContainerBackground }));
controlBar.registerWindow(new TestWindow(typedTerm, addons, { disposeRecreateButtonHandler, createNewWindowButtonHandler }));
const styleWindow = controlBar.registerWindow(new StyleWindow(typedTerm, addons));
controlBar.registerWindow(new VtWindow(typedTerm, addons));
addonsWindow = controlBar.registerWindow(new AddonsWindow(typedTerm, addons));
addonSearchWindow = controlBar.registerWindow(new AddonSearchWindow(typedTerm, addons), { afterId: 'addons', hidden: true, italics: true });
controlBar.registerWindow(new AddonSerializeWindow(typedTerm, addons), { afterId: 'addon-search', hidden: true, italics: true });
controlBar.registerWindow(new AddonImageWindow(typedTerm, addons), { afterId: 'addon-serialize', hidden: true, italics: true });
addonWebglWindow = controlBar.registerWindow(new WebglWindow(typedTerm, addons), { afterId: 'addon-image', hidden: true, italics: true });
controlBar.registerWindow(new TestWindow(typedTerm, addons, { disposeRecreateButtonHandler, createNewWindowButtonHandler }), { afterId: 'options' });
actionElements = {
findNext: addonSearchWindow.findNextInput,
findPrevious: addonSearchWindow.findPreviousInput,
findResults: addonSearchWindow.findResultsSpan
};
controlBar.activateDefaultTab();
// TODO: Most of below should be encapsulated within windows
paddingElement = styleWindow.paddingElement;
controlBar.setTabVisible('gpu', true);
gpuWindow.setTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => gpuWindow.setTextureAtlas(e));
addons.webgl.instance.onAddTextureAtlasCanvas(e => gpuWindow.appendTextureAtlas(e));
addons.webgl.instance.onRemoveTextureAtlasCanvas(e => gpuWindow.removeTextureAtlas(e));
controlBar.setTabVisible('addon-webgl', true);
controlBar.setTabVisible('addon-search', true);
controlBar.setTabVisible('addon-serialize', true);
controlBar.setTabVisible('addon-image', true);
addonWebglWindow.setTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => addonWebglWindow.setTextureAtlas(e));
addons.webgl.instance.onAddTextureAtlasCanvas(e => addonWebglWindow.appendTextureAtlas(e));
addons.webgl.instance.onRemoveTextureAtlasCanvas(e => addonWebglWindow.removeTextureAtlas(e));
paddingElement.value = '0';
addDomListener(paddingElement, 'change', setPadding);
@@ -409,15 +419,15 @@ function initAddons(term: Terminal): void {
const fragment = document.createDocumentFragment();
function postInitWebgl(): void {
controlBar.setTabVisible('gpu', true);
controlBar.setTabVisible('addon-webgl', true);
setTimeout(() => {
gpuWindow.setTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => gpuWindow.setTextureAtlas(e));
addons.webgl.instance.onAddTextureAtlasCanvas(e => gpuWindow.appendTextureAtlas(e));
addonWebglWindow.setTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => addonWebglWindow.setTextureAtlas(e));
addons.webgl.instance.onAddTextureAtlasCanvas(e => addonWebglWindow.appendTextureAtlas(e));
}, 500);
}
function preDisposeWebgl(): void {
controlBar.setTabVisible('gpu', false);
controlBar.setTabVisible('addon-webgl', false);
if (addons.webgl.instance.textureAtlas) {
addons.webgl.instance.textureAtlas.remove();
}
@@ -448,7 +458,9 @@ function initAddons(term: Terminal): void {
? new addons[name].ctor(JSON.parse(ctorOptionsJson))
: new addons[name].ctor();
term.loadAddon(addon.instance);
controlBar.setTabVisible('addon-image', true);
} else {
controlBar.setTabVisible('addon-image', false);
addon.instance!.dispose();
addon.instance = undefined;
}
@@ -466,7 +478,10 @@ function initAddons(term: Terminal): void {
} else if (name === 'unicodeGraphemes') {
term.unicode.activeVersion = '15-graphemes';
} else if (name === 'search') {
controlBar.setTabVisible('addon-search', true);
addons[name].instance.onDidChangeResults(e => updateFindResults(e));
} else if (name === 'serialize') {
controlBar.setTabVisible('addon-serialize', true);
}
}
catch {
@@ -479,6 +494,10 @@ function initAddons(term: Terminal): void {
preDisposeWebgl();
} else if (name === 'unicode11' || name === 'unicodeGraphemes') {
term.unicode.activeVersion = '6';
} else if (name === 'search') {
controlBar.setTabVisible('addon-search', false);
} else if (name === 'serialize') {
controlBar.setTabVisible('addon-serialize', false);
}
addon.instance!.dispose();
addon.instance = undefined;
+3 -3
View File
@@ -149,7 +149,7 @@ export class ControlBar {
}
}
public registerWindow<T extends IControlWindow>(window: T, options?: { afterId?: string, hidden?: boolean, smallTab?: boolean }): T {
public registerWindow<T extends IControlWindow>(window: T, options?: { afterId?: string, hidden?: boolean, italics?: boolean }): T {
// Create button
const button = document.createElement('button');
button.id = `${window.id}button`;
@@ -158,8 +158,8 @@ export class ControlBar {
button.addEventListener('click', (e) => this._openSection(e, window.id));
// Apply small tab styling
if (options?.smallTab) {
button.style.fontSize = '0.85em';
if (options?.italics) {
button.style.fontStyle = 'italic';
}
// Insert after specified tab or append at end
@@ -0,0 +1,76 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { BaseWindow } from './baseWindow';
import type { IControlWindow } from '../controlBar';
export class AddonImageWindow extends BaseWindow implements IControlWindow {
public readonly id = 'addon-image';
public readonly label = 'image';
private _imageStorageLimitInput: HTMLInputElement;
private _imageShowPlaceholderCheckbox: HTMLInputElement;
private _imageOptionsTextarea: HTMLTextAreaElement;
public build(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'Image Addon';
container.appendChild(h4);
const details = document.createElement('details');
const summary = document.createElement('summary');
summary.textContent = 'image addon settings';
details.appendChild(summary);
const wrapper = document.createElement('div');
// Storage limit
const storageLimitLabel = document.createElement('label');
storageLimitLabel.textContent = 'Storage Limit (in MB) ';
this._imageStorageLimitInput = document.createElement('input');
this._imageStorageLimitInput.type = 'number';
this._imageStorageLimitInput.id = 'image-storagelimit';
storageLimitLabel.appendChild(this._imageStorageLimitInput);
wrapper.appendChild(storageLimitLabel);
wrapper.appendChild(document.createElement('br'));
// Show placeholder
const placeholderLabel = document.createElement('label');
placeholderLabel.textContent = 'Show Placeholder ';
this._imageShowPlaceholderCheckbox = document.createElement('input');
this._imageShowPlaceholderCheckbox.type = 'checkbox';
this._imageShowPlaceholderCheckbox.id = 'image-showplaceholder';
placeholderLabel.appendChild(this._imageShowPlaceholderCheckbox);
wrapper.appendChild(placeholderLabel);
wrapper.appendChild(document.createElement('br'));
wrapper.appendChild(document.createElement('br'));
// Ctor options
const optionsLabel = document.createElement('label');
optionsLabel.appendChild(document.createTextNode('Ctor options (applied on addon relaunch)'));
optionsLabel.appendChild(document.createElement('br'));
this._imageOptionsTextarea = document.createElement('textarea');
this._imageOptionsTextarea.id = 'image-options';
this._imageOptionsTextarea.cols = 40;
this._imageOptionsTextarea.rows = 12;
optionsLabel.appendChild(this._imageOptionsTextarea);
wrapper.appendChild(optionsLabel);
details.appendChild(wrapper);
container.appendChild(details);
}
public get imageStorageLimitInput(): HTMLInputElement {
return this._imageStorageLimitInput;
}
public get imageShowPlaceholderCheckbox(): HTMLInputElement {
return this._imageShowPlaceholderCheckbox;
}
public get imageOptionsTextarea(): HTMLTextAreaElement {
return this._imageOptionsTextarea;
}
}
@@ -0,0 +1,105 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { BaseWindow } from './baseWindow';
import type { IControlWindow } from '../controlBar';
export class AddonSearchWindow extends BaseWindow implements IControlWindow {
public readonly id = 'addon-search';
public readonly label = 'search';
private _findNextInput: HTMLInputElement;
private _findPreviousInput: HTMLInputElement;
private _findResultsSpan: HTMLElement;
private _regexCheckbox: HTMLInputElement;
private _caseSensitiveCheckbox: HTMLInputElement;
private _wholeWordCheckbox: HTMLInputElement;
private _highlightAllMatchesCheckbox: HTMLInputElement;
public build(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'SearchAddon';
container.appendChild(h4);
const wrapper = document.createElement('div');
wrapper.style.display = 'flex';
wrapper.style.flexDirection = 'column';
// Find next
const findNextLabel = document.createElement('label');
findNextLabel.textContent = 'Find next ';
this._findNextInput = document.createElement('input');
this._findNextInput.id = 'find-next';
findNextLabel.appendChild(this._findNextInput);
wrapper.appendChild(findNextLabel);
// Find previous
const findPrevLabel = document.createElement('label');
findPrevLabel.textContent = 'Find previous ';
this._findPreviousInput = document.createElement('input');
this._findPreviousInput.id = 'find-previous';
findPrevLabel.appendChild(this._findPreviousInput);
wrapper.appendChild(findPrevLabel);
// Results
const resultsDiv = document.createElement('div');
resultsDiv.textContent = 'Results: ';
this._findResultsSpan = document.createElement('span');
this._findResultsSpan.id = 'find-results';
resultsDiv.appendChild(this._findResultsSpan);
wrapper.appendChild(resultsDiv);
// Regex checkbox
const regexLabel = document.createElement('label');
this._regexCheckbox = document.createElement('input');
this._regexCheckbox.type = 'checkbox';
this._regexCheckbox.id = 'regex';
regexLabel.appendChild(this._regexCheckbox);
regexLabel.appendChild(document.createTextNode('Use regex'));
wrapper.appendChild(regexLabel);
// Case sensitive checkbox
const caseLabel = document.createElement('label');
this._caseSensitiveCheckbox = document.createElement('input');
this._caseSensitiveCheckbox.type = 'checkbox';
this._caseSensitiveCheckbox.id = 'case-sensitive';
caseLabel.appendChild(this._caseSensitiveCheckbox);
caseLabel.appendChild(document.createTextNode('Case sensitive'));
wrapper.appendChild(caseLabel);
// Whole word checkbox
const wholeWordLabel = document.createElement('label');
this._wholeWordCheckbox = document.createElement('input');
this._wholeWordCheckbox.type = 'checkbox';
this._wholeWordCheckbox.id = 'whole-word';
wholeWordLabel.appendChild(this._wholeWordCheckbox);
wholeWordLabel.appendChild(document.createTextNode('Whole word'));
wrapper.appendChild(wholeWordLabel);
// Highlight all matches checkbox
const highlightLabel = document.createElement('label');
this._highlightAllMatchesCheckbox = document.createElement('input');
this._highlightAllMatchesCheckbox.type = 'checkbox';
this._highlightAllMatchesCheckbox.id = 'highlight-all-matches';
this._highlightAllMatchesCheckbox.checked = true;
highlightLabel.appendChild(this._highlightAllMatchesCheckbox);
highlightLabel.appendChild(document.createTextNode('Highlight All Matches'));
wrapper.appendChild(highlightLabel);
container.appendChild(wrapper);
}
public get findNextInput(): HTMLInputElement {
return this._findNextInput;
}
public get findPreviousInput(): HTMLInputElement {
return this._findPreviousInput;
}
public get findResultsSpan(): HTMLElement {
return this._findResultsSpan;
}
}
@@ -0,0 +1,97 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import type { Terminal } from '@xterm/xterm';
import { BaseWindow } from './baseWindow';
import type { IControlWindow } from '../controlBar';
import type { AddonCollection } from '../../types';
export class AddonSerializeWindow extends BaseWindow implements IControlWindow {
public readonly id = 'addon-serialize';
public readonly label = 'serialize';
private _serializeOutputPre: HTMLPreElement;
private _htmlSerializeOutputPre: HTMLPreElement;
private _htmlSerializeOutputResult: HTMLElement;
private _writeToTerminalCheckbox: HTMLInputElement;
public build(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'SerializeAddon';
container.appendChild(h4);
const wrapper = document.createElement('div');
// Serialize button
const serializeBtn = document.createElement('button');
serializeBtn.id = 'serialize';
serializeBtn.textContent = 'Serialize the content of terminal';
serializeBtn.addEventListener('click', () => this._serializeButtonHandler());
wrapper.appendChild(serializeBtn);
// Write to terminal checkbox
const writeLabel = document.createElement('label');
this._writeToTerminalCheckbox = document.createElement('input');
this._writeToTerminalCheckbox.type = 'checkbox';
this._writeToTerminalCheckbox.id = 'write-to-terminal';
writeLabel.appendChild(this._writeToTerminalCheckbox);
writeLabel.appendChild(document.createTextNode('Write back to terminal'));
wrapper.appendChild(writeLabel);
// Serialize output
const outputDiv = document.createElement('div');
this._serializeOutputPre = document.createElement('pre');
this._serializeOutputPre.id = 'serialize-output';
outputDiv.appendChild(this._serializeOutputPre);
wrapper.appendChild(outputDiv);
// HTML serialize button
const htmlSerializeBtn = document.createElement('button');
htmlSerializeBtn.id = 'htmlserialize';
htmlSerializeBtn.textContent = 'Serialize the content of terminal in HTML';
htmlSerializeBtn.addEventListener('click', () => this._htmlSerializeButtonHandler());
wrapper.appendChild(htmlSerializeBtn);
// HTML serialize result
this._htmlSerializeOutputResult = document.createElement('span');
this._htmlSerializeOutputResult.id = 'htmlserialize-output-result';
wrapper.appendChild(this._htmlSerializeOutputResult);
// HTML serialize output
const htmlOutputDiv = document.createElement('div');
this._htmlSerializeOutputPre = document.createElement('pre');
this._htmlSerializeOutputPre.id = 'htmlserialize-output';
htmlOutputDiv.appendChild(this._htmlSerializeOutputPre);
wrapper.appendChild(htmlOutputDiv);
container.appendChild(wrapper);
}
private _serializeButtonHandler(): void {
const output = this._addons.serialize.instance.serialize();
const outputString = JSON.stringify(output);
this._serializeOutputPre.innerText = outputString;
if (this._writeToTerminalCheckbox.checked) {
this._terminal.reset();
this._terminal.write(output);
}
}
private _htmlSerializeButtonHandler(): void {
const output = this._addons.serialize.instance.serializeAsHTML();
this._htmlSerializeOutputPre.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);
this._htmlSerializeOutputResult.innerText = 'Copied to clipboard';
}
}
@@ -3,30 +3,14 @@
* @license MIT
*/
import type { Terminal } from '@xterm/xterm';
import { BaseWindow } from './baseWindow';
import type { IControlWindow } from '../controlBar';
import type { AddonCollection } from '../../types';
export class AddonsWindow extends BaseWindow implements IControlWindow {
public readonly id = 'addons';
public readonly label = 'Addons';
private _addonsContainer: HTMLElement;
private _findNextInput: HTMLInputElement;
private _findPreviousInput: HTMLInputElement;
private _findResultsSpan: HTMLElement;
private _regexCheckbox: HTMLInputElement;
private _caseSensitiveCheckbox: HTMLInputElement;
private _wholeWordCheckbox: HTMLInputElement;
private _highlightAllMatchesCheckbox: HTMLInputElement;
private _serializeOutputPre: HTMLPreElement;
private _htmlSerializeOutputPre: HTMLPreElement;
private _htmlSerializeOutputResult: HTMLElement;
private _writeToTerminalCheckbox: HTMLInputElement;
private _imageStorageLimitInput: HTMLInputElement;
private _imageShowPlaceholderCheckbox: HTMLInputElement;
private _imageOptionsTextarea: HTMLTextAreaElement;
public build(container: HTMLElement): void {
// Heading
@@ -43,235 +27,9 @@ export class AddonsWindow extends BaseWindow implements IControlWindow {
this._addonsContainer = document.createElement('div');
this._addonsContainer.id = 'addons-container';
container.appendChild(this._addonsContainer);
// Addons Control section
const controlHeading = document.createElement('h3');
controlHeading.textContent = 'Addons Control';
container.appendChild(controlHeading);
// SearchAddon section
this._buildSearchSection(container);
// SerializeAddon section
this._buildSerializeSection(container);
// ImageAddon section
this._buildImageSection(container);
}
private _buildSearchSection(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'SearchAddon';
container.appendChild(h4);
const wrapper = document.createElement('div');
wrapper.style.display = 'flex';
wrapper.style.flexDirection = 'column';
// Find next
const findNextLabel = document.createElement('label');
findNextLabel.textContent = 'Find next ';
this._findNextInput = document.createElement('input');
this._findNextInput.id = 'find-next';
findNextLabel.appendChild(this._findNextInput);
wrapper.appendChild(findNextLabel);
// Find previous
const findPrevLabel = document.createElement('label');
findPrevLabel.textContent = 'Find previous ';
this._findPreviousInput = document.createElement('input');
this._findPreviousInput.id = 'find-previous';
findPrevLabel.appendChild(this._findPreviousInput);
wrapper.appendChild(findPrevLabel);
// Results
const resultsDiv = document.createElement('div');
resultsDiv.textContent = 'Results: ';
this._findResultsSpan = document.createElement('span');
this._findResultsSpan.id = 'find-results';
resultsDiv.appendChild(this._findResultsSpan);
wrapper.appendChild(resultsDiv);
// Regex checkbox
const regexLabel = document.createElement('label');
this._regexCheckbox = document.createElement('input');
this._regexCheckbox.type = 'checkbox';
this._regexCheckbox.id = 'regex';
regexLabel.appendChild(this._regexCheckbox);
regexLabel.appendChild(document.createTextNode('Use regex'));
wrapper.appendChild(regexLabel);
// Case sensitive checkbox
const caseLabel = document.createElement('label');
this._caseSensitiveCheckbox = document.createElement('input');
this._caseSensitiveCheckbox.type = 'checkbox';
this._caseSensitiveCheckbox.id = 'case-sensitive';
caseLabel.appendChild(this._caseSensitiveCheckbox);
caseLabel.appendChild(document.createTextNode('Case sensitive'));
wrapper.appendChild(caseLabel);
// Whole word checkbox
const wholeWordLabel = document.createElement('label');
this._wholeWordCheckbox = document.createElement('input');
this._wholeWordCheckbox.type = 'checkbox';
this._wholeWordCheckbox.id = 'whole-word';
wholeWordLabel.appendChild(this._wholeWordCheckbox);
wholeWordLabel.appendChild(document.createTextNode('Whole word'));
wrapper.appendChild(wholeWordLabel);
// Highlight all matches checkbox
const highlightLabel = document.createElement('label');
this._highlightAllMatchesCheckbox = document.createElement('input');
this._highlightAllMatchesCheckbox.type = 'checkbox';
this._highlightAllMatchesCheckbox.id = 'highlight-all-matches';
this._highlightAllMatchesCheckbox.checked = true;
highlightLabel.appendChild(this._highlightAllMatchesCheckbox);
highlightLabel.appendChild(document.createTextNode('Highlight All Matches'));
wrapper.appendChild(highlightLabel);
container.appendChild(wrapper);
}
private _buildSerializeSection(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'SerializeAddon';
container.appendChild(h4);
const wrapper = document.createElement('div');
// Serialize button
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
const writeLabel = document.createElement('label');
this._writeToTerminalCheckbox = document.createElement('input');
this._writeToTerminalCheckbox.type = 'checkbox';
this._writeToTerminalCheckbox.id = 'write-to-terminal';
writeLabel.appendChild(this._writeToTerminalCheckbox);
writeLabel.appendChild(document.createTextNode('Write back to terminal'));
wrapper.appendChild(writeLabel);
// Serialize output
const outputDiv = document.createElement('div');
this._serializeOutputPre = document.createElement('pre');
this._serializeOutputPre.id = 'serialize-output';
outputDiv.appendChild(this._serializeOutputPre);
wrapper.appendChild(outputDiv);
// HTML serialize button
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
this._htmlSerializeOutputResult = document.createElement('span');
this._htmlSerializeOutputResult.id = 'htmlserialize-output-result';
wrapper.appendChild(this._htmlSerializeOutputResult);
// HTML serialize output
const htmlOutputDiv = document.createElement('div');
this._htmlSerializeOutputPre = document.createElement('pre');
this._htmlSerializeOutputPre.id = 'htmlserialize-output';
htmlOutputDiv.appendChild(this._htmlSerializeOutputPre);
wrapper.appendChild(htmlOutputDiv);
container.appendChild(wrapper);
}
private _buildImageSection(container: HTMLElement): void {
const h4 = document.createElement('h4');
h4.textContent = 'Image Addon';
container.appendChild(h4);
const details = document.createElement('details');
const summary = document.createElement('summary');
summary.textContent = 'image addon settings';
details.appendChild(summary);
const wrapper = document.createElement('div');
// Storage limit
const storageLimitLabel = document.createElement('label');
storageLimitLabel.textContent = 'Storage Limit (in MB) ';
this._imageStorageLimitInput = document.createElement('input');
this._imageStorageLimitInput.type = 'number';
this._imageStorageLimitInput.id = 'image-storagelimit';
storageLimitLabel.appendChild(this._imageStorageLimitInput);
wrapper.appendChild(storageLimitLabel);
wrapper.appendChild(document.createElement('br'));
// Show placeholder
const placeholderLabel = document.createElement('label');
placeholderLabel.textContent = 'Show Placeholder ';
this._imageShowPlaceholderCheckbox = document.createElement('input');
this._imageShowPlaceholderCheckbox.type = 'checkbox';
this._imageShowPlaceholderCheckbox.id = 'image-showplaceholder';
placeholderLabel.appendChild(this._imageShowPlaceholderCheckbox);
wrapper.appendChild(placeholderLabel);
wrapper.appendChild(document.createElement('br'));
wrapper.appendChild(document.createElement('br'));
// Ctor options
const optionsLabel = document.createElement('label');
optionsLabel.appendChild(document.createTextNode('Ctor options (applied on addon relaunch)'));
optionsLabel.appendChild(document.createElement('br'));
this._imageOptionsTextarea = document.createElement('textarea');
this._imageOptionsTextarea.id = 'image-options';
this._imageOptionsTextarea.cols = 40;
this._imageOptionsTextarea.rows = 12;
optionsLabel.appendChild(this._imageOptionsTextarea);
wrapper.appendChild(optionsLabel);
details.appendChild(wrapper);
container.appendChild(details);
}
public get addonsContainer(): HTMLElement {
return this._addonsContainer;
}
public get findNextInput(): HTMLInputElement {
return this._findNextInput;
}
public get findPreviousInput(): HTMLInputElement {
return this._findPreviousInput;
}
public get findResultsSpan(): HTMLElement {
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';
}
+2 -2
View File
@@ -8,13 +8,13 @@ import type { IControlWindow } from '../controlBar';
export class GpuWindow extends BaseWindow implements IControlWindow {
public readonly id = 'gpu';
public readonly label = 'GPU';
public readonly label = 'WebGL';
private _textureAtlasContainer: HTMLElement;
public build(container: HTMLElement): void {
const heading = document.createElement('h3');
heading.textContent = 'GPU';
heading.textContent = 'WebGL';
container.appendChild(heading);
const zoomCheckbox = document.createElement('input');
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { BaseWindow } from './baseWindow';
import type { IControlWindow } from '../controlBar';
export class WebglWindow extends BaseWindow implements IControlWindow {
public readonly id = 'addon-webgl';
public readonly label = 'webgl';
private _textureAtlasContainer: HTMLElement;
public build(container: HTMLElement): void {
const heading = document.createElement('h3');
heading.textContent = 'WebGL';
container.appendChild(heading);
const zoomCheckbox = document.createElement('input');
zoomCheckbox.type = 'checkbox';
zoomCheckbox.id = 'texture-atlas-zoom';
container.appendChild(zoomCheckbox);
const zoomLabel = document.createElement('label');
zoomLabel.htmlFor = 'texture-atlas-zoom';
zoomLabel.textContent = 'Zoom texture atlas';
container.appendChild(zoomLabel);
this._textureAtlasContainer = document.createElement('div');
this._textureAtlasContainer.id = 'texture-atlas';
container.appendChild(this._textureAtlasContainer);
}
public setTextureAtlas(canvas: HTMLCanvasElement): void {
this._styleAtlasPage(canvas);
this._textureAtlasContainer.replaceChildren(canvas);
}
public appendTextureAtlas(canvas: HTMLCanvasElement): void {
this._styleAtlasPage(canvas);
this._textureAtlasContainer.appendChild(canvas);
}
public removeTextureAtlas(canvas: HTMLCanvasElement): void {
canvas.remove();
}
private _styleAtlasPage(canvas: HTMLCanvasElement): void {
canvas.style.width = `${canvas.width / window.devicePixelRatio}px`;
canvas.style.height = `${canvas.height / window.devicePixelRatio}px`;
}
}