Bug 1401972 - Release: Update reps bundle to 0.14.0; r=me. draft
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Thu, 21 Sep 2017 18:08:58 +0200
changeset 668915 4a8ac792905e50be77d19fffe9425380b1f8f304
parent 668408 b14c75b83d0226333b1240466ea9f07cfb206ff3
child 732801 03a0f52b9ce567469cb171c19b00bb181860e615
push id81153
push userbmo:nchevobbe@mozilla.com
push dateFri, 22 Sep 2017 06:24:28 +0000
reviewersme
bugs1401972
milestone58.0a1
Bug 1401972 - Release: Update reps bundle to 0.14.0; r=me. MozReview-Commit-ID: Jm4UDwdqrjE
devtools/client/shared/components/reps/reps.css
devtools/client/shared/components/reps/reps.js
--- a/devtools/client/shared/components/reps/reps.css
+++ b/devtools/client/shared/components/reps/reps.css
@@ -250,17 +250,17 @@
   -o-user-select: none;
   user-select: none;
 }
 
 .tree button {
   display: block;
 }
 
-.tree .tree-node {
+.tree .tree-node[data-expandable="true"] {
   cursor: pointer;
 }
 
 .tree .tree-node:not(.focused):hover {
   background-color: var(--tree-node-hover-background-color);
 }
 
 .tree .tree-node.focused {
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -131,18 +131,18 @@ const escapeRegexp = new RegExp("[" +
 // Quote and backslash.
 "\"\\\\" +
 // Controls.
 "\x00-\x1f" +
 // More controls.
 "\x7f-\x9f" +
 // BOM
 "\ufeff" +
-// Replacement characters and non-characters.
-"\ufffc-\uffff" +
+// Specials, except for the replacement character.
+"\ufff0-\ufffc\ufffe\uffff" +
 // Surrogates.
 "\ud800-\udfff" +
 // Mathematical invisibles.
 "\u2061-\u2064" +
 // Line and paragraph separators.
 "\u2028-\u2029" +
 // Private use area.
 "\ue000-\uf8ff" + "]", "g");
@@ -769,29 +769,31 @@ const { a, span } = React.DOM;
 StringRep.propTypes = {
   useQuotes: React.PropTypes.bool,
   escapeWhitespace: React.PropTypes.bool,
   style: React.PropTypes.object,
   object: React.PropTypes.string.isRequired,
   member: React.PropTypes.any,
   cropLimit: React.PropTypes.number,
   openLink: React.PropTypes.func,
-  className: React.PropTypes.string
+  className: React.PropTypes.string,
+  omitLinkHref: React.PropTypes.bool
 };
 
 function StringRep(props) {
   let {
     className,
     cropLimit,
     object: text,
     member,
     style,
     useQuotes = true,
     escapeWhitespace = true,
-    openLink
+    openLink,
+    omitLinkHref = true
   } = props;
 
   const classNames = ["objectBox", "objectBox-string"];
   if (className) {
     classNames.push(className);
   }
   let config = { className: classNames.join(" ") };
   if (style) {
@@ -823,17 +825,17 @@ function StringRep(props) {
     tokenStart = text.indexOf(token, textIndex);
     if (isURL(token)) {
       items.push(text.slice(textIndex, tokenStart));
       textIndex = tokenStart + token.length;
 
       items.push(a({
         className: "url",
         title: token,
-        href: token,
+        href: omitLinkHref === true ? null : token,
         draggable: false,
         onClick: openLink ? e => {
           e.preventDefault();
           openLink(token);
         } : null
       }, token));
     }
   });
@@ -2223,16 +2225,20 @@ function nodeHasAllEntriesInPreview(item
 
   const {
     entries,
     items,
     length,
     size
   } = preview;
 
+  if (!entries && !items) {
+    return false;
+  }
+
   return entries ? entries.length === size : items.length === length;
 }
 
 function nodeNeedsNumericalBuckets(item) {
   return nodeSupportsNumericalBucketing(item) && getNumericalPropertiesCount(item) > MAX_NUMERICAL_PROPERTIES;
 }
 
 function makeNodesForPromiseProperties(item) {
@@ -5136,16 +5142,17 @@ const ArrowExpander = createFactory(crea
     });
   }
 }));
 
 const TreeNode = createFactory(createClass({
   displayName: "TreeNode",
 
   propTypes: {
+    id: PropTypes.any.isRequired,
     index: PropTypes.number.isRequired,
     depth: PropTypes.number.isRequired,
     focused: PropTypes.bool.isRequired,
     expanded: PropTypes.bool.isRequired,
     item: PropTypes.any.isRequired,
     isExpandable: PropTypes.bool.isRequired,
     onClick: PropTypes.func,
     renderItem: PropTypes.func.isRequired
@@ -5153,16 +5160,17 @@ const TreeNode = createFactory(createCla
 
   shouldComponentUpdate(nextProps) {
     return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded;
   },
 
   render() {
     const {
       depth,
+      id,
       item,
       focused,
       expanded,
       renderItem,
       isExpandable
     } = this.props;
 
     const arrow = isExpandable ? ArrowExpander({
@@ -5202,25 +5210,27 @@ const TreeNode = createFactory(createCla
     if (this.props.isExpandable) {
       ariaExpanded = false;
     }
     if (this.props.expanded) {
       ariaExpanded = true;
     }
 
     return dom.div({
+      id,
       className: "tree-node" + (focused ? " focused" : ""),
       style: {
         paddingInlineStart,
         backgroundImage: backgroundBorder
       },
       onClick: this.props.onClick,
       role: "treeitem",
       "aria-level": depth,
-      "aria-expanded": ariaExpanded
+      "aria-expanded": ariaExpanded,
+      "data-expandable": this.props.isExpandable
     }, renderItem(item, depth, focused, arrow, expanded));
   }
 }));
 
 /**
  * Create a function that calls the given function `fn` only once per animation
  * frame.
  *
@@ -5412,20 +5422,16 @@ const Tree = createClass({
     //
     // Type: isExpanded(item: Item) -> Boolean
     //
     // Example:
     //
     //     isExpanded: item => item.expanded,
     isExpanded: PropTypes.func.isRequired,
 
-    // The height of an item in the tree including margin and padding, in
-    // pixels.
-    itemHeight: PropTypes.number.isRequired,
-
     // Optional props
 
     // The currently focused item, if any such item exists.
     focused: PropTypes.any,
 
     // Handle when a new item is focused.
     onFocus: PropTypes.func,
 
@@ -5467,35 +5473,26 @@ const Tree = createClass({
     return {
       autoExpandDepth: AUTO_EXPAND_DEPTH,
       autoExpandAll: true
     };
   },
 
   getInitialState() {
     return {
-      scroll: 0,
-      height: window.innerHeight,
       seen: new Set()
     };
   },
 
   componentDidMount() {
-    window.addEventListener("resize", this._updateHeight);
     this._autoExpand();
-    this._updateHeight();
   },
 
   componentWillReceiveProps(nextProps) {
     this._autoExpand();
-    this._updateHeight();
-  },
-
-  componentWillUnmount() {
-    window.removeEventListener("resize", this._updateHeight);
   },
 
   _autoExpand() {
     if (!this.props.autoExpandDepth) {
       return;
     }
 
     // Automatically expand the first autoExpandDepth levels for new items. Do
@@ -5542,25 +5539,16 @@ const Tree = createClass({
           if (e.nativeEvent.stopPropagation) {
             e.nativeEvent.stopPropagation();
           }
         }
     }
   },
 
   /**
-   * Updates the state's height based on clientHeight.
-   */
-  _updateHeight() {
-    this.setState({
-      height: this.refs.tree.clientHeight
-    });
-  },
-
-  /**
    * Perform a pre-order depth-first search from item.
    */
   _dfs(item, maxDepth = Infinity, traversal = [], _depth = 0) {
     traversal.push({ item, depth: _depth });
 
     if (!this.props.isExpanded(item)) {
       return traversal;
     }
@@ -5632,59 +5620,47 @@ const Tree = createClass({
    * @param {Number} index
    *        The index of the item in a full DFS traversal (ignoring collapsed
    *        nodes). Ignored if `item` is undefined.
    *
    * @param {Object|undefined} item
    *        The item to be focused, or undefined to focus no item.
    */
   _focus(index, item) {
-    if (item !== undefined) {
-      const itemStartPosition = index * this.props.itemHeight;
-      const itemEndPosition = (index + 1) * this.props.itemHeight;
-
-      // Note that if the height of the viewport (this.state.height) is less than
-      // `this.props.itemHeight`, we could accidentally try and scroll both up and
-      // down in a futile attempt to make both the item's start and end positions
-      // visible. Instead, give priority to the start of the item by checking its
-      // position first, and then using an "else if", rather than a separate "if",
-      // for the end position.
-      if (this.state.scroll > itemStartPosition) {
-        this.refs.tree.scrollTop = itemStartPosition;
-      } else if (this.state.scroll + this.state.height < itemEndPosition) {
-        this.refs.tree.scrollTop = itemEndPosition - this.state.height;
-      }
-    }
+    // TODO: Revisit how we should handle focus without having fixed item height.
+    // if (item !== undefined) {
+    //   const itemStartPosition = index * this.props.itemHeight;
+    //   const itemEndPosition = (index + 1) * this.props.itemHeight;
+
+    //   // Note that if the height of the viewport (this.state.height) is less than
+    //   // `this.props.itemHeight`, we could accidentally try and scroll both up and
+    //   // down in a futile attempt to make both the item's start and end positions
+    //   // visible. Instead, give priority to the start of the item by checking its
+    //   // position first, and then using an "else if", rather than a separate "if",
+    //   // for the end position.
+    //   if (this.state.scroll > itemStartPosition) {
+    //     this.refs.tree.scrollTop = itemStartPosition;
+    //   } else if ((this.state.scroll + this.state.height) < itemEndPosition) {
+    //     this.refs.tree.scrollTop = itemEndPosition - this.state.height;
+    //   }
+    // }
 
     if (this.props.onFocus) {
       this.props.onFocus(item);
     }
   },
 
   /**
    * Sets the state to have no focused item.
    */
   _onBlur() {
     this._focus(0, undefined);
   },
 
   /**
-   * Fired on a scroll within the tree's container, updates
-   * the stored position of the view port to handle virtual view rendering.
-   *
-   * @param {Event} e
-   */
-  _onScroll: oncePerAnimationFrame(function (e) {
-    this.setState({
-      scroll: Math.max(this.refs.tree.scrollTop, 0),
-      height: this.refs.tree.clientHeight
-    });
-  }),
-
-  /**
    * Handles key down events in the tree's container.
    *
    * @param {Event} e
    */
   _onKeyDown(e) {
     if (this.props.focused == null) {
       return;
     }
@@ -5805,18 +5781,20 @@ const Tree = createClass({
   render() {
     const traversal = this._dfsFromRoots();
     const {
       focused
     } = this.props;
 
     const nodes = traversal.map((v, i) => {
       const { item, depth } = traversal[i];
+      const key = this.props.getKey(item, i);
       return TreeNode({
-        key: this.props.getKey(item, i),
+        key,
+        id: key,
         index: i,
         item,
         depth,
         renderItem: this.props.renderItem,
         focused: focused === item,
         expanded: this.props.isExpanded(item),
         isExpandable: this._nodeIsExpandable(item),
         onExpand: this._onExpand,
@@ -5840,17 +5818,16 @@ const Tree = createClass({
     return dom.div({
       className: `tree ${this.props.className ? this.props.className : ""}`,
       ref: "tree",
       role: "tree",
       tabIndex: "0",
       onKeyDown: this._onKeyDown,
       onKeyPress: this._preventArrowKeyScrolling,
       onKeyUp: this._preventArrowKeyScrolling,
-      onScroll: this._onScroll,
       onFocus: ({ nativeEvent }) => {
         if (focused || !nativeEvent || !this.refs.tree) {
           return;
         }
 
         let { explicitOriginalTarget } = nativeEvent;
         // Only set default focus to the first tree node if the focus came
         // from outside the tree (e.g. by tabbing to the tree from other
@@ -5957,71 +5934,100 @@ module.exports = __WEBPACK_EXTERNAL_MODU
 /* 50 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 let enumIndexedProperties = (() => {
   var _ref = _asyncToGenerator(function* (objectClient, start, end) {
-    const { iterator } = yield objectClient.enumProperties({ ignoreNonIndexedProperties: true });
-    const response = yield iteratorSlice(iterator, start, end);
-    return response;
+    try {
+      const { iterator } = yield objectClient.enumProperties({ ignoreNonIndexedProperties: true });
+      const response = yield iteratorSlice(iterator, start, end);
+      return response;
+    } catch (e) {
+      console.error("Error in enumIndexedProperties", e);
+      return {};
+    }
   });
 
   return function enumIndexedProperties(_x, _x2, _x3) {
     return _ref.apply(this, arguments);
   };
 })(); /* 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/. */
 
 let enumNonIndexedProperties = (() => {
   var _ref2 = _asyncToGenerator(function* (objectClient, start, end) {
-    const { iterator } = yield objectClient.enumProperties({ ignoreIndexedProperties: true });
-
-    const response = yield iteratorSlice(iterator, start, end);
-    return response;
+    try {
+      const { iterator } = yield objectClient.enumProperties({ ignoreIndexedProperties: true });
+      const response = yield iteratorSlice(iterator, start, end);
+      return response;
+    } catch (e) {
+      console.error("Error in enumNonIndexedProperties", e);
+      return {};
+    }
   });
 
   return function enumNonIndexedProperties(_x4, _x5, _x6) {
     return _ref2.apply(this, arguments);
   };
 })();
 
 let enumEntries = (() => {
   var _ref3 = _asyncToGenerator(function* (objectClient, start, end) {
-    const { iterator } = yield objectClient.enumEntries();
-    const response = yield iteratorSlice(iterator, start, end);
-    return response;
+    try {
+      const { iterator } = yield objectClient.enumEntries();
+      const response = yield iteratorSlice(iterator, start, end);
+      return response;
+    } catch (e) {
+      console.error("Error in enumEntries", e);
+      return {};
+    }
   });
 
   return function enumEntries(_x7, _x8, _x9) {
     return _ref3.apply(this, arguments);
   };
 })();
 
 let enumSymbols = (() => {
   var _ref4 = _asyncToGenerator(function* (objectClient, start, end) {
-    const { iterator } = yield objectClient.enumSymbols();
-    const response = yield iteratorSlice(iterator, start, end);
-    return response;
+    try {
+      const { iterator } = yield objectClient.enumSymbols();
+      const response = yield iteratorSlice(iterator, start, end);
+      return response;
+    } catch (e) {
+      console.error("Error in enumSymbols", e);
+      return {};
+    }
   });
 
   return function enumSymbols(_x10, _x11, _x12) {
     return _ref4.apply(this, arguments);
   };
 })();
 
+let getPrototype = (() => {
+  var _ref5 = _asyncToGenerator(function* (objectClient) {
+    if (typeof objectClient.getPrototype !== "function") {
+      console.error("objectClient.getPrototype is not a function");
+      return Promise.resolve({});
+    }
+    return objectClient.getPrototype();
+  });
+
+  return function getPrototype(_x13) {
+    return _ref5.apply(this, arguments);
+  };
+})();
+
 function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-function getPrototype(objectClient) {
-  return objectClient.getPrototype();
-}
-
 function iteratorSlice(iterator, start, end) {
   start = start || 0;
   const count = end ? end - start + 1 : iterator.count;
   return iterator.slice(start, count);
 }
 
 module.exports = {
   enumEntries,