Bug 1531826 Part 1 - View event handler sources by ID, r=ochameau.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 04 Mar 2019 05:45:19 -1000
changeset 520787 1e0ab7de952fe2a48d9a44bb0f01b60b437a3254
parent 520786 b8137cbaf9cfa4f4c45cb9bd82584b4375ba2662
child 520788 5c9c74ed4f11449e65aa264974648840d357f0f7
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1531826
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531826 Part 1 - View event handler sources by ID, r=ochameau.
devtools/client/shared/view-source.js
devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
devtools/server/actors/inspector/event-collector.js
devtools/server/actors/inspector/node.js
devtools/server/actors/utils/TabSources.js
--- a/devtools/client/shared/view-source.js
+++ b/devtools/client/shared/view-source.js
@@ -47,17 +47,18 @@ exports.viewSourceInStyleEditor = async 
  * @param {string} sourceID
  * @param {string} [reason=unknown]
  *
  * @return {Promise<boolean>}
  */
 exports.viewSourceInDebugger = async function(toolbox, sourceURL, sourceLine, sourceId,
                                               reason = "unknown") {
   const dbg = await toolbox.loadTool("jsdebugger");
-  const source = dbg.getSourceByURL(sourceURL) || dbg.getSourceByActorId(sourceId);
+  const source =
+    sourceId ? dbg.getSourceByActorId(sourceId) : dbg.getSourceByURL(sourceURL);
   if (source) {
     await toolbox.selectTool("jsdebugger", reason);
     dbg.selectSource(source.id, sourceLine);
     return true;
   } else if (await toolbox.sourceMapService.hasOriginalURL(sourceURL)) {
     // We have seen a source map for the URL but no source. The debugger will
     // still be able to load the source.
     await toolbox.selectTool("jsdebugger", reason);
--- a/devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
+++ b/devtools/client/shared/widgets/tooltip/EventTooltipHelper.js
@@ -179,16 +179,17 @@ EventTooltip.prototype = {
       }
 
       // Content
       const editor = new Editor(config);
       this._eventEditors.set(content, {
         editor: editor,
         handler: listener.handler,
         uri: listener.origin,
+        sourceActor: listener.sourceActor,
         dom0: listener.DOM0,
         native: listener.native,
         appended: false,
       });
 
       content.className = "event-tooltip-content-box";
       this.container.appendChild(content);
 
@@ -258,26 +259,26 @@ EventTooltip.prototype = {
       });
     }
   },
 
   _debugClicked: function(event) {
     const header = event.currentTarget;
     const content = header.nextElementSibling;
 
-    const {uri} = this._eventEditors.get(content);
+    const {sourceActor, uri} = this._eventEditors.get(content);
 
     const location = this._parseLocation(uri);
     if (location) {
       // Save a copy of toolbox as it will be set to null when we hide the tooltip.
       const toolbox = this._toolbox;
 
       this._tooltip.hide();
 
-      toolbox.viewSourceInDebugger(location.url, location.line);
+      toolbox.viewSourceInDebugger(location.url, location.line, sourceActor);
     }
   },
 
   /**
    * Parse URI and return {url, line}; or return null if it can't be parsed.
    */
   _parseLocation: function(uri) {
     if (uri && uri !== "?") {
--- a/devtools/server/actors/inspector/event-collector.js
+++ b/devtools/server/actors/inspector/event-collector.js
@@ -703,17 +703,19 @@ class ReactEventCollector extends MainEv
     return handlerDO;
   }
 }
 
 /**
  * The exposed class responsible for gathering events.
  */
 class EventCollector {
-  constructor() {
+  constructor(targetActor) {
+    this.targetActor = targetActor;
+
     // The event collector array. Please preserve the order otherwise there will
     // be multiple failing tests.
     this.eventCollectors = [
       new ReactEventCollector(),
       new JQueryLiveEventCollector(),
       new JQueryEventCollector(),
       new DOMEventCollector(),
     ];
@@ -859,16 +861,17 @@ class EventCollector {
       const override = listener.override || {};
       const tags = listener.tags || "";
       const type = listener.type || "";
       let dom0 = false;
       let functionSource = handler.toString();
       let line = 0;
       let native = false;
       let url = "";
+      let sourceActor = "";
 
       // If the listener is an object with a 'handleEvent' method, use that.
       if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
         let desc;
 
         while (!desc && listenerDO) {
           desc = listenerDO.getOwnPropertyDescriptor("handleEvent");
           listenerDO = listenerDO.proto;
@@ -895,16 +898,18 @@ class EventCollector {
         if (script.source.element) {
           dom0 = script.source.element.class !== "HTMLScriptElement";
         } else {
           dom0 = false;
         }
 
         line = script.startLine;
         url = script.url;
+        const actor = this.targetActor.sources.getOrCreateSourceActor(script.source);
+        sourceActor = actor ? actor.actorID : null;
 
         // Checking for the string "[native code]" is the only way at this point
         // to check for native code. Even if this provides a false positive then
         // grabbing the source code a second time is harmless.
         if (functionSource === "[object Object]" ||
             functionSource === "[object XULElement]" ||
             functionSource.includes("[native code]")) {
           functionSource =
@@ -952,16 +957,17 @@ class EventCollector {
         handler: override.handler || functionSource.trim(),
         origin: override.origin || origin,
         tags: override.tags || tags,
         DOM0: typeof override.dom0 !== "undefined" ? override.dom0 : dom0,
         capturing: typeof override.capturing !== "undefined" ?
                           override.capturing : capturing,
         hide: typeof override.hide !== "undefined" ? override.hide : hide,
         native,
+        sourceActor,
       };
 
       // Hide the debugger icon for DOM0 and native listeners. DOM0 listeners are
       // generated dynamically from e.g. an onclick="" attribute so the script
       // doesn't actually exist.
       if (native || dom0) {
         eventObj.hide.debugger = true;
       }
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -43,17 +43,17 @@ const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20
 /**
  * Server side of the node actor.
  */
 const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
   initialize: function(walker, node) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
-    this._eventCollector = new EventCollector();
+    this._eventCollector = new EventCollector(this.walker.targetActor);
 
     // Store the original display type and scrollable state and whether or not the node is
     // displayed to track changes when reflows occur.
     this.currentDisplayType = this.displayType;
     this.wasDisplayed = this.isDisplayed;
     this.wasScrollable = this.isScrollable;
   },
 
--- a/devtools/server/actors/utils/TabSources.js
+++ b/devtools/server/actors/utils/TabSources.js
@@ -142,31 +142,35 @@ TabSources.prototype = {
     if (!sourceActor) {
       throw new Error("getSource: could not find source actor for " +
                       (source.url || "source"));
     }
 
     return sourceActor;
   },
 
+  getOrCreateSourceActor(source) {
+    if (this.hasSourceActor(source)) {
+      return this.getSourceActor(source);
+    }
+    return this.createSourceActor(source);
+  },
+
   getSourceActorByInternalSourceId: function(id) {
     if (!this._sourcesByInternalSourceId) {
       this._sourcesByInternalSourceId = new Map();
       for (const source of this._thread.dbg.findSources()) {
         if (source.id) {
           this._sourcesByInternalSourceId.set(source.id, source);
         }
       }
     }
     const source = this._sourcesByInternalSourceId.get(id);
     if (source) {
-      if (this.hasSourceActor(source)) {
-        return this.getSourceActor(source);
-      }
-      return this.createSourceActor(source);
+      return this.getOrCreateSourceActor(source);
     }
     return null;
   },
 
   getSourceActorsByURL: function(url) {
     const rv = [];
     if (url) {
       for (const [source, actor] of this._sourceActors) {