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