2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 * This may not be an interface due to "instanceof WebInspector.RemoteObject" checks in the code.
36 WebInspector.RemoteObject = function() { }
38 WebInspector.RemoteObject.prototype = {
39 /** @return {string} */
42 throw "Not implemented";
45 /** @return {string|undefined} */
48 throw "Not implemented";
51 /** @return {string|undefined} */
54 throw "Not implemented";
57 /** @return {boolean} */
60 throw "Not implemented";
66 arrayLength: function()
68 throw "Not implemented";
72 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
74 getOwnProperties: function(callback)
76 throw "Not implemented";
80 * @param {boolean} accessorPropertiesOnly
81 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
83 getAllProperties: function(accessorPropertiesOnly, callback)
85 throw "Not implemented";
89 * @param {function(this:Object, ...)} functionDeclaration
90 * @param {!Array.<!RuntimeAgent.CallArgument>=} args
91 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback
93 callFunction: function(functionDeclaration, args, callback)
95 throw "Not implemented";
99 * @param {function(this:Object)} functionDeclaration
100 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args
101 * @param {function(*)} callback
103 callFunctionJSON: function(functionDeclaration, args, callback)
105 throw "Not implemented";
109 * @return {!WebInspector.Target}
113 throw new Error("Target-less object");
126 WebInspector.Revealer.reveal(this);
130 * @param {function(?DebuggerAgent.FunctionDetails)} callback
132 functionDetails: function(callback)
140 * @return {!WebInspector.RemoteObject}
142 WebInspector.RemoteObject.fromLocalObject = function(value)
144 return new WebInspector.LocalJSONObject(value);
148 * @param {!WebInspector.RemoteObject} remoteObject
151 WebInspector.RemoteObject.type = function(remoteObject)
153 if (remoteObject === null)
156 var type = typeof remoteObject;
157 if (type !== "object" && type !== "function")
160 return remoteObject.type;
164 * @param {!RuntimeAgent.RemoteObject|!WebInspector.RemoteObject} remoteObject
165 * @return {!RuntimeAgent.CallArgument}
167 WebInspector.RemoteObject.toCallArgument = function(remoteObject)
169 var type = /** @type {!RuntimeAgent.CallArgumentType.<string>} */ (remoteObject.type);
170 var value = remoteObject.value;
172 // Handle special numbers: NaN, Infinity, -Infinity, -0.
173 if (type === "number") {
174 switch (remoteObject.description) {
179 value = remoteObject.description;
186 objectId: remoteObject.objectId,
193 * @extends {WebInspector.RemoteObject}
194 * @param {!WebInspector.Target} target
195 * @param {string|undefined} objectId
196 * @param {string} type
197 * @param {string|undefined} subtype
199 * @param {string=} description
200 * @param {!RuntimeAgent.ObjectPreview=} preview
202 WebInspector.RemoteObjectImpl = function(target, objectId, type, subtype, value, description, preview)
204 WebInspector.RemoteObject.call(this);
206 this._target = target;
207 this._runtimeAgent = target.runtimeAgent();
208 this._domModel = target.domModel;
211 this._subtype = subtype;
214 this._objectId = objectId;
215 this._description = description;
216 this._hasChildren = true;
217 this._preview = preview;
219 // Primitive or null object.
220 console.assert(type !== "object" || value === null);
221 this._description = description || (value + "");
222 this._hasChildren = false;
223 // Handle special numbers: NaN, Infinity, -Infinity, -0.
224 if (type === "number" && typeof value !== "number")
225 this.value = Number(value);
231 WebInspector.RemoteObjectImpl.prototype = {
232 /** @return {!RuntimeAgent.RemoteObjectId} */
235 return this._objectId;
238 /** @return {string} */
244 /** @return {string|undefined} */
247 return this._subtype;
250 /** @return {string|undefined} */
253 return this._description;
256 /** @return {boolean} */
259 return this._hasChildren;
262 /** @return {!RuntimeAgent.ObjectPreview|undefined} */
265 return this._preview;
269 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
271 getOwnProperties: function(callback)
273 this.doGetProperties(true, false, callback);
277 * @param {boolean} accessorPropertiesOnly
278 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
280 getAllProperties: function(accessorPropertiesOnly, callback)
282 this.doGetProperties(false, accessorPropertiesOnly, callback);
286 * @param {!Array.<string>} propertyPath
287 * @param {function(?WebInspector.RemoteObject, boolean=)} callback
289 getProperty: function(propertyPath, callback)
292 * @param {string} arrayStr
293 * @suppressReceiverCheck
296 function remoteFunction(arrayStr)
299 var properties = JSON.parse(arrayStr);
300 for (var i = 0, n = properties.length; i < n; ++i)
301 result = result[properties[i]];
305 var args = [{ value: JSON.stringify(propertyPath) }];
306 this.callFunction(remoteFunction, args, callback);
310 * @param {boolean} ownProperties
311 * @param {boolean} accessorPropertiesOnly
312 * @param {?function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
314 doGetProperties: function(ownProperties, accessorPropertiesOnly, callback)
316 if (!this._objectId) {
317 callback(null, null);
322 * @param {?Protocol.Error} error
323 * @param {!Array.<!RuntimeAgent.PropertyDescriptor>} properties
324 * @param {!Array.<!RuntimeAgent.InternalPropertyDescriptor>=} internalProperties
325 * @this {WebInspector.RemoteObjectImpl}
327 function remoteObjectBinder(error, properties, internalProperties)
330 callback(null, null);
334 for (var i = 0; properties && i < properties.length; ++i) {
335 var property = properties[i];
336 var propertyValue = property.value ? this._target.runtimeModel.createRemoteObject(property.value) : null;
337 var remoteProperty = new WebInspector.RemoteObjectProperty(property.name, propertyValue,
338 !!property.enumerable, !!property.writable, !!property.isOwn, !!property.wasThrown);
340 if (typeof property.value === "undefined") {
341 if (property.get && property.get.type !== "undefined")
342 remoteProperty.getter = this._target.runtimeModel.createRemoteObject(property.get);
343 if (property.set && property.set.type !== "undefined")
344 remoteProperty.setter = this._target.runtimeModel.createRemoteObject(property.set);
347 result.push(remoteProperty);
349 var internalPropertiesResult = null;
350 if (internalProperties) {
351 internalPropertiesResult = [];
352 for (var i = 0; i < internalProperties.length; i++) {
353 var property = internalProperties[i];
356 internalPropertiesResult.push(new WebInspector.RemoteObjectProperty(property.name, this._target.runtimeModel.createRemoteObject(property.value)));
359 callback(result, internalPropertiesResult);
361 this._runtimeAgent.getProperties(this._objectId, ownProperties, accessorPropertiesOnly, remoteObjectBinder.bind(this));
365 * @param {string} name
366 * @param {string} value
367 * @param {function(string=)} callback
369 setPropertyValue: function(name, value, callback)
371 if (!this._objectId) {
372 callback("Can't set a property of non-object.");
376 this._runtimeAgent.invoke_evaluate({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this));
379 * @param {?Protocol.Error} error
380 * @param {!RuntimeAgent.RemoteObject} result
381 * @param {boolean=} wasThrown
382 * @this {WebInspector.RemoteObject}
384 function evaluatedCallback(error, result, wasThrown)
386 if (error || wasThrown) {
387 callback(error || result.description);
391 this.doSetObjectPropertyValue(result, name, callback);
394 this._runtimeAgent.releaseObject(result.objectId);
399 * @param {!RuntimeAgent.RemoteObject} result
400 * @param {string} name
401 * @param {function(string=)} callback
403 doSetObjectPropertyValue: function(result, name, callback)
405 // This assignment may be for a regular (data) property, and for an acccessor property (with getter/setter).
406 // Note the sensitive matter about accessor property: the property may be physically defined in some proto object,
407 // but logically it is bound to the object in question. JavaScript passes this object to getters/setters, not the object
408 // where property was defined; so do we.
409 var setPropertyValueFunction = "function(a, b) { this[a] = b; }";
411 var argv = [{ value: name }, WebInspector.RemoteObject.toCallArgument(result)]
412 this._runtimeAgent.callFunctionOn(this._objectId, setPropertyValueFunction, argv, true, undefined, undefined, propertySetCallback);
415 * @param {?Protocol.Error} error
416 * @param {!RuntimeAgent.RemoteObject} result
417 * @param {boolean=} wasThrown
419 function propertySetCallback(error, result, wasThrown)
421 if (error || wasThrown) {
422 callback(error || result.description);
430 * @param {function(?WebInspector.DOMNode)} callback
432 pushNodeToFrontend: function(callback)
435 this._domModel.pushNodeToFrontend(this._objectId, callback);
440 highlightAsDOMNode: function()
442 this._domModel.highlightDOMNode(undefined, undefined, this._objectId);
445 hideDOMNodeHighlight: function()
447 this._domModel.hideDOMNodeHighlight();
451 * @param {function(this:Object, ...)} functionDeclaration
452 * @param {!Array.<!RuntimeAgent.CallArgument>=} args
453 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback
455 callFunction: function(functionDeclaration, args, callback)
458 * @param {?Protocol.Error} error
459 * @param {!RuntimeAgent.RemoteObject} result
460 * @param {boolean=} wasThrown
461 * @this {WebInspector.RemoteObjectImpl}
463 function mycallback(error, result, wasThrown)
468 callback(null, false);
470 callback(this.target().runtimeModel.createRemoteObject(result), wasThrown);
473 this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, undefined, mycallback.bind(this));
477 * @param {function(this:Object)} functionDeclaration
478 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args
479 * @param {function(*)} callback
481 callFunctionJSON: function(functionDeclaration, args, callback)
484 * @param {?Protocol.Error} error
485 * @param {!RuntimeAgent.RemoteObject} result
486 * @param {boolean=} wasThrown
488 function mycallback(error, result, wasThrown)
490 callback((error || wasThrown) ? null : result.value);
493 this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, false, mycallback);
500 this._runtimeAgent.releaseObject(this._objectId);
506 arrayLength: function()
508 if (this.subtype !== "array")
511 var matches = this._description.match(/\[([0-9]+)\]/);
514 return parseInt(matches[1], 10);
518 * @return {!WebInspector.Target}
530 return !!this._objectId && this.type === "object" && this.subtype === "node";
534 * @param {function(?DebuggerAgent.FunctionDetails)} callback
536 functionDetails: function(callback)
538 this._target.debuggerModel.functionDetails(this, callback)
541 __proto__: WebInspector.RemoteObject.prototype
546 * @param {!WebInspector.RemoteObject} object
547 * @param {boolean} flattenProtoChain
548 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
550 WebInspector.RemoteObject.loadFromObject = function(object, flattenProtoChain, callback)
552 if (flattenProtoChain)
553 object.getAllProperties(false, callback);
555 WebInspector.RemoteObject.loadFromObjectPerProto(object, callback);
559 * @param {!WebInspector.RemoteObject} object
560 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
562 WebInspector.RemoteObject.loadFromObjectPerProto = function(object, callback)
564 // Combines 2 asynch calls. Doesn't rely on call-back orders (some calls may be loop-back).
565 var savedOwnProperties;
566 var savedAccessorProperties;
567 var savedInternalProperties;
568 var resultCounter = 2;
570 function processCallback()
574 if (savedOwnProperties && savedAccessorProperties) {
575 var combinedList = savedAccessorProperties.slice(0);
576 for (var i = 0; i < savedOwnProperties.length; i++) {
577 var property = savedOwnProperties[i];
578 if (!property.isAccessorProperty())
579 combinedList.push(property);
581 return callback(combinedList, savedInternalProperties ? savedInternalProperties : null);
583 callback(null, null);
588 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
589 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
591 function allAccessorPropertiesCallback(properties, internalProperties)
593 savedAccessorProperties = properties;
598 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
599 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
601 function ownPropertiesCallback(properties, internalProperties)
603 savedOwnProperties = properties;
604 savedInternalProperties = internalProperties;
608 object.getAllProperties(true, allAccessorPropertiesCallback);
609 object.getOwnProperties(ownPropertiesCallback);
615 * @extends {WebInspector.RemoteObjectImpl}
616 * @param {!WebInspector.Target} target
617 * @param {string|undefined} objectId
618 * @param {!WebInspector.ScopeRef} scopeRef
619 * @param {string} type
620 * @param {string|undefined} subtype
622 * @param {string=} description
623 * @param {!RuntimeAgent.ObjectPreview=} preview
625 WebInspector.ScopeRemoteObject = function(target, objectId, scopeRef, type, subtype, value, description, preview)
627 WebInspector.RemoteObjectImpl.call(this, target, objectId, type, subtype, value, description, preview);
628 this._scopeRef = scopeRef;
629 this._savedScopeProperties = undefined;
630 this._debuggerAgent = target.debuggerAgent();
633 WebInspector.ScopeRemoteObject.prototype = {
635 * @param {boolean} ownProperties
636 * @param {boolean} accessorPropertiesOnly
637 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
640 doGetProperties: function(ownProperties, accessorPropertiesOnly, callback)
642 if (accessorPropertiesOnly) {
646 if (this._savedScopeProperties) {
647 // No need to reload scope variables, as the remote object never
648 // changes its properties. If variable is updated, the properties
649 // array is patched locally.
650 callback(this._savedScopeProperties.slice(), []);
655 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
656 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
657 * @this {WebInspector.ScopeRemoteObject}
659 function wrappedCallback(properties, internalProperties)
661 if (this._scopeRef && properties instanceof Array)
662 this._savedScopeProperties = properties.slice();
663 callback(properties, internalProperties);
666 WebInspector.RemoteObjectImpl.prototype.doGetProperties.call(this, ownProperties, accessorPropertiesOnly, wrappedCallback.bind(this));
671 * @param {!RuntimeAgent.RemoteObject} result
672 * @param {string} name
673 * @param {function(string=)} callback
675 doSetObjectPropertyValue: function(result, name, callback)
677 this._debuggerAgent.setVariableValue(this._scopeRef.number, name, WebInspector.RemoteObject.toCallArgument(result), this._scopeRef.callFrameId, this._scopeRef.functionId, setVariableValueCallback.bind(this));
680 * @param {?Protocol.Error} error
681 * @this {WebInspector.ScopeRemoteObject}
683 function setVariableValueCallback(error)
689 if (this._savedScopeProperties) {
690 for (var i = 0; i < this._savedScopeProperties.length; i++) {
691 if (this._savedScopeProperties[i].name === name)
692 this._savedScopeProperties[i].value = this._target.runtimeModel.createRemoteObject(result);
699 __proto__: WebInspector.RemoteObjectImpl.prototype
703 * Either callFrameId or functionId (exactly one) must be defined.
705 * @param {number} number
706 * @param {string=} callFrameId
707 * @param {string=} functionId
709 WebInspector.ScopeRef = function(number, callFrameId, functionId)
711 this.number = number;
712 this.callFrameId = callFrameId;
713 this.functionId = functionId;
718 * @param {string} name
719 * @param {?WebInspector.RemoteObject} value
720 * @param {boolean=} enumerable
721 * @param {boolean=} writable
722 * @param {boolean=} isOwn
723 * @param {boolean=} wasThrown
725 WebInspector.RemoteObjectProperty = function(name, value, enumerable, writable, isOwn, wasThrown)
730 this.enumerable = typeof enumerable !== "undefined" ? enumerable : true;
731 this.writable = typeof writable !== "undefined" ? writable : true;
732 this.isOwn = !!isOwn;
733 this.wasThrown = !!wasThrown;
736 WebInspector.RemoteObjectProperty.prototype = {
740 isAccessorProperty: function()
742 return !!(this.getter || this.setter);
746 // Below is a wrapper around a local object that implements the RemoteObject interface,
747 // which can be used by the UI code (primarily ObjectPropertiesSection).
748 // Note that only JSON-compliant objects are currently supported, as there's no provision
749 // for traversing prototypes, extracting class names via constructor, handling properties
754 * @extends {WebInspector.RemoteObject}
757 WebInspector.LocalJSONObject = function(value)
759 WebInspector.RemoteObject.call(this);
763 WebInspector.LocalJSONObject.prototype = {
769 if (this._cachedDescription)
770 return this._cachedDescription;
773 * @param {!WebInspector.RemoteObjectProperty} property
775 function formatArrayItem(property)
777 return property.value.description;
781 * @param {!WebInspector.RemoteObjectProperty} property
783 function formatObjectItem(property)
785 return property.name + ":" + property.value.description;
788 if (this.type === "object") {
789 switch (this.subtype) {
791 this._cachedDescription = this._concatenate("[", "]", formatArrayItem);
794 this._cachedDescription = "" + this._value;
797 this._cachedDescription = "null";
800 this._cachedDescription = this._concatenate("{", "}", formatObjectItem);
803 this._cachedDescription = String(this._value);
805 return this._cachedDescription;
809 * @param {string} prefix
810 * @param {string} suffix
811 * @param {function (!WebInspector.RemoteObjectProperty)} formatProperty
814 _concatenate: function(prefix, suffix, formatProperty)
816 const previewChars = 100;
819 var children = this._children();
820 for (var i = 0; i < children.length; ++i) {
821 var itemDescription = formatProperty(children[i]);
822 if (buffer.length + itemDescription.length > previewChars) {
828 buffer += itemDescription;
839 return typeof this._value;
843 * @return {string|undefined}
847 if (this._value === null)
850 if (this._value instanceof Array)
853 if (this._value instanceof Date)
864 if ((typeof this._value !== "object") || (this._value === null))
866 return !!Object.keys(/** @type {!Object} */ (this._value)).length;
870 * @param {function(!Array.<!WebInspector.RemoteObjectProperty>)} callback
872 getOwnProperties: function(callback)
874 callback(this._children());
878 * @param {boolean} accessorPropertiesOnly
879 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback
881 getAllProperties: function(accessorPropertiesOnly, callback)
883 if (accessorPropertiesOnly)
886 callback(this._children(), null);
890 * @return {!Array.<!WebInspector.RemoteObjectProperty>}
892 _children: function()
894 if (!this.hasChildren)
896 var value = /** @type {!Object} */ (this._value);
899 * @param {string} propName
900 * @this {WebInspector.LocalJSONObject}
902 function buildProperty(propName)
904 return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName]));
906 if (!this._cachedChildren)
907 this._cachedChildren = Object.keys(value).map(buildProperty.bind(this));
908 return this._cachedChildren;
922 arrayLength: function()
924 return this._value instanceof Array ? this._value.length : 0;
928 * @param {function(this:Object, ...)} functionDeclaration
929 * @param {!Array.<!RuntimeAgent.CallArgument>=} args
930 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback
932 callFunction: function(functionDeclaration, args, callback)
934 var target = /** @type {?Object} */ (this._value);
935 var rawArgs = args ? args.map(function(arg) {return arg.value;}) : [];
938 var wasThrown = false;
940 result = functionDeclaration.apply(target, rawArgs);
947 callback(WebInspector.RemoteObject.fromLocalObject(result), wasThrown);
951 * @param {function(this:Object)} functionDeclaration
952 * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args
953 * @param {function(*)} callback
955 callFunctionJSON: function(functionDeclaration, args, callback)
957 var target = /** @type {?Object} */ (this._value);
958 var rawArgs = args ? args.map(function(arg) {return arg.value;}) : [];
962 result = functionDeclaration.apply(target, rawArgs);
970 __proto__: WebInspector.RemoteObject.prototype