feat: add double-click select all behavior to urlbar

This commit is contained in:
Alex Kontos
2025-08-05 15:35:25 +01:00
parent 7d577575b0
commit c0f21b484c
5 changed files with 96 additions and 7 deletions

View File

@@ -532,15 +532,16 @@
/** /**
* Determines if we should select all the text in the searchbar based on the * Determines if we should select all the text in the searchbar based on the
* searchbar state, and whether the selection is empty. * clickSelectsAll pref, searchbar state, and whether the selection is empty.
*/ */
_maybeSelectAll() { _maybeSelectAll() {
if ( if (
!this._preventClickSelectsAll && !this._preventClickSelectsAll &&
UrlbarPrefs.get("clickSelectsAll") &&
document.activeElement == this._textbox && document.activeElement == this._textbox &&
this._textbox.selectionStart == this._textbox.selectionEnd this._textbox.selectionStart == this._textbox.selectionEnd
) { ) {
this.select(); this._textbox.editor.selectAll();
} }
} }
@@ -647,6 +648,11 @@
// is text in the textbox. // is text in the textbox.
this.openSuggestionsPanel(true); this.openSuggestionsPanel(true);
} }
if (event.detail == 2 && UrlbarPrefs.get("doubleClickSelectsAll")) {
this._textbox.editor.selectAll();
event.preventDefault();
}
}); });
} }

View File

