Bug 1397169 - Properly implement openLink; r=rickychien
authorJan Odvarko <odvarko@gmail.com>
Wed, 06 Sep 2017 13:57:26 +0200
changeset 428933 de7570a6289bef8e2a1863c486a1078ea3dd4ceb
parent 428932 bd0ce93776feb070b1e48a98200782bc32a20e5a
child 428934 b1e755219f3a0b286be68ec7f462d3b051e015e2
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrickychien
bugs1397169
milestone57.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 1397169 - Properly implement openLink; r=rickychien MozReview-Commit-ID: HdelvmPW1Zm
devtools/client/dom/content/components/dom-tree.js
devtools/client/dom/content/components/main-frame.js
devtools/client/dom/content/dom-view.js
devtools/client/dom/dom-panel.js
--- a/devtools/client/dom/content/components/dom-tree.js
+++ b/devtools/client/dom/content/components/dom-tree.js
@@ -25,20 +25,21 @@ const PropTypes = React.PropTypes;
 
 /**
  * Renders DOM panel tree.
  */
 var DomTree = React.createClass({
   displayName: "DomTree",
 
   propTypes: {
-    object: PropTypes.any,
+    dispatch: PropTypes.func.isRequired,
     filter: PropTypes.string,
-    dispatch: PropTypes.func.isRequired,
     grips: PropTypes.object,
+    object: PropTypes.any,
+    openLink: PropTypes.func,
   },
 
   /**
    * Filter DOM properties. Return true if the object
    * should be visible in the tree.
    */
   onFilter: function (object) {
     if (!this.props.filter) {
@@ -47,39 +48,47 @@ var DomTree = React.createClass({
 
     return (object.name && object.name.indexOf(this.props.filter) > -1);
   },
 
   /**
    * Render DOM panel content
    */
   render: function () {
+    let {
+      dispatch,
+      grips,
+      object,
+      openLink,
+    } = this.props;
+
     let columns = [{
       "id": "value"
     }];
 
     // This is the integration point with Reps. The DomTree is using
     // Reps to render all values. The code also specifies default rep
     // used for data types that don't have its own specific template.
     let renderValue = props => {
       return Rep(Object.assign({}, props, {
         defaultRep: Grip,
         cropLimit: 50,
       }));
     };
 
     return (
       TreeView({
-        object: this.props.object,
-        provider: new GripProvider(this.props.grips, this.props.dispatch),
+        columns,
         decorator: new DomDecorator(),
         mode: MODE.SHORT,
-        columns: columns,
-        renderValue: renderValue,
-        onFilter: this.onFilter
+        object,
+        onFilter: this.onFilter,
+        openLink,
+        provider: new GripProvider(grips, dispatch),
+        renderValue,
       })
     );
   }
 });
 
 const mapStateToProps = (state) => {
   return {
     grips: state.grips,
--- a/devtools/client/dom/content/components/main-frame.js
+++ b/devtools/client/dom/content/components/main-frame.js
@@ -1,54 +1,62 @@
 /* -*- 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/. */
+ /* globals DomProvider */
+
 "use strict";
 
 // React & Redux
 const React = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
 // DOM Panel
 const DomTree = React.createFactory(require("./dom-tree"));
 const MainToolbar = React.createFactory(require("./main-toolbar"));
 
 // Shortcuts
 const { div } = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
- * Renders basic layout of the DOM panel. The DOM panel cotent consists
+ * Renders basic layout of the DOM panel. The DOM panel content consists
  * from two main parts: toolbar and tree.
  */
 var MainFrame = React.createClass({
   displayName: "MainFrame",
 
   propTypes: {
-    object: PropTypes.any,
+    dispatch: PropTypes.func.isRequired,
     filter: PropTypes.string,
-    dispatch: PropTypes.func.isRequired,
+    object: PropTypes.any,
   },
 
   /**
    * Render DOM panel content
    */
   render: function () {
+    let {
+      filter,
+      object,
+    } = this.props;
+
     return (
       div({className: "mainFrame"},
         MainToolbar({
           dispatch: this.props.dispatch,
           object: this.props.object
         }),
         div({className: "treeTableBox"},
           DomTree({
-            object: this.props.object,
-            filter: this.props.filter,
+            filter,
+            object,
+            openLink: url => DomProvider.openLink(url),
           })
         )
       )
     );
   }
 });
 
 // Transform state into props
--- a/devtools/client/dom/content/dom-view.js
+++ b/devtools/client/dom/content/dom-view.js
@@ -56,10 +56,10 @@ DomView.prototype = {
 
     if (typeof this[method] == "function") {
       this[method](data.args);
     }
   },
 };
 
 // Construct DOM panel view object and expose it to tests.
-// Tests can access it throught: |panel.panelWin.view|
+// Tests can access it through: |panel.panelWin.view|
 window.view = new DomView(store);
--- a/devtools/client/dom/dom-panel.js
+++ b/devtools/client/dom/dom-panel.js
@@ -62,18 +62,20 @@ DomPanel.prototype = {
 
   initialize: function () {
     this.panelWin.addEventListener("devtools/content/message",
       this.onContentMessage, true);
 
     this.target.on("navigate", this.onTabNavigated);
     this._toolbox.on("select", this.onPanelVisibilityChange);
 
+    // Export provider object with useful API for DOM panel.
     let provider = {
-      getPrototypeAndProperties: this.getPrototypeAndProperties.bind(this)
+      getPrototypeAndProperties: this.getPrototypeAndProperties.bind(this),
+      openLink: this.openLink.bind(this),
     };
 
     exportIntoContentScope(this.panelWin, provider, "DomProvider");
 
     this.shouldRefresh = true;
   },
 
   destroy: Task.async(function* () {
@@ -111,17 +113,17 @@ DomPanel.prototype = {
 
     this.getRootGrip().then(rootGrip => {
       this.postContentMessage("initialize", rootGrip);
     });
   },
 
   /**
    * Make sure the panel is refreshed when the page is reloaded.
-   * The panel is refreshed immediatelly if it's currently selected
+   * The panel is refreshed immediately if it's currently selected
    * or lazily  when the user actually selects it.
    */
   onTabNavigated: function () {
     this.shouldRefresh = true;
     this.refresh();
   },
 
   /**
@@ -172,16 +174,23 @@ DomPanel.prototype = {
       }
     });
 
     this.pendingRequests.set(grip.actor, deferred.promise);
 
     return deferred.promise;
   },
 
+  openLink: function (url) {
+    let parentDoc = this._toolbox.doc;
+    let iframe = parentDoc.getElementById("this._toolbox");
+    let top = iframe.ownerDocument.defaultView.top;
+    top.openUILinkIn(url, "tab");
+  },
+
   getRootGrip: function () {
     let deferred = defer();
 
     // Attach Console. It might involve RDP communication, so wait
     // asynchronously for the result
     this.target.activeConsole.evaluateJSAsync("window", res => {
       deferred.resolve(res.result);
     });