Bug 1397169 - Properly implement openLink; r=rickychien draft
authorJan Odvarko <odvarko@gmail.com>
Wed, 06 Sep 2017 13:57:26 +0200
changeset 659954 7b91be4c1e0d5fb36dfd5501600a91e88f671a00
parent 659065 3ecda4678c49ca255c38b1697142b9118cdd27e7
child 730099 d3870831c5da975d468daa888e95ff5f2c0a237b
push id78248
push userjodvarko@mozilla.com
push dateWed, 06 Sep 2017 11:58:07 +0000
reviewersrickychien
bugs1397169
milestone57.0a1
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);
     });