maidr 2.13.0 → 2.14.1
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/README.md +11 -14
- package/dist/maidr.js +241 -34
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -397,22 +397,19 @@ To learn more about the theoretical background and user study results, we recomm
|
|
|
397
397
|
}
|
|
398
398
|
```
|
|
399
399
|
|
|
400
|
-
|
|
400
|
+
2. [Designing Born-Accessible Courses in Data Science and Visualization: Challenges and Opportunities of a Remote Curriculum Taught by Blind Instructors to Blind Students](https://diglib.eg.org:8443/server/api/core/bitstreams/6d392735-a045-46bb-867c-90b0a538b1b7/content):
|
|
401
401
|
|
|
402
402
|
```tex
|
|
403
|
-
@
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
urldate = {2024-03-08},
|
|
414
|
-
archiveprefix = {arxiv},
|
|
415
|
-
keywords = {Computer Science - Human-Computer Interaction}
|
|
403
|
+
@inproceedings{10.2312:eved.20241053,
|
|
404
|
+
booktitle = {EuroVis 2024 - Education Papers},
|
|
405
|
+
editor = {Firat, Elif E. and Laramee, Robert S. and Andersen, Nicklas Sindelv},
|
|
406
|
+
title = {{Designing Born-Accessible Courses in Data Science and Visualization: Challenges and Opportunities of a Remote Curriculum Taught by Blind Instructors
|
|
407
|
+
to Blind Students}},
|
|
408
|
+
author = {JooYoung Seo and Sile O'Modhrain and Yilin Xia and Sanchita Kamath and Bongshin Lee and James M. Coughlan},
|
|
409
|
+
year = {2024},
|
|
410
|
+
publisher = {The Eurographics Association},
|
|
411
|
+
isbn = {978-3-03868-257-8},
|
|
412
|
+
doi = {10.2312/eved.20241053}
|
|
416
413
|
}
|
|
417
414
|
```
|
|
418
415
|
|
package/dist/maidr.js
CHANGED
|
@@ -396,7 +396,7 @@ class Constants {
|
|
|
396
396
|
* @default 1
|
|
397
397
|
* @memberof AdvancedUserSettings
|
|
398
398
|
*/
|
|
399
|
-
isTracking =
|
|
399
|
+
isTracking = 0;
|
|
400
400
|
/**
|
|
401
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
402
|
* @type {boolean}
|
|
@@ -1662,6 +1662,16 @@ class ChatLLM {
|
|
|
1662
1662
|
]);
|
|
1663
1663
|
}
|
|
1664
1664
|
|
|
1665
|
+
/**
|
|
1666
|
+
* Copies the chat history to the clipboard in markdown format.
|
|
1667
|
+
* We do this by running on any click or keyup event on the chatLLM modal so we can handle all the cases.
|
|
1668
|
+
* If e is undefined, the entire chat history is copied.
|
|
1669
|
+
* If e.type is click, we see what button was clicked and copy just that block or the entire thing
|
|
1670
|
+
* If e.type is keyup, we check for alt shift c or ctrl shift c and copy the last message,
|
|
1671
|
+
* or ctrl shift a for the entire chat history
|
|
1672
|
+
*
|
|
1673
|
+
* @param {Event|undefined} e - The event that triggered the copy action. If undefined, the entire chat history is copied.
|
|
1674
|
+
*/
|
|
1665
1675
|
CopyChatHistory(e) {
|
|
1666
1676
|
let text = '';
|
|
1667
1677
|
if (typeof e == 'undefined') {
|
|
@@ -1708,9 +1718,9 @@ class ChatLLM {
|
|
|
1708
1718
|
let removeThese = cleanElems.querySelectorAll('.chatLLM_message_copy');
|
|
1709
1719
|
removeThese.forEach((elem) => elem.remove());
|
|
1710
1720
|
|
|
1711
|
-
// convert to markdown
|
|
1721
|
+
// convert from html to markdown
|
|
1712
1722
|
let markdown = this.htmlToMarkdown(cleanElems);
|
|
1713
|
-
// kill more than 2 newlines in a row
|
|
1723
|
+
// this messes up a bit with spacing, so kill more than 2 newlines in a row
|
|
1714
1724
|
markdown = markdown.replace(/\n{3,}/g, '\n\n');
|
|
1715
1725
|
|
|
1716
1726
|
try {
|
|
@@ -4433,6 +4443,11 @@ class Display {
|
|
|
4433
4443
|
globalMax = constants.maxX;
|
|
4434
4444
|
}
|
|
4435
4445
|
|
|
4446
|
+
// exception: return if we're out of bounds
|
|
4447
|
+
if (plotPos < 0 || plotPos >= plot.plotData.length) {
|
|
4448
|
+
return;
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4436
4451
|
// We convert main plot data to array of values and types, including min and max, and seperating outliers and removing nulls
|
|
4437
4452
|
let valData = [];
|
|
4438
4453
|
valData.push({ type: 'global_min', value: globalMin });
|
|
@@ -4698,8 +4713,6 @@ class Display {
|
|
|
4698
4713
|
}
|
|
4699
4714
|
}
|
|
4700
4715
|
|
|
4701
|
-
constants.brailleInput.value = brailleArray.join('');
|
|
4702
|
-
|
|
4703
4716
|
constants.brailleInput.value = brailleArray.join('');
|
|
4704
4717
|
if (constants.debugLevel > 5) {
|
|
4705
4718
|
console.log('braille:', constants.brailleInput.value);
|
|
@@ -8210,35 +8223,30 @@ class Control {
|
|
|
8210
8223
|
constants.lastx = 0;
|
|
8211
8224
|
let lastPlayed = '';
|
|
8212
8225
|
|
|
8213
|
-
//
|
|
8214
|
-
/*
|
|
8226
|
+
// braille cursor routing
|
|
8215
8227
|
document.addEventListener('selectionchange', function (e) {
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
}
|
|
8237
|
-
if (testEnd) {
|
|
8238
|
-
audio.playEnd();
|
|
8228
|
+
if (constants.brailleMode == 'on') {
|
|
8229
|
+
let pos = constants.brailleInput.selectionStart;
|
|
8230
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
8231
|
+
pos = constants.brailleInput.selectionStart;
|
|
8232
|
+
if (pos < 0) {
|
|
8233
|
+
pos = 0;
|
|
8234
|
+
}
|
|
8235
|
+
position.x = pos;
|
|
8236
|
+
lockPosition();
|
|
8237
|
+
let testEnd = true;
|
|
8238
|
+
|
|
8239
|
+
// update display / text / audio
|
|
8240
|
+
if (testEnd) {
|
|
8241
|
+
UpdateAll();
|
|
8242
|
+
}
|
|
8243
|
+
if (testEnd) {
|
|
8244
|
+
audio.playEnd();
|
|
8245
|
+
}
|
|
8246
|
+
} else {
|
|
8247
|
+
// we're using normal cursor, let the default handle it
|
|
8239
8248
|
}
|
|
8240
8249
|
});
|
|
8241
|
-
*/
|
|
8242
8250
|
|
|
8243
8251
|
// control eventlisteners
|
|
8244
8252
|
constants.events.push([
|
|
@@ -8417,17 +8425,19 @@ class Control {
|
|
|
8417
8425
|
function lockPosition() {
|
|
8418
8426
|
// lock to min / max postions
|
|
8419
8427
|
let didLockHappen = false;
|
|
8420
|
-
// if (!constants.hasRect) {
|
|
8421
|
-
// return didLockHappen;
|
|
8422
|
-
// }
|
|
8423
8428
|
|
|
8424
8429
|
if (position.x < 0) {
|
|
8425
8430
|
position.x = 0;
|
|
8426
8431
|
didLockHappen = true;
|
|
8432
|
+
if (constants.brailleMode != 'off') {
|
|
8433
|
+
// change selection to match postion as well
|
|
8434
|
+
constants.brailleInput.selectionEnd = 0;
|
|
8435
|
+
}
|
|
8427
8436
|
}
|
|
8428
8437
|
if (position.x > plot.plotData.length - 1) {
|
|
8429
8438
|
position.x = plot.plotData.length - 1;
|
|
8430
8439
|
didLockHappen = true;
|
|
8440
|
+
constants.brailleInput.selectionEnd = plot.plotData.length - 1;
|
|
8431
8441
|
}
|
|
8432
8442
|
|
|
8433
8443
|
return didLockHappen;
|
|
@@ -8514,6 +8524,59 @@ class Control {
|
|
|
8514
8524
|
}
|
|
8515
8525
|
let lastPlayed = '';
|
|
8516
8526
|
|
|
8527
|
+
// braille cursor routing
|
|
8528
|
+
// bug: still not working. Not really sure what's going on but the tethering is now totally broken
|
|
8529
|
+
// like, it doesn't even seem to be on the right plot
|
|
8530
|
+
document.addEventListener('selectionchange', function (e) {
|
|
8531
|
+
e.preventDefault();
|
|
8532
|
+
if (
|
|
8533
|
+
constants.brailleMode == 'on' &&
|
|
8534
|
+
constants.brailleInput.selectionStart
|
|
8535
|
+
) {
|
|
8536
|
+
let cursorPos = constants.brailleInput.selectionStart;
|
|
8537
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
8538
|
+
cursorPos = constants.brailleInput.selectionStart;
|
|
8539
|
+
if (cursorPos < 0) {
|
|
8540
|
+
pos = 0;
|
|
8541
|
+
}
|
|
8542
|
+
// convert braille position to start of whatever section we're in
|
|
8543
|
+
let walk = 0;
|
|
8544
|
+
let posType = '';
|
|
8545
|
+
if (constants.brailleData) {
|
|
8546
|
+
for (let i = 0; i < constants.brailleData.length; i++) {
|
|
8547
|
+
walk += constants.brailleData[i].numChars;
|
|
8548
|
+
if (walk > cursorPos) {
|
|
8549
|
+
if (constants.brailleData[i].type == 'blank') {
|
|
8550
|
+
posType = constants.brailleData[i + 1].type;
|
|
8551
|
+
} else {
|
|
8552
|
+
posType = constants.brailleData[i].type;
|
|
8553
|
+
}
|
|
8554
|
+
break;
|
|
8555
|
+
}
|
|
8556
|
+
}
|
|
8557
|
+
}
|
|
8558
|
+
let pos = plot.sections.indexOf(posType);
|
|
8559
|
+
|
|
8560
|
+
if (posType.length > 0) {
|
|
8561
|
+
if (constants.plotOrientation == 'vert') {
|
|
8562
|
+
position.y = pos;
|
|
8563
|
+
} else {
|
|
8564
|
+
position.x = pos;
|
|
8565
|
+
}
|
|
8566
|
+
lockPosition();
|
|
8567
|
+
let testEnd = true;
|
|
8568
|
+
|
|
8569
|
+
// update display / text / audio
|
|
8570
|
+
if (testEnd) {
|
|
8571
|
+
UpdateAll();
|
|
8572
|
+
}
|
|
8573
|
+
if (testEnd) {
|
|
8574
|
+
audio.playEnd();
|
|
8575
|
+
}
|
|
8576
|
+
}
|
|
8577
|
+
}
|
|
8578
|
+
});
|
|
8579
|
+
|
|
8517
8580
|
// control eventlisteners
|
|
8518
8581
|
constants.events.push([
|
|
8519
8582
|
constants.chart,
|
|
@@ -8526,12 +8589,14 @@ class Control {
|
|
|
8526
8589
|
if (e.key == 'ArrowRight') {
|
|
8527
8590
|
if (constants.isMac ? e.metaKey : e.ctrlKey) {
|
|
8528
8591
|
if (e.shiftKey) {
|
|
8592
|
+
// autoplay
|
|
8529
8593
|
if (constants.plotOrientation == 'vert') {
|
|
8530
8594
|
Autoplay('right', position.x, plot.plotData.length - 1);
|
|
8531
8595
|
} else {
|
|
8532
8596
|
Autoplay('right', position.x, plot.sections.length - 1);
|
|
8533
8597
|
}
|
|
8534
8598
|
} else {
|
|
8599
|
+
// move to end
|
|
8535
8600
|
isAtEnd = lockPosition();
|
|
8536
8601
|
if (constants.plotOrientation == 'vert') {
|
|
8537
8602
|
position.x = plot.plotData.length - 1;
|
|
@@ -8550,6 +8615,7 @@ class Control {
|
|
|
8550
8615
|
lastY = position.y;
|
|
8551
8616
|
Autoplay('reverse-right', plot.plotData.length - 1, position.x);
|
|
8552
8617
|
} else {
|
|
8618
|
+
// normal movement
|
|
8553
8619
|
if (position.x == -1 && position.y == plot.sections.length) {
|
|
8554
8620
|
position.y -= 1;
|
|
8555
8621
|
}
|
|
@@ -9122,6 +9188,45 @@ class Control {
|
|
|
9122
9188
|
let lastPlayed = '';
|
|
9123
9189
|
constants.lastx = 0;
|
|
9124
9190
|
|
|
9191
|
+
document.addEventListener('selectionchange', function (e) {
|
|
9192
|
+
if (constants.brailleMode == 'on') {
|
|
9193
|
+
let pos = constants.brailleInput.selectionStart;
|
|
9194
|
+
|
|
9195
|
+
// exception: don't let users click the seperator char
|
|
9196
|
+
let seperatorPositions = constants.brailleInput.value
|
|
9197
|
+
.split('')
|
|
9198
|
+
.reduce((positions, char, index) => {
|
|
9199
|
+
if (char === '⠳') positions.push(index);
|
|
9200
|
+
return positions;
|
|
9201
|
+
}, []);
|
|
9202
|
+
if (seperatorPositions.includes(pos)) {
|
|
9203
|
+
return;
|
|
9204
|
+
}
|
|
9205
|
+
|
|
9206
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
9207
|
+
pos = constants.brailleInput.selectionStart;
|
|
9208
|
+
if (pos < 0) {
|
|
9209
|
+
pos = 0;
|
|
9210
|
+
}
|
|
9211
|
+
|
|
9212
|
+
// actual position is based on num_cols and num_rows and the spacer
|
|
9213
|
+
position.y = Math.floor(pos / (plot.num_cols + 1));
|
|
9214
|
+
position.x = pos % (plot.num_cols + 1);
|
|
9215
|
+
lockPosition();
|
|
9216
|
+
let testEnd = true;
|
|
9217
|
+
|
|
9218
|
+
// update display / text / audio
|
|
9219
|
+
if (testEnd) {
|
|
9220
|
+
UpdateAll();
|
|
9221
|
+
}
|
|
9222
|
+
if (testEnd) {
|
|
9223
|
+
audio.playEnd();
|
|
9224
|
+
}
|
|
9225
|
+
} else {
|
|
9226
|
+
// we're using normal cursor, let the default handle it
|
|
9227
|
+
}
|
|
9228
|
+
});
|
|
9229
|
+
|
|
9125
9230
|
// control eventlisteners
|
|
9126
9231
|
constants.events.push([
|
|
9127
9232
|
constants.chart,
|
|
@@ -9228,6 +9333,8 @@ class Control {
|
|
|
9228
9333
|
constants.navigation = 0;
|
|
9229
9334
|
}
|
|
9230
9335
|
|
|
9336
|
+
console.log('position: ' + position.x + ', ' + position.y);
|
|
9337
|
+
|
|
9231
9338
|
// update text, display, and audio
|
|
9232
9339
|
if (updateInfoThisRound && !isAtEnd) {
|
|
9233
9340
|
UpdateAll();
|
|
@@ -9747,6 +9854,32 @@ class Control {
|
|
|
9747
9854
|
}
|
|
9748
9855
|
}
|
|
9749
9856
|
|
|
9857
|
+
// todo / bug: does'nt work at all on just line (in gallery)
|
|
9858
|
+
// it sorta works in scatter (in gallery), visual highlight changes, but sonify and text don't update
|
|
9859
|
+
document.addEventListener('selectionchange', function (e) {
|
|
9860
|
+
if (constants.brailleMode == 'on') {
|
|
9861
|
+
let pos = constants.brailleInput.selectionStart;
|
|
9862
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
9863
|
+
pos = constants.brailleInput.selectionStart;
|
|
9864
|
+
if (pos < 0) {
|
|
9865
|
+
pos = 0;
|
|
9866
|
+
}
|
|
9867
|
+
positionL1.x = pos;
|
|
9868
|
+
lockPosition();
|
|
9869
|
+
let testEnd = true;
|
|
9870
|
+
|
|
9871
|
+
// update display / text / audio
|
|
9872
|
+
if (testEnd) {
|
|
9873
|
+
UpdateAllBraille();
|
|
9874
|
+
}
|
|
9875
|
+
if (testEnd) {
|
|
9876
|
+
audio.playEnd();
|
|
9877
|
+
}
|
|
9878
|
+
} else {
|
|
9879
|
+
// we're using normal cursor, let the default handle it
|
|
9880
|
+
}
|
|
9881
|
+
});
|
|
9882
|
+
|
|
9750
9883
|
constants.events.push([
|
|
9751
9884
|
constants.brailleInput,
|
|
9752
9885
|
'keydown',
|
|
@@ -10048,6 +10181,30 @@ class Control {
|
|
|
10048
10181
|
let lastPlayed = '';
|
|
10049
10182
|
constants.lastx = 0;
|
|
10050
10183
|
|
|
10184
|
+
document.addEventListener('selectionchange', function (e) {
|
|
10185
|
+
if (constants.brailleMode == 'on') {
|
|
10186
|
+
let pos = constants.brailleInput.selectionStart;
|
|
10187
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
10188
|
+
pos = constants.brailleInput.selectionStart;
|
|
10189
|
+
if (pos < 0) {
|
|
10190
|
+
pos = 0;
|
|
10191
|
+
}
|
|
10192
|
+
position.x = pos;
|
|
10193
|
+
lockPosition();
|
|
10194
|
+
let testEnd = true;
|
|
10195
|
+
|
|
10196
|
+
// update display / text / audio
|
|
10197
|
+
if (testEnd) {
|
|
10198
|
+
UpdateAll();
|
|
10199
|
+
}
|
|
10200
|
+
if (testEnd) {
|
|
10201
|
+
audio.playEnd();
|
|
10202
|
+
}
|
|
10203
|
+
} else {
|
|
10204
|
+
// we're using normal cursor, let the default handle it
|
|
10205
|
+
}
|
|
10206
|
+
});
|
|
10207
|
+
|
|
10051
10208
|
// control eventlisteners
|
|
10052
10209
|
constants.events.push([
|
|
10053
10210
|
[constants.chart, constants.brailleInput],
|
|
@@ -10294,6 +10451,32 @@ class Control {
|
|
|
10294
10451
|
let lastPlayed = '';
|
|
10295
10452
|
constants.lastx = 0;
|
|
10296
10453
|
|
|
10454
|
+
// todo bug, forgot about all mode
|
|
10455
|
+
// bug: you can click 1 past end (for all chart types). Make sure we're lockign and then resetting the selectionStart
|
|
10456
|
+
document.addEventListener('selectionchange', function (e) {
|
|
10457
|
+
if (constants.brailleMode == 'on') {
|
|
10458
|
+
let pos = constants.brailleInput.selectionStart;
|
|
10459
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
10460
|
+
pos = constants.brailleInput.selectionStart;
|
|
10461
|
+
if (pos < 0) {
|
|
10462
|
+
pos = 0;
|
|
10463
|
+
}
|
|
10464
|
+
position.x = pos;
|
|
10465
|
+
lockPosition();
|
|
10466
|
+
let testEnd = true;
|
|
10467
|
+
|
|
10468
|
+
// update display / text / audio
|
|
10469
|
+
if (testEnd) {
|
|
10470
|
+
UpdateAll();
|
|
10471
|
+
}
|
|
10472
|
+
if (testEnd) {
|
|
10473
|
+
audio.playEnd();
|
|
10474
|
+
}
|
|
10475
|
+
} else {
|
|
10476
|
+
// we're using normal cursor, let the default handle it
|
|
10477
|
+
}
|
|
10478
|
+
});
|
|
10479
|
+
|
|
10297
10480
|
// control eventlisteners
|
|
10298
10481
|
constants.events.push([
|
|
10299
10482
|
[constants.chart, constants.brailleInput],
|
|
@@ -10651,6 +10834,29 @@ class Control {
|
|
|
10651
10834
|
let lastPlayed = '';
|
|
10652
10835
|
constants.lastx = 0;
|
|
10653
10836
|
|
|
10837
|
+
// braille cursor routing
|
|
10838
|
+
document.addEventListener('selectionchange', function (e) {
|
|
10839
|
+
if (constants.brailleMode == 'on') {
|
|
10840
|
+
let pos = constants.brailleInput.selectionStart;
|
|
10841
|
+
// we're using braille cursor, update the selection from what was clicked
|
|
10842
|
+
pos = constants.brailleInput.selectionStart;
|
|
10843
|
+
if (pos < 0) {
|
|
10844
|
+
pos = 0;
|
|
10845
|
+
}
|
|
10846
|
+
position.x = pos;
|
|
10847
|
+
lockPosition();
|
|
10848
|
+
let testEnd = true;
|
|
10849
|
+
|
|
10850
|
+
// update display / text / audio
|
|
10851
|
+
if (testEnd) {
|
|
10852
|
+
UpdateAll();
|
|
10853
|
+
}
|
|
10854
|
+
if (testEnd) {
|
|
10855
|
+
audio.playEnd();
|
|
10856
|
+
}
|
|
10857
|
+
}
|
|
10858
|
+
});
|
|
10859
|
+
|
|
10654
10860
|
// control eventlisteners
|
|
10655
10861
|
constants.events.push([
|
|
10656
10862
|
constants.chart,
|
|
@@ -11540,6 +11746,7 @@ function CreateChartComponents() {
|
|
|
11540
11746
|
constants.brailleDisplayLength +
|
|
11541
11747
|
'" ' +
|
|
11542
11748
|
'aria-brailleroledescription="" ' + // this kills the 2 char 'edit' that screen readers add
|
|
11749
|
+
'autocomplete="off" ' +
|
|
11543
11750
|
'/>\n</div>\n'
|
|
11544
11751
|
);
|
|
11545
11752
|
|