Skip to content

Commit

Permalink
Bug 1333352 - use client-side source map service in markup view event…
Browse files Browse the repository at this point in the history
… bubble; r=jdescottes

MozReview-Commit-ID: D8bF5kkHp2p
  • Loading branch information
tromey committed May 12, 2017
1 parent 7a999ec commit 6e00819
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 10 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ devtools/client/debugger/test/mochitest/code_math_bogus_map.js
devtools/client/debugger/test/mochitest/code_ugly*
devtools/client/debugger/test/mochitest/code_worker-source-map.js
devtools/client/framework/test/code_ugly*
devtools/client/inspector/markup/test/events_bundle.js
devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
devtools/server/tests/unit/setBreakpoint*
devtools/server/tests/unit/sourcemapped.js
Expand Down
5 changes: 5 additions & 0 deletions devtools/client/inspector/markup/test/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ support-files =
doc_markup_events_react_development_15.4.1_jsx.html
doc_markup_events_react_production_15.3.1.html
doc_markup_events_react_production_15.3.1_jsx.html
doc_markup_events-source_map.html
doc_markup_flashing.html
doc_markup_html_mixed_case.html
doc_markup_image_and_canvas.html
Expand All @@ -37,6 +38,9 @@ support-files =
doc_markup_void_elements.xhtml
doc_markup_whitespace.html
doc_markup_xul.xul
events_bundle.js
events_bundle.js.map
events_original.js
head.js
helper_attributes_test_runner.js
helper_diff.js
Expand Down Expand Up @@ -114,6 +118,7 @@ skip-if = true # Bug 1177550
[browser_markup_events_react_development_15.4.1_jsx.js]
[browser_markup_events_react_production_15.3.1.js]
[browser_markup_events_react_production_15.3.1_jsx.js]
[browser_markup_events_source_map.js]
[browser_markup_events-windowed-host.js]
[browser_markup_links_01.js]
[browser_markup_links_02.js]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Check that source maps work in the event popup.

const INITIAL_URL = URL_ROOT + "doc_markup_void_elements.html";
const TEST_URL = URL_ROOT + "doc_markup_events-source_map.html";

/* import-globals-from helper_events_test_runner.js */
loadHelperScript("helper_events_test_runner.js");

const TEST_DATA = [
{
selector: "#clicky",
isSourceMapped: true,
expected: [
{
type: "click",
filename: "webpack:///events_original.js:7",
attributes: [
"Bubbling",
"DOM2"
],
handler: `function clickme() {
console.log("clickme");
}`,
},
],
},
];

