Bug 444728 - autocomplete disregards maxlength for input fields. r=dolske, sr=mconnor
authorMattN <mnoorenberghe@mozilla.com>
Sat, 01 Aug 2009 17:30:27 -0700
changeset 31008 0c9d24a0f828
parent 31007 0f04a94f8089
child 31009 8366e5cc9f57
push id8338
push userjdolske@mozilla.com
push dateSun, 02 Aug 2009 00:30:58 +0000
treeherdermozilla-central@0c9d24a0f828 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdolske, mconnor
bugs444728
milestone1.9.2a1pre
Bug 444728 - autocomplete disregards maxlength for input fields. r=dolske, sr=mconnor
toolkit/components/satchel/public/nsIFormAutoComplete.idl
toolkit/components/satchel/src/nsFormAutoComplete.js
toolkit/components/satchel/src/nsFormFillController.cpp
toolkit/components/satchel/test/test_form_autocomplete.html
toolkit/components/satchel/test/unit/test_autocomplete.js
--- a/toolkit/components/satchel/public/nsIFormAutoComplete.idl
+++ b/toolkit/components/satchel/public/nsIFormAutoComplete.idl
@@ -33,20 +33,22 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #include "nsISupports.idl"
 
 interface nsIAutoCompleteResult;
+interface nsIDOMHTMLInputElement;
 
-[scriptable, uuid(2f5bb765-428e-4e33-b2d8-441eb7ddf730)]
+[scriptable, uuid(997c0c05-5d1d-47e5-9cbc-765c0b8ec699)]
 
 interface nsIFormAutoComplete: nsISupports {
     /**
      * Generate results for a form input autocomplete menu.
      */
     nsIAutoCompleteResult autoCompleteSearch(
                                     in AString aInputName,
                                     in AString aSearchString,
+                                    in nsIDOMHTMLInputElement aField,
                                     in nsIAutoCompleteResult aPreviousResult);
 };
--- a/toolkit/components/satchel/src/nsFormAutoComplete.js
+++ b/toolkit/components/satchel/src/nsFormAutoComplete.js
@@ -168,21 +168,22 @@ FormAutoComplete.prototype = {
     },
 
 
     /*
      * autoCompleteSearch
      *
      * aInputName    -- |name| attribute from the form input being autocompleted.
      * aUntrimmedSearchString -- current value of the input
+     * aField -- nsIDOMHTMLInputElement being autocompleted (may be null if from chrome)
      * aPreviousResult -- previous search result, if any.
      *
      * Returns: an nsIAutoCompleteResult
      */
