maidr 2.12.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/maidr.js +590 -68
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/dist/maidr.js
CHANGED
|
@@ -1,81 +1,421 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A class representing system vars, user config vars, and helper functions used throughout the application.
|
|
3
|
-
*
|
|
4
3
|
* @class
|
|
5
4
|
*/
|
|
6
5
|
class Constants {
|
|
6
|
+
/**
|
|
7
|
+
* @namespace HtmlIds
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* HTML id of the div containing the chart.
|
|
11
|
+
* @type {string}
|
|
12
|
+
* @memberof HtmlIds
|
|
13
|
+
* @default 'chart-container'
|
|
14
|
+
*/
|
|
7
15
|
chart_container_id = 'chart-container';
|
|
16
|
+
/**
|
|
17
|
+
* HTML id of the main container div.
|
|
18
|
+
* @type {string}
|
|
19
|
+
* @memberof HtmlIds
|
|
20
|
+
* @default 'maidr-container'
|
|
21
|
+
*/
|
|
8
22
|
main_container_id = 'maidr-container';
|
|
9
|
-
|
|
23
|
+
/**
|
|
24
|
+
* HTML id of the div containing the braille display input
|
|
25
|
+
* @type {string}
|
|
26
|
+
* @memberof HtmlIds
|
|
27
|
+
* @default 'braille-div'
|
|
28
|
+
*/
|
|
10
29
|
braille_container_id = 'braille-div';
|
|
30
|
+
/**
|
|
31
|
+
* HTML id of the actual braille input element.
|
|
32
|
+
* @type {string}
|
|
33
|
+
* @memberof HtmlIds
|
|
34
|
+
* @default 'braille-input'
|
|
35
|
+
*/
|
|
11
36
|
braille_input_id = 'braille-input';
|
|
37
|
+
/**
|
|
38
|
+
* HTML id of the div containing the info box.
|
|
39
|
+
* @type {string}
|
|
40
|
+
* @memberof HtmlIds
|
|
41
|
+
* @default 'info'
|
|
42
|
+
*/
|
|
12
43
|
info_id = 'info';
|
|
44
|
+
/**
|
|
45
|
+
* HTML id of the div containing announcements that hook directly into the screen reader via aria-live.
|
|
46
|
+
* @type {string}
|
|
47
|
+
* @memberof HtmlIds
|
|
48
|
+
* @default 'announcements'
|
|
49
|
+
*/
|
|
13
50
|
announcement_container_id = 'announcements';
|
|
51
|
+
/**
|
|
52
|
+
* HTML id of the div containing the end chime. To be implemented in the future.
|
|
53
|
+
* @type {string}
|
|
54
|
+
* @memberof HtmlIds
|
|
55
|
+
* @default 'end_chime'
|
|
56
|
+
*/
|
|
14
57
|
end_chime_id = 'end_chime';
|
|
58
|
+
/**
|
|
59
|
+
* HTML id of the main container div.
|
|
60
|
+
* @type {string}
|
|
61
|
+
* @memberof HtmlIds
|
|
62
|
+
* @default 'container'
|
|
63
|
+
*/
|
|
15
64
|
container_id = 'container';
|
|
65
|
+
/**
|
|
66
|
+
* The main project id, used throughout the application.
|
|
67
|
+
* @type {string}
|
|
68
|
+
* @memberof HtmlIds
|
|
69
|
+
* @default 'maidr'
|
|
70
|
+
*/
|
|
16
71
|
project_id = 'maidr';
|
|
72
|
+
/**
|
|
73
|
+
* HTML id of the div containing the review text.
|
|
74
|
+
* @type {string}
|
|
75
|
+
* @memberof HtmlIds
|
|
76
|
+
* @default 'review_container'
|
|
77
|
+
*/
|
|
17
78
|
review_id_container = 'review_container';
|
|
79
|
+
/**
|
|
80
|
+
* HTML id of the review input element.
|
|
81
|
+
* @type {string}
|
|
82
|
+
* @memberof HtmlIds
|
|
83
|
+
* @default 'review'
|
|
84
|
+
*/
|
|
18
85
|
review_id = 'review';
|
|
86
|
+
/**
|
|
87
|
+
* Storage element, used to store the last focused element before moving to the review input so we can switch back to it easily.
|
|
88
|
+
* @type {HTMLElement}
|
|
89
|
+
* @default null
|
|
90
|
+
*/
|
|
19
91
|
reviewSaveSpot;
|
|
92
|
+
/**
|
|
93
|
+
* Storage setting for the braille mode when we enter review mode
|
|
94
|
+
* @type {("on"|"off")}
|
|
95
|
+
*/
|
|
20
96
|
reviewSaveBrailleMode;
|
|
97
|
+
/**
|
|
98
|
+
* HTML id of the actual chart element. Used to connect the application to the chart.
|
|
99
|
+
* @type {string}
|
|
100
|
+
* @memberof HtmlIds
|
|
101
|
+
*/
|
|
21
102
|
chartId = '';
|
|
103
|
+
/**
|
|
104
|
+
* @typedef {Object} EventListenerSetupObject
|
|
105
|
+
* @property {HTMLElement} element - The element to attach the event listener to.
|
|
106
|
+
* @property {string} event - The event type to listen for.
|
|
107
|
+
* @property {function(Event)} func - The function to run when the event is triggered.
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* An array of event listeners to be added to the document. This is used so that we can properly create and destroy events when needed and not cause massive memory leaks when the system is run repeatedly.
|
|
111
|
+
* @type {Array<EventListenerSetupObject>}
|
|
112
|
+
* @default []
|
|
113
|
+
*/
|
|
22
114
|
events = [];
|
|
115
|
+
/**
|
|
116
|
+
* An array of functions to run after the page has loaded. This is used to ensure that the page is fully loaded before running any functions that may rely on that.
|
|
117
|
+
*/
|
|
23
118
|
postLoadEvents = [];
|
|
24
119
|
|
|
25
120
|
constructor() {}
|
|
26
121
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
122
|
+
/**
|
|
123
|
+
* @namespace BTSModes
|
|
124
|
+
*/
|
|
125
|
+
/**
|
|
126
|
+
* The current text mode. Can be 'off', 'terse', or 'verbose'.
|
|
127
|
+
* @type {("off"|"terse"|"verbose")}
|
|
128
|
+
* @memberof BTSModes
|
|
129
|
+
* @default 'verbose'
|
|
130
|
+
*/
|
|
131
|
+
textMode = 'verbose';
|
|
132
|
+
/**
|
|
133
|
+
* The current braille mode. Can be 'off' or 'on'.
|
|
134
|
+
* @type {("off"|"on")}
|
|
135
|
+
* @memberof BTSModes
|
|
136
|
+
* @default 'off'
|
|
137
|
+
*/
|
|
138
|
+
brailleMode = 'off';
|
|
139
|
+
/**
|
|
140
|
+
* The current sonification mode. Can be 'on', 'off', 'sep' (seperated), or 'same' (all played at once).
|
|
141
|
+
* @type {("on"|"off"|"sep"|"same")}
|
|
142
|
+
* @memberof BTSModes
|
|
143
|
+
* @default 'on'
|
|
144
|
+
*/
|
|
145
|
+
sonifMode = 'on';
|
|
146
|
+
/**
|
|
147
|
+
* The current review mode. Can be 'on' or 'off'.
|
|
148
|
+
* @type {("on"|"off")}
|
|
149
|
+
* @memberof BTSModes
|
|
150
|
+
* @default 'off'
|
|
151
|
+
*/
|
|
152
|
+
reviewMode = 'off';
|
|
32
153
|
|
|
33
154
|
// basic chart properties
|
|
155
|
+
/**
|
|
156
|
+
* @namespace BasicChartProperties
|
|
157
|
+
*/
|
|
158
|
+
/**
|
|
159
|
+
* The minimum x value of the chart, set during MAIDR initialization.
|
|
160
|
+
* @type {number}
|
|
161
|
+
* @memberof BasicChartProperties
|
|
162
|
+
* @default 0
|
|
163
|
+
*/
|
|
34
164
|
minX = 0;
|
|
165
|
+
/**
|
|
166
|
+
* The maximum x value of the chart, set during MAIDR initialization.
|
|
167
|
+
* @type {number}
|
|
168
|
+
* @memberof BasicChartProperties
|
|
169
|
+
* @default 0
|
|
170
|
+
*/
|
|
35
171
|
maxX = 0;
|
|
172
|
+
/**
|
|
173
|
+
* The minimum y value of the chart, set during MAIDR initialization.
|
|
174
|
+
* @type {number}
|
|
175
|
+
* @memberof BasicChartProperties
|
|
176
|
+
* @default 0
|
|
177
|
+
*/
|
|
36
178
|
minY = 0;
|
|
179
|
+
/**
|
|
180
|
+
* The maximum y value of the chart, set during MAIDR initialization.
|
|
181
|
+
* @type {number}
|
|
182
|
+
* @memberof BasicChartProperties
|
|
183
|
+
* @default 0
|
|
184
|
+
*/
|
|
37
185
|
maxY = 0;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The plotID of the chart, used interchangably with chartId.
|
|
189
|
+
* @type {string}
|
|
190
|
+
* @memberof HtmlIds
|
|
191
|
+
* @default ''
|
|
192
|
+
*/
|
|
38
193
|
plotId = ''; // update with id in chart specific js
|
|
39
|
-
|
|
194
|
+
/**
|
|
195
|
+
* The chart type, sort of a short name of the chart such as 'box', 'bar', 'line', etc.
|
|
196
|
+
* @type {string}
|
|
197
|
+
* @default ''
|
|
198
|
+
* @memberof BasicChartProperties
|
|
199
|
+
*/
|
|
200
|
+
chartType = '';
|
|
201
|
+
/**
|
|
202
|
+
* The navigation orientation of the chart. 0 = row navigation (up/down), 1 = col navigation (left/right).
|
|
203
|
+
* @type {number}
|
|
204
|
+
* @default 1
|
|
205
|
+
* @memberof BasicChartProperties
|
|
206
|
+
*/
|
|
40
207
|
navigation = 1; // 0 = row navigation (up/down), 1 = col navigation (left/right)
|
|
41
208
|
|
|
209
|
+
/**
|
|
210
|
+
* @namespace AudioProperties
|
|
211
|
+
*/
|
|
42
212
|
// basic audio properties
|
|
213
|
+
/**
|
|
214
|
+
* The max frequency (Hz) of the audio tones to be played when sonifying the chart.
|
|
215
|
+
* @type {number}
|
|
216
|
+
* @default 1000
|
|
217
|
+
* @memberof AudioProperties
|
|
218
|
+
*/
|
|
43
219
|
MAX_FREQUENCY = 1000;
|
|
220
|
+
/**
|
|
221
|
+
* The min frequency (Hz) of the audio tones to be played when sonifying the chart.
|
|
222
|
+
* @type {number}
|
|
223
|
+
* @default 200
|
|
224
|
+
* @memberof AudioProperties
|
|
225
|
+
*/
|
|
44
226
|
MIN_FREQUENCY = 200;
|
|
227
|
+
/**
|
|
228
|
+
* Frequncy (Hz) to play when there is no data in a cell, plays twice quickly, recommend a low tone here.
|
|
229
|
+
* @type {number}
|
|
230
|
+
* @default 100
|
|
231
|
+
* @memberof AudioProperties
|
|
232
|
+
*/
|
|
45
233
|
NULL_FREQUENCY = 100;
|
|
46
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Minimum volume of the audio tones to be played when sonifying the chart. Expected range is 0 to 2.
|
|
236
|
+
* @type {number}
|
|
237
|
+
* @default 0.25
|
|
238
|
+
* @memberof AudioProperties
|
|
239
|
+
*/
|
|
240
|
+
combinedVolMin = 0.25;
|
|
241
|
+
/**
|
|
242
|
+
* Maximum volume of the audio tones to be played when sonifying the chart. Expected range is 0 to 2.
|
|
243
|
+
* @type {number}
|
|
244
|
+
* @default 1.25
|
|
245
|
+
* @memberof AudioProperties
|
|
246
|
+
*/
|
|
47
247
|
combinedVolMax = 1.25; // volume for max amplitude combined tones
|
|
48
248
|
|
|
49
249
|
// autoplay speed
|
|
250
|
+
/**
|
|
251
|
+
* The maximum speed of the autoplay feature, in milliseconds per tone.
|
|
252
|
+
* @type {number}
|
|
253
|
+
* @default 500
|
|
254
|
+
* @memberof AudioProperties
|
|
255
|
+
*/
|
|
50
256
|
MAX_SPEED = 500;
|
|
257
|
+
/**
|
|
258
|
+
* The minimum speed of the autoplay feature, in milliseconds per tone.
|
|
259
|
+
* @type {number}
|
|
260
|
+
* @default 50
|
|
261
|
+
* @memberof AudioProperties
|
|
262
|
+
*/
|
|
51
263
|
MIN_SPEED = 50; // 50;
|
|
264
|
+
/**
|
|
265
|
+
* The default speed of the autoplay feature, in milliseconds per tone.
|
|
266
|
+
* @type {number}
|
|
267
|
+
* @default 250
|
|
268
|
+
* @memberof AudioProperties
|
|
269
|
+
*/
|
|
52
270
|
DEFAULT_SPEED = 250;
|
|
271
|
+
/**
|
|
272
|
+
* The interval between tones in the autoplay feature, in milliseconds.
|
|
273
|
+
* @type {number}
|
|
274
|
+
* @default 20
|
|
275
|
+
* @memberof AudioProperties
|
|
276
|
+
*/
|
|
53
277
|
INTERVAL = 20;
|
|
278
|
+
/**
|
|
279
|
+
* The duration of the autoplay feature, in milliseconds.
|
|
280
|
+
* @type {number}
|
|
281
|
+
* @default 5000
|
|
282
|
+
* @memberof AudioProperties
|
|
283
|
+
*/
|
|
54
284
|
AUTOPLAY_DURATION = 5000; // 5s
|
|
55
285
|
|
|
56
286
|
// user settings
|
|
287
|
+
/**
|
|
288
|
+
* @namespace UserSettings
|
|
289
|
+
*/
|
|
290
|
+
/**
|
|
291
|
+
* The volume of the audio tones to be played when sonifying the chart. Expected range is 0 to 1.
|
|
292
|
+
* @type {number}
|
|
293
|
+
* @default 0.5
|
|
294
|
+
* @memberof UserSettings
|
|
295
|
+
*/
|
|
57
296
|
vol = 0.5;
|
|
297
|
+
/**
|
|
298
|
+
* Max volume, used only to differentiate points in a scatterplot.
|
|
299
|
+
* @type {number}
|
|
300
|
+
* @default 30
|
|
301
|
+
* @memberof UserSettings
|
|
302
|
+
*/
|
|
58
303
|
MAX_VOL = 30;
|
|
59
|
-
|
|
60
|
-
|
|
304
|
+
/**
|
|
305
|
+
* The speed of the autoplay feature, in milliseconds per tone.
|
|
306
|
+
* @type {number}
|
|
307
|
+
* @default 250
|
|
308
|
+
* @memberof UserSettings
|
|
309
|
+
*/
|
|
310
|
+
autoPlayRate = this.DEFAULT_SPEED;
|
|
311
|
+
/**
|
|
312
|
+
* The color of the selected element in the chart in hex format.
|
|
313
|
+
* @type {string}
|
|
314
|
+
* @default '#03C809' (green)
|
|
315
|
+
* @memberof UserSettings
|
|
316
|
+
*/
|
|
61
317
|
colorSelected = '#03C809';
|
|
62
|
-
|
|
318
|
+
/**
|
|
319
|
+
* The length of the braille display in characters. Braille displays have a variety of sizes; 40 is pretty common, 32 is quite reliable. Set this to your actual display length so that the system can scale and display braille properly for you (where possible).
|
|
320
|
+
* @type {number}
|
|
321
|
+
* @default 32
|
|
322
|
+
* @memberof UserSettings
|
|
323
|
+
*/
|
|
324
|
+
brailleDisplayLength = 32;
|
|
63
325
|
|
|
64
326
|
// advanced user settings
|
|
65
|
-
|
|
327
|
+
/**
|
|
328
|
+
* @namespace AdvancedUserSettings
|
|
329
|
+
*/
|
|
330
|
+
/**
|
|
331
|
+
* Whether or not to show the outline of the selected element in the chart.
|
|
332
|
+
* @type {boolean}
|
|
333
|
+
* @default true
|
|
334
|
+
* @memberof AdvancedUserSettings
|
|
335
|
+
*/
|
|
336
|
+
showRect = 1;
|
|
337
|
+
/**
|
|
338
|
+
* Whether or not the chart even has a rectangle to show.
|
|
339
|
+
* @type {boolean}
|
|
340
|
+
* @default true
|
|
341
|
+
* @memberof AdvancedUserSettings
|
|
342
|
+
*/
|
|
66
343
|
hasRect = 1; // true / false
|
|
67
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Whether or not the chart has smooth line points.
|
|
346
|
+
* @type {boolean}
|
|
347
|
+
* @default true
|
|
348
|
+
* @memberof AdvancedUserSettings
|
|
349
|
+
*/
|
|
350
|
+
hasSmooth = 1;
|
|
351
|
+
/**
|
|
352
|
+
* Standard tone duration in seconds.
|
|
353
|
+
* @type {number}
|
|
354
|
+
* @default 0.3
|
|
355
|
+
* @memberof AdvancedUserSettings
|
|
356
|
+
*/
|
|
68
357
|
duration = 0.3;
|
|
358
|
+
/**
|
|
359
|
+
* Outlier tone duration in seconds.
|
|
360
|
+
* @type {number}
|
|
361
|
+
* @default 0.06
|
|
362
|
+
* @memberof AdvancedUserSettings
|
|
363
|
+
*/
|
|
69
364
|
outlierDuration = 0.06;
|
|
70
|
-
|
|
71
|
-
|
|
365
|
+
/**
|
|
366
|
+
* The rate at which to play outlier tones in the autoplay feature, in milliseconds per tone.
|
|
367
|
+
* @type {number}
|
|
368
|
+
* @default 50
|
|
369
|
+
* @memberof AdvancedUserSettings
|
|
370
|
+
*/
|
|
371
|
+
autoPlayOutlierRate = 50;
|
|
372
|
+
/**
|
|
373
|
+
* The rate at which to play points in the autoplay feature, in milliseconds per tone.
|
|
374
|
+
* @type {number}
|
|
375
|
+
* @default 50
|
|
376
|
+
* @memberof AdvancedUserSettings
|
|
377
|
+
*/
|
|
378
|
+
autoPlayPointsRate = 50;
|
|
379
|
+
/**
|
|
380
|
+
* The rate at which to play lines in the autoplay feature, in milliseconds per tone. Deprecated.
|
|
381
|
+
* @type {number}
|
|
382
|
+
* @default 50
|
|
383
|
+
* @memberof AdvancedUserSettings
|
|
384
|
+
*/
|
|
72
385
|
colorUnselected = '#595959'; // deprecated, todo: find all instances replace with storing old color method
|
|
73
|
-
|
|
74
|
-
|
|
386
|
+
/**
|
|
387
|
+
* Whether or not we're logging user data. This is off by default, but is used for research purposes.
|
|
388
|
+
* @type {boolean}
|
|
389
|
+
* @default 0
|
|
390
|
+
* @memberof AdvancedUserSettings
|
|
391
|
+
*/
|
|
392
|
+
canTrack = 0; // 0 / 1, can we track user data
|
|
393
|
+
/**
|
|
394
|
+
* Whether or not we're currently tracking user data.
|
|
395
|
+
* @type {boolean}
|
|
396
|
+
* @default 1
|
|
397
|
+
* @memberof AdvancedUserSettings
|
|
398
|
+
*/
|
|
399
|
+
isTracking = 1;
|
|
400
|
+
/**
|
|
401
|
+
* How are we representing braille? like, is it 1:1 with the chart, or do we do some compression and try to represent as accuratly as we can? Not currently in use.
|
|
402
|
+
* @type {boolean}
|
|
403
|
+
* @default false
|
|
404
|
+
* @memberof AdvancedUserSettings
|
|
405
|
+
*/
|
|
75
406
|
visualBraille = false; // do we want to represent braille based on what's visually there or actually there. Like if we have 2 outliers with the same position, do we show 1 (visualBraille true) or 2 (false)
|
|
76
|
-
|
|
77
|
-
|
|
407
|
+
/**
|
|
408
|
+
* The aria mode used throughout the application. Can be 'assertive' or 'polite'.
|
|
409
|
+
* @type {("assertive"|"polite")}
|
|
410
|
+
* @default 'assertive'
|
|
411
|
+
* @memberof AdvancedUserSettings
|
|
412
|
+
*/
|
|
413
|
+
ariaMode = 'assertive';
|
|
78
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Full list of user settings, used internally to save and load settings.
|
|
417
|
+
* @type {string[]}
|
|
418
|
+
*/
|
|
79
419
|
userSettingsKeys = [
|
|
80
420
|
'vol',
|
|
81
421
|
'autoPlayRate',
|
|
@@ -97,49 +437,206 @@ class Constants {
|
|
|
97
437
|
];
|
|
98
438
|
|
|
99
439
|
// LLM settings
|
|
100
|
-
|
|
101
|
-
|
|
440
|
+
/**
|
|
441
|
+
* @namespace LLMSettings
|
|
442
|
+
*/
|
|
443
|
+
/**
|
|
444
|
+
* The OpenAI authentication key, set in the menu.
|
|
445
|
+
* @type {string}
|
|
446
|
+
* @default null
|
|
447
|
+
* @memberof LLMSettings
|
|
448
|
+
*/
|
|
449
|
+
openAIAuthKey = null;
|
|
450
|
+
/**
|
|
451
|
+
* The Gemini authentication key, set in the menu.
|
|
452
|
+
* @type {string}
|
|
453
|
+
* @default null
|
|
454
|
+
* @memberof LLMSettings
|
|
455
|
+
*/
|
|
456
|
+
geminiAuthKey = null;
|
|
457
|
+
/**
|
|
458
|
+
* The maximum number of tokens to send to the LLM, only used if the specific LLM has that feature.
|
|
459
|
+
* @type {number}
|
|
460
|
+
* @default 1000
|
|
461
|
+
* @memberof LLMSettings
|
|
462
|
+
*/
|
|
102
463
|
LLMmaxResponseTokens = 1000; // max tokens to send to LLM, 20 for testing, 1000 ish for real
|
|
464
|
+
/**
|
|
465
|
+
* Whether or not to play the LLM waiting sound. It's a 1/sec beep.
|
|
466
|
+
* @type {boolean}
|
|
467
|
+
* @default true
|
|
468
|
+
* @memberof LLMSettings
|
|
469
|
+
*/
|
|
103
470
|
playLLMWaitingSound = true;
|
|
471
|
+
/**
|
|
472
|
+
* The detail level of the LLM. Can be 'low' or 'high'. Only used if the specific LLM has that feature.
|
|
473
|
+
* @type {"low"|"high"}
|
|
474
|
+
* @default 'high'
|
|
475
|
+
* @memberof LLMSettings
|
|
476
|
+
*/
|
|
104
477
|
LLMDetail = 'high'; // low (default for testing, like 100 tokens) / high (default for real, like 1000 tokens)
|
|
105
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'multi'. More to be added.
|
|
480
|
+
* @type {("openai"|"gemini"|"multi")}
|
|
481
|
+
* @default 'openai'
|
|
482
|
+
* @memberof LLMSettings
|
|
483
|
+
*/
|
|
484
|
+
LLMModel = 'openai';
|
|
485
|
+
/**
|
|
486
|
+
* The default system message for the LLM. Helps the LLM understand the context of the chart and its role.
|
|
487
|
+
* @type {string}
|
|
488
|
+
* @default 'You are a helpful assistant describing the chart to a blind person. '
|
|
489
|
+
* @memberof LLMSettings
|
|
490
|
+
*/
|
|
106
491
|
LLMSystemMessage =
|
|
107
492
|
'You are a helpful assistant describing the chart to a blind person. ';
|
|
493
|
+
/**
|
|
494
|
+
* The level of skill the user has with statistical charts. Can be 'basic', 'intermediate', 'expert', or 'other'. This is passed to the LLM on the initial message to help it speak correctly to the user. If 'other' is selected, the user can provide a custom skill level.
|
|
495
|
+
* @type {("basic"|"intermediate"|"expert"|"other")}
|
|
496
|
+
* @default 'basic'
|
|
497
|
+
* @memberof LLMSettings
|
|
498
|
+
*/
|
|
108
499
|
skillLevel = 'basic'; // basic / intermediate / expert
|
|
500
|
+
/**
|
|
501
|
+
* Custom skill level, used if the user selects 'other' as their skill level.
|
|
502
|
+
* @type {string}
|
|
503
|
+
* @default ''
|
|
504
|
+
* @memberof LLMSettings
|
|
505
|
+
*/
|
|
109
506
|
skillLevelOther = ''; // custom skill level
|
|
507
|
+
/**
|
|
508
|
+
* The LLM can send the first default message containing the chart image on initialization, so when the user opens the chat window the LLM already has an initial response and is ready for a conversation.
|
|
509
|
+
* @type {boolean}
|
|
510
|
+
* @default true
|
|
511
|
+
* @memberof LLMSettings
|
|
512
|
+
*/
|
|
110
513
|
autoInitLLM = true; // auto initialize LLM on page load
|
|
514
|
+
/**
|
|
515
|
+
* An internal variable used to store the current full verbose text, helps gives the LLM context on what's going on in the chart.
|
|
516
|
+
* @type {string}
|
|
517
|
+
* @default ''
|
|
518
|
+
* @memberof LLMSettings
|
|
519
|
+
*/
|
|
111
520
|
verboseText = '';
|
|
521
|
+
/**
|
|
522
|
+
* An internal variable used to turn the waiting beep on and off.
|
|
523
|
+
* @type {number}
|
|
524
|
+
* @default 0
|
|
525
|
+
* @memberof LLMSettings
|
|
526
|
+
*/
|
|
112
527
|
waitingQueue = 0;
|
|
113
528
|
|
|
114
529
|
// user controls (not exposed to menu, with shortcuts usually)
|
|
530
|
+
/**
|
|
531
|
+
* Whether or not to show the main display.
|
|
532
|
+
* @type {boolean}
|
|
533
|
+
* @default true
|
|
534
|
+
* @memberof AdvancedUserSettings
|
|
535
|
+
*/
|
|
115
536
|
showDisplay = 1; // true / false
|
|
537
|
+
/**
|
|
538
|
+
* Whether or not to show the display in braille.
|
|
539
|
+
* @type {boolean}
|
|
540
|
+
* @default true
|
|
541
|
+
* @memberof AdvancedUserSettings
|
|
542
|
+
*/
|
|
116
543
|
showDisplayInBraille = 1; // true / false
|
|
544
|
+
/**
|
|
545
|
+
* Whether or not to show the display in autoplay.
|
|
546
|
+
* @type {boolean}
|
|
547
|
+
* @default false
|
|
548
|
+
* @memberof AdvancedUserSettings
|
|
549
|
+
*/
|
|
117
550
|
showDisplayInAutoplay = 0; // true / false
|
|
551
|
+
/**
|
|
552
|
+
* The interval for the outlier. This might not be used anymore.
|
|
553
|
+
* @type {number}
|
|
554
|
+
* @default null
|
|
555
|
+
* @memberof AdvancedUserSettings
|
|
556
|
+
*/
|
|
118
557
|
outlierInterval = null;
|
|
119
558
|
|
|
120
559
|
// platform controls
|
|
560
|
+
/**
|
|
561
|
+
* @namespace PlatformControls
|
|
562
|
+
*/
|
|
563
|
+
/**
|
|
564
|
+
* Whether or not the user is on a Mac. Set automatically.
|
|
565
|
+
* @type {boolean}
|
|
566
|
+
* @memberof PlatformControls
|
|
567
|
+
*/
|
|
121
568
|
isMac = navigator.userAgent.toLowerCase().includes('mac'); // true if macOS
|
|
569
|
+
/**
|
|
570
|
+
* The control key for the user's platform. Can be 'Cmd' or 'Ctrl'. Used in keyboard shortcut display in help.
|
|
571
|
+
* @type {"Cmd"|"Ctrl"}
|
|
572
|
+
* @memberof PlatformControls
|
|
573
|
+
*/
|
|
122
574
|
control = this.isMac ? 'Cmd' : 'Ctrl';
|
|
575
|
+
/**
|
|
576
|
+
* The alt key for the user's platform. Can be 'option' or 'Alt'. Used in keyboard shortcut display in help.
|
|
577
|
+
* @type {"option"|"Alt"}
|
|
578
|
+
* @memberof PlatformControls
|
|
579
|
+
*/
|
|
123
580
|
alt = this.isMac ? 'option' : 'Alt';
|
|
581
|
+
/**
|
|
582
|
+
* The home key for the user's platform. Can be 'fn + Left arrow' or 'Home'. Used in keyboard shortcut display in help.
|
|
583
|
+
* @type {"fn + Left arrow"|"Home"}
|
|
584
|
+
* @memberof PlatformControls
|
|
585
|
+
*/
|
|
124
586
|
home = this.isMac ? 'fn + Left arrow' : 'Home';
|
|
587
|
+
/**
|
|
588
|
+
* The end key for the user's platform. Can be 'fn + Right arrow' or 'End'. Used in keyboard shortcut display in help.
|
|
589
|
+
* @type {"fn + Right arrow"|"End"}
|
|
590
|
+
* @memberof PlatformControls
|
|
591
|
+
*/
|
|
125
592
|
end = this.isMac ? 'fn + Right arrow' : 'End';
|
|
126
593
|
|
|
127
594
|
// internal controls
|
|
595
|
+
// todo: are these even used? Sean doesn't think so (May 2024)
|
|
128
596
|
keypressInterval = 2000; // ms or 2s
|
|
129
597
|
tabMovement = null;
|
|
130
598
|
|
|
131
599
|
// debug stuff
|
|
600
|
+
/**
|
|
601
|
+
* @namespace DebugSettings
|
|
602
|
+
*/
|
|
603
|
+
/**
|
|
604
|
+
* The debug level of the application. 0 = no console output, 1 = some console, 2 = more console, etc.
|
|
605
|
+
* @type {number}
|
|
606
|
+
* @default 3
|
|
607
|
+
* @memberof DebugSettings
|
|
608
|
+
*/
|
|
132
609
|
debugLevel = 3; // 0 = no console output, 1 = some console, 2 = more console, etc
|
|
610
|
+
/**
|
|
611
|
+
* Whether or not to display the end chime. This is not currently implemented as the end chime is not yet implemented.
|
|
612
|
+
* @type {boolean}
|
|
613
|
+
* @default false
|
|
614
|
+
* @memberof DebugSettings
|
|
615
|
+
*/
|
|
133
616
|
canPlayEndChime = false; //
|
|
617
|
+
/**
|
|
618
|
+
* Whether or not the LLM is connected, or generates a fake response for testing.
|
|
619
|
+
* @type {boolean}
|
|
620
|
+
* @default false
|
|
621
|
+
* @memberof DebugSettings
|
|
622
|
+
*/
|
|
134
623
|
manualData = true; // pull from manual data like chart2music (true), or do the old method where we pull from the chart (false)
|
|
135
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Stops the autoplay if it is currently running.
|
|
627
|
+
*
|
|
628
|
+
* @return {void}
|
|
629
|
+
*/
|
|
136
630
|
KillAutoplay() {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.autoplayId = null;
|
|
140
|
-
}
|
|
631
|
+
clearInterval(this.autoplayId);
|
|
632
|
+
this.autoplayId = null;
|
|
141
633
|
}
|
|
142
634
|
|
|
635
|
+
/**
|
|
636
|
+
* Stops the autoplay if it is currently running.
|
|
637
|
+
*
|
|
638
|
+
* @return {void}
|
|
639
|
+
*/
|
|
143
640
|
KillSepPlay() {
|
|
144
641
|
if (this.sepPlayId) {
|
|
145
642
|
clearInterval(this.sepPlayId);
|
|
@@ -147,18 +644,33 @@ class Constants {
|
|
|
147
644
|
}
|
|
148
645
|
}
|
|
149
646
|
|
|
647
|
+
/**
|
|
648
|
+
* Speed up the autoplay rate by the specified interval.
|
|
649
|
+
*
|
|
650
|
+
* @return {void}
|
|
651
|
+
*/
|
|
150
652
|
SpeedUp() {
|
|
151
653
|
if (constants.autoPlayRate - this.INTERVAL > this.MIN_SPEED) {
|
|
152
654
|
constants.autoPlayRate -= this.INTERVAL;
|
|
153
655
|
}
|
|
154
656
|
}
|
|
155
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Speed down the autoplay rate by the specified interval.
|
|
660
|
+
*
|
|
661
|
+
* @return {void}
|
|
662
|
+
*/
|
|
156
663
|
SpeedDown() {
|
|
157
664
|
if (constants.autoPlayRate + this.INTERVAL <= this.MAX_SPEED) {
|
|
158
665
|
constants.autoPlayRate += this.INTERVAL;
|
|
159
666
|
}
|
|
160
667
|
}
|
|
161
668
|
|
|
669
|
+
/**
|
|
670
|
+
* Reset the autoplay rate to the default.
|
|
671
|
+
*
|
|
672
|
+
* @return {void}
|
|
673
|
+
*/
|
|
162
674
|
SpeedReset() {
|
|
163
675
|
constants.autoPlayRate = constants.DEFAULT_SPEED;
|
|
164
676
|
}
|
|
@@ -167,7 +679,6 @@ class Constants {
|
|
|
167
679
|
* Function to convert hexadecimal color to string formatted rgb() functional notation.
|
|
168
680
|
* @param hexColorString - hexadecimal color (e.g., "#595959").
|
|
169
681
|
* @returns {string} - rgb() functional notation string (e.g., "rgb(100,100,100)").
|
|
170
|
-
* @constructor
|
|
171
682
|
*/
|
|
172
683
|
ConvertHexToRGBString(hexColorString) {
|
|
173
684
|
return (
|
|
@@ -185,7 +696,6 @@ class Constants {
|
|
|
185
696
|
* Function to convert an rgb() functional notation string to hexadecimal color.
|
|
186
697
|
* @param rgbColorString - color in rgb() functional notation (e.g., "rgb(100,100,100)").
|
|
187
698
|
* @returns {string} - hexadecimal color (e.g., "#595959").
|
|
188
|
-
* @constructor
|
|
189
699
|
*/
|
|
190
700
|
ConvertRGBStringToHex(rgbColorString) {
|
|
191
701
|
let rgb = rgbColorString.replace(/[^\d,]/g, '').split(',');
|
|
@@ -197,6 +707,12 @@ class Constants {
|
|
|
197
707
|
);
|
|
198
708
|
}
|
|
199
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Inverts an RGB color by subtracting each color component from 255.
|
|
712
|
+
*
|
|
713
|
+
* @param {string} color - The RGB color to invert, in the format "rgb(r,g,b)".
|
|
714
|
+
* @return {string} The inverted RGB color, in the format "rgb(r,g,b)".
|
|
715
|
+
*/
|
|
200
716
|
ColorInvert(color) {
|
|
201
717
|
// invert an rgb color
|
|
202
718
|
let rgb = color.replace(/[^\d,]/g, '').split(',');
|
|
@@ -205,10 +721,13 @@ class Constants {
|
|
|
205
721
|
let b = 255 - rgb[2];
|
|
206
722
|
return 'rgb(' + r + ',' + g + ',' + b + ')';
|
|
207
723
|
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Determines the best contrast color for the given color, by inverting it if necessary, but if it's just a shade of gray, default to this.colorSelected
|
|
727
|
+
* @param {string} oldColor - The color to make better
|
|
728
|
+
* @returns {string} The better color
|
|
729
|
+
*/
|
|
208
730
|
GetBetterColor(oldColor) {
|
|
209
|
-
// get a highly contrasting color against the current
|
|
210
|
-
// method: choose an inverted color, but if it's just a shade of gray, default to this.colorSelected
|
|
211
|
-
// Convert hex color to RGB color string if needed
|
|
212
731
|
if (oldColor.indexOf('#') !== -1) {
|
|
213
732
|
oldColor = this.ConvertHexToRGBString(oldColor);
|
|
214
733
|
}
|
|
@@ -232,7 +751,6 @@ class Constants {
|
|
|
232
751
|
* Function to parse a string containing CSS styles and return an array of strings containing CSS style attributes and values.
|
|
233
752
|
* @param styleString - a string containing CSS styles in inline format.
|
|
234
753
|
* @returns {string[]} - an array of strings containing CSS style attributes and values.
|
|
235
|
-
* @constructor
|
|
236
754
|
*/
|
|
237
755
|
GetStyleArrayFromString(styleString) {
|
|
238
756
|
// Get an array of CSS style attributes and values from a style string
|
|
@@ -243,7 +761,6 @@ class Constants {
|
|
|
243
761
|
* Function to parse an array of strings containing CSS style attributes and values and return a string containing CSS styles.
|
|
244
762
|
* @param styleArray - an array of strings containing CSS style attributes and values.
|
|
245
763
|
* @returns {string} - a string containing the CSS styles.
|
|
246
|
-
* @constructor
|
|
247
764
|
*/
|
|
248
765
|
GetStyleStringFromArray(styleArray) {
|
|
249
766
|
// Get CSS style string from an array of style attributes and values
|
|
@@ -264,15 +781,15 @@ class Constants {
|
|
|
264
781
|
}
|
|
265
782
|
|
|
266
783
|
/**
|
|
267
|
-
* Resources class
|
|
784
|
+
* Resources class to hold localization strings
|
|
268
785
|
*/
|
|
269
786
|
class Resources {
|
|
270
787
|
constructor() {}
|
|
271
788
|
|
|
272
|
-
language = 'en'; // 2 char lang code
|
|
789
|
+
language = 'en'; // Current language, 2 char lang code
|
|
273
790
|
knowledgeLevel = 'basic'; // basic, intermediate, expert
|
|
274
791
|
|
|
275
|
-
//
|
|
792
|
+
// language strings, per 2 char language code
|
|
276
793
|
strings = {
|
|
277
794
|
en: {
|
|
278
795
|
basic: {
|
|
@@ -313,7 +830,7 @@ class Resources {
|
|
|
313
830
|
}
|
|
314
831
|
|
|
315
832
|
/**
|
|
316
|
-
* Represents a menu
|
|
833
|
+
* Represents a menu class that contains the settings menu
|
|
317
834
|
*/
|
|
318
835
|
class Menu {
|
|
319
836
|
whereWasMyFocus = null;
|
|
@@ -323,6 +840,7 @@ class Menu {
|
|
|
323
840
|
this.LoadDataFromLocalStorage();
|
|
324
841
|
}
|
|
325
842
|
|
|
843
|
+
// initial html for the menu
|
|
326
844
|
menuHtml = `
|
|
327
845
|
<div id="menu" class="modal hidden" role="dialog" tabindex="-1">
|
|
328
846
|
<div class="modal-dialog" role="document" tabindex="0">
|
|
@@ -501,6 +1019,8 @@ class Menu {
|
|
|
501
1019
|
/**
|
|
502
1020
|
* Creates a menu element and sets up event listeners for opening and closing the menu,
|
|
503
1021
|
* and saving and loading data from local storage.
|
|
1022
|
+
*
|
|
1023
|
+
* @returns {void}
|
|
504
1024
|
*/
|
|
505
1025
|
CreateMenu() {
|
|
506
1026
|
// menu element creation
|
|
@@ -648,10 +1168,7 @@ class Menu {
|
|
|
648
1168
|
|
|
649
1169
|
/**
|
|
650
1170
|
* Destroys the menu element and its backdrop.
|
|
651
|
-
* @
|
|
652
|
-
* @name Destroy
|
|
653
|
-
* @memberof module:constants
|
|
654
|
-
* @returns {void}
|
|
1171
|
+
* @return {void}
|
|
655
1172
|
*/
|
|
656
1173
|
Destroy() {
|
|
657
1174
|
// menu element destruction
|
|
@@ -666,8 +1183,9 @@ class Menu {
|
|
|
666
1183
|
}
|
|
667
1184
|
|
|
668
1185
|
/**
|
|
669
|
-
* Toggles the menu on and off.
|
|
1186
|
+
* Toggles the menu on and off, toggling the css 'hidden' class.
|
|
670
1187
|
* @param {boolean} [onoff=false] - Whether to turn the menu on or off. Defaults to false (close).
|
|
1188
|
+
* @return {void}
|
|
671
1189
|
*/
|
|
672
1190
|
Toggle(onoff = false) {
|
|
673
1191
|
if (typeof onoff == 'undefined') {
|
|
@@ -701,7 +1219,8 @@ class Menu {
|
|
|
701
1219
|
}
|
|
702
1220
|
|
|
703
1221
|
/**
|
|
704
|
-
* Populates the form fields in the help menu with
|
|
1222
|
+
* Populates the form fields in the help menu with stored values in constants, which pulls from localStorage
|
|
1223
|
+
* @return {void}
|
|
705
1224
|
*/
|
|
706
1225
|
PopulateData() {
|
|
707
1226
|
document.getElementById('vol').value = constants.vol;
|
|
@@ -791,7 +1310,8 @@ class Menu {
|
|
|
791
1310
|
}
|
|
792
1311
|
|
|
793
1312
|
/**
|
|
794
|
-
* Saves the data from the HTML elements into the constants object
|
|
1313
|
+
* Saves the data from the HTML elements into the constants object, which is later stored in localStorage
|
|
1314
|
+
* @return {void}
|
|
795
1315
|
*/
|
|
796
1316
|
SaveData() {
|
|
797
1317
|
let shouldReset = this.ShouldLLMReset();
|
|
@@ -836,11 +1356,7 @@ class Menu {
|
|
|
836
1356
|
}
|
|
837
1357
|
|
|
838
1358
|
/**
|
|
839
|
-
*
|
|
840
|
-
* Typically used to do things like update the aria-live attributes
|
|
841
|
-
*
|
|
842
|
-
* @function
|
|
843
|
-
* @memberof constants
|
|
1359
|
+
* Sets the aria attributes on the HTML elements in the menu
|
|
844
1360
|
* @returns {void}
|
|
845
1361
|
*/
|
|
846
1362
|
UpdateHtml() {
|
|
@@ -854,7 +1370,8 @@ class Menu {
|
|
|
854
1370
|
}
|
|
855
1371
|
|
|
856
1372
|
/**
|
|
857
|
-
*
|
|
1373
|
+
* Adds a textual notification near the submit button to tell the user that the LLM history will be reset
|
|
1374
|
+
* @return {void}
|
|
858
1375
|
*/
|
|
859
1376
|
NotifyOfLLMReset() {
|
|
860
1377
|
let html =
|
|
@@ -876,8 +1393,9 @@ class Menu {
|
|
|
876
1393
|
);
|
|
877
1394
|
}
|
|
878
1395
|
/**
|
|
879
|
-
*
|
|
880
|
-
*
|
|
1396
|
+
* Checks whether or not we should reset the LLM history.
|
|
1397
|
+
* Criteria: if we've changed the LLM model, multi settings, preferences, or skill level.
|
|
1398
|
+
* @return {boolean} - if we're resetting or not.
|
|
881
1399
|
*/
|
|
882
1400
|
ShouldLLMReset() {
|
|
883
1401
|
let shouldReset = false;
|
|
@@ -914,9 +1432,7 @@ class Menu {
|
|
|
914
1432
|
}
|
|
915
1433
|
|
|
916
1434
|
/**
|
|
917
|
-
* Saves all data
|
|
918
|
-
* @function
|
|
919
|
-
* @memberof constants
|
|
1435
|
+
* Saves all data settings data in local storage. Specifially this saves data in constants variables to settings_data localStorage
|
|
920
1436
|
* @returns {void}
|
|
921
1437
|
*/
|
|
922
1438
|
SaveDataToLocalStorage() {
|
|
@@ -938,7 +1454,7 @@ class Menu {
|
|
|
938
1454
|
}
|
|
939
1455
|
}
|
|
940
1456
|
/**
|
|
941
|
-
* Loads data from
|
|
1457
|
+
* Loads data from 'settings_data' localStorage, and updates contants variables
|
|
942
1458
|
*/
|
|
943
1459
|
LoadDataFromLocalStorage() {
|
|
944
1460
|
let data = JSON.parse(localStorage.getItem('settings_data'));
|
|
@@ -954,9 +1470,7 @@ class Menu {
|
|
|
954
1470
|
}
|
|
955
1471
|
|
|
956
1472
|
/**
|
|
957
|
-
*
|
|
958
|
-
* and hooks to send info to an LLM
|
|
959
|
-
* @class
|
|
1473
|
+
* This class creates the chat LLM window, handles events, and handles all of the LLM calls
|
|
960
1474
|
*/
|
|
961
1475
|
class ChatLLM {
|
|
962
1476
|
constructor() {
|
|
@@ -1031,6 +1545,7 @@ class ChatLLM {
|
|
|
1031
1545
|
|
|
1032
1546
|
/**
|
|
1033
1547
|
* Sets events for the chatLLM modal
|
|
1548
|
+
* @return {void}
|
|
1034
1549
|
*/
|
|
1035
1550
|
SetEvents() {
|
|
1036
1551
|
// chatLLM close events
|
|
@@ -2449,7 +2964,7 @@ class Tracker {
|
|
|
2449
2964
|
}
|
|
2450
2965
|
|
|
2451
2966
|
/**
|
|
2452
|
-
*
|
|
2967
|
+
* The Review class. Review mode is basically an input that users can toggle to that holds the last text output. Very useful for screen reader users who want to copy what was just said.
|
|
2453
2968
|
* @class
|
|
2454
2969
|
*/
|
|
2455
2970
|
class Review {
|
|
@@ -2482,7 +2997,8 @@ class Review {
|
|
|
2482
2997
|
}
|
|
2483
2998
|
|
|
2484
2999
|
/**
|
|
2485
|
-
* Represents a class for
|
|
3000
|
+
* Represents a class for more easily sending custom errors to the console.
|
|
3001
|
+
* @class
|
|
2486
3002
|
*/
|
|
2487
3003
|
class LogError {
|
|
2488
3004
|
constructor() {}
|
|
@@ -7615,11 +8131,13 @@ class Control {
|
|
|
7615
8131
|
if (e.key == 'x') {
|
|
7616
8132
|
// X: x label
|
|
7617
8133
|
let xlabel = '';
|
|
7618
|
-
if (
|
|
8134
|
+
if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
|
|
7619
8135
|
xlabel = plot.plotLegend.x;
|
|
8136
|
+
} else if (singleMaidr.type == 'hist') {
|
|
8137
|
+
xlabel = plot.legendX;
|
|
7620
8138
|
} else if (
|
|
7621
|
-
|
|
7622
|
-
|
|
8139
|
+
singleMaidr.type == 'heat' ||
|
|
8140
|
+
singleMaidr.type == 'box' ||
|
|
7623
8141
|
singleMaidr.type == 'point' ||
|
|
7624
8142
|
singleMaidr.type.includes('point')
|
|
7625
8143
|
) {
|
|
@@ -7630,11 +8148,13 @@ class Control {
|
|
|
7630
8148
|
} else if (e.key == 'y') {
|
|
7631
8149
|
// Y: y label
|
|
7632
8150
|
let ylabel = '';
|
|
7633
|
-
if (
|
|
8151
|
+
if (singleMaidr.type == 'bar' || singleMaidr.type == 'line') {
|
|
7634
8152
|
ylabel = plot.plotLegend.y;
|
|
8153
|
+
} else if (singleMaidr.type == 'hist') {
|
|
8154
|
+
ylabel = plot.legendY;
|
|
7635
8155
|
} else if (
|
|
7636
|
-
|
|
7637
|
-
|
|
8156
|
+
singleMaidr.type == 'heat' ||
|
|
8157
|
+
singleMaidr.type == 'box' ||
|
|
7638
8158
|
singleMaidr.type == 'point' ||
|
|
7639
8159
|
singleMaidr.type == 'line' ||
|
|
7640
8160
|
singleMaidr.type.includes('point')
|
|
@@ -7691,6 +8211,7 @@ class Control {
|
|
|
7691
8211
|
let lastPlayed = '';
|
|
7692
8212
|
|
|
7693
8213
|
// testing for braille cursor routing
|
|
8214
|
+
/*
|
|
7694
8215
|
document.addEventListener('selectionchange', function (e) {
|
|
7695
8216
|
// notes:
|
|
7696
8217
|
// this basically works
|
|
@@ -7717,6 +8238,7 @@ class Control {
|
|
|
7717
8238
|
audio.playEnd();
|
|
7718
8239
|
}
|
|
7719
8240
|
});
|
|
8241
|
+
*/
|
|
7720
8242
|
|
|
7721
8243
|
// control eventlisteners
|
|
7722
8244
|
constants.events.push([
|