add_task(function* () {
// Load some other URL before opening the toolbox, then navigate to
// the test URL. This ensures that source map service will see the
// sources as they are loaded, avoiding any races.
let {toolbox, inspector, testActor} = yield openInspectorForURL(INITIAL_URL);

// Ensure the source map service is operating. This looks a bit
// funny, but sourceMapURLService is a getter, and we don't need the
// result.
toolbox.sourceMapURLService;

yield navigateTo(inspector, TEST_URL);

yield inspector.markup.expandAll();

for (let test of TEST_DATA) {
yield checkEventsForNode(test, inspector, testActor);
}

// Wait for promises to avoid leaks when running this as a single test.
// We need to do this because we have opened a bunch of popups and don't them
// to affect other test runs when they are GCd.
yield promiseNextTick();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="application/javascript" src="events_bundle.js"></script>
</head>
<body onload="init();">
<div id="clicky">click here</div>
</body>
</html>
94 changes: 94 additions & 0 deletions devtools/client/inspector/markup/test/events_bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions devtools/client/inspector/markup/test/events_bundle.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions devtools/client/inspector/markup/test/events_original.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

function clickme() {
console.log("clickme");
}

function init() {
let s = document.querySelector("#clicky");
s.addEventListener("click", clickme);
}

window.init = init;
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ function* runEventPopupTests(url, tests) {
* - handler {String} string representation of the handler
* - beforeTest {Function} (optional) a function to execute on the page
* before running the test
* - isSourceMapped {Boolean} (optional) true if the location
* is source-mapped, requiring some extra delay before the checks
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* opened
* @param {TestActorFront} testActor
*/
function* checkEventsForNode(test, inspector, testActor) {
let {selector, expected, beforeTest} = test;
let {selector, expected, beforeTest, isSourceMapped} = test;
let container = yield getContainerForSelector(selector, inspector);

if (typeof beforeTest === "function") {
Expand All @@ -65,13 +67,23 @@ function* checkEventsForNode(test, inspector, testActor) {

yield selectNode(selector, inspector);

let sourceMapPromise = null;
if (isSourceMapped) {
sourceMapPromise = tooltip.once("event-tooltip-source-map-ready");
}

// Click button to show tooltip
info("Clicking evHolder");
EventUtils.synthesizeMouseAtCenter(evHolder, {},
inspector.markup.doc.defaultView);
yield tooltip.once("shown");
info("tooltip shown");

if (isSourceMapped) {
info("Waiting for source map to be applied");
yield sourceMapPromise;
}

// Check values
let headers = tooltip.panel.querySelectorAll(".event-header");
let nodeFront = container.node;
Expand Down
48 changes: 39 additions & 9 deletions devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ const L10N = new LocalizationHelper("devtools/client/locales/inspector.propertie
const Editor = require("devtools/client/sourceeditor/editor");
const beautify = require("devtools/shared/jsbeautify/beautify");

loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");

const XHTML_NS = "http://www.w3.org/1999/xhtml";
const CONTAINER_WIDTH = 500;

Expand Down Expand Up @@ -64,10 +62,15 @@ EventTooltip.prototype = {
this.container = doc.createElementNS(XHTML_NS, "div");
this.container.className = "devtools-tooltip-events-container";

const sourceMapService = this._toolbox.sourceMapURLService;

for (let listener of this._eventListenerInfos) {
let phase = listener.capturing ? "Capturing" : "Bubbling";
let level = listener.DOM0 ? "DOM0" : "DOM2";

// Create this early so we can refer to it from a closure, below.
let content = doc.createElementNS(XHTML_NS, "div");

// Header
let header = doc.createElementNS(XHTML_NS, "div");
header.className = "event-header devtools-toolbar";
Expand Down Expand Up @@ -103,6 +106,23 @@ EventTooltip.prototype = {
if (listener.hide.filename) {
text = L10N.getStr("eventsTooltip.unknownLocation");
title = L10N.getStr("eventsTooltip.unknownLocationExplanation");
} else if (sourceMapService) {
const location = this._parseLocation(text);
if (location) {
sourceMapService.originalPositionFor(location.url, location.line)
.then((originalLocation) => {
if (originalLocation) {
const { sourceUrl, line } = originalLocation;
let newURI = sourceUrl + ":" + line;
filename.textContent = newURI;
filename.setAttribute("title", newURI);
let eventEditor = this._eventEditors.get(content);
eventEditor.uri = newURI;
}
// This is emitted for testing.
this._tooltip.emit("event-tooltip-source-map-ready");
});
}
}

filename.textContent = text;
Expand Down Expand Up @@ -152,7 +172,6 @@ EventTooltip.prototype = {
}

// Content
let content = doc.createElementNS(XHTML_NS, "div");
let editor = new Editor(config);
this._eventEditors.set(content, {
editor: editor,
Expand Down Expand Up @@ -236,24 +255,35 @@ EventTooltip.prototype = {

let {uri} = this._eventEditors.get(content);

if (uri && uri !== "?") {
let location = this._parseLocation(uri);
if (location) {
// Save a copy of toolbox as it will be set to null when we hide the tooltip.
let toolbox = this._toolbox;

this._tooltip.hide();

toolbox.viewSourceInDebugger(location.url, location.line);
}
},

/**
* Parse URI and return {url, line}; or return null if it can't be parsed.
*/
_parseLocation: function (uri) {
if (uri && uri !== "?") {
uri = uri.replace(/"/g, "");

let matches = uri.match(/(.*):(\d+$)/);
let line = 1;

if (matches) {
uri = matches[1];
line = matches[2];
return {
url: matches[1],
line: parseInt(matches[2], 10),
};
}

viewSource.viewSourceInDebugger(toolbox, uri, line);
return {url: uri, line: 1};
}
return null;
},

destroy: function () {
Expand Down

0 comments on commit 6e00819

Please sign in to comment.