mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Demo: Add addon tabs, shuffle order
This commit is contained in:
+40
-21
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user