mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1180944 - Implement one-off searches from Awesomebar. r=mak,florian
MozReview-Commit-ID: A9YXB32L7MN
This commit is contained in:
parent
b5ff483219
commit
55ab8f47c3
@ -308,6 +308,12 @@ pref("browser.urlbar.suggest.history.onlyTyped", false);
|
||||
pref("browser.urlbar.formatting.enabled", true);
|
||||
pref("browser.urlbar.trimURLs", true);
|
||||
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
pref("browser.urlbar.oneOffSearches", true);
|
||||
#else
|
||||
pref("browser.urlbar.oneOffSearches", false);
|
||||
#endif
|
||||
|
||||
pref("browser.altClickSave", false);
|
||||
|
||||
// Enable logging downloads operations to the Console.
|
||||
|
@ -152,14 +152,7 @@
|
||||
noautofocus="true"
|
||||
hidden="true"
|
||||
flip="none"
|
||||
level="parent">
|
||||
#ifdef NIGHTLY_BUILD
|
||||
<hbox id="urlbar-search-footer" flex="1" align="stretch" pack="end">
|
||||
<button id="urlbar-search-settings" label="&changeSearchSettings.button;"
|
||||
oncommand="BrowserUITelemetry.countSearchSettingsEvent('urlbar'); openPreferences('paneSearch')"/>
|
||||
</hbox>
|
||||
#endif
|
||||
</panel>
|
||||
level="parent"/>
|
||||
|
||||
<!-- for select dropdowns. The menupopup is what shows the list of options,
|
||||
and the popuponly menulist makes things like the menuactive attributes
|
||||
|
@ -56,6 +56,7 @@ support-files =
|
||||
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
|
||||
[browser_urlbarHashChangeProxyState.js]
|
||||
[browser_urlbarKeepStateAcrossTabSwitches.js]
|
||||
[browser_urlbarOneOffs.js]
|
||||
[browser_urlbarPrivateBrowsingWindowChange.js]
|
||||
[browser_urlbarRevert.js]
|
||||
[browser_urlbarSearchSingleWordNotification.js]
|
||||
|
@ -6,6 +6,21 @@ function repeat(limit, func) {
|
||||
|
||||
function is_selected(index) {
|
||||
is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
|
||||
|
||||
// This is true because although both the listbox and the one-offs can have
|
||||
// selections, the test doesn't check that.
|
||||
is(gURLBar.popup.oneOffSearchButtons.selectedButton, null,
|
||||
"A result is selected, so the one-offs should not have a selection");
|
||||
}
|
||||
|
||||
function is_selected_one_off(index) {
|
||||
is(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, index,
|
||||
"Expected one-off button should be selected");
|
||||
|
||||
// This is true because although both the listbox and the one-offs can have
|
||||
// selections, the test doesn't check that.
|
||||
is(gURLBar.popup.richlistbox.selectedIndex, -1,
|
||||
"A one-off is selected, so the listbox should not have a selection");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
@ -37,12 +52,27 @@ add_task(function*() {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
is_selected(1);
|
||||
|
||||
info("Key Down maxResults times should wrap around all the way around");
|
||||
repeat(maxResults, () => EventUtils.synthesizeKey("VK_DOWN", {}));
|
||||
info("Key Down maxResults-1 times should select the first one-off");
|
||||
repeat(maxResults - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
|
||||
is_selected_one_off(0);
|
||||
|
||||
info("Key Down numButtons-1 should select the last one-off");
|
||||
let numButtons =
|
||||
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
|
||||
repeat(numButtons - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
|
||||
is_selected_one_off(numButtons - 1);
|
||||
|
||||
info("Key Down twice more should select the second result");
|
||||
repeat(2, () => EventUtils.synthesizeKey("VK_DOWN", {}));
|
||||
is_selected(1);
|
||||
|
||||
info("Key Up maxResults times should wrap around the other way");
|
||||
repeat(maxResults, () => EventUtils.synthesizeKey("VK_UP", {}));
|
||||
info("Key Down maxResults + numButtons times should wrap around");
|
||||
repeat(maxResults + numButtons,
|
||||
() => EventUtils.synthesizeKey("VK_DOWN", {}));
|
||||
is_selected(1);
|
||||
|
||||
info("Key Up maxResults + numButtons times should wrap around the other way");
|
||||
repeat(maxResults + numButtons, () => EventUtils.synthesizeKey("VK_UP", {}));
|
||||
is_selected(1);
|
||||
|
||||
info("Page Up will go up the list, but not wrap");
|
||||
|
@ -31,15 +31,18 @@ add_task(function*() {
|
||||
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
|
||||
yield promiseSearchComplete();
|
||||
|
||||
let editedValue = gURLBar.value;
|
||||
let editedValue = gURLBar.textValue;
|
||||
is(list.selectedIndex, initialIndex, "The initial index is selected again.");
|
||||
isnot(editedValue, nextValue, "The URL has changed.");
|
||||
|
||||
let docLoad = waitForDocLoadAndStopIt("http://" + editedValue);
|
||||
|
||||
info("Press return to load edited URL.");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield Promise.all([
|
||||
promisePopupHidden(gURLBar.popup),
|
||||
waitForDocLoadAndStopIt("http://" + editedValue)]);
|
||||
docLoad,
|
||||
]);
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
@ -43,7 +43,7 @@ add_task(function*() {
|
||||
EventUtils.synthesizeKey("b", {});
|
||||
yield promiseSearchComplete();
|
||||
|
||||
is(gURLBar.value, "keyword ab", "urlbar should have expected input");
|
||||
is(gURLBar.textValue, "keyword ab", "urlbar should have expected input");
|
||||
|
||||
let result = gURLBar.popup.richlistbox.firstChild;
|
||||
isnot(result, null, "Should have first item");
|
||||
|
@ -44,8 +44,8 @@ function continue_test() {
|
||||
|
||||
EventUtils.synthesizeKey(aTyped.substr(-1), {});
|
||||
waitForSearchComplete(function () {
|
||||
info(`Got value: ${gURLBar.value}`);
|
||||
is(gURLBar.value, aExpected, "Autofilled value is as expected");
|
||||
info(`Got value: ${gURLBar.textValue}`);
|
||||
is(gURLBar.textValue, aExpected, "Autofilled value is as expected");
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
|
233
browser/base/content/test/urlbar/browser_urlbarOneOffs.js
Normal file
233
browser/base/content/test/urlbar/browser_urlbarOneOffs.js
Normal file
@ -0,0 +1,233 @@
|
||||
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
|
||||
|
||||
let gMaxResults;
|
||||
|
||||
add_task(function* init() {
|
||||
Services.prefs.setBoolPref("browser.urlbar.oneOffSearches", true);
|
||||
gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
|
||||
|
||||
// Add a search suggestion engine and move it to the front so that it appears
|
||||
// as the first one-off.
|
||||
let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
|
||||
Services.search.moveEngine(engine, 0);
|
||||
|
||||
registerCleanupFunction(function* () {
|
||||
yield hidePopup();
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
});
|
||||
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
|
||||
let visits = [];
|
||||
for (let i = 0; i < gMaxResults; i++) {
|
||||
visits.push({
|
||||
uri: makeURI("http://example.com/browser_urlbarOneOffs.js/?" + i),
|
||||
// TYPED so that the visit shows up when the urlbar's drop-down arrow is
|
||||
// pressed.
|
||||
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
|
||||
});
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
});
|
||||
|
||||
// Keys up and down through the history panel, i.e., the panel that's shown when
|
||||
// there's no text in the textbox.
|
||||
add_task(function* history() {
|
||||
gURLBar.focus();
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
yield promisePopupShown(gURLBar.popup);
|
||||
|
||||
assertState(-1, -1, "");
|
||||
|
||||
// Key down through each result.
|
||||
for (let i = 0; i < gMaxResults; i++) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(i, -1,
|
||||
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
|
||||
}
|
||||
|
||||
// Key down through each one-off.
|
||||
let numButtons =
|
||||
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
|
||||
for (let i = 0; i < numButtons; i++) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(-1, i, "");
|
||||
}
|
||||
|
||||
// Key down once more. Nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(-1, -1, "");
|
||||
|
||||
// Once more. The first result should be selected.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(0, -1,
|
||||
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - 1));
|
||||
|
||||
// Now key up. Nothing should be selected again.
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(-1, -1, "");
|
||||
|
||||
// Key up through each one-off.
|
||||
for (let i = numButtons - 1; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(-1, i, "");
|
||||
}
|
||||
|
||||
// Key up through each result.
|
||||
for (let i = gMaxResults - 1; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(i, -1,
|
||||
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
|
||||
}
|
||||
|
||||
// Key up once more. Nothing should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(-1, -1, "");
|
||||
|
||||
yield hidePopup();
|
||||
});
|
||||
|
||||
// Keys up and down through the non-history panel, i.e., the panel that's shown
|
||||
// when you type something in the textbox.
|
||||
add_task(function* typedValue() {
|
||||
// Use a typed value that returns the visits added above but that doesn't
|
||||
// trigger autofill since that would complicate the test.
|
||||
let typedValue = "browser_urlbarOneOffs";
|
||||
yield promiseAutocompleteResultPopup(typedValue, window, true);
|
||||
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
// Key down through each result. The first result is already selected, which
|
||||
// is why gMaxResults - 1 is the correct number of times to do this.
|
||||
for (let i = 0; i < gMaxResults - 1; i++) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
// i starts at zero so that the textValue passed to assertState is correct.
|
||||
// But that means that i + 1 is the expected selected index, since initially
|
||||
// (when this loop starts) the first result is selected.
|
||||
assertState(i + 1, -1,
|
||||
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
|
||||
}
|
||||
|
||||
// Key down through each one-off.
|
||||
let numButtons =
|
||||
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
|
||||
for (let i = 0; i < numButtons; i++) {
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(-1, i, typedValue);
|
||||
}
|
||||
|
||||
// Key down once more. The selection should wrap around to the first result.
|
||||
EventUtils.synthesizeKey("VK_DOWN", {})
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
// Now key up. The selection should wrap back around to the one-offs. Key
|
||||
// up through all the one-offs.
|
||||
for (let i = numButtons - 1; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(-1, i, typedValue);
|
||||
}
|
||||
|
||||
// Key up through each non-heuristic result.
|
||||
for (let i = gMaxResults - 2; i >= 0; i--) {
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(i + 1, -1,
|
||||
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
|
||||
}
|
||||
|
||||
// Key up once more. The heuristic result should be selected.
|
||||
EventUtils.synthesizeKey("VK_UP", {})
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
yield hidePopup();
|
||||
});
|
||||
|
||||
// Checks that "Search with Current Search Engine" items are updated to "Search
|
||||
// with One-Off Engine" when a one-off is selected.
|
||||
add_task(function* searchWith() {
|
||||
let typedValue = "foo";
|
||||
yield promiseAutocompleteResultPopup(typedValue);
|
||||
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
let item = gURLBar.popup.richlistbox.firstChild;
|
||||
Assert.equal(item._actionText.textContent,
|
||||
"Search with " + Services.search.currentEngine.name,
|
||||
"Sanity check: first result's action text");
|
||||
|
||||
// Tab to the first one-off. Now the first result and the first one-off
|
||||
// should both be selected.
|
||||
EventUtils.synthesizeKey("VK_TAB", {})
|
||||
assertState(0, 0, typedValue);
|
||||
|
||||
let engineName = gURLBar.popup.oneOffSearchButtons.selectedButton.engine.name;
|
||||
Assert.notEqual(engineName, Services.search.currentEngine.name,
|
||||
"Sanity check: First one-off engine should not be " +
|
||||
"the current engine");
|
||||
Assert.equal(item._actionText.textContent,
|
||||
"Search with " + engineName,
|
||||
"First result's action text should be updated");
|
||||
|
||||
yield hidePopup();
|
||||
});
|
||||
|
||||
// Clicks a one-off.
|
||||
add_task(function* oneOffClick() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let typedValue = "foo";
|
||||
yield promiseAutocompleteResultPopup(typedValue);
|
||||
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
let oneOffs = gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true);
|
||||
let resultsPromise = promiseSearchResultsLoaded();
|
||||
EventUtils.synthesizeMouseAtCenter(oneOffs[0], {});
|
||||
yield resultsPromise;
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Presses the Return key when a one-off is selected.
|
||||
add_task(function* oneOffReturn() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let typedValue = "foo";
|
||||
yield promiseAutocompleteResultPopup(typedValue, window, true);
|
||||
|
||||
assertState(0, -1, typedValue);
|
||||
|
||||
// Tab to select the first one-off.
|
||||
EventUtils.synthesizeKey("VK_TAB", {})
|
||||
assertState(0, 0, typedValue);
|
||||
|
||||
let resultsPromise = promiseSearchResultsLoaded();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {})
|
||||
yield resultsPromise;
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
|
||||
function assertState(result, oneOff, textValue = undefined) {
|
||||
Assert.equal(gURLBar.popup.selectedIndex, result,
|
||||
"Expected result should be selected");
|
||||
Assert.equal(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, oneOff,
|
||||
"Expected one-off should be selected");
|
||||
if (textValue !== undefined) {
|
||||
Assert.equal(gURLBar.textValue, textValue, "Expected textValue");
|
||||
}
|
||||
}
|
||||
|
||||
function* hidePopup() {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield promisePopupHidden(gURLBar.popup);
|
||||
}
|
||||
|
||||
function promiseSearchResultsLoaded() {
|
||||
let tab = gBrowser.selectedTab;
|
||||
return promiseTabLoadEvent(tab).then(() => {
|
||||
Assert.equal(tab.linkedBrowser.currentURI.spec,
|
||||
"http://mochi.test:8888/",
|
||||
'Expected "search results" page loaded');
|
||||
});
|
||||
}
|
@ -25,7 +25,10 @@ add_task(function* clickSuggestion() {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gURLBar.focus();
|
||||
yield promiseAutocompleteResultPopup("foo");
|
||||
let [idx, suggestion] = yield promiseFirstSuggestion();
|
||||
let [idx, suggestion, engineName] = yield promiseFirstSuggestion();
|
||||
Assert.equal(engineName,
|
||||
"browser_searchSuggestionEngine%20searchSuggestionEngine.xml",
|
||||
"Expected suggestion engine");
|
||||
let item = gURLBar.popup.richlistbox.getItemAtIndex(idx);
|
||||
let loadPromise = promiseTabLoaded(gBrowser.selectedTab);
|
||||
item.click();
|
||||
@ -47,7 +50,7 @@ function getFirstSuggestion() {
|
||||
let [, type, paramStr] = mozActionMatch;
|
||||
let params = JSON.parse(paramStr);
|
||||
if (type == "searchengine" && "searchSuggestion" in params) {
|
||||
return [i, params.searchSuggestion];
|
||||
return [i, params.searchSuggestion, params.engineName];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,10 +59,10 @@ function getFirstSuggestion() {
|
||||
|
||||
function promiseFirstSuggestion() {
|
||||
return new Promise(resolve => {
|
||||
let pair;
|
||||
let tuple;
|
||||
waitForCondition(() => {
|
||||
pair = getFirstSuggestion();
|
||||
return pair[0] >= 0;
|
||||
}, () => resolve(pair));
|
||||
tuple = getFirstSuggestion();
|
||||
return tuple[0] >= 0;
|
||||
}, () => resolve(tuple));
|
||||
});
|
||||
}
|
||||
|
@ -23,6 +23,12 @@ add_task(function* prepare() {
|
||||
gURLBar.blur();
|
||||
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
|
||||
});
|
||||
// Move the mouse away from the urlbar one-offs so that a one-off engine is
|
||||
// not inadvertently selected.
|
||||
yield new Promise(resolve => {
|
||||
EventUtils.synthesizeNativeMouseMove(window.document.documentElement, 0, 0,
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* heuristicResult() {
|
||||
|
@ -20,12 +20,11 @@ add_task(function* () {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function typeAndSubmitAndStop(url) {
|
||||
gBrowser.userTypedValue = url;
|
||||
URLBarSetURI();
|
||||
function* typeAndSubmitAndStop(url) {
|
||||
yield promiseAutocompleteResultPopup(url, window, true);
|
||||
is(gURLBar.textValue, gURLBar.trimValue(url), "location bar reflects loading page");
|
||||
|
||||
let promise = waitForDocLoadAndStopIt(url, gBrowser.selectedBrowser, false);
|
||||
gURLBar.handleCommand();
|
||||
return promise;
|
||||
yield promise;
|
||||
}
|
||||
|
@ -7,13 +7,13 @@ function* test_autocomplete(data) {
|
||||
info(desc);
|
||||
|
||||
yield promiseAutocompleteResultPopup(typed);
|
||||
is(gURLBar.value, autofilled, "autofilled value is as expected");
|
||||
is(gURLBar.textValue, autofilled, "autofilled value is as expected");
|
||||
if (onAutoFill)
|
||||
onAutoFill()
|
||||
|
||||
keys.forEach(key => EventUtils.synthesizeKey(key, {}));
|
||||
|
||||
is(gURLBar.value, modified, "backspaced value is as expected");
|
||||
is(gURLBar.textValue, modified, "backspaced value is as expected");
|
||||
|
||||
yield promiseSearchComplete();
|
||||
|
||||
|
@ -327,10 +327,18 @@ function promiseSearchComplete(win = window) {
|
||||
});
|
||||
}
|
||||
|
||||
function promiseAutocompleteResultPopup(inputText, win = window) {
|
||||
function promiseAutocompleteResultPopup(inputText,
|
||||
win = window,
|
||||
fireInputEvent = false) {
|
||||
waitForFocus(() => {
|
||||
win.gURLBar.focus();
|
||||
win.gURLBar.value = inputText;
|
||||
if (fireInputEvent) {
|
||||
// This is necessary to get the urlbar to set gBrowser.userTypedValue.
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("input", true, true);
|
||||
win.gURLBar.dispatchEvent(event);
|
||||
}
|
||||
win.gURLBar.controller.startSearch(inputText);
|
||||
}, win);
|
||||
|
||||
|
@ -108,6 +108,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
"gURLBar.select(); goDoCommand('cmd_paste'); gURLBar.handleCommand();");
|
||||
cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling);
|
||||
}
|
||||
|
||||
this._enableOrDisableOneOffSearches();
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
@ -197,7 +199,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
this.popup.selectedIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.popup.popupOpen &&
|
||||
!this.popup.disableKeyNavigation &&
|
||||
this.popup.handleKeyPress(aEvent)) {
|
||||
return true;
|
||||
}
|
||||
return this.handleKeyPress(aEvent);
|
||||
]]></body>
|
||||
</method>
|
||||
@ -331,135 +337,224 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
This is ultimately called by the autocomplete controller as the result
|
||||
of handleEnter when the Return key is pressed in the textbox. Since
|
||||
onPopupClick also calls handleEnter, this is also called as a result in
|
||||
that case.
|
||||
|
||||
@param event
|
||||
The event that triggered the command.
|
||||
@param openUILinkWhere
|
||||
Optional. The "where" to pass to openUILinkIn. This method
|
||||
computes the appropriate "where" given the event, but you can
|
||||
use this to override it.
|
||||
@param openUILinkParams
|
||||
Optional. The parameters to pass to openUILinkIn. As with
|
||||
"where", this method computes the appropriate parameters, but
|
||||
any parameters you supply here will override those.
|
||||
-->
|
||||
<method name="handleCommand">
|
||||
<parameter name="aTriggeringEvent"/>
|
||||
<parameter name="event"/>
|
||||
<parameter name="openUILinkWhere"/>
|
||||
<parameter name="openUILinkParams"/>
|
||||
<body><![CDATA[
|
||||
if (aTriggeringEvent instanceof MouseEvent && aTriggeringEvent.button == 2)
|
||||
return; // Do nothing for right clicks
|
||||
|
||||
var url = this.value;
|
||||
var mayInheritPrincipal = false;
|
||||
var postData = null;
|
||||
|
||||
let action = this._parseActionUrl(this._value);
|
||||
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
|
||||
|
||||
let matchLastLocationChange = true;
|
||||
if (action) {
|
||||
if (action.type == "switchtab") {
|
||||
url = action.params.url;
|
||||
if (this.hasAttribute("actiontype")) {
|
||||
this.handleRevert();
|
||||
let prevTab = gBrowser.selectedTab;
|
||||
if (switchToTabHavingURI(url) && isTabEmpty(prevTab)) {
|
||||
gBrowser.removeTab(prevTab);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (action.type == "remotetab") {
|
||||
url = action.params.url;
|
||||
} else if (action.type == "keyword") {
|
||||
url = action.params.url;
|
||||
} else if (action.type == "searchengine") {
|
||||
[url, postData] = this._parseAndRecordSearchEngineAction(action);
|
||||
} else if (action.type == "visiturl") {
|
||||
url = action.params.url;
|
||||
}
|
||||
continueOperation.call(this);
|
||||
}
|
||||
else {
|
||||
this._canonizeURL(aTriggeringEvent, response => {
|
||||
[url, postData, mayInheritPrincipal] = response;
|
||||
if (url) {
|
||||
matchLastLocationChange = (lastLocationChange ==
|
||||
gBrowser.selectedBrowser.lastLocationChange);
|
||||
continueOperation.call(this);
|
||||
}
|
||||
});
|
||||
let isMouseEvent = event instanceof MouseEvent;
|
||||
if (isMouseEvent && event.button == 2) {
|
||||
// Do nothing for right clicks.
|
||||
return;
|
||||
}
|
||||
|
||||
function continueOperation()
|
||||
{
|
||||
this.value = url;
|
||||
gBrowser.userTypedValue = url;
|
||||
if (gInitialPages.includes(url)) {
|
||||
gBrowser.selectedBrowser.initialPageLoadedFromURLBar = url;
|
||||
}
|
||||
try {
|
||||
addToUrlbarHistory(url);
|
||||
} catch (ex) {
|
||||
// Things may go wrong when adding url to session history,
|
||||
// but don't let that interfere with the loading of the url.
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
// Do the command of the selected one-off if it's not an engine.
|
||||
let selectedOneOff =
|
||||
this.popup.oneOffSearchButtons.visuallySelectedButton;
|
||||
if (selectedOneOff && !selectedOneOff.engine) {
|
||||
selectedOneOff.doCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
let loadCurrent = () => {
|
||||
try {
|
||||
openUILinkIn(url, "current", {
|
||||
allowThirdPartyFixup: true,
|
||||
indicateErrorPageLoad: true,
|
||||
disallowInheritPrincipal: !mayInheritPrincipal,
|
||||
allowPinnedTabHostChange: true,
|
||||
postData: postData,
|
||||
allowPopups: url.startsWith("javascript:"),
|
||||
});
|
||||
} catch (ex) {
|
||||
// This load can throw an exception in certain cases, which means
|
||||
// we'll want to replace the URL with the loaded URL:
|
||||
if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
|
||||
this.handleRevert();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the start of the URL is visible for UX reasons:
|
||||
this.selectionStart = this.selectionEnd = 0;
|
||||
};
|
||||
|
||||
// Focus the content area before triggering loads, since if the load
|
||||
// occurs in a new tab, we want focus to be restored to the content
|
||||
// area when the current tab is re-selected.
|
||||
gBrowser.selectedBrowser.focus();
|
||||
|
||||
let isMouseEvent = aTriggeringEvent instanceof MouseEvent;
|
||||
|
||||
// If the current tab is empty, ignore Alt+Enter (just reuse this tab)
|
||||
let altEnter = !isMouseEvent && aTriggeringEvent &&
|
||||
aTriggeringEvent.altKey && !isTabEmpty(gBrowser.selectedTab);
|
||||
|
||||
if (isMouseEvent || altEnter) {
|
||||
// Use the standard UI link behaviors for clicks or Alt+Enter
|
||||
let where = "tab";
|
||||
if (isMouseEvent)
|
||||
where = whereToOpenLink(aTriggeringEvent, false, false);
|
||||
|
||||
if (where == "current") {
|
||||
if (matchLastLocationChange) {
|
||||
loadCurrent();
|
||||
}
|
||||
} else {
|
||||
this.handleRevert();
|
||||
let params = { allowThirdPartyFixup: true,
|
||||
postData: postData,
|
||||
initiatingDoc: document };
|
||||
openUILinkIn(url, where, params);
|
||||
}
|
||||
let where = openUILinkWhere;
|
||||
if (!where) {
|
||||
if (isMouseEvent) {
|
||||
where = whereToOpenLink(event, false, false);
|
||||
} else {
|
||||
if (matchLastLocationChange) {
|
||||
loadCurrent();
|
||||
}
|
||||
// If the current tab is empty, ignore Alt+Enter (reuse this tab)
|
||||
let altEnter = !isMouseEvent &&
|
||||
event &&
|
||||
event.altKey &&
|
||||
!isTabEmpty(gBrowser.selectedTab);
|
||||
where = altEnter ? "tab" : "current";
|
||||
}
|
||||
}
|
||||
|
||||
let url = this.value;
|
||||
let mayInheritPrincipal = false;
|
||||
let postData = null;
|
||||
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
|
||||
let matchLastLocationChange = true;
|
||||
|
||||
let action = this._parseActionUrl(url);
|
||||
if (action) {
|
||||
switch (action.type) {
|
||||
case "visiturl":
|
||||
case "keyword":
|
||||
case "remotetab":
|
||||
url = action.params.url;
|
||||
break;
|
||||
case "switchtab":
|
||||
url = action.params.url;
|
||||
if (this.hasAttribute("actiontype")) {
|
||||
this.handleRevert();
|
||||
let prevTab = gBrowser.selectedTab;
|
||||
if (switchToTabHavingURI(url) && isTabEmpty(prevTab)) {
|
||||
gBrowser.removeTab(prevTab);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case "searchengine":
|
||||
if (selectedOneOff && selectedOneOff.engine) {
|
||||
// Replace the engine with the selected one-off engine.
|
||||
action.params.engineName = engine.name;
|
||||
}
|
||||
[url, postData] = this._recordSearchEngineLoad(
|
||||
action.params.engineName,
|
||||
action.params.searchSuggestion || action.params.searchQuery,
|
||||
event,
|
||||
where,
|
||||
openUILinkParams
|
||||
);
|
||||
break;
|
||||
}
|
||||
this._loadURL(url, postData, where, openUILinkParams,
|
||||
matchLastLocationChange, mayInheritPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's a selected one-off button and the input value is a
|
||||
// search query (or "keyword" in URI-fixup terminology), then load a
|
||||
// search using the one-off's engine.
|
||||
if (selectedOneOff && selectedOneOff.engine) {
|
||||
// `url` (which is this.value) may be an autofilled string. Search
|
||||
// only with the portion that the user typed, if any, by preferring
|
||||
// the autocomplete controller's searchString.
|
||||
let value = this._searchStringOnHandleEnter ||
|
||||
this.mController.searchString ||
|
||||
url;
|
||||
let fixup;
|
||||
try {
|
||||
fixup = Services.uriFixup.getFixupURIInfo(
|
||||
value,
|
||||
Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
|
||||
);
|
||||
} catch (ex) {}
|
||||
if (fixup && fixup.keywordProviderName) {
|
||||
[url, postData] =
|
||||
this._recordSearchEngineLoad(selectedOneOff.engine, value,
|
||||
event, where, openUILinkParams);
|
||||
this._loadURL(url, postData, where, openUILinkParams,
|
||||
matchLastLocationChange, mayInheritPrincipal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._canonizeURL(event, response => {
|
||||
[url, postData, mayInheritPrincipal] = response;
|
||||
if (url) {
|
||||
matchLastLocationChange =
|
||||
lastLocationChange ==
|
||||
gBrowser.selectedBrowser.lastLocationChange;
|
||||
this._loadURL(url, postData, where, openUILinkParams,
|
||||
matchLastLocationChange, mayInheritPrincipal);
|
||||
}
|
||||
});
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_loadURL">
|
||||
<parameter name="url"/>
|
||||
<parameter name="postData"/>
|
||||
<parameter name="openUILinkWhere"/>
|
||||
<parameter name="openUILinkParams"/>
|
||||
<parameter name="matchLastLocationChange"/>
|
||||
<parameter name="mayInheritPrincipal"/>
|
||||
<body><![CDATA[
|
||||
this.value = url;
|
||||
gBrowser.userTypedValue = url;
|
||||
if (gInitialPages.includes(url)) {
|
||||
gBrowser.selectedBrowser.initialPageLoadedFromURLBar = url;
|
||||
}
|
||||
try {
|
||||
addToUrlbarHistory(url);
|
||||
} catch (ex) {
|
||||
// Things may go wrong when adding url to session history,
|
||||
// but don't let that interfere with the loading of the url.
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
||||
let params = {
|
||||
postData: postData,
|
||||
allowThirdPartyFixup: true,
|
||||
};
|
||||
if (openUILinkWhere == "current") {
|
||||
params.indicateErrorPageLoad = true;
|
||||
params.allowPinnedTabHostChange = true;
|
||||
params.disallowInheritPrincipal = !mayInheritPrincipal;
|
||||
params.allowPopups = url.startsWith("javascript:");
|
||||
} else {
|
||||
params.initiatingDoc = document;
|
||||
}
|
||||
|
||||
if (openUILinkParams) {
|
||||
for (let key in openUILinkParams) {
|
||||
params[key] = openUILinkParams[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Focus the content area before triggering loads, since if the load
|
||||
// occurs in a new tab, we want focus to be restored to the content
|
||||
// area when the current tab is re-selected.
|
||||
gBrowser.selectedBrowser.focus();
|
||||
|
||||
if (openUILinkWhere == "current" && !matchLastLocationChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (openUILinkWhere != "current") {
|
||||
this.handleRevert();
|
||||
}
|
||||
|
||||
try {
|
||||
openUILinkIn(url, openUILinkWhere, params);
|
||||
} catch (ex) {
|
||||
// This load can throw an exception in certain cases, which means
|
||||
// we'll want to replace the URL with the loaded URL:
|
||||
if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
|
||||
this.handleRevert();
|
||||
}
|
||||
}
|
||||
|
||||
if (openUILinkWhere == "current") {
|
||||
// Ensure the start of the URL is visible for usability reasons.
|
||||
this.selectionStart = this.selectionEnd = 0;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_parseAndRecordSearchEngineAction">
|
||||
<parameter name="action"/>
|
||||
<method name="_recordSearchEngineLoad">
|
||||
<parameter name="engineOrEngineName"/>
|
||||
<parameter name="query"/>
|
||||
<parameter name="event"/>
|
||||
<parameter name="openUILinkWhere"/>
|
||||
<parameter name="openUILinkParams"/>
|
||||
<body><![CDATA[
|
||||
let engine =
|
||||
Services.search.getEngineByName(action.params.engineName);
|
||||
typeof(engineOrEngineName) == "string" ?
|
||||
Services.search.getEngineByName(engineOrEngineName) :
|
||||
engineOrEngineName;
|
||||
BrowserSearch.recordSearchInTelemetry(engine, "urlbar");
|
||||
let query = action.params.searchSuggestion ||
|
||||
action.params.searchQuery;
|
||||
this.popup.oneOffSearchButtons
|
||||
.maybeRecordTelemetry(event, openUILinkWhere, openUILinkParams);
|
||||
let submission = engine.getSubmission(query, null, "keyword");
|
||||
return [submission.uri.spec, submission.postData];
|
||||
]]></body>
|
||||
@ -728,11 +823,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
case "trimURLs":
|
||||
this._mayTrimURLs = this._prefs.getBoolPref(aData);
|
||||
break;
|
||||
case "oneOffSearches":
|
||||
this._enableOrDisableOneOffSearches();
|
||||
break;
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_enableOrDisableOneOffSearches">
|
||||
<body><![CDATA[
|
||||
let enable = this._prefs.getBoolPref("oneOffSearches");
|
||||
this.popup.enableOneOffSearches(enable);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
@ -903,6 +1008,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
</method>
|
||||
|
||||
<method name="handleEnter">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
// We need to ensure we're using a selected autocomplete result.
|
||||
// A result should automatically be selected by default,
|
||||
@ -919,7 +1025,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// ensure that it corresponds to the current input.
|
||||
|
||||
if (this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery) {
|
||||
return this.mController.handleEnter(false);
|
||||
// Store the current search string so it can be used in
|
||||
// handleCommand, which will be called as a result of
|
||||
// mController.handleEnter(). handleEnter will reset it.
|
||||
this._searchStringOnHandleEnter = this.mController.searchString;
|
||||
let rv = this.mController.handleEnter(false, event);
|
||||
delete this._searchStringOnHandleEnter;
|
||||
return rv;
|
||||
}
|
||||
|
||||
this.handleEnterWhenGotResult = true;
|
||||
@ -1100,7 +1212,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
// Check for unmodified left-click, and use default behavior
|
||||
if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
|
||||
!aEvent.altKey && !aEvent.metaKey) {
|
||||
controller.handleEnter(true);
|
||||
controller.handleEnter(true, aEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1137,6 +1249,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
|
||||
|
||||
<resources>
|
||||
<stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
|
||||
<stylesheet src="chrome://browser/skin/searchbar.css"/>
|
||||
</resources>
|
||||
|
||||
<content ignorekeys="true" level="top" consumeoutsideclicks="never"
|
||||
aria-owns="richlistbox">
|
||||
<xul:hbox anonid="search-suggestions-notification"
|
||||
@ -1171,6 +1288,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
flex="1"/>
|
||||
<xul:hbox anonid="footer">
|
||||
<children/>
|
||||
<xul:vbox anonid="one-off-search-buttons"
|
||||
class="search-one-offs"
|
||||
compact="true"
|
||||
flex="1"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
@ -1193,6 +1314,31 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "footer");
|
||||
</field>
|
||||
|
||||
<field name="oneOffSearchButtons" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"one-off-search-buttons");
|
||||
</field>
|
||||
|
||||
<field name="_oneOffSearchesEnabled">false</field>
|
||||
|
||||
<method name="enableOneOffSearches">
|
||||
<parameter name="enable"/>
|
||||
<body><![CDATA[
|
||||
this._oneOffSearchesEnabled = enable;
|
||||
if (enable) {
|
||||
this.oneOffSearchButtons.style.display = "-moz-box";
|
||||
this.oneOffSearchButtons.popup = this;
|
||||
this.oneOffSearchButtons.textbox = this.input;
|
||||
this.oneOffSearchButtons.telemetryOrigin = "urlbar";
|
||||
} else {
|
||||
this.oneOffSearchButtons.style.display = "none";
|
||||
this.oneOffSearchButtons.popup = null;
|
||||
this.oneOffSearchButtons.textbox = null;
|
||||
this.oneOffSearchButtons.telemetryOrigin = null;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="openSearchSuggestionsNotificationLearnMoreURL">
|
||||
<body><![CDATA[
|
||||
let url = Services.urlFormatter.formatURL(
|
||||
@ -1491,62 +1637,68 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="onPopupClick">
|
||||
<parameter name="aEvent"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Ignore right-clicks
|
||||
if (aEvent.button == 2)
|
||||
return;
|
||||
|
||||
var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Check for unmodified left-click, and use default behavior
|
||||
if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
|
||||
!aEvent.altKey && !aEvent.metaKey) {
|
||||
controller.handleEnter(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for middle-click or modified clicks on the URL bar
|
||||
if (gURLBar && this.mInput == gURLBar) {
|
||||
var url = controller.getValueAt(this.selectedIndex);
|
||||
var options = {};
|
||||
|
||||
// close the autocomplete popup and revert the entered address
|
||||
this.closePopup();
|
||||
controller.handleEscape();
|
||||
|
||||
// Check if this is meant to be an action
|
||||
let action = this.mInput._parseActionUrl(url);
|
||||
if (action) {
|
||||
// TODO (bug 1054816): Centralise the implementation of actions
|
||||
// into a JS module.
|
||||
switch (action.type) {
|
||||
case "switchtab": // Fall through.
|
||||
case "keyword": // Fall through.
|
||||
case "visiturl": {
|
||||
url = action.params.url;
|
||||
break;
|
||||
}
|
||||
case "searchengine": {
|
||||
[url, options.postData] =
|
||||
this.input._parseAndRecordSearchEngineAction(action);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
<method name="_visuallySelectedOneOffChanged">
|
||||
<body><![CDATA[
|
||||
// Update all searchengine result items to use the newly selected
|
||||
// engine.
|
||||
for (let item of this.richlistbox.childNodes) {
|
||||
if (item.collapsed) {
|
||||
break;
|
||||
}
|
||||
let url = item.getAttribute("url");
|
||||
if (url) {
|
||||
let action = item._parseActionUrl(url);
|
||||
if (action && action.type == "searchengine") {
|
||||
item._adjustAcItem();
|
||||
}
|
||||
}
|
||||
|
||||
// respect the usual clicking subtleties
|
||||
openUILink(url, aEvent, options);
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- This handles keypress changes to the selection among the one-off
|
||||
search buttons and between the one-offs and the listbox. It returns
|
||||
true if the keypress was consumed and false if not. -->
|
||||
<method name="handleKeyPress">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
this.oneOffSearchButtons.handleKeyPress(aEvent, this._matchCount,
|
||||
!this._isFirstResultHeuristic,
|
||||
gBrowser.userTypedValue);
|
||||
return aEvent.defaultPrevented;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- This is called when a one-off is clicked and when "search in new tab"
|
||||
is selected from a one-off context menu. -->
|
||||
<method name="handleOneOffSearch">
|
||||
<parameter name="event"/>
|
||||
<parameter name="engine"/>
|
||||
<parameter name="where"/>
|
||||
<parameter name="params"/>
|
||||
<body><![CDATA[
|
||||
this.input.handleCommand(event, where, params);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- Result listitems call this to determine which search engine they
|
||||
should show in their labels and include in their url attributes. -->
|
||||
<property name="overrideSearchEngineName" readonly="true">
|
||||
<getter><![CDATA[
|
||||
// When building the popup, autocomplete reuses an item at index i if
|
||||
// that item's url attribute matches the controller's value at index
|
||||
// i, but only if overrideSearchEngineName matches the engine in the
|
||||
// url attribute. To absolutely avoid reusing items that shouldn't be
|
||||
// reused, always return a non-null name here by falling back to the
|
||||
// current engine.
|
||||
let engine =
|
||||
(this.oneOffSearchButtons.visuallySelectedButton &&
|
||||
this.oneOffSearchButtons.visuallySelectedButton.engine) ||
|
||||
Services.search.currentEngine;
|
||||
return engine ? engine.name : null;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="createResultLabel">
|
||||
<parameter name="item"/>
|
||||
<parameter name="proposedLabel"/>
|
||||
@ -1616,6 +1768,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
</implementation>
|
||||
<handlers>
|
||||
|
||||
<handler event="OneOffsVisuallySelectedButtonChanged"><![CDATA[
|
||||
this._visuallySelectedOneOffChanged();
|
||||
]]></handler>
|
||||
|
||||
<handler event="mousedown"><![CDATA[
|
||||
// Required to make the xul:label.text-link elements in the search
|
||||
// suggestions notification work correctly when clicked on Linux.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,3 +7,12 @@
|
||||
.searchbar-textbox {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar-textbox");
|
||||
}
|
||||
|
||||
.search-one-offs {
|
||||
-moz-binding: url("chrome://browser/content/search/search.xml#search-one-offs");
|
||||
}
|
||||
|
||||
.search-setting-button[compact=true],
|
||||
.search-setting-button-compact:not([compact=true]) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -14,21 +14,6 @@ const diacritic_engine = "Foo \u2661";
|
||||
var Preferences =
|
||||
Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let oneOff =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.classList.contains("dummy"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
|
||||
return oneOffs;
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
let currentEngine = Services.search.currentEngine;
|
||||
yield promiseNewEngine("testEngine_diacritics.xml", {setAsCurrent: false});
|
||||
|
@ -10,11 +10,15 @@ const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
|
||||
"searchbar-search-button");
|
||||
const searchSettings =
|
||||
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
const searchSettings =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-settings");
|
||||
var header =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-panel-one-offs-header");
|
||||
function getHeaderText() {
|
||||
let headerChild = header.selectedPanel;
|
||||
@ -28,21 +32,6 @@ function getHeaderText() {
|
||||
return headerStrings.join("");
|
||||
}
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let oneOff =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.classList.contains("dummy"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
|
||||
return oneOffs;
|
||||
}
|
||||
|
||||
const msg = isMac ? 5 : 1;
|
||||
const utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
@ -3,29 +3,18 @@
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
|
||||
const kValues = ["foo1", "foo2", "foo3"];
|
||||
const kUserValue = "foo";
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let oneOff = document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.classList.contains("dummy"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
|
||||
return oneOffs;
|
||||
}
|
||||
|
||||
function getOpenSearchItems() {
|
||||
let os = [];
|
||||
|
||||
let addEngineList =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"add-engines");
|
||||
for (let item = addEngineList.firstChild; item; item = item.nextSibling)
|
||||
os.push(item);
|
||||
|
@ -3,30 +3,19 @@
|
||||
const searchbar = document.getElementById("searchbar");
|
||||
const textbox = searchbar._textbox;
|
||||
const searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
const oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
|
||||
"searchbar-search-button");
|
||||
|
||||
const kValues = ["foo1", "foo2", "foo3"];
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let oneOff = document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.classList.contains("dummy"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
|
||||
return oneOffs;
|
||||
}
|
||||
|
||||
function getOpenSearchItems() {
|
||||
let os = [];
|
||||
|
||||
let addEngineList =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"add-engines");
|
||||
for (let item = addEngineList.firstChild; item; item = item.nextSibling)
|
||||
os.push(item);
|
||||
|
@ -136,3 +136,24 @@ function promiseTabLoadEvent(tab, url)
|
||||
// timeout promise as well, causing the all promise to resolve.
|
||||
return Promise.all([deferred.promise, loaded]);
|
||||
}
|
||||
|
||||
// Get an array of the one-off buttons.
|
||||
function getOneOffs() {
|
||||
let oneOffs = [];
|
||||
let searchPopup = document.getElementById("PopupSearchAutoComplete");
|
||||
let oneOffsContainer =
|
||||
document.getAnonymousElementByAttribute(searchPopup, "anonid",
|
||||
"search-one-off-buttons");
|
||||
let oneOff =
|
||||
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
|
||||
"search-panel-one-offs");
|
||||
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
|
||||
if (oneOff.nodeType == Node.ELEMENT_NODE) {
|
||||
if (oneOff.classList.contains("dummy") ||
|
||||
oneOff.classList.contains("search-setting-button-compact"))
|
||||
break;
|
||||
oneOffs.push(oneOff);
|
||||
}
|
||||
}
|
||||
return oneOffs;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
||||
|
||||
.search-panel-one-offs {
|
||||
margin: 0 -1px !important;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item {
|
||||
@ -184,7 +184,15 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item.last-of-row {
|
||||
.search-setting-button-compact {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
|
||||
.search-setting-button-compact {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
@ -298,3 +306,11 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
||||
color: HighlightText;
|
||||
border-top-color: #bdbebe;
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
}
|
||||
|
@ -173,7 +173,15 @@
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item.last-of-row {
|
||||
.search-setting-button-compact {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
|
||||
.search-setting-button-compact {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
@ -277,3 +285,11 @@
|
||||
background-color: #d3d3d3;
|
||||
border-top-color: #bdbebe;
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
}
|
||||
|
@ -98,6 +98,7 @@
|
||||
skin/classic/browser/search-history-icon.svg (../shared/search/history-icon.svg)
|
||||
skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg)
|
||||
skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg)
|
||||
skin/classic/browser/gear.svg (../shared/search/gear.svg)
|
||||
skin/classic/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
|
||||
skin/classic/browser/social/gear_default.png (../shared/social/gear_default.png)
|
||||
skin/classic/browser/social/gear_clicked.png (../shared/social/gear_clicked.png)
|
||||
|
22
browser/themes/shared/search/gear.svg
Executable file
22
browser/themes/shared/search/gear.svg
Executable file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 32 32">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill: GrayText;
|
||||
}
|
||||
use[id$="-inverted"] {
|
||||
fill: highlighttext;
|
||||
}
|
||||
</style>
|
||||
<defs>
|
||||
<path id="glyphShape-gear" d="M28,16c0-1.7,0.9-3.1,2-3.3c-0.4-1.5-0.9-2.9-1.7-4.2c-0.9,0.7-2.6,0.3-3.8-0.9c-1.2-1.2-1.6-2.8-0.9-3.8 c-1.3-0.8-2.7-1.4-4.2-1.7c-0.2,1.1-1.6,2-3.3,2S13,3.1,12.8,2c-1.5,0.4-2.9,0.9-4.2,1.7c0.7,0.9,0.3,2.6-0.9,3.8 c-1.4,1.1-3,1.5-4,0.9C2.9,9.7,2.4,11.2,2,12.7c1.1,0.2,2,1.6,2,3.3s-0.9,3.1-2,3.3c0.4,1.5,0.9,2.9,1.7,4.2 c0.9-0.7,2.6-0.3,3.8,0.9c1.2,1.2,1.6,2.8,0.9,3.8c1.3,0.8,2.7,1.4,4.2,1.7c0.2-1.1,1.6-2,3.3-2s3.1,0.9,3.3,2 c1.5-0.4,2.9-0.9,4.2-1.7c-0.7-0.9-0.3-2.6,0.9-3.8c1.3-1.2,2.8-1.6,3.8-0.9c0.8-1.3,1.4-2.7,1.7-4.2C28.9,19.1,28,17.7,28,16z M16,24c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S20.4,24,16,24z"/>
|
||||
</defs>
|
||||
<use id="gear" xlink:href="#glyphShape-gear"/>
|
||||
<use id="gear-inverted" xlink:href="#glyphShape-gear"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -181,7 +181,15 @@
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item.last-of-row {
|
||||
.search-setting-button-compact {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
|
||||
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
|
||||
.search-setting-button-compact {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
@ -291,3 +299,11 @@
|
||||
background-color: #d3d3d3;
|
||||
border-top-color: #bdbebe;
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
}
|
||||
|
@ -289,7 +289,9 @@ nsAutoCompleteController::HandleText()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCompleteController::HandleEnter(bool aIsPopupSelection, bool *_retval)
|
||||
nsAutoCompleteController::HandleEnter(bool aIsPopupSelection,
|
||||
nsIDOMEvent *aEvent,
|
||||
bool *_retval)
|
||||
{
|
||||
*_retval = false;
|
||||
if (!mInput)
|
||||
@ -312,7 +314,7 @@ nsAutoCompleteController::HandleEnter(bool aIsPopupSelection, bool *_retval)
|
||||
|
||||
// Stop the search, and handle the enter.
|
||||
StopSearch();
|
||||
EnterMatch(aIsPopupSelection);
|
||||
EnterMatch(aIsPopupSelection, aEvent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -388,7 +390,7 @@ NS_IMETHODIMP
|
||||
nsAutoCompleteController::HandleTab()
|
||||
{
|
||||
bool cancel;
|
||||
return HandleEnter(false, &cancel);
|
||||
return HandleEnter(false, nullptr, &cancel);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1356,7 +1358,8 @@ nsAutoCompleteController::ClearSearchTimer()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAutoCompleteController::EnterMatch(bool aIsPopupSelection)
|
||||
nsAutoCompleteController::EnterMatch(bool aIsPopupSelection,
|
||||
nsIDOMEvent *aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIAutoCompleteInput> input(mInput);
|
||||
nsCOMPtr<nsIAutoCompletePopup> popup;
|
||||
@ -1492,7 +1495,7 @@ nsAutoCompleteController::EnterMatch(bool aIsPopupSelection)
|
||||
ClosePopup();
|
||||
|
||||
bool cancel;
|
||||
input->OnTextEntered(&cancel);
|
||||
input->OnTextEntered(aEvent, &cancel);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -55,7 +55,8 @@ protected:
|
||||
nsresult ProcessResult(int32_t aSearchIndex, nsIAutoCompleteResult *aResult);
|
||||
nsresult PostSearchCleanup();
|
||||
|
||||
nsresult EnterMatch(bool aIsPopupSelection);
|
||||
nsresult EnterMatch(bool aIsPopupSelection,
|
||||
nsIDOMEvent *aEvent);
|
||||
nsresult RevertTextValue();
|
||||
|
||||
nsresult CompleteDefaultIndex(int32_t aResultIndex);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAutoCompleteInput;
|
||||
interface nsIDOMEvent;
|
||||
|
||||
[scriptable, uuid(ff9f8465-204a-47a6-b3c9-0628b3856684)]
|
||||
interface nsIAutoCompleteController : nsISupports
|
||||
@ -63,9 +64,16 @@ interface nsIAutoCompleteController : nsISupports
|
||||
* fill this value into the input field before continuing. If false, just
|
||||
* use the current value of the input field.
|
||||
*
|
||||
* @param aIsPopupSelection
|
||||
* Pass true if the selection was made from the popup.
|
||||
* @param aEvent
|
||||
* The event that triggered the enter, like a key event if the user
|
||||
* pressed the Return key or a click event if the user clicked a popup
|
||||
* item.
|
||||
* @return True if the controller wishes to prevent event propagation and default event
|
||||
*/
|
||||
boolean handleEnter(in boolean aIsPopupSelection);
|
||||
boolean handleEnter(in boolean aIsPopupSelection,
|
||||
[optional] in nsIDOMEvent aEvent);
|
||||
|
||||
/*
|
||||
* Notify the controller that the user wishes to revert autocomplete
|
||||
|
@ -124,9 +124,11 @@ interface nsIAutoCompleteInput : nsISupports
|
||||
/*
|
||||
* Notification that the user selected and entered a result item
|
||||
*
|
||||
* @param aEvent
|
||||
* The event that triggered the enter.
|
||||
* @return True if the user wishes to prevent the enter
|
||||
*/
|
||||
boolean onTextEntered();
|
||||
boolean onTextEntered([optional] in nsIDOMEvent aEvent);
|
||||
|
||||
/*
|
||||
* Notification that the user cancelled the autocomplete session
|
||||
|
@ -326,6 +326,23 @@ this.PlacesUtils = {
|
||||
return bundle.GetStringFromName(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes a moz-action URI for the given action and set of parameters.
|
||||
*
|
||||
* @param type
|
||||
* The action type.
|
||||
* @param params
|
||||
* A JS object of action params.
|
||||
* @returns A moz-action URI as a string.
|
||||
*/
|
||||
mozActionURI(type, params) {
|
||||
let encodedParams = {};
|
||||
for (let key in params) {
|
||||
encodedParams[key] = encodeURIComponent(params[key]);
|
||||
}
|
||||
return "moz-action:" + type + "," + JSON.stringify(encodedParams);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not a ResultNode is a Bookmark folder.
|
||||
* @param aNode
|
||||
|
@ -575,24 +575,6 @@ function stripHttpAndTrim(spec) {
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a moz-action: URL for a given action and set of parameters.
|
||||
*
|
||||
* @param action
|
||||
* Name of the action
|
||||
* @param params
|
||||
* Object, whose keys are parameter names and values are the
|
||||
* corresponding parameter values.
|
||||
* @return String representation of the built moz-action: URL
|
||||
*/
|
||||
function makeActionURL(action, params) {
|
||||
let encodedParams = {};
|
||||
for (let key in params) {
|
||||
encodedParams[key] = encodeURIComponent(params[key]);
|
||||
}
|
||||
return "moz-action:" + action + "," + JSON.stringify(encodedParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key to be used for a URL in a map for the purposes of removing
|
||||
* duplicate entries - any 2 URLs that should be considered the same should
|
||||
@ -1132,8 +1114,10 @@ Search.prototype = {
|
||||
let escapedURL = entry.url.href.replace("%s", queryString);
|
||||
|
||||
let style = (this._enableActions ? "action " : "") + "keyword";
|
||||
let actionURL = makeActionURL("keyword", { url: escapedURL,
|
||||
input: this._originalSearchString });
|
||||
let actionURL = PlacesUtils.mozActionURI("keyword", {
|
||||
url: escapedURL,
|
||||
input: this._originalSearchString,
|
||||
});
|
||||
let value = this._enableActions ? actionURL : escapedURL;
|
||||
// The title will end up being "host: queryString"
|
||||
let comment = entry.url.host;
|
||||
@ -1231,7 +1215,7 @@ Search.prototype = {
|
||||
if (match.engineAlias) {
|
||||
actionURLParams.alias = match.engineAlias;
|
||||
}
|
||||
let value = makeActionURL("searchengine", actionURLParams);
|
||||
let value = PlacesUtils.mozActionURI("searchengine", actionURLParams);
|
||||
|
||||
this._addMatch({
|
||||
value: value,
|
||||
@ -1263,7 +1247,7 @@ Search.prototype = {
|
||||
let match = {
|
||||
// We include the deviceName in the action URL so we can render it in
|
||||
// the URLBar.
|
||||
value: makeActionURL("remotetab", { url, deviceName }),
|
||||
value: PlacesUtils.mozActionURI("remotetab", { url, deviceName }),
|
||||
comment: title || url,
|
||||
style: "action remotetab",
|
||||
// we want frecency > FRECENCY_DEFAULT so it doesn't get pushed out
|
||||
@ -1323,7 +1307,7 @@ Search.prototype = {
|
||||
let escapedURL = uri.spec;
|
||||
let displayURL = textURIService.unEscapeURIForUI("UTF-8", uri.spec);
|
||||
|
||||
let value = makeActionURL("visiturl", {
|
||||
let value = PlacesUtils.mozActionURI("visiturl", {
|
||||
url: escapedURL,
|
||||
input: this._originalSearchString,
|
||||
});
|
||||
@ -1392,7 +1376,7 @@ Search.prototype = {
|
||||
}
|
||||
|
||||
// Turn the match into a searchengine action with a favicon.
|
||||
match.value = makeActionURL("searchengine", {
|
||||
match.value = PlacesUtils.mozActionURI("searchengine", {
|
||||
engineName: parseResult.engineName,
|
||||
input: parseResult.terms,
|
||||
searchQuery: parseResult.terms,
|
||||
@ -1564,7 +1548,7 @@ Search.prototype = {
|
||||
let url = escapedURL;
|
||||
let action = null;
|
||||
if (this._enableActions && openPageCount > 0 && this.hasBehavior("openpage")) {
|
||||
url = makeActionURL("switchtab", {url: escapedURL});
|
||||
url = PlacesUtils.mozActionURI("switchtab", {url: escapedURL});
|
||||
action = "switchtab";
|
||||
}
|
||||
|
||||
|
@ -557,7 +557,8 @@ nsFormFillController::OnSearchComplete()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFormFillController::OnTextEntered(bool* aPrevent)
|
||||
nsFormFillController::OnTextEntered(nsIDOMEvent* aEvent,
|
||||
bool* aPrevent)
|
||||
{
|
||||
NS_ENSURE_ARG(aPrevent);
|
||||
NS_ENSURE_TRUE(mFocusedInput, NS_OK);
|
||||
@ -1008,7 +1009,7 @@ nsFormFillController::KeyPress(nsIDOMEvent* aEvent)
|
||||
cancel = false;
|
||||
break;
|
||||
case nsIDOMKeyEvent::DOM_VK_RETURN:
|
||||
mController->HandleEnter(false, &cancel);
|
||||
mController->HandleEnter(false, aEvent, &cancel);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@
|
||||
<field name="mController">null</field>
|
||||
<field name="mSearchNames">null</field>
|
||||
<field name="mIgnoreInput">false</field>
|
||||
<field name="mEnterEvent">null</field>
|
||||
|
||||
<field name="_searchBeginHandler">null</field>
|
||||
<field name="_searchCompleteHandler">null</field>
|
||||
@ -232,11 +231,12 @@
|
||||
</method>
|
||||
|
||||
<method name="onTextEntered">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
let rv = false;
|
||||
if (this._textEnteredHandler)
|
||||
rv = this._textEnteredHandler(this.mEnterEvent);
|
||||
this.mEnterEvent = null;
|
||||
if (this._textEnteredHandler) {
|
||||
rv = this._textEnteredHandler(event);
|
||||
}
|
||||
return rv;
|
||||
]]></body>
|
||||
</method>
|
||||
@ -494,14 +494,13 @@
|
||||
if (aEvent.metaKey)
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
this.mEnterEvent = aEvent;
|
||||
if (this.mController.selection) {
|
||||
this._selectionDetails = {
|
||||
index: this.mController.selection.currentIndex,
|
||||
kind: "key"
|
||||
};
|
||||
}
|
||||
cancel = this.handleEnter();
|
||||
cancel = this.handleEnter(aEvent);
|
||||
break;
|
||||
case KeyEvent.DOM_VK_DELETE:
|
||||
if (AppConstants.platform == "macosx" && !aEvent.shiftKey) {
|
||||
@ -536,8 +535,9 @@
|
||||
</method>
|
||||
|
||||
<method name="handleEnter">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
return this.mController.handleEnter(false);
|
||||
return this.mController.handleEnter(false, event || null);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
@ -946,7 +946,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController);
|
||||
controller.handleEnter(true);
|
||||
controller.handleEnter(true, aEvent);
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
@ -1253,15 +1253,24 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
invalidateReason == iface.INVALIDATE_REASON_NEW_RESULT &&
|
||||
(item.getAttribute("url") == url ||
|
||||
this.richlistbox.mouseSelectedIndex === this._currentIndex)) {
|
||||
item.collapsed = false;
|
||||
// Call adjustSiteIconStart only after setting collapsed=false.
|
||||
// The calculations it does may be wrong otherwise.
|
||||
item.adjustSiteIconStart(this._siteIconStart);
|
||||
// The popup may have changed size between now and the last time
|
||||
// the item was shown, so always handle over/underflow.
|
||||
item.handleOverUnderflow();
|
||||
this._currentIndex++;
|
||||
continue;
|
||||
// Additionally, if the item is a searchengine action, then it
|
||||
// should only be reused if the engine name is the same as the
|
||||
// popup's override engine name, if any.
|
||||
let action = item._parseActionUrl(url);
|
||||
if (!action ||
|
||||
action.type != "searchengine" ||
|
||||
!this.overrideSearchEngineName ||
|
||||
action.params.engineName == this.overrideSearchEngineName) {
|
||||
item.collapsed = false;
|
||||
// Call adjustSiteIconStart only after setting collapsed=
|
||||
// false. The calculations it does may be wrong otherwise.
|
||||
item.adjustSiteIconStart(this._siteIconStart);
|
||||
// The popup may have changed size between now and the last
|
||||
// time the item was shown, so always handle over/underflow.
|
||||
item.handleOverUnderflow();
|
||||
this._currentIndex++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1276,7 +1285,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
item.setAttribute("image", iconURI);
|
||||
item.setAttribute("url", url);
|
||||
item.setAttribute("title", controller.getCommentAt(this._currentIndex));
|
||||
item.setAttribute("type", controller.getStyleAt(this._currentIndex));
|
||||
item.setAttribute("originaltype", controller.getStyleAt(this._currentIndex));
|
||||
item.setAttribute("text", trimmedSearchString);
|
||||
|
||||
if (this._currentIndex < existingItemsCount) {
|
||||
@ -1851,7 +1860,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
let originalUrl = this.getAttribute("url");
|
||||
let emphasiseUrl = true;
|
||||
|
||||
let type = this.getAttribute("type");
|
||||
let type = this.getAttribute("originaltype");
|
||||
let types = new Set(type.split(/\s+/));
|
||||
let initialTypes = new Set(types);
|
||||
// Remove types that should ultimately not be in the `type` string.
|
||||
@ -1898,6 +1907,17 @@ extends="chrome://global/content/bindings/popup.xml#popup">
|
||||
// changed the order while it was possible, so doesn't look like
|
||||
// there's a strong need for that.
|
||||
let {engineName, searchSuggestion, searchQuery} = action.params;
|
||||
|
||||
// Override the engine name if the popup defines an override.
|
||||
let override = popup.overrideSearchEngineName;
|
||||
if (override && override != engineName) {
|
||||
engineName = override;
|
||||
action.params.engineName = override;
|
||||
let newURL =
|
||||
PlacesUtils.mozActionURI(action.type, action.params);
|
||||
this.setAttribute("url", newURL);
|
||||
}
|
||||
|
||||
let engineStr =
|
||||
this._stringBundle.formatStringFromName("searchWithEngine",
|
||||
[engineName], 1);
|
||||
|
Loading…
Reference in New Issue
Block a user