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

Side by Side Diff: components/autofill/ios/browser/resources/suggestion_controller.js

Issue 1007813002: [iOS] Upstream autofill component code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added dconnelly to OWNERS Created 5 years, 9 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 unified diff | Download patch
« no previous file with comments | « components/autofill/ios/browser/resources/autofill_controller.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 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 // Installs suggestion management functions on the |__gCrWeb| object.
6
7 /**
8 * Namespace for this file. It depends on |__gCrWeb| having already been
9 * injected.
10 */
11 __gCrWeb['suggestion'] = {};
12
13 /**
14 * Returns the first element in |elements| that is later than |elementToCompare|
15 * in tab order.
16 *
17 * @param {Element} elementToCompare The element to start searching forward in
18 * tab order from.
19 * @param {NodeList} elementList Elements in which the first element that is
20 * later than |elementToCompare| in tab order is to be returned if there is
21 * one; |elements| should be sorted in DOM tree order and should contain
22 * |elementToCompare|.
23 * @return {Element} the first element in |elements| that is later than
24 * |elementToCompare| in tab order if there is one; null otherwise.
25 */
26 __gCrWeb.suggestion.getNextElementInTabOrder =
27 function(elementToCompare, elementList) {
28 var elements = [];
29 for (var i = 0; i < elementList.length; ++i) {
30 elements[i] = elementList[i];
31 }
32 // There is no defined behavior if the element is not reachable. Here the
33 // next reachable element in DOM tree order is returned. (This is what is
34 // observed in Mobile Safari and Chrome Desktop, if |elementToCompare| is not
35 // the last element in DOM tree order).
36 // TODO(chenyu): investigate and simulate Mobile Safari's behavior when
37 // |elementToCompare| is the last one in DOM tree order.
38 if (!__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)) {
39 var indexToCompare = elements.indexOf(elementToCompare);
40 if (indexToCompare === elements.length - 1 || indexToCompare === -1) {
41 return null;
42 }
43 for (var index = indexToCompare + 1; index < elements.length; ++index) {
44 var element = elements[index];
45 if (__gCrWeb.suggestion.isSequentiallyReachable(element)) {
46 return element;
47 }
48 }
49 return null;
50 }
51
52 // Returns true iff |element1| that has DOM tree position |index1| is after
53 // |element2| that has DOM tree position |index2| in tab order. It is assumed
54 // |index1 !== index2|.
55 var comparator = function(element1, index1, element2, index2) {
56 var tabOrder1 = __gCrWeb.suggestion.getTabOrder(element1);
57 var tabOrder2 = __gCrWeb.suggestion.getTabOrder(element2);
58 return tabOrder1 > tabOrder2 ||
59 (tabOrder1 === tabOrder2 && index1 > index2);
60 };
61 return __gCrWeb.suggestion.getFormElementAfter(
62 elementToCompare, elements, comparator);
63 };
64
65 /**
66 * Returns the last element in |elements| that is earlier than
67 * |elementToCompare| in tab order.
68 *
69 * @param {Element} elementToCompare The element to start searching backward in
70 * tab order from.
71 * @param {NodeList} elementList Elements in which the last element that is
72 * earlier than |elementToCompare| in tab order is to be returned if
73 * there is one; |elements| should be sorted in DOM tree order and it should
74 * contain |elementToCompare|.
75 * @return {Element} the last element in |elements| that is earlier than
76 * |elementToCompare| in tab order if there is one; null otherwise.
77 */
78 __gCrWeb.suggestion.getPreviousElementInTabOrder =
79 function(elementToCompare, elementList) {
80 var elements = [];
81 for (var i = 0; i < elementList.length; ++i) {
82 elements[i] = elementList[i];
83 }
84
85 // There is no defined behavior if the element is not reachable. Here the
86 // previous reachable element in DOM tree order is returned.
87 if (!__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)) {
88 var indexToCompare = elements.indexOf(elementToCompare);
89 if (elementToCompare === 0 || elementToCompare === -1) {
90 return null;
91 }
92 for (var index = indexToCompare - 1; index >= 0; --index) {
93 var element = elements[index];
94 if (__gCrWeb.suggestion.isSequentiallyReachable(element)) {
95 return element;
96 }
97 }
98 return null;
99 }
100
101 // Returns true iff |element1| that has DOM tree position |index1| is before
102 // |element2| that has DOM tree position |index2| in tab order. It is assumed
103 // |index1 !== index2|.
104 var comparator = function(element1, index1, element2, index2) {
105 var tabOrder1 = __gCrWeb.suggestion.getTabOrder(element1);
106 var tabOrder2 = __gCrWeb.suggestion.getTabOrder(element2);
107 return tabOrder1 < tabOrder2 ||
108 (tabOrder1 === tabOrder2 && index1 < index2);
109 };
110
111 return __gCrWeb.suggestion.getFormElementAfter(
112 elementToCompare, elements, comparator);
113 };
114
115 /**
116 * Given an element |elementToCompare|, such as
117 * |__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)|, and a list
118 * of |elements| which are sorted in DOM tree order and contains
119 * |elementToCompare|, this method returns the next element in |elements| after
120 * |elementToCompare| in the order defined by |comparator|, where an element is
121 * said to be 'after' anotherElement if and only if
122 * comparator(element, indexOfElement, anotherElement, anotherIndex) is true.
123 *
124 * @param {Element} elementToCompare The element to be compared.
125 * @param {Array.<Element>} elements Elements to compare; |elements| should be
126 * sorted in DOM tree order and it should contain |elementToCompare|.
127 * @param {function} comparator A function that returns a boolean, given an
128 * Element |element1|, an integer that represents |element1|'s position in
129 * DOM tree order, an Element |element2| and an integer that represents
130 * |element2|'s position in DOM tree order.
131 * @return {Element} The element that satisfies the conditions given above.
132 */
133 __gCrWeb.suggestion.getFormElementAfter =
134 function(elementToCompare, elements, comparator) {
135 // Computes the index |indexToCompare| of |elementToCompare| in |element|.
136 var indexToCompare = elements.indexOf(elementToCompare);
137 if (indexToCompare === -1) {
138 return null;
139 }
140
141 var result = null;
142 var resultIndex = -1;
143 for (var index = 0; index < elements.length; ++index) {
144 if (index === indexToCompare) {
145 continue;
146 }
147 var element = elements[index];
148 if (!__gCrWeb.suggestion.isSequentiallyReachable(element)) {
149 continue;
150 }
151
152 if (comparator(element, index, elementToCompare, indexToCompare)) {
153 if (!result) {
154 result = element;
155 resultIndex = index;
156 } else {
157 if (comparator(result, resultIndex, element, index)) {
158 result = element;
159 resultIndex = index;
160 }
161 }
162 }
163 }
164 return result;
165 };
166
167 /**
168 * Returns if an element is reachable in sequential navigation.
169 *
170 * @param {Element} element The element that is to be examined.
171 * @return {boolean} Whether an element is reachable in sequential navigation.
172 */
173 __gCrWeb.suggestion.isSequentiallyReachable = function(element) {
174 var tabIndex = element.tabIndex;
175 // It is proposed in W3C that if tabIndex is omitted or parsing the value
176 // returns an error, the user agent should follow platform conventions to
177 // determine whether the element can be reached using sequential focus
178 // navigation, and if so, what its relative order should be. No document is
179 // found on the platform conventions in this case on iOS.
180 //
181 // There is a list of elements for which the tabIndex focus flags are
182 // suggested to be set in this case in W3C proposal. It is observed that in
183 // UIWebview parsing the tabIndex of an element in this list returns 0 if it
184 // is omitted or it is set to be an invalid value, undefined, null or NaN. So
185 // here it is assumed that all the elements that have invalid tabIndex is
186 // not reachable in sequential focus navigation.
187 //
188 // It is proposed in W3C that if tabIndex is a negative integer, the user
189 // agent should not allow the element to be reached using sequential focus
190 // navigation.
191 if ((!tabIndex && tabIndex != 0) || tabIndex < 0) {
192 return false;
193 }
194 if (element.type === 'hidden' || element.hasAttribute('disabled')) {
195 return false;
196 }
197
198 // false is returned if |element| is neither an input nor a select. Note based
199 // on this condition, false is returned for an iframe (as Mobile Safari does
200 // not navigate to elements in an iframe, there is no need to recursively
201 // check if there is a reachable element in an iframe).
202 if (element.tagName !== 'INPUT' &&
203 element.tagName !== 'SELECT' &&
204 element.tagName !== 'TEXTAREA') {
205 return false;
206 }
207
208 // The following elements are skipped when navigating using 'Prev' and "Next'
209 // buttons in Mobile Safari.
210 if (element.tagName === 'INPUT' &&
211 (element.type === 'submit' ||
212 element.type === 'reset' ||
213 element.type === 'image' ||
214 element.type === 'button' ||
215 element.type === 'range' ||
216 element.type === 'radio' ||
217 element.type === 'checkbox')) {
218 return false;
219 }
220
221 // Expensive, final check that the element is not concealed.
222 return __gCrWeb['common'].isElementVisible(element);
223 };
224
225 /**
226 * It is proposed in W3C an element that has a tabIndex greater than zero should
227 * be placed before any focusable element whose tabIndex is equal to zero in
228 * sequential focus navigation order. Here a value adjusted from tabIndex that
229 * reflects this order is returned. That is, given |element1| and |element2|,
230 * if |__gCrWeb.suggestion.getTabOrder(element1) >
231 * __gCrWeb.suggestion.getTabOrder(element2)|, then |element1| is after
232 * |element2| in sequential navigation.
233 *
234 * @param {Element} element The element of which the sequential navigation order
235 * information is returned.
236 * @return {Number} An adjusted value that reflect |element|'s position in the
237 * sequential navigation.
238 */
239 __gCrWeb.suggestion.getTabOrder = function(element) {
240 var tabIndex = element.tabIndex;
241 if (tabIndex === 0) {
242 return Number.MAX_VALUE;
243 }
244 return tabIndex;
245 };
246
247 /**
248 * Returns the element named |fieldName| in the form specified by |formName|,
249 * if it exists.
250 *
251 * @param {string} formName The name of the form containing the element.
252 * @param {string} fieldName The name of the field containing the element.
253 * @return {Element} The element if found, otherwise null.
254 */
255 __gCrWeb.suggestion.getFormElement = function(formName, fieldName) {
256 var form = __gCrWeb.common.getFormElementFromIdentifier(formName);
257 if (!form)
258 return null;
259 return __gCrWeb.getElementByNameWithParent(form, fieldName);
260 };
261
262 /**
263 * Focuses the next element in the sequential focus navigation. No operation
264 * if there is no such element.
265 */
266 __gCrWeb.suggestion['selectNextElement'] = function(formName, fieldName) {
267 var currentElement =
268 formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
269 document.activeElement;
270 var nextElement = __gCrWeb.suggestion.getNextElementInTabOrder(currentElement,
271 document.all);
272 if (nextElement) {
273 nextElement.focus();
274 }
275 };
276
277 /**
278 * Focuses the previous element in the sequential focus navigation. No
279 * operation if there is no such element.
280 */
281 __gCrWeb.suggestion['selectPreviousElement'] = function(formName, fieldName) {
282 var currentElement =
283 formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
284 document.activeElement;
285 var prevElement = __gCrWeb.suggestion.getPreviousElementInTabOrder(
286 currentElement, document.all);
287 if (prevElement) {
288 prevElement.focus();
289 }
290 };
291
292 /**
293 * @return {boolean} Whether there is an element in the sequential navigation
294 * after the currently active element.
295 */
296 __gCrWeb.suggestion['hasNextElement'] = function(formName, fieldName) {
297 var currentElement =
298 formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
299 document.activeElement;
300 return __gCrWeb.suggestion.getNextElementInTabOrder(currentElement,
301 document.all) !== null;
302 };
303
304 /**
305 * @return {boolean} Whether there is an element in the sequential navigation
306 * before the currently active element.
307 */
308 __gCrWeb.suggestion['hasPreviousElement'] = function(formName, fieldName) {
309 var currentElement =
310 formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
311 document.activeElement;
312 return __gCrWeb.suggestion.getPreviousElementInTabOrder(
313 currentElement, document.all) !== null;
314 };
OLDNEW
« no previous file with comments | « components/autofill/ios/browser/resources/autofill_controller.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698