]>
Commit | Line | Data |
---|---|---|
7ff03bb4 DI |
1 | /** |
2 | * xterm.js: xterm, in the browser | |
a7acee72 | 3 | * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) |
7ff03bb4 DI |
4 | */ |
5 | ||
e0d98711 DI |
6 | import { ITerminal } from './Interfaces'; |
7 | ||
7ff03bb4 DI |
8 | /** |
9 | * Represents the viewport of a terminal, the visible area within the larger buffer of output. | |
10 | * Logic for the virtual scroll bar is included in this object. | |
e0d98711 DI |
11 | * @param viewportElement The DOM element acting as the viewport. |
12 | * @param scrollArea The DOM element acting as the scroll area. | |
13 | * @param charMeasureElement A DOM element used to measure the character size of. the terminal. | |
7ff03bb4 | 14 | */ |
e0d98711 | 15 | export class Viewport { |
e0d98711 DI |
16 | private currentRowHeight: number; |
17 | private lastRecordedBufferLength: number; | |
18 | private lastRecordedViewportHeight: number; | |
7ff03bb4 | 19 | |
e0d98711 DI |
20 | constructor( |
21 | private terminal: ITerminal, | |
22 | private viewportElement: HTMLElement, | |
23 | private scrollArea: HTMLElement, | |
24 | private charMeasureElement: HTMLElement | |
25 | ) { | |
26 | this.currentRowHeight = 0; | |
27 | this.lastRecordedBufferLength = 0; | |
28 | this.lastRecordedViewportHeight = 0; | |
7ff03bb4 | 29 | |
e0d98711 DI |
30 | this.terminal.on('scroll', this.syncScrollArea.bind(this)); |
31 | this.terminal.on('resize', this.syncScrollArea.bind(this)); | |
32 | this.viewportElement.addEventListener('scroll', this.onScroll.bind(this)); | |
7ff03bb4 | 33 | |
e0d98711 | 34 | this.syncScrollArea(); |
7ff03bb4 DI |
35 | } |
36 | ||
e0d98711 DI |
37 | /** |
38 | * Refreshes row height, setting line-height, viewport height and scroll area height if | |
39 | * necessary. | |
40 | * @param charSize A character size measurement bounding rect object, if it doesn't exist it will | |
41 | * be created. | |
42 | */ | |
43 | private refresh(charSize?: ClientRect): void { | |
44 | var size = charSize || this.charMeasureElement.getBoundingClientRect(); | |
45 | if (size.height > 0) { | |
46 | var rowHeightChanged = size.height !== this.currentRowHeight; | |
47 | if (rowHeightChanged) { | |
48 | this.currentRowHeight = size.height; | |
49 | this.viewportElement.style.lineHeight = size.height + 'px'; | |
50 | this.terminal.rowContainer.style.lineHeight = size.height + 'px'; | |
51 | } | |
52 | var viewportHeightChanged = this.lastRecordedViewportHeight !== this.terminal.rows; | |
53 | if (rowHeightChanged || viewportHeightChanged) { | |
54 | this.lastRecordedViewportHeight = this.terminal.rows; | |
55 | this.viewportElement.style.height = size.height * this.terminal.rows + 'px'; | |
56 | } | |
57 | this.scrollArea.style.height = (size.height * this.lastRecordedBufferLength) + 'px'; | |
58 | } | |
7ff03bb4 | 59 | } |
7ff03bb4 | 60 | |
e0d98711 DI |
61 | /** |
62 | * Updates dimensions and synchronizes the scroll area if necessary. | |
63 | */ | |
64 | public syncScrollArea(): void { | |
65 | if (this.lastRecordedBufferLength !== this.terminal.lines.length) { | |
66 | // If buffer height changed | |
67 | this.lastRecordedBufferLength = this.terminal.lines.length; | |
68 | this.refresh(); | |
69 | } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { | |
70 | // If viewport height changed | |
71 | this.refresh(); | |
72 | } else { | |
73 | // If size has changed, refresh viewport | |
74 | var size = this.charMeasureElement.getBoundingClientRect(); | |
75 | if (size.height !== this.currentRowHeight) { | |
76 | this.refresh(size); | |
77 | } | |
78 | } | |
7ff03bb4 | 79 | |
e0d98711 DI |
80 | // Sync scrollTop |
81 | var scrollTop = this.terminal.ydisp * this.currentRowHeight; | |
82 | if (this.viewportElement.scrollTop !== scrollTop) { | |
83 | this.viewportElement.scrollTop = scrollTop; | |
84 | } | |
7ff03bb4 | 85 | } |
e0d98711 DI |
86 | |
87 | /** | |
88 | * Handles scroll events on the viewport, calculating the new viewport and requesting the | |
89 | * terminal to scroll to it. | |
90 | * @param ev The scroll event. | |
91 | */ | |
92 | private onScroll(ev: Event) { | |
93 | var newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); | |
94 | var diff = newRow - this.terminal.ydisp; | |
95 | this.terminal.scrollDisp(diff, true); | |
7ff03bb4 | 96 | } |
7ff03bb4 | 97 | |
e0d98711 DI |
98 | /** |
99 | * Handles mouse wheel events by adjusting the viewport's scrollTop and delegating the actual | |
100 | * scrolling to `onScroll`, this event needs to be attached manually by the consumer of | |
101 | * `Viewport`. | |
102 | * @param ev The mouse wheel event. | |
103 | */ | |
104 | public onWheel(ev: WheelEvent) { | |
105 | if (ev.deltaY === 0) { | |
106 | // Do nothing if it's not a vertical scroll event | |
107 | return; | |
108 | } | |
109 | // Fallback to WheelEvent.DOM_DELTA_PIXEL | |
110 | var multiplier = 1; | |
111 | if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) { | |
112 | multiplier = this.currentRowHeight; | |
113 | } else if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) { | |
114 | multiplier = this.currentRowHeight * this.terminal.rows; | |
115 | } | |
116 | this.viewportElement.scrollTop += ev.deltaY * multiplier; | |
117 | // Prevent the page from scrolling when the terminal scrolls | |
118 | ev.preventDefault(); | |
119 | }; | |
120 | } |