blob: 707e25cbb79fcbd1c13e8769e47a85d64560c646 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
const RENDER_DEBOUNCE_THRESHOLD_MS = 1000; // 1 Second
import { IRenderDebouncer } from 'browser/Types';
/**
* Debounces calls to update screen readers to update at most once configurable interval of time.
*/
export class TimeBasedDebouncer implements IRenderDebouncer {
private _rowStart: number | undefined;
private _rowEnd: number | undefined;
private _rowCount: number | undefined;
// The last moment that the Terminal was refreshed at
private _lastRefreshMs = 0;
// Whether a trailing refresh should be triggered due to a refresh request that was throttled
private _additionalRefreshRequested = false;
private _refreshTimeoutID: number | undefined;
constructor(
private _renderCallback: (start: number, end: number) => void,
private readonly _debounceThresholdMS = RENDER_DEBOUNCE_THRESHOLD_MS
) {
}
public dispose(): void {
if (this._refreshTimeoutID) {
clearTimeout(this._refreshTimeoutID);
}
}
public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void {
this._rowCount = rowCount;
// Get the min/max row start/end for the arg values
rowStart = rowStart !== undefined ? rowStart : 0;
rowEnd = rowEnd !== undefined ? rowEnd : this._rowCount - 1;
// Set the properties to the updated values
this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart;
this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd;
// Only refresh if the time since last refresh is above a threshold, otherwise wait for
// enough time to pass before refreshing again.
const refreshRequestTime: number = Date.now();
if (refreshRequestTime - this._lastRefreshMs >= this._debounceThresholdMS) {
// Enough time has lapsed since the last refresh; refresh immediately
this._lastRefreshMs = refreshRequestTime;
this._innerRefresh();
} else if (!this._additionalRefreshRequested) {
// This is the first additional request throttled; set up trailing refresh
const elapsed = refreshRequestTime - this._lastRefreshMs;
const waitPeriodBeforeTrailingRefresh = this._debounceThresholdMS - elapsed;
this._additionalRefreshRequested = true;
this._refreshTimeoutID = window.setTimeout(() => {
this._lastRefreshMs = Date.now();
this._innerRefresh();
this._additionalRefreshRequested = false;
this._refreshTimeoutID = undefined; // No longer need to clear the timeout
}, waitPeriodBeforeTrailingRefresh);
}
}
private _innerRefresh(): void {
// Make sure values are set
if (this._rowStart === undefined || this._rowEnd === undefined || this._rowCount === undefined) {
return;
}
// Clamp values
const start = Math.max(this._rowStart, 0);
const end = Math.min(this._rowEnd, this._rowCount - 1);
// Reset debouncer (this happens before render callback as the render could trigger it again)
this._rowStart = undefined;
this._rowEnd = undefined;
// Run render callback
this._renderCallback(start, end);
}
}
|