mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Hook up scroll APIs to scroll and focus when navigating
This commit is contained in:
@@ -103,10 +103,20 @@ export class AccessibilityManager implements IDisposable {
|
||||
this._rowElements = null;
|
||||
}
|
||||
|
||||
public get isNavigatingRows(): boolean {
|
||||
return this._rowElements.indexOf(<HTMLElement>document.activeElement) >= 0;
|
||||
}
|
||||
|
||||
private _onBoundaryFocus(e: FocusEvent, position: BoundaryPosition): void {
|
||||
const boundaryElement = <HTMLElement>e.target;
|
||||
const beforeBoundaryElement = this._rowElements[position === BoundaryPosition.Top ? 1 : this._rowElements.length - 2];
|
||||
|
||||
// Don't scroll when the last focused item was not the second row (focus is going the other
|
||||
// direction)
|
||||
if (e.relatedTarget !== beforeBoundaryElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't scroll if the buffer top has reached the end in that direction
|
||||
const posInSet = boundaryElement.getAttribute('aria-posinset');
|
||||
const lastRowPos = position === BoundaryPosition.Top ? '1' : `${this._terminal.buffer.lines.length}`;
|
||||
@@ -114,12 +124,6 @@ export class AccessibilityManager implements IDisposable {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't scroll when the last focused item was not the second row (focus is going the other
|
||||
// direction)
|
||||
if (e.relatedTarget !== beforeBoundaryElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove old boundary element from array
|
||||
let topBoundaryElement: HTMLElement;
|
||||
let bottomBoundaryElement: HTMLElement;
|
||||
@@ -163,6 +167,64 @@ export class AccessibilityManager implements IDisposable {
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the focus of the terminal relatively by a number of rows.
|
||||
* @param amount The amount of rows to scroll
|
||||
*/
|
||||
public moveRowFocus(amount: number): void {
|
||||
console.log('moveRowFocus', amount);
|
||||
// Do nothing if not navigating rows or the amount to navigate is 0
|
||||
if (!this.isNavigatingRows || amount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find and validate the new absolute row position
|
||||
const buffer = this._terminal.buffer;
|
||||
const oldRelativeRow = this._rowElements.indexOf(<HTMLElement>document.activeElement);
|
||||
const oldAbsoluteRow = buffer.ydisp + oldRelativeRow;
|
||||
const newAbsoluteRow = Math.max(Math.min(oldAbsoluteRow + amount, buffer.lines.length - 1), 0);
|
||||
if (oldAbsoluteRow === newAbsoluteRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the new relative row, this cannot be on a boundary element unless the focused row is the
|
||||
// top-most or bottom-most row in the buffer.
|
||||
let newRelativeRow: number;
|
||||
if (newAbsoluteRow === 0) {
|
||||
newRelativeRow = 0;
|
||||
} else if (newAbsoluteRow === buffer.lines.length - 1) {
|
||||
newRelativeRow = this._terminal.rows - 1;
|
||||
} else {
|
||||
newRelativeRow = Math.max(Math.min(oldRelativeRow + amount, this._terminal.rows - 2), 1);
|
||||
}
|
||||
|
||||
// Find the new viewport position
|
||||
let newYDisp: number;
|
||||
if (newAbsoluteRow === 0) {
|
||||
// Start of buffer
|
||||
newYDisp = 0;
|
||||
} else if (newAbsoluteRow === buffer.lines.length - 1) {
|
||||
// End of buffer
|
||||
newYDisp = buffer.lines.length - 1 - this._terminal.rows;
|
||||
} else if (newAbsoluteRow > buffer.ydisp && newAbsoluteRow < buffer.ydisp + this._terminal.rows - 1) {
|
||||
// No scrolling necessary
|
||||
newYDisp = buffer.ydisp;
|
||||
} else if (newAbsoluteRow < oldAbsoluteRow) {
|
||||
// Scrolling up needed
|
||||
newYDisp = newAbsoluteRow - 1;
|
||||
} else { // if (newAbsoluteRow > oldAbsoluteRow)
|
||||
// Scrolling down needed
|
||||
newYDisp = newAbsoluteRow + this._terminal.rows - 2;
|
||||
}
|
||||
|
||||
// Perform scroll
|
||||
const scrollAmount = newYDisp - buffer.ydisp;
|
||||
this._terminal.scrollLines(scrollAmount);
|
||||
|
||||
// Focus new row
|
||||
this._rowElements[newRelativeRow].focus();
|
||||
}
|
||||
|
||||
private _onResize(cols: number, rows: number): void {
|
||||
// Remove bottom boundary listener
|
||||
this._rowElements[this._rowElements.length - 1].removeEventListener('focus', this._bottomBoundaryFocusListener);
|
||||
|
||||
+17
-3
@@ -1187,26 +1187,40 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
||||
this.refresh(0, this.rows - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the viewport by a number of rows when not navigating rows. When
|
||||
* navigating rows, move focus relatively by a number of rows.
|
||||
* @param amount The number of lines to scroll.
|
||||
*/
|
||||
private _accessibilityAwareScrollLines(amount: number): void {
|
||||
console.log('_accessibilityAwareScrollLines');
|
||||
if (this.options.screenReaderMode && this._accessibilityManager.isNavigatingRows) {
|
||||
this._accessibilityManager.moveRowFocus(amount);
|
||||
} else {
|
||||
this.scrollLines(amount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll the display of the terminal by a number of pages.
|
||||
* @param {number} pageCount The number of pages to scroll (negative scrolls up).
|
||||
*/
|
||||
public scrollPages(pageCount: number): void {
|
||||
this.scrollLines(pageCount * (this.rows - 1));
|
||||
this._accessibilityAwareScrollLines(pageCount * (this.rows - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the display of the terminal to the top.
|
||||
*/
|
||||
public scrollToTop(): void {
|
||||
this.scrollLines(-this.buffer.ydisp);
|
||||
this._accessibilityAwareScrollLines(-this.buffer.ydisp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the display of the terminal to the bottom.
|
||||
*/
|
||||
public scrollToBottom(): void {
|
||||
this.scrollLines(this.buffer.ybase - this.buffer.ydisp);
|
||||
this._accessibilityAwareScrollLines(this.buffer.ybase - this.buffer.ydisp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user