From 634d4af4dddf02845b5faa76316edcffaae7def2 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 21 Nov 2016 14:27:41 -0800 Subject: [PATCH 1/4] Rename Viewport.js -> Viewport.ts Part of #335 --- src/{Viewport.js => Viewport.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{Viewport.js => Viewport.ts} (100%) diff --git a/src/Viewport.js b/src/Viewport.ts similarity index 100% rename from src/Viewport.js rename to src/Viewport.ts From e0d98711956bb1a78110aa98dec10b046a08a7f4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 21 Nov 2016 14:39:08 -0800 Subject: [PATCH 2/4] Convert Viewport to a TS class --- src/Interfaces.ts | 14 +++ src/Viewport.ts | 211 ++++++++++++++++++++++++---------------------- 2 files changed, 123 insertions(+), 102 deletions(-) create mode 100644 src/Interfaces.ts diff --git a/src/Interfaces.ts b/src/Interfaces.ts new file mode 100644 index 0000000..14355e5 --- /dev/null +++ b/src/Interfaces.ts @@ -0,0 +1,14 @@ +/** + * xterm.js: xterm, in the browser + * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) + */ + +export interface ITerminal { + rowContainer: HTMLElement; + ydisp: number; + lines: string[]; + rows: number; + + on(event: string, callback: () => void); + scrollDisp(disp: number, suppressScrollEvent: boolean); +} diff --git a/src/Viewport.ts b/src/Viewport.ts index b47e805..573a050 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -3,112 +3,119 @@ * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) */ +import { ITerminal } from './Interfaces'; + /** * Represents the viewport of a terminal, the visible area within the larger buffer of output. * Logic for the virtual scroll bar is included in this object. - * @param {Terminal} terminal The Terminal object. - * @param {HTMLElement} viewportElement The DOM element acting as the viewport - * @param {HTMLElement} charMeasureElement A DOM element used to measure the character size of - * the terminal. + * @param viewportElement The DOM element acting as the viewport. + * @param scrollArea The DOM element acting as the scroll area. + * @param charMeasureElement A DOM element used to measure the character size of. the terminal. */ -function Viewport(terminal, viewportElement, scrollArea, charMeasureElement) { - this.terminal = terminal; - this.viewportElement = viewportElement; - this.scrollArea = scrollArea; - this.charMeasureElement = charMeasureElement; - this.currentRowHeight = 0; - this.lastRecordedBufferLength = 0; - this.lastRecordedViewportHeight = 0; +export class Viewport { - this.terminal.on('scroll', this.syncScrollArea.bind(this)); - this.terminal.on('resize', this.syncScrollArea.bind(this)); - this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); + private currentRowHeight: number; + private lastRecordedBufferLength: number; + private lastRecordedViewportHeight: number; - this.syncScrollArea(); + constructor( + private terminal: ITerminal, + private viewportElement: HTMLElement, + private scrollArea: HTMLElement, + private charMeasureElement: HTMLElement + ) { + this.currentRowHeight = 0; + this.lastRecordedBufferLength = 0; + this.lastRecordedViewportHeight = 0; + + this.terminal.on('scroll', this.syncScrollArea.bind(this)); + this.terminal.on('resize', this.syncScrollArea.bind(this)); + this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); + + this.syncScrollArea(); + } + + /** + * Refreshes row height, setting line-height, viewport height and scroll area height if + * necessary. + * @param charSize A character size measurement bounding rect object, if it doesn't exist it will + * be created. + */ + private refresh(charSize?: ClientRect): void { + var size = charSize || this.charMeasureElement.getBoundingClientRect(); + if (size.height > 0) { + var rowHeightChanged = size.height !== this.currentRowHeight; + if (rowHeightChanged) { + this.currentRowHeight = size.height; + this.viewportElement.style.lineHeight = size.height + 'px'; + this.terminal.rowContainer.style.lineHeight = size.height + 'px'; + } + var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; + if (rowHeightChanged || viewportHeightChanged) { + this.lastRecordedViewportHeight = this.terminal.rows; + this.viewportElement.style.height = size.height * this.terminal.rows + 'px'; + } + this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px'; + } + } + + /** + * Updates dimensions and synchronizes the scroll area if necessary. + */ + public syncScrollArea(): void { + if (this.lastRecordedBufferLength !== this.terminal.lines.length) { + // If buffer height changed + this.lastRecordedBufferLength = this.terminal.lines.length; + this.refresh(); + } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { + // If viewport height changed + this.refresh(); + } else { + // If size has changed, refresh viewport + var size = this.charMeasureElement.getBoundingClientRect(); + if (size.height !== this.currentRowHeight) { + this.refresh(size); + } + } + + // Sync scrollTop + var scrollTop = this.terminal.ydisp * this.currentRowHeight; + if (this.viewportElement.scrollTop !== scrollTop) { + this.viewportElement.scrollTop = scrollTop; + } + } + + /** + * Handles scroll events on the viewport, calculating the new viewport and requesting the + * terminal to scroll to it. + * @param ev The scroll event. + */ + private onScroll(ev: Event) { + var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); + var diff = newRow - this.terminal.ydisp; + this.terminal.scrollDisp(diff, true); + } + + /** + * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual + * scrolling to `onScroll`, this event needs to be attached manually by the consumer of + * `Viewport`. + * @param ev The mouse wheel event. + */ + public onWheel(ev: WheelEvent) { + if (ev.deltaY === 0) { + // Do nothing if it's not a vertical scroll event + return; + } + // Fallback to WheelEvent.DOM_DELTA_PIXEL + var multiplier = 1; + if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { + multiplier = this.currentRowHeight; + } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { + multiplier = this.currentRowHeight * this.terminal.rows; + } + this.viewportElement.scrollTop += ev.deltaY * multiplier; + // Prevent the page from scrolling when the terminal scrolls + ev.preventDefault(); + }; } - -/** - * Refreshes row height, setting line-height, viewport height and scroll area height if - * necessary. - * @param {number|undefined} charSize A character size measurement bounding rect object, if it - * doesn't exist it will be created. - */ -Viewport.prototype.refresh = function(charSize) { - var size = charSize || this.charMeasureElement.getBoundingClientRect(); - if (size.height > 0) { - var rowHeightChanged = size.height !== this.currentRowHeight; - if (rowHeightChanged) { - this.currentRowHeight = size.height; - this.viewportElement.style.lineHeight = size.height + 'px'; - this.terminal.rowContainer.style.lineHeight = size.height + 'px'; - } - var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; - if (rowHeightChanged || viewportHeightChanged) { - this.lastRecordedViewportHeight = this.terminal.rows; - this.viewportElement.style.height = size.height * this.terminal.rows + 'px'; - } - this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px'; - } -}; - -/** - * Updates dimensions and synchronizes the scroll area if necessary. - */ -Viewport.prototype.syncScrollArea = function() { - if (this.lastRecordedBufferLength !== this.terminal.lines.length) { - // If buffer height changed - this.lastRecordedBufferLength = this.terminal.lines.length; - this.refresh(); - } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { - // If viewport height changed - this.refresh(); - } else { - // If size has changed, refresh viewport - var size = this.charMeasureElement.getBoundingClientRect(); - if (size.height !== this.currentRowHeight) { - this.refresh(size); - } - } - - // Sync scrollTop - var scrollTop = this.terminal.ydisp * this.currentRowHeight; - if (this.viewportElement.scrollTop !== scrollTop) { - this.viewportElement.scrollTop = scrollTop; - } -}; - -/** - * Handles scroll events on the viewport, calculating the new viewport and requesting the - * terminal to scroll to it. - * @param {Event} ev The scroll event. - */ -Viewport.prototype.onScroll = function(ev) { - var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); - var diff = newRow - this.terminal.ydisp; - this.terminal.scrollDisp(diff, true); -}; - -/** - * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual - * scrolling to `onScroll`, this event needs to be attached manually by the consumer of - * `Viewport`. - * @param {WheelEvent} ev The mouse wheel event. - */ -Viewport.prototype.onWheel = function(ev) { - if (ev.deltaY === 0) { - // Do nothing if it's not a vertical scroll event - return; - } - // Fallback to WheelEvent.DOM_DELTA_PIXEL - var multiplier = 1; - if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { - multiplier = this.currentRowHeight; - } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { - multiplier = this.currentRowHeight * this.terminal.rows; - } - this.viewportElement.scrollTop += ev.deltaY * multiplier; - // Prevent the page from scrolling when the terminal scrolls - ev.preventDefault(); -}; - -export { Viewport }; From 51932161af672cb6c33a00ac786d7045147df889 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 21 Nov 2016 14:39:58 -0800 Subject: [PATCH 3/4] Move viewport-test.js to Viewport.test.ts --- src/{test/viewport-test.js => Viewport.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{test/viewport-test.js => Viewport.test.ts} (100%) diff --git a/src/test/viewport-test.js b/src/Viewport.test.ts similarity index 100% rename from src/test/viewport-test.js rename to src/Viewport.test.ts From 5bddb9374586b50ccf4325d0d361f6522cdc9a9e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 21 Nov 2016 14:44:10 -0800 Subject: [PATCH 4/4] Adopt more TS syntax in Viewport.test.ts --- src/Viewport.test.ts | 38 ++++++++++++++++---------------------- src/Viewport.ts | 1 - 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/Viewport.test.ts b/src/Viewport.test.ts index 376fcdc..5b106b4 100644 --- a/src/Viewport.test.ts +++ b/src/Viewport.test.ts @@ -1,21 +1,21 @@ -var assert = require('chai').assert; -var Terminal = require('../xterm'); +import { assert } from 'chai'; +import { Viewport } from './Viewport'; -describe('Viewport', function () { +describe('Viewport', () => { var terminal; var viewportElement; var charMeasureElement; var viewport; var scrollAreaElement; - var CHARACTER_HEIGHT = 10; + const CHARACTER_HEIGHT = 10; - beforeEach(function () { + beforeEach(() => { terminal = { lines: [], rows: 0, ydisp: 0, - on: function () {}, + on: () => {}, rowContainer: { style: { lineHeight: 0 @@ -23,7 +23,7 @@ describe('Viewport', function () { } }; viewportElement = { - addEventListener: function () {}, + addEventListener: () => {}, style: { height: 0, lineHeight: 0 @@ -35,37 +35,31 @@ describe('Viewport', function () { } }; charMeasureElement = { - getBoundingClientRect: function () { + getBoundingClientRect: () => { return { width: null, height: CHARACTER_HEIGHT }; } }; - viewport = new Terminal.Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement); + viewport = new Viewport(terminal, viewportElement, scrollAreaElement, charMeasureElement); }); - describe('Public API', function () { - it('should define Viewport.prototype.onWheel', function () { - assert.isDefined(Terminal.Viewport.prototype.onWheel); - }); - }); - - describe('refresh', function () { - it('should set the line-height of the terminal', function () { + describe('refresh', () => { + it('should set the line-height of the terminal', () => { assert.equal(viewportElement.style.lineHeight, CHARACTER_HEIGHT + 'px'); assert.equal(terminal.rowContainer.style.lineHeight, CHARACTER_HEIGHT + 'px'); - charMeasureElement.getBoundingClientRect = function () { + charMeasureElement.getBoundingClientRect = () => { return { width: null, height: 1 }; }; viewport.refresh(); assert.equal(viewportElement.style.lineHeight, '1px'); assert.equal(terminal.rowContainer.style.lineHeight, '1px'); }); - it('should set the height of the viewport when the line-height changed', function () { + it('should set the height of the viewport when the line-height changed', () => { terminal.lines.push(''); terminal.lines.push(''); terminal.rows = 1; viewport.refresh(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); - charMeasureElement.getBoundingClientRect = function () { + charMeasureElement.getBoundingClientRect = () => { return { width: null, height: 20 }; }; viewport.refresh(); @@ -73,8 +67,8 @@ describe('Viewport', function () { }); }); - describe('syncScrollArea', function () { - it('should sync the scroll area', function () { + describe('syncScrollArea', () => { + it('should sync the scroll area', () => { terminal.lines.push(''); terminal.rows = 1; assert.equal(scrollAreaElement.style.height, 0 * CHARACTER_HEIGHT + 'px'); diff --git a/src/Viewport.ts b/src/Viewport.ts index 573a050..11889da 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -13,7 +13,6 @@ import { ITerminal } from './Interfaces'; * @param charMeasureElement A DOM element used to measure the character size of. the terminal. */ export class Viewport { - private currentRowHeight: number; private lastRecordedBufferLength: number; private lastRecordedViewportHeight: number;