2 * xterm.js: xterm, in the browser
3 * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License)
7 * Represents the viewport of a terminal, the visible area within the larger buffer of output.
8 * Logic for the virtual scroll bar is included in this object.
9 * @param {Terminal} terminal The Terminal object.
10 * @param {HTMLElement} viewportElement The DOM element acting as the viewport
11 * @param {HTMLElement} charMeasureElement A DOM element used to measure the character size of
14 function Viewport(terminal
, viewportElement
, scrollArea
, charMeasureElement
) {
15 this.terminal
= terminal
;
16 this.viewportElement
= viewportElement
;
17 this.scrollArea
= scrollArea
;
18 this.charMeasureElement
= charMeasureElement
;
19 this.currentRowHeight
= 0;
20 this.lastRecordedBufferLength
= 0;
21 this.lastRecordedViewportHeight
= 0;
23 this.terminal
.on('scroll', this.syncScrollArea
.bind(this));
24 this.terminal
.on('resize', this.syncScrollArea
.bind(this));
25 this.viewportElement
.addEventListener('scroll', this.onScroll
.bind(this));
27 this.syncScrollArea();
31 * Refreshes row height, setting line-height, viewport height and scroll area height if
33 * @param {number|undefined} charSize A character size measurement bounding rect object, if it
34 * doesn't exist it will be created.
36 Viewport
.prototype.refresh = function(charSize
) {
37 var size
= charSize
|| this.charMeasureElement
.getBoundingClientRect();
38 if (size
.height
> 0) {
39 var rowHeightChanged
= size
.height
!== this.currentRowHeight
;
40 if (rowHeightChanged
) {
41 this.currentRowHeight
= size
.height
;
42 this.viewportElement
.style
.lineHeight
= size
.height
+ 'px';
43 this.terminal
.rowContainer
.style
.lineHeight
= size
.height
+ 'px';
45 var viewportHeightChanged
= this.lastRecordedViewportHeight
!== this.terminal
.rows
;
46 if (rowHeightChanged
|| viewportHeightChanged
) {
47 this.lastRecordedViewportHeight
= this.terminal
.rows
;
48 this.viewportElement
.style
.height
= size
.height
* this.terminal
.rows
+ 'px';
50 this.scrollArea
.style
.height
= (size
.height
* this.lastRecordedBufferLength
) + 'px';
55 * Updates dimensions and synchronizes the scroll area if necessary.
57 Viewport
.prototype.syncScrollArea = function() {
58 if (this.lastRecordedBufferLength
!== this.terminal
.lines
.length
) {
59 // If buffer height changed
60 this.lastRecordedBufferLength
= this.terminal
.lines
.length
;
62 } else if (this.lastRecordedViewportHeight
!== this.terminal
.rows
) {
63 // If viewport height changed
66 // If size has changed, refresh viewport
67 var size
= this.charMeasureElement
.getBoundingClientRect();
68 if (size
.height
!== this.currentRowHeight
) {
74 var scrollTop
= this.terminal
.ydisp
* this.currentRowHeight
;
75 if (this.viewportElement
.scrollTop
!== scrollTop
) {
76 this.viewportElement
.scrollTop
= scrollTop
;
81 * Handles scroll events on the viewport, calculating the new viewport and requesting the
82 * terminal to scroll to it.
83 * @param {Event} ev The scroll event.
85 Viewport
.prototype.onScroll = function(ev
) {
86 var newRow
= Math
.round(this.viewportElement
.scrollTop
/ this.currentRowHeight
);
87 var diff
= newRow
- this.terminal
.ydisp
;
88 this.terminal
.scrollDisp(diff
, true);
92 * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual
93 * scrolling to `onScroll`, this event needs to be attached manually by the consumer of
95 * @param {WheelEvent} ev The mouse wheel event.
97 Viewport
.prototype.onWheel = function(ev
) {
98 if (ev
.deltaY
=== 0) {
99 // Do nothing if it's not a vertical scroll event
102 // Fallback to WheelEvent.DOM_DELTA_PIXEL
104 if (ev
.deltaMode
=== WheelEvent
.DOM_DELTA_LINE
) {
105 multiplier
= this.currentRowHeight
;
106 } else if (ev
.deltaMode
=== WheelEvent
.DOM_DELTA_PAGE
) {
107 multiplier
= this.currentRowHeight
* this.terminal
.rows
;
109 this.viewportElement
.scrollTop
+= ev
.deltaY
* multiplier
;
110 // Prevent the page from scrolling when the terminal scrolls