Bug 1603321 - Replace Touch Bar "Search or enter address" button with an "Exit Fullscreen" button while in fullscreen. r=mikedeboer,fluent-reviewers,flod

Differential Revision: https://phabricator.services.mozilla.com/D57350

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Harry Twyford 2020-01-22 21:08:45 +00:00
parent f362f78bca
commit 4cde91dd0c
8 changed files with 158 additions and 53 deletions

View File

@ -1687,14 +1687,8 @@ var BookmarkingUI = {
}
if (starred) {
element.setAttribute("starred", "true");
Services.obs.notifyObservers(null, "bookmark-icon-updated", "starred");
} else {
element.removeAttribute("starred");
Services.obs.notifyObservers(
null,
"bookmark-icon-updated",
"unstarred"
);
}
}
@ -1708,6 +1702,12 @@ var BookmarkingUI = {
starred ? this._starredTooltip : this._unstarredTooltip
);
}
Services.obs.notifyObservers(
null,
"bookmark-icon-updated",
starred ? "starred" : "unstarred"
);
},
/**

View File

@ -87,7 +87,7 @@ const kInputTypes = {
/**
* An object containing all implemented TouchBarInput objects.
*/
const kBuiltInInputs = {
var gBuiltInInputs = {
Back: {
title: "back",
image: "chrome://browser/skin/back.svg",
@ -164,6 +164,7 @@ const kBuiltInInputs = {
disabled: true, // Updated when the page is found to be Reader View-able.
},
OpenLocation: {
key: "open-location",
title: "open-location",
image: "chrome://browser/skin/search-glass.svg",
type: kInputTypes.MAIN_BUTTON,
@ -244,6 +245,7 @@ var localizedStrings = {};
const kHelperObservers = new Set([
"bookmark-icon-updated",
"fullscreen-painted",
"reader-mode-available",
"touchbar-location-change",
"quit-application",
@ -265,11 +267,7 @@ class TouchBarHelper {
// created/destroyed for the urlbar-focus/blur events.
this._searchPopover = this.getTouchBarInput("SearchPopover");
// The test machines do not have Touch Bars, so _inputsNotUpdated is never
// initialized. This causes problems in the tests.
if (Cu.isInAutomation) {
this._inputsNotUpdated = new Set();
}
this._inputsNotUpdated = new Set();
}
destructor() {
@ -296,19 +294,20 @@ class TouchBarHelper {
Ci.nsIMutableArray
);
for (let inputName of Object.keys(kBuiltInInputs)) {
// Every input must be updated at least once so that all assets (titles,
// icons) are loaded. We keep track of which inputs haven't updated and
// run an update on them ASAP.
this._inputsNotUpdated.clear();
for (let inputName of Object.keys(gBuiltInInputs)) {
let input = this.getTouchBarInput(inputName);
if (!input) {
continue;
}
this._inputsNotUpdated.add(inputName);
layoutItems.appendElement(input);
}
// Every input must be updated at least once so that all assets (titles,
// icons) are loaded. We keep track of which inputs haven't updated and
// run an update on them after the first location change.
this._inputsNotUpdated = new Set(Object.keys(kBuiltInInputs));
return layoutItems;
}
@ -343,11 +342,11 @@ class TouchBarHelper {
return this._searchPopover;
}
if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
if (!inputName || !gBuiltInInputs.hasOwnProperty(inputName)) {
return null;
}
let inputData = kBuiltInInputs[inputName];
let inputData = gBuiltInInputs[inputName];
let item = new TouchBarInput(inputData);
@ -361,7 +360,7 @@ class TouchBarHelper {
}
// Async l10n fills in the localized input labels after the initial load.
this._l10n.formatValue(item.key).then(result => {
this._l10n.formatValue(inputData.title).then(result => {
item.title = result;
localizedStrings[inputData.title] = result; // Cache result.
// Checking TouchBarHelper.window since this callback can fire after all windows are closed.
@ -381,7 +380,7 @@ class TouchBarHelper {
/**
* Fetches a specific Touch Bar Input by name and updates it on the Touch Bar.
* @param {...*} inputNames
* A key/keys to a value/values in the kBuiltInInputs object in this file.
* A key/keys to a value/values in the gBuiltInInputs object in this file.
*/
_updateTouchBarInputs(...inputNames) {
if (!TouchBarHelper.window || !inputNames.length) {
@ -389,14 +388,13 @@ class TouchBarHelper {
}
let inputs = [];
for (let inputName of new Set(inputNames)) {
for (let inputName of new Set([...inputNames, ...this._inputsNotUpdated])) {
let input = this.getTouchBarInput(inputName);
if (!input) {
continue;
}
if (this._inputsNotUpdated) {
this._inputsNotUpdated.delete(inputName);
}
this._inputsNotUpdated.delete(inputName);
inputs.push(input);
}
@ -433,28 +431,43 @@ class TouchBarHelper {
this.activeUrl = data;
// ReaderView button is disabled on every location change since
// Reader View must determine if the new page can be Reader Viewed.
kBuiltInInputs.ReaderView.disabled = !data.startsWith("about:reader");
kBuiltInInputs.Back.disabled = !TouchBarHelper.window.gBrowser
gBuiltInInputs.ReaderView.disabled = !data.startsWith("about:reader");
gBuiltInInputs.Back.disabled = !TouchBarHelper.window.gBrowser
.canGoBack;
kBuiltInInputs.Forward.disabled = !TouchBarHelper.window.gBrowser
gBuiltInInputs.Forward.disabled = !TouchBarHelper.window.gBrowser
.canGoForward;
this._updateTouchBarInputs(
"ReaderView",
"Back",
"Forward",
...this._inputsNotUpdated
);
this._updateTouchBarInputs("ReaderView", "Back", "Forward");
break;
case "fullscreen-painted":
if (TouchBarHelper.window.document.fullscreenElement) {
gBuiltInInputs.OpenLocation.title = "touchbar-fullscreen-exit";
gBuiltInInputs.OpenLocation.image =
"chrome://browser/skin/fullscreen-exit.svg";
gBuiltInInputs.OpenLocation.callback = () => {
TouchBarHelper.window.windowUtils.exitFullscreen();
let telemetry = Services.telemetry.getHistogramById(
"TOUCHBAR_BUTTON_PRESSES"
);
telemetry.add("OpenLocation");
};
} else {
gBuiltInInputs.OpenLocation.title = "open-location";
gBuiltInInputs.OpenLocation.image =
"chrome://browser/skin/search-glass.svg";
gBuiltInInputs.OpenLocation.callback = () =>
execCommand("Browser:OpenLocation", "OpenLocation");
}
this._updateTouchBarInputs("OpenLocation");
break;
case "bookmark-icon-updated":
data == "starred"
? (kBuiltInInputs.AddBookmark.image =
"chrome://browser/skin/bookmark.svg")
: (kBuiltInInputs.AddBookmark.image =
"chrome://browser/skin/bookmark-hollow.svg");
gBuiltInInputs.AddBookmark.image =
data == "starred"
? "chrome://browser/skin/bookmark.svg"
: "chrome://browser/skin/bookmark-hollow.svg";
this._updateTouchBarInputs("AddBookmark");
break;
case "reader-mode-available":
kBuiltInInputs.ReaderView.disabled = false;
gBuiltInInputs.ReaderView.disabled = false;
this._updateTouchBarInputs("ReaderView");
break;
case "urlbar-focus":
@ -487,7 +500,7 @@ class TouchBarHelper {
this._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
helperProto._l10n = this._l10n;
this._updateTouchBarInputs(...Object.keys(kBuiltInInputs));
this._updateTouchBarInputs(...Object.keys(gBuiltInInputs));
break;
case "quit-application":
this.destructor();

View File

@ -53,8 +53,8 @@ JavaScript API
``browser/components/touchbar/MacTouchBar.js`` defines what specific inputs are
available to the user, what icon they will have, what action they will perform,
and so on. Inputs are defined in the ``kBuiltInInputs`` object `in that file`_.
When creating a new object in ``kBuiltInInputs``, the available properties are
and so on. Inputs are defined in the ``gBuiltInInputs`` object `in that file`_.
When creating a new object in ``gBuiltInInputs``, the available properties are
documented in the JSDoc for ``TouchBarInput``:
.. highlight:: JavaScript
@ -95,7 +95,7 @@ Clarification on some of these properties is warranted.
second string, "Back", records an interaction with the back button in
Telemetry.
* ``children`` is an array of objects with the same properties as members of
``kBuiltInInputs``. When used with an input of type
``gBuiltInInputs``. When used with an input of type
``kInputTypes.SCROLLVIEW``, ``children`` can only contain inputs of type
``kInputTypes.BUTTON``. When used with an input of type
``kInputTypes.POPOVER``, any input type except another ``kInputTypes.POPOVER``
@ -159,7 +159,7 @@ Scroll View
Examples
--------
Some examples of ``kBuiltInInputs`` objects follow.
Some examples of ``gBuiltInInputs`` objects follow.
A simple button
.. highlight:: JavaScript
@ -246,13 +246,13 @@ The search popover
Adding a new input
------------------
Adding a new input is easy: just add a new object to ``kBuiltInInputs``. This
Adding a new input is easy: just add a new object to ``gBuiltInInputs``. This
will make the input available in the Touch Bar customization window (accessible
from the Firefox menu bar item).
If you want to to add your new input to the default set, add its identifier
here_, where ``type`` is a value from ``kAllowedInputTypes`` in that
file and ``key`` is the value you set for ``title`` in ``kBuiltInInputs``.
file and ``key`` is the value you set for ``title`` in ``gBuiltInInputs``.
You should request approval from UX before changing the default set of inputs.
.. _here: https://searchfox.org/mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c/widget/cocoa/nsTouchBar.mm#100
@ -323,7 +323,7 @@ If you need to generate an identifier, use the convenience method
will be erased.
Each identifier is tied to a ``TouchBarInput``. ``TouchBarInput`` is a class
that holds the properties specified for each input in ``kBuiltInInputs``.
that holds the properties specified for each input in ``gBuiltInInputs``.
``nsTouchBar`` uses them to create instances of ``NSTouchBarItem``
which are the actual objects used by Apple's Touch Bar API and displayed in the
Touch Bar. It is important to understand the difference between

View File

@ -1,6 +1,8 @@
[DEFAULT]
support-files =
readerModeArticle.html
test-video.mp4
video_test.html
[browser_touchbar_searchrestrictions.js]
[browser_touchbar_tests.js]

View File

@ -19,6 +19,11 @@ XPCOMUtils.defineLazyServiceGetter(
"nsITouchBarInput"
);
const TEST_PATH = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
);
function is_element_visible(aElement, aMsg) {
isnot(aElement, null, "Element should not be null when checking visibility");
ok(!BrowserTestUtils.is_hidden(aElement), aMsg);
@ -74,10 +79,6 @@ add_task(async function updateReaderView() {
"ReaderView Touch Bar button should be disabled by default."
);
const TEST_PATH = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
);
let url = TEST_PATH + "readerModeArticle.html";
await BrowserTestUtils.withNewTab(url, async function() {
await BrowserTestUtils.waitForCondition(() => !readerButton.hidden);
@ -89,3 +90,59 @@ add_task(async function updateReaderView() {
);
});
});
add_task(async function updateMainButtonInFullscreen() {
Assert.equal(
TouchBarHelper.getTouchBarInput("OpenLocation").image.spec,
"chrome://browser/skin/search-glass.svg",
"OpenLocation should be displaying the search glass icon."
);
await BrowserTestUtils.loadURI(
gBrowser.selectedBrowser,
TEST_PATH + "video_test.html"
);
await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
let entered = waitForFullScreenState(gBrowser.selectedBrowser, true);
// Fullscreen video must be triggered from a user input handler so the video
// page contains a script to enter fullscreen on Enter instead of us calling
// requestFullscreen directly here.
EventUtils.synthesizeKey("KEY_Enter");
await entered;
Assert.equal(
TouchBarHelper.getTouchBarInput("OpenLocation").image.spec,
"chrome://browser/skin/fullscreen-exit.svg",
"OpenLocation should be displaying the exit fullscreen icon."
);
let exited = waitForFullScreenState(gBrowser.selectedBrowser, false);
EventUtils.synthesizeKey("KEY_Enter");
await exited;
Assert.equal(
TouchBarHelper.getTouchBarInput("OpenLocation").image.spec,
"chrome://browser/skin/search-glass.svg",
"OpenLocation should be displaying the search glass icon."
);
});
function waitForFullScreenState(browser, state) {
info("inside waitforfullscreenstate");
return new Promise(resolve => {
let eventReceived = false;
let observe = (subject, topic, data) => {
if (!eventReceived) {
return;
}
Services.obs.removeObserver(observe, "fullscreen-painted");
resolve();
};
Services.obs.addObserver(observe, "fullscreen-painted");
window.addEventListener(
`MozDOMFullscreen:${state ? "Entered" : "Exited"}`,
() => {
eventReceived = true;
},
{ once: true }
);
});
}

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Touch Bar Fullscreen Video Test</title>
</head>
<style>
video {
display: block;
border: 1px solid black;
}
</style>
<body>
<video id="test-video" src="test-video.mp4" controls loop="true"></video>
</body>
<script>
let video = document.getElementById("test-video");
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
}
document.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
toggleFullScreen();
}
});
</script>
</html>

View File

@ -9,6 +9,7 @@ forward = Forward
reload = Reload
home = Home
fullscreen = Fullscreen
touchbar-fullscreen-exit = Exit Fullscreen
find = Find
new-tab = New tab
add-bookmark = Add bookmark