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  * @fileoverview Some utilities for defining what groups are.
      7  */
      8 
      9 
     10 goog.provide('cvox.GroupUtil');
     11 
     12 goog.require('cvox.AriaUtil');
     13 goog.require('cvox.DomUtil');
     14 
     15 
     16 /**
     17  * If a node contains more characters than this, it should not be treated
     18  * as a leaf node by the smart navigation algorithm.
     19  *
     20  * This number was determined by looking at the average number of
     21  * characters in a paragraph:
     22  * http://www.fullondesign.co.uk/design/usability/
     23  * 285-how-many-characters-per-a-page-is-normal.htm
     24  * and then trying it out on a few popular websites (CNN, BBC,
     25  * Google Search, etc.) and making sure it made sense.
     26  * @type {number}
     27  * @private
     28  * @const
     29  */
     30 cvox.GroupUtil.MAX_CHARCOUNT_ = 1500;
     31 
     32 
     33 /**
     34  * If a node contains any of these elements, it should not be treated
     35  * as a leaf node by the smart navigation algorithm.
     36  * @type {string}
     37  * @private
     38  * @const
     39  */
     40 cvox.GroupUtil.BREAKOUT_SELECTOR_ = 'blockquote,' +
     41     'button,' +
     42     'code,' +
     43     'form,' +
     44     'frame,' +
     45     'h1,' +
     46     'h2,' +
     47     'h3,' +
     48     'h4,' +
     49     'h5,' +
     50     'h6,' +
     51     'hr,' +
     52     'iframe,' +
     53     'input,' +
     54     'object,' +
     55     'ol,' +
     56     'p,' +
     57     'pre,' +
     58     'select,' +
     59     'table,' +
     60     'tr,' +
     61     'ul,' +
     62     'math,' +
     63   // This takes care of MathJax expressions.
     64     'span.math,' +
     65 // TODO (sorge) Do we want to group all math or only display math?
     66 //    '[mode="display"],' +
     67     // Aria widget roles
     68     '[role~="alert ' +
     69     'alertdialog ' +
     70     'button ' +
     71     'checkbox ' +
     72     'combobox ' +
     73     'dialog ' +
     74     'log ' +
     75     'marquee ' +
     76     'menubar ' +
     77     'progressbar ' +
     78     'radio ' +
     79     'radiogroup ' +
     80     'scrollbar ' +
     81     'slider ' +
     82     'spinbutton ' +
     83     'status ' +
     84     'tab ' +
     85     'tabpanel ' +
     86     'textbox ' +
     87     'toolbar ' +
     88     'tooltip ' +
     89     'treeitem ' +
     90     // Aria structure roles
     91     'article ' +
     92     'document ' +
     93     'group ' +
     94     'heading ' +
     95     'img ' +
     96     'list ' +
     97     'math ' +
     98     'region ' +
     99     'row ' +
    100     'separator"]';
    101 
    102 
    103 /**
    104  * Returns true if this is a leaf node for groups.
    105  * true for a node => true for all child nodes
    106  * true if node has no children
    107  * @param {!Node} node The node to check.
    108  * @return {boolean} true if this is at the "leaf node" level or lower
    109  * for this granularity.
    110  */
    111 cvox.GroupUtil.isLeafNode = function(node) {
    112   // TODO (stoarca): Write test to make sure that this function satisfies
    113   // the restriction given above.
    114   if (node.tagName == 'LABEL') {
    115     return cvox.DomUtil.isLeafNode(node);
    116   }
    117   if (cvox.DomUtil.isLeafNode(node)) {
    118     return true;
    119   }
    120 
    121   if (!cvox.DomUtil.isSemanticElt(node)) {
    122     var breakingNodes = node.querySelectorAll(
    123         cvox.GroupUtil.BREAKOUT_SELECTOR_);
    124 
    125     for (var i = 0; i < breakingNodes.length; ++i) {
    126       if (cvox.DomUtil.hasContent(breakingNodes[i])) {
    127         return false;
    128       }
    129     }
    130   }
    131 
    132   if (cvox.AriaUtil.isCompositeControl(node) &&
    133       !cvox.DomUtil.isFocusable(node)) {
    134     return false;
    135   }
    136 
    137   var content = cvox.DomUtil.collapseWhitespace(
    138       cvox.DomUtil.getValue(node) + ' ' +
    139       cvox.DomUtil.getName(node));
    140   if (content.length > cvox.GroupUtil.MAX_CHARCOUNT_) {
    141     return false;
    142   }
    143 
    144   if (content.replace(/\s/g, '') === '') {
    145     // Text only contains whitespace
    146     return false;
    147   }
    148 
    149   return true;
    150 };
    151