зеркало из https://github.com/mozilla/gecko-dev.git
Bug 720589 - mMatchCounts may be accessed with a nonexisting index. r=neil
This commit is contained in:
Родитель
651792a7c1
Коммит
2cb37ef1e6
|
@ -132,7 +132,6 @@ nsAutoCompleteController::SetInput(nsIAutoCompleteInput *aInput)
|
|||
aInput->GetSearchCount(&searchCount);
|
||||
mResults.SetCapacity(searchCount);
|
||||
mSearches.SetCapacity(searchCount);
|
||||
mMatchCounts.SetLength(searchCount);
|
||||
mImmediateSearchesCount = 0;
|
||||
|
||||
const char *searchCID = kAutoCompleteSearchCID;
|
||||
|
@ -629,7 +628,7 @@ nsAutoCompleteController::HandleDelete(bool *_retval)
|
|||
RowIndexToSearch(index, &searchIndex, &rowIndex);
|
||||
NS_ENSURE_TRUE(searchIndex >= 0 && rowIndex >= 0, NS_ERROR_FAILURE);
|
||||
|
||||
nsIAutoCompleteResult *result = mResults[searchIndex];
|
||||
nsIAutoCompleteResult *result = mResults.SafeObjectAt(searchIndex);
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoString search;
|
||||
|
@ -691,7 +690,7 @@ nsAutoCompleteController::GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aR
|
|||
RowIndexToSearch(aIndex, &searchIndex, aRowIndex);
|
||||
NS_ENSURE_TRUE(searchIndex >= 0 && *aRowIndex >= 0, NS_ERROR_FAILURE);
|
||||
|
||||
*aResult = mResults[searchIndex];
|
||||
*aResult = mResults.SafeObjectAt(searchIndex);
|
||||
NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1522,39 +1521,50 @@ nsresult
|
|||
nsAutoCompleteController::ProcessResult(int32_t aSearchIndex, nsIAutoCompleteResult *aResult)
|
||||
{
|
||||
NS_ENSURE_STATE(mInput);
|
||||
MOZ_ASSERT(aResult, "ProcessResult should always receive a result");
|
||||
NS_ENSURE_ARG(aResult);
|
||||
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
|
||||
|
||||
uint16_t result = 0;
|
||||
if (aResult)
|
||||
aResult->GetSearchResult(&result);
|
||||
uint16_t searchResult = 0;
|
||||
aResult->GetSearchResult(&searchResult);
|
||||
|
||||
uint32_t oldMatchCount = 0;
|
||||
uint32_t matchCount = 0;
|
||||
if (aResult)
|
||||
aResult->GetMatchCount(&matchCount);
|
||||
|
||||
int32_t resultIndex = mResults.IndexOf(aResult);
|
||||
if (resultIndex == -1) {
|
||||
// cache the result
|
||||
mResults.AppendObject(aResult);
|
||||
mMatchCounts.AppendElement(matchCount);
|
||||
resultIndex = mResults.Count() - 1;
|
||||
}
|
||||
else {
|
||||
oldMatchCount = mMatchCounts[aSearchIndex];
|
||||
mMatchCounts[resultIndex] = matchCount;
|
||||
// The following code supports incremental updating results in 2 ways:
|
||||
// * The search may reuse the same result, just by adding entries to it.
|
||||
// * The search may send a new result every time. In this case we merge
|
||||
// the results and proceed on the same code path as before.
|
||||
// This way both mSearches and mResults can be indexed by the search index,
|
||||
// cause we'll always have only one result per search.
|
||||
if (mResults.IndexOf(aResult) == -1) {
|
||||
nsIAutoCompleteResult* oldResult = mResults.SafeObjectAt(aSearchIndex);
|
||||
if (oldResult) {
|
||||
MOZ_ASSERT(false, "Passing new matches to OnSearchResult with a new "
|
||||
"nsIAutoCompleteResult every time is deprecated, please "
|
||||
"update the same result until the search is done");
|
||||
// Build a new nsIAutocompleteSimpleResult and merge results into it.
|
||||
RefPtr<nsAutoCompleteSimpleResult> mergedResult =
|
||||
new nsAutoCompleteSimpleResult();
|
||||
mergedResult->AppendResult(oldResult);
|
||||
mergedResult->AppendResult(aResult);
|
||||
mResults.ReplaceObjectAt(mergedResult, aSearchIndex);
|
||||
} else {
|
||||
// This inserts and grows the array if needed.
|
||||
mResults.ReplaceObjectAt(aResult, aSearchIndex);
|
||||
}
|
||||
}
|
||||
// When found the result should have the same index as the search.
|
||||
MOZ_ASSERT_IF(mResults.IndexOf(aResult) != -1,
|
||||
mResults.IndexOf(aResult) == aSearchIndex);
|
||||
MOZ_ASSERT(mResults.Count() >= aSearchIndex + 1,
|
||||
"aSearchIndex should always be valid for mResults");
|
||||
|
||||
bool isTypeAheadResult = false;
|
||||
if (aResult) {
|
||||
aResult->GetTypeAheadResult(&isTypeAheadResult);
|
||||
}
|
||||
aResult->GetTypeAheadResult(&isTypeAheadResult);
|
||||
|
||||
if (!isTypeAheadResult) {
|
||||
uint32_t oldRowCount = mRowCount;
|
||||
// If the search failed, increase the match count to include the error
|
||||
// description.
|
||||
if (result == nsIAutoCompleteResult::RESULT_FAILURE) {
|
||||
if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) {
|
||||
nsAutoString error;
|
||||
aResult->GetErrorDescription(error);
|
||||
if (!error.IsEmpty()) {
|
||||
|
@ -1563,13 +1573,28 @@ nsAutoCompleteController::ProcessResult(int32_t aSearchIndex, nsIAutoCompleteRes
|
|||
mTree->RowCountChanged(oldRowCount, 1);
|
||||
}
|
||||
}
|
||||
} else if (result == nsIAutoCompleteResult::RESULT_SUCCESS ||
|
||||
result == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
|
||||
} else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
|
||||
searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
|
||||
// Increase the match count for all matches in this result.
|
||||
mRowCount += matchCount - oldMatchCount;
|
||||
uint32_t totalMatchCount = 0;
|
||||
for (uint32_t i = 0; i < mResults.Length(); i++) {
|
||||
nsIAutoCompleteResult* result = mResults.SafeObjectAt(i);
|
||||
if (result) {
|
||||
// not all results implement this, so it can likely fail.
|
||||
bool typeAhead = false;
|
||||
result->GetTypeAheadResult(&typeAhead);
|
||||
if (!typeAhead) {
|
||||
uint32_t matchCount = 0;
|
||||
result->GetMatchCount(&matchCount);
|
||||
totalMatchCount += matchCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t delta = totalMatchCount - oldRowCount;
|
||||
|
||||
mRowCount += delta;
|
||||
if (mTree) {
|
||||
mTree->RowCountChanged(oldRowCount, matchCount - oldMatchCount);
|
||||
mTree->RowCountChanged(oldRowCount, delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1592,10 +1617,10 @@ nsAutoCompleteController::ProcessResult(int32_t aSearchIndex, nsIAutoCompleteRes
|
|||
}
|
||||
}
|
||||
|
||||
if (result == nsIAutoCompleteResult::RESULT_SUCCESS ||
|
||||
result == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
|
||||
if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
|
||||
searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
|
||||
// Try to autocomplete the default index for this search.
|
||||
CompleteDefaultIndex(resultIndex);
|
||||
CompleteDefaultIndex(aSearchIndex);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1633,7 +1658,6 @@ nsAutoCompleteController::ClearResults()
|
|||
int32_t oldRowCount = mRowCount;
|
||||
mRowCount = 0;
|
||||
mResults.Clear();
|
||||
mMatchCounts.Clear();
|
||||
if (oldRowCount != 0) {
|
||||
if (mTree)
|
||||
mTree->RowCountChanged(0, -oldRowCount);
|
||||
|
@ -1701,14 +1725,16 @@ nsAutoCompleteController::GetDefaultCompleteResult(int32_t aResultIndex,
|
|||
|
||||
// If a result index was not provided, find the first defaultIndex result.
|
||||
for (int32_t i = 0; resultIndex < 0 && i < mResults.Count(); ++i) {
|
||||
nsIAutoCompleteResult *result = mResults[i];
|
||||
nsIAutoCompleteResult *result = mResults.SafeObjectAt(i);
|
||||
if (result &&
|
||||
NS_SUCCEEDED(result->GetDefaultIndex(_defaultIndex)) &&
|
||||
*_defaultIndex >= 0) {
|
||||
resultIndex = i;
|
||||
}
|
||||
}
|
||||
NS_ENSURE_TRUE(resultIndex >= 0, NS_ERROR_FAILURE);
|
||||
if (resultIndex < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*_result = mResults.SafeObjectAt(resultIndex);
|
||||
NS_ENSURE_TRUE(*_result, NS_ERROR_FAILURE);
|
||||
|
|
|
@ -123,10 +123,8 @@ protected:
|
|||
nsCOMPtr<nsIAutoCompleteInput> mInput;
|
||||
|
||||
nsCOMArray<nsIAutoCompleteSearch> mSearches;
|
||||
// This is used as a sparse array, always use SafeObjectAt to access it.
|
||||
nsCOMArray<nsIAutoCompleteResult> mResults;
|
||||
// Caches the match counts for the current ongoing results to allow
|
||||
// incremental results to keep the rowcount up to date.
|
||||
nsTArray<uint32_t> mMatchCounts;
|
||||
// Temporarily keeps the results alive while invoking startSearch() for each
|
||||
// search. This is needed to allow the searches to reuse the previous result,
|
||||
// since otherwise the first search clears mResults.
|
||||
|
|
|
@ -22,12 +22,14 @@ struct AutoCompleteSimpleResultMatch
|
|||
const nsAString& aComment,
|
||||
const nsAString& aImage,
|
||||
const nsAString& aStyle,
|
||||
const nsAString& aFinalCompleteValue)
|
||||
const nsAString& aFinalCompleteValue,
|
||||
const nsAString& aLabel)
|
||||
: mValue(aValue)
|
||||
, mComment(aComment)
|
||||
, mImage(aImage)
|
||||
, mStyle(aStyle)
|
||||
, mFinalCompleteValue(aFinalCompleteValue)
|
||||
, mLabel(aLabel)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -36,6 +38,7 @@ struct AutoCompleteSimpleResultMatch
|
|||
nsString mImage;
|
||||
nsString mStyle;
|
||||
nsString mFinalCompleteValue;
|
||||
nsString mLabel;
|
||||
};
|
||||
|
||||
nsAutoCompleteSimpleResult::nsAutoCompleteSimpleResult() :
|
||||
|
@ -45,6 +48,74 @@ nsAutoCompleteSimpleResult::nsAutoCompleteSimpleResult() :
|
|||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAutoCompleteSimpleResult::AppendResult(nsIAutoCompleteResult* aResult)
|
||||
{
|
||||
nsAutoString searchString;
|
||||
nsresult rv = aResult->GetSearchString(searchString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mSearchString = searchString;
|
||||
|
||||
uint16_t searchResult;
|
||||
rv = aResult->GetSearchResult(&searchResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mSearchResult = searchResult;
|
||||
|
||||
nsAutoString errorDescription;
|
||||
if (NS_SUCCEEDED(aResult->GetErrorDescription(errorDescription)) &&
|
||||
!errorDescription.IsEmpty()) {
|
||||
mErrorDescription = errorDescription;
|
||||
}
|
||||
|
||||
bool typeAheadResult = false;
|
||||
if (NS_SUCCEEDED(aResult->GetTypeAheadResult(&typeAheadResult)) &&
|
||||
typeAheadResult) {
|
||||
mTypeAheadResult = typeAheadResult;
|
||||
}
|
||||
|
||||
int32_t defaultIndex = -1;
|
||||
if (NS_SUCCEEDED(aResult->GetDefaultIndex(&defaultIndex)) &&
|
||||
defaultIndex >= 0) {
|
||||
mDefaultIndex = defaultIndex;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAutoCompleteSimpleResult> simpleResult =
|
||||
do_QueryInterface(aResult);
|
||||
if (simpleResult) {
|
||||
nsCOMPtr<nsIAutoCompleteSimpleResultListener> listener;
|
||||
if (NS_SUCCEEDED(simpleResult->GetListener(getter_AddRefs(listener))) &&
|
||||
listener) {
|
||||
listener.swap(mListener);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy matches.
|
||||
uint32_t matchCount = 0;
|
||||
rv = aResult->GetMatchCount(&matchCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (size_t i = 0; i < matchCount; ++i) {
|
||||
nsAutoString value, comment, image, style, finalCompleteValue, label;
|
||||
|
||||
rv = aResult->GetValueAt(i, value);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aResult->GetCommentAt(i, comment);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aResult->GetImageAt(i, image);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aResult->GetStyleAt(i, style);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aResult->GetFinalCompleteValueAt(i, finalCompleteValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aResult->GetLabelAt(i, label);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = AppendMatch(value, comment, image, style, finalCompleteValue, label);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// searchString
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteSimpleResult::GetSearchString(nsAString &aSearchString)
|
||||
|
@ -122,11 +193,12 @@ nsAutoCompleteSimpleResult::InsertMatchAt(int32_t aIndex,
|
|||
const nsAString& aComment,
|
||||
const nsAString& aImage,
|
||||
const nsAString& aStyle,
|
||||
const nsAString& aFinalCompleteValue)
|
||||
const nsAString& aFinalCompleteValue,
|
||||
const nsAString& aLabel)
|
||||
{
|
||||
CHECK_MATCH_INDEX(aIndex, true);
|
||||
|
||||
AutoCompleteSimpleResultMatch match(aValue, aComment, aImage, aStyle, aFinalCompleteValue);
|
||||
AutoCompleteSimpleResultMatch match(aValue, aComment, aImage, aStyle, aFinalCompleteValue, aLabel);
|
||||
|
||||
if (!mMatches.InsertElementAt(aIndex, match)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -140,10 +212,11 @@ nsAutoCompleteSimpleResult::AppendMatch(const nsAString& aValue,
|
|||
const nsAString& aComment,
|
||||
const nsAString& aImage,
|
||||
const nsAString& aStyle,
|
||||
const nsAString& aFinalCompleteValue)
|
||||
const nsAString& aFinalCompleteValue,
|
||||
const nsAString& aLabel)
|
||||
{
|
||||
return InsertMatchAt(mMatches.Length(), aValue, aComment, aImage, aStyle,
|
||||
aFinalCompleteValue);
|
||||
aFinalCompleteValue, aLabel);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -164,7 +237,12 @@ nsAutoCompleteSimpleResult::GetValueAt(int32_t aIndex, nsAString& _retval)
|
|||
NS_IMETHODIMP
|
||||
nsAutoCompleteSimpleResult::GetLabelAt(int32_t aIndex, nsAString& _retval)
|
||||
{
|
||||
return GetValueAt(aIndex, _retval);
|
||||
CHECK_MATCH_INDEX(aIndex, false);
|
||||
_retval = mMatches[aIndex].mLabel;
|
||||
if (_retval.IsEmpty()) {
|
||||
_retval = mMatches[aIndex].mValue;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -197,8 +275,9 @@ nsAutoCompleteSimpleResult::GetFinalCompleteValueAt(int32_t aIndex,
|
|||
{
|
||||
CHECK_MATCH_INDEX(aIndex, false);
|
||||
_retval = mMatches[aIndex].mFinalCompleteValue;
|
||||
if (_retval.Length() == 0)
|
||||
if (_retval.IsEmpty()) {
|
||||
_retval = mMatches[aIndex].mValue;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -209,6 +288,14 @@ nsAutoCompleteSimpleResult::SetListener(nsIAutoCompleteSimpleResultListener* aLi
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteSimpleResult::GetListener(nsIAutoCompleteSimpleResultListener** aListener)
|
||||
{
|
||||
nsCOMPtr<nsIAutoCompleteSimpleResultListener> listener(mListener);
|
||||
listener.forget(aListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteSimpleResult::RemoveValueAt(int32_t aRowIndex,
|
||||
bool aRemoveFromDb)
|
||||
|
@ -218,8 +305,9 @@ nsAutoCompleteSimpleResult::RemoveValueAt(int32_t aRowIndex,
|
|||
nsString value = mMatches[aRowIndex].mValue;
|
||||
mMatches.RemoveElementAt(aRowIndex);
|
||||
|
||||
if (mListener)
|
||||
if (mListener) {
|
||||
mListener->OnValueRemoved(this, value, aRemoveFromDb);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ public:
|
|||
NS_DECL_NSIAUTOCOMPLETERESULT
|
||||
NS_DECL_NSIAUTOCOMPLETESIMPLERESULT
|
||||
|
||||
nsresult AppendResult(nsIAutoCompleteResult* aResult);
|
||||
|
||||
private:
|
||||
~nsAutoCompleteSimpleResult() {}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ interface nsIAutoCompleteSimpleResultListener;
|
|||
* an array.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(457ce8da-9631-45c5-b3b0-293ab0928df1)]
|
||||
[scriptable, uuid(23de9c96-becb-4d0d-a9bb-1d131ce361b5)]
|
||||
interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
|
||||
{
|
||||
/**
|
||||
|
@ -69,7 +69,8 @@ interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
|
|||
in AString aComment,
|
||||
[optional] in AString aImage,
|
||||
[optional] in AString aStyle,
|
||||
[optional] in AString aFinalCompleteValue);
|
||||
[optional] in AString aFinalCompleteValue,
|
||||
[optional] in AString aLabel);
|
||||
|
||||
/**
|
||||
* Appends a match consisting of the given value, comment, image, style and
|
||||
|
@ -90,7 +91,13 @@ interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
|
|||
in AString aComment,
|
||||
[optional] in AString aImage,
|
||||
[optional] in AString aStyle,
|
||||
[optional] in AString aFinalCompleteValue);
|
||||
[optional] in AString aFinalCompleteValue,
|
||||
[optional] in AString aLabel);
|
||||
|
||||
/**
|
||||
* Gets the listener for changes in the result.
|
||||
*/
|
||||
nsIAutoCompleteSimpleResultListener getListener();
|
||||
|
||||
/**
|
||||
* Sets a listener for changes in the result.
|
||||
|
|
|
@ -146,6 +146,7 @@ AutoCompleteResult.prototype = {
|
|||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
@ -154,7 +155,7 @@ AutoCompleteSearch.prototype = {
|
|||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result:null,
|
||||
_result: null,
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Search object that returns results at different times.
|
||||
* First, the search that returns results asynchronously.
|
||||
|
@ -10,11 +7,16 @@ function AutoCompleteAsyncSearch(aName, aResult) {
|
|||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteAsyncSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
|
||||
AutoCompleteAsyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
AutoCompleteAsyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
setTimeout(this._returnResults.bind(this), 500, aListener);
|
||||
this._result.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH_ONGOING;
|
||||
aListener.onSearchResult(this, this._result);
|
||||
|
||||
do_timeout(500, () => {
|
||||
this._returnResults(aListener);
|
||||
});
|
||||
};
|
||||
|
||||
AutoCompleteAsyncSearch.prototype._returnResults = function(aListener) {
|
||||
|
@ -32,9 +34,9 @@ function AutoCompleteSyncSearch(aName, aResult) {
|
|||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSyncSearch.prototype = Object.create(AutoCompleteAsyncSearch.prototype);
|
||||
AutoCompleteSyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
AutoCompleteSyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
this._returnResults(aListener);
|
||||
};
|
||||
|
@ -49,7 +51,7 @@ function AutoCompleteResult(aValues, aDefaultIndex) {
|
|||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources, with one of them
|
||||
* (index != 0) returning before the rest.
|
||||
*/
|
||||
|
@ -60,19 +62,19 @@ function run_test() {
|
|||
var inputStr = "moz";
|
||||
|
||||
// Async search
|
||||
var asyncSearch = new AutoCompleteAsyncSearch("Async",
|
||||
var asyncSearch = new AutoCompleteAsyncSearch("Async",
|
||||
new AutoCompleteResult(results, -1));
|
||||
// Sync search
|
||||
var syncSearch = new AutoCompleteSyncSearch("Sync",
|
||||
new AutoCompleteResult(results, 0));
|
||||
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(asyncSearch);
|
||||
registerAutoCompleteSearch(syncSearch);
|
||||
|
||||
|
||||
var controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete.
|
||||
// Async search MUST be FIRST to trigger the bug this tests.
|
||||
|
|
|
@ -285,7 +285,7 @@ FormAutoComplete.prototype = {
|
|||
result.entries = aEntries;
|
||||
}
|
||||
|
||||
if (aDatalistResult) {
|
||||
if (aDatalistResult && aDatalistResult.matchCount > 0) {
|
||||
result = this.mergeResults(result, aDatalistResult);
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ FormAutoCompleteResult.prototype = {
|
|||
|
||||
getLabelAt: function(index) {
|
||||
this._checkIndexBounds(index);
|
||||
return this._labels[index];
|
||||
return this._labels[index] || this._values[index];
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -727,11 +727,12 @@ public:
|
|||
: mObserver(aObserver)
|
||||
, mSearch(aSearch)
|
||||
, mResult(aResult)
|
||||
{}
|
||||
{
|
||||
MOZ_ASSERT(mResult, "Should have a valid result");
|
||||
MOZ_ASSERT(mObserver, "You shouldn't call this runnable with a null observer!");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
NS_ASSERTION(mObserver, "You shouldn't call this runnable with a null observer!");
|
||||
|
||||
mObserver->OnUpdateSearchResult(mSearch, mResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ InputListAutoComplete.prototype = {
|
|||
|
||||
autoCompleteSearch : function (aUntrimmedSearchString, aField) {
|
||||
let [values, labels] = this.getListSuggestions(aField);
|
||||
if (values.length === 0)
|
||||
return null;
|
||||
let searchResult = values.length > 0 ? Ci.nsIAutoCompleteResult.RESULT_SUCCESS
|
||||
: Ci.nsIAutoCompleteResult.RESULT_NOMATCH;
|
||||
let defaultIndex = values.length > 0 ? 0 : -1;
|
||||
return new FormAutoCompleteResult(aUntrimmedSearchString,
|
||||
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
|
||||
0, "", values, labels,
|
||||
[], null);
|
||||
searchResult, defaultIndex, "",
|
||||
values, labels, [], null);
|
||||
},
|
||||
|
||||
getListSuggestions : function (aField) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче