Bug 1330111 - Add FormLikeFactory.findRootForField API. r=johannh a=jcristau
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Tue, 31 Jan 2017 23:54:45 -0800
changeset 378292 aa053c7497f4ea51d56bec8ede8b39bff36939cb
parent 378291 8898738f895e8800c0f181c3b2784ac766d22a1e
child 378293 f64a17520775e840bbd421e107ce2d43a7298d1b
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh, jcristau
bugs1330111
milestone53.0a2
Bug 1330111 - Add FormLikeFactory.findRootForField API. r=johannh a=jcristau MozReview-Commit-ID: 6qo0hVx3J6p
toolkit/modules/FormLikeFactory.jsm
--- a/toolkit/modules/FormLikeFactory.jsm
+++ b/toolkit/modules/FormLikeFactory.jsm
@@ -63,42 +63,61 @@ let FormLikeFactory = {
    * @throws Error if aField isn't a password or username field in a document
    */
   createFromField(aField) {
     if (!(aField instanceof Ci.nsIDOMHTMLInputElement) ||
         !aField.ownerDocument) {
       throw new Error("createFromField requires a field in a document");
     }
 
-    if (aField.form) {
-      return this.createFromForm(aField.form);
+    let rootElement = this.findRootForField(aField);
+    if (rootElement instanceof Ci.nsIDOMHTMLFormElement) {
+      return this.createFromForm(rootElement);
     }
 
     let doc = aField.ownerDocument;
     let elements = [];
-    for (let el of doc.documentElement.querySelectorAll("input")) {
+    for (let el of rootElement.querySelectorAll("input")) {
+      // Exclude elements inside the rootElement that are already in a <form> as
+      // they will be handled by their own FormLike.
       if (!el.form) {
         elements.push(el);
       }
     }
     let formLike = {
       action: doc.baseURI,
       autocomplete: "on",
-      // Exclude elements inside the rootElement that are already in a <form> as
-      // they will be handled by their own FormLike.
       elements,
       ownerDocument: doc,
-      rootElement: doc.documentElement,
+      rootElement,
     };
 
     this._addToJSONProperty(formLike);
     return formLike;
   },
 
   /**
+   * Determine the Element that encapsulates the related fields. For example, if
+   * a page contains a login form and a checkout form which are "submitted"
+   * separately, and the username field is passed in, ideally this would return
+   * an ancestor Element of the username and password fields which doesn't
+   * include any of the checkout fields.
+   *
+   * @param {HTMLInputElement} aField - a field in a document
+   * @return {HTMLElement} - the root element surrounding related fields
+   */
+  findRootForField(aField) {
+    if (aField.form) {
+      return aField.form;
+    }
+
+    return aField.ownerDocument.documentElement;
+  },
+
+  /**
    * Add a `toJSON` property to a FormLike so logging which ends up going
    * through dump doesn't include usless garbage from DOM objects.
    */
   _addToJSONProperty(aFormLike) {
     function prettyElementOutput(aElement) {
       let idText = aElement.id ? "#" + aElement.id : "";
       let classText = "";
       for (let className of aElement.classList) {