Home | History | Annotate | Download | only in common
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 /**
      7  * @fileoverview This class acts as the persistent store for all static data
      8  * about commands.
      9  *
     10  * This store can safely be used within either a content or background script
     11  * context.
     12  *
     13  * If you are looking to add a user command, follow the below steps for best
     14  * integration with existing components:
     15  * 1. Add a command below in cvox.CommandStore.CMD_WHITELIST. Pick a
     16  * programmatic name and fill in each of the relevant JSON keys.
     17  * Be sure to add a msg id and define it in chromevox/messages/messages.js which
     18  * describes the command. Please also add a category msg id so that the command
     19  * will show up in the options page.
     20  * 2. Add the command's logic to cvox.UserCommands inside of our switch-based
     21  * dispatch method (doCommand_).
     22  * 3. Add a key binding in chromevox/background/keymaps/classic_keymap.json and
     23  * chromevox/background/keymaps/flat_keymap.json.
     24  *
     25  * Class description:
     26  * This class is entirely static and holds a JSON structure that stores
     27  * commands and their associated metadata.
     28  *
     29  * From this metadata, we compute relevant subsets of data such as all present
     30  * categories.
     31  */
     32 
     33 
     34 goog.provide('cvox.CommandStore');
     35 
     36 goog.require('cvox.PlatformFilter');
     37 
     38 
     39 /**
     40  * Returns all of the categories in the store as an array.
     41  * @return {Array.<string>} The collection of categories.
     42  */
     43 cvox.CommandStore.categories = function() {
     44   var categorySet = {};
     45   for (var cmd in cvox.CommandStore.CMD_WHITELIST) {
     46     var struct = cvox.CommandStore.CMD_WHITELIST[cmd];
     47     if (struct.category) {
     48       categorySet[struct.category] = true;
     49     }
     50   }
     51   var ret = [];
     52   for (var category in categorySet) {
     53     ret.push(category);
     54   }
     55   return ret;
     56 };
     57 
     58 
     59 /**
     60  * Gets a message given a command.
     61  * @param {string} command The command to query.
     62  * @return {string|undefined} The message id, if any.
     63  */
     64 cvox.CommandStore.messageForCommand = function(command) {
     65   return (cvox.CommandStore.CMD_WHITELIST[command] || {}).msgId;
     66 };
     67 
     68 
     69 /**
     70  * Gets a category given a command.
     71  * @param {string} command The command to query.
     72  * @return {string|undefined} The command, if any.
     73  */
     74 cvox.CommandStore.categoryForCommand = function(command) {
     75   return (cvox.CommandStore.CMD_WHITELIST[command] || {}).category;
     76 };
     77 
     78 
     79 /**
     80  * Gets all commands for a category.
     81  * @param {string} category The category to query.
     82  * @return {Array.<string>} The commands, if any.
     83  */
     84 cvox.CommandStore.commandsForCategory = function(category) {
     85   var ret = [];
     86   for (var cmd in cvox.CommandStore.CMD_WHITELIST) {
     87     var struct = cvox.CommandStore.CMD_WHITELIST[cmd];
     88     if (category == struct.category) {
     89       ret.push(cmd);
     90     }
     91   }
     92   return ret;
     93 };
     94 
     95 
     96 /**
     97  * List of commands and their properties
     98  * @type {Object.<string, {forward: (undefined|boolean),
     99  *                         backward: (undefined|boolean),
    100  *                         announce: boolean,
    101  *                         category: (undefined|string),
    102  *                         findNext: (undefined|string),
    103  *                         doDefault: (undefined|boolean),
    104  *                         msgId: (undefined|string),
    105  *                         nodeList: (undefined|string),
    106  *                         platformFilter: (undefined|cvox.PlatformFilter),
    107  *                         skipInput: (undefined|boolean),
    108  *                         allowEvents: (undefined|boolean),
    109  *                         disallowContinuation: (undefined|boolean)
    110  *                         }>}
    111  *  forward: Whether this command points forward.
    112  *  backward: Whether this command points backward. If neither forward or
    113  *            backward are specified, it stays facing in the current direction.
    114  *  announce: Whether to call finishNavCommand and announce the current
    115  *            position after the command is done.
    116  *  findNext: The id from the map above if this command is used for
    117  *            finding next/previous of something.
    118  *  category: The message resource describing the command's category.
    119  *  doDefault: Whether to do the default action. This means that keys will be
    120  *             passed through to the usual DOM capture/bubble phases.
    121  *  msgId: The message resource describing the command.
    122  *  nodeList: The id from the map above if this command is used for
    123  *            showing a list of nodes.
    124  *  platformFilter: Specifies to which platforms this command applies. If left
    125  *                  undefined, the command applies to all platforms.
    126  *  skipInput: Explicitly skips this command when text input has focus.
    127  *             Defaults to false.
    128  *  disallowOOBE: Explicitly disallows this command when on chrome://oobe/*.
    129  *             Defaults to false.
    130  *  allowEvents: Allows EventWatcher to continue processing events which can
    131  * trump TTS.
    132  *  disallowContinuation: Disallows continuous read to proceed. Defaults to
    133  * false.
    134  */
    135 cvox.CommandStore.CMD_WHITELIST = {
    136   'toggleStickyMode': {announce: false,
    137                        msgId: 'toggle_sticky_mode',
    138                        'disallowOOBE': true,
    139                        category: 'modifier_keys'},
    140   'toggleKeyPrefix': {announce: false,
    141                       skipInput: true,
    142                       msgId: 'prefix_key',
    143                          'disallowOOBE': true,
    144                       category: 'modifier_keys'},
    145   'passThroughMode': {announce: false,
    146                       msgId: 'pass_through_key_description',
    147                       category: 'modifier_keys'},
    148 
    149   'stopSpeech': {announce: false,
    150                  disallowContinuation: true,
    151                  doDefault: true,
    152                  msgId: 'stop_speech_key',
    153                  category: 'controlling_speech'},
    154   'toggleChromeVox': {announce: false,
    155                       platformFilter: cvox.PlatformFilter.WML,
    156                       msgId: 'toggle_chromevox_active',
    157                       category: 'controlling_speech'},
    158   'decreaseTtsRate': {announce: false,
    159                       msgId: 'decrease_tts_rate',
    160                       category: 'controlling_speech'},
    161   'increaseTtsRate': {announce: false,
    162                       msgId: 'increase_tts_rate',
    163                       category: 'controlling_speech'},
    164   'decreaseTtsPitch': {announce: false,
    165                       msgId: 'decrease_tts_pitch',
    166                       category: 'controlling_speech'},
    167   'increaseTtsPitch': {announce: false,
    168                       msgId: 'increase_tts_pitch',
    169                       category: 'controlling_speech'},
    170   'decreaseTtsVolume': {announce: false,
    171                       msgId: 'decrease_tts_volume',
    172                       category: 'controlling_speech'},
    173   'increaseTtsVolume': {announce: false,
    174                       msgId: 'increase_tts_volume',
    175                       category: 'controlling_speech'},
    176   'cyclePunctuationEcho': {announce: false,
    177                            msgId: 'cycle_punctuation_echo',
    178                            category: 'controlling_speech'},
    179   'cycleTypingEcho': {announce: false,
    180                       msgId: 'cycle_typing_echo',
    181                       category: 'controlling_speech'},
    182 
    183 
    184   'toggleEarcons': {announce: true,
    185                     msgId: 'toggle_earcons',
    186                     category: 'controlling_speech'},
    187 
    188   'handleTab': {
    189     allowEvents: true,
    190     msgId: 'handle_tab_next',
    191     disallowContinuation: true,
    192     category: 'navigation'},
    193   'handleTabPrev': {
    194     allowEvents: true,
    195     msgId: 'handle_tab_prev',
    196     disallowContinuation: true,
    197     category: 'navigation'},
    198   'forward': {forward: true,
    199               announce: true,
    200               msgId: 'forward',
    201               category: 'navigation'},
    202   'backward': {backward: true,
    203                announce: true,
    204                msgId: 'backward',
    205                category: 'navigation'},
    206   'right': {forward: true,
    207             announce: true,
    208             msgId: 'right',
    209             category: 'navigation'},
    210   'left': {backward: true,
    211            announce: true,
    212            msgId: 'left',
    213            category: 'navigation'},
    214   'previousGranularity': {announce: true,
    215                           msgId: 'previous_granularity',
    216                           category: 'navigation'},
    217   'nextGranularity': {announce: true,
    218                           msgId: 'next_granularity',
    219                           category: 'navigation'},
    220 
    221   'previousCharacter': {backward: true,
    222                         announce: true,
    223                         msgId: 'previous_character',
    224                         skipInput: true,
    225                         category: 'navigation'},
    226   'nextCharacter': {forward: true,
    227                     announce: true,
    228                     msgId: 'next_character',
    229                     skipInput: true,
    230                     category: 'navigation'},
    231   'previousWord': {backward: true,
    232                         announce: true,
    233                         msgId: 'previous_word',
    234                         skipInput: true,
    235                         category: 'navigation'},
    236   'nextWord': {forward: true,
    237                     announce: true,
    238                     msgId: 'next_word',
    239                     skipInput: true,
    240                     category: 'navigation'},
    241   'previousLine': {backward: true,
    242                         announce: true,
    243                         msgId: 'previous_line',
    244                         category: 'navigation'},
    245   'nextLine': {forward: true,
    246                     announce: true,
    247                     msgId: 'next_line',
    248                     category: 'navigation'},
    249   'previousSentence': {backward: true,
    250                         announce: true,
    251                         msgId: 'previous_sentence',
    252                         skipInput: true,
    253                         category: 'navigation'},
    254   'nextSentence': {forward: true,
    255                     announce: true,
    256                     msgId: 'next_sentence',
    257                     skipInput: true,
    258                     category: 'navigation'},
    259   'previousObject': {backward: true,
    260                         announce: true,
    261                         msgId: 'previous_object',
    262                         skipInput: true,
    263                         category: 'navigation'},
    264   'nextObject': {forward: true,
    265                     announce: true,
    266                     msgId: 'next_object',
    267                     skipInput: true,
    268                     category: 'navigation'},
    269   'previousGroup': {backward: true,
    270                         announce: true,
    271                         msgId: 'previous_group',
    272                         skipInput: true,
    273                         category: 'navigation'},
    274   'nextGroup': {forward: true,
    275                     announce: true,
    276                     msgId: 'next_group',
    277                     skipInput: true,
    278                     category: 'navigation'},
    279 
    280   'jumpToTop': {forward: true,
    281                 announce: true,
    282                 msgId: 'jump_to_top',
    283                 category: 'navigation'
    284 },
    285   'jumpToBottom': {backward: true,
    286                    announce: true,
    287                    msgId: 'jump_to_bottom',
    288                    category: 'navigation'},
    289   // Intentionally uncategorized.
    290   'moveToStartOfLine': {forward: true, announce: true},
    291   'moveToEndOfLine': {backward: true, announce: true},
    292 
    293   'readFromHere': {forward: true,
    294                    announce: false,
    295                    msgId: 'read_from_here',
    296                    category: 'navigation'},
    297 
    298   'performDefaultAction': {disallowContinuation: true,
    299                            msgId: 'perform_default_action',
    300                            doDefault: true,
    301                            skipInput: true,
    302                            category: 'navigation'},
    303   'forceClickOnCurrentItem': {announce: true,
    304                               disallowContinuation: true,
    305                               allowEvents: true,
    306                               msgId: 'force_click_on_current_item',
    307                               category: 'navigation'},
    308   'forceDoubleClickOnCurrentItem': {announce: true,
    309                                     allowEvents: true,
    310                                     disallowContinuation: true},
    311 
    312   'readLinkURL': {announce: false,
    313                   msgId: 'read_link_url',
    314                   category: 'information'},
    315   'readCurrentTitle': {announce: false,
    316                        msgId: 'read_current_title',
    317                        category: 'information'},
    318   'readCurrentURL': {announce: false,
    319                      msgId: 'read_current_url',
    320                      category: 'information'},
    321 
    322   'fullyDescribe': {announce: false,
    323                     msgId: 'fully_describe',
    324                     category: 'information'},
    325   'speakTimeAndDate': {announce: false,
    326                        msgId: 'speak_time_and_date',
    327                        category: 'information'},
    328   'toggleSelection': {announce: true,
    329                       msgId: 'toggle_selection',
    330                       category: 'information'},
    331 
    332   'toggleSearchWidget': {announce: false,
    333                          disallowContinuation: true,
    334                          msgId: 'toggle_search_widget',
    335                          category: 'information'},
    336 
    337   'toggleKeyboardHelp': {announce: false,
    338                          disallowContinuation: true,
    339                          msgId: 'show_power_key',
    340                          category: 'help_commands'},
    341   'help': {announce: false,
    342            msgId: 'help',
    343            'disallowOOBE': true,
    344            disallowContinuation: true,
    345            category: 'help_commands'},
    346   'contextMenu': {announce: false,
    347                   disallowContinuation: true},
    348 
    349   'showOptionsPage': {announce: false,
    350                       disallowContinuation: true,
    351                       msgId: 'show_options_page',
    352                       'disallowOOBE': true,
    353                       category: 'help_commands'},
    354   'showKbExplorerPage': {announce: false,
    355                          disallowContinuation: true,
    356                          msgId: 'show_kb_explorer_page',
    357                          'disallowOOBE': true,
    358                          category: 'help_commands'},
    359 
    360 
    361   'showFormsList': {announce: false,
    362                     disallowContinuation: true,
    363                     nodeList: 'formField',
    364                     msgId: 'show_forms_list',
    365                     category: 'overview'},
    366   'showHeadingsList': {announce: false, nodeList: 'heading',
    367                        disallowContinuation: true,
    368                        msgId: 'show_headings_list',
    369                        category: 'overview'},
    370   'showLandmarksList': {announce: false, nodeList: 'landmark',
    371                         disallowContinuation: true,
    372                         msgId: 'show_landmarks_list',
    373                         category: 'overview'},
    374   'showLinksList': {announce: false, nodeList: 'link',
    375                     disallowContinuation: true,
    376                     msgId: 'show_links_list',
    377                     category: 'overview'},
    378   'showTablesList': {announce: false, nodeList: 'table',
    379                      disallowContinuation: true,
    380                      msgId: 'show_tables_list',
    381                      category: 'overview'},
    382 
    383   'nextArticle': {forward: true,
    384                   findNext: 'article'},
    385 
    386   'nextButton': {forward: true,
    387                  findNext: 'button',
    388                  msgId: 'next_button',
    389                  category: 'jump_commands'},
    390   'nextCheckbox': {forward: true,
    391                    findNext: 'checkbox',
    392                    msgId: 'next_checkbox',
    393                    category: 'jump_commands'},
    394   'nextComboBox': {forward: true,
    395                    findNext: 'combobox',
    396                    msgId: 'next_combo_box',
    397                    category: 'jump_commands'},
    398   'nextControl': {forward: true, findNext: 'control'},
    399   'nextEditText': {forward: true,
    400                    findNext: 'editText',
    401                    msgId: 'next_edit_text',
    402                    category: 'jump_commands'},
    403   'nextFormField': {forward: true,
    404                     findNext: 'formField',
    405                     msgId: 'next_form_field',
    406                     category: 'jump_commands'},
    407   'nextGraphic': {forward: true,
    408                   findNext: 'graphic',
    409                   msgId: 'next_graphic',
    410                   category: 'jump_commands'},
    411   'nextHeading': {forward: true,
    412                   findNext: 'heading',
    413                   msgId: 'next_heading',
    414                   category: 'jump_commands'},
    415   'nextHeading1': {forward: true,
    416                    findNext: 'heading1',
    417                    msgId: 'next_heading1',
    418                    category: 'jump_commands'},
    419   'nextHeading2': {forward: true,
    420                    findNext: 'heading2',
    421                    msgId: 'next_heading2',
    422                    category: 'jump_commands'},
    423   'nextHeading3': {forward: true,
    424                    findNext: 'heading3',
    425                    msgId: 'next_heading3',
    426                    category: 'jump_commands'},
    427   'nextHeading4': {forward: true,
    428                    findNext: 'heading4',
    429                    msgId: 'next_heading4',
    430                    category: 'jump_commands'},
    431   'nextHeading5': {forward: true,
    432                    findNext: 'heading5',
    433                    msgId: 'next_heading5',
    434                    category: 'jump_commands'},
    435   'nextHeading6': {forward: true,
    436                    findNext: 'heading6',
    437                    msgId: 'next_heading6',
    438                    category: 'jump_commands'},
    439 
    440   'nextLandmark': {forward: true,
    441                    findNext: 'landmark',
    442                    msgId: 'next_landmark',
    443                    category: 'jump_commands'},
    444   'nextLink': {forward: true,
    445                findNext: 'link',
    446                msgId: 'next_link',
    447                category: 'jump_commands'},
    448   'nextList': {forward: true,
    449                findNext: 'list',
    450                msgId: 'next_list',
    451                category: 'jump_commands'},
    452   'nextListItem': {forward: true,
    453                    findNext: 'listItem',
    454                    msgId: 'next_list_item',
    455                    category: 'jump_commands'},
    456   'nextMath': {forward: true,
    457                findNext: 'math',
    458                msgId: 'next_math',
    459                category: 'jump_commands'},
    460   'nextMedia': {forward: true,
    461                 findNext: 'media',
    462                 msgId: 'next_media',
    463                 category: 'jump_commands'},
    464   'nextRadio': {forward: true,
    465                 findNext: 'radio',
    466                 msgId: 'next_radio',
    467                 category: 'jump_commands'},
    468   'nextSection': {forward: true, findNext: 'section'},
    469   'nextSlider': {forward: true, findNext: 'slider'},
    470   'nextTable': {forward: true,
    471                 findNext: 'table',
    472                 msgId: 'next_table',
    473                 category: 'jump_commands'},
    474   'nextVisitedLink': {forward: true,
    475                 findNext: 'visitedLink',
    476                 msgId: 'next_visited_link',
    477                 category: 'jump_commands'},
    478 
    479 
    480   'previousArticle': {backward: true,
    481                   findNext: 'article'},
    482 
    483   'previousButton': {backward: true,
    484                  findNext: 'button',
    485                  msgId: 'previous_button',
    486                  category: 'jump_commands'},
    487   'previousCheckbox': {backward: true,
    488                    findNext: 'checkbox',
    489                    msgId: 'previous_checkbox',
    490                    category: 'jump_commands'},
    491   'previousComboBox': {backward: true,
    492                    findNext: 'combobox',
    493                    msgId: 'previous_combo_box',
    494                    category: 'jump_commands'},
    495   'previousControl': {backward: true, findNext: 'control'},
    496   'previousEditText': {backward: true,
    497                    findNext: 'editText',
    498                    msgId: 'previous_edit_text',
    499                    category: 'jump_commands'},
    500   'previousFormField': {backward: true,
    501                     findNext: 'formField',
    502                     msgId: 'previous_form_field',
    503                     category: 'jump_commands'},
    504   'previousGraphic': {backward: true,
    505                   findNext: 'graphic',
    506                   msgId: 'previous_graphic',
    507                   category: 'jump_commands'},
    508   'previousHeading': {backward: true,
    509                   findNext: 'heading',
    510                   msgId: 'previous_heading',
    511                   category: 'jump_commands'},
    512   'previousHeading1': {backward: true,
    513                    findNext: 'heading1',
    514                    msgId: 'previous_heading1',
    515                    category: 'jump_commands'},
    516   'previousHeading2': {backward: true,
    517                    findNext: 'heading2',
    518                    msgId: 'previous_heading2',
    519                    category: 'jump_commands'},
    520   'previousHeading3': {backward: true,
    521                    findNext: 'heading3',
    522                    msgId: 'previous_heading3',
    523                    category: 'jump_commands'},
    524   'previousHeading4': {backward: true,
    525                    findNext: 'heading4',
    526                    msgId: 'previous_heading4',
    527                    category: 'jump_commands'},
    528   'previousHeading5': {backward: true,
    529                    findNext: 'heading5',
    530                    msgId: 'previous_heading5',
    531                    category: 'jump_commands'},
    532   'previousHeading6': {backward: true,
    533                    findNext: 'heading6',
    534                    msgId: 'previous_heading6',
    535                    category: 'jump_commands'},
    536 
    537   'previousLandmark': {backward: true,
    538                    findNext: 'landmark',
    539                    msgId: 'previous_landmark',
    540                    category: 'jump_commands'},
    541   'previousLink': {backward: true,
    542                    findNext: 'link',
    543                    msgId: 'previous_link',
    544                    category: 'jump_commands'},
    545   'previousList': {backward: true,
    546                findNext: 'list',
    547                msgId: 'previous_list',
    548                category: 'jump_commands'},
    549   'previousListItem': {backward: true,
    550                    findNext: 'listItem',
    551                    msgId: 'previous_list_item',
    552                    category: 'jump_commands'},
    553   'previousMath': {backward: true,
    554                    findNext: 'math',
    555                    msgId: 'previous_math',
    556                    category: 'jump_commands'},
    557   'previousMedia': {backward: true,
    558                     findNext: 'media',
    559                     msgId: 'previous_media',
    560                     category: 'jump_commands'},
    561   'previousRadio': {backward: true,
    562                 findNext: 'radio',
    563                 msgId: 'previous_radio',
    564                 category: 'jump_commands'},
    565   'previousSection': {backward: true, findNext: 'section'},
    566   'previousSlider': {backward: true, findNext: 'slider'},
    567   'previousTable': {backward: true,
    568                 findNext: 'table',
    569                 msgId: 'previous_table',
    570                 category: 'jump_commands'},
    571   'previousVisitedLink': {backward: true,
    572                           findNext: 'visitedLink',
    573                           msgId: 'previous_visited_link',
    574                           category: 'jump_commands'},
    575 
    576 
    577   // Table Actions.
    578   'announceHeaders': {announce: false,
    579                       msgId: 'announce_headers',
    580                       category: 'tables'},
    581   'speakTableLocation': {announce: false,
    582                          msgId: 'speak_table_location',
    583                          category: 'tables'},
    584   'goToFirstCell': {announce: true,
    585                     msgId: 'skip_to_beginning',
    586                     category: 'tables'},
    587   'goToLastCell': {announce: true,
    588                    msgId: 'skip_to_end',
    589                    category: 'tables'},
    590   'goToRowFirstCell': {announce: true,
    591                        msgId: 'skip_to_row_beginning',
    592                        category: 'tables'},
    593   'goToRowLastCell': {announce: true,
    594                       msgId: 'skip_to_row_end',
    595                       category: 'tables'},
    596   'goToColFirstCell': {announce: true,
    597                        msgId: 'skip_to_col_beginning',
    598                        category: 'tables'},
    599   'goToColLastCell': {announce: true,
    600                       msgId: 'skip_to_col_end',
    601                       category: 'tables'},
    602   // These commands are left out of the options page because they involve
    603   // multiple, non-user configurable modifiers.
    604   'previousRow': {backward: true, announce: true, skipInput: true},
    605   'previousCol': {backward: true, announce: true, skipInput: true},
    606   'nextRow': {forward: true, announce: true, skipInput: true},
    607   'nextCol': {forward: true, announce: true, skipInput: true},
    608 
    609   // Generic Actions.
    610   'enterShifter': {announce: true,
    611                    msgId: 'enter_content',
    612                    category: 'navigation'},
    613   'exitShifter': {announce: true,
    614                   msgId: 'exit_content',
    615                   category: 'navigation'},
    616   'exitShifterContent': {announce: true},
    617 
    618   'openLongDesc': {announce: false,
    619                    msgId: 'open_long_desc',
    620                    category: 'information'},
    621 
    622   'pauseAllMedia': {announce: false,
    623                     msgId: 'pause_all_media',
    624                     category: 'information'},
    625 
    626   // Math specific commands.
    627   'toggleSemantics': {announce: false,
    628                       msgId: 'toggle_semantics',
    629                       category: 'information'},
    630 
    631   // Braille specific commands.
    632   'routing': {announce: false,
    633               allowEvents: true,
    634               msgId: 'braille_routing',
    635               category: 'braille'},
    636   'pan_left': {backward: true,
    637                announce: true,
    638                msgId: 'braille_pan_left',
    639                category: 'braille'},
    640   'pan_right': {forward: true,
    641                 announce: true,
    642                 msgId: 'braille_pan_right',
    643                 category: 'braille'},
    644   'line_up': {backward: true,
    645               announce: true,
    646               msgId: 'braille_line_up',
    647               category: 'braille'},
    648   'line_down': {forward: true,
    649                 announce: true,
    650                 msgId: 'braille_line_down',
    651                 category: 'braille'},
    652   'top': {forward: true,
    653                 announce: true,
    654                 msgId: 'braille_top',
    655                 category: 'braille'},
    656   'bottom': {backward: true,
    657                 announce: true,
    658                 msgId: 'braille_bottom',
    659                 category: 'braille'},
    660 
    661   // Developer commands.
    662   'enableConsoleTts': {announce: false,
    663                       msgId: 'enable_tts_log',
    664                       category: 'developer'},
    665   'toggleBrailleCaptions': {announce: false,
    666                             msgId: 'braille_captions',
    667                             category: 'developer'},
    668 
    669   'startHistoryRecording': {announce: false},
    670   'stopHistoryRecording': {announce: false},
    671   'autorunner': {announce: false},
    672 
    673   'debug': {announce: false},
    674 
    675   'nop': {announce: false}
    676 };
    677 
    678 
    679 /**
    680  * List of find next commands and their associated data.
    681  * @type {Object.<string, {predicate: string,
    682  *                         forwardError: string,
    683  *                         backwardError: string}>}
    684  *  predicate: The name of the predicate. This must be defined in DomPredicates.
    685  *  forwardError: The message id of the error string when moving forward.
    686  *  backwardError: The message id of the error string when moving backward.
    687  */
    688 cvox.CommandStore.NODE_INFO_MAP = {
    689   'checkbox': {predicate: 'checkboxPredicate',
    690                forwardError: 'no_next_checkbox',
    691                backwardError: 'no_previous_checkbox',
    692                typeMsg: 'aria_role_checkbox'},
    693   'radio': {predicate: 'radioPredicate',
    694             forwardError: 'no_next_radio_button',
    695             backwardError: 'no_previous_radio_button',
    696             typeMsg: 'aria_role_radio'},
    697   'slider': {predicate: 'sliderPredicate',
    698              forwardError: 'no_next_slider',
    699              backwardError: 'no_previous_slider',
    700              typeMsg: 'aria_role_slider'},
    701   'graphic': {predicate: 'graphicPredicate',
    702               forwardError: 'no_next_graphic',
    703               backwardError: 'no_previous_graphic',
    704               typeMsg: 'UNUSED'},
    705   'article': {predicate: 'articlePredicate',
    706              forwardError: 'no_next_ARTICLE',
    707              backwardError: 'no_previous_ARTICLE',
    708              typeMsg: 'TAG_ARTICLE'},
    709   'button': {predicate: 'buttonPredicate',
    710              forwardError: 'no_next_button',
    711              backwardError: 'no_previous_button',
    712              typeMsg: 'aria_role_button'},
    713   'combobox': {predicate: 'comboBoxPredicate',
    714                forwardError: 'no_next_combo_box',
    715                backwardError: 'no_previous_combo_box',
    716                typeMsg: 'aria_role_combobox'},
    717   'editText': {predicate: 'editTextPredicate',
    718                forwardError: 'no_next_edit_text',
    719                backwardError: 'no_previous_edit_text',
    720                typeMsg: 'input_type_text'},
    721   'heading': {predicate: 'headingPredicate',
    722               forwardError: 'no_next_heading',
    723               backwardError: 'no_previous_heading',
    724               typeMsg: 'aria_role_heading'},
    725   'heading1': {predicate: 'heading1Predicate',
    726                forwardError: 'no_next_heading_1',
    727                backwardError: 'no_previous_heading_1'},
    728   'heading2': {predicate: 'heading2Predicate',
    729                forwardError: 'no_next_heading_2',
    730                backwardError: 'no_previous_heading_2'},
    731   'heading3': {predicate: 'heading3Predicate',
    732                forwardError: 'no_next_heading_3',
    733                backwardError: 'no_previous_heading_3'},
    734   'heading4': {predicate: 'heading4Predicate',
    735                forwardError: 'no_next_heading_4',
    736                backwardError: 'no_previous_heading_4'},
    737   'heading5': {predicate: 'heading5Predicate',
    738                forwardError: 'no_next_heading_5',
    739                backwardError: 'no_previous_heading_5'},
    740   'heading6': {predicate: 'heading6Predicate',
    741                forwardError: 'no_next_heading_6',
    742                backwardError: 'no_previous_heading_6'},
    743 
    744   'link': {predicate: 'linkPredicate',
    745            forwardError: 'no_next_link',
    746            backwardError: 'no_previous_link',
    747            typeMsg: 'aria_role_link'},
    748   'table': {predicate: 'tablePredicate',
    749             forwardError: 'no_next_table',
    750             backwardError: 'no_previous_table',
    751             typeMsg: 'table_strategy'},
    752   'visitedLink': {predicate: 'visitedLinkPredicate',
    753             forwardError: 'no_next_visited_link',
    754             backwardError: 'no_previous_visited_link',
    755             typeMsg: 'tag_link'},
    756   'list': {predicate: 'listPredicate',
    757            forwardError: 'no_next_list',
    758            backwardError: 'no_previous_list',
    759            typeMsg: 'aria_role_list'},
    760   'listItem': {predicate: 'listItemPredicate',
    761                forwardError: 'no_next_list_item',
    762                backwardError: 'no_previous_list_item',
    763                typeMsg: 'aria_role_listitem'},
    764   'formField': {predicate: 'formFieldPredicate',
    765                 forwardError: 'no_next_form_field',
    766                 backwardError: 'no_previous_form_field',
    767                 typeMsg: 'aria_role_form'},
    768   'landmark': {predicate: 'landmarkPredicate',
    769                forwardError: 'no_next_landmark',
    770                backwardError: 'no_previous_landmark',
    771                typeMsg: 'role_landmark'},
    772   'math': {predicate: 'mathPredicate',
    773            forwardError: 'no_next_math',
    774            backwardError: 'no_previous_math',
    775            typeMsg: 'math_expr'},
    776   'media': {predicate: 'mediaPredicate',
    777             forwardError: 'no_next_media_widget',
    778             backwardError: 'no_previous_media_widget'},
    779   'section': {predicate: 'sectionPredicate',
    780            forwardError: 'no_next_section',
    781            backwardError: 'no_previous_section'},
    782   'control': {predicate: 'controlPredicate',
    783            forwardError: 'no_next_control',
    784            backwardError: 'no_previous_control'}
    785 };
    786