--- 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,