object.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. // Make this available to both AMD and CJS environments
  7. define(function (require, exports, module) {
  8. // Dependencies
  9. const React = require("devtools/client/shared/vendor/react");
  10. const { createFactories } = require("./rep-utils");
  11. const { Caption } = createFactories(require("./caption"));
  12. const { PropRep } = createFactories(require("./prop-rep"));
  13. // Shortcuts
  14. const { span } = React.DOM;
  15. /**
  16. * Renders an object. An object is represented by a list of its
  17. * properties enclosed in curly brackets.
  18. */
  19. const Obj = React.createClass({
  20. displayName: "Obj",
  21. propTypes: {
  22. object: React.PropTypes.object,
  23. mode: React.PropTypes.string,
  24. },
  25. getTitle: function (object) {
  26. let className = object && object.class ? object.class : "Object";
  27. if (this.props.objectLink) {
  28. return this.props.objectLink({
  29. object: object
  30. }, className);
  31. }
  32. return className;
  33. },
  34. safePropIterator: function (object, max) {
  35. max = (typeof max === "undefined") ? 3 : max;
  36. try {
  37. return this.propIterator(object, max);
  38. } catch (err) {
  39. console.error(err);
  40. }
  41. return [];
  42. },
  43. propIterator: function (object, max) {
  44. let isInterestingProp = (t, value) => {
  45. // Do not pick objects, it could cause recursion.
  46. return (t == "boolean" || t == "number" || (t == "string" && value));
  47. };
  48. // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377
  49. if (Object.prototype.toString.call(object) === "[object Generator]") {
  50. object = Object.getPrototypeOf(object);
  51. }
  52. // Object members with non-empty values are preferred since it gives the
  53. // user a better overview of the object.
  54. let props = this.getProps(object, max, isInterestingProp);
  55. if (props.length <= max) {
  56. // There are not enough props yet (or at least, not enough props to
  57. // be able to know whether we should print "more…" or not).
  58. // Let's display also empty members and functions.
  59. props = props.concat(this.getProps(object, max, (t, value) => {
  60. return !isInterestingProp(t, value);
  61. }));
  62. }
  63. if (props.length > max) {
  64. props.pop();
  65. let objectLink = this.props.objectLink || span;
  66. props.push(Caption({
  67. object: objectLink({
  68. object: object
  69. }, (Object.keys(object).length - max) + " more…")
  70. }));
  71. } else if (props.length > 0) {
  72. // Remove the last comma.
  73. props[props.length - 1] = React.cloneElement(
  74. props[props.length - 1], { delim: "" });
  75. }
  76. return props;
  77. },
  78. getProps: function (object, max, filter) {
  79. let props = [];
  80. max = max || 3;
  81. if (!object) {
  82. return props;
  83. }
  84. // Hardcode tiny mode to avoid recursive handling.
  85. let mode = "tiny";
  86. try {
  87. for (let name in object) {
  88. if (props.length > max) {
  89. return props;
  90. }
  91. let value;
  92. try {
  93. value = object[name];
  94. } catch (exc) {
  95. continue;
  96. }
  97. let t = typeof value;
  98. if (filter(t, value)) {
  99. props.push(PropRep({
  100. mode: mode,
  101. name: name,
  102. object: value,
  103. equal: ": ",
  104. delim: ", ",
  105. }));
  106. }
  107. }
  108. } catch (err) {
  109. console.error(err);
  110. }
  111. return props;
  112. },
  113. render: function () {
  114. let object = this.props.object;
  115. let props = this.safePropIterator(object);
  116. let objectLink = this.props.objectLink || span;
  117. if (this.props.mode == "tiny" || !props.length) {
  118. return (
  119. span({className: "objectBox objectBox-object"},
  120. objectLink({className: "objectTitle"}, this.getTitle(object))
  121. )
  122. );
  123. }
  124. return (
  125. span({className: "objectBox objectBox-object"},
  126. this.getTitle(object),
  127. objectLink({
  128. className: "objectLeftBrace",
  129. object: object
  130. }, " { "),
  131. ...props,
  132. objectLink({
  133. className: "objectRightBrace",
  134. object: object
  135. }, " }")
  136. )
  137. );
  138. },
  139. });
  140. function supportsObject(object, type) {
  141. return true;
  142. }
  143. // Exports from this module
  144. exports.Obj = {
  145. rep: Obj,
  146. supportsObject: supportsObject
  147. };
  148. });