зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1531311 - [devtools] Add more visibility for node picker when debugging remote pages. r=jdescottes,devtools-backward-compat-reviewers.
This patch does a couple things to tell users they can use the node picker when debugging a remote page: - changes the node picker button icon (arrow -> hand) when connected to an android phone, as well as its tooltip - adds a notice in the content page (i.e. on the phone) when the picker starts Differential Revision: https://phabricator.services.mozilla.com/D132705
This commit is contained in:
Родитель
5c71755e40
Коммит
ab7531ceed
|
@ -167,6 +167,7 @@ function connectRuntime(id) {
|
|||
info: {
|
||||
deviceName: deviceDescription.deviceName,
|
||||
icon,
|
||||
isFenix: runtime.isFenix,
|
||||
name: runtimeName,
|
||||
os: deviceDescription.os,
|
||||
type: runtime.type,
|
||||
|
|
|
@ -82,6 +82,7 @@ skip-if = ccov || (os == 'linux' && bits == 64) # Bug 1521349, Bug 1548015, Bug
|
|||
skip-if = debug || asan # This test leaks. See bug 1529005
|
||||
[browser_aboutdebugging_devtoolstoolbox_tooltip_markupview.js]
|
||||
[browser_aboutdebugging_fenix_runtime_display.js]
|
||||
[browser_aboutdebugging_fenix_runtime_node_picker.js]
|
||||
[browser_aboutdebugging_message_close.js]
|
||||
[browser_aboutdebugging_navigate.js]
|
||||
[browser_aboutdebugging_persist_connection.js]
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const RUNTIME_ID = "1337id";
|
||||
const DEVICE_NAME = "Fancy Phone";
|
||||
const SERVER_RUNTIME_NAME = "Mozilla Firefox";
|
||||
const ADB_RUNTIME_NAME = "Firefox Preview";
|
||||
const SERVER_VERSION = "v7.3.31";
|
||||
const ADB_VERSION = "v1.3.37";
|
||||
|
||||
/**
|
||||
* Check that the node picker button in about:devtools-toolbox has the expected class when
|
||||
* connecting to an Android phone.
|
||||
*/
|
||||
add_task(async function() {
|
||||
// We use a real local client combined with a mocked USB runtime to be able to open
|
||||
// about:devtools-toolbox on a real target.
|
||||
const clientWrapper = await createLocalClientWrapper();
|
||||
|
||||
const mocks = new Mocks();
|
||||
mocks.createUSBRuntime(RUNTIME_ID, {
|
||||
channel: "nightly",
|
||||
clientWrapper: clientWrapper,
|
||||
deviceName: DEVICE_NAME,
|
||||
isFenix: true,
|
||||
name: SERVER_RUNTIME_NAME,
|
||||
shortName: ADB_RUNTIME_NAME,
|
||||
versionName: ADB_VERSION,
|
||||
version: SERVER_VERSION,
|
||||
});
|
||||
|
||||
// open a remote runtime page
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
await selectThisFirefoxPage(document, window.AboutDebugging.store);
|
||||
|
||||
mocks.emitUSBUpdate();
|
||||
info("Select the runtime page for the USB runtime");
|
||||
const onRequestSuccess = waitForRequestsSuccess(window.AboutDebugging.store);
|
||||
await connectToRuntime(DEVICE_NAME, document);
|
||||
await selectRuntime(DEVICE_NAME, ADB_RUNTIME_NAME, document);
|
||||
info(
|
||||
"Wait for requests to finish the USB runtime is backed by a real local client"
|
||||
);
|
||||
await onRequestSuccess;
|
||||
|
||||
info("Wait for the about:debugging target to be available");
|
||||
await waitUntil(() => findDebugTargetByText("about:debugging", document));
|
||||
const { devtoolsDocument, devtoolsTab } = await openAboutDevtoolsToolbox(
|
||||
document,
|
||||
tab,
|
||||
window
|
||||
);
|
||||
|
||||
const pickerButton = devtoolsDocument.querySelector("#command-button-pick");
|
||||
ok(
|
||||
pickerButton.classList.contains("remote-fenix"),
|
||||
"The node picker does have the expected additional className when debugging an android phone"
|
||||
);
|
||||
const pickerButtonTitle = pickerButton.getAttribute("title");
|
||||
const expectedKeyboardShortcut =
|
||||
Services.appinfo.OS === "Darwin"
|
||||
? `Cmd+Shift+C or Cmd+Opt+C`
|
||||
: `Ctrl+Shift+C`;
|
||||
is(
|
||||
pickerButtonTitle,
|
||||
`Pick an element from the Android phone (${expectedKeyboardShortcut})`,
|
||||
`The node picker does have the expected tooltip when debugging an android phone`
|
||||
);
|
||||
|
||||
info("Wait for all pending requests to settle on the DevToolsClient");
|
||||
await clientWrapper.client.waitForRequestsToSettle();
|
||||
await closeAboutDevtoolsToolbox(document, devtoolsTab, window);
|
||||
|
||||
info("Remove USB runtime");
|
||||
mocks.removeUSBRuntime(RUNTIME_ID);
|
||||
mocks.emitUSBUpdate();
|
||||
await waitUntilUsbDeviceIsUnplugged(DEVICE_NAME, document);
|
||||
|
||||
await removeTab(tab);
|
||||
await clientWrapper.close();
|
||||
});
|
|
@ -1350,6 +1350,10 @@ Toolbox.prototype = {
|
|||
};
|
||||
},
|
||||
|
||||
_isDebugTargetFenix() {
|
||||
return this._getDebugTargetData()?.runtimeInfo?.isFenix;
|
||||
},
|
||||
|
||||
/**
|
||||
* loading React modules when needed (to avoid performance penalties
|
||||
* during Firefox start up time).
|
||||
|
@ -2152,6 +2156,7 @@ Toolbox.prototype = {
|
|||
_buildPickerButton() {
|
||||
this.pickerButton = this._createButtonState({
|
||||
id: "command-button-pick",
|
||||
className: this._getPickerAdditionalClassName(),
|
||||
description: this._getPickerTooltip(),
|
||||
onClick: this._onPickerClick,
|
||||
isInStartContainer: true,
|
||||
|
@ -2163,6 +2168,13 @@ Toolbox.prototype = {
|
|||
return this.pickerButton;
|
||||
},
|
||||
|
||||
_getPickerAdditionalClassName() {
|
||||
if (this._isDebugTargetFenix()) {
|
||||
return "remote-fenix";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the tooltip for the element picker button.
|
||||
* It has multiple possible keyboard shortcuts for macOS.
|
||||
|
@ -2175,9 +2187,17 @@ Toolbox.prototype = {
|
|||
shortcut = KeyShortcuts.stringify(shortcut);
|
||||
const shortcutMac = L10N.getStr("toolbox.elementPicker.mac.key");
|
||||
const isMac = Services.appinfo.OS === "Darwin";
|
||||
const label = isMac
|
||||
? "toolbox.elementPicker.mac.tooltip"
|
||||
: "toolbox.elementPicker.tooltip";
|
||||
|
||||
let label;
|
||||
if (this._isDebugTargetFenix()) {
|
||||
label = isMac
|
||||
? "toolbox.androidElementPicker.mac.tooltip"
|
||||
: "toolbox.androidElementPicker.tooltip";
|
||||
} else {
|
||||
label = isMac
|
||||
? "toolbox.elementPicker.mac.tooltip"
|
||||
: "toolbox.elementPicker.tooltip";
|
||||
}
|
||||
|
||||
return isMac
|
||||
? L10N.getFormatStr(label, shortcut, shortcutMac)
|
||||
|
@ -2274,7 +2294,7 @@ Toolbox.prototype = {
|
|||
// If the current panel doesn't define a custom updatePickerButton,
|
||||
// revert the button to its default state
|
||||
button.description = this._getPickerTooltip();
|
||||
button.className = null;
|
||||
button.className = this._getPickerAdditionalClassName();
|
||||
button.disabled = null;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -418,7 +418,11 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
|
|||
}
|
||||
|
||||
this._isPicking = true;
|
||||
return super.pick(doFocus);
|
||||
|
||||
return super.pick(
|
||||
doFocus,
|
||||
this.targetFront.commands.descriptorFront.isLocalTab
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -177,7 +177,6 @@ devtools.jar:
|
|||
skin/rules.css (themes/rules.css)
|
||||
skin/images/command-screenshot.svg (themes/images/command-screenshot.svg)
|
||||
skin/images/command-responsivemode.svg (themes/images/command-responsivemode.svg)
|
||||
skin/images/command-pick.svg (themes/images/command-pick.svg)
|
||||
skin/images/command-pick-accessibility.svg (themes/images/command-pick-accessibility.svg)
|
||||
skin/images/command-frames.svg (themes/images/command-frames.svg)
|
||||
skin/images/command-console.svg (themes/images/command-console.svg)
|
||||
|
|
|
@ -47,6 +47,18 @@ toolbox.elementPicker.tooltip=Pick an element from the page (%S)
|
|||
# shortcuts: Cmd+Shift+C or Cmd+Opt+C
|
||||
toolbox.elementPicker.mac.tooltip=Pick an element from the page (%1$S or %2$S)
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.androidElementPicker.tooltip)
|
||||
# This is the tooltip of the element picker button in the about:devtools-toolbox toolbox toolbar
|
||||
# when debugging an Android device
|
||||
# %S is the keyboard shortcut that toggles the element picker.
|
||||
toolbox.androidElementPicker.tooltip=Pick an element from the Android phone (%S)
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.androidElementPicker.mac.tooltip)
|
||||
# Like toolbox.androidElementPicker.tooltip, but for macOS as there are two possible keyboard
|
||||
# shortcuts (Cmd+Shift+C or Cmd+Opt+C)
|
||||
# %1$S and %2$S are the keyboard shortcuts that toggle the element picker.
|
||||
toolbox.androidElementPicker.mac.tooltip=Pick an element from the Android phone (%1$S or %2$S)
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.elementPicker.key)
|
||||
# Key shortcut used to toggle the element picker.
|
||||
toolbox.elementPicker.key=CmdOrCtrl+Shift+C
|
||||
|
|
|
@ -746,5 +746,5 @@ select.playback-rate-selector.devtools-button:not(:empty, :disabled, .checked):h
|
|||
}
|
||||
|
||||
.animation-element-picker::before {
|
||||
background-image: url("chrome://devtools/skin/images/command-pick.svg");
|
||||
background-image: url("chrome://devtools/content/shared/images/command-pick.svg");
|
||||
}
|
||||
|
|
|
@ -409,13 +409,17 @@
|
|||
}
|
||||
|
||||
#command-button-pick::before {
|
||||
background-image: url("chrome://devtools/skin/images/command-pick.svg");
|
||||
background-image: url("chrome://devtools/content/shared/images/command-pick.svg");
|
||||
}
|
||||
|
||||
#command-button-pick.accessibility::before {
|
||||
background-image: url("chrome://devtools/skin/images/command-pick-accessibility.svg");
|
||||
}
|
||||
|
||||
#command-button-pick.remote-fenix::before {
|
||||
background-image: url("chrome://devtools/content/shared/images/command-pick-remote-touch.svg");
|
||||
}
|
||||
|
||||
/* Command button images */
|
||||
|
||||
#command-button-screenshot::before {
|
||||
|
|
|
@ -754,6 +754,95 @@
|
|||
font-size: var(--highlighter-font-size);
|
||||
}
|
||||
|
||||
|
||||
/* Remote Node Picker Notice Highlighter */
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-root {
|
||||
position: fixed;
|
||||
max-width: 100vw;
|
||||
/* Position at the bottom of the screen so it doesn't get into the user's way */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
zoom: 1;
|
||||
|
||||
z-index: 2;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
/* We don't have access to DevTools themes here, but some of these colors come from the
|
||||
themes. Theme variable names are given in comments. */
|
||||
--text-color: #585959; /* --theme-body-color-alt */
|
||||
--toolbar-background: #fcfcfc; /* --theme-toolbar-background */
|
||||
--toolbar-border: #dde1e4; /* --theme-splitter-color */
|
||||
--toolbar-button-hover-background: rgba(12, 12, 13, 0.15); /* --theme-toolbarbutton-hover-background */
|
||||
--toolbar-box-shadow: 0 2px 2px 0 rgba(155, 155, 155, 0.26); /* --rdm-box-shadow */
|
||||
}
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-root[overlay] {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
padding: 8px 16px;
|
||||
font-size: 24px;
|
||||
|
||||
color: var(--text-color);
|
||||
box-shadow: var(--toolbar-box-shadow);
|
||||
background-color: var(--toolbar-background);
|
||||
border: 1px solid var(--toolbar-border);
|
||||
border-radius: 2px;
|
||||
|
||||
font: var(--highlighter-font-family);
|
||||
font-size: var(--highlighter-font-size);
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-info {
|
||||
font: var(--highlighter-font-family);
|
||||
font-size: var(--highlighter-font-size);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
background-image: url(chrome://devtools/content/shared/images/command-pick.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-icon.touch {
|
||||
background-image: url(chrome://devtools/content/shared/images/command-pick-remote-touch.svg);
|
||||
}
|
||||
|
||||
|
||||
:-moz-native-anonymous #node-picker-notice-hide-button {
|
||||
border: 0px;
|
||||
border-radius: 2px;
|
||||
appearance: none;
|
||||
background-color: var(--toolbar-border);
|
||||
color: currentColor;
|
||||
font-size: 1em;
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
/* We can't use :hover as it wouldn't work if the page is paused, so we add a specific class for this */
|
||||
:-moz-native-anonymous #node-picker-notice-hide-button.hover {
|
||||
background-color: var(--toolbar-button-hover-background);
|
||||
}
|
||||
|
||||
/* Shapes highlighter */
|
||||
|
||||
:-moz-native-anonymous .shapes-root {
|
||||
|
|
|
@ -21,6 +21,7 @@ DevToolsModules(
|
|||
"measuring-tool.js",
|
||||
"node-tabbing-order.js",
|
||||
"paused-debugger.js",
|
||||
"remote-node-picker-notice.js",
|
||||
"rulers.js",
|
||||
"selector.js",
|
||||
"shapes.js",
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/* 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";
|
||||
|
||||
const {
|
||||
CanvasFrameAnonymousContentHelper,
|
||||
} = require("devtools/server/actors/highlighters/utils/markup");
|
||||
|
||||
loader.lazyGetter(this, "L10N", () => {
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const STRINGS_URI = "devtools/shared/locales/highlighters.properties";
|
||||
return new LocalizationHelper(STRINGS_URI);
|
||||
});
|
||||
loader.lazyGetter(this, "isAndroid", () => {
|
||||
const Services = require("Services");
|
||||
return Services.appinfo.OS === "Android";
|
||||
});
|
||||
|
||||
/**
|
||||
* The RemoteNodePickerNotice is a class that displays a notice in a remote debugged page.
|
||||
* This is used to signal to users they can click/tap an element to select it in the
|
||||
* about:devtools-toolbox toolbox inspector.
|
||||
*/
|
||||
class RemoteNodePickerNotice {
|
||||
#highlighterEnvironment;
|
||||
#previousHoveredElement;
|
||||
|
||||
rootElementId = "node-picker-notice-root";
|
||||
hideButtonId = "node-picker-notice-hide-button";
|
||||
infoNoticeElementId = "node-picker-notice-info";
|
||||
|
||||
/**
|
||||
* @param {highlighterEnvironment} highlighterEnvironment
|
||||
*/
|
||||
constructor(highlighterEnvironment) {
|
||||
this.#highlighterEnvironment = highlighterEnvironment;
|
||||
|
||||
this.markup = new CanvasFrameAnonymousContentHelper(
|
||||
this.#highlighterEnvironment,
|
||||
this.#buildMarkup
|
||||
);
|
||||
this.isReady = this.markup.initialize();
|
||||
}
|
||||
|
||||
#buildMarkup = () => {
|
||||
const container = this.markup.createNode({
|
||||
attributes: { class: "highlighter-container" },
|
||||
});
|
||||
|
||||
// Wrapper element.
|
||||
const wrapper = this.markup.createNode({
|
||||
parent: container,
|
||||
attributes: {
|
||||
id: this.rootElementId,
|
||||
hidden: "true",
|
||||
overlay: "true",
|
||||
},
|
||||
});
|
||||
|
||||
const toolbar = this.markup.createNode({
|
||||
parent: wrapper,
|
||||
attributes: {
|
||||
id: "node-picker-notice-toolbar",
|
||||
class: "toolbar",
|
||||
},
|
||||
});
|
||||
|
||||
this.markup.createNode({
|
||||
parent: toolbar,
|
||||
attributes: {
|
||||
id: "node-picker-notice-icon",
|
||||
class: isAndroid ? "touch" : "",
|
||||
},
|
||||
});
|
||||
|
||||
const actionStr = L10N.getStr(
|
||||
isAndroid
|
||||
? "remote-node-picker-notice-action-touch"
|
||||
: "remote-node-picker-notice-action-desktop"
|
||||
);
|
||||
|
||||
this.markup.createNode({
|
||||
nodeType: "span",
|
||||
parent: toolbar,
|
||||
text: L10N.getFormatStr("remote-node-picker-notice", actionStr),
|
||||
attributes: {
|
||||
id: this.infoNoticeElementId,
|
||||
},
|
||||
});
|
||||
|
||||
this.markup.createNode({
|
||||
nodeType: "button",
|
||||
parent: toolbar,
|
||||
text: L10N.getStr("remote-node-picker-notice-hide-button"),
|
||||
attributes: {
|
||||
id: this.hideButtonId,
|
||||
},
|
||||
});
|
||||
|
||||
return container;
|
||||
};
|
||||
|
||||
destroy() {
|
||||
// hide will nullify take care of this.#abortController.
|
||||
this.hide();
|
||||
this.markup.destroy();
|
||||
this.#highlighterEnvironment = null;
|
||||
this.#previousHoveredElement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* We can't use event listener directly on the anonymous content because they aren't
|
||||
* working while the page is paused.
|
||||
* This is called from the NodePicker instance for easier events management.
|
||||
*
|
||||
* @param {ClickEvent}
|
||||
*/
|
||||
onClick(e) {
|
||||
const target = e.originalTarget || e.target;
|
||||
const targetId = target?.id;
|
||||
|
||||
if (targetId === this.hideButtonId) {
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we can't use :hover in the CSS for the anonymous content as it wouldn't work
|
||||
* when the page is paused, we have to roll our own implementation, adding a `.hover`
|
||||
* class for the element we want to style on hover (e.g. the close button).
|
||||
* This is called from the NodePicker instance for easier events management.
|
||||
*
|
||||
* @param {MouseMoveEvent}
|
||||
*/
|
||||
handleHoveredElement(e) {
|
||||
const hideButton = this.markup.getElement(this.hideButtonId);
|
||||
|
||||
const target = e.originalTarget || e.target;
|
||||
const targetId = target?.id;
|
||||
|
||||
// If the user didn't change targets, do nothing
|
||||
if (this.#previousHoveredElement?.id === targetId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetId === this.hideButtonId) {
|
||||
hideButton.classList.add("hover");
|
||||
} else {
|
||||
hideButton.classList.remove("hover");
|
||||
}
|
||||
this.#previousHoveredElement = target;
|
||||
}
|
||||
|
||||
getMarkupRootElement() {
|
||||
return this.markup.getElement(this.rootElementId);
|
||||
}
|
||||
|
||||
async show() {
|
||||
if (this.#highlighterEnvironment.isXUL) {
|
||||
return false;
|
||||
}
|
||||
await this.isReady;
|
||||
|
||||
// Show the highlighter's root element.
|
||||
const root = this.getMarkupRootElement();
|
||||
root.removeAttribute("hidden");
|
||||
root.setAttribute("overlay", "true");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hide() {
|
||||
if (this.#highlighterEnvironment.isXUL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide the overlay.
|
||||
this.getMarkupRootElement().setAttribute("hidden", "true");
|
||||
// Reset the hover state
|
||||
this.markup.getElement(this.hideButtonId).classList.remove("hover");
|
||||
this.#previousHoveredElement = null;
|
||||
}
|
||||
}
|
||||
exports.RemoteNodePickerNotice = RemoteNodePickerNotice;
|
|
@ -12,11 +12,24 @@ loader.lazyRequireGetter(
|
|||
"devtools/shared/layout/utils",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"HighlighterEnvironment",
|
||||
"devtools/server/actors/highlighters",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"RemoteNodePickerNotice",
|
||||
"devtools/server/actors/highlighters/remote-node-picker-notice.js",
|
||||
true
|
||||
);
|
||||
|
||||
const IS_OSX = Services.appinfo.OS === "Darwin";
|
||||
|
||||
class NodePicker {
|
||||
#eventListenersAbortController;
|
||||
#remoteNodePickerNoticeHighlighter;
|
||||
|
||||
constructor(walker, targetActor) {
|
||||
this._walker = walker;
|
||||
|
@ -33,6 +46,16 @@ class NodePicker {
|
|||
this._preventContentEvent = this._preventContentEvent.bind(this);
|
||||
}
|
||||
|
||||
get remoteNodePickerNoticeHighlighter() {
|
||||
if (!this.#remoteNodePickerNoticeHighlighter) {
|
||||
const env = new HighlighterEnvironment();
|
||||
env.initFromTargetActor(this._targetActor);
|
||||
this.#remoteNodePickerNoticeHighlighter = new RemoteNodePickerNotice(env);
|
||||
}
|
||||
|
||||
return this.#remoteNodePickerNoticeHighlighter;
|
||||
}
|
||||
|
||||
_findAndAttachElement(event) {
|
||||
// originalTarget allows access to the "real" element before any retargeting
|
||||
// is applied, such as in the case of XBL anonymous elements. See also
|
||||
|
@ -60,6 +83,21 @@ class NodePicker {
|
|||
return this._targetActor.windows.includes(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the passed event original target is in the RemoteNodePickerNotice.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
_isEventInRemoteNodePickerNotice(event) {
|
||||
return (
|
||||
this.#remoteNodePickerNoticeHighlighter &&
|
||||
event.originalTarget?.closest?.(
|
||||
`#${this.#remoteNodePickerNoticeHighlighter.rootElementId}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick a node on click.
|
||||
*
|
||||
|
@ -82,6 +120,15 @@ class NodePicker {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the click was done inside the node picker notice highlighter (e.g. clicking the
|
||||
// close button), directly call its `onClick` method, as it doesn't have event listeners
|
||||
// itself, to avoid managing events (+ suppressedEventListeners) for the same target
|
||||
// from different places.
|
||||
if (this._isEventInRemoteNodePickerNotice(event)) {
|
||||
this.#remoteNodePickerNoticeHighlighter.onClick(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// If Shift is pressed, this is only a preview click.
|
||||
// Send the event to the client, but don't stop picking.
|
||||
if (event.shiftKey) {
|
||||
|
@ -94,6 +141,10 @@ class NodePicker {
|
|||
|
||||
this._stopPickerListeners();
|
||||
this._isPicking = false;
|
||||
if (this.#remoteNodePickerNoticeHighlighter) {
|
||||
this.#remoteNodePickerNoticeHighlighter.hide();
|
||||
}
|
||||
|
||||
if (!this._currentNode) {
|
||||
this._currentNode = this._findAndAttachElement(event);
|
||||
}
|
||||
|
@ -113,6 +164,16 @@ class NodePicker {
|
|||
return;
|
||||
}
|
||||
|
||||
// Always call remoteNodePickerNotice handleHoveredElement so the hover state can be updated
|
||||
// (it doesn't have its own event listeners to avoid managing events and suppressed
|
||||
// events for the same target from different places).
|
||||
if (this.#remoteNodePickerNoticeHighlighter) {
|
||||
this.#remoteNodePickerNoticeHighlighter.handleHoveredElement(event);
|
||||
if (this._isEventInRemoteNodePickerNotice(event)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._currentNode = this._findAndAttachElement(event);
|
||||
if (this._hoveredNode !== this._currentNode.node) {
|
||||
this._walker.emit("picker-node-hovered", this._currentNode);
|
||||
|
@ -278,10 +339,13 @@ class NodePicker {
|
|||
this._stopPickerListeners();
|
||||
this._isPicking = false;
|
||||
this._hoveredNode = null;
|
||||
if (this.#remoteNodePickerNoticeHighlighter) {
|
||||
this.#remoteNodePickerNoticeHighlighter.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pick(doFocus = false) {
|
||||
pick(doFocus = false, isLocalTab = true) {
|
||||
if (this._targetActor.threadActor) {
|
||||
this._targetActor.threadActor.hideOverlay();
|
||||
}
|
||||
|
@ -296,6 +360,10 @@ class NodePicker {
|
|||
if (doFocus) {
|
||||
this._targetActor.window.focus();
|
||||
}
|
||||
|
||||
if (!isLocalTab) {
|
||||
this.remoteNodePickerNoticeHighlighter.show();
|
||||
}
|
||||
}
|
||||
|
||||
resetHoveredNodeReference() {
|
||||
|
@ -307,6 +375,7 @@ class NodePicker {
|
|||
|
||||
this._targetActor = null;
|
||||
this._walker = null;
|
||||
this.#remoteNodePickerNoticeHighlighter = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2785,8 +2785,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
return this.attachElement(rawNode);
|
||||
},
|
||||
|
||||
pick(doFocus) {
|
||||
this.nodePicker.pick(doFocus);
|
||||
pick(doFocus, isLocalTab) {
|
||||
this.nodePicker.pick(doFocus, isLocalTab);
|
||||
},
|
||||
|
||||
cancelPick() {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!-- 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" width="16" height="16" viewBox="0 0 16 16" fill="context-fill #0c0c0d">
|
||||
<path d="M3 3C2.73478 3 2.48043 3.10536 2.29289 3.29289C2.10536 3.48043 2 3.73478 2 4V12C2 12.2652 2.10536 12.5196 2.29289 12.7071C2.48043 12.8946 2.73478 13 3 13H5.6C5.86522 13 6.11957 13.1054 6.30711 13.2929C6.49464 13.4804 6.6 13.7348 6.6 14C6.6 14.2652 6.49464 14.5196 6.30711 14.7071C6.11957 14.8946 5.86522 15 5.6 15H3C2.20435 15 1.44129 14.6839 0.87868 14.1213C0.31607 13.5587 0 12.7956 0 12L0 4C0 3.20435 0.31607 2.44129 0.87868 1.87868C1.44129 1.31607 2.20435 1 3 1H13C13.7956 1 14.5587 1.31607 15.1213 1.87868C15.6839 2.44129 16 3.20435 16 4V6.6C16 6.86522 15.8946 7.11957 15.7071 7.30711C15.5196 7.49464 15.2652 7.6 15 7.6C14.7348 7.6 14.4804 7.49464 14.2929 7.30711C14.1054 7.11957 14 6.86522 14 6.6V4C14 3.73478 13.8946 3.48043 13.7071 3.29289C13.5196 3.10536 13.2652 3 13 3H3Z"/>
|
||||
<path d="M6.21903 7.75153L8.79269 11.3027L8.06998 10.9489C7.83801 10.8352 7.58498 10.8171 7.36652 10.8986C7.14806 10.9802 6.98202 11.1547 6.90491 11.3838C6.89437 11.4162 6.89437 11.4162 6.88626 11.4487L6.87815 11.4812C6.81795 11.7203 6.84669 11.9866 6.95903 12.2306C7.07137 12.4746 7.25964 12.6797 7.48882 12.8077L10.835 14.6745C11.1195 14.8333 11.4293 14.9137 11.7316 14.9073C12.0338 14.9008 12.3171 14.8077 12.5514 14.6377L14.6502 13.1166C14.8085 12.9953 14.9194 12.8195 14.9677 12.6138C15.016 12.4081 14.9993 12.1825 14.9199 11.9683L13.4528 7.98781C13.4117 7.87533 13.3547 7.77158 13.2871 7.67829L13.2892 7.67678C13.175 7.51901 13.0271 7.38977 12.8603 7.30195C12.6935 7.21412 12.5136 7.17077 12.3386 7.17621C12.1635 7.18164 11.9993 7.23568 11.8624 7.33293C11.7254 7.43019 11.6205 7.56727 11.5581 7.73053C11.3101 7.61345 11.0416 7.59498 10.808 7.67893C10.5743 7.76288 10.3933 7.94286 10.302 8.18185C10.0829 8.07845 9.84692 8.05164 9.63258 8.10578C9.41824 8.15993 9.23818 8.29183 9.12174 8.47999L7.77602 6.62313C7.60248 6.38368 7.35403 6.21348 7.08533 6.14997C6.81662 6.08646 6.54967 6.13485 6.3432 6.28448C6.13673 6.43412 6.00765 6.67274 5.98437 6.94787C5.96108 7.22299 6.04549 7.51208 6.21903 7.75153Z"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 2.3 KiB |
До Ширина: | Высота: | Размер: 661 B После Ширина: | Высота: | Размер: 661 B |
|
@ -10,6 +10,10 @@ devtools.jar:
|
|||
# PausedDebuggerOverlay (which is in devtools/server).
|
||||
content/shared/images/resume.svg (images/resume.svg)
|
||||
content/shared/images/stepOver.svg (images/stepOver.svg)
|
||||
# These images are in devtools/shared (and not in devtools/client/themes/images/) because
|
||||
# they're also used in the RemoteNodePickerNotice (which is in devtools/server).
|
||||
content/shared/images/command-pick.svg (images/command-pick.svg)
|
||||
content/shared/images/command-pick-remote-touch.svg (images/command-pick-remote-touch.svg)
|
||||
% resource devtools %modules/devtools/
|
||||
% resource devtools-client-jsonview resource://devtools/client/jsonview/ contentaccessible=yes
|
||||
% resource devtools-client-shared resource://devtools/client/shared/ contentaccessible=yes
|
||||
|
|
|
@ -33,3 +33,22 @@ flexType.item=Flex Item
|
|||
# LOCALIZATION NOTE (flexType.dual): the layout type of an element shown in
|
||||
# the infobar when hovering over a DOM element and it is both a flex container and a flex item.
|
||||
flexType.dual=Flex Container/Item
|
||||
|
||||
# LOCALIZATION NOTE (remote-node-picker-notice): The message displayed in the content page
|
||||
# when the user clicks on the "Pick an element from the page" in about:devtools-toolbox
|
||||
# inspector panel, when debugging a remote page.
|
||||
# %S will either be remote-node-picker-notice-action-desktop or remote-node-picker-notice-action-touch
|
||||
remote-node-picker-notice=DevTools Node Picker enabled. %S
|
||||
|
||||
# LOCALIZATION NOTE (remote-node-picker-notice-action-desktop): Text displayed in
|
||||
# `remote-node-picker-notice`, when the remote page is on desktop
|
||||
remote-node-picker-notice-action-desktop=Click an element to select it in the Inspector
|
||||
|
||||
# LOCALIZATION NOTE (remote-node-picker-notice-action-touch): Text displayed in
|
||||
# `remote-node-picker-notice`, when the remote page is on Android
|
||||
remote-node-picker-notice-action-touch=Tap an element to select it in the Inspector
|
||||
|
||||
# LOCALIZATION NOTE (remote-node-picker-notice-hide-button): The text displayed in the button
|
||||
# that is in the notice in the content page when the user clicks on the "Pick an element from the page"
|
||||
# in about:devtools-toolbox inspector panel, when debugging a remote page.
|
||||
remote-node-picker-notice-hide-button=Hide
|
||||
|
|
|
@ -354,6 +354,7 @@ const walkerSpec = generateActorSpec({
|
|||
pick: {
|
||||
request: {
|
||||
doFocus: Arg(0, "nullable:boolean"),
|
||||
isLocalTab: Arg(1, "nullable:boolean"),
|
||||
},
|
||||
},
|
||||
cancelPick: {
|
||||
|
|
Загрузка…
Ссылка в новой задаче