@@ -4077,11 +4077,15 @@ export class UrlbarInput {
/** /**
* Determines if we should select all the text in the Urlbar based on the * Determines if we should select all the text in the Urlbar based on the
* Urlbar state, and whether the selection is empty. * clickSelectsAll pref, Urlbar state, and whether the selection is empty.
*
* @param {boolean} [ignoreClickSelectsAllPref]
* If true, the browser.urlbar.clickSelectsAll pref will be ignored.
*/ */
_maybeSelectAll() { _maybeSelectAll(ignoreClickSelectsAllPref = false) {
if ( if (
!this._preventClickSelectsAll && !this._preventClickSelectsAll &&
(ignoreClickSelectsAllPref || lazy.UrlbarPrefs.get("clickSelectsAll")) &&
this._compositionState != lazy.UrlbarUtils.COMPOSITION.COMPOSING && this._compositionState != lazy.UrlbarUtils.COMPOSITION.COMPOSING &&
this.focused && this.focused &&
this.inputField.selectionStart == this.inputField.selectionEnd this.inputField.selectionStart == this.inputField.selectionEnd
@@ -4214,7 +4218,9 @@ export class UrlbarInput {
return; return;
} }
this._maybeSelectAll(); // If the user right clicks, we select all regardless of the value of
// the browser.urlbar.clickSelectsAll pref.
this._maybeSelectAll(/* ignoreClickSelectsAllPref */ event.button == 2);
} }
_on_focus(event) { _on_focus(event) {
@@ -4263,7 +4269,7 @@ export class UrlbarInput {
} }
if (this.inputField.hasAttribute("refocused-by-panel")) { if (this.inputField.hasAttribute("refocused-by-panel")) {
this._maybeSelectAll(); this._maybeSelectAll(true);
} }
} }
@@ -4325,7 +4331,10 @@ export class UrlbarInput {
this.inputField.setSelectionRange(0, 0); this.inputField.setSelectionRange(0, 0);
} }
if (event.target.classList.contains(SEARCH_BUTTON_CLASS)) { if (event.detail == 2 && lazy.UrlbarPrefs.get("doubleClickSelectsAll")) {
this.editor.selectAll();
event.preventDefault();
} else if (event.target.classList.contains(SEARCH_BUTTON_CLASS)) {
this._preventClickSelectsAll = true; this._preventClickSelectsAll = true;
this.search(lazy.UrlbarTokenizer.RESTRICT.SEARCH); this.search(lazy.UrlbarTokenizer.RESTRICT.SEARCH);
} else { } else {

View File

@@ -75,6 +75,11 @@ const PREF_URLBAR_DEFAULTS = new Map([
// active view if the the view utilizes OpenSearch. // active view if the the view utilizes OpenSearch.
["contextualSearch.enabled", true], ["contextualSearch.enabled", true],
// If true, this optimizes for replacing the full URL rather than editing
// part of it. This also copies the urlbar value to the selection clipboard
// on systems that support it.
["clickSelectsAll", false],
// Whether using `ctrl` when hitting return/enter in the URL bar // Whether using `ctrl` when hitting return/enter in the URL bar
// (or clicking 'go') should prefix 'www.' and suffix // (or clicking 'go') should prefix 'www.' and suffix
// browser.fixup.alternate.suffix to the URL bar value prior to // browser.fixup.alternate.suffix to the URL bar value prior to
@@ -90,6 +95,11 @@ const PREF_URLBAR_DEFAULTS = new Map([
// "heuristic" result). We fetch it as fast as possible. // "heuristic" result). We fetch it as fast as possible.
["delay", 50], ["delay", 50],
// If true, this optimizes for replacing the full URL rather than selecting a
// portion of it. This also copies the urlbar value to the selection
// clipboard on systems that support it.
["doubleClickSelectsAll", false],
// Ensure we use trailing dots for DNS lookups for single words that could // Ensure we use trailing dots for DNS lookups for single words that could
// be hosts. // be hosts.
["dnsResolveFullyQualifiedNames", true], ["dnsResolveFullyQualifiedNames", true],

View File

@@ -0,0 +1,45 @@
/* 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/. */
function doubleClick(target) {
let promise = BrowserTestUtils.waitForEvent(target, "dblclick");
EventUtils.synthesizeMouseAtCenter(
target,
{ clickCount: 1 },
target.ownerGlobal
);
EventUtils.synthesizeMouseAtCenter(
target,
{ clickCount: 2 },
target.ownerGlobal
);
return promise;
}
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.clickSelectsAll", false],
["browser.urlbar.doubleClickSelectsAll", true],
],
});
let url = "about:mozilla";
let win = await BrowserTestUtils.openNewBrowserWindow();
await BrowserTestUtils.openNewForegroundTab({ gBrowser: win.gBrowser, url });
await doubleClick(win.gURLBar.inputField);
is(
win.gURLBar.selectionStart,
0,
"Selection should start at the beginning of the urlbar value"
);
is(
win.gURLBar.selectionEnd,
url.length,
"Selection should end at the end of the urlbar value"
);
win.close();
});

View File

@@ -40,6 +40,25 @@ pref("browser.uiCustomization.state", "{\"placements\":{\"widget-overflow-fixed-
// Alternative smooth scroll physics. ("MSD" = Mass-Spring-Damper) // Alternative smooth scroll physics. ("MSD" = Mass-Spring-Damper)
pref("general.smoothScroll.msdPhysics.enabled", true); pref("general.smoothScroll.msdPhysics.enabled", true);
// --- URL Bar Behavior ---
// Platform-specific settings for how clicks interact with the URL bar.
#ifdef UNIX_BUT_NOT_MAC
// On Linux (excluding macOS), a single click does not select all text in the URL bar.
pref("browser.urlbar.clickSelectsAll", false);
// On Linux (excluding macOS), a double click selects all text.
pref("browser.urlbar.doubleClickSelectsAll", true);
#else
// On other operating systems (Windows, macOS), a single click selects all text.
pref("browser.urlbar.clickSelectsAll", true);
// On other operating systems, double click behavior might be different or not specifically set to select all.
pref("browser.urlbar.doubleClickSelectsAll", false);
#endif
#ifdef XP_MACOSX
// Whether to disable treating ctrl click as right click
pref("dom.event.treat_ctrl_click_as_right_click.disabled", true);
#endif
// --- Top Sites and Partner Integrations --- // --- Top Sites and Partner Integrations ---
// Settings related to "Top Sites" on the New Tab Page and partner integrations. // Settings related to "Top Sites" on the New Tab Page and partner integrations.
pref("browser.partnerlink.attributionURL", "", locked); // URL for partner attribution (locked). pref("browser.partnerlink.attributionURL", "", locked); // URL for partner attribution (locked).