maidr 2.28.0 → 2.28.2

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 CHANGED
@@ -660,6 +660,7 @@ class Constants {
660
660
  * @default Array(10).fill(null)
661
661
  */
662
662
  mark = Array(10).fill(null);
663
+ markText = Array(10).fill(null);
663
664
 
664
665
  /**
665
666
  * Stops the autoplay if it is currently running.
@@ -1053,6 +1054,22 @@ class Menu {
1053
1054
  <td>Copy full chat history in AI Chat View</td>
1054
1055
  <td>${constants.alt} + Shift + A</td>
1055
1056
  </tr>
1057
+ <tr>
1058
+ <td>Mark current position</td>
1059
+ <td>M # (Shift + m, then a number 0-9)</td>
1060
+ </tr>
1061
+ <tr>
1062
+ <td>Play marked position</td>
1063
+ <td>m # (m, then a number 0-9)</td>
1064
+ </tr>
1065
+ <tr>
1066
+ <td>Jump to marked position</td>
1067
+ <td>j # (j, then a number 0-9)</td>
1068
+ </tr>
1069
+ <tr>
1070
+ <td>Goto location menu</td>
1071
+ <td>g</td>
1072
+ </tr>
1056
1073
  </tbody>
1057
1074
  </table>
1058
1075
  </div>
@@ -9160,7 +9177,7 @@ class Control {
9160
9177
  ]);
9161
9178
 
9162
9179
  // mark and recall
9163
- // mark with M + # (0-9), recall with m + # (0-9)
9180
+ // mark with M + # (0-9), play with m + # (0-9), jump to with j + #
9164
9181
  // available in chart and braille, not review
9165
9182
  let lastKeytime = 0;
9166
9183
  let lastKey = null;
@@ -9178,17 +9195,36 @@ class Control {
9178
9195
  if (lastKey == 'M' && /[0-9]/.test(key)) {
9179
9196
  const markIndex = parseInt(key, 10);
9180
9197
  constants.mark[markIndex] = JSON.parse(JSON.stringify(position)); // deep copy
9198
+ constants.markText[markIndex] = JSON.parse(
9199
+ JSON.stringify(constants.verboseText)
9200
+ ); // deep copy
9181
9201
  display.announceText('Marked position ' + markIndex);
9182
9202
  }
9183
9203
 
9184
- // recall with m
9185
- if (lastKey == 'm' && /[0-9]/.test(key)) {
9204
+ // jump with j
9205
+ if (lastKey == 'j' && /[0-9]/.test(key)) {
9186
9206
  const recallIndex = parseInt(key, 10);
9187
9207
  if (constants.mark[recallIndex]) {
9188
9208
  position = JSON.parse(
9189
9209
  JSON.stringify(constants.mark[recallIndex])
9190
9210
  ); // deep copy
9191
9211
  control.UpdateAll();
9212
+ } else {
9213
+ display.announceText(
9214
+ 'No position marked at index ' + recallIndex
9215
+ );
9216
+ }
9217
+ }
9218
+
9219
+ // play with m
9220
+ if (lastKey == 'm' && /[0-9]/.test(key)) {
9221
+ const recallIndex = parseInt(key, 10);
9222
+ if (constants.markText[recallIndex]) {
9223
+ display.announceText(constants.markText[recallIndex]);
9224
+ } else {
9225
+ display.announceText(
9226
+ 'No position marked at index ' + recallIndex
9227
+ );
9192
9228
  }
9193
9229
  }
9194
9230
  }
@@ -11910,118 +11946,137 @@ class Control {
11910
11946
 
11911
11947
  class Goto {
11912
11948
  //locations = ['Max Value', 'Min Value', 'Mean', 'Median'];
11913
- locations = ['Max Value', 'Min Value'];
11949
+ static options = ['Max Value', 'Min Value'];
11914
11950
 
11915
11951
  constructor() {
11916
- this.popupOpen = false;
11917
- this.popupIndex = 0;
11918
- this.attachBootstrapModal();
11952
+ this.menuOpen = false;
11953
+ this.initMenu();
11919
11954
  this.attachEventListeners();
11920
11955
  }
11921
11956
 
11922
- attachBootstrapModal() {
11923
- // Create modal container
11924
- const modalHtml = `
11925
- <div class="modal fade hidden" id="goto-modal" tabindex="-1" aria-labelledby="navigationModalLabel">
11926
- <div class="modal-dialog modal-dialog-centered">
11927
- <div class="modal-content">
11928
- <div class="modal-header">
11929
- <h5 class="modal-title" id="navigationModalLabel">Navigate to Location</h5>
11930
- <button type="button" class="close" data-dismiss="modal" aria-label="Close">
11931
- <span aria-hidden="true">&times;</span>
11932
- </button>
11933
- </div>
11934
- <div class="modal-body">
11935
- <ul class="list-group" id="goto-list">
11936
- ${this.locations
11937
- .map(
11938
- (location, index) => `
11939
- <li class="list-group-item ${index === 0 ? 'active' : ''}">
11940
- <button type="button" class="btn btn-link">
11941
- ${location}
11942
- </button>
11943
- </li>`
11944
- )
11945
- .join('')}
11946
- </ul>
11957
+ initMenu() {
11958
+ this.menu = document.createElement('div');
11959
+ this.menu.id = 'goto-menu';
11960
+ this.menu.style.display = 'none';
11961
+ this.menu.innerHTML = `
11962
+ <div class="menu-container">
11963
+ <input
11964
+ type="text"
11965
+ id="menu-search"
11966
+ placeholder="Search locations..."
11967
+ aria-label="Search locations to go to"
11968
+ />
11969
+ <ul id="menu-items">
11970
+ ${Goto.options
11971
+ .map((option) => `<li><button>${option}</button></li>`)
11972
+ .join('')}
11973
+ </ul>
11947
11974
  </div>
11948
- </div>
11949
- </div>
11950
- </div>
11951
- <div id="goto_modal_backdrop" class="modal-backdrop hidden"></div>
11952
- `;
11975
+ `;
11953
11976
 
11954
- document.body.insertAdjacentHTML('beforeend', modalHtml);
11977
+ this.menuSearch = this.menu.querySelector('#menu-search');
11978
+ this.menuItems = Array.from(
11979
+ this.menu.querySelectorAll('#menu-items button')
11980
+ );
11955
11981
 
11956
- constants.gotoModal = document.getElementById('goto-modal');
11982
+ constants.gotoMenu = this.menu;
11983
+ document.body.appendChild(this.menu);
11957
11984
  }
11958
11985
 
11959
- openPopup() {
11960
- this.popupOpen = true;
11961
- this.popupIndex = 0;
11962
- constants.tabMovement = 0;
11963
-
11986
+ openMenu() {
11987
+ // save the current focus so we can return to it later
11964
11988
  this.whereWasMyFocus = document.activeElement;
11965
- document.getElementById('goto-modal').classList.remove('hidden');
11966
- document.getElementById('goto_modal_backdrop').classList.remove('hidden');
11967
- document.querySelector('#goto-modal .close').focus();
11968
- this.updateSelection(this.popupIndex);
11989
+ constants.tabMovement = 0; // to prevent maidr from being destroyed as we leave the chart
11990
+
11991
+ // clear the search input
11992
+ this.menuSearch.value = '';
11993
+ this.filterItems('');
11994
+
11995
+ // open the menu etc
11996
+ this.menuOpen = true;
11997
+ this.menu.style.display = 'block';
11998
+ this.menuSearch.focus();
11969
11999
  }
11970
12000
 
11971
- closePopup() {
11972
- this.popupOpen = false;
11973
- // close
11974
- document.getElementById('goto-modal').classList.add('hidden');
11975
- document.getElementById('goto_modal_backdrop').classList.add('hidden');
12001
+ closeMenu() {
12002
+ this.menuOpen = false;
12003
+ this.menu.style.display = 'none';
11976
12004
  this.whereWasMyFocus.focus();
11977
12005
  this.whereWasMyFocus = null;
11978
12006
  }
11979
12007
 
11980
- updateSelection(index) {
11981
- const items = document.querySelectorAll('#goto-list button');
11982
- Array.from(items).forEach((item, idx) => {
11983
- item.classList.toggle('active', idx === index);
12008
+ filterItems(query) {
12009
+ const lowerCaseQuery = query.toLowerCase();
12010
+ this.menuItems.forEach((item) => {
12011
+ if (item.textContent.toLowerCase().includes(lowerCaseQuery)) {
12012
+ item.parentElement.style.display = 'block';
12013
+ } else {
12014
+ item.parentElement.style.display = 'none';
12015
+ }
11984
12016
  });
11985
12017
  }
11986
12018
 
11987
12019
  attachEventListeners() {
12020
+ this.menuSearch.addEventListener('input', (event) =>
12021
+ this.filterItems(event.target.value)
12022
+ );
12023
+
11988
12024
  // Open the modal when the user presses 'g'
11989
12025
  constants.events.push([
11990
12026
  [constants.chart, constants.brailleInput],
11991
- 'keydown',
12027
+ 'keyup',
11992
12028
  function (event) {
11993
12029
  if (event.key === 'g' && !goto.popupOpen) {
11994
- goto.openPopup();
12030
+ goto.openMenu();
11995
12031
  }
11996
12032
  },
11997
12033
  ]);
11998
- // arrow keys to navigate the list, enter to select, escape to close
12034
+ // arrow keys to navigate the list, escape to close
11999
12035
  constants.events.push([
12000
- constants.gotoModal,
12036
+ constants.gotoMenu,
12001
12037
  'keydown',
12002
12038
  function (event) {
12003
- if (goto.popupOpen) {
12039
+ if (goto.menuOpen) {
12040
+ const focusableElements = [
12041
+ goto.menuSearch,
12042
+ ...goto.menuItems.filter(
12043
+ (item) => item.parentElement.style.display !== 'none'
12044
+ ),
12045
+ ];
12046
+ const currentIndex = focusableElements.indexOf(
12047
+ document.activeElement
12048
+ );
12049
+
12004
12050
  if (event.key === 'ArrowDown') {
12005
12051
  event.preventDefault();
12006
- goto.popupIndex = (goto.popupIndex + 1) % goto.locations.length;
12007
- goto.updateSelection(goto.popupIndex);
12052
+ const nextIndex = (currentIndex + 1) % focusableElements.length;
12053
+ focusableElements[nextIndex]?.focus();
12008
12054
  } else if (event.key === 'ArrowUp') {
12009
12055
  event.preventDefault();
12010
- goto.popupIndex =
12011
- (goto.popupIndex - 1 + goto.locations.length) %
12012
- goto.locations.length;
12013
- goto.updateSelection(goto.popupIndex);
12014
- } else if (event.key === 'Enter') {
12015
- event.preventDefault();
12016
- const selectedLocation = goto.locations[goto.popupIndex];
12017
- goto.closePopup();
12018
- goto.goToLocation(selectedLocation);
12019
- } else if (event.key === 'Escape') {
12020
- goto.closePopup();
12056
+ const prevIndex =
12057
+ (currentIndex - 1 + focusableElements.length) %
12058
+ focusableElements.length;
12059
+ focusableElements[prevIndex]?.focus();
12060
+ } else {
12061
+ if (event.key === 'Escape') {
12062
+ goto.closeMenu();
12063
+ }
12021
12064
  }
12022
12065
  }
12023
12066
  },
12024
12067
  ]);
12068
+ // enter to select, which we register as a click event so it works with screen readers
12069
+ constants.events.push([
12070
+ constants.gotoMenu,
12071
+ 'click',
12072
+ function (event) {
12073
+ if (event.target.tagName === 'BUTTON') {
12074
+ let loc = event.target.textContent;
12075
+ goto.closeMenu();
12076
+ goto.goToLocation(loc);
12077
+ }
12078
+ },
12079
+ ]);
12025
12080
  }
12026
12081
 
12027
12082
  goToLocation(loc) {