Bug 1477985 - Implement basic UrlbarInput and UrlbarView classes and a hidden pref for using them. r=standard8

This commit is contained in:
Dão Gottwald 2018-09-13 18:38:07 +02:00
Родитель 21d0088d00
Коммит 7dee39df6f
15 изменённых файлов: 448 добавлений и 47 удалений

Просмотреть файл

@ -335,6 +335,8 @@ pref("browser.urlbar.switchTabs.adoptIntoActiveWindow", false);
// should be opened in new tabs by default.
pref("browser.urlbar.openintab", false);
pref("browser.urlbar.quantumbar", false);
pref("browser.altClickSave", false);
// Enable logging downloads operations to the Console.

Просмотреть файл

@ -536,6 +536,10 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
}
#urlbar {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#legacy-urlbar);
}
#urlbar[quantumbar] {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
}

Просмотреть файл

@ -67,6 +67,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
Translation: "resource:///modules/translation/Translation.jsm",
UITour: "resource:///modules/UITour.jsm",
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
UrlbarInput: "resource:///modules/UrlbarInput.jsm",
Utils: "resource://gre/modules/sessionstore/Utils.jsm",
Weave: "resource://services-sync/main.js",
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
@ -251,27 +252,41 @@ if (AppConstants.platform != "macosx") {
var gEditUIVisible = true;
}
/* globals gNavToolbox, gURLBar:true */
[
["gNavToolbox", "navigator-toolbox"],
["gURLBar", "urlbar"],
].forEach(function(elementGlobal) {
var [name, id] = elementGlobal;
Object.defineProperty(window, name, {
configurable: true,
enumerable: true,
get() {
var element = document.getElementById(id);
if (!element)
return null;
delete window[name];
return window[name] = element;
},
set(val) {
delete window[name];
return window[name] = val;
},
});
Object.defineProperty(this, "gURLBar", {
configurable: true,
enumerable: true,
get() {
delete this.gURLBar;
let element = document.getElementById("urlbar");
// For now, always use the legacy implementation in the first window to
// have a usable address bar e.g. for accessing about:config.
if (BrowserWindowTracker.windowCount <= 1 ||
!Services.prefs.getBoolPref("browser.urlbar.quantumbar", false)) {
return this.gURLBar = element;
}
// Disable the legacy XBL binding.
element.setAttribute("quantumbar", "true");
// Re-focus the input field if it was focused before switching bindings.
if (element.hasAttribute("focused")) {
element.inputField.focus();
}
return this.gURLBar =
new UrlbarInput(element, document.getElementById("urlbar-results"));
},
});
Object.defineProperty(this, "gNavToolbox", {
configurable: true,
enumerable: true,
get() {
delete this.gNavToolbox;
return this.gNavToolbox = document.getElementById("navigator-toolbox");
},
});
// Smart getter for the findbar. If you don't wish to force the creation of

Просмотреть файл

@ -213,6 +213,22 @@ xmlns="http://www.w3.org/1999/xhtml"
level="parent"
overflowpadding="15" />
<!-- for url bar autocomplete -->
<panel id="urlbar-results"
role="group"
noautofocus="true"
hidden="true"
flip="none"
level="parent">
<html:div class="urlbarView-body-outer">
<html:div class="urlbarView-body-inner">
<!-- TODO: add search suggestions notification -->
<html:div class="urlbarView-results"/>
<!-- TODO: add footer -->
</html:div>
</html:div>
</panel>
<!-- for date/time picker. consumeoutsideclicks is set to never, so that
clicks on the anchored input box are never consumed. -->
<panel id="DateTimePickerPanel"

Просмотреть файл

@ -15,21 +15,25 @@ requestLongerTimeout(5);
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
{
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.DEBUG ||
AppConstants.platform == "win" ||
AppConstants.platform == "macosx") {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"_rebuild@chrome://browser/content/search/search.xml",
"set_popup@chrome://browser/content/search/search.xml",
"set_oneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
},
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
@ -62,8 +66,8 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
},
];
}
);
// These extra reflows happen on beta/release as one of the default bookmarks in
// bookmarks.html.in has a long URL.
@ -75,16 +79,16 @@ if (AppConstants.RELEASE_OR_BETA) {
"onunderflow@chrome://browser/content/browser.xul",
],
maxCount: 6,
});
EXPECTED_REFLOWS_FIRST_OPEN.push({
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
"_onOverflow@chrome://global/content/bindings/autocomplete.xml",
"onoverflow@chrome://browser/content/browser.xul",
],
maxCount: 6,
});
EXPECTED_REFLOWS_FIRST_OPEN.push({
},
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
"_adjustAcItem@chrome://global/content/bindings/autocomplete.xml",

Просмотреть файл

@ -15,21 +15,26 @@ requestLongerTimeout(5);
*/
/* These reflows happen only the first time the awesomebar panel opens. */
const EXPECTED_REFLOWS_FIRST_OPEN = [
{
const EXPECTED_REFLOWS_FIRST_OPEN = [];
if (AppConstants.DEBUG ||
AppConstants.platform == "linux" ||
AppConstants.platform == "macosx" ||
AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
EXPECTED_REFLOWS_FIRST_OPEN.push({
stack: [
"_rebuild@chrome://browser/content/search/search.xml",
"set_popup@chrome://browser/content/search/search.xml",
"set_oneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
"urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
"@chrome://browser/content/urlbarBindings.xml",
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
},
});
}
EXPECTED_REFLOWS_FIRST_OPEN.push(
{
stack: [
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
@ -62,8 +67,8 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
"openPopup@chrome://global/content/bindings/autocomplete.xml",
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
],
},
];
}
);
/* These reflows happen everytime the awesomebar panel opens. */
const EXPECTED_REFLOWS_SECOND_OPEN = [

Просмотреть файл

@ -21,7 +21,43 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="urlbar" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
<binding id="urlbar" extends="chrome://global/content/bindings/textbox.xml#textbox">
<content sizetopopup="pref">
<xul:hbox flex="1" class="urlbar-textbox-container" tooltip="aHTMLTooltip">
<children includes="image|deck|stack|box"/>
<xul:moz-input-box anonid="moz-input-box"
class="urlbar-input-box"
flex="1">
<children/>
<html:input anonid="scheme"
class="urlbar-scheme textbox-input"
required="required"
xbl:inherits="textoverflow,focused"/>
<html:input anonid="input"
class="urlbar-input textbox-input"
allowevents="true"
inputmode="mozAwesomebar"
xbl:inherits="value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
</xul:moz-input-box>
<xul:image anonid="urlbar-go-button"
class="urlbar-go-button urlbar-icon"
onclick="gURLBar.handleCommand(event);"
tooltiptext="&goEndCap.tooltip;"
xbl:inherits="pageproxystate,parentfocused=focused,usertyping"/>
<xul:dropmarker anonid="historydropmarker"
class="urlbar-history-dropmarker urlbar-icon chromeclass-toolbar-additional"
tooltiptext="&urlbar.openHistoryPopup.tooltip;"
allowevents="true"
xbl:inherits="open,parentfocused=focused,usertyping"/>
<children includes="hbox"/>
</xul:hbox>
<xul:popupset anonid="popupset"
class="autocomplete-result-popupset"/>
<children includes="toolbarbutton"/>
</content>
</binding>
<binding id="legacy-urlbar" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
<content sizetopopup="pref">
<xul:hbox flex="1" class="urlbar-textbox-container" tooltip="aHTMLTooltip">

Просмотреть файл

@ -5,11 +5,11 @@ module.exports = {
"mozilla/var-only-at-top-level": "error",
"require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"FunctionDeclaration": false,
"MethodDefinition": false,
"ClassDeclaration": true,
"ArrowFunctionExpression": true,
"FunctionExpression": true
"ArrowFunctionExpression": false,
"FunctionExpression": false
}
}],
"valid-jsdoc": ["error", {

Просмотреть файл

@ -0,0 +1,101 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["UrlbarInput"];
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarView: "resource:///modules/UrlbarView.jsm",
});
/**
* Represents the urlbar <textbox>.
* Also forwards important textbox properties and methods.
*/
class UrlbarInput {
/**
* @param {object} textbox
* The <textbox> element.
* @param {object} panel
* The <panel> element.
*/
constructor(textbox, panel) {
this.textbox = textbox;
this.panel = panel;
this.view = new UrlbarView(this);
this.valueIsTyped = false;
this.userInitiatedFocus = false;
const METHODS = ["addEventListener", "removeEventListener",
"setAttribute", "hasAttribute", "removeAttribute", "getAttribute",
"focus", "blur", "select"];
const READ_ONLY_PROPERTIES = ["focused", "inputField", "editor"];
const READ_WRITE_PROPERTIES = ["value", "placeholder", "readOnly",
"selectionStart", "selectionEnd"];
for (let method of METHODS) {
this[method] = (...args) => {
this.textbox[method](...args);
};
}
for (let property of READ_ONLY_PROPERTIES) {
Object.defineProperty(this, property, {
enumerable: true,
get() {
return this.textbox[property];
},
});
}
for (let property of READ_WRITE_PROPERTIES) {
Object.defineProperty(this, property, {
enumerable: true,
get() {
return this.textbox[property];
},
set(val) {
return this.textbox[property] = val;
},
});
}
this.addEventListener("input", this);
}
formatValue() {
}
closePopup() {
this.view.close();
}
openResults() {
this.view.open();
}
/**
* Passes DOM events for the textbox to the _on<event type> methods.
* @param {Event} event
* DOM event from the <textbox>.
*/
handleEvent(event) {
let methodName = "_on" + event.type;
if (methodName in this) {
this[methodName](event);
} else {
throw "Unrecognized urlbar event: " + event.type;
}
}
// Private methods below.
/* eslint-disable require-jsdoc */
_oninput(event) {
this.openResults();
}
}

