mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1266450 - part6: migrate EventDetails tooltip;r=bgrins
For now this is a 1 to 1 migration of the existing Tooltip helper method from XUL to HTML. MozReview-Commit-ID: 9YiJLgibV9h --HG-- extra : rebase_source : af428055060a105d270d70b1e4694717e0869b2b extra : source : d03cca0c048c9ba1f3062519650e37ae986d4bc7
This commit is contained in:
parent
3615d9843b
commit
0f7dbc517b
@ -35,11 +35,10 @@ const {editableField, InplaceEditor} =
|
||||
const {HTMLEditor} = require("devtools/client/inspector/markup/html-editor");
|
||||
const promise = require("promise");
|
||||
const Services = require("Services");
|
||||
const {Tooltip} = require("devtools/client/shared/widgets/Tooltip");
|
||||
const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
|
||||
const {setImageTooltip, setBrokenImageTooltip} =
|
||||
require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
|
||||
|
||||
const {setEventTooltip} = require("devtools/client/shared/widgets/tooltip/EventTooltipHelper");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const {parseAttribute} =
|
||||
@ -174,7 +173,8 @@ MarkupView.prototype = {
|
||||
_selectedContainer: null,
|
||||
|
||||
_initTooltips: function () {
|
||||
this.eventDetailsTooltip = new Tooltip(this._inspector.panelDoc);
|
||||
this.eventDetailsTooltip = new HTMLTooltip(this._inspector.toolbox,
|
||||
{type: "arrow"});
|
||||
this.imagePreviewTooltip = new HTMLTooltip(this._inspector.toolbox,
|
||||
{type: "arrow"});
|
||||
this._enableImagePreviewTooltip();
|
||||
@ -2615,11 +2615,8 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, {
|
||||
tooltip.hide(target);
|
||||
|
||||
this.node.getEventListenerInfo().then(listenerInfo => {
|
||||
tooltip.setEventContent({
|
||||
eventListenerInfos: listenerInfo,
|
||||
toolbox: this.markup._inspector.toolbox
|
||||
});
|
||||
|
||||
let toolbox = this.markup._inspector.toolbox;
|
||||
setEventTooltip(tooltip, listenerInfo, toolbox);
|
||||
// Disable the image preview tooltip while we display the event details
|
||||
this.markup._disableImagePreviewTooltip();
|
||||
tooltip.once("hidden", () => {
|
||||
|
@ -43,7 +43,7 @@ add_task(function* () {
|
||||
yield tooltip.once("shown");
|
||||
info("EventTooltip visible.");
|
||||
|
||||
let container = tooltip.content;
|
||||
let container = tooltip.panel;
|
||||
let containerRect = container.getBoundingClientRect();
|
||||
let headers = container.querySelectorAll(".event-header");
|
||||
|
||||
|
@ -70,7 +70,7 @@ function* checkEventsForNode(test, inspector, testActor) {
|
||||
info("tooltip shown");
|
||||
|
||||
// Check values
|
||||
let headers = tooltip.content.querySelectorAll(".event-header");
|
||||
let headers = tooltip.panel.querySelectorAll(".event-header");
|
||||
let nodeFront = container.node;
|
||||
let cssSelector = nodeFront.nodeName + "#" + nodeFront.id;
|
||||
|
||||
@ -83,19 +83,22 @@ function* checkEventsForNode(test, inspector, testActor) {
|
||||
let attributes = header.querySelectorAll(".event-tooltip-attributes");
|
||||
let contentBox = header.nextElementSibling;
|
||||
|
||||
is(type.getAttribute("value"), expected[i].type,
|
||||
is(type.textContent, expected[i].type,
|
||||
"type matches for " + cssSelector);
|
||||
is(filename.getAttribute("value"), expected[i].filename,
|
||||
is(filename.textContent, expected[i].filename,
|
||||
"filename matches for " + cssSelector);
|
||||
|
||||
is(attributes.length, expected[i].attributes.length,
|
||||
"we have the correct number of attributes");
|
||||
|
||||
for (let j = 0; j < expected[i].attributes.length; j++) {
|
||||
is(attributes[j].getAttribute("value"), expected[i].attributes[j],
|
||||
is(attributes[j].textContent, expected[i].attributes[j],
|
||||
"attribute[" + j + "] matches for " + cssSelector);
|
||||
}
|
||||
|
||||
// Make sure the header is not hidden by scrollbars before clicking.
|
||||
header.scrollIntoView();
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(header, {}, type.ownerGlobal);
|
||||
yield tooltip.once("event-tooltip-ready");
|
||||
|
||||
|
@ -110,14 +110,15 @@ HTMLTooltip.prototype = {
|
||||
* The tooltip content, should be a HTML element.
|
||||
* @param {Number} width
|
||||
* Preferred width for the tooltip container
|
||||
* @param {Number} height
|
||||
* @param {Number} height (optional)
|
||||
* Preferred height for the tooltip container. If the content height is
|
||||
* smaller than the container's height, the tooltip will automatically
|
||||
* shrink around the content.
|
||||
* shrink around the content. If not specified, will use all the height
|
||||
* available.
|
||||
* @return {Promise} a promise that will resolve when the content has been
|
||||
* added in the tooltip container.
|
||||
*/
|
||||
setContent: function (content, width, height) {
|
||||
setContent: function (content, width, height = Infinity) {
|
||||
let themeHeight = EXTRA_HEIGHT[this.type] + 2 * EXTRA_BORDER[this.type];
|
||||
let themeWidth = 2 * EXTRA_BORDER[this.type];
|
||||
|
||||
|
@ -16,7 +16,6 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {colorUtils} = require("devtools/client/shared/css-color");
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const {Eyedropper} = require("devtools/client/eyedropper/eyedropper");
|
||||
const Editor = require("devtools/client/sourceeditor/editor");
|
||||
const Services = require("Services");
|
||||
|
||||
loader.lazyRequireGetter(this, "beautify", "devtools/shared/jsbeautify/beautify");
|
||||
@ -434,19 +433,6 @@ Tooltip.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets some event listener info as the content of this tooltip.
|
||||
*
|
||||
* @param {Object} (destructuring assignment)
|
||||
* @0 {array} eventListenerInfos
|
||||
* A list of event listeners.
|
||||
* @1 {toolbox} toolbox
|
||||
* Toolbox used to select debugger panel.
|
||||
*/
|
||||
setEventContent: function ({ eventListenerInfos, toolbox }) {
|
||||
new EventTooltip(this, eventListenerInfos, toolbox);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fill the tooltip with a variables view, inspecting an object via its
|
||||
* corresponding object actor, as specified in the remote debugging protocol.
|
||||
@ -1066,298 +1052,6 @@ Heritage.extend(SwatchBasedEditorTooltip.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
function EventTooltip(tooltip, eventListenerInfos, toolbox) {
|
||||
this._tooltip = tooltip;
|
||||
this._eventListenerInfos = eventListenerInfos;
|
||||
this._toolbox = toolbox;
|
||||
this._tooltip.eventEditors = new WeakMap();
|
||||
|
||||
this._headerClicked = this._headerClicked.bind(this);
|
||||
this._debugClicked = this._debugClicked.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
EventTooltip.prototype = {
|
||||
_init: function () {
|
||||
let config = {
|
||||
mode: Editor.modes.js,
|
||||
lineNumbers: false,
|
||||
lineWrapping: false,
|
||||
readOnly: true,
|
||||
styleActiveLine: true,
|
||||
extraKeys: {},
|
||||
theme: "mozilla markup-view"
|
||||
};
|
||||
|
||||
let doc = this._tooltip.doc;
|
||||
let container = doc.createElement("vbox");
|
||||
container.setAttribute("id", "devtools-tooltip-events-container");
|
||||
|
||||
for (let listener of this._eventListenerInfos) {
|
||||
let phase = listener.capturing ? "Capturing" : "Bubbling";
|
||||
let level = listener.DOM0 ? "DOM0" : "DOM2";
|
||||
|
||||
// Header
|
||||
let header = doc.createElement("hbox");
|
||||
header.className = "event-header devtools-toolbar";
|
||||
container.appendChild(header);
|
||||
|
||||
if (!listener.hide.debugger) {
|
||||
let debuggerIcon = doc.createElement("image");
|
||||
debuggerIcon.className = "event-tooltip-debugger-icon";
|
||||
debuggerIcon.setAttribute("src", "chrome://devtools/skin/images/tool-debugger.svg");
|
||||
let openInDebugger =
|
||||
l10n.strings.GetStringFromName("eventsTooltip.openInDebugger");
|
||||
debuggerIcon.setAttribute("tooltiptext", openInDebugger);
|
||||
header.appendChild(debuggerIcon);
|
||||
}
|
||||
|
||||
if (!listener.hide.type) {
|
||||
let eventTypeLabel = doc.createElement("label");
|
||||
eventTypeLabel.className = "event-tooltip-event-type";
|
||||
eventTypeLabel.setAttribute("value", listener.type);
|
||||
eventTypeLabel.setAttribute("tooltiptext", listener.type);
|
||||
header.appendChild(eventTypeLabel);
|
||||
}
|
||||
|
||||
if (!listener.hide.filename) {
|
||||
let filename = doc.createElement("label");
|
||||
filename.className = "event-tooltip-filename devtools-monospace";
|
||||
filename.setAttribute("value", listener.origin);
|
||||
filename.setAttribute("tooltiptext", listener.origin);
|
||||
filename.setAttribute("crop", "left");
|
||||
header.appendChild(filename);
|
||||
}
|
||||
|
||||
let attributesContainer = doc.createElement("hbox");
|
||||
attributesContainer.setAttribute("class",
|
||||
"event-tooltip-attributes-container");
|
||||
header.appendChild(attributesContainer);
|
||||
|
||||
if (!listener.hide.capturing) {
|
||||
let attributesBox = doc.createElement("box");
|
||||
attributesBox.setAttribute("class", "event-tooltip-attributes-box");
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let capturing = doc.createElement("label");
|
||||
capturing.className = "event-tooltip-attributes";
|
||||
capturing.setAttribute("value", phase);
|
||||
capturing.setAttribute("tooltiptext", phase);
|
||||
attributesBox.appendChild(capturing);
|
||||
}
|
||||
|
||||
if (listener.tags) {
|
||||
for (let tag of listener.tags.split(",")) {
|
||||
let attributesBox = doc.createElement("box");
|
||||
attributesBox.setAttribute("class", "event-tooltip-attributes-box");
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let tagBox = doc.createElement("label");
|
||||
tagBox.className = "event-tooltip-attributes";
|
||||
tagBox.setAttribute("value", tag);
|
||||
tagBox.setAttribute("tooltiptext", tag);
|
||||
attributesBox.appendChild(tagBox);
|
||||
}
|
||||
}
|
||||
|
||||
if (!listener.hide.dom0) {
|
||||
let attributesBox = doc.createElement("box");
|
||||
attributesBox.setAttribute("class", "event-tooltip-attributes-box");
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let dom0 = doc.createElement("label");
|
||||
dom0.className = "event-tooltip-attributes";
|
||||
dom0.setAttribute("value", level);
|
||||
dom0.setAttribute("tooltiptext", level);
|
||||
attributesBox.appendChild(dom0);
|
||||
}
|
||||
|
||||
// Content
|
||||
let content = doc.createElement("box");
|
||||
let editor = new Editor(config);
|
||||
this._tooltip.eventEditors.set(content, {
|
||||
editor: editor,
|
||||
handler: listener.handler,
|
||||
searchString: listener.searchString,
|
||||
uri: listener.origin,
|
||||
dom0: listener.DOM0,
|
||||
appended: false
|
||||
});
|
||||
|
||||
content.className = "event-tooltip-content-box";
|
||||
container.appendChild(content);
|
||||
|
||||
this._addContentListeners(header);
|
||||
}
|
||||
|
||||
this._tooltip.content = container;
|
||||
this._tooltip.panel.setAttribute("clamped-dimensions-no-max-or-min-height",
|
||||
"");
|
||||
this._tooltip.panel.setAttribute("wide", "");
|
||||
|
||||
this._tooltip.panel.addEventListener("popuphiding", () => {
|
||||
this.destroy(container);
|
||||
}, false);
|
||||
},
|
||||
|
||||
_addContentListeners: function (header) {
|
||||
header.addEventListener("click", this._headerClicked);
|
||||
},
|
||||
|
||||
_headerClicked: function (event) {
|
||||
if (event.target.classList.contains("event-tooltip-debugger-icon")) {
|
||||
this._debugClicked(event);
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = this._tooltip.doc;
|
||||
let header = event.currentTarget;
|
||||
let content = header.nextElementSibling;
|
||||
|
||||
if (content.hasAttribute("open")) {
|
||||
content.removeAttribute("open");
|
||||
} else {
|
||||
let contentNodes = doc.querySelectorAll(".event-tooltip-content-box");
|
||||
|
||||
for (let node of contentNodes) {
|
||||
if (node !== content) {
|
||||
node.removeAttribute("open");
|
||||
}
|
||||
}
|
||||
|
||||
content.setAttribute("open", "");
|
||||
|
||||
let eventEditors = this._tooltip.eventEditors.get(content);
|
||||
|
||||
if (eventEditors.appended) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {editor, handler} = eventEditors;
|
||||
|
||||
let iframe = doc.createElement("iframe");
|
||||
iframe.setAttribute("style", "width:100%;");
|
||||
|
||||
editor.appendTo(content, iframe).then(() => {
|
||||
/* eslint-disable camelcase */
|
||||
let tidied = beautify.js(handler, { indent_size: 2 });
|
||||
/* eslint-enable */
|
||||
editor.setText(tidied);
|
||||
|
||||
eventEditors.appended = true;
|
||||
|
||||
let container = header.parentElement.getBoundingClientRect();
|
||||
if (header.getBoundingClientRect().top < container.top) {
|
||||
header.scrollIntoView(true);
|
||||
} else if (content.getBoundingClientRect().bottom > container.bottom) {
|
||||
content.scrollIntoView(false);
|
||||
}
|
||||
|
||||
this._tooltip.emit("event-tooltip-ready");
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_debugClicked: function (event) {
|
||||
let header = event.currentTarget;
|
||||
let content = header.nextElementSibling;
|
||||
|
||||
let {uri, searchString, dom0} =
|
||||
this._tooltip.eventEditors.get(content);
|
||||
|
||||
if (uri && uri !== "?") {
|
||||
// Save a copy of toolbox as it will be set to null when we hide the
|
||||
// tooltip.
|
||||
let toolbox = this._toolbox;
|
||||
|
||||
this._tooltip.hide();
|
||||
|
||||
uri = uri.replace(/"/g, "");
|
||||
|
||||
let showSource = ({ DebuggerView }) => {
|
||||
let matches = uri.match(/(.*):(\d+$)/);
|
||||
let line = 1;
|
||||
|
||||
if (matches) {
|
||||
uri = matches[1];
|
||||
line = matches[2];
|
||||
}
|
||||
|
||||
let item = DebuggerView.Sources.getItemForAttachment(
|
||||
a => a.source.url === uri
|
||||
);
|
||||
if (item) {
|
||||
let actor = item.attachment.source.actor;
|
||||
DebuggerView.setEditorLocation(
|
||||
actor, line, {noDebug: true}
|
||||
).then(() => {
|
||||
if (dom0) {
|
||||
let text = DebuggerView.editor.getText();
|
||||
let index = text.indexOf(searchString);
|
||||
let lastIndex = text.lastIndexOf(searchString);
|
||||
|
||||
// To avoid confusion we only search for DOM0 event handlers when
|
||||
// there is only one possible match in the file.
|
||||
if (index !== -1 && index === lastIndex) {
|
||||
text = text.substr(0, index);
|
||||
let newlineMatches = text.match(/\n/g);
|
||||
|
||||
if (newlineMatches) {
|
||||
DebuggerView.editor.setCursor({
|
||||
line: newlineMatches.length
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger");
|
||||
toolbox.selectTool("jsdebugger").then(({ panelWin: dbg }) => {
|
||||
if (debuggerAlreadyOpen) {
|
||||
showSource(dbg);
|
||||
} else {
|
||||
dbg.once(dbg.EVENTS.SOURCES_ADDED, () => showSource(dbg));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function (container) {
|
||||
if (this._tooltip) {
|
||||
this._tooltip.panel.removeEventListener("popuphiding", this.destroy,
|
||||
false);
|
||||
|
||||
let boxes = container.querySelectorAll(".event-tooltip-content-box");
|
||||
|
||||
for (let box of boxes) {
|
||||
let {editor} = this._tooltip.eventEditors.get(box);
|
||||
editor.destroy();
|
||||
}
|
||||
|
||||
this._tooltip.eventEditors = null;
|
||||
}
|
||||
|
||||
let headerNodes = container.querySelectorAll(".event-header");
|
||||
|
||||
for (let node of headerNodes) {
|
||||
node.removeEventListener("click", this._headerClicked);
|
||||
}
|
||||
|
||||
let sourceNodes =
|
||||
container.querySelectorAll(".event-tooltip-debugger-icon");
|
||||
for (let node of sourceNodes) {
|
||||
node.removeEventListener("click", this._debugClicked);
|
||||
}
|
||||
|
||||
this._eventListenerInfos = this._toolbox = this._tooltip = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The swatch cubic-bezier tooltip class is a specific class meant to be used
|
||||
* along with rule-view's generated cubic-bezier swatches.
|
||||
|
315
devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
Normal file
315
devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
Normal file
@ -0,0 +1,315 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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 Services = require("Services");
|
||||
loader.lazyGetter(this, "GetStringFromName", () => {
|
||||
let bundle = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/inspector.properties");
|
||||
return key => {
|
||||
return bundle.GetStringFromName(key);
|
||||
};
|
||||
});
|
||||
|
||||
loader.lazyRequireGetter(this, "Editor", "devtools/client/sourceeditor/editor");
|
||||
loader.lazyRequireGetter(this, "beautify", "devtools/shared/jsbeautify/beautify");
|
||||
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const CONTAINER_WIDTH = 500;
|
||||
|
||||
/**
|
||||
* Set the content of a provided HTMLTooltip instance to display a list of event
|
||||
* listeners, with their event type, capturing argument and a link to the code
|
||||
* of the event handler.
|
||||
*
|
||||
* @param {HTMLTooltip} tooltip
|
||||
* The tooltip instance on which the event details content should be set
|
||||
* @param {Array} eventListenerInfos
|
||||
* A list of event listeners
|
||||
* @param {Toolbox} toolbox
|
||||
* Toolbox used to select debugger panel
|
||||
*/
|
||||
function setEventTooltip(tooltip, eventListenerInfos, toolbox) {
|
||||
let eventTooltip = new EventTooltip(tooltip, eventListenerInfos, toolbox);
|
||||
eventTooltip.init();
|
||||
}
|
||||
|
||||
function EventTooltip(tooltip, eventListenerInfos, toolbox) {
|
||||
this._tooltip = tooltip;
|
||||
this._eventListenerInfos = eventListenerInfos;
|
||||
this._toolbox = toolbox;
|
||||
this._tooltip.eventEditors = new WeakMap();
|
||||
|
||||
this._headerClicked = this._headerClicked.bind(this);
|
||||
this._debugClicked = this._debugClicked.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
}
|
||||
|
||||
EventTooltip.prototype = {
|
||||
init: function () {
|
||||
let config = {
|
||||
mode: Editor.modes.js,
|
||||
lineNumbers: false,
|
||||
lineWrapping: true,
|
||||
readOnly: true,
|
||||
styleActiveLine: true,
|
||||
extraKeys: {},
|
||||
theme: "mozilla markup-view"
|
||||
};
|
||||
|
||||
let doc = this._tooltip.doc;
|
||||
this.container = doc.createElementNS(XHTML_NS, "div");
|
||||
this.container.className = "devtools-tooltip-events-container";
|
||||
|
||||
for (let listener of this._eventListenerInfos) {
|
||||
let phase = listener.capturing ? "Capturing" : "Bubbling";
|
||||
let level = listener.DOM0 ? "DOM0" : "DOM2";
|
||||
|
||||
// Header
|
||||
let header = doc.createElementNS(XHTML_NS, "div");
|
||||
header.className = "event-header devtools-toolbar";
|
||||
this.container.appendChild(header);
|
||||
|
||||
if (!listener.hide.debugger) {
|
||||
let debuggerIcon = doc.createElementNS(XHTML_NS, "img");
|
||||
debuggerIcon.className = "event-tooltip-debugger-icon";
|
||||
debuggerIcon.setAttribute("src",
|
||||
"chrome://devtools/skin/images/tool-debugger.svg");
|
||||
let openInDebugger = GetStringFromName("eventsTooltip.openInDebugger");
|
||||
debuggerIcon.setAttribute("title", openInDebugger);
|
||||
header.appendChild(debuggerIcon);
|
||||
}
|
||||
|
||||
if (!listener.hide.type) {
|
||||
let eventTypeLabel = doc.createElementNS(XHTML_NS, "span");
|
||||
eventTypeLabel.className = "event-tooltip-event-type";
|
||||
eventTypeLabel.textContent = listener.type;
|
||||
eventTypeLabel.setAttribute("title", listener.type);
|
||||
header.appendChild(eventTypeLabel);
|
||||
}
|
||||
|
||||
if (!listener.hide.filename) {
|
||||
let filename = doc.createElementNS(XHTML_NS, "span");
|
||||
filename.className = "event-tooltip-filename devtools-monospace";
|
||||
filename.textContent = listener.origin;
|
||||
filename.setAttribute("title", listener.origin);
|
||||
header.appendChild(filename);
|
||||
}
|
||||
|
||||
let attributesContainer = doc.createElementNS(XHTML_NS, "div");
|
||||
attributesContainer.className = "event-tooltip-attributes-container";
|
||||
header.appendChild(attributesContainer);
|
||||
|
||||
if (!listener.hide.capturing) {
|
||||
let attributesBox = doc.createElementNS(XHTML_NS, "div");
|
||||
attributesBox.className = "event-tooltip-attributes-box";
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let capturing = doc.createElementNS(XHTML_NS, "span");
|
||||
capturing.className = "event-tooltip-attributes";
|
||||
capturing.textContent = phase;
|
||||
capturing.setAttribute("title", phase);
|
||||
attributesBox.appendChild(capturing);
|
||||
}
|
||||
|
||||
if (listener.tags) {
|
||||
for (let tag of listener.tags.split(",")) {
|
||||
let attributesBox = doc.createElementNS(XHTML_NS, "div");
|
||||
attributesBox.className = "event-tooltip-attributes-box";
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let tagBox = doc.createElementNS(XHTML_NS, "span");
|
||||
tagBox.className = "event-tooltip-attributes";
|
||||
tagBox.textContent = tag;
|
||||
tagBox.setAttribute("title", tag);
|
||||
attributesBox.appendChild(tagBox);
|
||||
}
|
||||
}
|
||||
|
||||
if (!listener.hide.dom0) {
|
||||
let attributesBox = doc.createElementNS(XHTML_NS, "div");
|
||||
attributesBox.className = "event-tooltip-attributes-box";
|
||||
attributesContainer.appendChild(attributesBox);
|
||||
|
||||
let dom0 = doc.createElementNS(XHTML_NS, "span");
|
||||
dom0.className = "event-tooltip-attributes";
|
||||
dom0.textContent = level;
|
||||
dom0.setAttribute("title", level);
|
||||
attributesBox.appendChild(dom0);
|
||||
}
|
||||
|
||||
// Content
|
||||
let content = doc.createElementNS(XHTML_NS, "div");
|
||||
let editor = new Editor(config);
|
||||
this._tooltip.eventEditors.set(content, {
|
||||
editor: editor,
|
||||
handler: listener.handler,
|
||||
searchString: listener.searchString,
|
||||
uri: listener.origin,
|
||||
dom0: listener.DOM0,
|
||||
appended: false
|
||||
});
|
||||
|
||||
content.className = "event-tooltip-content-box";
|
||||
this.container.appendChild(content);
|
||||
|
||||
this._addContentListeners(header);
|
||||
}
|
||||
|
||||
this._tooltip.setContent(this.container, CONTAINER_WIDTH);
|
||||
this._tooltip.on("hidden", this.destroy);
|
||||
},
|
||||
|
||||
_addContentListeners: function (header) {
|
||||
header.addEventListener("click", this._headerClicked);
|
||||
},
|
||||
|
||||
_headerClicked: function (event) {
|
||||
if (event.target.classList.contains("event-tooltip-debugger-icon")) {
|
||||
this._debugClicked(event);
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = this._tooltip.doc;
|
||||
let header = event.currentTarget;
|
||||
let content = header.nextElementSibling;
|
||||
|
||||
if (content.hasAttribute("open")) {
|
||||
content.removeAttribute("open");
|
||||
} else {
|
||||
let contentNodes = doc.querySelectorAll(".event-tooltip-content-box");
|
||||
|
||||
for (let node of contentNodes) {
|
||||
if (node !== content) {
|
||||
node.removeAttribute("open");
|
||||
}
|
||||
}
|
||||
|
||||
content.setAttribute("open", "");
|
||||
|
||||
let eventEditors = this._tooltip.eventEditors.get(content);
|
||||
|
||||
if (eventEditors.appended) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {editor, handler} = eventEditors;
|
||||
|
||||
let iframe = doc.createElementNS(XHTML_NS, "iframe");
|
||||
iframe.setAttribute("style", "width: 100%; height: 100%; border-style: none;");
|
||||
|
||||
editor.appendTo(content, iframe).then(() => {
|
||||
let tidied = beautify.js(handler, { "indent_size": 2 });
|
||||
editor.setText(tidied);
|
||||
|
||||
eventEditors.appended = true;
|
||||
|
||||
let container = header.parentElement.getBoundingClientRect();
|
||||
if (header.getBoundingClientRect().top < container.top) {
|
||||
header.scrollIntoView(true);
|
||||
} else if (content.getBoundingClientRect().bottom > container.bottom) {
|
||||
content.scrollIntoView(false);
|
||||
}
|
||||
|
||||
this._tooltip.emit("event-tooltip-ready");
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_debugClicked: function (event) {
|
||||
let header = event.currentTarget;
|
||||
let content = header.nextElementSibling;
|
||||
|
||||
let {uri, searchString, dom0} = this._tooltip.eventEditors.get(content);
|
||||
|
||||
if (uri && uri !== "?") {
|
||||
// Save a copy of toolbox as it will be set to null when we hide the tooltip.
|
||||
let toolbox = this._toolbox;
|
||||
|
||||
this._tooltip.hide();
|
||||
|
||||
uri = uri.replace(/"/g, "");
|
||||
|
||||
let showSource = ({ DebuggerView }) => {
|
||||
let matches = uri.match(/(.*):(\d+$)/);
|
||||
let line = 1;
|
||||
|
||||
if (matches) {
|
||||
uri = matches[1];
|
||||
line = matches[2];
|
||||
}
|
||||
|
||||
let item = DebuggerView.Sources.getItemForAttachment(a => a.source.url === uri);
|
||||
if (item) {
|
||||
let actor = item.attachment.source.actor;
|
||||
DebuggerView.setEditorLocation(
|
||||
actor, line, {noDebug: true}
|
||||
).then(() => {
|
||||
if (dom0) {
|
||||
let text = DebuggerView.editor.getText();
|
||||
let index = text.indexOf(searchString);
|
||||
let lastIndex = text.lastIndexOf(searchString);
|
||||
|
||||
// To avoid confusion we only search for DOM0 event handlers when
|
||||
// there is only one possible match in the file.
|
||||
if (index !== -1 && index === lastIndex) {
|
||||
text = text.substr(0, index);
|
||||
let newlineMatches = text.match(/\n/g);
|
||||
|
||||
if (newlineMatches) {
|
||||
DebuggerView.editor.setCursor({
|
||||
line: newlineMatches.length
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger");
|
||||
toolbox.selectTool("jsdebugger").then(({ panelWin: dbg }) => {
|
||||
if (debuggerAlreadyOpen) {
|
||||
showSource(dbg);
|
||||
} else {
|
||||
dbg.once(dbg.EVENTS.SOURCES_ADDED, () => showSource(dbg));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
if (this._tooltip) {
|
||||
this._tooltip.off("hidden", this.destroy);
|
||||
|
||||
let boxes = this.container.querySelectorAll(".event-tooltip-content-box");
|
||||
|
||||
for (let box of boxes) {
|
||||
let {editor} = this._tooltip.eventEditors.get(box);
|
||||
editor.destroy();
|
||||
}
|
||||
|
||||
this._tooltip.eventEditors = null;
|
||||
}
|
||||
|
||||
let headerNodes = this.container.querySelectorAll(".event-header");
|
||||
|
||||
for (let node of headerNodes) {
|
||||
node.removeEventListener("click", this._headerClicked);
|
||||
}
|
||||
|
||||
let sourceNodes = this.container.querySelectorAll(".event-tooltip-debugger-icon");
|
||||
for (let node of sourceNodes) {
|
||||
node.removeEventListener("click", this._debugClicked);
|
||||
}
|
||||
|
||||
this._eventListenerInfos = this._toolbox = this._tooltip = null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.setEventTooltip = setEventTooltip;
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'EventTooltipHelper.js',
|
||||
'ImageTooltipHelper.js',
|
||||
'TooltipToggle.js',
|
||||
)
|
||||
|
@ -199,8 +199,6 @@
|
||||
/* Tooltip: Events */
|
||||
|
||||
#devtools-tooltip-events-container {
|
||||
margin: -4px; /* Compensate for the .panel-arrowcontent padding. */
|
||||
max-width: 590px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@ -208,6 +206,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.event-header:first-child {
|
||||
@ -218,6 +217,11 @@
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.devtools-tooltip-events-container {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.event-tooltip-event-type,
|
||||
.event-tooltip-filename,
|
||||
.event-tooltip-attributes {
|
||||
@ -232,9 +236,14 @@
|
||||
}
|
||||
|
||||
.event-tooltip-filename {
|
||||
margin-inline-end: 0;
|
||||
margin: 0 5px;
|
||||
font-size: 100%;
|
||||
flex-shrink: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
/* Force ellipsis to be displayed on the left */
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.event-tooltip-debugger-icon {
|
||||
@ -251,7 +260,7 @@
|
||||
|
||||
.event-tooltip-content-box {
|
||||
display: none;
|
||||
height: 100px;
|
||||
height: 54px;
|
||||
overflow: hidden;
|
||||
margin-inline-end: 0;
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
@ -260,6 +269,7 @@
|
||||
|
||||
.event-toolbox-content-box iframe {
|
||||
height: 100%;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.event-tooltip-content-box[open] {
|
||||
@ -288,6 +298,7 @@
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
height: 14px;
|
||||
border-radius: 3px;
|
||||
padding: 2px;
|
||||
margin-inline-start: 5px;
|
||||
|
Loading…
Reference in New Issue
Block a user