From 7ff03bb475406ae91411d1fc93e101b4f1b376cf Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 29 Aug 2016 16:17:59 -0700 Subject: [PATCH 1/3] Pull Viewport into a module Fixes #253 --- src/Viewport.js | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ src/xterm.js | 130 +--------------------------------------------- 2 files changed, 136 insertions(+), 129 deletions(-) create mode 100644 src/Viewport.js diff --git a/src/Viewport.js b/src/Viewport.js new file mode 100644 index 00000000..ce274f2f --- /dev/null +++ b/src/Viewport.js @@ -0,0 +1,135 @@ +/** + * xterm.js: xterm, in the browser + * Copyright (c) 2016, SourceLair Limited (www.sourcelair.com (MIT License) + */ + +/** + * 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. + */ +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; + + 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 {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.isApplicationMode) { + // Fix scroll bar in application mode + this.lastRecordedBufferLength = this.terminal.rows; + this.refresh(); + return; + } + + 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; + } +}; + +/** + * Sets the application mode of the viewport. + * @param {boolean} isApplicationMode Sets whether the terminal is in application mode. true + * for application mode (DECKPAM) and false for normal mode (DECKPNM). + */ +Viewport.prototype.setApplicationMode = function(isApplicationMode) { + this.isApplicationMode = isApplicationMode; + this.syncScrollArea(); +}; + +/** + * 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) { + if (this.isApplicationMode) { + // Scrolling via the scroll bar is disabled during application mode + return; + } + 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 }; diff --git a/src/xterm.js b/src/xterm.js index f4d26465..698d6cca 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -32,6 +32,7 @@ */ import { EventEmitter } from './EventEmitter.js'; +import { Viewport } from './Viewport.js'; /** * Terminal Emulation References: @@ -242,135 +243,6 @@ import { EventEmitter } from './EventEmitter.js'; this.textarea.style.top = ''; }; - /** - * 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. - */ - 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; - - 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 {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.isApplicationMode) { - // Fix scroll bar in application mode - this.lastRecordedBufferLength = this.terminal.rows; - this.refresh(); - return; - } - - 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; - } - }; - - /** - * Sets the application mode of the viewport. - * @param {boolean} isApplicationMode Sets whether the terminal is in application mode. true - * for application mode (DECKPAM) and false for normal mode (DECKPNM). - */ - Viewport.prototype.setApplicationMode = function(isApplicationMode) { - this.isApplicationMode = isApplicationMode; - this.syncScrollArea(); - }; - - /** - * 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) { - if (this.isApplicationMode) { - // Scrolling via the scroll bar is disabled during application mode - return; - } - 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(); - }; - /** * States */ From 4caac78241eca6b0e236557d93452255641a2427 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 29 Aug 2016 16:19:27 -0700 Subject: [PATCH 2/3] Improve copyright line --- src/Viewport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Viewport.js b/src/Viewport.js index ce274f2f..d23ba7c4 100644 --- a/src/Viewport.js +++ b/src/Viewport.js @@ -1,6 +1,6 @@ /** * xterm.js: xterm, in the browser - * Copyright (c) 2016, SourceLair Limited (www.sourcelair.com (MIT License) + * Copyright (c) 2016, SourceLair Limited (MIT License) */ /** From 749ed6372a38fb7db039d6a18d9741a9b307e469 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 29 Aug 2016 16:21:00 -0700 Subject: [PATCH 3/3] Improve copyright line --- src/xterm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xterm.js b/src/xterm.js index f4d26465..823431cf 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -1,6 +1,6 @@ /** * xterm.js: xterm, in the browser - * Copyright (c) 2014, sourceLair Limited (www.sourcelair.com (MIT License) + * Copyright (c) 2014, SourceLair Limited (MIT License) * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) * https://github.com/chjj/term.js *