Просмотреть файл

@ -0,0 +1,131 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["UrlbarView"];
/**
* Receives and displays address bar autocomplete results.
*/
class UrlbarView {
/**
* @param {UrlbarInput} urlbar
* The UrlbarInput instance belonging to this UrlbarView instance.
*/
constructor(urlbar) {
this.urlbar = urlbar;
this.panel = urlbar.panel;
this.document = urlbar.panel.ownerDocument;
this.window = this.document.defaultView;
this._mainContainer = this.panel.querySelector(".urlbarView-body-inner");
this._rows = this.panel.querySelector(".urlbarView-results");
// For the horizontal fade-out effect, set the overflow attribute on result
// rows when they overflow.
this._rows.addEventListener("overflow", event => {
if (event.target.classList.contains("urlbarView-row-inner")) {
event.target.toggleAttribute("overflow", true);
}
});
this._rows.addEventListener("underflow", event => {
if (event.target.classList.contains("urlbarView-row-inner")) {
event.target.toggleAttribute("overflow", false);
}
});
}
/**
* Opens the autocomplete results popup.
*/
open() {
this.panel.removeAttribute("hidden");
let panelDirection = this.panel.style.direction;
if (!panelDirection) {
panelDirection = this.panel.style.direction =
this.window.getComputedStyle(this.urlbar.textbox).direction;
}
// Make the panel span the width of the window.
let documentRect =
this._getBoundsWithoutFlushing(this.document.documentElement);
let width = documentRect.right - documentRect.left;
this.panel.setAttribute("width", width);
// Subtract two pixels for left and right borders on the panel.
this._mainContainer.style.maxWidth = (width - 2) + "px";
this.panel.openPopup(this.urlbar.textbox.closest("toolbar"), "after_end", 0, -1);
this._rows.textContent = "";
for (let i = 0; i < 12; i++) {
this._addRow();
}
this._rows.firstElementChild.toggleAttribute("selected", true);
}
/**
* Closes the autocomplete results popup.
*/
close() {
}
// Private methods below.
/* eslint-disable require-jsdoc */
_getBoundsWithoutFlushing(element) {
return this.window.windowUtils.getBoundsWithoutFlushing(element);
}
_createElement(name) {
return this.document.createElementNS("http://www.w3.org/1999/xhtml", name);
}
_addRow() {
const SWITCH_TO_TAB = Math.random() < .3;
let item = this._createElement("div");
item.className = "urlbarView-row";
if (SWITCH_TO_TAB) {
item.setAttribute("action", "switch-to-tab");
}
let content = this._createElement("span");
content.className = "urlbarView-row-inner";
item.appendChild(content);
let actionIcon = this._createElement("span");
actionIcon.className = "urlbarView-action-icon";
content.appendChild(actionIcon);
let favicon = this._createElement("span");
favicon.className = "urlbarView-favicon";
content.appendChild(favicon);
let title = this._createElement("span");
title.className = "urlbarView-title";
do {
title.textContent += "foo bar ";
} while (Math.random() < .5);
content.appendChild(title);
let secondary = this._createElement("span");
secondary.className = "urlbarView-secondary";
if (SWITCH_TO_TAB) {
secondary.classList.add("urlbarView-action");
secondary.textContent = "Switch to Tab";
} else {
secondary.classList.add("urlbarView-url");
secondary.textContent = "http://www";
while (Math.random() < .95) {
secondary.textContent += ".xyz";
}
}
content.appendChild(secondary);
this._rows.appendChild(item);
}
}

