Bug 1024437 - Make <datalist> work in e10s. r=MattN

This commit is contained in:
Blake Kaplan 2015-05-28 09:55:46 -07:00
parent 7b5ef0f481
commit 80be7ba197
9 changed files with 272 additions and 170 deletions

View File

@ -5885,7 +5885,7 @@ var FormAssistant = {
this._formAutoCompleteService.autoCompleteSearchAsync(aElement.name || aElement.id,
aSearchString, aElement, null,
resultsAvailable);
null, resultsAvailable);
},
/**

View File

@ -12,6 +12,7 @@ this.EXPORTED_SYMBOLS = [ "AutoCompleteE10S" ];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm");
// nsITreeView implementation that feeds the autocomplete popup
// with the search data.
@ -142,14 +143,33 @@ this.AutoCompleteE10S = {
this._initPopup(browserWindow, rect, direction);
// NB: We use .wrappedJSObject here in order to pass our mock DOM object
// without being rejected by XPConnect (which attempts to enforce that DOM
// objects are implemented in C++.
let formAutoComplete = Cc["@mozilla.org/satchel/form-autocomplete;1"]
.getService(Ci.nsIFormAutoComplete);
.getService(Ci.nsIFormAutoComplete).wrappedJSObject;
let values, labels;
if (message.data.datalistResult) {
// Create a full FormAutoCompleteResult from the mock one that we pass
// over IPC.
message.data.datalistResult =
new FormAutoCompleteResult(message.data.untrimmedSearchString,
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
0, "", message.data.datalistResult.values,
message.data.datalistResult.labels,
[], null);
} else {
message.data.datalistResult = null;
}
formAutoComplete.autoCompleteSearchAsync(message.data.inputName,
message.data.untrimmedSearchString,
message.data.mockField,
null,
null,
this.onSearchComplete.bind(this));
message.data.datalistResult,
{ onSearchCompletion:
this.onSearchComplete.bind(this) });
},
// The second half of search, this fills in the popup and returns the

View File

@ -1,14 +1,14 @@
/* vim: set ts=4 sts=4 sw=4 et tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
@ -17,6 +17,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
"resource://gre/modules/FormHistory.jsm");
function isAutocompleteDisabled(aField) {
if (aField.autocomplete !== "") {
return aField.autocomplete === "off";
}
return aField.form && aField.form.autocomplete === "off";
}
function FormAutoComplete() {
this.init();
}
@ -107,6 +115,11 @@ FormAutoComplete.prototype = {
}
},
// AutoCompleteE10S needs to be able to call autoCompleteSearchAsync without
// going through IDL in order to pass a mock DOM object field.
get wrappedJSObject() {
return this;
},
/*
* log
@ -128,19 +141,36 @@ FormAutoComplete.prototype = {
* aUntrimmedSearchString -- current value of the input
* aField -- nsIDOMHTMLInputElement being autocompleted (may be null if from chrome)
* aPreviousResult -- previous search result, if any.
* aDatalistResult -- results from list=datalist for aField.
* aListener -- nsIFormAutoCompleteObserver that listens for the nsIAutoCompleteResult
* that may be returned asynchronously.
*/
autoCompleteSearchAsync : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult, aListener) {
autoCompleteSearchAsync : function (aInputName,
aUntrimmedSearchString,
aField,
aPreviousResult,
aDatalistResult,
aListener) {
function sortBytotalScore (a, b) {
return b.totalScore - a.totalScore;
}
let result = null;
// Guard against void DOM strings filtering into this code.
if (typeof aInputName === "object") {
aInputName = "";
}
if (typeof aUntrimmedSearchString === "object") {
aUntrimmedSearchString = "";
}
// If we have datalist results, they become our "empty" result.
let emptyResult = aDatalistResult ||
new FormAutoCompleteResult(FormHistory, [],
aInputName,
aUntrimmedSearchString);
if (!this._enabled) {
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
if (aListener) {
aListener.onSearchCompletion(result);
aListener.onSearchCompletion(emptyResult);
}
return;
}
@ -148,9 +178,16 @@ FormAutoComplete.prototype = {
// don't allow form inputs (aField != null) to get results from search bar history
if (aInputName == 'searchbar-history' && aField) {
this.log('autoCompleteSearch for input name "' + aInputName + '" is denied');
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
if (aListener) {
aListener.onSearchCompletion(result);
aListener.onSearchCompletion(emptyResult);
}
return;
}
if (aField && isAutocompleteDisabled(aField)) {
this.log('autoCompleteSearch not allowed due to autcomplete=off');
if (aListener) {
aListener.onSearchCompletion(emptyResult);
}
return;
}
@ -164,13 +201,41 @@ FormAutoComplete.prototype = {
if (aPreviousResult && aPreviousResult.searchString.trim().length > 1 &&
searchString.indexOf(aPreviousResult.searchString.trim().toLowerCase()) >= 0) {
this.log("Using previous autocomplete result");
result = aPreviousResult;
result.wrappedJSObject.searchString = aUntrimmedSearchString;
let result = aPreviousResult;
let wrappedResult = result.wrappedJSObject;
wrappedResult.searchString = aUntrimmedSearchString;
// Leaky abstraction alert: it would be great to be able to split
// this code between nsInputListAutoComplete and here but because of
// the way we abuse the formfill autocomplete API in e10s, we have
// to deal with the <datalist> results here as well (and down below
// in mergeResults).
// If there were datalist results result is a FormAutoCompleteResult
// as defined in nsFormAutoCompleteResult.jsm with the entire list
// of results in wrappedResult._values and only the results from
// form history in wrappedResults.entries.
// First, grab the entire list of old results.
let allResults = wrappedResult._values;
let datalistResults, datalistLabels;
if (allResults) {
// We have datalist results, extract them from the values array.
datalistResults = allResults.slice(wrappedResult.entries.length);
let filtered = [];
datalistLabels = [];
for (let i = datalistResults.length; i > 0; --i) {
if (datalistResults[i - 1].contains(searchString)) {
filtered.push(datalistResults[i - 1]);
datalistLabels.push(wrappedResult._labels[i - 1]);
}
}
datalistResults = filtered;
}
let searchTokens = searchString.split(/\s+/);
// We have a list of results for a shorter search string, so just
// filter them further based on the new search string and add to a new array.
let entries = result.wrappedJSObject.entries;
let entries = wrappedResult.entries;
let filteredEntries = [];
for (let i = 0; i < entries.length; i++) {
let entry = entries[i];
@ -184,34 +249,90 @@ FormAutoComplete.prototype = {
filteredEntries.push(entry);
}
filteredEntries.sort(sortBytotalScore);
result.wrappedJSObject.entries = filteredEntries;
wrappedResult.entries = filteredEntries;
// If we had datalistResults, re-merge them back into the filtered
// entries.
if (datalistResults) {
filteredEntries = filteredEntries.map(elt => elt.text);
let comments = new Array(filteredEntries.length + datalistResults.length).fill("");
comments[filteredEntries.length] = "separator";
datalistLabels = new Array(filteredEntries.length).fill("").concat(datalistLabels);
wrappedResult._values = filteredEntries.concat(datalistResults);
wrappedResult._labels = datalistLabels;
wrappedResult._comments = comments;
}
if (aListener) {
aListener.onSearchCompletion(result);
aListener.onSearchCompletion(result);
}
} else {
this.log("Creating new autocomplete search result.");
// Start with an empty list.
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
let result = aDatalistResult ?
new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString) :
emptyResult;
let processEntry = function(aEntries) {
if (aField && aField.maxLength > -1) {
result.entries =
aEntries.filter(function (el) { return el.text.length <= aField.maxLength; });
} else {
result.entries = aEntries;
}
let processEntry = (aEntries) => {
if (aField && aField.maxLength > -1) {
result.entries =
aEntries.filter(function (el) { return el.text.length <= aField.maxLength; });
} else {
result.entries = aEntries;
}
if (aListener) {
aListener.onSearchCompletion(result);
}
if (aDatalistResult) {
result = this.mergeResults(result, aDatalistResult);
}
if (aListener) {
aListener.onSearchCompletion(result);
}
}
this.getAutoCompleteValues(aInputName, searchString, processEntry);
}
},
mergeResults(historyResult, datalistResult) {
let values = datalistResult.wrappedJSObject._values;
let labels = datalistResult.wrappedJSObject._labels;
let comments = [];
// formHistoryResult will be null if form autocomplete is disabled. We
// still want the list values to display.
let entries = historyResult.wrappedJSObject.entries;
let historyResults = entries.map(function(entry) { return entry.text });
let historyComments = new Array(entries.length).fill("");
// fill out the comment column for the suggestions
// if we have any suggestions, put a label at the top
if (values.length) {
comments[0] = "separator";
comments.fill(1, "");
}
// now put the history results above the datalist suggestions
let finalValues = historyResults.concat(values);
let finalLabels = historyResults.concat(labels);
let finalComments = historyComments.concat(comments);
// This is ugly: there are two FormAutoCompleteResult classes in the
// tree, one in a module and one in this file. Datalist results need to
// use the one defined in the module but the rest of this file assumes
// that we use the one defined here. To get around that, we explicitly
// import the module here, out of the way of the other uses of
// FormAutoCompleteResult.
let {FormAutoCompleteResult} = Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm", {});
return new FormAutoCompleteResult(datalistResult.searchString,
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
0, "", finalValues, finalLabels,
finalComments, historyResult);
},
stopAutoCompleteSearch : function () {
if (this._pendingQuery) {
this._pendingQuery.cancel();
@ -338,7 +459,9 @@ FormAutoCompleteChild.prototype = {
dump("FormAutoCompleteChild: " + message + "\n");
},
autoCompleteSearchAsync : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult, aListener) {
autoCompleteSearchAsync : function (aInputName, aUntrimmedSearchString,
aField, aPreviousResult, aDatalistResult,
aListener) {
this.log("autoCompleteSearchAsync");
if (this._pendingSearch) {
@ -349,6 +472,17 @@ FormAutoCompleteChild.prototype = {
let rect = BrowserUtils.getElementBoundingScreenRect(aField);
let direction = window.getComputedStyle(aField).direction;
let mockField = {};
if (isAutocompleteDisabled(aField))
mockField.autocomplete = "off";
if (aField.maxLength > -1)
mockField.maxLength = aField.maxLength;
let datalistResult = aDatalistResult ?
{ values: aDatalistResult.wrappedJSObject._values,
labels: aDatalistResult.wrappedJSObject._labels} :
null;
let topLevelDocshell = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
@ -360,6 +494,8 @@ FormAutoCompleteChild.prototype = {
mm.sendAsyncMessage("FormHistory:AutoCompleteSearchAsync", {
inputName: aInputName,
untrimmedSearchString: aUntrimmedSearchString,
mockField: mockField,
datalistResult: datalistResult,
left: rect.left,
top: rect.top,
width: rect.width,
@ -451,7 +587,7 @@ FormAutoCompleteResult.prototype = {
},
getLabelAt: function(index) {
return getValueAt(index);
return this.getValueAt(index);
},
getCommentAt : function (index) {

View File

@ -1,4 +1,3 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -42,8 +41,7 @@ using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION(nsFormFillController,
mController, mLoginManager, mFocusedPopup, mDocShells,
mPopups, mLastSearchResult, mLastListener,
mLastFormAutoComplete)
mPopups, mLastListener, mLastFormAutoComplete)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormFillController)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFormFillController)
@ -217,8 +215,7 @@ nsFormFillController::MaybeRemoveMutationObserver(nsINode* aNode)
{
// Nodes being tracked in mPwmgrInputs will have their observers removed when
// they stop being tracked.
bool dummy;
if (!mPwmgrInputs.Get(aNode, &dummy)) {
if (!mPwmgrInputs.Get(aNode)) {
aNode->RemoveMutationObserver(this);
}
}
@ -637,8 +634,7 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin
// If the login manager has indicated it's responsible for this field, let it
// handle the autocomplete. Otherwise, handle with form history.
bool dummy;
if (mPwmgrInputs.Get(mFocusedInputNode, &dummy)) {
if (mPwmgrInputs.Get(mFocusedInputNode)) {
// XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
// satchel manage the field?
mLastListener = aListener;
@ -650,81 +646,64 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin
} else {
mLastListener = aListener;
// It appears that mFocusedInput is always null when we are focusing a XUL
// element. Scary :)
if (!mFocusedInput || nsContentUtils::IsAutocompleteEnabled(mFocusedInput)) {
nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
nsCOMPtr<nsIAutoCompleteResult> datalistResult;
if (mFocusedInput) {
rv = PerformInputListAutoComplete(aSearchString,
getter_AddRefs(datalistResult));
NS_ENSURE_SUCCESS(rv, rv);
formAutoComplete->AutoCompleteSearchAsync(aSearchParam,
aSearchString,
mFocusedInput,
aPreviousResult,
this);
mLastFormAutoComplete = formAutoComplete;
} else {
mLastSearchString = aSearchString;
// Even if autocomplete is disabled, handle the inputlist anyway as that was
// specifically requested by the page. This is so a field can have the default
// autocomplete disabled and replaced with a custom inputlist autocomplete.
return PerformInputListAutoComplete(aPreviousResult);
}
nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
formAutoComplete->AutoCompleteSearchAsync(aSearchParam,
aSearchString,
mFocusedInput,
aPreviousResult,
datalistResult,
this);
mLastFormAutoComplete = formAutoComplete;
}
return NS_OK;
}
nsresult
nsFormFillController::PerformInputListAutoComplete(nsIAutoCompleteResult* aPreviousResult)
nsFormFillController::PerformInputListAutoComplete(const nsAString& aSearch,
nsIAutoCompleteResult** aResult)
{
// If an <input> is focused, check if it has a list="<datalist>" which can
// provide the list of suggestions.
MOZ_ASSERT(!mPwmgrInputs.Get(mFocusedInputNode));
nsresult rv;
nsCOMPtr<nsIAutoCompleteResult> result;
bool dummy;
if (!mPwmgrInputs.Get(mFocusedInputNode, &dummy)) {
nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = inputListAutoComplete->AutoCompleteSearch(aPreviousResult,
mLastSearchString,
mFocusedInput,
getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = inputListAutoComplete->AutoCompleteSearch(aSearch,
mFocusedInput,
aResult);
NS_ENSURE_SUCCESS(rv, rv);
if (mFocusedInput) {
nsCOMPtr<nsIDOMHTMLElement> list;
mFocusedInput->GetList(getter_AddRefs(list));
if (mFocusedInput) {
nsCOMPtr<nsIDOMHTMLElement> list;
mFocusedInput->GetList(getter_AddRefs(list));
// Add a mutation observer to check for changes to the items in the <datalist>
// and update the suggestions accordingly.
nsCOMPtr<nsINode> node = do_QueryInterface(list);
if (mListNode != node) {
if (mListNode) {
mListNode->RemoveMutationObserver(this);
mListNode = nullptr;
}
if (node) {
node->AddMutationObserverUnlessExists(this);
mListNode = node;
}
// Add a mutation observer to check for changes to the items in the <datalist>
// and update the suggestions accordingly.
nsCOMPtr<nsINode> node = do_QueryInterface(list);
if (mListNode != node) {
if (mListNode) {
mListNode->RemoveMutationObserver(this);
mListNode = nullptr;
}
if (node) {
node->AddMutationObserverUnlessExists(this);
mListNode = node;
}
}
} else {
result = aPreviousResult;
// If this is a password manager input mLastSearchResult will be a JS
// object (wrapped in an XPConnect reflector), so we need to take care not
// to hold onto it for too long.
mLastSearchResult = nullptr;
}
if (mLastListener) {
mLastListener->OnSearchResult(this, result);
}
return NS_OK;
@ -759,14 +738,24 @@ void nsFormFillController::RevalidateDataList()
if (!mLastListener) {
return;
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
nsCOMPtr<nsIAutoCompleteController> controller(do_QueryInterface(mLastListener));
if (!controller) {
return;
}
controller->StartSearch(mLastSearchString);
return;
}
nsresult rv;
nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
nsCOMPtr<nsIAutoCompleteResult> result;
rv = inputListAutoComplete->AutoCompleteSearch(mLastSearchResult,
mLastSearchString,
rv = inputListAutoComplete->AutoCompleteSearch(mLastSearchString,
mFocusedInput,
getter_AddRefs(result));
@ -793,14 +782,16 @@ nsFormFillController::StopSearch()
NS_IMETHODIMP
nsFormFillController::OnSearchCompletion(nsIAutoCompleteResult *aResult)
{
nsCOMPtr<nsIAutoCompleteResult> resultParam = do_QueryInterface(aResult);
nsAutoString searchString;
resultParam->GetSearchString(searchString);
mLastSearchResult = aResult;
aResult->GetSearchString(searchString);
mLastSearchString = searchString;
return PerformInputListAutoComplete(resultParam);
if (mLastListener) {
mLastListener->OnSearchResult(this, aResult);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
@ -905,9 +896,8 @@ nsFormFillController::MaybeStartControllingInput(nsIDOMHTMLInputElement* aInput)
aInput->GetList(getter_AddRefs(datalist));
bool hasList = datalist != nullptr;
bool dummy;
bool isPwmgrInput = false;
if (mPwmgrInputs.Get(inputNode, &dummy))
if (mPwmgrInputs.Get(inputNode))
isPwmgrInput = true;
if (isPwmgrInput || hasList || autocomplete) {

View File

@ -72,7 +72,8 @@ protected:
*/
void MaybeStartControllingInput(nsIDOMHTMLInputElement* aElement);
nsresult PerformInputListAutoComplete(nsIAutoCompleteResult* aPreviousResult);
nsresult PerformInputListAutoComplete(const nsAString& aSearch,
nsIAutoCompleteResult** aResult);
void RevalidateDataList();
bool RowMatch(nsFormHistory *aHistory, uint32_t aIndex, const nsAString &aInputName, const nsAString &aInputValue);
@ -102,9 +103,6 @@ protected:
nsTArray<nsCOMPtr<nsIDocShell> > mDocShells;
nsTArray<nsCOMPtr<nsIAutoCompletePopup> > mPopups;
//these are used to dynamically update the autocomplete
nsCOMPtr<nsIAutoCompleteResult> mLastSearchResult;
// The observer passed to StartSearch. It will be notified when the search is
// complete or the data from a datalist changes.
nsCOMPtr<nsIAutoCompleteObserver> mLastListener;

View File

@ -9,7 +9,7 @@ interface nsIAutoCompleteResult;
interface nsIFormAutoCompleteObserver;
interface nsIDOMHTMLInputElement;
[scriptable, uuid(1d5b18b1-25f9-4407-9a0f-076dba1e41a0)]
[scriptable, uuid(bfd9b82b-0ab3-4b6b-9e54-aa961ff4b732)]
interface nsIFormAutoComplete: nsISupports {
/**
* Generate results for a form input autocomplete menu asynchronously.
@ -18,6 +18,7 @@ interface nsIFormAutoComplete: nsISupports {
in AString aSearchString,
in nsIDOMHTMLInputElement aField,
in nsIAutoCompleteResult aPreviousResult,
in nsIAutoCompleteResult aDatalistResult,
in nsIFormAutoCompleteObserver aListener);
/**

View File

@ -7,13 +7,11 @@
interface nsIAutoCompleteResult;
interface nsIDOMHTMLInputElement;
[scriptable, uuid(9e7ba3eb-a9cf-4861-93e0-82e93d836f7a)]
[scriptable, uuid(0e33de3e-4faf-4a1a-b96e-24115b8bfd45)]
interface nsIInputListAutoComplete: nsISupports {
/**
* Generate results for a form input autocomplete menu.
*/
nsIAutoCompleteResult autoCompleteSearch(in nsIAutoCompleteResult aResult,
in AString aSearchString,
nsIAutoCompleteResult autoCompleteSearch(in AString aSearchString,
in nsIDOMHTMLInputElement aField);
};

View File

@ -14,40 +14,14 @@ InputListAutoComplete.prototype = {
classID : Components.ID("{bf1e01d0-953e-11df-981c-0800200c9a66}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIInputListAutoComplete]),
autoCompleteSearch : function (formHistoryResult, aUntrimmedSearchString, aField) {
let comments = []; // "comments" column values for suggestions
autoCompleteSearch : function (aUntrimmedSearchString, aField) {
let [values, labels] = this.getListSuggestions(aField);
let historyResults = [];
let historyComments = [];
// formHistoryResult will be null if form autocomplete is disabled.
// We still want the list values to display.
if (formHistoryResult) {
let entries = formHistoryResult.wrappedJSObject.entries;
for (let i = 0; i < entries.length; ++i) {
historyResults.push(entries[i].text);
historyComments.push("");
}
}
// fill out the comment column for the suggestions
// if we have any suggestions, put a label at the top
if (values.length) {
comments[0] = "separator";
}
for (let i = 1; i < values.length; ++i) {
comments.push("");
}
// now put the history results above the suggestions
let finalValues = historyResults.concat(values);
let finalLabels = historyResults.concat(labels);
let finalComments = historyComments.concat(comments);
if (values.length === 0)
return null;
return new FormAutoCompleteResult(aUntrimmedSearchString,
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
0, "", finalValues, finalLabels,
finalComments, formHistoryResult);
0, "", values, labels,
[], null);
},
getListSuggestions : function (aField) {

View File

@ -85,7 +85,7 @@ add_test(function test1() {
add_test(function test2() {
do_log_info("Check search contains all entries");
fac.autoCompleteSearchAsync("field1", "", null, null, {
fac.autoCompleteSearchAsync("field1", "", null, null, null, {
onSearchCompletion : function(aResults) {
do_check_eq(numRecords, aResults.matchCount);
run_next_test();
@ -97,7 +97,7 @@ add_test(function test3() {
do_log_info("Check search result ordering with empty search term");
let lastFound = numRecords;
fac.autoCompleteSearchAsync("field1", "", null, null, {
fac.autoCompleteSearchAsync("field1", "", null, null, null, {
onSearchCompletion : function(aResults) {
for (let i = 0; i < numRecords; i+=2) {
do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound);
@ -112,7 +112,7 @@ add_test(function test4() {
do_log_info("Check search result ordering with \"v\"");
let lastFound = numRecords;
fac.autoCompleteSearchAsync("field1", "v", null, null, {
fac.autoCompleteSearchAsync("field1", "v", null, null, null, {
onSearchCompletion : function(aResults) {
for (let i = 0; i < numRecords; i+=2) {
do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound);
@ -142,7 +142,7 @@ add_test(function test6() {
do_log_info("Check search result ordering with empty search term");
let lastFound = timesUsedSamples;
fac.autoCompleteSearchAsync("field2", "", null, null, {
fac.autoCompleteSearchAsync("field2", "", null, null, null, {
onSearchCompletion : function(aResults) {
for (let i = 0; i < timesUsedSamples; i++) {
do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound);
@ -156,7 +156,7 @@ add_test(function test7() {
do_log_info("Check search result ordering with \"v\"");
let lastFound = timesUsedSamples;
fac.autoCompleteSearchAsync("field2", "v", null, null, {
fac.autoCompleteSearchAsync("field2", "v", null, null, null, {
onSearchCompletion : function(aResults) {
for (let i = 0; i < timesUsedSamples; i++) {
do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound);
@ -180,7 +180,7 @@ add_test(function test8() {
});
add_test(function test9() {
fac.autoCompleteSearchAsync("field3", "", null, null, {
fac.autoCompleteSearchAsync("field3", "", null, null, null, {
onSearchCompletion : function(aResults) {
do_check_eq(aResults.getValueAt(0), "senior citizen");
do_check_eq(aResults.getValueAt(1), "old but not senior");
@ -203,7 +203,7 @@ add_test(function test10() {
});
add_test(function test11() {
fac.autoCompleteSearchAsync("field4", "", null, null, {
fac.autoCompleteSearchAsync("field4", "", null, null, null, {
onSearchCompletion : function(aResults) {
do_check_eq(aResults.matchCount, 3);
run_next_test();
@ -223,21 +223,6 @@ add_test(function test12() {
updateFormHistory(changes, run_next_test);
});
add_test(function test13() {
let autocompleteService = Cc["@mozilla.org/satchel/form-autocomplete;1"].getService(Ci.nsIFormAutoComplete);
let results = autocompleteService.autoCompleteSearch("field5", "", null, null);
do_check_eq(results.matchCount, syncValues.length, "synchronous matchCount");
for (let i = 0; i < results.matchCount; i++) {
do_check_eq(results.getValueAt(i), syncValues[i]);
}
results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null);
do_check_eq(results.matchCount, 2, "synchronous matchCount");
do_check_eq(results.getValueAt(0), "sync1");
do_check_eq(results.getValueAt(1), "sync1a");
run_next_test();
});
add_test(function test_token_limit_DB() {
function test_token_limit_previousResult(previousResult) {
do_log_info("Check that the number of tokens used in a search is not capped to " +
@ -247,7 +232,7 @@ add_test(function test_token_limit_DB() {
// when re-using a previous result.
fac.autoCompleteSearchAsync("field_token_cap",
"a b c d e f g h i j .",
null, previousResult, {
null, previousResult, null, {
onSearchCompletion : function(aResults) {
do_check_eq(aResults.matchCount, 0,
"All search tokens should be used with " +
@ -269,7 +254,7 @@ add_test(function test_token_limit_DB() {
// (which would prevent the result from being returned if the 11th term was used).
fac.autoCompleteSearchAsync("field_token_cap",
"a b c d e f g h i j .",
null, null, {
null, null, null, {
onSearchCompletion : function(aResults) {
do_check_eq(aResults.matchCount, 1,
"Only the first MAX_SEARCH_TOKENS tokens " +