Bug 1401573 - Fix PoE, Link, and linux issue. r=nchevobbe
authorjason laster <jlaster@mozilla.com>
Wed, 20 Sep 2017 10:52:54 -0400
changeset 435532 a001ffb41787284a00cf3dd7c917eb803c275f1c
parent 435531 8e8def4061c5ee388fe4fcaa231b59f23dbba534
child 435533 a3816cf18525943c8fdbcb5049aae80592eab403
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe
bugs1401573
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 1401573 - Fix PoE, Link, and linux issue. r=nchevobbe MozReview-Commit-ID: 35TA6bhW1Wr
devtools/client/debugger/new/debugger.js
devtools/client/debugger/new/panel.js
devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -111,27 +111,29 @@ function _interopRequireDefault(obj) { r
 // }
 
 if ((0, _devtoolsConfig.isFirefoxPanel)()) {
   module.exports = {
     bootstrap: (_ref) => {
       var threadClient = _ref.threadClient,
           tabTarget = _ref.tabTarget,
           debuggerClient = _ref.debuggerClient,
-          sourceMaps = _ref.sourceMaps;
+          sourceMaps = _ref.sourceMaps,
+          toolboxActions = _ref.toolboxActions;
 
       return (0, _client.onConnect)({
         tab: { clientType: "firefox" },
         tabConnection: {
           tabTarget,
           threadClient,
           debuggerClient
         }
       }, {
-        sourceMaps
+        services: { sourceMaps },
+        toolboxActions
       });
     },
     destroy: () => {
       (0, _devtoolsLaunchpad.unmountRoot)(_reactDom2.default);
       (0, _bootstrap.teardownWorkers)();
     }
   };
 } else {
@@ -19304,23 +19306,40 @@ function evaluateExpression(expression, 
         getState = _ref7.getState,
         client = _ref7.client;
 
     if (!expression.input) {
       console.warn("Expressions should not be empty");
       return;
     }
 
+	const input = wrapExpression(expression.input);
     return dispatch({
       type: "EVALUATE_EXPRESSION",
       input: expression.input,
-      [_promise.PROMISE]: client.evaluate(expression.input, { frameId })
-    });
-  };
-}
+      [_promise.PROMISE]: client.evaluate(input, { frameId })
+    });
+  };
+}
+
+function sanitizeInput(input) {
+  return input.replace(/\\/g, "\\\\").replace(/"/g, "\\$&");
+}
+
+function wrapExpression(input) {
+  return `eval(\`
+    try {
+      ${sanitizeInput(input)}
+    } catch (e) {
+      e.name + ": " + e.message
+    }
+  \`)`.trim();
+}
+
+
 
 /***/ }),
 /* 253 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
@@ -19591,16 +19610,17 @@ var checkPendingBreakpoints = (() => {
  * @memberof actions/sources
  * @static
  */
 
 
 exports.newSource = newSource;
 exports.newSources = newSources;
 exports.selectSourceURL = selectSourceURL;
+exports.openLink = openLink;
 exports.selectSource = selectSource;
 exports.jumpToMappedLocation = jumpToMappedLocation;
 exports.addTab = addTab;
 exports.moveTab = moveTab;
 exports.closeTab = closeTab;
 exports.closeTabs = closeTabs;
 exports.togglePrettyPrint = togglePrettyPrint;
 exports.toggleBlackBox = toggleBlackBox;
@@ -19733,16 +19753,22 @@ function loadSourceMap(generatedSource) 
     });
 
     return function (_x13) {
       return _ref8.apply(this, arguments);
     };
   })();
 }
 