-    autoCompleteSearch : function (aInputName, aUntrimmedSearchString, aPreviousResult) {
+    autoCompleteSearch : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult) {
         function sortBytotalScore (a, b) {
             let x = a.totalScore;
             let y = b.totalScore;
             return ((x > y) ? -1 : ((x < y) ? 1 : 0));
         }
 
         if (!this._enabled)
             return null;
@@ -217,16 +218,21 @@ FormAutoComplete.prototype = {
                 filteredEntries.push(entry);
             }
             filteredEntries.sort(sortBytotalScore);
             result.wrappedJSObject.entries = filteredEntries;
         } else {
             this.log("Creating new autocomplete search result.");
             let entries = this.getAutoCompleteValues(aInputName, searchString);
             result = new FormAutoCompleteResult(this._formHistory, entries, aInputName, aUntrimmedSearchString);
+            if (aField && aField.maxLength > -1) {
+                let original = result.wrappedJSObject.entries;
+                let filtered = original.filter(function (el) el.text.length <= this.maxLength, aField);
+                result.wrappedJSObject.entries = filtered;
+            }
         }
 
         return result;
     },
 
     getAutoCompleteValues : function (fieldName, searchString) {
         let values = [];
         let searchTokens;
--- a/toolkit/components/satchel/src/nsFormFillController.cpp
+++ b/toolkit/components/satchel/src/nsFormFillController.cpp
@@ -512,16 +512,17 @@ nsFormFillController::StartSearch(const 
                                          getter_AddRefs(result));
   } else {
     nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
       do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = formAutoComplete->AutoCompleteSearch(aSearchParam,
                                               aSearchString,
+                                              mFocusedInput,
                                               aPreviousResult,
                                               getter_AddRefs(result));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   aListener->OnSearchResult(this, result);  
   
   return NS_OK;
--- a/toolkit/components/satchel/test/test_form_autocomplete.html
+++ b/toolkit/components/satchel/test/test_form_autocomplete.html
@@ -46,16 +46,22 @@ Form History test: form field autocomple
   </form>
 
   <!-- normal form for testing word boundary filtering -->
   <form id="form6" onsubmit="return false;">
     <input  type="text" name="field4">
     <button type="submit">Submit</button>
   </form>
 
+  <!-- form with maxlength attribute on input -->
+  <form id="form7" onsubmit="return false;">
+    <input  type="text" name="field5" maxlength="10">
+    <button type="submit">Submit</button>
+  </form>
+
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Form History autocomplete **/
 
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
@@ -79,16 +85,20 @@ fh.addEntry("field3", "aa");
 fh.addEntry("field3", "aaz");
 fh.addEntry("field3", "aa\xe6"); // 0xae == latin ae pair (0xc6 == AE)
 fh.addEntry("field3", "az");
 fh.addEntry("field3", "z");
 fh.addEntry("field4", "a\xe6");
 fh.addEntry("field4", "aa a\xe6");
 fh.addEntry("field4", "aba\xe6");
 fh.addEntry("field4", "bc d\xe6");
+fh.addEntry("field5", "1");
+fh.addEntry("field5", "12");
+fh.addEntry("field5", "123");
+fh.addEntry("field5", "1234");
 
 // Restore the form to the default state.
 function restoreForm() {
     input.value = "";
     input.focus();
 }
 
 // Check for expected form data.
@@ -516,16 +526,99 @@ function runTest(testNum) {
         // check inserting in multi-word searches
         checkMenuEntries(["bc d\xe6"]);
         sendChar("z", input);
         break;
 
     case 256:
         checkMenuEntries([]);
 
+        // Look at form 7, try to trigger autocomplete popup
+        input = $_(7, "field5");
+        restoreForm();
+        doKey("down");
+        testNum = 299;
+        break;
+
+    case 300:
+        checkMenuEntries(["1", "12", "123", "1234"]);
+        input.maxLength = 4;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 301:
+        checkMenuEntries(["1", "12", "123", "1234"]);
+        input.maxLength = 3;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 302:
+        checkMenuEntries(["1", "12", "123"]);
+        input.maxLength = 2;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 303:
+        checkMenuEntries(["1", "12"]);
+        input.maxLength = 1;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 304:
+        checkMenuEntries(["1"]);
+        input.maxLength = 0;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 305:
+        checkMenuEntries([]);
+        input.maxLength = 4;
+
+        // now again with a character typed
+        sendChar("1", input);
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 306:
+        checkMenuEntries(["1", "12", "123", "1234"]);
+        input.maxLength = 3;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 307:
+        checkMenuEntries(["1", "12", "123"]);
+        input.maxLength = 2;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 308:
+        checkMenuEntries(["1", "12"]);
+        input.maxLength = 1;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 309:
+        checkMenuEntries(["1"]);
+        input.maxLength = 0;
+        doKey("escape");
+        doKey("down");
+        break;
+
+    case 310:
+        checkMenuEntries([]);
+
         SimpleTest.finish();
         return;
 
     default:
         ok(false, "Unexpected invocation of test #" + testNum);
         SimpleTest.finish();
         return;
   }
--- a/toolkit/components/satchel/test/unit/test_autocomplete.js
+++ b/toolkit/components/satchel/test/unit/test_autocomplete.js
@@ -126,33 +126,33 @@ function run_test() {
         testnum++;
         do_check_true(fh.hasEntries);
         do_check_eq(numRecords, countAllEntries());
         do_check_true(fh.nameExists("field1"));
 
         // ===== 2 =====
         // Check search contains all entries
         testnum++;
-        results = fac.autoCompleteSearch("field1", "", null);
+        results = fac.autoCompleteSearch("field1", "", null, null);
         do_check_eq(numRecords, results.matchCount);
 
         // ===== 3 =====
         // Check search result ordering with empty search term
         testnum++;
-        results = fac.autoCompleteSearch("field1", "", null);
+        results = fac.autoCompleteSearch("field1", "", null, null);
         let lastFound = numRecords;
         for (let i = 0; i < numRecords; i+=2) {
             do_check_eq(parseInt(results.getValueAt(i + 1).substr(5), 10), --lastFound);
             do_check_eq(parseInt(results.getValueAt(i).substr(5), 10), --lastFound);
         }
 
         // ===== 4 =====
         // Check search result ordering with "v"
         testnum++;
-        results = fac.autoCompleteSearch("field1", "v", null);
+        results = fac.autoCompleteSearch("field1", "v", null, null);
         lastFound = numRecords;
         for (let i = 0; i < numRecords; i+=2) {
             do_check_eq(parseInt(results.getValueAt(i + 1).substr(5), 10), --lastFound);
             do_check_eq(parseInt(results.getValueAt(i).substr(5), 10), --lastFound);
         }
 
         // ===== Tests with constant use dates and varying timesUsed =====
 
@@ -171,26 +171,26 @@ function run_test() {
                   now +
               ");");
         }
         fh.DBConnection.commitTransaction();
 
         // ===== 5 =====
         // Check search result ordering with empty search term
         testnum++;
-        results = fac.autoCompleteSearch("field2", "", null);
+        results = fac.autoCompleteSearch("field2", "", null, null);
         lastFound = timesUsedSamples;
         for (let i = 0; i < timesUsedSamples; i++) {
             do_check_eq(parseInt(results.getValueAt(i).substr(5)), --lastFound);
         }
 
         // ===== 6 =====
         // Check search result ordering with "v"
         testnum++;
-        results = fac.autoCompleteSearch("field2", "v", null);
+        results = fac.autoCompleteSearch("field2", "v", null, null);
         lastFound = timesUsedSamples;
         for (let i = 0; i < timesUsedSamples; i++) {
             do_check_eq(parseInt(results.getValueAt(i).substr(5)), --lastFound);
         }
 
         // ===== 7 =====
         // Check that "senior citizen" entries get a bonus (browser.formfill.agedBonus)
         testnum++;
@@ -212,17 +212,17 @@ function run_test() {
           "VALUES ("+
               "'field3', " +
               "'senior citizen', " +
               "100, " +
               agedDate + ", " +
               now +
           ");");
 
-        results = fac.autoCompleteSearch("field3", "", null);
+        results = fac.autoCompleteSearch("field3", "", null, null);
         do_check_eq(results.getValueAt(0), "senior citizen");
         do_check_eq(results.getValueAt(1), "old but not senior");
 
         // ===== 8 =====
         // Check entries that are really old or in the future
         testnum++;
         fh.DBConnection.executeSimpleSQL(
           "INSERT INTO moz_formhistory "+
@@ -252,16 +252,16 @@ function run_test() {
           "VALUES ("+
               "'field4', " +
               "'in the future 2', " +
               "1, " +
               (now * 2) + ", " +
               (now * 2) +
           ");");
 
-        results = fac.autoCompleteSearch("field4", "", null);
+        results = fac.autoCompleteSearch("field4", "", null, null);
         do_check_eq(results.matchCount, 3);
 
 
     } catch (e) {
       throw "FAILED in test #" + testnum + " -- " + e;
     }
 }