RemoteObject.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /*
  2. * Copyright (C) 2009 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @param {string|undefined} objectId
  33. * @param {string} type
  34. * @param {string|undefined} subtype
  35. * @param {*} value
  36. * @param {string=} description
  37. * @param {RuntimeAgent.ObjectPreview=} preview
  38. */
  39. WebInspector.RemoteObject = function(objectId, type, subtype, value, description, preview)
  40. {
  41. this._type = type;
  42. this._subtype = subtype;
  43. if (objectId) {
  44. // handle
  45. this._objectId = objectId;
  46. this._description = description;
  47. this._hasChildren = true;
  48. this._preview = preview;
  49. } else {
  50. // Primitive or null object.
  51. console.assert(type !== "object" || value === null);
  52. this._description = description || (value + "");
  53. this._hasChildren = false;
  54. this.value = value;
  55. }
  56. }
  57. /**
  58. * @param {number|string|boolean} value
  59. * @return {WebInspector.RemoteObject}
  60. */
  61. WebInspector.RemoteObject.fromPrimitiveValue = function(value)
  62. {
  63. return new WebInspector.RemoteObject(undefined, typeof value, undefined, value);
  64. }
  65. /**
  66. * @param {*} value
  67. * @return {WebInspector.RemoteObject}
  68. */
  69. WebInspector.RemoteObject.fromLocalObject = function(value)
  70. {
  71. return new WebInspector.LocalJSONObject(value);
  72. }
  73. /**
  74. * @param {WebInspector.DOMNode} node
  75. * @param {string} objectGroup
  76. * @param {function(?WebInspector.RemoteObject)} callback
  77. */
  78. WebInspector.RemoteObject.resolveNode = function(node, objectGroup, callback)
  79. {
  80. /**
  81. * @param {?Protocol.Error} error
  82. * @param {RuntimeAgent.RemoteObject} object
  83. */
  84. function mycallback(error, object)
  85. {
  86. if (!callback)
  87. return;
  88. if (error || !object)
  89. callback(null);
  90. else
  91. callback(WebInspector.RemoteObject.fromPayload(object));
  92. }
  93. DOMAgent.resolveNode(node.id, objectGroup, mycallback);
  94. }
  95. /**
  96. * @param {RuntimeAgent.RemoteObject=} payload
  97. * @return {WebInspector.RemoteObject}
  98. */
  99. WebInspector.RemoteObject.fromPayload = function(payload)
  100. {
  101. console.assert(typeof payload === "object", "Remote object payload should only be an object");
  102. return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
  103. }
  104. /**
  105. * @param {WebInspector.RemoteObject} remoteObject
  106. * @return {string}
  107. */
  108. WebInspector.RemoteObject.type = function(remoteObject)
  109. {
  110. if (remoteObject === null)
  111. return "null";
  112. var type = typeof remoteObject;
  113. if (type !== "object" && type !== "function")
  114. return type;
  115. return remoteObject.type;
  116. }
  117. WebInspector.RemoteObject.prototype = {
  118. /** @return {RuntimeAgent.RemoteObjectId} */
  119. get objectId()
  120. {
  121. return this._objectId;
  122. },
  123. /** @return {string} */
  124. get type()
  125. {
  126. return this._type;
  127. },
  128. /** @return {string|undefined} */
  129. get subtype()
  130. {
  131. return this._subtype;
  132. },
  133. /** @return {string|undefined} */
  134. get description()
  135. {
  136. return this._description;
  137. },
  138. /** @return {boolean} */
  139. get hasChildren()
  140. {
  141. return this._hasChildren;
  142. },
  143. /** @return {RuntimeAgent.ObjectPreview|undefined} */
  144. get preview()
  145. {
  146. return this._preview;
  147. },
  148. /**
  149. * @param {function(Array.<WebInspector.RemoteObjectProperty>, Array.<WebInspector.RemoteObjectProperty>=)} callback
  150. */
  151. getOwnProperties: function(callback)
  152. {
  153. this.doGetProperties(true, false, callback);
  154. },
  155. /**
  156. * @param {boolean} accessorPropertiesOnly
  157. * @param {function(?Array.<WebInspector.RemoteObjectProperty>, ?Array.<WebInspector.RemoteObjectProperty>)} callback
  158. */
  159. getAllProperties: function(accessorPropertiesOnly, callback)
  160. {
  161. this.doGetProperties(false, accessorPropertiesOnly, callback);
  162. },
  163. /**
  164. * @param {boolean} ownProperties
  165. * @param {boolean} accessorPropertiesOnly
  166. * @param {?function(Array.<WebInspector.RemoteObjectProperty>, ?Array.<WebInspector.RemoteObjectProperty>)} callback
  167. */
  168. doGetProperties: function(ownProperties, accessorPropertiesOnly, callback)
  169. {
  170. if (!this._objectId) {
  171. callback([], null);
  172. return;
  173. }
  174. /**
  175. * @param {?Protocol.Error} error
  176. * @param {Array.<RuntimeAgent.PropertyDescriptor>=} properties
  177. * @param {Array.<RuntimeAgent.InternalPropertyDescriptor>=} internalProperties
  178. */
  179. function remoteObjectBinder(error, properties, internalProperties)
  180. {
  181. if (error) {
  182. callback(null, null);
  183. return;
  184. }
  185. var result = [];
  186. for (var i = 0; properties && i < properties.length; ++i) {
  187. var property = properties[i];
  188. result.push(new WebInspector.RemoteObjectProperty(property.name, null, property));
  189. }
  190. var internalPropertiesResult = null;
  191. if (internalProperties) {
  192. internalPropertiesResult = [];
  193. for (var i = 0; i < internalProperties.length; i++) {
  194. var property = internalProperties[i];
  195. internalPropertiesResult.push(new WebInspector.RemoteObjectProperty(property.name, WebInspector.RemoteObject.fromPayload(property.value)));
  196. }
  197. }
  198. callback(result, internalPropertiesResult);
  199. }
  200. RuntimeAgent.getProperties(this._objectId, ownProperties, accessorPropertiesOnly, remoteObjectBinder);
  201. },
  202. /**
  203. * @param {string} name
  204. * @param {string} value
  205. * @param {function(string=)} callback
  206. */
  207. setPropertyValue: function(name, value, callback)
  208. {
  209. if (!this._objectId) {
  210. callback("Can't set a property of non-object.");
  211. return;
  212. }
  213. RuntimeAgent.evaluate.invoke({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this));
  214. /**
  215. * @param {?Protocol.Error} error
  216. * @param {RuntimeAgent.RemoteObject} result
  217. * @param {boolean=} wasThrown
  218. */
  219. function evaluatedCallback(error, result, wasThrown)
  220. {
  221. if (error || wasThrown) {
  222. callback(error || result.description);
  223. return;
  224. }
  225. this.doSetObjectPropertyValue(result, name, callback);
  226. if (result.objectId)
  227. RuntimeAgent.releaseObject(result.objectId);
  228. }
  229. },
  230. /**
  231. * @param {RuntimeAgent.RemoteObject} result
  232. * @param {string} name
  233. * @param {function(string=)} callback
  234. */
  235. doSetObjectPropertyValue: function(result, name, callback)
  236. {
  237. // This assignment may be for a regular (data) property, and for an acccessor property (with getter/setter).
  238. // Note the sensitive matter about accessor property: the property may be physically defined in some proto object,
  239. // but logically it is bound to the object in question. JavaScript passes this object to getters/setters, not the object
  240. // where property was defined; so do we.
  241. var setPropertyValueFunction = "function(a, b) { this[a] = b; }";
  242. // Special case for NaN, Infinity and -Infinity
  243. if (result.type === "number" && typeof result.value !== "number")
  244. setPropertyValueFunction = "function(a) { this[a] = " + result.description + "; }";
  245. delete result.description; // Optimize on traffic.
  246. RuntimeAgent.callFunctionOn(this._objectId, setPropertyValueFunction, [{ value:name }, result], true, undefined, undefined, propertySetCallback.bind(this));
  247. /**
  248. * @param {?Protocol.Error} error
  249. * @param {RuntimeAgent.RemoteObject} result
  250. * @param {boolean=} wasThrown
  251. */
  252. function propertySetCallback(error, result, wasThrown)
  253. {
  254. if (error || wasThrown) {
  255. callback(error || result.description);
  256. return;
  257. }
  258. callback();
  259. }
  260. },
  261. /**
  262. * @param {function(?DOMAgent.NodeId)} callback
  263. */
  264. pushNodeToFrontend: function(callback)
  265. {
  266. if (this._objectId)
  267. WebInspector.domAgent.pushNodeToFrontend(this._objectId, callback);
  268. else
  269. callback(0);
  270. },
  271. highlightAsDOMNode: function()
  272. {
  273. WebInspector.domAgent.highlightDOMNode(undefined, undefined, this._objectId);
  274. },
  275. hideDOMNodeHighlight: function()
  276. {
  277. WebInspector.domAgent.hideDOMNodeHighlight();
  278. },
  279. /**
  280. * @param {function(this:Object)} functionDeclaration
  281. * @param {Array.<RuntimeAgent.CallArgument>=} args
  282. * @param {function(?WebInspector.RemoteObject)=} callback
  283. */
  284. callFunction: function(functionDeclaration, args, callback)
  285. {
  286. /**
  287. * @param {?Protocol.Error} error
  288. * @param {RuntimeAgent.RemoteObject} result
  289. * @param {boolean=} wasThrown
  290. */
  291. function mycallback(error, result, wasThrown)
  292. {
  293. if (!callback)
  294. return;
  295. callback((error || wasThrown) ? null : WebInspector.RemoteObject.fromPayload(result));
  296. }
  297. RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, undefined, mycallback);
  298. },
  299. /**
  300. * @param {function(this:Object)} functionDeclaration
  301. * @param {Array.<RuntimeAgent.CallArgument>|undefined} args
  302. * @param {function(*)} callback
  303. */
  304. callFunctionJSON: function(functionDeclaration, args, callback)
  305. {
  306. /**
  307. * @param {?Protocol.Error} error
  308. * @param {RuntimeAgent.RemoteObject} result
  309. * @param {boolean=} wasThrown
  310. */
  311. function mycallback(error, result, wasThrown)
  312. {
  313. callback((error || wasThrown) ? null : result.value);
  314. }
  315. RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, false, mycallback);
  316. },
  317. release: function()
  318. {
  319. if (!this._objectId)
  320. return;
  321. RuntimeAgent.releaseObject(this._objectId);
  322. },
  323. /**
  324. * @return {number}
  325. */
  326. arrayLength: function()
  327. {
  328. if (this.subtype !== "array")
  329. return 0;
  330. var matches = this._description.match(/\[([0-9]+)\]/);
  331. if (!matches)
  332. return 0;
  333. return parseInt(matches[1], 10);
  334. }
  335. };
  336. /**
  337. * @param {WebInspector.RemoteObject} object
  338. * @param {boolean} flattenProtoChain
  339. * @param {function(?Array.<WebInspector.RemoteObjectProperty>, ?Array.<WebInspector.RemoteObjectProperty>)} callback
  340. */
  341. WebInspector.RemoteObject.loadFromObject = function(object, flattenProtoChain, callback)
  342. {
  343. if (flattenProtoChain)
  344. object.getAllProperties(false, callback);
  345. else
  346. WebInspector.RemoteObject.loadFromObjectPerProto(object, callback);
  347. };
  348. /**
  349. * @param {WebInspector.RemoteObject} object
  350. * @param {function(?Array.<WebInspector.RemoteObjectProperty>, ?Array.<WebInspector.RemoteObjectProperty>)} callback
  351. */
  352. WebInspector.RemoteObject.loadFromObjectPerProto = function(object, callback)
  353. {
  354. // Combines 2 asynch calls. Doesn't rely on call-back orders (some calls may be loop-back).
  355. var savedOwnProperties;
  356. var savedAccessorProperties;
  357. var savedInternalProperties;
  358. var resultCounter = 2;
  359. function processCallback()
  360. {
  361. if (--resultCounter)
  362. return;
  363. if (savedOwnProperties && savedAccessorProperties) {
  364. var combinedList = savedAccessorProperties.slice(0);
  365. for (var i = 0; i < savedOwnProperties.length; i++) {
  366. var property = savedOwnProperties[i];
  367. if (!property.isAccessorProperty())
  368. combinedList.push(property);
  369. }
  370. return callback(combinedList, savedInternalProperties ? savedInternalProperties : null);
  371. } else {
  372. callback(null, null);
  373. }
  374. }
  375. /**
  376. * @param {Array.<WebInspector.RemoteObjectProperty>} properties
  377. * @param {Array.<WebInspector.RemoteObjectProperty>=} internalProperties
  378. */
  379. function allAccessorPropertiesCallback(properties, internalProperties)
  380. {
  381. savedAccessorProperties = properties;
  382. processCallback();
  383. }
  384. /**
  385. * @param {Array.<WebInspector.RemoteObjectProperty>} properties
  386. * @param {Array.<WebInspector.RemoteObjectProperty>=} internalProperties
  387. */
  388. function ownPropertiesCallback(properties, internalProperties)
  389. {
  390. savedOwnProperties = properties;
  391. savedInternalProperties = internalProperties;
  392. processCallback();
  393. }
  394. object.getAllProperties(true, allAccessorPropertiesCallback);
  395. object.getOwnProperties(ownPropertiesCallback);
  396. };
  397. /**
  398. * @constructor
  399. * @extends {WebInspector.RemoteObject}
  400. * @param {string|undefined} objectId
  401. * @param {WebInspector.ScopeRef} scopeRef
  402. * @param {string} type
  403. * @param {string|undefined} subtype
  404. * @param {*} value
  405. * @param {string=} description
  406. * @param {RuntimeAgent.ObjectPreview=} preview
  407. */
  408. WebInspector.ScopeRemoteObject = function(objectId, scopeRef, type, subtype, value, description, preview)
  409. {
  410. WebInspector.RemoteObject.call(this, objectId, type, subtype, value, description, preview);
  411. this._scopeRef = scopeRef;
  412. this._savedScopeProperties = undefined;
  413. };
  414. /**
  415. * @param {RuntimeAgent.RemoteObject} payload
  416. * @param {WebInspector.ScopeRef=} scopeRef
  417. * @return {WebInspector.RemoteObject}
  418. */
  419. WebInspector.ScopeRemoteObject.fromPayload = function(payload, scopeRef)
  420. {
  421. if (scopeRef)
  422. return new WebInspector.ScopeRemoteObject(payload.objectId, scopeRef, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
  423. else
  424. return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
  425. }
  426. WebInspector.ScopeRemoteObject.prototype = {
  427. /**
  428. * @param {boolean} ownProperties
  429. * @param {boolean} accessorPropertiesOnly
  430. * @param {function(Array.<WebInspector.RemoteObjectProperty>, Array.<WebInspector.RemoteObjectProperty>=)} callback
  431. * @override
  432. */
  433. doGetProperties: function(ownProperties, accessorPropertiesOnly, callback)
  434. {
  435. if (accessorPropertiesOnly) {
  436. callback([], []);
  437. return;
  438. }
  439. if (this._savedScopeProperties) {
  440. // No need to reload scope variables, as the remote object never
  441. // changes its properties. If variable is updated, the properties
  442. // array is patched locally.
  443. callback(this._savedScopeProperties.slice(), []);
  444. return;
  445. }
  446. /**
  447. * @param {Array.<WebInspector.RemoteObjectProperty>} properties
  448. * @param {Array.<WebInspector.RemoteObjectProperty>=} internalProperties
  449. */
  450. function wrappedCallback(properties, internalProperties)
  451. {
  452. if (this._scopeRef && properties instanceof Array)
  453. this._savedScopeProperties = properties.slice();
  454. callback(properties, internalProperties);
  455. }
  456. WebInspector.RemoteObject.prototype.doGetProperties.call(this, ownProperties, accessorPropertiesOnly, wrappedCallback.bind(this));
  457. },
  458. /**
  459. * @override
  460. * @param {RuntimeAgent.RemoteObject} result
  461. * @param {string} name
  462. * @param {function(string=)} callback
  463. */
  464. doSetObjectPropertyValue: function(result, name, callback)
  465. {
  466. var newValue;
  467. switch (result.type) {
  468. case "undefined":
  469. newValue = {};
  470. break;
  471. case "object":
  472. case "function":
  473. newValue = { objectId: result.objectId };
  474. break;
  475. default:
  476. newValue = { value: result.value };
  477. }
  478. DebuggerAgent.setVariableValue(this._scopeRef.number, name, newValue, this._scopeRef.callFrameId, this._scopeRef.functionId, setVariableValueCallback.bind(this));
  479. /**
  480. * @param {?Protocol.Error} error
  481. */
  482. function setVariableValueCallback(error)
  483. {
  484. if (error) {
  485. callback(error);
  486. return;
  487. }
  488. if (this._savedScopeProperties) {
  489. for (var i = 0; i < this._savedScopeProperties.length; i++) {
  490. if (this._savedScopeProperties[i].name === name)
  491. this._savedScopeProperties[i].value = WebInspector.RemoteObject.fromPayload(result);
  492. }
  493. }
  494. callback();
  495. }
  496. },
  497. __proto__: WebInspector.RemoteObject.prototype
  498. };
  499. /**
  500. * Either callFrameId or functionId (exactly one) must be defined.
  501. * @constructor
  502. * @param {number} number
  503. * @param {string=} callFrameId
  504. * @param {string=} functionId
  505. */
  506. WebInspector.ScopeRef = function(number, callFrameId, functionId)
  507. {
  508. this.number = number;
  509. this.callFrameId = callFrameId;
  510. this.functionId = functionId;
  511. }
  512. /**
  513. * @constructor
  514. * @param {string} name
  515. * @param {?WebInspector.RemoteObject} value
  516. * @param {RuntimeAgent.PropertyDescriptor=} descriptor
  517. */
  518. WebInspector.RemoteObjectProperty = function(name, value, descriptor)
  519. {
  520. this.name = name;
  521. this.enumerable = descriptor ? !!descriptor.enumerable : true;
  522. this.writable = descriptor ? !!descriptor.writable : true;
  523. if (value === null && descriptor) {
  524. if (descriptor.value)
  525. this.value = WebInspector.RemoteObject.fromPayload(descriptor.value)
  526. if (descriptor.get && descriptor.get.type !== "undefined")
  527. this.getter = WebInspector.RemoteObject.fromPayload(descriptor.get);
  528. if (descriptor.set && descriptor.set.type !== "undefined")
  529. this.setter = WebInspector.RemoteObject.fromPayload(descriptor.set);
  530. } else {
  531. this.value = value;
  532. }
  533. if (descriptor) {
  534. this.isOwn = descriptor.isOwn;
  535. this.wasThrown = !!descriptor.wasThrown;
  536. }
  537. }
  538. WebInspector.RemoteObjectProperty.prototype = {
  539. isAccessorProperty: function()
  540. {
  541. return this.getter || this.setter;
  542. }
  543. };
  544. /**
  545. * @param {string} name
  546. * @param {string} value
  547. * @return {WebInspector.RemoteObjectProperty}
  548. */
  549. WebInspector.RemoteObjectProperty.fromPrimitiveValue = function(name, value)
  550. {
  551. return new WebInspector.RemoteObjectProperty(name, WebInspector.RemoteObject.fromPrimitiveValue(value));
  552. }
  553. /**
  554. * @param {string} name
  555. * @param {WebInspector.RemoteObject} value
  556. * @return {WebInspector.RemoteObjectProperty}
  557. */
  558. WebInspector.RemoteObjectProperty.fromScopeValue = function(name, value)
  559. {
  560. var result = new WebInspector.RemoteObjectProperty(name, value);
  561. result.writable = false;
  562. return result;
  563. }
  564. // The below is a wrapper around a local object that provides an interface comaptible
  565. // with RemoteObject, to be used by the UI code (primarily ObjectPropertiesSection).
  566. // Note that only JSON-compliant objects are currently supported, as there's no provision
  567. // for traversing prototypes, extracting class names via constuctor, handling properties
  568. // or functions.
  569. /**
  570. * @constructor
  571. * @extends {WebInspector.RemoteObject}
  572. * @param {*} value
  573. */
  574. WebInspector.LocalJSONObject = function(value)
  575. {
  576. this._value = value;
  577. }
  578. WebInspector.LocalJSONObject.prototype = {
  579. /**
  580. * @return {string}
  581. */
  582. get description()
  583. {
  584. if (this._cachedDescription)
  585. return this._cachedDescription;
  586. if (this.type === "object") {
  587. switch (this.subtype) {
  588. case "array":
  589. function formatArrayItem(property)
  590. {
  591. return property.value.description;
  592. }
  593. this._cachedDescription = this._concatenate("[", "]", formatArrayItem);
  594. break;
  595. case "date":
  596. this._cachedDescription = "" + this._value;
  597. break;
  598. case "null":
  599. this._cachedDescription = "null";
  600. break;
  601. default:
  602. function formatObjectItem(property)
  603. {
  604. return property.name + ":" + property.value.description;
  605. }
  606. this._cachedDescription = this._concatenate("{", "}", formatObjectItem);
  607. }
  608. } else
  609. this._cachedDescription = String(this._value);
  610. return this._cachedDescription;
  611. },
  612. /**
  613. * @param {string} prefix
  614. * @param {string} suffix
  615. * @return {string}
  616. */
  617. _concatenate: function(prefix, suffix, formatProperty)
  618. {
  619. const previewChars = 100;
  620. var buffer = prefix;
  621. var children = this._children();
  622. for (var i = 0; i < children.length; ++i) {
  623. var itemDescription = formatProperty(children[i]);
  624. if (buffer.length + itemDescription.length > previewChars) {
  625. buffer += ",\u2026";
  626. break;
  627. }
  628. if (i)
  629. buffer += ", ";
  630. buffer += itemDescription;
  631. }
  632. buffer += suffix;
  633. return buffer;
  634. },
  635. /**
  636. * @return {string}
  637. */
  638. get type()
  639. {
  640. return typeof this._value;
  641. },
  642. /**
  643. * @return {string|undefined}
  644. */
  645. get subtype()
  646. {
  647. if (this._value === null)
  648. return "null";
  649. if (this._value instanceof Array)
  650. return "array";
  651. if (this._value instanceof Date)
  652. return "date";
  653. return undefined;
  654. },
  655. /**
  656. * @return {boolean}
  657. */
  658. get hasChildren()
  659. {
  660. if ((typeof this._value !== "object") || (this._value === null))
  661. return false;
  662. return !!Object.keys(/** @type {!Object} */ (this._value)).length;
  663. },
  664. /**
  665. * @param {function(Array.<WebInspector.RemoteObjectProperty>)} callback
  666. */
  667. getOwnProperties: function(callback)
  668. {
  669. callback(this._children());
  670. },
  671. /**
  672. * @param {boolean} accessorPropertiesOnly
  673. * @param {function(Array.<WebInspector.RemoteObjectProperty>)} callback
  674. */
  675. getAllProperties: function(accessorPropertiesOnly, callback)
  676. {
  677. if (accessorPropertiesOnly)
  678. callback([]);
  679. else
  680. callback(this._children());
  681. },
  682. /**
  683. * @return {Array.<WebInspector.RemoteObjectProperty>}
  684. */
  685. _children: function()
  686. {
  687. if (!this.hasChildren)
  688. return [];
  689. var value = /** @type {!Object} */ (this._value);
  690. function buildProperty(propName)
  691. {
  692. return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName]));
  693. }
  694. if (!this._cachedChildren)
  695. this._cachedChildren = Object.keys(value).map(buildProperty.bind(this));
  696. return this._cachedChildren;
  697. },
  698. /**
  699. * @return {boolean}
  700. */
  701. isError: function()
  702. {
  703. return false;
  704. },
  705. /**
  706. * @return {number}
  707. */
  708. arrayLength: function()
  709. {
  710. return this._value instanceof Array ? this._value.length : 0;
  711. }
  712. }