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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/autofill/ios/browser/resources/autofill_controller.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/autofill/ios/browser/resources/suggestion_controller.js
diff --git a/components/autofill/ios/browser/resources/suggestion_controller.js b/components/autofill/ios/browser/resources/suggestion_controller.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c4ab63082c3329af1c18ee2f94bbc783687d5ce
--- /dev/null
+++ b/components/autofill/ios/browser/resources/suggestion_controller.js
@@ -0,0 +1,314 @@
+// Copyright 2013 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.
+
+// Installs suggestion management functions on the |__gCrWeb| object.
+
+/**
+ * Namespace for this file. It depends on |__gCrWeb| having already been
+ * injected.
+ */
+__gCrWeb['suggestion'] = {};
+
+/**
+ * Returns the first element in |elements| that is later than |elementToCompare|
+ * in tab order.
+ *
+ * @param {Element} elementToCompare The element to start searching forward in
+ * tab order from.
+ * @param {NodeList} elementList Elements in which the first element that is
+ * later than |elementToCompare| in tab order is to be returned if there is
+ * one; |elements| should be sorted in DOM tree order and should contain
+ * |elementToCompare|.
+ * @return {Element} the first element in |elements| that is later than
+ * |elementToCompare| in tab order if there is one; null otherwise.
+ */
+__gCrWeb.suggestion.getNextElementInTabOrder =
+ function(elementToCompare, elementList) {
+ var elements = [];
+ for (var i = 0; i < elementList.length; ++i) {
+ elements[i] = elementList[i];
+ }
+ // There is no defined behavior if the element is not reachable. Here the
+ // next reachable element in DOM tree order is returned. (This is what is
+ // observed in Mobile Safari and Chrome Desktop, if |elementToCompare| is not
+ // the last element in DOM tree order).
+ // TODO(chenyu): investigate and simulate Mobile Safari's behavior when
+ // |elementToCompare| is the last one in DOM tree order.
+ if (!__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)) {
+ var indexToCompare = elements.indexOf(elementToCompare);
+ if (indexToCompare === elements.length - 1 || indexToCompare === -1) {
+ return null;
+ }
+ for (var index = indexToCompare + 1; index < elements.length; ++index) {
+ var element = elements[index];
+ if (__gCrWeb.suggestion.isSequentiallyReachable(element)) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ // Returns true iff |element1| that has DOM tree position |index1| is after
+ // |element2| that has DOM tree position |index2| in tab order. It is assumed
+ // |index1 !== index2|.
+ var comparator = function(element1, index1, element2, index2) {
+ var tabOrder1 = __gCrWeb.suggestion.getTabOrder(element1);
+ var tabOrder2 = __gCrWeb.suggestion.getTabOrder(element2);
+ return tabOrder1 > tabOrder2 ||
+ (tabOrder1 === tabOrder2 && index1 > index2);
+ };
+ return __gCrWeb.suggestion.getFormElementAfter(
+ elementToCompare, elements, comparator);
+};
+
+/**
+ * Returns the last element in |elements| that is earlier than
+ * |elementToCompare| in tab order.
+ *
+ * @param {Element} elementToCompare The element to start searching backward in
+ * tab order from.
+ * @param {NodeList} elementList Elements in which the last element that is
+ * earlier than |elementToCompare| in tab order is to be returned if
+ * there is one; |elements| should be sorted in DOM tree order and it should
+ * contain |elementToCompare|.
+ * @return {Element} the last element in |elements| that is earlier than
+ * |elementToCompare| in tab order if there is one; null otherwise.
+ */
+__gCrWeb.suggestion.getPreviousElementInTabOrder =
+ function(elementToCompare, elementList) {
+ var elements = [];
+ for (var i = 0; i < elementList.length; ++i) {
+ elements[i] = elementList[i];
+ }
+
+ // There is no defined behavior if the element is not reachable. Here the
+ // previous reachable element in DOM tree order is returned.
+ if (!__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)) {
+ var indexToCompare = elements.indexOf(elementToCompare);
+ if (elementToCompare === 0 || elementToCompare === -1) {
+ return null;
+ }
+ for (var index = indexToCompare - 1; index >= 0; --index) {
+ var element = elements[index];
+ if (__gCrWeb.suggestion.isSequentiallyReachable(element)) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ // Returns true iff |element1| that has DOM tree position |index1| is before
+ // |element2| that has DOM tree position |index2| in tab order. It is assumed
+ // |index1 !== index2|.
+ var comparator = function(element1, index1, element2, index2) {
+ var tabOrder1 = __gCrWeb.suggestion.getTabOrder(element1);
+ var tabOrder2 = __gCrWeb.suggestion.getTabOrder(element2);
+ return tabOrder1 < tabOrder2 ||
+ (tabOrder1 === tabOrder2 && index1 < index2);
+ };
+
+ return __gCrWeb.suggestion.getFormElementAfter(
+ elementToCompare, elements, comparator);
+};
+
+/**
+ * Given an element |elementToCompare|, such as
+ * |__gCrWeb.suggestion.isSequentiallyReachable(elementToCompare)|, and a list
+ * of |elements| which are sorted in DOM tree order and contains
+ * |elementToCompare|, this method returns the next element in |elements| after
+ * |elementToCompare| in the order defined by |comparator|, where an element is
+ * said to be 'after' anotherElement if and only if
+ * comparator(element, indexOfElement, anotherElement, anotherIndex) is true.
+ *
+ * @param {Element} elementToCompare The element to be compared.
+ * @param {Array.<Element>} elements Elements to compare; |elements| should be
+ * sorted in DOM tree order and it should contain |elementToCompare|.
+ * @param {function} comparator A function that returns a boolean, given an
+ * Element |element1|, an integer that represents |element1|'s position in
+ * DOM tree order, an Element |element2| and an integer that represents
+ * |element2|'s position in DOM tree order.
+ * @return {Element} The element that satisfies the conditions given above.
+ */
+__gCrWeb.suggestion.getFormElementAfter =
+ function(elementToCompare, elements, comparator) {
+ // Computes the index |indexToCompare| of |elementToCompare| in |element|.
+ var indexToCompare = elements.indexOf(elementToCompare);
+ if (indexToCompare === -1) {
+ return null;
+ }
+
+ var result = null;
+ var resultIndex = -1;
+ for (var index = 0; index < elements.length; ++index) {
+ if (index === indexToCompare) {
+ continue;
+ }
+ var element = elements[index];
+ if (!__gCrWeb.suggestion.isSequentiallyReachable(element)) {
+ continue;
+ }
+
+ if (comparator(element, index, elementToCompare, indexToCompare)) {
+ if (!result) {
+ result = element;
+ resultIndex = index;
+ } else {
+ if (comparator(result, resultIndex, element, index)) {
+ result = element;
+ resultIndex = index;
+ }
+ }
+ }
+ }
+ return result;
+};
+
+/**
+ * Returns if an element is reachable in sequential navigation.
+ *
+ * @param {Element} element The element that is to be examined.
+ * @return {boolean} Whether an element is reachable in sequential navigation.
+ */
+__gCrWeb.suggestion.isSequentiallyReachable = function(element) {
+ var tabIndex = element.tabIndex;
+ // It is proposed in W3C that if tabIndex is omitted or parsing the value
+ // returns an error, the user agent should follow platform conventions to
+ // determine whether the element can be reached using sequential focus
+ // navigation, and if so, what its relative order should be. No document is
+ // found on the platform conventions in this case on iOS.
+ //
+ // There is a list of elements for which the tabIndex focus flags are
+ // suggested to be set in this case in W3C proposal. It is observed that in
+ // UIWebview parsing the tabIndex of an element in this list returns 0 if it
+ // is omitted or it is set to be an invalid value, undefined, null or NaN. So
+ // here it is assumed that all the elements that have invalid tabIndex is
+ // not reachable in sequential focus navigation.
+ //
+ // It is proposed in W3C that if tabIndex is a negative integer, the user
+ // agent should not allow the element to be reached using sequential focus
+ // navigation.
+ if ((!tabIndex && tabIndex != 0) || tabIndex < 0) {
+ return false;
+ }
+ if (element.type === 'hidden' || element.hasAttribute('disabled')) {
+ return false;
+ }
+
+ // false is returned if |element| is neither an input nor a select. Note based
+ // on this condition, false is returned for an iframe (as Mobile Safari does
+ // not navigate to elements in an iframe, there is no need to recursively
+ // check if there is a reachable element in an iframe).
+ if (element.tagName !== 'INPUT' &&
+ element.tagName !== 'SELECT' &&
+ element.tagName !== 'TEXTAREA') {
+ return false;
+ }
+
+ // The following elements are skipped when navigating using 'Prev' and "Next'
+ // buttons in Mobile Safari.
+ if (element.tagName === 'INPUT' &&
+ (element.type === 'submit' ||
+ element.type === 'reset' ||
+ element.type === 'image' ||
+ element.type === 'button' ||
+ element.type === 'range' ||
+ element.type === 'radio' ||
+ element.type === 'checkbox')) {
+ return false;
+ }
+
+ // Expensive, final check that the element is not concealed.
+ return __gCrWeb['common'].isElementVisible(element);
+};
+
+/**
+ * It is proposed in W3C an element that has a tabIndex greater than zero should
+ * be placed before any focusable element whose tabIndex is equal to zero in
+ * sequential focus navigation order. Here a value adjusted from tabIndex that
+ * reflects this order is returned. That is, given |element1| and |element2|,
+ * if |__gCrWeb.suggestion.getTabOrder(element1) >
+ * __gCrWeb.suggestion.getTabOrder(element2)|, then |element1| is after
+ * |element2| in sequential navigation.
+ *
+ * @param {Element} element The element of which the sequential navigation order
+ * information is returned.
+ * @return {Number} An adjusted value that reflect |element|'s position in the
+ * sequential navigation.
+ */
+__gCrWeb.suggestion.getTabOrder = function(element) {
+ var tabIndex = element.tabIndex;
+ if (tabIndex === 0) {
+ return Number.MAX_VALUE;
+ }
+ return tabIndex;
+};
+
+/**
+ * Returns the element named |fieldName| in the form specified by |formName|,
+ * if it exists.
+ *
+ * @param {string} formName The name of the form containing the element.
+ * @param {string} fieldName The name of the field containing the element.
+ * @return {Element} The element if found, otherwise null.
+ */
+__gCrWeb.suggestion.getFormElement = function(formName, fieldName) {
+ var form = __gCrWeb.common.getFormElementFromIdentifier(formName);
+ if (!form)
+ return null;
+ return __gCrWeb.getElementByNameWithParent(form, fieldName);
+};
+
+/**
+ * Focuses the next element in the sequential focus navigation. No operation
+ * if there is no such element.
+ */
+__gCrWeb.suggestion['selectNextElement'] = function(formName, fieldName) {
+ var currentElement =
+ formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
+ document.activeElement;
+ var nextElement = __gCrWeb.suggestion.getNextElementInTabOrder(currentElement,
+ document.all);
+ if (nextElement) {
+ nextElement.focus();
+ }
+};
+
+/**
+ * Focuses the previous element in the sequential focus navigation. No
+ * operation if there is no such element.
+ */
+__gCrWeb.suggestion['selectPreviousElement'] = function(formName, fieldName) {
+ var currentElement =
+ formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
+ document.activeElement;
+ var prevElement = __gCrWeb.suggestion.getPreviousElementInTabOrder(
+ currentElement, document.all);
+ if (prevElement) {
+ prevElement.focus();
+ }
+};
+
+/**
+ * @return {boolean} Whether there is an element in the sequential navigation
+ * after the currently active element.
+ */
+__gCrWeb.suggestion['hasNextElement'] = function(formName, fieldName) {
+ var currentElement =
+ formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
+ document.activeElement;
+ return __gCrWeb.suggestion.getNextElementInTabOrder(currentElement,
+ document.all) !== null;
+};
+
+/**
+ * @return {boolean} Whether there is an element in the sequential navigation
+ * before the currently active element.
+ */
+__gCrWeb.suggestion['hasPreviousElement'] = function(formName, fieldName) {
+ var currentElement =
+ formName ? __gCrWeb.suggestion.getFormElement(formName, fieldName) :
+ document.activeElement;
+ return __gCrWeb.suggestion.getPreviousElementInTabOrder(
+ currentElement, document.all) !== null;
+};
« 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