Bug 1173583 - Make autocompletion from the username field work outside of <form>. r=MattN
authorAndrew Krawchyk <akrawchyk@gmail.com>
Thu, 29 Oct 2015 16:44:20 -0400
changeset 271127 4d8bd0c31603d278abfaedcf7ad2fccb959d3617
parent 271126 67c49cc5adc9bb5f4ce5758675f20593043419f4
child 271128 e0ba952c2819d0015ae5a81bfe0960cf1d42baf5
push id16088
push usermozilla@noorenberghe.ca
push dateThu, 05 Nov 2015 02:33:40 +0000
treeherderfx-team@e0ba952c2819 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1173583
milestone45.0a1
Bug 1173583 - Make autocompletion from the username field work outside of <form>. r=MattN
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/test/pwmgr_common.js
toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -238,24 +238,19 @@ var LoginManagerContent = {
     return this._sendRequest(messageManager, requestData,
                              "RemoteLogins:findLogins",
                              messageData);
   },
 
   _autoCompleteSearchAsync: function(aSearchString, aPreviousResult,
                                      aElement, aRect) {
     let doc = aElement.ownerDocument;
-    let form = aElement.form;
+    let form = FormLikeFactory.createFromField(aElement);
     let win = doc.defaultView;
 
-    if (!form) {
-      return Promise.reject("Bug 1173583: _autoCompleteSearchAsync needs to be " +
-                            "updated to work outside of <form>");
-    }
-
     let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
     let actionOrigin = LoginUtils._getActionOrigin(form);
 
     let messageManager = messageManagerFromWindow(win);
 
     let remote = (Services.appinfo.processType ===
                   Services.appinfo.PROCESS_TYPE_CONTENT);
 
@@ -519,17 +514,17 @@ var LoginManagerContent = {
 
     // This is probably a bit over-conservatative.
     if (!(acInputField.ownerDocument instanceof Ci.nsIDOMHTMLDocument))
       return;
 
     if (!LoginHelper.isUsernameFieldType(acInputField))
       return;
 
-    var acForm = acInputField.form; // XXX: Bug 1173583 - This doesn't work outside of <form>.
+    var acForm = FormLikeFactory.createFromField(acInputField);
     if (!acForm)
       return;
 
     // If the username is blank, bail out now -- we don't want
     // fillForm() to try filling in a login without a username
     // to filter on (bug 471906).
     if (!acInputField.value)
       return;
--- a/toolkit/components/passwordmgr/test/pwmgr_common.js
+++ b/toolkit/components/passwordmgr/test/pwmgr_common.js
@@ -5,17 +5,17 @@
  */
 function $_(formNum, name) {
   var form = document.getElementById("form" + formNum);
   if (!form) {
     logWarning("$_ couldn't find requested form " + formNum);
     return null;
   }
 
-  var element = form.elements.namedItem(name);
+  var element = form.children.namedItem(name);
   if (!element) {
     logWarning("$_ couldn't find requested element " + name);
     return null;
   }
 
   // Note that namedItem is a bit stupid, and will prefer an
   // |id| attribute over a |name| attribute when looking for
   // the element. Login Mananger happens to use .namedItem
@@ -40,17 +40,17 @@ function $_(formNum, name) {
  * <form id="form#">
  * checkForm(#, "foo");
  */
 function checkForm(formNum, val1, val2, val3) {
     var e, form = document.getElementById("form" + formNum);
     ok(form, "Locating form " + formNum);
 
     var numToCheck = arguments.length - 1;
-    
+
     if (!numToCheck--)
         return;
     e = form.elements[0];
     if (val1 == null)
         is(e.value, e.defaultValue, "Test default value of field " + e.name +
             " in form " + formNum);
     else
         is(e.value, val1, "Test value of field " + e.name +
--- a/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html
@@ -80,16 +80,17 @@ var login8C = new nsLoginInfo(
 var login9 = new nsLoginInfo(
     "http://mochi.test:8888", "http://autocomplete6", null,
     "testuser9", "testpass9", "uname", "pword");
 
 var login10 = new nsLoginInfo(
     "http://mochi.test:8888", "http://autocomplete7", null,
     "testuser10", "testpass10", "uname", "pword");
 
+
 // try/catch in case someone runs the tests manually, twice.
 try {
     pwmgr.addLogin(login0);
     pwmgr.addLogin(login1);
     pwmgr.addLogin(login2);
     pwmgr.addLogin(login3);
     pwmgr.addLogin(login4);
     pwmgr.addLogin(login5);
@@ -178,16 +179,23 @@ try {
   </form>
 
   <!-- test for onUsernameInput recipe testing -->
   <form id="form11" action="https://autocomplete7" onsubmit="return false;">
     <input  type="text"   name="1">
     <input  type="text"   name="2">
     <button type="submit">Submit</button>
   </form>
+
+  <!-- tests <form>-less autocomplete -->
+  <div id="form12">
+     <input  type="text"       name="uname" id="uname">
+     <input  type="password"   name="pword" id="pword">
+     <button type="submit">Submit</button>
+   </div>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
 var tester;
@@ -854,16 +862,33 @@ function* runTest() {
   checkACForm("testuser10", "");
   doKey("tab");
   yield waitForCompletion();
   checkACForm("testuser10", "testpass10");
 
   recipeParent.reset();
   yield runNextTest();
 
+  // Test form-less autocomplete
+  uname = $_(12, "uname")
+  pword = $_(12, "pword")
+  restoreForm();
+  checkACForm("", "");
+  // Trigger autocomplete popup
+  doKey("down");
+  yield runNextTest("expect popup");
+
+  // Trigger autocomplete
+  doKey("down");
+  checkACForm("", ""); // value shouldn't update
+  doKey("return"); // not "enter"!
+  yield waitForCompletion();
+  checkACForm("testuser", "testpass");
+  yield runNextTest();
+
   SimpleTest.finish();
   return;
 }
 
 
 function checkMenuEntries(expectedValues) {
     var actualValues = getMenuEntries();
     is(actualValues.length, expectedValues.length, "Checking length of expected menu");