зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1589135 - Add Touch Bar documentation. r=mikedeboer
Differential Revision: https://phabricator.services.mozilla.com/D49665 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
aef57c4d86
Коммит
120863db8c
|
@ -483,11 +483,10 @@ helperProto._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
|
|||
* @param {string} input.title
|
||||
* The lookup key for the button's localized text title.
|
||||
* @param {string} input.image
|
||||
* The name of a icon file added to
|
||||
* /widget/cocoa/resources/touchbar_icons.
|
||||
* A URL pointing to an SVG internal to Firefox.
|
||||
* @param {string} input.type
|
||||
* The type of Touch Bar input represented by the object.
|
||||
* One of `button`, `mainButton`.
|
||||
* Must be a value from kInputTypes.
|
||||
* @param {Function} input.callback
|
||||
* A callback invoked when a touchbar item is touched.
|
||||
* @param {string} [input.color]
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
Touch Bar
|
||||
=========
|
||||
|
||||
The Touch Bar is a hardware component on some MacBook Pros released from 2016.
|
||||
It is a display above the keyboard that allows more flexible types of
|
||||
input than is otherwise possible with a normal keyboard. Apple offers Touch Bar
|
||||
APIs so developers can extend the Touch Bar to display inputs specific to their
|
||||
application. Firefox consumes these APIs to offer a customizable row of inputs
|
||||
in the Touch Bar.
|
||||
|
||||
In Apple's documentation, the term "the Touch Bar" refers to the hardware.
|
||||
The term "a Touch Bar" refers not to the hardware but to a collection of inputs
|
||||
shown on the Touch Bar. This means that there can be multiple "Touch Bars" that
|
||||
switch out as the user switches contexts. The same naming convention is used in
|
||||
this document.
|
||||
|
||||
In this document and in the code, the word "input" is used to refer to
|
||||
an interactive element in the Touch Bar. It is often interchangable with
|
||||
"button", but "input" can also refer to any element displayed in the Touch Bar.
|
||||
|
||||
The Touch Bar should never offer functionality unavailable to Firefox users
|
||||
without the Touch Bar. Most macOS Firefox users do not have the Touch Bar and
|
||||
some choose to disable it. Apple's own `Human Interface Guidelines`_ (HIG)
|
||||
forbids this kind of Touch Bar functionality. Please read the HIG for more
|
||||
design considerations before you plan on implementing a new Touch Bar feature.
|
||||
|
||||
If you have questions about the Touch Bar that are not answered in this
|
||||
document, feel free to reach out to `Harry Twyford`_ (:harry on Slack).
|
||||
He wrote this document and Firefox's initial Touch Bar implementation.
|
||||
|
||||
.. _Human Interface Guidelines: https://developer.apple.com/design/human-interface-guidelines/macos/touch-bar/touch-bar-overview/
|
||||
|
||||
.. _Harry Twyford: mailto:harry@mozilla.com
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
Firefox's Touch Bar implementation is equal parts JavaScript and Cocoa
|
||||
(Objective-C++). The JavaScript code lives in ``browser/components/touchbar``
|
||||
and the Cocoa code lives in ``widget/cocoa``, mostly in ``nsTouchBar.mm``. The
|
||||
Cocoa code is a consumer of Apple's Touch Bar APIs and defines what types of
|
||||
Touch Bar inputs are available to its own consumers. The JS code in
|
||||
``browser/components/touchbar`` provides services to ``nsTouchBar.mm`` and
|
||||
defines what inputs the user actually sees in the Touch Bar. There is two-way
|
||||
communication between the JS and the Cocoa: the Cocoa code asks the JS what
|
||||
inputs it should display, and the JS asks the Cocoa code to update those inputs
|
||||
when needed.
|
||||
|
||||
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
|
||||
documented in the JSDoc for ``TouchBarInput``:
|
||||
|
||||
.. highlight:: JavaScript
|
||||
.. code::
|
||||
|
||||
/**
|
||||
* A representation of a Touch Bar input.
|
||||
* @param {string} input.title
|
||||
* The lookup key for the button's localized text title.
|
||||
* @param {string} input.image
|
||||
* A URL pointing to an SVG internal to Firefox.
|
||||
* @param {string} input.type
|
||||
* The type of Touch Bar input represented by the object.
|
||||
* Must be a value from kInputTypes.
|
||||
* @param {Function} input.callback
|
||||
* A callback invoked when a touchbar item is touched.
|
||||
* @param {string} [input.color]
|
||||
* A string in hex format specifying the button's background color.
|
||||
* If omitted, the default background color is used.
|
||||
* @param {bool} [input.disabled]
|
||||
* If `true`, the Touch Bar input is greyed out and inoperable.
|
||||
* @param {Array} [input.children]
|
||||
* An array of input objects that will be displayed as children of
|
||||
* this input. Available only for types KInputTypes.POPOVER and
|
||||
* kInputTypes.SCROLLVIEW.
|
||||
*/
|
||||
|
||||
Clarification on some of these properties is warranted.
|
||||
|
||||
* ``title`` is the key to a Fluent translation defined in ``browser/locales/<LOCALE>/browser/touchbar/touchbar.ftl``.
|
||||
* ``type`` must be a value from the ``kInputTypes`` enum in ``MacTouchBar.js``.
|
||||
For example, ``kInputTypes.BUTTON``. More information on input types follows
|
||||
below.
|
||||
* ``callback`` points to a JavaScript function. Any chrome-level JavaScript can
|
||||
be executed. ``execCommand`` is a convenience method in ``MacTouchBar.js``
|
||||
that takes a XUL command as a string and executes that command. For instance,
|
||||
one input sets ``callback`` to ``execCommand("Browser:Back", "Back")``. The
|
||||
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
|
||||
``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``
|
||||
can be used.
|
||||
|
||||
A final property, ``context``, is also accepted. ``context`` is a function that
|
||||
returns a string. The returned string should be the name of a key in
|
||||
``kBuiltInInputs``. ``context`` is a useful property if you want to show one
|
||||
input in the Touch Bar in one context, and another input in a different context.
|
||||
An example of its use follows below.
|
||||
|
||||
.. _in that file: https://searchfox.org/mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c/browser/components/touchbar/MacTouchBar.js#82
|
||||
|
||||
Input types
|
||||
-----------
|
||||
|
||||
Button
|
||||
A simple button. If ``image`` is not specified, the buttons displays the text
|
||||
label from ``title``. If both ``image`` and ``title`` are specified, only the
|
||||
``image`` is shown. The action specified in ``callback`` is executed when the
|
||||
button is pressed.
|
||||
|
||||
.. caution::
|
||||
|
||||
Even if the ``title`` will not be shown in the Touch Bar, you must still
|
||||
define a ``title`` property.
|
||||
|
||||
Main Button
|
||||
Similar to a button, but displayed at double the width. A main button
|
||||
displays both the string in ``title`` and the icon in ``image``. Only one
|
||||
main button should be shown in the Touch Bar at any time, although this is
|
||||
not enforced.
|
||||
|
||||
Label
|
||||
A non-interactive text label. This input takes only the attributes ``title``
|
||||
and ``type``.
|
||||
|
||||
Popover
|
||||
Initially represented in the Touch Bar as a button, a popover will display an
|
||||
entirely different set of inputs when pressed. These different inputs should
|
||||
be defined in the ``children`` property of the parent. Popovers can also be
|
||||
shown and hidden programmatically, by calling
|
||||
|
||||
.. highlight:: JavaScript
|
||||
.. code::
|
||||
|
||||
gTouchBarUpdater.showPopover(
|
||||
TouchBarHelper.baseWindow,
|
||||
[POPOVER],
|
||||
{true | false}
|
||||
);
|
||||
|
||||
where the second argument is a reference to a popover TouchBarInput and
|
||||
the third argument is whether the popover should be shown or hidden.
|
||||
|
||||
Scroll View
|
||||
A Scroll View is a scrolling list of buttons. The buttons should be defined
|
||||
in the Scroll View's ``children`` array.
|
||||
|
||||
.. note::
|
||||
|
||||
In Firefox, a list of search shortcuts appears in the Touch Bar when the
|
||||
address bar is focused. This is an example of a ScrollView contained within
|
||||
a popover. The popover is opened programmatically with
|
||||
``gTouchBarUpdater.showPopover`` when the address bar is focused and it is
|
||||
hidden when the address bar is blurred.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Some examples of ``kBuiltInInputs`` objects follow.
|
||||
|
||||
A simple button
|
||||
.. highlight:: JavaScript
|
||||
.. code::
|
||||
|
||||
Back: {
|
||||
title: "back",
|
||||
image: "chrome://browser/skin/back.svg",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () => execCommand("Browser:Back", "Back"),
|
||||
},
|
||||
|
||||
A button is defined with a title, icon, type, and a callback. The callback
|
||||
simply calls the XUL command to go back.
|
||||
|
||||
Using ``context``
|
||||
In this example, two main buttons are defined. One focuses the address bar
|
||||
and the other closes the current window. The OpenLocationOrClosePrivateWindow
|
||||
object uses the ``context`` property to display the former in Normal
|
||||
Browsing Mode and the latter in Private Browsing Mode. Note also that
|
||||
ClosePrivateWindow uses ``image`` and ``color`` to be consistent with
|
||||
PBM styling. By including OpenLocationOrClosePrivateWindow as a default input
|
||||
in ``nsTouchBar.mm``, the user can be shown a different Touch Bar depending on
|
||||
whether they are in Normal or Private Browsing Mode.
|
||||
|
||||
.. highlight:: JavaScript
|
||||
.. code::
|
||||
|
||||
OpenLocation: {
|
||||
title: "open-location",
|
||||
image: "chrome://browser/skin/search-glass.svg",
|
||||
type: kInputTypes.MAIN_BUTTON,
|
||||
callback: () => execCommand("Browser:OpenLocation", "OpenLocation"),
|
||||
},
|
||||
ClosePrivateWindow: {
|
||||
title: "close-private-window",
|
||||
image: "hrome://browser/skin/privateBrowsing.svg",
|
||||
type: kInputTypes.MAIN_BUTTON,
|
||||
callback: () => execCommand("cmd_closeWindow", "ClosePrivateWindow"),
|
||||
color: "#8000D7",
|
||||
},
|
||||
OpenLocationOrClosePrivateWindow: {
|
||||
// This is just a forwarder to other inputs.
|
||||
context: () => {
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(BrowserWindowTracker.getTopWindow())) {
|
||||
return "ClosePrivateWindow";
|
||||
} else {
|
||||
return "OpenLocation";
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
The search popover
|
||||
This is the input that occupies the Touch Bar when the address bar is focused.
|
||||
|
||||
.. highlight:: JavaScript
|
||||
.. code::
|
||||
|
||||
SearchPopover: {
|
||||
title: "search-popover",
|
||||
image: "chrome://browser/skin/search-glass.svg",
|
||||
type: kInputTypes.POPOVER,
|
||||
children: {
|
||||
SearchScrollViewLabel: {
|
||||
title: "search-search-in",
|
||||
type: kInputTypes.LABEL,
|
||||
},
|
||||
SearchScrollView: {
|
||||
key: "search-scrollview",
|
||||
type: kInputTypes.SCROLLVIEW,
|
||||
children: {
|
||||
Bookmarks: {
|
||||
title: "search-bookmarks",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () =>
|
||||
gTouchBarHelper.insertRestrictionInUrlbar(
|
||||
UrlbarTokenizer.RESTRICT.BOOKMARK
|
||||
),
|
||||
},
|
||||
History: {
|
||||
title: "search-history",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () =>
|
||||
gTouchBarHelper.insertRestrictionInUrlbar(
|
||||
UrlbarTokenizer.RESTRICT.HISTORY
|
||||
),
|
||||
},
|
||||
OpenTabs: {
|
||||
title: "search-opentabs",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () =>
|
||||
gTouchBarHelper.insertRestrictionInUrlbar(
|
||||
UrlbarTokenizer.RESTRICT.OPENPAGE
|
||||
),
|
||||
},
|
||||
Tags: {
|
||||
title: "search-tags",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () =>
|
||||
gTouchBarHelper.insertRestrictionInUrlbar(
|
||||
UrlbarTokenizer.RESTRICT.TAG
|
||||
),
|
||||
},
|
||||
Titles: {
|
||||
title: "search-titles",
|
||||
type: kInputTypes.BUTTON,
|
||||
callback: () =>
|
||||
gTouchBarHelper.insertRestrictionInUrlbar(
|
||||
UrlbarTokenizer.RESTRICT.TITLE
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
At the top level, a Popover is defined. This allows a collection of children
|
||||
to be shown in a separate Touch Bar. The Popover has two children: a Label,
|
||||
and a Scroll View. The Scroll View displays five similar buttons that call a
|
||||
helper method to insert search shortcut symbols into the address bar.
|
||||
|
||||
Adding a new input
|
||||
------------------
|
||||
Adding a new input is easy: just add a new object to ``kBuiltInInputs``. 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``.
|
||||
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
|
||||
|
||||
If you are interested in adding new features to Firefox's implementation of the
|
||||
Touch Bar API, read on!
|
||||
|
||||
|
||||
Cocoa API
|
||||
~~~~~~~~~
|
||||
Firefox implements Apple's Touch Bar API in its Widget: Cocoa code with an
|
||||
``nsTouchBar`` class. ``nsTouchBar`` interfaces between Apple's Touch Bar API
|
||||
and the ``TouchBarHelper`` JavaScript API.
|
||||
|
||||
The best resource to understand the Touch Bar API is Apple's
|
||||
`official documentation`_. This documentation will cover how Firefox implements
|
||||
these APIs and how one might extend ``nsTouchBar`` to enable new Touch Bar
|
||||
features.
|
||||
|
||||
Every new Firefox window initializes ``nsTouchBar`` (link_). The function
|
||||
``makeTouchBar`` is looked for automatically on every new instance of an
|
||||
``NSWindow*``. If ``makeTouchBar`` is defined, that window will own a new
|
||||
instance of ``nsTouchBar``.
|
||||
|
||||
At the time of this writing, every window initializes ``nsTouchBar`` with a
|
||||
default set of inputs. In the future, Firefox windows other than the main
|
||||
browser window (such as the Library window or DevTools) may initialize
|
||||
``nsTouchBar`` with a different set of inputs.
|
||||
|
||||
``nsTouchBar`` has two different initialization methods: ``init`` and
|
||||
``initWithInputs``. The former is a convenience method for the latter, calling
|
||||
``initWithInputs`` with a nil argument. When that happens, a Touch Bar is
|
||||
created containing a default set of inputs. ``initWithInputs`` can also take an
|
||||
``NSArray<TouchBarInput*>*``. In that case, a non-customizable Touch Bar will be
|
||||
initialized with only those inputs available.
|
||||
|
||||
.. _official documentation: https://developer.apple.com/documentation/appkit/nstouchbar?language=objc
|
||||
.. _link: https://searchfox.org/mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c/widget/cocoa/nsCocoaWindow.mm#2877
|
||||
|
||||
NSTouchBarItemIdentifiers
|
||||
-------------------------
|
||||
The architecture of the Touch Bar is based largely around an ``NSString*``
|
||||
wrapper class called ``NSTouchBarItemIdentifier``. Every input in the Touch Bar
|
||||
has a unique ``NSTouchBarItemIdentifier``. They are structured in reverse-URI
|
||||
format like so:
|
||||
|
||||
``com.mozilla.firefox.touchbar.[TYPE].[KEY]``
|
||||
|
||||
[TYPE] is a string indicating the type of the input, e.g. "button". If an
|
||||
input is a child of another input, the parent's type is prepended to the child's
|
||||
type, e.g. "scrubber.button" indicates a button contained in a scrubber.
|
||||
|
||||
[KEY] is the ``title`` attribute defined for that input on the JS side.
|
||||
|
||||
If you need to generate an identifier, use the convenience method
|
||||
``[TouchBarInput nativeIdentifierWithType:withKey:]``.
|
||||
|
||||
.. caution::
|
||||
|
||||
Do not create a new input that would have the same identifier as any other
|
||||
input. All identifiers must be unique.
|
||||
|
||||
.. warning::
|
||||
|
||||
``NSTouchBarItemIdentifier`` `is used in one other place`_: setting
|
||||
``customizationIdentifier``. Do not ever change this string. If it is changed,
|
||||
any customizations users have made to the layout of their Touch Bar in Firefox
|
||||
will be erased.
|
||||
|
||||
Each identifier is tied to a ``TouchBarInput``. ``TouchBarInput`` is a class
|
||||
that holds the properties specified for each input in ``kBuiltInInputs``.
|
||||
``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
|
||||
``TouchBarInput`` and ``NSTouchBarItem``!
|
||||
|
||||
.. _is used in one other place: https://searchfox.org/mozilla-central/rev/ebe492edacc75bb122a2b380e4cafcca3470864c/widget/cocoa/nsTouchBar.mm#71
|
||||
|
||||
TouchBarInput creation flow
|
||||
---------------------------
|
||||
Creating a Touch Bar and its ``TouchBarInputs`` flows as follows:
|
||||
|
||||
#. ``[nsTouchBar init]`` is called from ``[NSWindow makeTouchBar]``.
|
||||
|
||||
#. ``init`` populates two NSArrays: ``customizationAllowedItemIdentifiers`` and
|
||||
``defaultItemIdentifiers``. It also initializes a ``TouchBarInput`` object
|
||||
for every element in the union of the two arrays and stores them in
|
||||
``NSMutableDictionary<NSTouchBarItemIdentifier, TouchBarInput*>* mappedLayoutItems``.
|
||||
|
||||
#. ``touchBar:makeItemForIdentifier:`` is called for every element in the union
|
||||
of the two arrays of identifiers. This method retrieves the ``TouchBarInput``
|
||||
for the given identifier and uses it to initialize a ``NSTouchBarItem``.
|
||||
``touchBar:makeItemForIdentifier:`` reads the ``type`` attribute from the
|
||||
``TouchBarInput`` to determine what ``NSTouchBarItem`` subclass should be
|
||||
initialized. Our Touch Bar code currently supports ``NSCustomTouchBarItem``
|
||||
(buttons, main buttons); ``NSPopoverTouchBarItem`` (popovers);
|
||||
``NSTextField`` (labels); and ``NSScrollView`` (ScrollViews).
|
||||
|
||||
#. Once the ``NSTouchBarItem`` is initialized, its properties are populated with
|
||||
an assortment of "update" methods. These include ``updateButton``,
|
||||
``updateMainButton``, ``updateLabel``, ``updatePopover``, and
|
||||
``updateScrollView``.
|
||||
|
||||
#. Since the localization of ``TouchBarInput`` titles happens asynchronously in
|
||||
JavaScript code, the l10n callback executes
|
||||
``[nsTouchBarUpdater updateTouchBarInputs:]``. This method reads the
|
||||
identifier of the input(s) that need to be updated and calls their respective
|
||||
"update" methods. This method is most often used to update ``title`` after
|
||||
l10n is complete. It can also be used to update any property of a
|
||||
``TouchBarInput``; for instance, one might wish to change ``color``
|
||||
when a specific event occurs in the browser.
|
|
@ -11,3 +11,5 @@ EXTRA_COMPONENTS += [
|
|||
'MacTouchBar.js',
|
||||
'MacTouchBar.manifest',
|
||||
]
|
||||
|
||||
SPHINX_TREES['/browser/touchbar'] = 'docs'
|
||||
|
|
|
@ -15,4 +15,5 @@ This is the nascent documentation of the Firefox front-end code.
|
|||
installer/windows/installer/index
|
||||
base/sslerrorreport/index
|
||||
base/tabbrowser/index
|
||||
touchbar/index
|
||||
components/payments/docs/index
|
||||
|
|
Загрузка…
Ссылка в новой задаче