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/** 32 * This may not be an interface due to "instanceof WebInspector.RemoteObject" checks in the code. 33 * 34 * @constructor 35 */ 36WebInspector.RemoteObject = function() { } 37 38WebInspector.RemoteObject.prototype = { 39 /** @return {string} */ 40 get type() 41 { 42 throw "Not implemented"; 43 }, 44 45 /** @return {string|undefined} */ 46 get subtype() 47 { 48 throw "Not implemented"; 49 }, 50 51 /** @return {string|undefined} */ 52 get description() 53 { 54 throw "Not implemented"; 55 }, 56 57 /** @return {boolean} */ 58 get hasChildren() 59 { 60 throw "Not implemented"; 61 }, 62 63 /** 64 * @return {number} 65 */ 66 arrayLength: function() 67 { 68 throw "Not implemented"; 69 }, 70 71 /** 72 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 73 */ 74 getOwnProperties: function(callback) 75 { 76 throw "Not implemented"; 77 }, 78 79 /** 80 * @param {boolean} accessorPropertiesOnly 81 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 82 */ 83 getAllProperties: function(accessorPropertiesOnly, callback) 84 { 85 throw "Not implemented"; 86 }, 87 88 /** 89 * @param {string} name 90 * @param {function(string=)} callback 91 */ 92 deleteProperty: function(name, callback) 93 { 94 throw "Not implemented"; 95 }, 96 97 /** 98 * @param {function(this:Object, ...)} functionDeclaration 99 * @param {!Array.<!RuntimeAgent.CallArgument>=} args 100 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback 101 */ 102 callFunction: function(functionDeclaration, args, callback) 103 { 104 throw "Not implemented"; 105 }, 106 107 /** 108 * @param {function(this:Object)} functionDeclaration 109 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args 110 * @param {function(*)} callback 111 */ 112 callFunctionJSON: function(functionDeclaration, args, callback) 113 { 114 throw "Not implemented"; 115 }, 116 117 /** 118 * @return {!WebInspector.Target} 119 */ 120 target: function() 121 { 122 throw new Error("Target-less object"); 123 }, 124 125 /** 126 * @return {boolean} 127 */ 128 isNode: function() 129 { 130 return false; 131 }, 132 133 reveal: function() 134 { 135 WebInspector.Revealer.reveal(this); 136 }, 137 138 /** 139 * @param {function(?DebuggerAgent.FunctionDetails)} callback 140 */ 141 functionDetails: function(callback) 142 { 143 callback(null); 144 } 145} 146 147/** 148 * @param {*} value 149 * @return {!WebInspector.RemoteObject} 150 */ 151WebInspector.RemoteObject.fromLocalObject = function(value) 152{ 153 return new WebInspector.LocalJSONObject(value); 154} 155 156/** 157 * @param {!WebInspector.RemoteObject} remoteObject 158 * @return {string} 159 */ 160WebInspector.RemoteObject.type = function(remoteObject) 161{ 162 if (remoteObject === null) 163 return "null"; 164 165 var type = typeof remoteObject; 166 if (type !== "object" && type !== "function") 167 return type; 168 169 return remoteObject.type; 170} 171 172/** 173 * @param {!RuntimeAgent.RemoteObject|!WebInspector.RemoteObject} remoteObject 174 * @return {!RuntimeAgent.CallArgument} 175 */ 176WebInspector.RemoteObject.toCallArgument = function(remoteObject) 177{ 178 var type = /** @type {!RuntimeAgent.CallArgumentType.<string>} */ (remoteObject.type); 179 var value = remoteObject.value; 180 181 // Handle special numbers: NaN, Infinity, -Infinity, -0. 182 if (type === "number") { 183 switch (remoteObject.description) { 184 case "NaN": 185 case "Infinity": 186 case "-Infinity": 187 case "-0": 188 value = remoteObject.description; 189 break; 190 } 191 } 192 193 return { 194 value: value, 195 objectId: remoteObject.objectId, 196 type: type 197 }; 198} 199 200/** 201 * @constructor 202 * @extends {WebInspector.RemoteObject} 203 * @param {!WebInspector.Target} target 204 * @param {string|undefined} objectId 205 * @param {string} type 206 * @param {string|undefined} subtype 207 * @param {*} value 208 * @param {string=} description 209 * @param {!RuntimeAgent.ObjectPreview=} preview 210 */ 211WebInspector.RemoteObjectImpl = function(target, objectId, type, subtype, value, description, preview) 212{ 213 WebInspector.RemoteObject.call(this); 214 215 this._target = target; 216 this._runtimeAgent = target.runtimeAgent(); 217 this._domModel = target.domModel; 218 219 this._type = type; 220 this._subtype = subtype; 221 if (objectId) { 222 // handle 223 this._objectId = objectId; 224 this._description = description; 225 this._hasChildren = (type !== "symbol"); 226 this._preview = preview; 227 } else { 228 // Primitive or null object. 229 console.assert(type !== "object" || value === null); 230 this._description = description || (value + ""); 231 this._hasChildren = false; 232 // Handle special numbers: NaN, Infinity, -Infinity, -0. 233 if (type === "number" && typeof value !== "number") 234 this.value = Number(value); 235 else 236 this.value = value; 237 } 238} 239 240WebInspector.RemoteObjectImpl.prototype = { 241 /** @return {!RuntimeAgent.RemoteObjectId} */ 242 get objectId() 243 { 244 return this._objectId; 245 }, 246 247 /** @return {string} */ 248 get type() 249 { 250 return this._type; 251 }, 252 253 /** @return {string|undefined} */ 254 get subtype() 255 { 256 return this._subtype; 257 }, 258 259 /** @return {string|undefined} */ 260 get description() 261 { 262 return this._description; 263 }, 264 265 /** @return {boolean} */ 266 get hasChildren() 267 { 268 return this._hasChildren; 269 }, 270 271 /** @return {!RuntimeAgent.ObjectPreview|undefined} */ 272 get preview() 273 { 274 return this._preview; 275 }, 276 277 /** 278 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 279 */ 280 getOwnProperties: function(callback) 281 { 282 this.doGetProperties(true, false, callback); 283 }, 284 285 /** 286 * @param {boolean} accessorPropertiesOnly 287 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 288 */ 289 getAllProperties: function(accessorPropertiesOnly, callback) 290 { 291 this.doGetProperties(false, accessorPropertiesOnly, callback); 292 }, 293 294 /** 295 * @param {!Array.<string>} propertyPath 296 * @param {function(?WebInspector.RemoteObject, boolean=)} callback 297 */ 298 getProperty: function(propertyPath, callback) 299 { 300 /** 301 * @param {string} arrayStr 302 * @suppressReceiverCheck 303 * @this {Object} 304 */ 305 function remoteFunction(arrayStr) 306 { 307 var result = this; 308 var properties = JSON.parse(arrayStr); 309 for (var i = 0, n = properties.length; i < n; ++i) 310 result = result[properties[i]]; 311 return result; 312 } 313 314 var args = [{ value: JSON.stringify(propertyPath) }]; 315 this.callFunction(remoteFunction, args, callback); 316 }, 317 318 /** 319 * @param {boolean} ownProperties 320 * @param {boolean} accessorPropertiesOnly 321 * @param {?function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 322 */ 323 doGetProperties: function(ownProperties, accessorPropertiesOnly, callback) 324 { 325 if (!this._objectId) { 326 callback(null, null); 327 return; 328 } 329 330 /** 331 * @param {?Protocol.Error} error 332 * @param {!Array.<!RuntimeAgent.PropertyDescriptor>} properties 333 * @param {!Array.<!RuntimeAgent.InternalPropertyDescriptor>=} internalProperties 334 * @this {WebInspector.RemoteObjectImpl} 335 */ 336 function remoteObjectBinder(error, properties, internalProperties) 337 { 338 if (error) { 339 callback(null, null); 340 return; 341 } 342 var result = []; 343 for (var i = 0; properties && i < properties.length; ++i) { 344 var property = properties[i]; 345 var propertyValue = property.value ? this._target.runtimeModel.createRemoteObject(property.value) : null; 346 var propertySymbol = property.symbol ? this._target.runtimeModel.createRemoteObject(property.symbol) : null; 347 var remoteProperty = new WebInspector.RemoteObjectProperty(property.name, propertyValue, 348 !!property.enumerable, !!property.writable, !!property.isOwn, !!property.wasThrown, propertySymbol); 349 350 if (typeof property.value === "undefined") { 351 if (property.get && property.get.type !== "undefined") 352 remoteProperty.getter = this._target.runtimeModel.createRemoteObject(property.get); 353 if (property.set && property.set.type !== "undefined") 354 remoteProperty.setter = this._target.runtimeModel.createRemoteObject(property.set); 355 } 356 357 result.push(remoteProperty); 358 } 359 var internalPropertiesResult = null; 360 if (internalProperties) { 361 internalPropertiesResult = []; 362 for (var i = 0; i < internalProperties.length; i++) { 363 var property = internalProperties[i]; 364 if (!property.value) 365 continue; 366 var propertyValue = this._target.runtimeModel.createRemoteObject(property.value); 367 internalPropertiesResult.push(new WebInspector.RemoteObjectProperty(property.name, propertyValue, true, false)); 368 } 369 } 370 callback(result, internalPropertiesResult); 371 } 372 this._runtimeAgent.getProperties(this._objectId, ownProperties, accessorPropertiesOnly, remoteObjectBinder.bind(this)); 373 }, 374 375 /** 376 * @param {string} name 377 * @param {string} value 378 * @param {function(string=)} callback 379 */ 380 setPropertyValue: function(name, value, callback) 381 { 382 if (!this._objectId) { 383 callback("Can't set a property of non-object."); 384 return; 385 } 386 387 this._runtimeAgent.invoke_evaluate({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this)); 388 389 /** 390 * @param {?Protocol.Error} error 391 * @param {!RuntimeAgent.RemoteObject} result 392 * @param {boolean=} wasThrown 393 * @this {WebInspector.RemoteObject} 394 */ 395 function evaluatedCallback(error, result, wasThrown) 396 { 397 if (error || wasThrown) { 398 callback(error || result.description); 399 return; 400 } 401 402 this.doSetObjectPropertyValue(result, name, callback); 403 404 if (result.objectId) 405 this._runtimeAgent.releaseObject(result.objectId); 406 } 407 }, 408 409 /** 410 * @param {!RuntimeAgent.RemoteObject} result 411 * @param {string} name 412 * @param {function(string=)} callback 413 */ 414 doSetObjectPropertyValue: function(result, name, callback) 415 { 416 // This assignment may be for a regular (data) property, and for an acccessor property (with getter/setter). 417 // Note the sensitive matter about accessor property: the property may be physically defined in some proto object, 418 // but logically it is bound to the object in question. JavaScript passes this object to getters/setters, not the object 419 // where property was defined; so do we. 420 var setPropertyValueFunction = "function(a, b) { this[a] = b; }"; 421 422 var argv = [{ value: name }, WebInspector.RemoteObject.toCallArgument(result)] 423 this._runtimeAgent.callFunctionOn(this._objectId, setPropertyValueFunction, argv, true, undefined, undefined, propertySetCallback); 424 425 /** 426 * @param {?Protocol.Error} error 427 * @param {!RuntimeAgent.RemoteObject} result 428 * @param {boolean=} wasThrown 429 */ 430 function propertySetCallback(error, result, wasThrown) 431 { 432 if (error || wasThrown) { 433 callback(error || result.description); 434 return; 435 } 436 callback(); 437 } 438 }, 439 440 /** 441 * @param {string} name 442 * @param {function(string=)} callback 443 */ 444 deleteProperty: function(name, callback) 445 { 446 if (!this._objectId) { 447 callback("Can't delete a property of non-object."); 448 return; 449 } 450 451 var deletePropertyFunction = "function(a) { delete this[a]; return !(a in this); }"; 452 this._runtimeAgent.callFunctionOn(this._objectId, deletePropertyFunction, [{ value: name }], true, undefined, undefined, deletePropertyCallback); 453 454 /** 455 * @param {?Protocol.Error} error 456 * @param {!RuntimeAgent.RemoteObject} result 457 * @param {boolean=} wasThrown 458 */ 459 function deletePropertyCallback(error, result, wasThrown) 460 { 461 if (error || wasThrown) { 462 callback(error || result.description); 463 return; 464 } 465 if (!result.value) 466 callback("Failed to delete property."); 467 else 468 callback(); 469 } 470 }, 471 472 /** 473 * @param {function(?WebInspector.DOMNode)} callback 474 */ 475 pushNodeToFrontend: function(callback) 476 { 477 if (this.isNode()) 478 this._domModel.pushNodeToFrontend(this._objectId, callback); 479 else 480 callback(null); 481 }, 482 483 highlightAsDOMNode: function() 484 { 485 this._domModel.highlightDOMNode(undefined, undefined, this._objectId); 486 }, 487 488 hideDOMNodeHighlight: function() 489 { 490 this._domModel.hideDOMNodeHighlight(); 491 }, 492 493 /** 494 * @param {function(this:Object, ...)} functionDeclaration 495 * @param {!Array.<!RuntimeAgent.CallArgument>=} args 496 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback 497 */ 498 callFunction: function(functionDeclaration, args, callback) 499 { 500 /** 501 * @param {?Protocol.Error} error 502 * @param {!RuntimeAgent.RemoteObject} result 503 * @param {boolean=} wasThrown 504 * @this {WebInspector.RemoteObjectImpl} 505 */ 506 function mycallback(error, result, wasThrown) 507 { 508 if (!callback) 509 return; 510 if (error) 511 callback(null, false); 512 else 513 callback(this.target().runtimeModel.createRemoteObject(result), wasThrown); 514 } 515 516 this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, undefined, mycallback.bind(this)); 517 }, 518 519 /** 520 * @param {function(this:Object)} functionDeclaration 521 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args 522 * @param {function(*)} callback 523 */ 524 callFunctionJSON: function(functionDeclaration, args, callback) 525 { 526 /** 527 * @param {?Protocol.Error} error 528 * @param {!RuntimeAgent.RemoteObject} result 529 * @param {boolean=} wasThrown 530 */ 531 function mycallback(error, result, wasThrown) 532 { 533 callback((error || wasThrown) ? null : result.value); 534 } 535 536 this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, false, mycallback); 537 }, 538 539 release: function() 540 { 541 if (!this._objectId) 542 return; 543 this._runtimeAgent.releaseObject(this._objectId); 544 }, 545 546 /** 547 * @return {number} 548 */ 549 arrayLength: function() 550 { 551 if (this.subtype !== "array") 552 return 0; 553 554 var matches = this._description.match(/\[([0-9]+)\]/); 555 if (!matches) 556 return 0; 557 return parseInt(matches[1], 10); 558 }, 559 560 /** 561 * @return {!WebInspector.Target} 562 */ 563 target: function() 564 { 565 return this._target; 566 }, 567 568 /** 569 * @return {boolean} 570 */ 571 isNode: function() 572 { 573 return !!this._objectId && this.type === "object" && this.subtype === "node"; 574 }, 575 576 /** 577 * @param {function(?DebuggerAgent.FunctionDetails)} callback 578 */ 579 functionDetails: function(callback) 580 { 581 this._target.debuggerModel.functionDetails(this, callback) 582 }, 583 584 __proto__: WebInspector.RemoteObject.prototype 585}; 586 587 588/** 589 * @param {!WebInspector.RemoteObject} object 590 * @param {boolean} flattenProtoChain 591 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 592 */ 593WebInspector.RemoteObject.loadFromObject = function(object, flattenProtoChain, callback) 594{ 595 if (flattenProtoChain) 596 object.getAllProperties(false, callback); 597 else 598 WebInspector.RemoteObject.loadFromObjectPerProto(object, callback); 599}; 600 601/** 602 * @param {!WebInspector.RemoteObject} object 603 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 604 */ 605WebInspector.RemoteObject.loadFromObjectPerProto = function(object, callback) 606{ 607 // Combines 2 asynch calls. Doesn't rely on call-back orders (some calls may be loop-back). 608 var savedOwnProperties; 609 var savedAccessorProperties; 610 var savedInternalProperties; 611 var resultCounter = 2; 612 613 function processCallback() 614 { 615 if (--resultCounter) 616 return; 617 if (savedOwnProperties && savedAccessorProperties) { 618 var combinedList = savedAccessorProperties.slice(0); 619 for (var i = 0; i < savedOwnProperties.length; i++) { 620 var property = savedOwnProperties[i]; 621 if (!property.isAccessorProperty()) 622 combinedList.push(property); 623 } 624 return callback(combinedList, savedInternalProperties ? savedInternalProperties : null); 625 } else { 626 callback(null, null); 627 } 628 } 629 630 /** 631 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties 632 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties 633 */ 634 function allAccessorPropertiesCallback(properties, internalProperties) 635 { 636 savedAccessorProperties = properties; 637 processCallback(); 638 } 639 640 /** 641 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties 642 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties 643 */ 644 function ownPropertiesCallback(properties, internalProperties) 645 { 646 savedOwnProperties = properties; 647 savedInternalProperties = internalProperties; 648 processCallback(); 649 } 650 651 object.getAllProperties(true, allAccessorPropertiesCallback); 652 object.getOwnProperties(ownPropertiesCallback); 653}; 654 655 656/** 657 * @constructor 658 * @extends {WebInspector.RemoteObjectImpl} 659 * @param {!WebInspector.Target} target 660 * @param {string|undefined} objectId 661 * @param {!WebInspector.ScopeRef} scopeRef 662 * @param {string} type 663 * @param {string|undefined} subtype 664 * @param {*} value 665 * @param {string=} description 666 * @param {!RuntimeAgent.ObjectPreview=} preview 667 */ 668WebInspector.ScopeRemoteObject = function(target, objectId, scopeRef, type, subtype, value, description, preview) 669{ 670 WebInspector.RemoteObjectImpl.call(this, target, objectId, type, subtype, value, description, preview); 671 this._scopeRef = scopeRef; 672 this._savedScopeProperties = undefined; 673 this._debuggerAgent = target.debuggerAgent(); 674}; 675 676WebInspector.ScopeRemoteObject.prototype = { 677 /** 678 * @param {boolean} ownProperties 679 * @param {boolean} accessorPropertiesOnly 680 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 681 * @override 682 */ 683 doGetProperties: function(ownProperties, accessorPropertiesOnly, callback) 684 { 685 if (accessorPropertiesOnly) { 686 callback([], []); 687 return; 688 } 689 if (this._savedScopeProperties) { 690 // No need to reload scope variables, as the remote object never 691 // changes its properties. If variable is updated, the properties 692 // array is patched locally. 693 callback(this._savedScopeProperties.slice(), []); 694 return; 695 } 696 697 /** 698 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties 699 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties 700 * @this {WebInspector.ScopeRemoteObject} 701 */ 702 function wrappedCallback(properties, internalProperties) 703 { 704 if (this._scopeRef && properties instanceof Array) 705 this._savedScopeProperties = properties.slice(); 706 callback(properties, internalProperties); 707 } 708 709 WebInspector.RemoteObjectImpl.prototype.doGetProperties.call(this, ownProperties, accessorPropertiesOnly, wrappedCallback.bind(this)); 710 }, 711 712 /** 713 * @override 714 * @param {!RuntimeAgent.RemoteObject} result 715 * @param {string} name 716 * @param {function(string=)} callback 717 */ 718 doSetObjectPropertyValue: function(result, name, callback) 719 { 720 this._debuggerAgent.setVariableValue(this._scopeRef.number, name, WebInspector.RemoteObject.toCallArgument(result), this._scopeRef.callFrameId, this._scopeRef.functionId, setVariableValueCallback.bind(this)); 721 722 /** 723 * @param {?Protocol.Error} error 724 * @this {WebInspector.ScopeRemoteObject} 725 */ 726 function setVariableValueCallback(error) 727 { 728 if (error) { 729 callback(error); 730 return; 731 } 732 if (this._savedScopeProperties) { 733 for (var i = 0; i < this._savedScopeProperties.length; i++) { 734 if (this._savedScopeProperties[i].name === name) 735 this._savedScopeProperties[i].value = this._target.runtimeModel.createRemoteObject(result); 736 } 737 } 738 callback(); 739 } 740 }, 741 742 __proto__: WebInspector.RemoteObjectImpl.prototype 743}; 744 745/** 746 * Either callFrameId or functionId (exactly one) must be defined. 747 * @constructor 748 * @param {number} number 749 * @param {string=} callFrameId 750 * @param {string=} functionId 751 */ 752WebInspector.ScopeRef = function(number, callFrameId, functionId) 753{ 754 this.number = number; 755 this.callFrameId = callFrameId; 756 this.functionId = functionId; 757} 758 759/** 760 * @constructor 761 * @param {string} name 762 * @param {?WebInspector.RemoteObject} value 763 * @param {boolean=} enumerable 764 * @param {boolean=} writable 765 * @param {boolean=} isOwn 766 * @param {boolean=} wasThrown 767 * @param {?WebInspector.RemoteObject=} symbol 768 */ 769WebInspector.RemoteObjectProperty = function(name, value, enumerable, writable, isOwn, wasThrown, symbol) 770{ 771 this.name = name; 772 if (value !== null) 773 this.value = value; 774 this.enumerable = typeof enumerable !== "undefined" ? enumerable : true; 775 this.writable = typeof writable !== "undefined" ? writable : true; 776 this.isOwn = !!isOwn; 777 this.wasThrown = !!wasThrown; 778 if (symbol) 779 this.symbol = symbol; 780} 781 782WebInspector.RemoteObjectProperty.prototype = { 783 /** 784 * @return {boolean} 785 */ 786 isAccessorProperty: function() 787 { 788 return !!(this.getter || this.setter); 789 } 790}; 791 792// Below is a wrapper around a local object that implements the RemoteObject interface, 793// which can be used by the UI code (primarily ObjectPropertiesSection). 794// Note that only JSON-compliant objects are currently supported, as there's no provision 795// for traversing prototypes, extracting class names via constructor, handling properties 796// or functions. 797 798/** 799 * @constructor 800 * @extends {WebInspector.RemoteObject} 801 * @param {*} value 802 */ 803WebInspector.LocalJSONObject = function(value) 804{ 805 WebInspector.RemoteObject.call(this); 806 this._value = value; 807} 808 809WebInspector.LocalJSONObject.prototype = { 810 /** 811 * @return {string} 812 */ 813 get description() 814 { 815 if (this._cachedDescription) 816 return this._cachedDescription; 817 818 /** 819 * @param {!WebInspector.RemoteObjectProperty} property 820 */ 821 function formatArrayItem(property) 822 { 823 return property.value.description; 824 } 825 826 /** 827 * @param {!WebInspector.RemoteObjectProperty} property 828 */ 829 function formatObjectItem(property) 830 { 831 return property.name + ":" + property.value.description; 832 } 833 834 if (this.type === "object") { 835 switch (this.subtype) { 836 case "array": 837 this._cachedDescription = this._concatenate("[", "]", formatArrayItem); 838 break; 839 case "date": 840 this._cachedDescription = "" + this._value; 841 break; 842 case "null": 843 this._cachedDescription = "null"; 844 break; 845 default: 846 this._cachedDescription = this._concatenate("{", "}", formatObjectItem); 847 } 848 } else 849 this._cachedDescription = String(this._value); 850 851 return this._cachedDescription; 852 }, 853 854 /** 855 * @param {string} prefix 856 * @param {string} suffix 857 * @param {function (!WebInspector.RemoteObjectProperty)} formatProperty 858 * @return {string} 859 */ 860 _concatenate: function(prefix, suffix, formatProperty) 861 { 862 const previewChars = 100; 863 864 var buffer = prefix; 865 var children = this._children(); 866 for (var i = 0; i < children.length; ++i) { 867 var itemDescription = formatProperty(children[i]); 868 if (buffer.length + itemDescription.length > previewChars) { 869 buffer += ",\u2026"; 870 break; 871 } 872 if (i) 873 buffer += ", "; 874 buffer += itemDescription; 875 } 876 buffer += suffix; 877 return buffer; 878 }, 879 880 /** 881 * @return {string} 882 */ 883 get type() 884 { 885 return typeof this._value; 886 }, 887 888 /** 889 * @return {string|undefined} 890 */ 891 get subtype() 892 { 893 if (this._value === null) 894 return "null"; 895 896 if (this._value instanceof Array) 897 return "array"; 898 899 if (this._value instanceof Date) 900 return "date"; 901 902 return undefined; 903 }, 904 905 /** 906 * @return {boolean} 907 */ 908 get hasChildren() 909 { 910 if ((typeof this._value !== "object") || (this._value === null)) 911 return false; 912 return !!Object.keys(/** @type {!Object} */ (this._value)).length; 913 }, 914 915 /** 916 * @param {function(!Array.<!WebInspector.RemoteObjectProperty>)} callback 917 */ 918 getOwnProperties: function(callback) 919 { 920 callback(this._children()); 921 }, 922 923 /** 924 * @param {boolean} accessorPropertiesOnly 925 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback 926 */ 927 getAllProperties: function(accessorPropertiesOnly, callback) 928 { 929 if (accessorPropertiesOnly) 930 callback([], null); 931 else 932 callback(this._children(), null); 933 }, 934 935 /** 936 * @return {!Array.<!WebInspector.RemoteObjectProperty>} 937 */ 938 _children: function() 939 { 940 if (!this.hasChildren) 941 return []; 942 var value = /** @type {!Object} */ (this._value); 943 944 /** 945 * @param {string} propName 946 * @this {WebInspector.LocalJSONObject} 947 */ 948 function buildProperty(propName) 949 { 950 return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName])); 951 } 952 if (!this._cachedChildren) 953 this._cachedChildren = Object.keys(value).map(buildProperty.bind(this)); 954 return this._cachedChildren; 955 }, 956 957 /** 958 * @return {boolean} 959 */ 960 isError: function() 961 { 962 return false; 963 }, 964 965 /** 966 * @return {number} 967 */ 968 arrayLength: function() 969 { 970 return this._value instanceof Array ? this._value.length : 0; 971 }, 972 973 /** 974 * @param {function(this:Object, ...)} functionDeclaration 975 * @param {!Array.<!RuntimeAgent.CallArgument>=} args 976 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback 977 */ 978 callFunction: function(functionDeclaration, args, callback) 979 { 980 var target = /** @type {?Object} */ (this._value); 981 var rawArgs = args ? args.map(function(arg) {return arg.value;}) : []; 982 983 var result; 984 var wasThrown = false; 985 try { 986 result = functionDeclaration.apply(target, rawArgs); 987 } catch (e) { 988 wasThrown = true; 989 } 990 991 if (!callback) 992 return; 993 callback(WebInspector.RemoteObject.fromLocalObject(result), wasThrown); 994 }, 995 996 /** 997 * @param {function(this:Object)} functionDeclaration 998 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args 999 * @param {function(*)} callback 1000 */ 1001 callFunctionJSON: function(functionDeclaration, args, callback) 1002 { 1003 var target = /** @type {?Object} */ (this._value); 1004 var rawArgs = args ? args.map(function(arg) {return arg.value;}) : []; 1005 1006 var result; 1007 try { 1008 result = functionDeclaration.apply(target, rawArgs); 1009 } catch (e) { 1010 result = null; 1011 } 1012 1013 callback(result); 1014 }, 1015 1016 __proto__: WebInspector.RemoteObject.prototype 1017} 1018