Просмотреть файл

@ -7,7 +7,9 @@ with Files("**"):
EXTRA_JS_MODULES += [
'UrlbarController.jsm',
'UrlbarInput.jsm',
'UrlbarTokenizer.jsm',
'UrlbarView.jsm',
]
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']

Просмотреть файл

@ -4,7 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%endif
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
%include ../shared/browser.inc.css

Просмотреть файл

@ -5,7 +5,6 @@
%include shared.inc
%define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"])
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
%include ../shared/browser.inc.css

Просмотреть файл

@ -22,6 +22,94 @@
--urlbar-popup-action-color: #30e60b;
}
#urlbar-results {
-moz-appearance: none;
background: var(--autocomplete-popup-background);
color: var(--autocomplete-popup-color);
border: 1px solid var(--autocomplete-popup-border-color);
}
.urlbarView-body-inner {
box-sizing: border-box;
}
.urlbarView-results {
padding: 5px;
white-space: nowrap;
}
.urlbarView-row {
padding: 7px 50px;
border-radius: 2px;
}
.urlbarView-row-inner {
overflow: hidden;
display: block;
}
.urlbarView-row-inner[overflow] {
mask-image: linear-gradient(to left, transparent, black 2em);
}
.urlbarView-row:hover {
background: var(--arrowpanel-dimmed);
}
.urlbarView-row[selected] {
background: var(--autocomplete-popup-highlight-background);
color: var(--autocomplete-popup-highlight-color);
}
.urlbarView-action-icon,
.urlbarView-favicon {
display: inline-block;
vertical-align: middle;
width: 16px;
height: 16px;
margin-inline-end: .6em;
}
.urlbarView-favicon {
border-radius: 8px;
background: currentcolor;
opacity: 0.6;
}
.urlbarView-row[action=switch-to-tab] > .row-inner > .action-icon {
height: 8px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
background: currentcolor;
opacity: 0.5;
}
.urlbarView-title {
font-size: 1.05em;
}
.urlbarView-title::after {
content: "\2014";
color: var(--panel-disabled-color);
margin: 0 .4em;
}
.urlbarView-secondary {
color: var(--urlbar-popup-action-color);
font-size: 0.9em;
}
.urlbarView-url {
color: var(--urlbar-popup-url-color);
}
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-title::after,
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary {
color: inherit;
}
/* legacy URL bar styles below */
#PopupAutoCompleteRichResult,
#PopupSearchAutoComplete {
background: var(--autocomplete-popup-background);

Просмотреть файл

@ -2,7 +2,6 @@
* 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/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
%include ../shared/browser.inc.css