Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: chrome/browser/resources/access_chromevox/common/dom_util.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/access_chromevox/common/dom_util.js
===================================================================
--- chrome/browser/resources/access_chromevox/common/dom_util.js (revision 0)
+++ chrome/browser/resources/access_chromevox/common/dom_util.js (revision 0)
@@ -0,0 +1,837 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A collection of JavaScript utilities used to simplify working
+ * with the DOM.
+ */
+
+
+goog.provide('cvox.DomUtil');
+
+goog.require('cvox.AriaUtil');
+goog.require('cvox.XpathUtil');
+
+/**
+ * Create the namespace
+ * @constructor
+ */
+cvox.DomUtil = function() {
+};
+
+
+/**
+ * @type {Object}
+ */
+cvox.DomUtil.INPUT_TYPE_TO_INFORMATION_TABLE = {
+ 'button' : 'Button',
+ 'checkbox' : 'Check box',
+ 'color' : 'Color picker',
+ 'datetime' : 'Date time control',
+ 'datetime-local' : 'Date time control',
+ 'date' : 'Date control',
+ 'email' : 'Edit text for email',
+ 'file' : 'File selection',
+ 'hidden' : '',
+ 'image' : 'Button',
+ 'month' : 'Month control',
+ 'number' : 'Edit text numeric only',
+ 'password' : 'Password edit text',
+ 'radio' : 'Radio button',
+ 'range' : 'Slider',
+ 'reset' : 'Reset',
+ 'search' : 'Edit text for search',
+ 'submit' : 'Button',
+ 'tel' : 'Edit text for telephone number',
+ 'text' : 'Edit text',
+ 'url' : 'Edit text for URL',
+ 'week' : 'Week of the year control'
+};
+/**
+ * @type {Object}
+ */
+cvox.DomUtil.TAG_TO_INFORMATION_TABLE = {
+ 'A' : 'Link',
+ 'H1' : 'Heading 1',
+ 'H2' : 'Heading 2',
+ 'H3' : 'Heading 3',
+ 'H4' : 'Heading 4',
+ 'H5' : 'Heading 5',
+ 'H6' : 'Heading 6',
+ 'BUTTON' : 'Button',
+ 'SELECT' : 'Combo box',
+ 'TEXTAREA' : 'Text area'
+};
+
+
+/**
+ * Determines whether or not a style is invisible according to any CSS
+ * criteria that can hide a node.
+ *
+ * @param {Object} style An object's style.
+ * @return {boolean} True if the style is invisible.
+ */
+cvox.DomUtil.isInvisibleStyle = function(style) {
+ if (!style) {
+ return false;
+ }
+ if (style.display == 'none') {
+ return true;
+ }
+ if (style.visibility == 'hidden') {
+ return true;
+ }
+ if (style.opacity == 0) {
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Determines whether or not a node is a leaf node.
+ *
+ * @param {Node} node The node to be checked.
+ * @return {boolean} True if the node is a leaf node.
+ */
+cvox.DomUtil.isLeafNode = function(node) {
+ // TODO (clchen): account for widgets that should be treated as leaf nodes.
+ if (!node.firstChild) {
+ return true;
+ }
+ // Think of hidden nodes as spacer nodes; leaf node with no content.
+ if (node.nodeType == 1) { // nodeType:1 == ELEMENT_NODE
+ var style = document.defaultView.getComputedStyle(node, null);
+ if (cvox.DomUtil.isInvisibleStyle(style)) {
+ return true;
+ }
+ }
+ if (cvox.AriaUtil.isHidden(node)) {
+ return true;
+ }
+ if (node.tagName) {
+ if (node.tagName == 'SELECT') {
+ return true;
+ }
+ if (node.tagName == 'TEXTAREA') {
+ return true;
+ }
+ if (node.tagName == 'LABEL') {
+ return true;
+ }
+ }
+ if (cvox.DomUtil.getTitle(node)) {
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Determines whether or not a node is or is the descendant of a node
+ * with a particular tag or class name.
+ *
+ * @param {Node} node The node to be checked.
+ * @param {?string} tagName The tag to check for, or null if the tag
+ * doesn't matter.
+ * @param {?string=} className The class to check for, or null if the class
+ * doesn't matter.
+ * @return {boolean} True if the node or one of its ancestor has the specified
+ * tag.
+ */
+cvox.DomUtil.isDescendantOf = function(node, tagName, className) {
+ while (node) {
+
+ if (tagName && className &&
+ (node.tagName && (node.tagName == tagName)) &&
+ (node.className && (node.className == className))) {
+ return true;
+ } else if (tagName && !className &&
+ (node.tagName && (node.tagName == tagName))) {
+ return true;
+ } else if (!tagName && className &&
+ (node.className && (node.className == className))) {
+ return true;
+ }
+ node = node.parentNode;
+ }
+ return false;
+};
+
+
+/**
+ * Determines whether or not a node is or is the descendant of another node.
+ *
+ * @param {Object} node The node to be checked.
+ * @param {Object} ancestor The node to see if it's a descendant of.
+ * @return {boolean} True if the node is ancestor or is a descendant of it.
+ */
+cvox.DomUtil.isDescendantOfNode = function(node, ancestor) {
+ while (node && ancestor) {
+ if (node == ancestor) {
+ return true;
+ }
+ node = node.parentNode;
+ }
+ return false;
+};
+
+/**
+ * Get the label of a node.
+ *
+ * Not recursive.
+ *
+ * @param {Node} node The node to get the title from.
+ * @param {boolean} useHeuristics Whether or not to use heuristics to guess at
+ * the label if one is not explicitly set in the DOM.
+ * @return {string} The label of the node.
+ */
+cvox.DomUtil.getLabel = function(node, useHeuristics) {
+ var label = '';
+ if (!node) {
+ return '';
+ }
+ // Find any labels that are associated with this text control.
+ // aria-labelledby takes precedence and overrides any label for= elements.
+ if (node.hasAttribute && node.hasAttribute('aria-labelledby')) {
+ var labelNodeIds = node.getAttribute('aria-labelledby').split(' ');
+ for (var labelNodeId, i = 0; labelNodeId = labelNodeIds[i]; i++) {
+ var labelNode = document.getElementById(labelNodeId);
+ label += cvox.DomUtil.getText(labelNode) + ' ';
+ }
+ } else if (node && node.id) {
+ var labels = cvox.XpathUtil.evalXPath('//label[@for="' +
+ node.id + '"]', document.body);
+ if (labels.length > 0) {
+ label += cvox.DomUtil.getText(labels[0]) + ' ';
+ }
+ }
+
+ // If no description has been found yet and heuristics are enabled,
+ // then try getting the content from the previous node.
+ if (useHeuristics && (label.length < 1)) {
+ var tempNode = cvox.DomUtil.previousLeafNode(node);
+ while (tempNode && !cvox.DomUtil.hasContent(tempNode)) {
+ tempNode = cvox.DomUtil.previousLeafNode(tempNode);
+ }
+ if (tempNode) {
+ if (!cvox.DomUtil.isControl(tempNode)) {
+ label += cvox.DomUtil.getText(tempNode) + ' ';
+ }
+ }
+ }
+
+ return label;
+};
+
+/**
+ * Get the title of a node. In many cases this is equivalent to the
+ * text of the node, but it can be overridden by a title tag or alt tag,
+ * and for some form controls (like submit buttons) the title is actually
+ * the value.
+ *
+ * Not recursive.
+ *
+ * @param {Node} node The node to get the title from.
+ * @return {string} The title of the node.
+ */
+cvox.DomUtil.getTitle = function(node) {
+ if (node.constructor == Text) {
+ return node.data;
+ } else if (node.constructor == HTMLImageElement) {
+ return cvox.DomUtil.getImageTitle(node);
+ } else if (node.hasAttribute && node.hasAttribute('title')) {
+ return node.getAttribute('title');
+ } else if (node.constructor == HTMLInputElement) {
+ if (node.type == 'image') {
+ return cvox.DomUtil.getImageTitle(node);
+ } else if (node.type == 'submit') {
+ if (node.hasAttribute && node.hasAttribute('value')) {
+ return node.getAttribute('value');
+ } else {
+ return 'Submit';
+ }
+ } else if (node.type == 'reset') {
+ if (node.hasAttribute && node.hasAttribute('value')) {
+ return node.getAttribute('value');
+ } else {
+ return 'Reset';
+ }
+ }
+ }
+ return '';
+};
+
+/**
+ * Get the text value of a node: the selected value of a select control or the
+ * current text of a text control. Does not return the state of a checkbox
+ * or radio button.
+ *
+ * Not recursive.
+ *
+ * @param {Node} node The node to get the value from.
+ * @return {String} The value of the node.
+ */
+cvox.DomUtil.getValue = function(node) {
+ if (node.constructor == HTMLSelectElement) {
+ if (node.selectedIndex >= 0 &&
+ node.selectedIndex < node.options.length) {
+ return node.options[node.selectedIndex].text + '';
+ } else {
+ return '';
+ }
+ }
+
+ if (node.constructor == HTMLTextAreaElement) {
+ return node.value;
+ }
+
+ if (node.constructor == HTMLInputElement) {
+ switch (node.type) {
+ // Returning '' for the submit button since it is covered by getText.
+ case 'hidden':
+ case 'image':
+ case 'submit':
+ case 'reset':
+ case 'checkbox':
+ case 'radio':
+ return '';
+ case 'password':
+ return node.value.replace(/./g, '*');
+ default:
+ return node.value;
+ }
+ }
+
+ return '';
+};
+
+
+/**
+ * Given a node, return its complete text as a string. This is recursive;
+ * it will extract the text from all child nodes and concatenate it,
+ * removing extraneous whitespace.
+ *
+ * This is similar to accessing the textContent property of a node, but
+ * that doesn't handle nodes that override the text with a title attribute,
+ * or nodes that can have both a title and a value.
+ *
+ * This function concatenates the value and title of a node (value first,
+ * if both are present) and recursively concatenates the text of children
+ * of any node that doesn't have either a value or title.
+
+ * @param {Node} node The node to extract the text from.
+ * @return {string} The text of the node.
+ */
+cvox.DomUtil.getText = function(node) {
+ var title = cvox.DomUtil.getTitle(node);
+ var value = cvox.DomUtil.getValue(node);
+ var text = '';
+ if (title && value) {
+ text = value + ' ' + title;
+ } else if (title) {
+ text = title;
+ } else if (value) {
+ text = value;
+ } else if (!cvox.DomUtil.isControl(node)) {
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ var childStyle = window.getComputedStyle(child, null);
+ if (!cvox.DomUtil.isInvisibleStyle(childStyle) &&
+ !cvox.AriaUtil.isHidden(node)) {
+ text += ' ' + cvox.DomUtil.getText(child);
+ }
+ }
+ }
+ // Remove all whitespace from the beginning and end, and collapse all
+ // inner strings of whitespace to a single space.
+ text = text.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
+
+ return text;
+};
+
+
+/**
+ * Given an image node, return its title as a string. The preferred title
+ * is always the alt text, and if that's not available, then the title
+ * attribute. If neither of those are available, it attempts to construct
+ * a title from the filename, and if all else fails returns the word Image.
+ * @param {Node} node The image node.
+ * @return {string} The title of the image.
+ */
+cvox.DomUtil.getImageTitle = function(node) {
+ var text;
+ if (node.hasAttribute('alt')) {
+ text = node.alt;
+ } else if (node.hasAttribute('title')) {
+ text = node.title;
+ } else {
+ var url = node.src;
+ if (url.substring(0, 4) != 'data') {
+ var filename = url.substring(
+ url.lastIndexOf('/') + 1, url.lastIndexOf('.'));
+
+ // Hack to not speak the filename if it's ridiculously long.
+ if (filename.length >= 1 && filename.length <= 16) {
+ text = filename + ' Image';
+ } else {
+ text = 'Image';
+ }
+ } else {
+ text = 'Image';
+ }
+ }
+ return text;
+};
+
+
+/**
+ * Determines whether or not a node has content.
+ *
+ * @param {Node} node The node to be checked.
+ * @return {boolean} True if the node has content.
+ */
+cvox.DomUtil.hasContent = function(node) {
+ // nodeType:8 == COMMENT_NODE
+ if (node.nodeType == 8) {
+ return false;
+ }
+
+ // Exclude anything in the head
+ if (cvox.DomUtil.isDescendantOf(node, 'HEAD')) {
+ return false;
+ }
+
+ // Exclude script nodes
+ if (cvox.DomUtil.isDescendantOf(node, 'SCRIPT')) {
+ return false;
+ }
+
+ // Exclude noscript nodes
+ if (cvox.DomUtil.isDescendantOf(node, 'NOSCRIPT')) {
+ return false;
+ }
+
+ // Exclude style nodes that have been dumped into the body
+ if (cvox.DomUtil.isDescendantOf(node, 'STYLE')) {
+ return false;
+ }
+
+ // Check the style to exclude undisplayed/hidden nodes
+ var closestStyledParent = node;
+ // nodeType:3 == TEXT_NODE
+ while (closestStyledParent && (closestStyledParent.nodeType == 3)) {
+ closestStyledParent = closestStyledParent.parentNode;
+ }
+ if (closestStyledParent) {
+ var style =
+ document.defaultView.getComputedStyle(closestStyledParent, null);
+ if (cvox.DomUtil.isInvisibleStyle(style)) {
+ return false;
+ }
+ // TODO (clchen, raman): Look into why WebKit has a problem here.
+ // The issue is that getComputedStyle does not always return the correct
+ // result; manually going up the parent chain sometimes produces a different
+ // result than just using getComputedStyle.
+ var tempNode = closestStyledParent;
+ while (tempNode && tempNode.tagName != 'BODY') {
+ style = document.defaultView.getComputedStyle(tempNode, null);
+ if (cvox.DomUtil.isInvisibleStyle(style)) {
+ return false;
+ }
+ tempNode = tempNode.parentNode;
+ }
+ }
+
+ // Ignore anything that is hidden by ARIA
+ if (cvox.AriaUtil.isHidden(node)) {
+ return false;
+ }
+
+ // We need to speak controls, including those with no value entered. We
+ // therefore treat visible controls as if they had content, and return true
+ // below.
+ if (cvox.DomUtil.isControl(node)) {
+ return true;
+ }
+
+ var text = cvox.DomUtil.getText(node);
+ if (text === '') {
+ // Text only contains whitespace
+ return false;
+ }
+
+ return true;
+};
+
+/**
+ * Returns a list of all the ancestors of a given node.
+ *
+ * @param {Object} targetNode The node to get ancestors for.
+ * @return {Object} An array of ancestors for the targetNode.
+ */
+cvox.DomUtil.getAncestors = function(targetNode) {
+ var ancestors = new Array();
+ while (targetNode) {
+ ancestors.push(targetNode);
+ targetNode = targetNode.parentNode;
+ }
+ ancestors.reverse();
+ while (ancestors.length && !ancestors[0].tagName && !ancestors[0].nodeValue) {
+ ancestors.shift();
+ }
+ return ancestors;
+};
+
+/**
+ * Compares Ancestors of A with Ancestors of B and returns
+ * the index value in B at which B diverges from A.
+ * If there is no divergence, the result will be -1.
+ * Note that if B is the same as A except B has more nodes
+ * even after A has ended, that is considered a divergence.
+ * The first node that B has which A does not have will
+ * be treated as the divergence point.
+ *
+ * @param {Object} ancestorsA The array of ancestors for Node A.
+ * @param {Object} ancestorsB The array of ancestors for Node B.
+ * @return {number} The index of the divergence point (the first node that B has
+ * which A does not have in B's list of ancestors).
+ */
+cvox.DomUtil.compareAncestors = function(ancestorsA, ancestorsB) {
+ var i = 0;
+ while (ancestorsA[i] && ancestorsB[i] && (ancestorsA[i] == ancestorsB[i])) {
+ i++;
+ }
+ if (!ancestorsA[i] && !ancestorsB[i]) {
+ i = -1;
+ }
+ return i;
+};
+
+/**
+ * Returns an array of ancestors that are unique for the currentNode when
+ * compared to the previousNode. Having such an array is useful in generating
+ * the node information (identifying when interesting node boundaries have been
+ * crossed, etc.).
+ *
+ * @param {Object} previousNode The previous node.
+ * @param {Object} currentNode The current node.
+ * @return {Array.<Node>} An array of unique ancestors for the current node.
+ */
+cvox.DomUtil.getUniqueAncestors = function(previousNode, currentNode) {
+ var prevAncestors = cvox.DomUtil.getAncestors(previousNode);
+ var currentAncestors = cvox.DomUtil.getAncestors(currentNode);
+ var divergence = cvox.DomUtil.compareAncestors(prevAncestors,
+ currentAncestors);
+ return currentAncestors.slice(divergence);
+};
+
+/**
+ * Returns a string of basic information about the target node.
+ * This information is only about the node itself and does not take into
+ * account any of the node's ancestors.
+ *
+ * @param {Object} targetNode The node to get information about.
+ * @return {string} A string of basic information about the current node.
+ */
+cvox.DomUtil.getBasicNodeInformation = function(targetNode) {
+ var info = cvox.DomUtil.getBasicNodeRole(targetNode);
+ if (info.length > 0) {
+ info = info + ' ' + cvox.DomUtil.getBasicNodeState(targetNode);
+ }
+ return info;
+};
+
+/**
+ * Returns a string to be presented to the user that identifies what the
+ * targetNode's role is.
+ * ARIA roles are given priority; if there is no ARIA role set, the role
+ * will be determined by the HTML tag for the node.
+ *
+ * @param {Object} targetNode The node to get the role name for.
+ * @return {string} The role name for the targetNode.
+ */
+cvox.DomUtil.getBasicNodeRole = function(targetNode) {
+ var info;
+ info = cvox.AriaUtil.getRoleName(targetNode);
+ if (!info) {
+ if (targetNode.tagName == 'INPUT') {
+ info = cvox.DomUtil.INPUT_TYPE_TO_INFORMATION_TABLE[targetNode.type];
+ } else {
+ info = cvox.DomUtil.TAG_TO_INFORMATION_TABLE[targetNode.tagName];
+ }
+ }
+ if (!info) {
+ info = '';
+ }
+ return info;
+};
+
+/**
+ * Returns a string that gives information about the state of the targetNode.
+ *
+ * @param {Object} targetNode The node to get the state information for.
+ * @return {string} The status information about the node.
+ */
+cvox.DomUtil.getBasicNodeState = function(targetNode) {
+ var info;
+ info = cvox.AriaUtil.getState(targetNode);
+ if (!info) {
+ info = '';
+ } else {
+ info = info + ' ';
+ }
+
+ if (targetNode.tagName == 'INPUT') {
+ if (targetNode.type == 'checkbox' || targetNode.type == 'radio') {
+ if (targetNode.checked) {
+ info = info + ' checked';
+ } else {
+ info = info + ' not checked';
+ }
+ }
+ } else if (targetNode.tagName == 'SELECT') {
+ info = info + ' ' + (targetNode.selectedIndex + 1) + ' of ' +
+ targetNode.options.length;
+ }
+
+ return info;
+};
+
+
+/**
+ * Returns a string of detailed information given an array of
+ * ancestor nodes.
+ *
+ * @param {Object} ancestorsArray An array of ancestor nodes.
+ * @return {string} A string of detailed information given the
+ * array of ancestor nodes.
+ */
+cvox.DomUtil.getInformationFromAncestors = function(ancestorsArray) {
+ var info = '';
+ for (var i = 0, node; node = ancestorsArray[i]; i++) {
+ var nodeInfo = cvox.DomUtil.getBasicNodeInformation(node);
+ if (nodeInfo.length > 0) {
+ info = info + ' ' + nodeInfo;
+ }
+ }
+ return info;
+};
+
+
+/**
+ * Sets the browser focus to the targetNode or its closest ancestor that is
+ * able to get focus.
+ *
+ * @param {Object} targetNode The node to move the browser focus to.
+ */
+cvox.DomUtil.setFocus = function(targetNode) {
+ while (targetNode && ((typeof(targetNode.tabIndex) == 'undefined') ||
+ (targetNode.tabIndex == -1))) {
+ // If the target is a label for a control, focus the control.
+ if (targetNode.tagName && (targetNode.tagName == 'LABEL')) {
+ if (targetNode.htmlFor && document.getElementById(targetNode.htmlFor)) {
+ targetNode = document.getElementById(targetNode.htmlFor);
+ } else {
+ // Handle the case if a label is wrapping a control
+ var inputElems = targetNode.getElementsByTagName('INPUT');
+ if (inputElems && (inputElems.length > 0)) {
+ // In case there are multiple controls, focus on the first one.
+ // The user can always read through to the next control.
+ targetNode = inputElems[0];
+ } else {
+ // No wrapped controls found. In this case, keep moving
+ // because it means the page author was misusing label
+ // and failed to associate it with anything.
+ targetNode = targetNode.parentNode;
+ }
+ }
+ } else {
+ targetNode = targetNode.parentNode;
+ }
+
+ }
+ if (targetNode && (typeof(targetNode.tabIndex) != 'undefined') &&
+ (targetNode.tabIndex != -1)) {
+ targetNode.focus();
+ } else {
+ if (document.activeElement && (document.activeElement.tagName != 'BODY')) {
+ // Chrome will lose the selection if there is a blur, even if the blur
+ // does not touch the selection. To work around this, backup the
+ // selection, do the blur, then restore the selection.
+ var sel = window.getSelection();
+ if (sel.rangeCount > 0) {
+ var range = sel.getRangeAt(0);
+ document.activeElement.blur();
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+ }
+ }
+};
+
+/**
+ * Checks if the targetNode is still attached to the document.
+ * A node can become detached because of AJAX changes.
+ *
+ * @param {Object} targetNode The node to check.
+ * @return {boolean} True if the targetNode is still attached.
+ */
+cvox.DomUtil.isAttachedToDocument = function(targetNode) {
+ while (targetNode) {
+ if (targetNode.tagName && (targetNode.tagName == 'HTML')) {
+ return true;
+ }
+ targetNode = targetNode.parentNode;
+ }
+ return false;
+};
+
+
+/**
+ * Dispatches a left click event on the element that is the targetNode.
+ * Clicks go in the sequence of mousedown, mouseup, and click.
+ * @param {Node} targetNode The target node of this operation.
+ * @param {boolean} shiftKey Specifies if shift is held down.
+ */
+cvox.DomUtil.clickElem = function(targetNode, shiftKey) {
+ //Send a mousedown
+ var evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('mousedown', true, true, document.defaultView,
+ 1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
+ //Use a try block here so that if the AJAX fails and it is a link,
+ //it can still fall through and retry by setting the document.location.
+ try {
+ targetNode.dispatchEvent(evt);
+ } catch (e) {}
+ //Send a mouse up
+ evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('mouseup', true, true, document.defaultView,
+ 1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
+ //Use a try block here so that if the AJAX fails and it is a link,
+ //it can still fall through and retry by setting the document.location.
+ try {
+ targetNode.dispatchEvent(evt);
+ } catch (e) {}
+ //Send a click
+ evt = document.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, document.defaultView,
+ 1, 0, 0, 0, 0, false, false, shiftKey, false, 0, null);
+ //Use a try block here so that if the AJAX fails and it is a link,
+ //it can still fall through and retry by setting the document.location.
+ try {
+ targetNode.dispatchEvent(evt);
+ } catch (e) {}
+ //Clicking on a link does not cause traversal because of script
+ //privilege limitations. The traversal has to be done by setting
+ //document.location.
+ var href = targetNode.getAttribute('href');
+ if ((targetNode.tagName == 'A') &&
+ href &&
+ (href != '#')) {
+ if (shiftKey) {
+ window.open(targetNode.href);
+ } else {
+ document.location = targetNode.href;
+ }
+ }
+
+};
+
+
+/**
+ * Given an HTMLInputElement, returns true if it's an editable text type.
+ * This includes input type='text' and input type='password' and a few
+ * others.
+ *
+ * @param {Node} node The node to check.
+ * @return {boolean} True if the node is an INPUT with an editable text type.
+ */
+cvox.DomUtil.isInputTypeText = function(node) {
+ if (node.constructor != HTMLInputElement) {
+ return false;
+ }
+
+ switch (node.type) {
+ case 'email':
+ case 'number':
+ case 'password':
+ case 'search':
+ case 'text':
+ case 'tel':
+ case 'url':
+ case '':
+ return true;
+ default:
+ return false;
+ }
+};
+
+/**
+ * Given a node, returns true if it's a control.
+ * Note that controls are all leaf level widgets; they
+ * are NOT containers.
+ *
+ * @param {Node} node The node to check.
+ * @return {boolean} True if the node is a control.
+ */
+cvox.DomUtil.isControl = function(node) {
+ if (cvox.AriaUtil.isControlWidget(node)) {
+ return true;
+ }
+ if (node.tagName) {
+ switch (node.tagName) {
+ case 'BUTTON':
+ case 'INPUT':
+ case 'TEXTAREA':
+ case 'SELECT':
+ return true;
+ }
+ }
+ return false;
+};
+
+/**
+ * Given a node, returns the next leaf node.
+ *
+ * @param {Node} node The node from which to start looking
+ * for the next leaf node.
+ * @return {Node} The next leaf node.
+ * Null if there is no next leaf node.
+ */
+cvox.DomUtil.nextLeafNode = function(node) {
+ var tempNode = node;
+ while (tempNode && (!tempNode.nextSibling)) {
+ tempNode = tempNode.parentNode;
+ }
+ if (tempNode && tempNode.nextSibling) {
+ tempNode = tempNode.nextSibling;
+ while (!cvox.DomUtil.isLeafNode(tempNode)) {
+ tempNode = tempNode.firstChild;
+ }
+ }
+ return tempNode;
+};
+
+/**
+ * Given a node, returns the previous leaf node.
+ *
+ * @param {Node} node The node from which to start looking
+ * for the previous leaf node.
+ * @return {Node} The previous leaf node.
+ * Null if there is no previous leaf node.
+ */
+cvox.DomUtil.previousLeafNode = function(node) {
+ var tempNode = node;
+ while (tempNode && (!tempNode.previousSibling)) {
+ tempNode = tempNode.parentNode;
+ }
+ if (tempNode && tempNode.previousSibling) {
+ tempNode = tempNode.previousSibling;
+ while (!cvox.DomUtil.isLeafNode(tempNode)) {
+ tempNode = tempNode.lastChild;
+ }
+ }
+ return tempNode;
+};
Property changes on: chrome/browser/resources/access_chromevox/common/dom_util.js
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698