1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @fileoverview A utility class for general braille functionality.
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.provide('cvox.BrailleUtil');
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.ChromeVox');
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.DomUtil');
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.Focuser');
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.NavBraille');
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.NodeStateUtil');
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)goog.require('cvox.Spannable');
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Trimmable whitespace character that appears between consecutive items in
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * braille.
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @const {string}
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.ITEM_SEPARATOR = ' ';
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Messages considered as containers in braille.
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Containers are distinguished from roles by their appearance higher up in the
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * DOM tree of a selected node.
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * This list should be very short.
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @type {!Array.<string>}
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.CONTAINER = [
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h1_brl',
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h2_brl',
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h3_brl',
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h4_brl',
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h5_brl',
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_h6_brl'
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)];
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Maps a ChromeVox message id to a braille template.
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * The template takes one-character specifiers:
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * n: replaced with braille name.
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * r: replaced with braille role.
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * s: replaced with braille state.
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * c: replaced with braille container role; this potentially returns whitespace,
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * so place at the beginning or end of templates for trimming.
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * v: replaced with braille value.
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @type {Object.<string, string>}
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.TEMPLATE = {
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'base': 'c n v r s',
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'aria_role_alert': 'r: n',
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'aria_role_button': '[n]',
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'aria_role_textbox': 'n: v r',
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_button': '[n]',
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_checkbox': 'n (s)',
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_email': 'n: v r',
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_number': 'n: v r',
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_password': 'n: v r',
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_search': 'n: v r',
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_submit': '[n]',
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_text': 'n: v r',
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_tel': 'n: v r',
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'input_type_url': 'n: v r',
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_button': '[n]',
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  'tag_textarea': 'n: v r'
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Attached to the value region of a braille spannable.
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} offset The offset of the span into the value.
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.ValueSpan = function(offset) {
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  /**
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * The offset of the span into the value.
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   * @type {number}
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)   */
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.offset = offset;
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Creates a value span from a json serializable object.
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {!Object} obj The json serializable object to convert.
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @return {!cvox.BrailleUtil.ValueSpan} The value span.
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.ValueSpan.fromJson = function(obj) {
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return new cvox.BrailleUtil.ValueSpan(obj.offset);
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Converts this object to a json serializable object.
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @return {!Object} The JSON representation.
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.ValueSpan.prototype.toJson = function() {
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return this;
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.Spannable.registerSerializableSpan(
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cvox.BrailleUtil.ValueSpan,
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    'cvox.BrailleUtil.ValueSpan',
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cvox.BrailleUtil.ValueSpan.fromJson,
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cvox.BrailleUtil.ValueSpan.prototype.toJson);
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Attached to the selected text within a value.
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @constructor
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.ValueSelectionSpan = function() {
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.Spannable.registerStatelessSerializableSpan(
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cvox.BrailleUtil.ValueSelectionSpan,
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    'cvox.BrailleUtil.ValueSelectionSpan');
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille name for a node.
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * See DomUtil for a more precise definition of 'name'.
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Additionally, whitespace is trimmed.
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} The string representation.
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getName = function(node) {
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!node) {
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return '';
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return cvox.DomUtil.getName(node).trim();
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille role message id for a node.
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * See DomUtil for a more precise definition of 'role'.
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} The string representation.
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getRoleMsg = function(node) {
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!node) {
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return '';
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var roleMsg = cvox.DomUtil.getRoleMsg(node, cvox.VERBOSITY_VERBOSE);
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (roleMsg) {
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    roleMsg = cvox.DomUtil.collapseWhitespace(roleMsg);
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (roleMsg && (roleMsg.length > 0)) {
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (cvox.ChromeVox.msgs.getMsg(roleMsg + '_brl')) {
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      roleMsg += '_brl';
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return roleMsg;
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille role of a node.
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * See DomUtil for a more precise definition of 'role'.
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} The string representation.
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getRole = function(node) {
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!node) {
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return '';
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var roleMsg = cvox.BrailleUtil.getRoleMsg(node);
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return roleMsg ? cvox.ChromeVox.msgs.getMsg(roleMsg) : '';
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille state of a node.
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} The string representation.
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getState = function(node) {
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!node) {
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return '';
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return cvox.NodeStateUtil.expand(
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      cvox.DomUtil.getStateMsgs(node, true).map(function(state) {
19346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // Check to see if a variant of the message with '_brl' exists,
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // and use it if so.
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          //
19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // Note: many messages are templatized, and if we don't pass any
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // argument to substitute, getMsg might throw an error if the
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // resulting string is empty. To avoid this, we pass a dummy
19946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          // substitution string array here.
20046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          var dummySubs = ['dummy', 'dummy', 'dummy'];
20146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          if (cvox.ChromeVox.msgs.getMsg(state[0] + '_brl', dummySubs)) {
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            state[0] += '_brl';
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          return state;
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }));
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille container role of a node.
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} prev The previous node in navigation.
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {string} The string representation.
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getContainer = function(prev, node) {
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!prev || !node) {
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return '';
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var ancestors = cvox.DomUtil.getUniqueAncestors(prev, node);
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (var i = 0, container; container = ancestors[i]; i++) {
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var msg = cvox.BrailleUtil.getRoleMsg(container);
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (msg && cvox.BrailleUtil.CONTAINER.indexOf(msg) != -1) {
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return cvox.ChromeVox.msgs.getMsg(msg);
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return '';
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the braille value of a node. A cvox.BrailleUtil.ValueSpan will be
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * attached, along with (possibly) a cvox.BrailleUtil.ValueSelectionSpan.
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {!cvox.Spannable} The value spannable.
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getValue = function(node) {
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!node) {
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return new cvox.Spannable();
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var valueSpan = new cvox.BrailleUtil.ValueSpan(0 /* offset */);
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (cvox.DomUtil.isInputTypeText(node)) {
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var value = node.value;
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (node.type === 'password') {
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      value = value.replace(/./g, '*');
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var spannable = new cvox.Spannable(value, valueSpan);
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (node === document.activeElement &&
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.DomUtil.doesInputSupportSelection(node)) {
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var selectionStart = cvox.BrailleUtil.clamp_(
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          node.selectionStart, 0, spannable.getLength());
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var selectionEnd = cvox.BrailleUtil.clamp_(
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          node.selectionEnd, 0, spannable.getLength());
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(),
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        Math.min(selectionStart, selectionEnd),
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        Math.max(selectionStart, selectionEnd));
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return spannable;
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (node instanceof HTMLTextAreaElement) {
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var shadow = new cvox.EditableTextAreaShadow();
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    shadow.update(node);
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var lineIndex = shadow.getLineIndex(node.selectionEnd);
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var lineStart = shadow.getLineStart(lineIndex);
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var lineEnd = shadow.getLineEnd(lineIndex);
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var lineText = node.value.substring(lineStart, lineEnd);
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    valueSpan.offset = lineStart;
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var spannable = new cvox.Spannable(lineText, valueSpan);
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (node === document.activeElement) {
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var selectionStart = cvox.BrailleUtil.clamp_(
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          node.selectionStart - lineStart, 0, spannable.getLength());
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var selectionEnd = cvox.BrailleUtil.clamp_(
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          node.selectionEnd - lineStart, 0, spannable.getLength());
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(),
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        Math.min(selectionStart, selectionEnd),
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        Math.max(selectionStart, selectionEnd));
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return spannable;
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return new cvox.Spannable(cvox.DomUtil.getValue(node), valueSpan);
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Gets the templated representation of braille.
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} prev The previous node (during navigation).
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {Node} node The node.
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {{name:(undefined|string),
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * role:(undefined|string),
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * roleMsg:(undefined|string),
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * state:(undefined|string),
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * container:(undefined|string),
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * value:(undefined|cvox.Spannable)}|Object=} opt_override Override a
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * specific property for the given node.
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {!cvox.Spannable} The string representation.
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) {
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  opt_override = opt_override ? opt_override : {};
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var roleMsg = opt_override.roleMsg ||
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (node ? cvox.DomUtil.getRoleMsg(node, cvox.VERBOSITY_VERBOSE) : '');
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var role = opt_override.role;
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!role && opt_override.roleMsg) {
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    role = cvox.ChromeVox.msgs.getMsg(opt_override.roleMsg + '_brl') ||
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVox.msgs.getMsg(opt_override.roleMsg);
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  role = role || cvox.BrailleUtil.getRole(node);
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var template = cvox.BrailleUtil.TEMPLATE[roleMsg] ||
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      cvox.BrailleUtil.TEMPLATE['base'];
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var templated = new cvox.Spannable();
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var mapChar = function(c) {
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    switch (c) {
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case 'n':
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return opt_override.name || cvox.BrailleUtil.getName(node);
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case 'r':
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return role;
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case 's':
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return opt_override.state || cvox.BrailleUtil.getState(node);
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case 'c':
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return opt_override.container ||
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            cvox.BrailleUtil.getContainer(prev, node);
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case 'v':
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return opt_override.value || cvox.BrailleUtil.getValue(node);
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      default:
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return c;
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (var i = 0; i < template.length; i++) {
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var component = mapChar(template[i]);
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    templated.append(component);
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Ignore the next whitespace separator if the current component is empty.
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!component.toString() && template[i + 1] == ' ') {
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      i++;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return templated.trimRight();
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Creates a braille value from a string and, optionally, a selection range.
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * A cvox.BrailleUtil.ValueSpan will be
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * attached, along with a cvox.BrailleUtil.ValueSelectionSpan if applicable.
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {string} text The text to display as the value.
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number=} opt_selStart Selection start.
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number=} opt_selEnd Selection end if different from selection start.
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number=} opt_textOffset Start offset of text.
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {!cvox.Spannable} The value spannable.
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd,
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                        opt_textOffset) {
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var spannable = new cvox.Spannable(
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      text, new cvox.BrailleUtil.ValueSpan(opt_textOffset || 0));
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (goog.isDef(opt_selStart)) {
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart;
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(plundblad): This looses the distinction between the selection
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // anchor (start) and focus (end).  We should use that information to
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // decide where to pan the braille display.
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (opt_selStart > opt_selEnd) {
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var temp = opt_selStart;
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      opt_selStart = opt_selEnd;
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      opt_selEnd = temp;
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(),
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          opt_selStart, opt_selEnd);
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return spannable;
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Activates a position in a nav braille.  Moves the caret in text fields
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * and simulates a mouse click on the node at the position.
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {!cvox.NavBraille} braille the nav braille representing the display
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *        content that was active when the user issued the key command.
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *        The annotations in the spannable are used to decide what
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *        node to activate and what part of the node value (if any) to
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *        move the caret to.
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number=} opt_displayPosition position of the display that the user
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *                  activated, relative to the start of braille.
382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.click = function(braille, opt_displayPosition) {
384116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  var handled = false;
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var spans = braille.text.getSpans(opt_displayPosition || 0);
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  var node = spans.filter(function(n) { return n instanceof Node; })[0];
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (node) {
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (goog.isDef(opt_displayPosition) &&
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        (cvox.DomUtil.isInputTypeText(node) ||
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            node instanceof HTMLTextAreaElement)) {
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var valueSpan = spans.filter(
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          function(s) {
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            return s instanceof cvox.BrailleUtil.ValueSpan;
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          })[0];
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (valueSpan) {
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if (document.activeElement !== node) {
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          cvox.Focuser.setFocus(node);
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        }
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        var cursorPosition = opt_displayPosition -
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            braille.text.getSpanStart(valueSpan) +
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            valueSpan.offset;
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVoxEventWatcher.setUpTextHandler();
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        node.selectionStart = node.selectionEnd = cursorPosition;
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        cvox.ChromeVoxEventWatcher.handleTextChanged(true);
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        handled = true;
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!handled) {
410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    cvox.DomUtil.clickElem(
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        node || cvox.ChromeVox.navigationManager.getCurrentNode(),
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        false, false, false, true);
413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/**
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Clamps a number so it is within the given boundaries.
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} number The number to clamp.
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} min The minimum value to return.
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param {number} max The maximum value to return.
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return {number} {@code number} if it is within the bounds, or the nearest
423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *     number within the bounds otherwise.
424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @private
425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
426cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)cvox.BrailleUtil.clamp_ = function(number, min, max) {
427cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return Math.min(Math.max(number, min), max);
428cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
429