--- a/devtools/client/shared/components/reps/array.js
+++ b/devtools/client/shared/components/reps/array.js
@@ -5,17 +5,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { createFactories } = require("./rep-utils");
+ const {
+ createFactories,
+ wrapRender,
+ } = require("./rep-utils");
const { Caption } = createFactories(require("./caption"));
const { MODE } = require("./constants");
// Shortcuts
const DOM = React.DOM;
/**
* Renders an array. The array is enclosed by left and right bracket
@@ -111,17 +114,17 @@ define(function (require, exports, modul
// Event Handlers
onToggleProperties: function (event) {
},
onClickBracket: function (event) {
},
- render: function () {
+ render: wrapRender(function () {
let {
object,
mode = MODE.SHORT,
} = this.props;
let items;
let brackets;
let needSpace = function (space) {
@@ -153,38 +156,38 @@ define(function (require, exports, modul
object: object
}, brackets.right),
DOM.span({
className: "arrayProperties",
role: "group"}
)
)
);
- },
+ }),
});
/**
* Renders array item. Individual values are separated by a comma.
*/
let ItemRep = React.createFactory(React.createClass({
displayName: "ItemRep",
- render: function () {
+ render: wrapRender(function () {
const { Rep } = createFactories(require("./rep"));
let object = this.props.object;
let delim = this.props.delim;
let mode = this.props.mode;
return (
DOM.span({},
Rep({object: object, mode: mode}),
delim
)
);
- }
+ })
}));
function supportsObject(object, type) {
return Array.isArray(object) ||
Object.prototype.toString.call(object) === "[object Arguments]";
}
// Exports from this module
--- a/devtools/client/shared/components/reps/attribute.js
+++ b/devtools/client/shared/components/reps/attribute.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { StringRep } = require("./string");
// Shortcuts
const { span } = React.DOM;
const { rep: StringRepFactory } = createFactories(StringRep);
/**
* Renders DOM attribute
@@ -27,17 +31,17 @@ define(function (require, exports, modul
propTypes: {
object: React.PropTypes.object.isRequired
},
getTitle: function (grip) {
return grip.preview.nodeName;
},
- render: function () {
+ render: wrapRender(function () {
let object = this.props.object;
let value = object.preview.value;
let objectLink = this.props.objectLink || span;
return (
objectLink({className: "objectLink-Attr", object},
span({},
span({className: "attrTitle"},
@@ -45,17 +49,17 @@ define(function (require, exports, modul
),
span({className: "attrEqual"},
"="
),
StringRepFactory({object: value})
)
)
);
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/caption.js
+++ b/devtools/client/shared/components/reps/caption.js
@@ -7,25 +7,27 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
const DOM = React.DOM;
+ const { wrapRender } = require("./rep-utils");
+
/**
* Renders a caption. This template is used by other components
* that needs to distinguish between a simple text/value and a label.
*/
const Caption = React.createClass({
displayName: "Caption",
- render: function () {
+ render: wrapRender(function () {
return (
DOM.span({"className": "caption"}, this.props.object)
);
- },
+ }),
});
// Exports from this module
exports.Caption = Caption;
});
--- a/devtools/client/shared/components/reps/comment-node.js
+++ b/devtools/client/shared/components/reps/comment-node.js
@@ -4,17 +4,22 @@
* 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/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { isGrip, cropString, cropMultipleLines } = require("./rep-utils");
+ const {
+ isGrip,
+ cropString,
+ cropMultipleLines,
+ wrapRender,
+ } = require("./rep-utils");
const { MODE } = require("./constants");
const nodeConstants = require("devtools/shared/dom-node-constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders DOM comment node.
@@ -23,31 +28,31 @@ define(function (require, exports, modul
displayName: "CommentNode",
propTypes: {
object: React.PropTypes.object.isRequired,
// @TODO Change this to Object.values once it's supported in Node's version of V8
mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
},
- render: function () {
+ render: wrapRender(function () {
let {
object,
mode = MODE.SHORT
} = this.props;
let {textContent} = object.preview;
if (mode === MODE.TINY) {
textContent = cropMultipleLines(textContent, 30);
} else if (mode === MODE.SHORT) {
textContent = cropString(textContent, 50);
}
return span({className: "objectBox theme-comment"}, `<!-- ${textContent} -->`);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE;
--- a/devtools/client/shared/components/reps/date-time.js
+++ b/devtools/client/shared/components/reps/date-time.js
@@ -6,17 +6,20 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip } = require("./rep-utils");
+ const {
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Used to render JS built-in Date() object.
*/
let DateTime = React.createClass({
@@ -30,31 +33,32 @@ define(function (require, exports, modul
if (this.props.objectLink) {
return this.props.objectLink({
object: grip
}, grip.class + " ");
}
return "";
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
let date;
try {
date = span({className: "objectBox"},
this.getTitle(grip),
span({className: "Date"},
new Date(grip.preview.timestamp).toISOString()
)
);
} catch (e) {
date = span({className: "objectBox"}, "Invalid Date");
}
+
return date;
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/document.js
+++ b/devtools/client/shared/components/reps/document.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, getURLDisplayString } = require("./rep-utils");
+ const {
+ isGrip,
+ getURLDisplayString,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders DOM document object.
*/
let Document = React.createClass({
@@ -41,28 +45,28 @@ define(function (require, exports, modul
}
return "";
},
getTooltip: function (doc) {
return doc.location.href;
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
span({className: "objectBox objectBox-object"},
this.getTitle(grip),
span({className: "objectPropValue"},
this.getLocation(grip)
)
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
--- a/devtools/client/shared/components/reps/element-node.js
+++ b/devtools/client/shared/components/reps/element-node.js
@@ -6,17 +6,20 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Utils
- const { isGrip } = require("./rep-utils");
+ const {
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { MODE } = require("./constants");
const nodeConstants = require("devtools/shared/dom-node-constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders DOM element node.
@@ -83,17 +86,17 @@ define(function (require, exports, modul
return [
"<",
nodeNameElement,
...attributeElements,
">",
];
},
- render: function () {
+ render: wrapRender(function () {
let {
object,
mode,
onDOMNodeMouseOver,
onDOMNodeMouseOut
} = this.props;
let elements = this.getElements(object, mode);
let objectLink = this.props.objectLink || span;
@@ -109,17 +112,17 @@ define(function (require, exports, modul
Object.assign(baseConfig, {
onMouseOut: onDOMNodeMouseOut
});
}
return objectLink({object},
span(baseConfig, ...elements)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
--- a/devtools/client/shared/components/reps/error.js
+++ b/devtools/client/shared/components/reps/error.js
@@ -3,34 +3,37 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Utils
- const { isGrip } = require("./rep-utils");
+ const {
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders Error objects.
*/
const ErrorRep = React.createClass({
displayName: "Error",
propTypes: {
object: React.PropTypes.object.isRequired,
// @TODO Change this to Object.values once it's supported in Node's version of V8
mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
},
- render: function () {
+ render: wrapRender(function () {
let object = this.props.object;
let preview = object.preview;
let name = preview && preview.name
? preview.name
: "Error";
let content = this.props.mode === MODE.TINY
? name
@@ -46,17 +49,17 @@ define(function (require, exports, modul
}
let objectLink = this.props.objectLink || span;
return (
objectLink({object, className: "objectBox-stackTrace"},
span({}, content)
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return (object.preview && type === "Error");
--- a/devtools/client/shared/components/reps/event.js
+++ b/devtools/client/shared/components/reps/event.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { rep } = createFactories(require("./grip").Grip);
/**
* Renders DOM event objects.
*/
let Event = React.createClass({
displayName: "event",
@@ -29,17 +33,17 @@ define(function (require, exports, modul
let title = preview.type;
if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) {
title = `${title} ${preview.modifiers.join("-")}`;
}
return title;
},
- render: function () {
+ render: wrapRender(function () {
// Use `Object.assign` to keep `this.props` without changes because:
// 1. JSON.stringify/JSON.parse is slow.
// 2. Immutable.js is planned for the future.
let props = Object.assign({
title: this.getTitle(this.props)
}, this.props);
props.object = Object.assign({}, this.props.object);
props.object.preview = Object.assign({}, this.props.object.preview);
@@ -75,17 +79,17 @@ define(function (require, exports, modul
default:
props.isInterestingProp = (type, value, name) => {
// We want to show the properties in the order they are declared.
return Object.keys(props.object.preview.ownProperties).includes(name);
};
}
return rep(props);
- }
+ })
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/function.js
+++ b/devtools/client/shared/components/reps/function.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, cropString } = require("./rep-utils");
+ const {
+ isGrip,
+ cropString,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* This component represents a template for Function objects.
*/
let Func = React.createClass({
@@ -35,28 +39,28 @@ define(function (require, exports, modul
return "";
},
summarizeFunction: function (grip) {
let name = grip.userDisplayName || grip.displayName || grip.name || "function";
return cropString(name + "()", 100);
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
// Set dir="ltr" to prevent function parentheses from
// appearing in the wrong direction
span({dir: "ltr", className: "objectBox objectBox-function"},
this.getTitle(grip),
this.summarizeFunction(grip)
)
);
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return (type == "function");
}
--- a/devtools/client/shared/components/reps/grip-array.js
+++ b/devtools/client/shared/components/reps/grip-array.js
@@ -5,17 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { Caption } = createFactories(require("./caption"));
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders an array. The array is enclosed by left and right bracket
@@ -104,17 +108,17 @@ define(function (require, exports, modul
object: this.props.object
}, leftItemNum + " more…")
}));
}
return items;
},
- render: function () {
+ render: wrapRender(function () {
let {
object,
mode = MODE.SHORT
} = this.props;
let items;
let brackets;
let needSpace = function (space) {
@@ -149,17 +153,17 @@ define(function (require, exports, modul
object: object
}, brackets.right),
span({
className: "arrayProperties",
role: "group"}
)
)
);
- },
+ }),
});
/**
* Renders array item. Individual values are separated by
* a delimiter (a comma by default).
*/
let GripArrayItem = React.createFactory(React.createClass({
displayName: "GripArrayItem",
--- a/devtools/client/shared/components/reps/grip-map.js
+++ b/devtools/client/shared/components/reps/grip-map.js
@@ -4,17 +4,21 @@
* 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/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { Caption } = createFactories(require("./caption"));
const { PropRep } = createFactories(require("./prop-rep"));
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders an map. A map is represented by a list of its
* entries enclosed in curly brackets.
@@ -139,17 +143,17 @@ define(function (require, exports, modul
indexes.push(i);
}
}
return indexes;
}, []);
},
- render: function () {
+ render: wrapRender(function () {
let object = this.props.object;
let props = this.safeEntriesIterator(object,
(this.props.mode === MODE.LONG) ? 10 : 3);
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY) {
return (
span({className: "objectBox objectBox-object"},
@@ -171,17 +175,17 @@ define(function (require, exports, modul
}, " { "),
props,
objectLink({
className: "objectRightBrace",
object: object
}, " }")
)
);
- },
+ }),
});
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
return (grip.preview && grip.preview.kind == "MapLike");
}
--- a/devtools/client/shared/components/reps/grip.js
+++ b/devtools/client/shared/components/reps/grip.js
@@ -5,17 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Dependencies
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
const { Caption } = createFactories(require("./caption"));
const { PropRep } = createFactories(require("./prop-rep"));
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders generic grip. Grip is client representation
@@ -193,17 +197,17 @@ define(function (require, exports, modul
value = property.value;
} else if (keys.includes("getterValue")) {
value = property.getterValue;
}
}
return value;
},
- render: function () {
+ render: wrapRender(function () {
let object = this.props.object;
let props = this.safePropIterator(object,
(this.props.mode === MODE.LONG) ? 10 : 3);
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY) {
return (
span({className: "objectBox objectBox-object"},
@@ -225,17 +229,17 @@ define(function (require, exports, modul
}, " { "),
...props,
objectLink({
className: "objectRightBrace",
object: object
}, " }")
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return (object.preview && object.preview.ownProperties);
--- a/devtools/client/shared/components/reps/infinity.js
+++ b/devtools/client/shared/components/reps/infinity.js
@@ -6,32 +6,34 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders a Infinity object
*/
const InfinityRep = React.createClass({
displayName: "Infinity",
- render: function () {
+ render: wrapRender(function () {
return (
span({className: "objectBox objectBox-number"},
this.props.object.type
)
);
- }
+ })
});
function supportsObject(object, type) {
return type == "Infinity" || type == "-Infinity";
}
// Exports from this module
exports.InfinityRep = {
--- a/devtools/client/shared/components/reps/long-string.js
+++ b/devtools/client/shared/components/reps/long-string.js
@@ -3,17 +3,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { sanitizeString, isGrip } = require("./rep-utils");
+ const {
+ sanitizeString,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a long string grip.
*/
const LongStringRep = React.createClass({
displayName: "LongStringRep",
@@ -24,17 +28,17 @@ define(function (require, exports, modul
},
getDefaultProps: function () {
return {
useQuotes: true,
};
},
- render: function () {
+ render: wrapRender(function () {
let {
cropLimit,
member,
object,
style,
useQuotes
} = this.props;
let {fullText, initial, length} = object;
@@ -48,17 +52,17 @@ define(function (require, exports, modul
? fullText || initial
: initial.substring(0, cropLimit);
if (string.length < length) {
string += "\u2026";
}
let formattedString = useQuotes ? `"${string}"` : string;
return span(config, sanitizeString(formattedString));
- },
+ }),
});
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return object.type === "longString";
}
--- a/devtools/client/shared/components/reps/nan.js
+++ b/devtools/client/shared/components/reps/nan.js
@@ -6,32 +6,34 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders a NaN object
*/
const NaNRep = React.createClass({
displayName: "NaN",
- render: function () {
+ render: wrapRender(function () {
return (
span({className: "objectBox objectBox-nan"},
"NaN"
)
);
- }
+ })
});
function supportsObject(object, type) {
return type == "NaN";
}
// Exports from this module
exports.NaNRep = {
--- a/devtools/client/shared/components/reps/null.js
+++ b/devtools/client/shared/components/reps/null.js
@@ -6,32 +6,34 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders null value
*/
const Null = React.createClass({
displayName: "NullRep",
- render: function () {
+ render: wrapRender(function () {
return (
span({className: "objectBox objectBox-null"},
"null"
)
);
- },
+ }),
});
function supportsObject(object, type) {
if (object && object.type && object.type == "null") {
return true;
}
return (object == null);
--- a/devtools/client/shared/components/reps/number.js
+++ b/devtools/client/shared/components/reps/number.js
@@ -6,41 +6,43 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders a number
*/
const Number = React.createClass({
displayName: "Number",
stringify: function (object) {
let isNegativeZero = Object.is(object, -0) ||
(object.type && object.type == "-0");
return (isNegativeZero ? "-0" : String(object));
},
- render: function () {
+ render: wrapRender(function () {
let value = this.props.object;
return (
span({className: "objectBox objectBox-number"},
this.stringify(value)
)
);
- }
+ })
});
function supportsObject(object, type) {
return ["boolean", "number", "-0"].includes(type);
}
// Exports from this module
--- a/devtools/client/shared/components/reps/object-with-text.js
+++ b/devtools/client/shared/components/reps/object-with-text.js
@@ -6,17 +6,20 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip } = require("./rep-utils");
+ const {
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a grip object with textual data.
*/
let ObjectWithText = React.createClass({
@@ -40,27 +43,27 @@ define(function (require, exports, modul
getType: function (grip) {
return grip.class;
},
getDescription: function (grip) {
return "\"" + grip.preview.text + "\"";
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
span({className: "objectBox objectBox-" + this.getType(grip)},
this.getTitle(grip),
span({className: "objectPropValue"},
this.getDescription(grip)
)
)
);
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/object-with-url.js
+++ b/devtools/client/shared/components/reps/object-with-url.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, getURLDisplayString } = require("./rep-utils");
+ const {
+ isGrip,
+ getURLDisplayString,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a grip object with URL data.
*/
let ObjectWithURL = React.createClass({
@@ -40,27 +44,27 @@ define(function (require, exports, modul
getType: function (grip) {
return grip.class;
},
getDescription: function (grip) {
return getURLDisplayString(grip.preview.url);
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
span({className: "objectBox objectBox-" + this.getType(grip)},
this.getTitle(grip),
span({className: "objectPropValue"},
this.getDescription(grip)
)
)
);
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/object.js
+++ b/devtools/client/shared/components/reps/object.js
@@ -4,17 +4,20 @@
* 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/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { createFactories } = require("./rep-utils");
+ const {
+ createFactories,
+ wrapRender,
+ } = require("./rep-utils");
const { Caption } = createFactories(require("./caption"));
const { PropRep } = createFactories(require("./prop-rep"));
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders an object. An object is represented by a list of its
* properties enclosed in curly brackets.
@@ -127,17 +130,17 @@ define(function (require, exports, modul
}
} catch (err) {
console.error(err);
}
return props;
},
- render: function () {
+ render: wrapRender(function () {
let object = this.props.object;
let props = this.safePropIterator(object);
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY || !props.length) {
return (
span({className: "objectBox objectBox-object"},
objectLink({className: "objectTitle"}, this.getTitle(object))
@@ -154,17 +157,17 @@ define(function (require, exports, modul
}, " { "),
...props,
objectLink({
className: "objectRightBrace",
object: object
}, " }")
)
);
- },
+ }),
});
function supportsObject(object, type) {
return true;
}
// Exports from this module
exports.Obj = {
rep: Obj,
--- a/devtools/client/shared/components/reps/promise.js
+++ b/devtools/client/shared/components/reps/promise.js
@@ -5,17 +5,22 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Dependencies
- const { createFactories, isGrip } = require("./rep-utils");
+ const {
+ createFactories,
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
+
const { PropRep } = createFactories(require("./prop-rep"));
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a DOM Promise object.
*/
@@ -50,17 +55,17 @@ define(function (require, exports, modul
name: `<${key}>`,
object: promiseState[key],
equal: ": ",
delim: i < keys.length - 1 ? ", " : ""
}));
});
},
- render: function () {
+ render: wrapRender(function () {
const object = this.props.object;
const {promiseState} = object;
let objectLink = this.props.objectLink || span;
if (this.props.mode === MODE.TINY) {
let { Rep } = createFactories(require("./rep"));
return (
@@ -89,17 +94,17 @@ define(function (require, exports, modul
}, " { "),
...props,
objectLink({
className: "objectRightBrace",
object: object
}, " }")
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
return type === "Promise";
--- a/devtools/client/shared/components/reps/prop-rep.js
+++ b/devtools/client/shared/components/reps/prop-rep.js
@@ -4,44 +4,47 @@
* 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/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { createFactories } = require("./rep-utils");
+ const {
+ createFactories,
+ wrapRender,
+ } = require("./rep-utils");
const { MODE } = require("./constants");
// Shortcuts
const { span } = React.DOM;
/**
* Property for Obj (local JS objects), Grip (remote JS objects)
* and GripMap (remote JS maps and weakmaps) reps.
* It's used to render object properties.
*/
- let PropRep = React.createFactory(React.createClass({
+ let PropRep = React.createClass({
displayName: "PropRep",
propTypes: {
// Property name.
name: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.object,
]).isRequired,
// Equal character rendered between property name and value.
equal: React.PropTypes.string,
// Delimiter character used to separate individual properties.
delim: React.PropTypes.string,
// @TODO Change this to Object.values once it's supported in Node's version of V8
mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
},
- render: function () {
+ render: wrapRender(function () {
const { Grip } = require("./grip");
let { Rep } = createFactories(require("./rep"));
let key;
// The key can be a simple string, for plain objects,
// or another object for maps and weakmaps.
if (typeof this.props.name === "string") {
key = span({"className": "nodeName"}, this.props.name);
@@ -61,14 +64,14 @@ define(function (require, exports, modul
"className": "objectEqual"
}, this.props.equal),
Rep(this.props),
span({
"className": "objectComma"
}, this.props.delim)
)
);
- }
- }));
+ })
+ });
// Exports from this module
exports.PropRep = PropRep;
});
--- a/devtools/client/shared/components/reps/regexp.js
+++ b/devtools/client/shared/components/reps/regexp.js
@@ -6,17 +6,20 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip } = require("./rep-utils");
+ const {
+ isGrip,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a grip object with regular expression.
*/
let RegExp = React.createClass({
@@ -25,29 +28,29 @@ define(function (require, exports, modul
propTypes: {
object: React.PropTypes.object.isRequired,
},
getSource: function (grip) {
return grip.displayString;
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
let objectLink = this.props.objectLink || span;
return (
span({className: "objectBox objectBox-regexp"},
objectLink({
object: grip,
className: "regexpSource"
}, this.getSource(grip))
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
--- a/devtools/client/shared/components/reps/rep-utils.js
+++ b/devtools/client/shared/components/reps/rep-utils.js
@@ -142,19 +142,41 @@ define(function (require, exports, modul
return {
protocol: m[1],
domain: m[2],
path: m[2] + m[3],
name: m[4] + m[5]
};
}
+ /**
+ * Wrap the provided render() method of a rep in a try/catch block that will render a
+ * fallback rep if the render fails.
+ */
+ function wrapRender(renderMethod) {
+ return function () {
+ try {
+ return renderMethod.call(this);
+ } catch (e) {
+ return React.DOM.span(
+ {
+ className: "objectBox objectBox-failure",
+ title: "This object could not be rendered, " +
+ "please file a bug on bugzilla.mozilla.org"
+ },
+ /* Labels have to be hardcoded for reps, see Bug 1317038. */
+ "Invalid object");
+ }
+ };
+ }
+
// Exports from this module
exports.createFactories = createFactories;
exports.isGrip = isGrip;
exports.cropString = cropString;
exports.cropMultipleLines = cropMultipleLines;
exports.parseURLParams = parseURLParams;
exports.parseURLEncodedText = parseURLEncodedText;
exports.getFileName = getFileName;
exports.getURLDisplayString = getURLDisplayString;
+ exports.wrapRender = wrapRender;
exports.sanitizeString = sanitizeString;
});
--- a/devtools/client/shared/components/reps/reps.css
+++ b/devtools/client/shared/components/reps/reps.css
@@ -91,16 +91,25 @@
position: absolute;
right: 4px;
top: 2px;
padding-left: 8px;
font-weight: bold;
color: var(--source-link-color);
}
+.objectBox-failure {
+ color: var(--string-color);
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 2px;
+ font-size: 0.8em;
+ padding: 0 2px;
+}
+
/******************************************************************************/
.objectLink-event,
.objectLink-eventLog,
.objectLink-regexp,
.objectLink-object,
.objectLink-Date {
font-weight: bold;
--- a/devtools/client/shared/components/reps/string.js
+++ b/devtools/client/shared/components/reps/string.js
@@ -5,17 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
- const { cropString } = require("./rep-utils");
+
+ const {
+ cropString,
+ wrapRender,
+ } = require("./rep-utils");
// Shortcuts
const { span } = React.DOM;
/**
* Renders a string. String value is enclosed within quotes.
*/
const StringRep = React.createClass({
@@ -27,17 +31,17 @@ define(function (require, exports, modul
},
getDefaultProps: function () {
return {
useQuotes: true,
};
},
- render: function () {
+ render: wrapRender(function () {
let text = this.props.object;
let member = this.props.member;
let style = this.props.style;
let config = {className: "objectBox objectBox-string"};
if (style) {
config.style = style;
}
@@ -48,17 +52,17 @@ define(function (require, exports, modul
let croppedString = this.props.cropLimit ?
cropString(text, this.props.cropLimit) : cropString(text);
let formattedString = this.props.useQuotes ?
"\"" + croppedString + "\"" : croppedString;
return span(config, formattedString);
- },
+ }),
});
function supportsObject(object, type) {
return (type == "string");
}
// Exports from this module
--- a/devtools/client/shared/components/reps/stylesheet.js
+++ b/devtools/client/shared/components/reps/stylesheet.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, getURLDisplayString } = require("./rep-utils");
+ const {
+ isGrip,
+ getURLDisplayString,
+ wrapRender
+ } = require("./rep-utils");
// Shortcuts
const DOM = React.DOM;
/**
* Renders a grip representing CSSStyleSheet
*/
let StyleSheet = React.createClass({
@@ -39,28 +43,28 @@ define(function (require, exports, modul
},
getLocation: function (grip) {
// Embedded stylesheets don't have URL and so, no preview.
let url = grip.preview ? grip.preview.url : "";
return url ? getURLDisplayString(url) : "";
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
DOM.span({className: "objectBox objectBox-object"},
this.getTitle(grip),
DOM.span({className: "objectPropValue"},
this.getLocation(grip)
)
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
--- a/devtools/client/shared/components/reps/symbol.js
+++ b/devtools/client/shared/components/reps/symbol.js
@@ -6,39 +6,41 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders a symbol.
*/
const SymbolRep = React.createClass({
displayName: "SymbolRep",
propTypes: {
object: React.PropTypes.object.isRequired
},
- render: function () {
+ render: wrapRender(function () {
let {object} = this.props;
let {name} = object;
return (
span({className: "objectBox objectBox-symbol"},
`Symbol(${name || ""})`
)
);
- },
+ }),
});
function supportsObject(object, type) {
return (type == "symbol");
}
// Exports from this module
exports.SymbolRep = {
--- a/devtools/client/shared/components/reps/text-node.js
+++ b/devtools/client/shared/components/reps/text-node.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, cropString } = require("./rep-utils");
+ const {
+ isGrip,
+ cropString,
+ wrapRender,
+ } = require("./rep-utils");
const { MODE } = require("./constants");
// Shortcuts
const DOM = React.DOM;
/**
* Renders DOM #text node.
*/
@@ -38,17 +42,17 @@ define(function (require, exports, modul
if (this.props.objectLink) {
return this.props.objectLink({
object: grip
}, title);
}
return title;
},
- render: function () {
+ render: wrapRender(function () {
let {
object: grip,
mode = MODE.SHORT,
} = this.props;
let baseConfig = {className: "objectBox objectBox-textNode"};
if (this.props.onDOMNodeMouseOver) {
Object.assign(baseConfig, {
@@ -70,17 +74,17 @@ define(function (require, exports, modul
DOM.span(baseConfig,
this.getTitle(grip),
DOM.span({className: "nodeValue"},
" ",
`"${this.getTextContent(grip)}"`
)
)
);
- },
+ }),
});
// Registration
function supportsObject(grip, type) {
if (!isGrip(grip)) {
return false;
}
--- a/devtools/client/shared/components/reps/undefined.js
+++ b/devtools/client/shared/components/reps/undefined.js
@@ -6,32 +6,34 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// Dependencies
const React = require("devtools/client/shared/vendor/react");
+ const { wrapRender } = require("./rep-utils");
+
// Shortcuts
const { span } = React.DOM;
/**
* Renders undefined value
*/
const Undefined = React.createClass({
displayName: "UndefinedRep",
- render: function () {
+ render: wrapRender(function () {
return (
span({className: "objectBox objectBox-undefined"},
"undefined"
)
);
- },
+ }),
});
function supportsObject(object, type) {
if (object && object.type && object.type == "undefined") {
return true;
}
return (type == "undefined");
--- a/devtools/client/shared/components/reps/window.js
+++ b/devtools/client/shared/components/reps/window.js
@@ -6,17 +6,21 @@
"use strict";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const React = require("devtools/client/shared/vendor/react");
// Reps
- const { isGrip, getURLDisplayString } = require("./rep-utils");
+ const {
+ isGrip,
+ getURLDisplayString,
+ wrapRender
+ } = require("./rep-utils");
// Shortcuts
const DOM = React.DOM;
/**
* Renders a grip representing a window.
*/
let Window = React.createClass({
@@ -36,28 +40,28 @@ define(function (require, exports, modul
}
return "";
},
getLocation: function (grip) {
return getURLDisplayString(grip.preview.url);
},
- render: function () {
+ render: wrapRender(function () {
let grip = this.props.object;
return (
DOM.span({className: "objectBox objectBox-Window"},
this.getTitle(grip),
DOM.span({className: "objectPropValue"},
this.getLocation(grip)
)
)
);
- },
+ }),
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
--- a/devtools/client/shared/components/test/mochitest/chrome.ini
+++ b/devtools/client/shared/components/test/mochitest/chrome.ini
@@ -10,16 +10,17 @@ support-files =
[test_reps_array.html]
[test_reps_attribute.html]
[test_reps_comment-node.html]
[test_reps_date-time.html]
[test_reps_document.html]
[test_reps_element-node.html]
[test_reps_error.html]
[test_reps_event.html]
+[test_reps_failure.html]
[test_reps_function.html]
[test_reps_grip.html]
[test_reps_grip-array.html]
[test_reps_grip-map.html]
[test_reps_infinity.html]
[test_reps_long-string.html]
[test_reps_nan.html]
[test_reps_null.html]
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_failure.html
@@ -0,0 +1,60 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test fallback for rep rendering when a rep fails to render.
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Failure</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+ try {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ArrayRep } = browserRequire("devtools/client/shared/components/reps/array");
+ let { RegExp } = browserRequire("devtools/client/shared/components/reps/regexp");
+
+ // Force the RegExp rep to crash by creating RegExp grip that throws when accessing
+ // the displayString property
+ let gripStub = {
+ "type": "object",
+ "class": "RegExp",
+ "actor": "server1.conn22.obj39",
+ "extensible": true,
+ "frozen": false,
+ "sealed": false,
+ "ownPropertyLength": 1,
+ get displayString() {
+ throw new Error("failure");
+ }
+ };
+
+ // Test that correct rep is chosen.
+ const renderedRep = shallowRenderComponent(Rep, { object: gripStub });
+ is(renderedRep.type, RegExp.rep, `Rep correctly selects ${RegExp.rep.displayName}`);
+
+ // Test fallback message is displayed when rendering bad rep directly.
+ let renderedComponent = renderComponent(RegExp.rep, { object: gripStub });
+ is(renderedComponent.textContent, "Invalid object", "Fallback rendering has expected text content");
+
+ // Test fallback message is displayed when bad rep is nested in another rep.
+ renderedComponent = renderComponent(ArrayRep.rep, { object: [1, gripStub, 2] });
+ is(renderedComponent.textContent, "[ 1, Invalid object, 2 ]", "Fallback rendering has expected text content");
+ } catch(e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+});
+</script>
+</pre>
+</body>
+</html>
\ No newline at end of file