Skip to content

Commit

Permalink
Bug 1304501 - Properly disable trimUrl on autofill. r=adw
Browse files Browse the repository at this point in the history
MozReview-Commit-ID: IxCOWkqFYV0
  • Loading branch information
mak77 committed Sep 21, 2016
1 parent 050869f commit b08979a
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 131 deletions.
96 changes: 32 additions & 64 deletions browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
Original file line number Diff line number Diff line change
@@ -1,81 +1,49 @@
/* 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/. */

// This test ensures that autoFilled values are not trimmed, unless the user
// selects from the autocomplete popup.

function test() {
waitForExplicitFinish();

add_task(function* setup() {
const PREF_TRIMURL = "browser.urlbar.trimURLs";
const PREF_AUTOFILL = "browser.urlbar.autoFill";

registerCleanupFunction(function () {
registerCleanupFunction(function* () {
Services.prefs.clearUserPref(PREF_TRIMURL);
Services.prefs.clearUserPref(PREF_AUTOFILL);
yield PlacesTestUtils.clearHistory();
gURLBar.handleRevert();
});
Services.prefs.setBoolPref(PREF_TRIMURL, true);
Services.prefs.setBoolPref(PREF_AUTOFILL, true);

// Adding a tab would hit switch-to-tab, so it's safer to just add a visit.
let callback = {
handleError: function () {},
handleResult: function () {},
handleCompletion: continue_test
};
let history = Cc["@mozilla.org/browser/history;1"]
.getService(Ci.mozIAsyncHistory);
history.updatePlaces({ uri: NetUtil.newURI("http://www.autofilltrimurl.com/whatever")
, visits: [ { transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED
, visitDate: Date.now() * 1000
} ]
}, callback);
}

function continue_test() {
function test_autoFill(aTyped, aExpected, aCallback) {
info(`Testing with input: ${aTyped}`);
gURLBar.inputField.value = aTyped.substr(0, aTyped.length - 1);
gURLBar.focus();
gURLBar.selectionStart = aTyped.length - 1;
gURLBar.selectionEnd = aTyped.length - 1;

EventUtils.synthesizeKey(aTyped.substr(-1), {});
waitForSearchComplete(function () {
info(`Got value: ${gURLBar.textValue}`);
is(gURLBar.textValue, aExpected, "Autofilled value is as expected");
aCallback();
});
}

test_autoFill("http://", "http://", function () {
test_autoFill("http://au", "http://autofilltrimurl.com/", function () {
test_autoFill("http://www.autofilltrimurl.com", "http://www.autofilltrimurl.com/", function () {
// Now ensure selecting from the popup correctly trims.
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.textValue, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
gURLBar.closePopup();
PlacesTestUtils.clearHistory().then(finish);
});
});
yield PlacesTestUtils.addVisits({
uri: "http://www.autofilltrimurl.com/whatever",
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
});
}
});

var gOnSearchComplete = null;
function waitForSearchComplete(aCallback) {
info("Waiting for onSearchComplete");
if (!gOnSearchComplete) {
gOnSearchComplete = gURLBar.onSearchComplete;
registerCleanupFunction(() => {
gURLBar.onSearchComplete = gOnSearchComplete;
});
}
gURLBar.onSearchComplete = function () {
ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
gOnSearchComplete.apply(gURLBar);
aCallback();
}
function* promiseSearch(searchtext) {
gURLBar.focus();
gURLBar.inputField.value = searchtext.substr(0, searchtext.length -1);
EventUtils.synthesizeKey(searchtext.substr(-1, 1), {});
yield promiseSearchComplete();
}

add_task(function* () {
yield promiseSearch("http://");
is(gURLBar.inputField.value, "http://", "Autofilled value is as expected");
});

add_task(function* () {
yield promiseSearch("http://au");
is(gURLBar.inputField.value, "http://autofilltrimurl.com/", "Autofilled value is as expected");
});

add_task(function* () {
yield promiseSearch("http://www.autofilltrimurl.com");
is(gURLBar.inputField.value, "http://www.autofilltrimurl.com/", "Autofilled value is as expected");

// Now ensure selecting from the popup correctly trims.
is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
EventUtils.synthesizeKey("VK_DOWN", {});
is(gURLBar.inputField.value, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
});
6 changes: 4 additions & 2 deletions browser/base/content/test/urlbar/browser_urlbarDecode.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ add_task(function* injectJSON() {
});

add_task(function losslessDecode() {
let url = "http://example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
let url = "http://" + urlNoScheme;
gURLBar.textValue = url;
Assert.equal(gURLBar.inputField.value, url,
// Since this is directly setting textValue, it is expected to be trimmed.
Assert.equal(gURLBar.inputField.value, urlNoScheme,
"The string displayed in the textbox should not be escaped");
gURLBar.value = "";
gURLBar.handleRevert();
Expand Down
56 changes: 22 additions & 34 deletions browser/base/content/urlbarBindings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<method name="onBeforeValueGet">
<body><![CDATA[
return {value: this._value};
return { value: this._value };
]]></body>
</method>

Expand Down Expand Up @@ -919,12 +919,24 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body>
</method>

<property name="textValue">
<getter><![CDATA[
return this.inputField.value;
]]></getter>
<setter>
<![CDATA[
<!--
onBeforeTextValueSet is called by the base-binding's .textValue getter.
It should return the value that the getter should use.
-->
<method name="onBeforeTextValueGet">
<body><![CDATA[
return { value: this.inputField.value };
]]></body>
</method>

<!--
onBeforeTextValueSet is called by the base-binding's .textValue setter.
It should return the value that the setter should use.
-->
<method name="onBeforeTextValueSet">
<parameter name="aValue"/>
<body><![CDATA[
let val = aValue;
let uri;
try {
uri = makeURI(val);
Expand All @@ -939,33 +951,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
}
}

// Trim popup selected values, but never trim results coming from
// autofill.
let styles = new Set(
this.popup.selectedIndex == -1 ? [] :
this.mController.getStyleAt(this.popup.selectedIndex).split(/\s+/)
);
if (this.popup.selectedIndex == -1 ||
this.mController
.getStyleAt(this.popup.selectedIndex)
.split(/\s+/).indexOf("autofill") >= 0) {
this._disableTrim = true;
}
this.value = val;
this._disableTrim = false;

// Completing a result should simulate the user typing the result, so
// fire an input event.
let evt = document.createEvent("UIEvents");
evt.initUIEvent("input", true, false, window, 0);
this.mIgnoreInput = true;
this.dispatchEvent(evt);
this.mIgnoreInput = false;

return this.value;
]]>
</setter>
</property>
return val;
]]></body>
</method>

<method name="_parseActionUrl">
<parameter name="aUrl"/>
Expand Down
42 changes: 33 additions & 9 deletions toolkit/components/autocomplete/nsAutoCompleteController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@

static const char *kAutoCompleteSearchCID = "@mozilla.org/autocomplete/search;1?name=";

namespace {

void
SetTextValue(nsIAutoCompleteInput* aInput,
const nsString& aValue,
uint16_t aReason) {
nsresult rv = aInput->SetTextValueWithReason(aValue, aReason);
if (NS_FAILED(rv)) {
aInput->SetTextValue(aValue);
}
}

} // anon namespace

NS_IMPL_CYCLE_COLLECTION_CLASS(nsAutoCompleteController)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAutoCompleteController)
Expand Down Expand Up @@ -483,16 +497,21 @@ nsAutoCompleteController::HandleKeyNavigation(uint32_t aKey, bool *_retval)
nsCaseInsensitiveStringComparator())) {
start = mSearchString.Length();
value = mPlaceholderCompletionString;
SetTextValue(input, value,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
} else {
start = value.Length();
SetTextValue(input, value,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETESELECTED);
}
input->SetTextValue(value);

input->SelectTextRange(start, value.Length());
}
mCompletedSelectionIndex = selectedIndex;
} else {
// Nothing is selected, so fill in the last typed value
input->SetTextValue(mSearchString);
SetTextValue(input, mSearchString,
nsIAutoCompleteInput::TEXTVALUE_REASON_REVERT);
input->SelectTextRange(mSearchString.Length(), mSearchString.Length());
mCompletedSelectionIndex = -1;
}
Expand Down Expand Up @@ -587,7 +606,8 @@ nsAutoCompleteController::HandleKeyNavigation(uint32_t aKey, bool *_retval)
// The pop-up is open and has a selection, take its value
nsAutoString value;
if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
input->SetTextValue(value);
SetTextValue(input, value,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETESELECTED);
input->SelectTextRange(value.Length(), value.Length());
}
}
Expand All @@ -612,7 +632,8 @@ nsAutoCompleteController::HandleKeyNavigation(uint32_t aKey, bool *_retval)
}

if (value.Equals(suggestedValue, nsCaseInsensitiveStringComparator())) {
input->SetTextValue(value);
SetTextValue(input, value,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
input->SelectTextRange(value.Length(), value.Length());
}
}
Expand Down Expand Up @@ -1527,7 +1548,7 @@ nsAutoCompleteController::EnterMatch(bool aIsPopupSelection,
obsSvc->NotifyObservers(input, "autocomplete-will-enter-text", nullptr);

if (!value.IsEmpty()) {
input->SetTextValue(value);
SetTextValue(input, value, nsIAutoCompleteInput::TEXTVALUE_REASON_ENTERMATCH);
input->SelectTextRange(value.Length(), value.Length());
mSearchString = value;
}
Expand Down Expand Up @@ -1567,7 +1588,7 @@ nsAutoCompleteController::RevertTextValue()
// Don't change the value if it is the same to prevent sending useless events.
// NOTE: how can |RevertTextValue| be called with inputValue != oldValue?
if (!oldValue.Equals(inputValue)) {
input->SetTextValue(oldValue);
SetTextValue(input, oldValue, nsIAutoCompleteInput::TEXTVALUE_REASON_REVERT);
}

obsSvc->NotifyObservers(input, "autocomplete-did-revert-text", nullptr);
Expand Down Expand Up @@ -1893,7 +1914,8 @@ nsAutoCompleteController::CompleteValue(nsString &aValue)
// matches the beginning of aValue. In either case we can simply
// autocomplete to aValue.
mPlaceholderCompletionString = aValue;
input->SetTextValue(aValue);
SetTextValue(input, aValue,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
} else {
nsresult rv;
nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
Expand All @@ -1915,14 +1937,16 @@ nsAutoCompleteController::CompleteValue(nsString &aValue)

mPlaceholderCompletionString = mSearchString +
Substring(aValue, mSearchStringLength + findIndex, endSelect);
input->SetTextValue(mPlaceholderCompletionString);
SetTextValue(input, mPlaceholderCompletionString,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);

endSelect -= findIndex; // We're skipping this many characters of aValue.
} else {
// Autocompleting something other than a URI from the middle.
// Use the format "searchstring >> full string" to indicate to the user
// what we are going to replace their search string with.
input->SetTextValue(mSearchString + NS_LITERAL_STRING(" >> ") + aValue);
SetTextValue(input, mSearchString + NS_LITERAL_STRING(" >> ") + aValue,
nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);

endSelect = mSearchString.Length() + 4 + aValue.Length();

Expand Down
Loading

0 comments on commit b08979a

Please sign in to comment.