mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #5640 from Tyriar/strict_demo
Make demo use strict TS compiler mode
This commit is contained in:
+70
-70
@@ -58,11 +58,11 @@ export interface IWindowWithTerminal extends Window {
|
||||
}
|
||||
declare let window: IWindowWithTerminal;
|
||||
|
||||
let term;
|
||||
let protocol;
|
||||
let socketURL;
|
||||
let socket;
|
||||
let pid;
|
||||
let term: Terminal | null;
|
||||
let protocol: string;
|
||||
let socketURL: string;
|
||||
let socket: WebSocket | null;
|
||||
let pid: string;
|
||||
let controlBar: ControlBar;
|
||||
let addonsWindow: AddonsWindow;
|
||||
let addonSearchWindow: AddonSearchWindow;
|
||||
@@ -73,7 +73,7 @@ const addons: AddonCollection = {
|
||||
attach: { name: 'attach', ctor: AttachAddon, canChange: false },
|
||||
clipboard: { name: 'clipboard', ctor: ClipboardAddon, canChange: true },
|
||||
fit: { name: 'fit', ctor: FitAddon, canChange: false },
|
||||
image: { name: 'image', ctor: ImageAddon, canChange: true },
|
||||
image: { name: 'image', ctor: ImageAddon!, canChange: true },
|
||||
progress: { name: 'progress', ctor: ProgressAddon, canChange: true },
|
||||
search: { name: 'search', ctor: SearchAddon, canChange: true },
|
||||
serialize: { name: 'serialize', ctor: SerializeAddon, canChange: true },
|
||||
@@ -116,8 +116,8 @@ const xtermjsTheme = {
|
||||
brightWhite: '#FFFFFF'
|
||||
} satisfies ITheme;
|
||||
function setPadding(): void {
|
||||
term.element.style.padding = parseInt(paddingElement.value, 10).toString() + 'px';
|
||||
addons.fit.instance.fit();
|
||||
term!.element!.style.padding = parseInt(paddingElement.value, 10).toString() + 'px';
|
||||
addons.fit.instance!.fit();
|
||||
}
|
||||
|
||||
function getSearchOptions(): ISearchOptions {
|
||||
@@ -141,7 +141,7 @@ const disposeRecreateButtonHandler: () => void = () => {
|
||||
if (term) {
|
||||
term.dispose();
|
||||
term = null;
|
||||
window.term = null;
|
||||
(window as any).term = null;
|
||||
socket = null;
|
||||
addons.attach.instance = undefined;
|
||||
addons.clipboard.instance = undefined;
|
||||
@@ -154,10 +154,10 @@ const disposeRecreateButtonHandler: () => void = () => {
|
||||
addons.ligatures.instance = undefined;
|
||||
addons.webLinks.instance = undefined;
|
||||
addons.webgl.instance = undefined;
|
||||
document.getElementById('dispose').innerHTML = 'Recreate Terminal';
|
||||
document.getElementById('dispose')!.innerHTML = 'Recreate Terminal';
|
||||
} else {
|
||||
createTerminal();
|
||||
document.getElementById('dispose').innerHTML = 'Dispose terminal';
|
||||
document.getElementById('dispose')!.innerHTML = 'Dispose terminal';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,7 +165,7 @@ const createNewWindowButtonHandler: () => void = () => {
|
||||
if (term) {
|
||||
disposeRecreateButtonHandler();
|
||||
}
|
||||
const win = window.open();
|
||||
const win = window.open()!;
|
||||
terminalContainer = win.document.createElement('div');
|
||||
terminalContainer.id = 'terminal-container';
|
||||
win.document.body.appendChild(terminalContainer);
|
||||
@@ -207,7 +207,7 @@ if (document.location.pathname === '/test') {
|
||||
} else {
|
||||
const typedTerm = createTerminal();
|
||||
|
||||
controlBar = new ControlBar(document.getElementById('sidebar'), document.querySelector('.banner-tabs'), []);
|
||||
controlBar = new ControlBar(document.getElementById('sidebar')!, document.querySelector('.banner-tabs')!, []);
|
||||
optionsWindow = controlBar.registerWindow(new OptionsWindow(typedTerm, addons, { updateTerminalSize, updateTerminalContainerBackground }));
|
||||
const styleWindow = controlBar.registerWindow(new StyleWindow(typedTerm, addons));
|
||||
controlBar.registerWindow(new CellInspectorWindow(typedTerm, addons));
|
||||
@@ -234,43 +234,43 @@ if (document.location.pathname === '/test') {
|
||||
controlBar.setTabVisible('addon-serialize', true);
|
||||
controlBar.setTabVisible('addon-image', true);
|
||||
controlBar.setTabVisible('addon-web-fonts', 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));
|
||||
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);
|
||||
addDomListener(actionElements.findNext, 'keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
addons.search.instance.findNext(actionElements.findNext.value, getSearchOptions());
|
||||
addons.search.instance!.findNext(actionElements.findNext.value, getSearchOptions());
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
addDomListener(actionElements.findNext, 'input', (e) => {
|
||||
addons.search.instance.findNext(actionElements.findNext.value, getSearchOptions());
|
||||
addons.search.instance!.findNext(actionElements.findNext.value, getSearchOptions());
|
||||
});
|
||||
addDomListener(actionElements.findPrevious, 'keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
addons.search.instance.findPrevious(actionElements.findPrevious.value, getSearchOptions());
|
||||
addons.search.instance!.findPrevious(actionElements.findPrevious.value, getSearchOptions());
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
addDomListener(actionElements.findPrevious, 'input', (e) => {
|
||||
addons.search.instance.findPrevious(actionElements.findPrevious.value, getSearchOptions());
|
||||
addons.search.instance!.findPrevious(actionElements.findPrevious.value, getSearchOptions());
|
||||
});
|
||||
addDomListener(actionElements.findNext, 'blur', (e) => {
|
||||
addons.search.instance.clearActiveDecoration();
|
||||
addons.search.instance!.clearActiveDecoration();
|
||||
});
|
||||
addDomListener(actionElements.findPrevious, 'blur', (e) => {
|
||||
addons.search.instance.clearActiveDecoration();
|
||||
addons.search.instance!.clearActiveDecoration();
|
||||
});
|
||||
}
|
||||
|
||||
function createTerminal(): Terminal {
|
||||
// Clean terminal
|
||||
while (terminalContainer.children.length) {
|
||||
terminalContainer.removeChild(terminalContainer.children[0]);
|
||||
while (terminalContainer!.children.length) {
|
||||
terminalContainer!.removeChild(terminalContainer!.children[0]);
|
||||
}
|
||||
|
||||
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
|
||||
@@ -290,7 +290,7 @@ function createTerminal(): Terminal {
|
||||
addons.search.instance = new SearchAddon();
|
||||
addons.serialize.instance = new SerializeAddon();
|
||||
addons.fit.instance = new FitAddon();
|
||||
addons.image.instance = new ImageAddon();
|
||||
addons.image.instance = new ImageAddon!();
|
||||
addons.progress.instance = new ProgressAddon();
|
||||
addons.unicodeGraphemes.instance = new UnicodeGraphemesAddon();
|
||||
addons.clipboard.instance = new ClipboardAddon();
|
||||
@@ -311,7 +311,7 @@ function createTerminal(): Terminal {
|
||||
typedTerm.loadAddon(addons.webFonts.instance);
|
||||
typedTerm.loadAddon(addons.clipboard.instance);
|
||||
|
||||
window.term = term; // Expose `term` to window for debugging purposes
|
||||
(window as any).term = term; // Expose `term` to window for debugging purposes
|
||||
term.onResize((size: { cols: number, rows: number }) => {
|
||||
if (!pid) {
|
||||
return;
|
||||
@@ -330,7 +330,7 @@ function createTerminal(): Terminal {
|
||||
if (addons.webgl.instance) {
|
||||
try {
|
||||
typedTerm.loadAddon(addons.webgl.instance);
|
||||
term.open(terminalContainer);
|
||||
term.open(terminalContainer!);
|
||||
} catch (e) {
|
||||
console.warn('error during loading webgl addon:', e);
|
||||
addons.webgl.instance.dispose();
|
||||
@@ -339,7 +339,7 @@ function createTerminal(): Terminal {
|
||||
}
|
||||
if (!typedTerm.element) {
|
||||
// webgl loading failed for some reason, attach with DOM renderer
|
||||
term.open(terminalContainer);
|
||||
term.open(terminalContainer!);
|
||||
}
|
||||
|
||||
term.focus();
|
||||
@@ -349,13 +349,13 @@ function createTerminal(): Terminal {
|
||||
if (optionsWindow.autoResize) {
|
||||
// In general this should be debounced to avoid excessive work on the main
|
||||
// thread by firing the expensive resize action repeatedly
|
||||
addons.fit.instance.fit();
|
||||
addons.fit.instance!.fit();
|
||||
}
|
||||
});
|
||||
resizeObserver.observe(terminalContainer);
|
||||
resizeObserver.observe(terminalContainer!);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
terminalContainer.style.width = document.body.clientWidth + 'px';
|
||||
terminalContainer!.style.width = document.body.clientWidth + 'px';
|
||||
});
|
||||
|
||||
// fit is called within a setTimeout, cols and rows need this.
|
||||
@@ -369,7 +369,7 @@ function createTerminal(): Terminal {
|
||||
if (useRealTerminal instanceof HTMLInputElement && !useRealTerminal.checked) {
|
||||
runFakeTerminal();
|
||||
} else {
|
||||
const res = await fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, { method: 'POST' });
|
||||
const res = await fetch('/terminals?cols=' + term!.cols + '&rows=' + term!.rows, { method: 'POST' });
|
||||
const processId = await res.text();
|
||||
pid = processId;
|
||||
socketURL += processId;
|
||||
@@ -384,52 +384,52 @@ function createTerminal(): Terminal {
|
||||
}
|
||||
|
||||
function runRealTerminal(): void {
|
||||
addons.attach.instance = new AttachAddon(socket);
|
||||
term.loadAddon(addons.attach.instance);
|
||||
term._initialized = true;
|
||||
initAddons(term);
|
||||
addons.attach.instance = new AttachAddon(socket!);
|
||||
term!.loadAddon(addons.attach.instance);
|
||||
(term as any)._initialized = true;
|
||||
initAddons(term!);
|
||||
}
|
||||
|
||||
function runFakeTerminal(): void {
|
||||
if (term._initialized) {
|
||||
if ((term as any)._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
term._initialized = true;
|
||||
initAddons(term);
|
||||
(term as any)._initialized = true;
|
||||
initAddons(term!);
|
||||
|
||||
term.prompt = () => {
|
||||
term.write('\r\n$ ');
|
||||
(term as any).prompt = () => {
|
||||
term!.write('\r\n$ ');
|
||||
};
|
||||
|
||||
term.writeln('Welcome to xterm.js');
|
||||
term.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
|
||||
term.writeln('Type some keys and commands to play around.');
|
||||
term.writeln('');
|
||||
term.prompt();
|
||||
term!.writeln('Welcome to xterm.js');
|
||||
term!.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
|
||||
term!.writeln('Type some keys and commands to play around.');
|
||||
term!.writeln('');
|
||||
(term as any).prompt();
|
||||
|
||||
term.onKey((e: { key: string, domEvent: KeyboardEvent }) => {
|
||||
term!.onKey((e: { key: string, domEvent: KeyboardEvent }) => {
|
||||
const ev = e.domEvent;
|
||||
const printable = !ev.altKey && !ev.ctrlKey && !ev.metaKey;
|
||||
|
||||
if (ev.keyCode === 13) {
|
||||
term.prompt();
|
||||
(term as any).prompt();
|
||||
} else if (ev.keyCode === 8) {
|
||||
// Do not delete the prompt
|
||||
if (term._core.buffer.x > 2) {
|
||||
term.write('\b \b');
|
||||
if ((term as any)._core.buffer.x > 2) {
|
||||
term!.write('\b \b');
|
||||
}
|
||||
} else if (printable) {
|
||||
term.write(e.key);
|
||||
term!.write(e.key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTerminalContainerBackground(): void {
|
||||
if (term.options.allowTransparency) {
|
||||
terminalContainer.style.background = 'repeating-conic-gradient(#000000 0% 25%, #101010 0% 50%) 50% / 20px 20px';
|
||||
if (term!.options.allowTransparency) {
|
||||
terminalContainer!.style.background = 'repeating-conic-gradient(#000000 0% 25%, #101010 0% 50%) 50% / 20px 20px';
|
||||
} else {
|
||||
terminalContainer.style.background = term.options.theme?.background ?? '#000000';
|
||||
terminalContainer!.style.background = term!.options.theme?.background ?? '#000000';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,19 +439,19 @@ function initAddons(term: Terminal): void {
|
||||
function postInitWebgl(): void {
|
||||
controlBar.setTabVisible('addon-webgl', true);
|
||||
setTimeout(() => {
|
||||
addonWebglWindow.setTextureAtlas(addons.webgl.instance.textureAtlas);
|
||||
addons.webgl.instance.onChangeTextureAtlas(e => addonWebglWindow.setTextureAtlas(e));
|
||||
addons.webgl.instance.onAddTextureAtlasCanvas(e => addonWebglWindow.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('addon-webgl', false);
|
||||
if (addons.webgl.instance.textureAtlas) {
|
||||
addons.webgl.instance.textureAtlas.remove();
|
||||
if (addons.webgl.instance!.textureAtlas) {
|
||||
addons.webgl.instance!.textureAtlas.remove();
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(addons).forEach((name: AddonType) => {
|
||||
(Object.keys(addons) as AddonType[]).forEach(name => {
|
||||
const addon = addons[name];
|
||||
const checkbox = document.createElement('input') as HTMLInputElement;
|
||||
checkbox.type = 'checkbox';
|
||||
@@ -466,12 +466,12 @@ function initAddons(term: Terminal): void {
|
||||
term.unicode.activeVersion = '15-graphemes';
|
||||
}
|
||||
if (name === 'search' && checkbox.checked) {
|
||||
addons[name].instance.onDidChangeResults(e => updateFindResults(e));
|
||||
addons[name].instance!.onDidChangeResults(e => updateFindResults(e));
|
||||
}
|
||||
addDomListener(checkbox, 'change', () => {
|
||||
if (name === 'image') {
|
||||
if (checkbox.checked) {
|
||||
const ctorOptionsJson = document.querySelector<HTMLTextAreaElement>('#image-options').value;
|
||||
const ctorOptionsJson = document.querySelector<HTMLTextAreaElement>('#image-options')!.value;
|
||||
addon.instance = ctorOptionsJson
|
||||
? new addons[name].ctor(JSON.parse(ctorOptionsJson))
|
||||
: new addons[name].ctor();
|
||||
@@ -497,7 +497,7 @@ function initAddons(term: Terminal): void {
|
||||
term.unicode.activeVersion = '15-graphemes';
|
||||
} else if (name === 'search') {
|
||||
controlBar.setTabVisible('addon-search', true);
|
||||
addons[name].instance.onDidChangeResults(e => updateFindResults(e));
|
||||
addons[name].instance!.onDidChangeResults(e => updateFindResults(e));
|
||||
} else if (name === 'serialize') {
|
||||
controlBar.setTabVisible('addon-serialize', true);
|
||||
}
|
||||
@@ -587,17 +587,17 @@ function updateFindResults(e: { resultIndex: number, resultCount: number } | und
|
||||
|
||||
function addDomListener(element: HTMLElement, type: string, handler: (...args: any[]) => any): void {
|
||||
element.addEventListener(type, handler);
|
||||
term._core._register({ dispose: () => element.removeEventListener(type, handler) });
|
||||
(term as any)._core._register({ dispose: () => element.removeEventListener(type, handler) });
|
||||
}
|
||||
|
||||
function updateTerminalSize(): void {
|
||||
const width = optionsWindow.autoResize ? '100%'
|
||||
: (term.dimensions.css.canvas.width + term._core.viewport.scrollBarWidth).toString() + 'px';
|
||||
: ((term as any).dimensions.css.canvas.width + (term as any)._core.viewport.scrollBarWidth).toString() + 'px';
|
||||
const height = optionsWindow.autoResize ? '100%'
|
||||
: (term.dimensions.css.canvas.height).toString() + 'px';
|
||||
terminalContainer.style.width = width;
|
||||
terminalContainer.style.height = height;
|
||||
addons.fit.instance.fit();
|
||||
: ((term as any).dimensions.css.canvas.height).toString() + 'px';
|
||||
terminalContainer!.style.width = width;
|
||||
terminalContainer!.style.height = height;
|
||||
addons.fit.instance!.fit();
|
||||
}
|
||||
|
||||
(console as any).image = (source: ImageData | HTMLCanvasElement, scale: number = 1) => {
|
||||
|
||||
@@ -10,9 +10,9 @@ 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;
|
||||
private _imageStorageLimitInput!: HTMLInputElement;
|
||||
private _imageShowPlaceholderCheckbox!: HTMLInputElement;
|
||||
private _imageOptionsTextarea!: HTMLTextAreaElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
// Storage limit
|
||||
|
||||
@@ -10,13 +10,13 @@ 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;
|
||||
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 wrapper = document.createElement('div');
|
||||
|
||||
@@ -10,10 +10,10 @@ 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;
|
||||
private _serializeOutputPre!: HTMLPreElement;
|
||||
private _htmlSerializeOutputPre!: HTMLPreElement;
|
||||
private _htmlSerializeOutputResult!: HTMLElement;
|
||||
private _writeToTerminalCheckbox!: HTMLInputElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
const wrapper = document.createElement('div');
|
||||
@@ -64,7 +64,7 @@ export class AddonSerializeWindow extends BaseWindow implements IControlWindow {
|
||||
}
|
||||
|
||||
private _serializeButtonHandler(): void {
|
||||
const output = this._addons.serialize.instance.serialize();
|
||||
const output = this._addons.serialize.instance!.serialize();
|
||||
const outputString = JSON.stringify(output);
|
||||
|
||||
this._serializeOutputPre.innerText = outputString;
|
||||
@@ -75,7 +75,7 @@ export class AddonSerializeWindow extends BaseWindow implements IControlWindow {
|
||||
}
|
||||
|
||||
private _htmlSerializeButtonHandler(): void {
|
||||
const output = this._addons.serialize.instance.serializeAsHTML();
|
||||
const output = this._addons.serialize.instance!.serializeAsHTML();
|
||||
this._htmlSerializeOutputPre.innerText = output;
|
||||
|
||||
// Deprecated, but the most supported for now.
|
||||
|
||||
@@ -10,7 +10,7 @@ export class AddonsWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'addons';
|
||||
public readonly label = 'Addons';
|
||||
|
||||
private _addonsContainer: HTMLElement;
|
||||
private _addonsContainer!: HTMLElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
// Description
|
||||
|
||||
@@ -30,14 +30,14 @@ export class CellInspectorWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'cell-inspector';
|
||||
public readonly label = 'Cell Inspector';
|
||||
|
||||
private _container: HTMLElement;
|
||||
private _positionEl: HTMLElement;
|
||||
private _charEl: HTMLElement;
|
||||
private _codeEl: HTMLElement;
|
||||
private _widthEl: HTMLElement;
|
||||
private _fgEl: HTMLElement;
|
||||
private _bgEl: HTMLElement;
|
||||
private _attrsEl: HTMLElement;
|
||||
private _container!: HTMLElement;
|
||||
private _positionEl!: HTMLElement;
|
||||
private _charEl!: HTMLElement;
|
||||
private _codeEl!: HTMLElement;
|
||||
private _widthEl!: HTMLElement;
|
||||
private _fgEl!: HTMLElement;
|
||||
private _bgEl!: HTMLElement;
|
||||
private _attrsEl!: HTMLElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
this._container = container;
|
||||
|
||||
@@ -10,7 +10,7 @@ export class GpuWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'gpu';
|
||||
public readonly label = 'WebGL';
|
||||
|
||||
private _textureAtlasContainer: HTMLElement;
|
||||
private _textureAtlasContainer!: HTMLElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
const zoomCheckbox = document.createElement('input');
|
||||
|
||||
@@ -80,8 +80,8 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'options';
|
||||
public readonly label = 'Options';
|
||||
|
||||
private _container: HTMLElement;
|
||||
private _optionsContainer: HTMLElement;
|
||||
private _container!: HTMLElement;
|
||||
private _optionsContainer!: HTMLElement;
|
||||
private _autoResize: boolean = true;
|
||||
|
||||
constructor(
|
||||
@@ -143,7 +143,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
const booleanOptions: string[] = [];
|
||||
const numberOptions: string[] = [];
|
||||
options.filter(o => blacklistedOptions.indexOf(o) === -1).forEach(o => {
|
||||
switch (typeof this._terminal.options[o]) {
|
||||
switch (typeof (this._terminal.options as Record<string, unknown>)[o]) {
|
||||
case 'boolean':
|
||||
booleanOptions.push(o);
|
||||
break;
|
||||
@@ -160,25 +160,25 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
let html = '';
|
||||
html += '<div class="option-group">';
|
||||
booleanOptions.forEach(o => {
|
||||
html += `<div class="option"><label><input id="opt-${o}" type="checkbox" ${this._terminal.options[o] ? 'checked' : ''}/> ${o}</label></div>`;
|
||||
html += `<div class="option"><label><input id="opt-${o}" type="checkbox" ${(this._terminal.options as Record<string, unknown>)[o] ? 'checked' : ''}/> ${o}</label></div>`;
|
||||
});
|
||||
nestedBooleanOptions.forEach(({ label, parent, prop }) => {
|
||||
const checked = this._terminal.options[parent]?.[prop] ?? false;
|
||||
const checked = (this._terminal.options as Record<string, Record<string, unknown> | undefined>)[parent]?.[prop] ?? false;
|
||||
html += `<div class="option"><label><input id="opt-${label.replace('.', '-')}" type="checkbox" ${checked ? 'checked' : ''}/> ${label}</label></div>`;
|
||||
});
|
||||
html += '</div><div class="option-group">';
|
||||
numberOptions.forEach(o => {
|
||||
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 class="option"><label>${o} <input id="opt-${o}" type="number" value="${(this._terminal.options as Record<string, unknown>)[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' : this._terminal.options[o];
|
||||
const selectedOption = o === 'theme' ? 'xtermjs' : (this._terminal.options as Record<string, unknown>)[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="${this._terminal.options[o]}"/></label></div>`;
|
||||
html += `<div class="option"><label>${o} <input id="opt-${o}" type="text" value="${(this._terminal.options as Record<string, unknown>)[o]}"/></label></div>`;
|
||||
}
|
||||
});
|
||||
html += '</div>';
|
||||
@@ -190,7 +190,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
const input = document.getElementById(`opt-${o}`) as HTMLInputElement;
|
||||
addDomListener(input, 'change', () => {
|
||||
console.log('change', o, input.checked);
|
||||
this._terminal.options[o] = input.checked;
|
||||
(this._terminal.options as Record<string, unknown>)[o] = input.checked;
|
||||
if (o ==='allowTransparency') {
|
||||
this._terminal.options.theme = this._getTheme();
|
||||
this._handlers.updateTerminalContainerBackground();
|
||||
@@ -201,7 +201,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
const input = document.getElementById(`opt-${label.replace('.', '-')}`) as HTMLInputElement;
|
||||
addDomListener(input, 'change', () => {
|
||||
console.log('change', label, input.checked);
|
||||
this._terminal.options[parent] = { ...this._terminal.options[parent], [prop]: input.checked };
|
||||
(this._terminal.options as Record<string, unknown>)[parent] = { ...(this._terminal.options as Record<string, Record<string, unknown> | undefined>)[parent], [prop]: input.checked };
|
||||
});
|
||||
});
|
||||
numberOptions.forEach(o => {
|
||||
@@ -216,7 +216,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
this._terminal.options.scrollback = parseInt(input.value);
|
||||
setTimeout(() => this._handlers.updateTerminalSize(), 5);
|
||||
} else {
|
||||
this._terminal.options[o] = parseInt(input.value);
|
||||
(this._terminal.options as Record<string, unknown>)[o] = parseInt(input.value);
|
||||
}
|
||||
this._handlers.updateTerminalSize();
|
||||
});
|
||||
@@ -225,7 +225,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
const input = document.getElementById(`opt-${o}`) as HTMLInputElement;
|
||||
addDomListener(input, 'change', () => {
|
||||
console.log('change', o, input.value);
|
||||
let value: any = input.value;
|
||||
let value: unknown = input.value;
|
||||
if (o === 'colsRows') {
|
||||
const m = input.value.match(/^([0-9]+)x([0-9]+)$/);
|
||||
if (m) {
|
||||
@@ -239,7 +239,7 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
} else if (o === 'theme') {
|
||||
value = this._getTheme();
|
||||
}
|
||||
this._terminal.options[o] = value;
|
||||
(this._terminal.options as Record<string, unknown>)[o] = value;
|
||||
if (o === 'theme') {
|
||||
this._handlers.updateTerminalContainerBackground();
|
||||
}
|
||||
@@ -259,11 +259,11 @@ export class OptionsWindow extends BaseWindow implements IControlWindow {
|
||||
}
|
||||
|
||||
private _getTheme(): ITheme {
|
||||
const input = document.querySelector<HTMLInputElement>('#opt-theme');
|
||||
let theme: ITheme;
|
||||
const input = document.querySelector<HTMLInputElement>('#opt-theme')!;
|
||||
let theme: ITheme = {};
|
||||
switch (input.value) {
|
||||
case 'default':
|
||||
theme = undefined;
|
||||
theme = {};
|
||||
break;
|
||||
case 'xtermjs':
|
||||
theme = { ...xtermjsTheme };
|
||||
|
||||
@@ -10,7 +10,7 @@ export class StyleWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'style';
|
||||
public readonly label = 'Style';
|
||||
|
||||
private _paddingElement: HTMLInputElement;
|
||||
private _paddingElement!: HTMLInputElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
const wrapper = document.createElement('div');
|
||||
|
||||
@@ -139,7 +139,9 @@ export class TestWindow extends BaseWindow implements IControlWindow {
|
||||
}
|
||||
dd.appendChild(button);
|
||||
dl.appendChild(dd);
|
||||
button.addEventListener('click', handler);
|
||||
if (handler) {
|
||||
button.addEventListener('click', handler);
|
||||
}
|
||||
}
|
||||
|
||||
private _addDdWithCheckbox(dl: HTMLElement, id: string, label: string, title: string, checked: boolean): void {
|
||||
@@ -465,7 +467,7 @@ function customGlyphAlignmentHandler(term: Terminal): void {
|
||||
while (fillChars.length > 0) {
|
||||
const batch = fillChars.splice(0, 10);
|
||||
for (const fillChar of batch) {
|
||||
term.write(`${fillChar.codePointAt(0).toString(16).toUpperCase().padEnd(5, ' ')} `);
|
||||
term.write(`${fillChar.codePointAt(0)!.toString(16).toUpperCase().padEnd(5, ' ')} `);
|
||||
}
|
||||
term.write('\n\r');
|
||||
for (let i = 0; i < 3; i++) {
|
||||
@@ -864,7 +866,7 @@ function addDecoration(term: Terminal, dim: number = 1): void {
|
||||
foregroundColor: '#00FE00',
|
||||
overviewRulerOptions: { color: '#ef292980', position: 'left' }
|
||||
});
|
||||
decoration.onRender((e: HTMLElement) => {
|
||||
decoration?.onRender((e: HTMLElement) => {
|
||||
e.style.right = '100%';
|
||||
e.style.backgroundColor = '#ef292980';
|
||||
});
|
||||
@@ -896,13 +898,16 @@ function decorationStressTest(term: Terminal): void {
|
||||
for (const x of [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]) {
|
||||
for (let y = 0; y < term.buffer.active.length; y++) {
|
||||
const cursorOffsetY = y - cursorY;
|
||||
decorationStressTestDecorations.push(term.registerDecoration({
|
||||
const decoration = term.registerDecoration({
|
||||
marker: term.registerMarker(cursorOffsetY),
|
||||
x,
|
||||
width: 4,
|
||||
backgroundColor: '#FF0000',
|
||||
overviewRulerOptions: { color: '#FF0000' }
|
||||
}));
|
||||
});
|
||||
if (decoration) {
|
||||
decorationStressTestDecorations.push(decoration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -919,56 +924,57 @@ function initProgress(term: Terminal, addons: AddonCollection): void {
|
||||
// NOTE: This is most likely not what you want to do for other progress indicators,
|
||||
// that have a proper visual state for error/paused.
|
||||
value = Math.min(10 + value * 0.9, 100);
|
||||
document.getElementById('progress-percent').style.width = `${value}%`;
|
||||
document.getElementById('progress-percent').style.backgroundColor = COLORS[state];
|
||||
document.getElementById('progress-state').innerText = `State: ${STATES[state]}`;
|
||||
document.getElementById('progress-percent')!.style.width = `${value}%`;
|
||||
document.getElementById('progress-percent')!.style.backgroundColor = COLORS[state];
|
||||
document.getElementById('progress-state')!.innerText = `State: ${STATES[state]}`;
|
||||
|
||||
document.getElementById('progress-percent').style.display = state === 3 ? 'none' : 'block';
|
||||
document.getElementById('progress-indeterminate').style.display = state === 3 ? 'block' : 'none';
|
||||
document.getElementById('progress-percent')!.style.display = state === 3 ? 'none' : 'block';
|
||||
document.getElementById('progress-indeterminate')!.style.display = state === 3 ? 'block' : 'none';
|
||||
}
|
||||
|
||||
const progressAddon = addons.progress.instance;
|
||||
const progressAddon = addons.progress.instance!;
|
||||
progressAddon.onChange(progressHandler);
|
||||
|
||||
// apply initial state once to make it visible on page load
|
||||
const initialProgress = progressAddon.progress;
|
||||
progressHandler(initialProgress);
|
||||
|
||||
document.getElementById('progress-run').addEventListener('click', async () => {
|
||||
document.getElementById('progress-run')!.addEventListener('click', async () => {
|
||||
term.write('\x1b]9;4;0\x1b\\');
|
||||
for (let i = 0; i <= 100; i += 5) {
|
||||
term.write(`\x1b]9;4;1;${i}\x1b\\`);
|
||||
await new Promise(res => setTimeout(res, 200));
|
||||
}
|
||||
});
|
||||
document.getElementById('progress-0').addEventListener('click', () => term.write('\x1b]9;4;0\x1b\\'));
|
||||
document.getElementById('progress-1').addEventListener('click', () => term.write('\x1b]9;4;1;20\x1b\\'));
|
||||
document.getElementById('progress-2').addEventListener('click', () => term.write('\x1b]9;4;2\x1b\\'));
|
||||
document.getElementById('progress-3').addEventListener('click', () => term.write('\x1b]9;4;3\x1b\\'));
|
||||
document.getElementById('progress-4').addEventListener('click', () => term.write('\x1b]9;4;4\x1b\\'));
|
||||
document.getElementById('progress-0')!.addEventListener('click', () => term.write('\x1b]9;4;0\x1b\\'));
|
||||
document.getElementById('progress-1')!.addEventListener('click', () => term.write('\x1b]9;4;1;20\x1b\\'));
|
||||
document.getElementById('progress-2')!.addEventListener('click', () => term.write('\x1b]9;4;2\x1b\\'));
|
||||
document.getElementById('progress-3')!.addEventListener('click', () => term.write('\x1b]9;4;3\x1b\\'));
|
||||
document.getElementById('progress-4')!.addEventListener('click', () => term.write('\x1b]9;4;4\x1b\\'));
|
||||
}
|
||||
|
||||
function initImageAddonExposed(term: Terminal, addons: AddonCollection): void {
|
||||
const DEFAULT_OPTIONS: IImageAddonOptions = (addons.image.instance as any)._defaultOpts;
|
||||
const limitStorageElement = document.querySelector<HTMLInputElement>('#image-storagelimit');
|
||||
limitStorageElement.valueAsNumber = addons.image.instance.storageLimit;
|
||||
const imageAddon = addons.image.instance!;
|
||||
const DEFAULT_OPTIONS: IImageAddonOptions = (imageAddon as any)._defaultOpts;
|
||||
const limitStorageElement = document.querySelector<HTMLInputElement>('#image-storagelimit')!;
|
||||
limitStorageElement.valueAsNumber = imageAddon.storageLimit;
|
||||
addDomListener(term, limitStorageElement, 'change', () => {
|
||||
try {
|
||||
addons.image.instance.storageLimit = limitStorageElement.valueAsNumber;
|
||||
limitStorageElement.valueAsNumber = addons.image.instance.storageLimit;
|
||||
console.log('changed storageLimit to', addons.image.instance.storageLimit);
|
||||
imageAddon.storageLimit = limitStorageElement.valueAsNumber;
|
||||
limitStorageElement.valueAsNumber = imageAddon.storageLimit;
|
||||
console.log('changed storageLimit to', imageAddon.storageLimit);
|
||||
} catch (e) {
|
||||
limitStorageElement.valueAsNumber = addons.image.instance.storageLimit;
|
||||
console.log('storageLimit at', addons.image.instance.storageLimit);
|
||||
limitStorageElement.valueAsNumber = imageAddon.storageLimit;
|
||||
console.log('storageLimit at', imageAddon.storageLimit);
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
const showPlaceholderElement = document.querySelector<HTMLInputElement>('#image-showplaceholder');
|
||||
showPlaceholderElement.checked = addons.image.instance.showPlaceholder;
|
||||
const showPlaceholderElement = document.querySelector<HTMLInputElement>('#image-showplaceholder')!;
|
||||
showPlaceholderElement.checked = imageAddon.showPlaceholder;
|
||||
addDomListener(term, showPlaceholderElement, 'change', () => {
|
||||
addons.image.instance.showPlaceholder = showPlaceholderElement.checked;
|
||||
imageAddon.showPlaceholder = showPlaceholderElement.checked;
|
||||
});
|
||||
const ctorOptionsElement = document.querySelector<HTMLTextAreaElement>('#image-options');
|
||||
const ctorOptionsElement = document.querySelector<HTMLTextAreaElement>('#image-options')!;
|
||||
ctorOptionsElement.value = JSON.stringify(DEFAULT_OPTIONS, null, 2);
|
||||
|
||||
const sixelDemo = (url: string) => () => fetch(url)
|
||||
@@ -988,16 +994,16 @@ function initImageAddonExposed(term: Terminal, addons: AddonCollection): void {
|
||||
term.write(`\x1b]1337;File=inline=1;size=${data.length}:${btoa(sdata)}\x1b\\`);
|
||||
});
|
||||
|
||||
document.getElementById('image-demo1').addEventListener('click',
|
||||
document.getElementById('image-demo1')!.addEventListener('click',
|
||||
sixelDemo('https://raw.githubusercontent.com/saitoha/libsixel/master/images/snake.six'));
|
||||
document.getElementById('image-demo2').addEventListener('click',
|
||||
document.getElementById('image-demo2')!.addEventListener('click',
|
||||
sixelDemo('https://raw.githubusercontent.com/jerch/node-sixel/master/testfiles/test2.sixel'));
|
||||
document.getElementById('image-demo3').addEventListener('click',
|
||||
document.getElementById('image-demo3')!.addEventListener('click',
|
||||
iipDemo('https://raw.githubusercontent.com/jerch/node-sixel/master/palette.png'));
|
||||
|
||||
// demo for image retrieval API
|
||||
term.element.addEventListener('click', (ev: MouseEvent) => {
|
||||
if (!ev.ctrlKey || !addons.image.instance) return;
|
||||
term.element!.addEventListener('click', (ev: MouseEvent) => {
|
||||
if (!ev.ctrlKey || !imageAddon) return;
|
||||
|
||||
// TODO...
|
||||
// if (ev.altKey) {
|
||||
@@ -1015,10 +1021,10 @@ function initImageAddonExposed(term: Terminal, addons: AddonCollection): void {
|
||||
const y = pos[1] - 1;
|
||||
const canvas = ev.shiftKey
|
||||
// ctrl+shift+click: get single tile
|
||||
? addons.image.instance.extractTileAtBufferCell(x, term.buffer.active.viewportY + y)
|
||||
? imageAddon.extractTileAtBufferCell(x, term.buffer.active.viewportY + y)
|
||||
// ctrl+click: get original image
|
||||
: addons.image.instance.getImageAtBufferCell(x, term.buffer.active.viewportY + y);
|
||||
canvas?.toBlob(data => window.open(URL.createObjectURL(data), '_blank'));
|
||||
: imageAddon.getImageAtBufferCell(x, term.buffer.active.viewportY + y);
|
||||
canvas?.toBlob(data => data && window.open(URL.createObjectURL(data), '_blank'));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
|
||||
import { BaseWindow } from './baseWindow';
|
||||
import type { IControlWindow } from '../controlBar';
|
||||
import type { Terminal } from '@xterm/xterm';
|
||||
|
||||
export class VtWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'vt';
|
||||
public readonly label = 'VT';
|
||||
|
||||
private _container: HTMLElement;
|
||||
private _term: Terminal | undefined;
|
||||
private _container!: HTMLElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
this._container = container;
|
||||
@@ -65,7 +63,7 @@ export class VtWindow extends BaseWindow implements IControlWindow {
|
||||
const writeCsiSplit = writeCsi.split('|');
|
||||
const prefix = writeCsiSplit.length === 2 ? writeCsiSplit[0] : '';
|
||||
const suffix = writeCsiSplit[writeCsiSplit.length - 1];
|
||||
element.addEventListener('click', () => this._term?.write(this._csi(`${prefix}${inputs.map(e => e.value).join(';')}${suffix}`)));
|
||||
element.addEventListener('click', () => this._terminal.write(this._csi(`${prefix}${inputs.map(e => e.value).join(';')}${suffix}`)));
|
||||
|
||||
const desc = document.createElement('span');
|
||||
desc.textContent = description;
|
||||
|
||||
@@ -10,7 +10,7 @@ export class WebglWindow extends BaseWindow implements IControlWindow {
|
||||
public readonly id = 'addon-webgl';
|
||||
public readonly label = 'webgl';
|
||||
|
||||
private _textureAtlasContainer: HTMLElement;
|
||||
private _textureAtlasContainer!: HTMLElement;
|
||||
|
||||
public build(container: HTMLElement): void {
|
||||
const zoomCheckbox = document.createElement('input');
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"rootDir": ".",
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"strict": true,
|
||||
"paths": {
|
||||
"@xterm/addon-attach": ["../../addons/addon-attach"],
|
||||
"@xterm/addon-clipboard": ["../../addons/addon-clipboard"],
|
||||
|
||||
Reference in New Issue
Block a user