GetElementsByRole

Posted on March 22, 2009

/**
 * Returns elements with a particular WAI-ARIA role or roles
 *
 * @param node root     The node to start searching from (defaults
 *                      to document.body)
 * @param string role   Can be any of:
 *                        - '*' to find all roles
 *                        - The name of a particular role
 *                        - An all-caps role category: LANDMARK,
 *                          INPUT, UI, DOCUMENT or APPLICATION 
 *                        - Multiple roles and/or categories
 *                          separated by '|'
 *
 * @return object       An object indexed by role names. If no
 *                      roles are found, returns null.
 */

function getElementsByRole(root, role){
  if (arguments.length == 1) {
    role = root;
    root = document.body;
  }

  var roleArray = role.split('|');
  var roleRegexString = '';
  var findAllRoles = false;

  for (var i=0; i<roleArray.length && !findAllRoles; i++) {
    roleRegexString += roleRegexString ? '|' : '';
    switch (roleArray[i]) {
    case '*':
      roleRegexString = '.*';
      findAllRoles = true;
      break;
    case 'LANDMARK':
      roleRegexString += '^(application|banner|complementary|contentinfo|main|navigation|search)$';
      break;
    case 'INPUT':
      roleRegexString += '^((check|combo|list|text)box|option|radio(group)?|slider|spinbutton)$';
      break;
    case 'UI':
      roleRegexString += '^(button|link|menu(bar|item(checkbox|radio)?)?|tab(list|panel)?|tool(bar|tip)|tree(grid|item)?)$';
      break;
    case 'DOCUMENT':
      roleRegexString += '^(article|(column|row)header|definition|directory|document|grid(cell)?|group|heading|img|list(item)?|math|note|presentation|region|row|separator)$';
      break;
    case 'APPLICATION':
      roleRegexString += '^(alert(dialog)?|dialog|log|marquee|progressbar|status|timer)$';
      break;
    default:
      roleRegexString += roleArray[i];
    }
  }

  roleRegex = new RegExp(roleRegexString);

  var roles = {};
  var roleCount = 0;

  var getRoles = function(el) {
    if (!el.nodeType || el.nodeType != 1)
      return; // Not an element

    var role = el.getAttribute('role');

    if (role) {
      var foundRole = roleRegex.exec(role) ;

      if (foundRole) {
        if (!roles[foundRole[0]]) {
          roles[foundRole[0]] = [];
          roleCount++;
        }

        roles[foundRole[0]].push(el);
      }
    }

    for (var i=0; i<el.childNodes.length; i++){
      getRoles(el.childNodes[i]);
    }
  };

  getRoles(root);
  return roleCount ? roles : null;
}

The function serves as the basis for this Document Landmarks bookmarklet.

Comments

There are no comments yet.

Submit a comment