diff --git a/README.md b/README.md
index 551a94f4..c654f288 100644
--- a/README.md
+++ b/README.md
@@ -172,6 +172,7 @@ computational environment for Jupyter, supporting interactive data science and s
- [**Shellvault**](https://www.shellvault.io): The cloud-based SSH terminal you can access from anywhere.
- [**Juno**](http://junolab.org/): A flexible Julia IDE, based on Atom.
- [**webssh**](https://github.com/huashengdun/webssh): Web based ssh client.
+- [**info-beamer hosted**](https://info-beamer.com): Uses Xterm.js to manage digital signage devices from the web dashboard.
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
diff --git a/demo/client.ts b/demo/client.ts
index d5196d37..6c69899e 100644
--- a/demo/client.ts
+++ b/demo/client.ts
@@ -235,7 +235,7 @@ function initOptions(term: TerminalType): void {
});
html += '
';
Object.keys(stringOptions).forEach(o => {
@@ -265,7 +265,7 @@ function initOptions(term: TerminalType): void {
if (o === 'cols' || o === 'rows') {
updateTerminalSize();
} else {
- term.setOption(o, parseInt(input.value, 10));
+ term.setOption(o, o === 'lineHeight' ? parseFloat(input.value) : parseInt(input.value, 10));
}
});
});
diff --git a/package.json b/package.json
index c84a0164..4aef95af 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "xterm",
"description": "Full xterm terminal, in your browser",
- "version": "3.8.0",
+ "version": "3.9.0",
"main": "lib/public/Terminal.js",
"types": "typings/xterm.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
diff --git a/src/Buffer.test.ts b/src/Buffer.test.ts
index db8a460d..2561ce36 100644
--- a/src/Buffer.test.ts
+++ b/src/Buffer.test.ts
@@ -7,7 +7,7 @@ import { assert, expect } from 'chai';
import { ITerminal } from './Types';
import { Buffer, DEFAULT_ATTR, CHAR_DATA_CHAR_INDEX } from './Buffer';
import { CircularList } from './common/CircularList';
-import { MockTerminal, TestTerminal } from './utils/TestUtils.test';
+import { MockTerminal, TestTerminal } from './ui/TestUtils.test';
import { BufferLine } from './BufferLine';
const INIT_COLS = 80;
diff --git a/src/Buffer.ts b/src/Buffer.ts
index 0f75bdad..dd657a2a 100644
--- a/src/Buffer.ts
+++ b/src/Buffer.ts
@@ -7,7 +7,7 @@ import { CircularList } from './common/CircularList';
import { CharData, ITerminal, IBuffer, IBufferLine, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult, IBufferLineConstructor } from './Types';
import { EventEmitter } from './common/EventEmitter';
import { IMarker } from 'xterm';
-import { BufferLine, BufferLineTypedArray } from './BufferLine';
+import { BufferLine, BufferLineJSArray } from './BufferLine';
import { DEFAULT_COLOR } from './renderer/atlas/Types';
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
@@ -57,9 +57,9 @@ export class Buffer implements IBuffer {
}
public setBufferLineFactory(type: string): void {
- if (type === 'TypedArray') {
- if (this._bufferLineConstructor !== BufferLineTypedArray) {
- this._bufferLineConstructor = BufferLineTypedArray;
+ if (type === 'JsArray') {
+ if (this._bufferLineConstructor !== BufferLineJSArray) {
+ this._bufferLineConstructor = BufferLineJSArray;
this._recreateLines();
}
} else {
diff --git a/src/BufferLine.ts b/src/BufferLine.ts
index 7c697334..a95fe0f4 100644
--- a/src/BufferLine.ts
+++ b/src/BufferLine.ts
@@ -7,8 +7,10 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
/**
* Class representing a terminal line.
+ *
+ * @deprecated to be removed with one of the next releases
*/
-export class BufferLine implements IBufferLine {
+export class BufferLineJSArray implements IBufferLine {
protected _data: CharData[];
public isWrapped = false;
public length: number;
@@ -94,14 +96,14 @@ export class BufferLine implements IBufferLine {
}
}
- public copyFrom(line: BufferLine): void {
+ public copyFrom(line: BufferLineJSArray): void {
this._data = line._data.slice(0);
this.length = line.length;
this.isWrapped = line.isWrapped;
}
public clone(): IBufferLine {
- const newLine = new BufferLine(0);
+ const newLine = new BufferLineJSArray(0);
newLine.copyFrom(this);
return newLine;
}
@@ -119,17 +121,8 @@ const enum Cell {
/**
* Typed array based bufferline implementation.
- * Note: Unlike the JS variant the access to the data
- * via set/get is always a copy action.
- * Sloppy ref style coding will not work anymore:
- * line = new BufferLine(10);
- * char = line.get(0); // char is a copy
- * char[some_index] = 123; // will not update the line
- * line.set(0, ch); // do this to update line data
- * TODO:
- * - provide getData/setData to directly access the data
*/
-export class BufferLineTypedArray implements IBufferLine {
+export class BufferLine implements IBufferLine {
protected _data: Uint32Array | null = null;
protected _combined: {[index: number]: string} = {};
public length: number;
@@ -248,7 +241,7 @@ export class BufferLineTypedArray implements IBufferLine {
}
/** alter to a full copy of line */
- public copyFrom(line: BufferLineTypedArray): void {
+ public copyFrom(line: BufferLine): void {
if (this.length !== line.length) {
this._data = new Uint32Array(line._data);
} else {
@@ -265,7 +258,7 @@ export class BufferLineTypedArray implements IBufferLine {
/** create a new clone */
public clone(): IBufferLine {
- const newLine = new BufferLineTypedArray(0);
+ const newLine = new BufferLine(0);
// creation of new typed array from another is actually pretty slow :(
// still faster than copying values one by one
newLine._data = new Uint32Array(this._data);
diff --git a/src/BufferSet.test.ts b/src/BufferSet.test.ts
index 38f2ddab..26f9cd42 100644
--- a/src/BufferSet.test.ts
+++ b/src/BufferSet.test.ts
@@ -7,7 +7,7 @@ import { assert } from 'chai';
import { ITerminal } from './Types';
import { BufferSet } from './BufferSet';
import { Buffer } from './Buffer';
-import { MockTerminal } from './utils/TestUtils.test';
+import { MockTerminal } from './ui/TestUtils.test';
describe('BufferSet', () => {
let terminal: ITerminal;
diff --git a/src/CharWidth.test.ts b/src/CharWidth.test.ts
index d4ddd24c..0747fdf1 100644
--- a/src/CharWidth.test.ts
+++ b/src/CharWidth.test.ts
@@ -3,7 +3,7 @@
* @license MIT
*/
-import { TestTerminal } from './utils/TestUtils.test';
+import { TestTerminal } from './ui/TestUtils.test';
import { assert } from 'chai';
import { getStringCellWidth, wcwidth } from './CharWidth';
import { IBuffer } from './Types';
diff --git a/src/EscapeSequenceParser.ts b/src/EscapeSequenceParser.ts
index b38c50f5..f4898841 100644
--- a/src/EscapeSequenceParser.ts
+++ b/src/EscapeSequenceParser.ts
@@ -67,7 +67,8 @@ const PRINTABLES = r(0x20, 0x7f);
const EXECUTABLES = r(0x00, 0x18);
EXECUTABLES.push(0x19);
EXECUTABLES.push.apply(EXECUTABLES, r(0x1c, 0x20));
-const DEFAULT_TRANSITION = ParserAction.ERROR << 4 | ParserState.GROUND;
+// Pseudo-character placeholder for printable non-ascii characters.
+const NON_ASCII_PRINTABLE = 0xA0;
/**
* VT500 compatible transition table.
@@ -79,10 +80,10 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
const states: number[] = r(ParserState.GROUND, ParserState.DCS_PASSTHROUGH + 1);
let state: any;
- // table with default transition [any] --> DEFAULT_TRANSITION
+ // table with default transition
for (state in states) {
// NOTE: table lookup is capped at 0xa0 in parse to keep the table small
- for (let code = 0; code < 160; ++code) {
+ for (let code = 0; code <= NON_ASCII_PRINTABLE; ++code) {
table.add(code, state, ParserAction.ERROR, ParserState.GROUND);
}
}
@@ -184,6 +185,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable {
table.addMany(PRINTABLES, ParserState.DCS_PASSTHROUGH, ParserAction.DCS_PUT, ParserState.DCS_PASSTHROUGH);
table.add(0x7f, ParserState.DCS_PASSTHROUGH, ParserAction.IGNORE, ParserState.DCS_PASSTHROUGH);
table.addMany([0x1b, 0x9c], ParserState.DCS_PASSTHROUGH, ParserAction.DCS_UNHOOK, ParserState.GROUND);
+ table.add(NON_ASCII_PRINTABLE, ParserState.OSC_STRING, ParserAction.OSC_PUT, ParserState.OSC_STRING);
return table;
})();
@@ -391,7 +393,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
}
// normal transition & action lookup
- transition = (code < 0xa0) ? (table[currentState << 8 | code]) : DEFAULT_TRANSITION;
+ transition = table[currentState << 8 | (code < 0xa0 ? code : NON_ASCII_PRINTABLE)];
switch (transition >> 4) {
case ParserAction.PRINT:
print = (~print) ? print : i;
@@ -423,10 +425,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
case ParserState.GROUND:
print = (~print) ? print : i;
break;
- case ParserState.OSC_STRING:
- osc += String.fromCharCode(code);
- transition |= ParserState.OSC_STRING;
- break;
case ParserState.CSI_IGNORE:
transition |= ParserState.CSI_IGNORE;
break;
@@ -517,7 +515,15 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
osc = '';
break;
case ParserAction.OSC_PUT:
- osc += data.charAt(i);
+ for (let j = i + 1; ; j++) {
+ if (j >= l
+ || (code = data.charCodeAt(j)) < 0x20
+ || (code > 0x7f && code <= 0x9f)) {
+ osc += data.substring(i, j);
+ i = j - 1;
+ break;
+ }
+ }
break;
case ParserAction.OSC_END:
if (osc && code !== 0x18 && code !== 0x1a) {
diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts
index b2fea06a..acc18ea5 100644
--- a/src/InputHandler.test.ts
+++ b/src/InputHandler.test.ts
@@ -5,7 +5,7 @@
import { assert, expect } from 'chai';
import { InputHandler } from './InputHandler';
-import { MockInputHandlingTerminal } from './utils/TestUtils.test';
+import { MockInputHandlingTerminal } from './ui/TestUtils.test';
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, DEFAULT_ATTR } from './Buffer';
import { Terminal } from './Terminal';
import { IBufferLine } from './Types';
diff --git a/src/Linkifier.test.ts b/src/Linkifier.test.ts
index 22e797aa..0ba1294a 100644
--- a/src/Linkifier.test.ts
+++ b/src/Linkifier.test.ts
@@ -7,7 +7,7 @@ import { assert } from 'chai';
import { IMouseZoneManager, IMouseZone } from './ui/Types';
import { ILinkMatcher, ITerminal, IBufferLine } from './Types';
import { Linkifier } from './Linkifier';
-import { MockBuffer, MockTerminal, TestTerminal } from './utils/TestUtils.test';
+import { MockBuffer, MockTerminal, TestTerminal } from './ui/TestUtils.test';
import { CircularList } from './common/CircularList';
import { BufferLine } from './BufferLine';
diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts
index 8735e894..2f74ccda 100644
--- a/src/SelectionManager.test.ts
+++ b/src/SelectionManager.test.ts
@@ -9,7 +9,7 @@ import { SelectionManager, SelectionMode } from './SelectionManager';
import { SelectionModel } from './SelectionModel';
import { BufferSet } from './BufferSet';
import { ITerminal, IBuffer, IBufferLine } from './Types';
-import { MockTerminal } from './utils/TestUtils.test';
+import { MockTerminal } from './ui/TestUtils.test';
import { BufferLine } from './BufferLine';
class TestMockTerminal extends MockTerminal {
diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts
index 3dc50271..4bac0400 100644
--- a/src/SelectionManager.ts
+++ b/src/SelectionManager.ts
@@ -5,7 +5,7 @@
import { ITerminal, ISelectionManager, IBuffer, CharData, IBufferLine } from './Types';
import { XtermListener } from './common/Types';
-import { MouseHelper } from './utils/MouseHelper';
+import { MouseHelper } from './ui/MouseHelper';
import * as Browser from './core/Platform';
import { CharMeasure } from './ui/CharMeasure';
import { EventEmitter } from './common/EventEmitter';
diff --git a/src/SelectionModel.test.ts b/src/SelectionModel.test.ts
index 59b2ce75..8d4b30bb 100644
--- a/src/SelectionModel.test.ts
+++ b/src/SelectionModel.test.ts
@@ -7,7 +7,7 @@ import { assert } from 'chai';
import { ITerminal } from './Types';
import { SelectionModel } from './SelectionModel';
import { BufferSet } from './BufferSet';
-import { MockTerminal } from './utils/TestUtils.test';
+import { MockTerminal } from './ui/TestUtils.test';
class TestSelectionModel extends SelectionModel {
constructor(
diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts
index fd59144c..733d2b39 100644
--- a/src/Terminal.test.ts
+++ b/src/Terminal.test.ts
@@ -5,7 +5,7 @@
import { assert, expect } from 'chai';
import { Terminal } from './Terminal';
-import { MockViewport, MockCompositionHelper, MockRenderer } from './utils/TestUtils.test';
+import { MockViewport, MockCompositionHelper, MockRenderer } from './ui/TestUtils.test';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, DEFAULT_ATTR } from './Buffer';
const INIT_COLS = 80;
diff --git a/src/Terminal.ts b/src/Terminal.ts
index e374f2cd..bc8fb103 100644
--- a/src/Terminal.ts
+++ b/src/Terminal.ts
@@ -39,8 +39,7 @@ import { CharMeasure } from './ui/CharMeasure';
import * as Browser from './core/Platform';
import { addDisposableDomListener } from './ui/Lifecycle';
import * as Strings from './Strings';
-import { MouseHelper } from './utils/MouseHelper';
-import { clone } from './utils/Clone';
+import { MouseHelper } from './ui/MouseHelper';
import { DEFAULT_BELL_SOUND, SoundManager } from './SoundManager';
import { DEFAULT_ANSI_COLORS } from './renderer/ColorManager';
import { MouseZoneManager } from './ui/MouseZoneManager';
@@ -52,6 +51,7 @@ import { DomRenderer } from './renderer/dom/DomRenderer';
import { IKeyboardEvent } from './common/Types';
import { evaluateKeyboardEvent } from './core/input/Keyboard';
import { KeyboardResultType, ICharset } from './core/Types';
+import { clone } from './common/Clone';
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -106,7 +106,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
theme: null,
rightClickSelectsWord: Browser.isMac,
rendererType: 'canvas',
- experimentalBufferLineImpl: 'JsArray'
+ experimentalBufferLineImpl: 'TypedArray'
};
export class Terminal extends EventEmitter implements ITerminal, IDisposable, IInputHandlingTerminal {
@@ -464,6 +464,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.renderer.onResize(this.cols, this.rows);
this.refresh(0, this.rows - 1);
}
+ break;
case 'rendererType':
if (this.renderer) {
this.unregister(this.renderer);
@@ -1179,7 +1180,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
*/
public scroll(isWrapped: boolean = false): void {
let newLine: IBufferLine;
- const useRecycling = this.options.experimentalBufferLineImpl === 'TypedArray';
+ const useRecycling = this.options.experimentalBufferLineImpl !== 'JsArray';
if (useRecycling) {
newLine = this._blankLine;
if (!newLine || newLine.length !== this.cols || newLine.get(0)[CHAR_DATA_ATTR_INDEX] !== this.eraseAttr()) {
diff --git a/src/Types.ts b/src/Types.ts
index 430c6575..a5aa8add 100644
--- a/src/Types.ts
+++ b/src/Types.ts
@@ -245,7 +245,7 @@ export interface ILinkifierAccessor {
}
export interface IMouseHelper {
- getCoords(event: { pageX: number, pageY: number }, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
+ getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number): { x: number, y: number };
}
diff --git a/src/utils/Clone.test.ts b/src/common/Clone.test.ts
similarity index 95%
rename from src/utils/Clone.test.ts
rename to src/common/Clone.test.ts
index b24452c8..4b815ff3 100644
--- a/src/utils/Clone.test.ts
+++ b/src/common/Clone.test.ts
@@ -101,7 +101,7 @@ describe('clone', () => {
test.a.b.c.d.e.f = 'bar';
// The values at a greater depth then 5 should not be cloned
- assert.equal(cloned.a.b.c.d.e.f, 'bar');
+ assert.equal((cloned as any).a.b.c.d.e.f, 'bar');
});
it('should allow an optional maximum depth to be set', () => {
@@ -118,7 +118,7 @@ describe('clone', () => {
test.a.b.c = 'bar';
// The values at a greater depth then 2 should not be cloned
- assert.equal(cloned.a.b.c, 'bar');
+ assert.equal((cloned as any).a.b.c, 'bar');
});
it('should not throw when cloning a recursive reference', () => {
diff --git a/src/utils/Clone.ts b/src/common/Clone.ts
similarity index 90%
rename from src/utils/Clone.ts
rename to src/common/Clone.ts
index b09c0258..78bacbb5 100644
--- a/src/utils/Clone.ts
+++ b/src/common/Clone.ts
@@ -6,7 +6,7 @@
/*
* A simple utility for cloning values
*/
-export const clone = (val: T, depth: number = 5): T => {
+export function clone(val: T, depth: number = 5): T | null {
if (typeof val !== 'object') {
return val;
}
@@ -25,4 +25,4 @@ export const clone = (val: T, depth: number = 5): T => {
}
return clonedObject as T;
-};
+}
diff --git a/src/renderer/CharacterJoinerRegistry.test.ts b/src/renderer/CharacterJoinerRegistry.test.ts
index 383d2a7f..0c29566a 100644
--- a/src/renderer/CharacterJoinerRegistry.test.ts
+++ b/src/renderer/CharacterJoinerRegistry.test.ts
@@ -1,6 +1,6 @@
import { assert } from 'chai';
-import { MockTerminal, MockBuffer } from '../utils/TestUtils.test';
+import { MockTerminal, MockBuffer } from '../ui/TestUtils.test';
import { CircularList } from '../common/CircularList';
import { ICharacterJoinerRegistry } from './Types';
diff --git a/src/renderer/atlas/CharAtlasCache.ts b/src/renderer/atlas/CharAtlasCache.ts
index 3cb0e1cd..388a181b 100644
--- a/src/renderer/atlas/CharAtlasCache.ts
+++ b/src/renderer/atlas/CharAtlasCache.ts
@@ -42,8 +42,6 @@ export function acquireCharAtlas(
): BaseCharAtlas {
const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors);
- // TODO: Currently if a terminal changes configs it will not free the entry reference (until it's disposed)
-
// Check to see if the terminal already owns this config
for (let i = 0; i < charAtlasCache.length; i++) {
const entry = charAtlasCache[i];
@@ -54,6 +52,7 @@ export function acquireCharAtlas(
}
// The configs differ, release the terminal from the entry
if (entry.ownedBy.length === 1) {
+ entry.atlas.dispose();
charAtlasCache.splice(i, 1);
} else {
entry.ownedBy.splice(ownedByIndex, 1);
@@ -94,6 +93,7 @@ export function removeTerminalFromCache(terminal: ITerminal): void {
if (index !== -1) {
if (charAtlasCache[i].ownedBy.length === 1) {
// Remove the cache entry if it's the only terminal
+ charAtlasCache[i].atlas.dispose();
charAtlasCache.splice(i, 1);
} else {
// Remove the reference from the cache entry
diff --git a/src/utils/MouseHelper.test.ts b/src/ui/MouseHelper.test.ts
similarity index 61%
rename from src/utils/MouseHelper.test.ts
rename to src/ui/MouseHelper.test.ts
index 94d63b2b..26888bf7 100644
--- a/src/utils/MouseHelper.test.ts
+++ b/src/ui/MouseHelper.test.ts
@@ -37,34 +37,28 @@ describe('MouseHelper.getCoords', () => {
describe('when charMeasure is not initialized', () => {
it('should return null', () => {
charMeasure = new MockCharMeasure();
- assert.equal(mouseHelper.getCoords({ pageX: 0, pageY: 0 }, document.createElement('div'), charMeasure, 10, 10), null);
- });
- });
-
- describe('when pageX/pageY are not supported', () => {
- it('should return null', () => {
- assert.equal(mouseHelper.getCoords({ pageX: undefined, pageY: undefined }, document.createElement('div'), charMeasure, 10, 10), null);
+ assert.equal(mouseHelper.getCoords({ clientX: 0, clientY: 0 }, document.createElement('div'), charMeasure, 10, 10), null);
});
});
it('should return the cell that was clicked', () => {
let coords: [number, number];
- coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH / 2, pageY: CHAR_HEIGHT / 2 }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
- coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
- coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT + 1 }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 2]);
- coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH + 1, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [2, 1]);
});
it('should ensure the coordinates are returned within the terminal bounds', () => {
let coords: [number, number];
- coords = mouseHelper.getCoords({ pageX: -1, pageY: -1 }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
// Event are double the cols/rows
- coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH * 20, pageY: CHAR_HEIGHT * 20 }, document.createElement('div'), charMeasure, 10, 10);
+ coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal');
});
});
diff --git a/src/utils/MouseHelper.ts b/src/ui/MouseHelper.ts
similarity index 72%
rename from src/utils/MouseHelper.ts
rename to src/ui/MouseHelper.ts
index e4b3f211..e36e7f17 100644
--- a/src/utils/MouseHelper.ts
+++ b/src/ui/MouseHelper.ts
@@ -3,40 +3,19 @@
* @license MIT
*/
-import { ICharMeasure } from '../Types';
+import { ICharMeasure, IMouseHelper } from '../Types';
import { IRenderer } from '../renderer/Types';
-export class MouseHelper {
+export class MouseHelper implements IMouseHelper {
constructor(private _renderer: IRenderer) {}
public setRenderer(renderer: IRenderer): void {
this._renderer = renderer;
}
- public static getCoordsRelativeToElement(event: {pageX: number, pageY: number}, element: HTMLElement): [number, number] {
- // Ignore browsers that don't support MouseEvent.pageX
- if (event.pageX === null || event.pageX === undefined) {
- return null;
- }
-
- const originalElement = element;
- let x = event.pageX;
- let y = event.pageY;
-
- // Converts the coordinates from being relative to the document to being
- // relative to the terminal.
- while (element) {
- x -= element.offsetLeft;
- y -= element.offsetTop;
- element = element.offsetParent;
- }
- element = originalElement;
- while (element && element !== element.ownerDocument.body) {
- x += element.scrollLeft;
- y += element.scrollTop;
- element = element.parentElement;
- }
- return [x, y];
+ public static getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] {
+ const rect = element.getBoundingClientRect();
+ return [event.clientX - rect.left, event.clientY - rect.top];
}
/**
@@ -52,7 +31,7 @@ export class MouseHelper {
* apply an offset to the x value such that the left half of the cell will
* select that cell and the right half will select the next cell.
*/
- public getCoords(event: {pageX: number, pageY: number}, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
+ public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
// Coordinates cannot be measured if charMeasure has not been initialized
if (!charMeasure.width || !charMeasure.height) {
return null;
diff --git a/src/utils/TestUtils.test.ts b/src/ui/TestUtils.test.ts
similarity index 100%
rename from src/utils/TestUtils.test.ts
rename to src/ui/TestUtils.test.ts
diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts
index c6b6b1e5..7528bb55 100644
--- a/typings/xterm.d.ts
+++ b/typings/xterm.d.ts
@@ -108,7 +108,7 @@ declare module 'xterm' {
* - 'TypedArray': The new experimental implementation based on TypedArrays that is expected to
* significantly boost performance and memory consumption. Use at your own risk.
*
- * This option will be removed in the future.
+ * @deprecated This option will be removed in the future.
*/
experimentalBufferLineImpl?: 'JsArray' | 'TypedArray';