+function openLink(url) {
+  return async function({ openLink }) {
+    openLink(url);
+  };
+}
+
 /**
  * Deterministically select a source that has a given URL. This will
  * work regardless of the connection status or if the source exists
  * yet. This exists mostly for external things to interact with the
  * debugger.
  *
  * @memberof actions/sources
  * @static
@@ -27880,17 +27906,18 @@ class Expressions extends _react.PureCom
         ref: c => this._input = c
       })
     );
   }
 
   renderExpression(expression) {
     var _props3 = this.props,
         loadObjectProperties = _props3.loadObjectProperties,
-        loadedObjects = _props3.loadedObjects;
+        loadedObjects = _props3.loadedObjects,
+        openLink = _props3.openLink;
     var editing = this.state.editing;
     var input = expression.input,
         updating = expression.updating;
 
 
     if (editing == input) {
       return this.renderExpressionEditInput(expression);
     }
@@ -27924,17 +27951,18 @@ class Expressions extends _react.PureCom
           autoExpandDepth: 0,
           disableWrap: true,
           disabledFocus: true,
           onDoubleClick: (items, options) => this.editExpression(expression, options),
           getObjectProperties: id => loadedObjects[id],
           loadObjectProperties: loadObjectProperties
           // TODO: See https://github.com/devtools-html/debugger.html/issues/3555.
           , getObjectEntries: actor => {},
-          loadObjectEntries: grip => {}
+          loadObjectEntries: grip => {},
+          openLink: openLink
         }),
         _react2.default.createElement(
           "div",
           { className: "expression-container__close-btn" },
           _react2.default.createElement(_Close2.default, {
             handleClick: e => this.deleteExpression(e, expression)
           })
         )
@@ -28696,17 +28724,18 @@ class Scopes extends _react.PureComponen
       });
     }
   }
 
   render() {
     var _props2 = this.props,
         pauseInfo = _props2.pauseInfo,
         loadObjectProperties = _props2.loadObjectProperties,
-        loadedObjects = _props2.loadedObjects;
+        loadedObjects = _props2.loadedObjects,
+        openLink = _props2.openLink;
     var scopes = this.state.scopes;
 
 
     if (scopes) {
       return _react2.default.createElement(
         "div",
         { className: "pane scopes-list" },
         _react2.default.createElement(_devtoolsReps.ObjectInspector, {
@@ -28714,17 +28743,18 @@ class Scopes extends _react.PureComponen
           autoExpandDepth: 1,
           getObjectProperties: id => loadedObjects[id],
           loadObjectProperties: loadObjectProperties,
           disableWrap: true,
           disabledFocus: true,
           dimTopLevelWindow: true
           // TODO: See https://github.com/devtools-html/debugger.html/issues/3555.
           , getObjectEntries: actor => {},
-          loadObjectEntries: grip => {}
+          loadObjectEntries: grip => {},
+          openLink: openLink
         })
       );
     }
     return _react2.default.createElement(
       "div",
       { className: "pane scopes-list" },
       _react2.default.createElement(
         "div",
@@ -29225,17 +29255,18 @@ var KEYS = {
   }
 };
 
 function getKey(action) {
   return getKeyForOS(appinfo.OS, action);
 }
 
 function getKeyForOS(os, action) {
-  return KEYS[os][action];
+  var osActions = KEYS[os] || KEYS.Linux;
+  return osActions[action];
 }
 
 function formatKey(action) {
   var key = getKey(`${action}Display`) || getKey(action);
   if (isMacOS) {
     var winKey = getKeyForOS("WINNT", `${action}Display`) || getKeyForOS("WINNT", action);
     // display both Windows type and Mac specific keys
     return (0, _text.formatKeyShortcut)([key, winKey].join(" "));
@@ -30726,27 +30757,29 @@ class Popup extends _react.Component {
     return _react2.default.createElement(
       "div",
       { className: "preview-popup" },
       this.renderObjectInspector(root)
     );
   }
 
   renderSimplePreview(value) {
+    var openLink = this.props.openLink;
     return _react2.default.createElement(
       "div",
       { className: "preview-popup" },
-      Rep({ object: value, mode: MODE.LONG })
+      Rep({ object: value, mode: MODE.LONG, openLink: openLink })
     );
   }
 
   renderObjectInspector(root) {
     var _props2 = this.props,
         loadObjectProperties = _props2.loadObjectProperties,
-        loadedObjects = _props2.loadedObjects;
+        loadedObjects = _props2.loadedObjects,
+        openLink = _props2.openLink;
 
 
     var getObjectProperties = id => loadedObjects[id];
     var roots = this.getChildren(root, getObjectProperties);
 
     if (!roots) {
       return null;
     }
@@ -30755,17 +30788,18 @@ class Popup extends _react.Component {
       roots: roots,
       autoExpandDepth: 0,
       disableWrap: true,
       disabledFocus: true,
       getObjectProperties: getObjectProperties,
       loadObjectProperties: loadObjectProperties
       // TODO: See https://github.com/devtools-html/debugger.html/issues/3555.
       , getObjectEntries: actor => {},
-      loadObjectEntries: grip => {}
+      loadObjectEntries: grip => {},
+      openLink: openLink
     });
   }
 
   renderAddToExpressionBar(expression) {
     if (!(0, _devtoolsConfig.isEnabled)("previewWatch")) {
       return null;
     }
 
@@ -32124,26 +32158,28 @@ module.exports = {
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.onConnect = undefined;
 
 var onConnect = (() => {
-  var _ref = _asyncToGenerator(function* (connection, services) {
+  var _ref = _asyncToGenerator(function* (connection, options) {
     // NOTE: the landing page does not connect to a JS process
     if (!connection) {
       return;
     }
 
+	var services = options.services;
+	var toolboxActions = options.toolboxActions;
     var client = getClient(connection);
     var commands = client.clientCommands;
 
-    var _bootstrapStore = (0, _bootstrap.bootstrapStore)(commands, services),
+    var _bootstrapStore = (0, _bootstrap.bootstrapStore)(commands, options),
         store = _bootstrapStore.store,
         actions = _bootstrapStore.actions,
         selectors = _bootstrapStore.selectors;
 
     (0, _bootstrap.bootstrapWorkers)();
 
     var _ref2 = yield client.onConnect(connection, actions),
         bpClients = _ref2.bpClients;
@@ -33212,22 +33248,24 @@ var _selectors2 = _interopRequireDefault
 var _App = __webpack_require__(243);
 
 var _App2 = _interopRequireDefault(_App);
 
 var _prefs = __webpack_require__(226);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function bootstrapStore(client, services) {
+function bootstrapStore(client, options) {
+    var services = options.services;
+    var toolboxActions = options.toolboxActions;
   var createStore = (0, _createStore2.default)({
     log: (0, _devtoolsConfig.getValue)("logging.actions"),
     timing: (0, _devtoolsConfig.getValue)("performance.actions"),
     makeThunkArgs: (args, state) => {
-      return Object.assign({}, args, { client }, services);
+      return Object.assign({}, args, { client }, services, toolboxActions);
     }
   });
 
   var store = createStore((0, _redux.combineReducers)(_reducers2.default));
   store.subscribe(() => updatePrefs(store.getState()));
 
   var actions = (0, _redux.bindActionCreators)(__webpack_require__(244).default, store.dispatch);
 
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -25,18 +25,22 @@ DebuggerPanel.prototype = {
       actions,
       store,
       selectors,
       client
     } = await this.panelWin.Debugger.bootstrap({
       threadClient: this.toolbox.threadClient,
       tabTarget: this.toolbox.target,
       debuggerClient: this.toolbox.target.client,
-      sourceMaps: this.toolbox.sourceMapService
-    });
+      sourceMaps: this.toolbox.sourceMapService,
+      // Open a link in a new browser tab.
+      toolboxActions: {
+        openLink: this.openLink.bind(this)
+      }
+    })
 
     this._actions = actions;
     this._store = store;
     this._selectors = selectors;
     this._client = client;
     this.isReady = true;
     return this;
   },
@@ -49,16 +53,35 @@ DebuggerPanel.prototype = {
       client: this._client
     };
   },
 
   _getState: function() {
     return this._store.getState();
   },
 
+  openLink: function(url) {
+    const parentDoc = this.toolbox.doc;
+    if (!parentDoc) {
+      return;
+    }
+
+    const win = parentDoc.querySelector("window");
+    if (!win) {
+      return;
+    }
+
+    const top = win.ownerDocument.defaultView.top;
+    if (!top || typeof top.openUILinkIn !== "function") {
+      return;
+    }
+
+    top.openUILinkIn(url, "tab");
+  },
+
   getFrames: function() {
     let frames = this._selectors.getFrames(this._getState());
 
     // Frames is null when the debugger is not paused.
     if (!frames) {
       return {
         frames: [],
         selected: -1
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
@@ -56,17 +56,17 @@ async function editExpression(dbg, input
 add_task(async function() {
   const dbg = await initDebugger("doc-script-switching.html");
 
   invokeInTab("firstCall");
   await waitForPaused(dbg);
 
   await addExpression(dbg, "f");
   is(getLabel(dbg, 1), "f");
-  is(getValue(dbg, 1), "(unavailable)");
+  is(getValue(dbg, 1), `"ReferenceError: f is not defined"`);
 
   await editExpression(dbg, "oo");
   is(getLabel(dbg, 1), "foo()");
 
   // There is no "value" element for functions.
   assertEmptyValue(dbg, 1);
 
   await addExpression(dbg, "location");