diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js')
-rw-r--r-- | chromium/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js new file mode 100644 index 00000000000..16f63803174 --- /dev/null +++ b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js @@ -0,0 +1,1017 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This may not be an interface due to "instanceof WebInspector.RemoteObject" checks in the code. + * + * @constructor + */ +WebInspector.RemoteObject = function() { } + +WebInspector.RemoteObject.prototype = { + /** @return {string} */ + get type() + { + throw "Not implemented"; + }, + + /** @return {string|undefined} */ + get subtype() + { + throw "Not implemented"; + }, + + /** @return {string|undefined} */ + get description() + { + throw "Not implemented"; + }, + + /** @return {boolean} */ + get hasChildren() + { + throw "Not implemented"; + }, + + /** + * @return {number} + */ + arrayLength: function() + { + throw "Not implemented"; + }, + + /** + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getOwnProperties: function(callback) + { + throw "Not implemented"; + }, + + /** + * @param {boolean} accessorPropertiesOnly + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getAllProperties: function(accessorPropertiesOnly, callback) + { + throw "Not implemented"; + }, + + /** + * @param {string} name + * @param {function(string=)} callback + */ + deleteProperty: function(name, callback) + { + throw "Not implemented"; + }, + + /** + * @param {function(this:Object, ...)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>=} args + * @param {function(?WebInspector.RemoteObject, boolean=)=} callback + */ + callFunction: function(functionDeclaration, args, callback) + { + throw "Not implemented"; + }, + + /** + * @param {function(this:Object)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args + * @param {function(*)} callback + */ + callFunctionJSON: function(functionDeclaration, args, callback) + { + throw "Not implemented"; + }, + + /** + * @return {!WebInspector.Target} + */ + target: function() + { + throw new Error("Target-less object"); + }, + + /** + * @return {boolean} + */ + isNode: function() + { + return false; + }, + + reveal: function() + { + WebInspector.Revealer.reveal(this); + }, + + /** + * @param {function(?DebuggerAgent.FunctionDetails)} callback + */ + functionDetails: function(callback) + { + callback(null); + } +} + +/** + * @param {*} value + * @return {!WebInspector.RemoteObject} + */ +WebInspector.RemoteObject.fromLocalObject = function(value) +{ + return new WebInspector.LocalJSONObject(value); +} + +/** + * @param {!WebInspector.RemoteObject} remoteObject + * @return {string} + */ +WebInspector.RemoteObject.type = function(remoteObject) +{ + if (remoteObject === null) + return "null"; + + var type = typeof remoteObject; + if (type !== "object" && type !== "function") + return type; + + return remoteObject.type; +} + +/** + * @param {!RuntimeAgent.RemoteObject|!WebInspector.RemoteObject} remoteObject + * @return {!RuntimeAgent.CallArgument} + */ +WebInspector.RemoteObject.toCallArgument = function(remoteObject) +{ + var type = /** @type {!RuntimeAgent.CallArgumentType.<string>} */ (remoteObject.type); + var value = remoteObject.value; + + // Handle special numbers: NaN, Infinity, -Infinity, -0. + if (type === "number") { + switch (remoteObject.description) { + case "NaN": + case "Infinity": + case "-Infinity": + case "-0": + value = remoteObject.description; + break; + } + } + + return { + value: value, + objectId: remoteObject.objectId, + type: type + }; +} + +/** + * @constructor + * @extends {WebInspector.RemoteObject} + * @param {!WebInspector.Target} target + * @param {string|undefined} objectId + * @param {string} type + * @param {string|undefined} subtype + * @param {*} value + * @param {string=} description + * @param {!RuntimeAgent.ObjectPreview=} preview + */ +WebInspector.RemoteObjectImpl = function(target, objectId, type, subtype, value, description, preview) +{ + WebInspector.RemoteObject.call(this); + + this._target = target; + this._runtimeAgent = target.runtimeAgent(); + this._domModel = target.domModel; + + this._type = type; + this._subtype = subtype; + if (objectId) { + // handle + this._objectId = objectId; + this._description = description; + this._hasChildren = (type !== "symbol"); + this._preview = preview; + } else { + // Primitive or null object. + console.assert(type !== "object" || value === null); + this._description = description || (value + ""); + this._hasChildren = false; + // Handle special numbers: NaN, Infinity, -Infinity, -0. + if (type === "number" && typeof value !== "number") + this.value = Number(value); + else + this.value = value; + } +} + +WebInspector.RemoteObjectImpl.prototype = { + /** @return {!RuntimeAgent.RemoteObjectId} */ + get objectId() + { + return this._objectId; + }, + + /** @return {string} */ + get type() + { + return this._type; + }, + + /** @return {string|undefined} */ + get subtype() + { + return this._subtype; + }, + + /** @return {string|undefined} */ + get description() + { + return this._description; + }, + + /** @return {boolean} */ + get hasChildren() + { + return this._hasChildren; + }, + + /** @return {!RuntimeAgent.ObjectPreview|undefined} */ + get preview() + { + return this._preview; + }, + + /** + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getOwnProperties: function(callback) + { + this.doGetProperties(true, false, callback); + }, + + /** + * @param {boolean} accessorPropertiesOnly + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getAllProperties: function(accessorPropertiesOnly, callback) + { + this.doGetProperties(false, accessorPropertiesOnly, callback); + }, + + /** + * @param {!Array.<string>} propertyPath + * @param {function(?WebInspector.RemoteObject, boolean=)} callback + */ + getProperty: function(propertyPath, callback) + { + /** + * @param {string} arrayStr + * @suppressReceiverCheck + * @this {Object} + */ + function remoteFunction(arrayStr) + { + var result = this; + var properties = JSON.parse(arrayStr); + for (var i = 0, n = properties.length; i < n; ++i) + result = result[properties[i]]; + return result; + } + + var args = [{ value: JSON.stringify(propertyPath) }]; + this.callFunction(remoteFunction, args, callback); + }, + + /** + * @param {boolean} ownProperties + * @param {boolean} accessorPropertiesOnly + * @param {?function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + doGetProperties: function(ownProperties, accessorPropertiesOnly, callback) + { + if (!this._objectId) { + callback(null, null); + return; + } + + /** + * @param {?Protocol.Error} error + * @param {!Array.<!RuntimeAgent.PropertyDescriptor>} properties + * @param {!Array.<!RuntimeAgent.InternalPropertyDescriptor>=} internalProperties + * @this {WebInspector.RemoteObjectImpl} + */ + function remoteObjectBinder(error, properties, internalProperties) + { + if (error) { + callback(null, null); + return; + } + var result = []; + for (var i = 0; properties && i < properties.length; ++i) { + var property = properties[i]; + var propertyValue = property.value ? this._target.runtimeModel.createRemoteObject(property.value) : null; + var propertySymbol = property.symbol ? this._target.runtimeModel.createRemoteObject(property.symbol) : null; + var remoteProperty = new WebInspector.RemoteObjectProperty(property.name, propertyValue, + !!property.enumerable, !!property.writable, !!property.isOwn, !!property.wasThrown, propertySymbol); + + if (typeof property.value === "undefined") { + if (property.get && property.get.type !== "undefined") + remoteProperty.getter = this._target.runtimeModel.createRemoteObject(property.get); + if (property.set && property.set.type !== "undefined") + remoteProperty.setter = this._target.runtimeModel.createRemoteObject(property.set); + } + + result.push(remoteProperty); + } + var internalPropertiesResult = null; + if (internalProperties) { + internalPropertiesResult = []; + for (var i = 0; i < internalProperties.length; i++) { + var property = internalProperties[i]; + if (!property.value) + continue; + var propertyValue = this._target.runtimeModel.createRemoteObject(property.value); + internalPropertiesResult.push(new WebInspector.RemoteObjectProperty(property.name, propertyValue, true, false)); + } + } + callback(result, internalPropertiesResult); + } + this._runtimeAgent.getProperties(this._objectId, ownProperties, accessorPropertiesOnly, remoteObjectBinder.bind(this)); + }, + + /** + * @param {string} name + * @param {string} value + * @param {function(string=)} callback + */ + setPropertyValue: function(name, value, callback) + { + if (!this._objectId) { + callback("Can't set a property of non-object."); + return; + } + + this._runtimeAgent.invoke_evaluate({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this)); + + /** + * @param {?Protocol.Error} error + * @param {!RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + * @this {WebInspector.RemoteObject} + */ + function evaluatedCallback(error, result, wasThrown) + { + if (error || wasThrown) { + callback(error || result.description); + return; + } + + this.doSetObjectPropertyValue(result, name, callback); + + if (result.objectId) + this._runtimeAgent.releaseObject(result.objectId); + } + }, + + /** + * @param {!RuntimeAgent.RemoteObject} result + * @param {string} name + * @param {function(string=)} callback + */ + doSetObjectPropertyValue: function(result, name, callback) + { + // This assignment may be for a regular (data) property, and for an acccessor property (with getter/setter). + // Note the sensitive matter about accessor property: the property may be physically defined in some proto object, + // but logically it is bound to the object in question. JavaScript passes this object to getters/setters, not the object + // where property was defined; so do we. + var setPropertyValueFunction = "function(a, b) { this[a] = b; }"; + + var argv = [{ value: name }, WebInspector.RemoteObject.toCallArgument(result)] + this._runtimeAgent.callFunctionOn(this._objectId, setPropertyValueFunction, argv, true, undefined, undefined, propertySetCallback); + + /** + * @param {?Protocol.Error} error + * @param {!RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + */ + function propertySetCallback(error, result, wasThrown) + { + if (error || wasThrown) { + callback(error || result.description); + return; + } + callback(); + } + }, + + /** + * @param {string} name + * @param {function(string=)} callback + */ + deleteProperty: function(name, callback) + { + if (!this._objectId) { + callback("Can't delete a property of non-object."); + return; + } + + var deletePropertyFunction = "function(a) { delete this[a]; return !(a in this); }"; + this._runtimeAgent.callFunctionOn(this._objectId, deletePropertyFunction, [{ value: name }], true, undefined, undefined, deletePropertyCallback); + + /** + * @param {?Protocol.Error} error + * @param {!RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + */ + function deletePropertyCallback(error, result, wasThrown) + { + if (error || wasThrown) { + callback(error || result.description); + return; + } + if (!result.value) + callback("Failed to delete property."); + else + callback(); + } + }, + + /** + * @param {function(?WebInspector.DOMNode)} callback + */ + pushNodeToFrontend: function(callback) + { + if (this.isNode()) + this._domModel.pushNodeToFrontend(this._objectId, callback); + else + callback(null); + }, + + highlightAsDOMNode: function() + { + this._domModel.highlightDOMNode(undefined, undefined, this._objectId); + }, + + hideDOMNodeHighlight: function() + { + this._domModel.hideDOMNodeHighlight(); + }, + + /** + * @param {function(this:Object, ...)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>=} args + * @param {function(?WebInspector.RemoteObject, boolean=)=} callback + */ + callFunction: function(functionDeclaration, args, callback) + { + /** + * @param {?Protocol.Error} error + * @param {!RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + * @this {WebInspector.RemoteObjectImpl} + */ + function mycallback(error, result, wasThrown) + { + if (!callback) + return; + if (error) + callback(null, false); + else + callback(this.target().runtimeModel.createRemoteObject(result), wasThrown); + } + + this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, undefined, mycallback.bind(this)); + }, + + /** + * @param {function(this:Object)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args + * @param {function(*)} callback + */ + callFunctionJSON: function(functionDeclaration, args, callback) + { + /** + * @param {?Protocol.Error} error + * @param {!RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + */ + function mycallback(error, result, wasThrown) + { + callback((error || wasThrown) ? null : result.value); + } + + this._runtimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, false, mycallback); + }, + + release: function() + { + if (!this._objectId) + return; + this._runtimeAgent.releaseObject(this._objectId); + }, + + /** + * @return {number} + */ + arrayLength: function() + { + if (this.subtype !== "array") + return 0; + + var matches = this._description.match(/\[([0-9]+)\]/); + if (!matches) + return 0; + return parseInt(matches[1], 10); + }, + + /** + * @return {!WebInspector.Target} + */ + target: function() + { + return this._target; + }, + + /** + * @return {boolean} + */ + isNode: function() + { + return !!this._objectId && this.type === "object" && this.subtype === "node"; + }, + + /** + * @param {function(?DebuggerAgent.FunctionDetails)} callback + */ + functionDetails: function(callback) + { + this._target.debuggerModel.functionDetails(this, callback) + }, + + __proto__: WebInspector.RemoteObject.prototype +}; + + +/** + * @param {!WebInspector.RemoteObject} object + * @param {boolean} flattenProtoChain + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ +WebInspector.RemoteObject.loadFromObject = function(object, flattenProtoChain, callback) +{ + if (flattenProtoChain) + object.getAllProperties(false, callback); + else + WebInspector.RemoteObject.loadFromObjectPerProto(object, callback); +}; + +/** + * @param {!WebInspector.RemoteObject} object + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ +WebInspector.RemoteObject.loadFromObjectPerProto = function(object, callback) +{ + // Combines 2 asynch calls. Doesn't rely on call-back orders (some calls may be loop-back). + var savedOwnProperties; + var savedAccessorProperties; + var savedInternalProperties; + var resultCounter = 2; + + function processCallback() + { + if (--resultCounter) + return; + if (savedOwnProperties && savedAccessorProperties) { + var combinedList = savedAccessorProperties.slice(0); + for (var i = 0; i < savedOwnProperties.length; i++) { + var property = savedOwnProperties[i]; + if (!property.isAccessorProperty()) + combinedList.push(property); + } + return callback(combinedList, savedInternalProperties ? savedInternalProperties : null); + } else { + callback(null, null); + } + } + + /** + * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties + * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties + */ + function allAccessorPropertiesCallback(properties, internalProperties) + { + savedAccessorProperties = properties; + processCallback(); + } + + /** + * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties + * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties + */ + function ownPropertiesCallback(properties, internalProperties) + { + savedOwnProperties = properties; + savedInternalProperties = internalProperties; + processCallback(); + } + + object.getAllProperties(true, allAccessorPropertiesCallback); + object.getOwnProperties(ownPropertiesCallback); +}; + + +/** + * @constructor + * @extends {WebInspector.RemoteObjectImpl} + * @param {!WebInspector.Target} target + * @param {string|undefined} objectId + * @param {!WebInspector.ScopeRef} scopeRef + * @param {string} type + * @param {string|undefined} subtype + * @param {*} value + * @param {string=} description + * @param {!RuntimeAgent.ObjectPreview=} preview + */ +WebInspector.ScopeRemoteObject = function(target, objectId, scopeRef, type, subtype, value, description, preview) +{ + WebInspector.RemoteObjectImpl.call(this, target, objectId, type, subtype, value, description, preview); + this._scopeRef = scopeRef; + this._savedScopeProperties = undefined; + this._debuggerAgent = target.debuggerAgent(); +}; + +WebInspector.ScopeRemoteObject.prototype = { + /** + * @param {boolean} ownProperties + * @param {boolean} accessorPropertiesOnly + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + * @override + */ + doGetProperties: function(ownProperties, accessorPropertiesOnly, callback) + { + if (accessorPropertiesOnly) { + callback([], []); + return; + } + if (this._savedScopeProperties) { + // No need to reload scope variables, as the remote object never + // changes its properties. If variable is updated, the properties + // array is patched locally. + callback(this._savedScopeProperties.slice(), []); + return; + } + + /** + * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties + * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties + * @this {WebInspector.ScopeRemoteObject} + */ + function wrappedCallback(properties, internalProperties) + { + if (this._scopeRef && properties instanceof Array) + this._savedScopeProperties = properties.slice(); + callback(properties, internalProperties); + } + + WebInspector.RemoteObjectImpl.prototype.doGetProperties.call(this, ownProperties, accessorPropertiesOnly, wrappedCallback.bind(this)); + }, + + /** + * @override + * @param {!RuntimeAgent.RemoteObject} result + * @param {string} name + * @param {function(string=)} callback + */ + doSetObjectPropertyValue: function(result, name, callback) + { + this._debuggerAgent.setVariableValue(this._scopeRef.number, name, WebInspector.RemoteObject.toCallArgument(result), this._scopeRef.callFrameId, this._scopeRef.functionId, setVariableValueCallback.bind(this)); + + /** + * @param {?Protocol.Error} error + * @this {WebInspector.ScopeRemoteObject} + */ + function setVariableValueCallback(error) + { + if (error) { + callback(error); + return; + } + if (this._savedScopeProperties) { + for (var i = 0; i < this._savedScopeProperties.length; i++) { + if (this._savedScopeProperties[i].name === name) + this._savedScopeProperties[i].value = this._target.runtimeModel.createRemoteObject(result); + } + } + callback(); + } + }, + + __proto__: WebInspector.RemoteObjectImpl.prototype +}; + +/** + * Either callFrameId or functionId (exactly one) must be defined. + * @constructor + * @param {number} number + * @param {string=} callFrameId + * @param {string=} functionId + */ +WebInspector.ScopeRef = function(number, callFrameId, functionId) +{ + this.number = number; + this.callFrameId = callFrameId; + this.functionId = functionId; +} + +/** + * @constructor + * @param {string} name + * @param {?WebInspector.RemoteObject} value + * @param {boolean=} enumerable + * @param {boolean=} writable + * @param {boolean=} isOwn + * @param {boolean=} wasThrown + * @param {?WebInspector.RemoteObject=} symbol + */ +WebInspector.RemoteObjectProperty = function(name, value, enumerable, writable, isOwn, wasThrown, symbol) +{ + this.name = name; + if (value !== null) + this.value = value; + this.enumerable = typeof enumerable !== "undefined" ? enumerable : true; + this.writable = typeof writable !== "undefined" ? writable : true; + this.isOwn = !!isOwn; + this.wasThrown = !!wasThrown; + if (symbol) + this.symbol = symbol; +} + +WebInspector.RemoteObjectProperty.prototype = { + /** + * @return {boolean} + */ + isAccessorProperty: function() + { + return !!(this.getter || this.setter); + } +}; + +// Below is a wrapper around a local object that implements the RemoteObject interface, +// which can be used by the UI code (primarily ObjectPropertiesSection). +// Note that only JSON-compliant objects are currently supported, as there's no provision +// for traversing prototypes, extracting class names via constructor, handling properties +// or functions. + +/** + * @constructor + * @extends {WebInspector.RemoteObject} + * @param {*} value + */ +WebInspector.LocalJSONObject = function(value) +{ + WebInspector.RemoteObject.call(this); + this._value = value; +} + +WebInspector.LocalJSONObject.prototype = { + /** + * @return {string} + */ + get description() + { + if (this._cachedDescription) + return this._cachedDescription; + + /** + * @param {!WebInspector.RemoteObjectProperty} property + */ + function formatArrayItem(property) + { + return property.value.description; + } + + /** + * @param {!WebInspector.RemoteObjectProperty} property + */ + function formatObjectItem(property) + { + return property.name + ":" + property.value.description; + } + + if (this.type === "object") { + switch (this.subtype) { + case "array": + this._cachedDescription = this._concatenate("[", "]", formatArrayItem); + break; + case "date": + this._cachedDescription = "" + this._value; + break; + case "null": + this._cachedDescription = "null"; + break; + default: + this._cachedDescription = this._concatenate("{", "}", formatObjectItem); + } + } else + this._cachedDescription = String(this._value); + + return this._cachedDescription; + }, + + /** + * @param {string} prefix + * @param {string} suffix + * @param {function (!WebInspector.RemoteObjectProperty)} formatProperty + * @return {string} + */ + _concatenate: function(prefix, suffix, formatProperty) + { + const previewChars = 100; + + var buffer = prefix; + var children = this._children(); + for (var i = 0; i < children.length; ++i) { + var itemDescription = formatProperty(children[i]); + if (buffer.length + itemDescription.length > previewChars) { + buffer += ",\u2026"; + break; + } + if (i) + buffer += ", "; + buffer += itemDescription; + } + buffer += suffix; + return buffer; + }, + + /** + * @return {string} + */ + get type() + { + return typeof this._value; + }, + + /** + * @return {string|undefined} + */ + get subtype() + { + if (this._value === null) + return "null"; + + if (this._value instanceof Array) + return "array"; + + if (this._value instanceof Date) + return "date"; + + return undefined; + }, + + /** + * @return {boolean} + */ + get hasChildren() + { + if ((typeof this._value !== "object") || (this._value === null)) + return false; + return !!Object.keys(/** @type {!Object} */ (this._value)).length; + }, + + /** + * @param {function(!Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getOwnProperties: function(callback) + { + callback(this._children()); + }, + + /** + * @param {boolean} accessorPropertiesOnly + * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!WebInspector.RemoteObjectProperty>)} callback + */ + getAllProperties: function(accessorPropertiesOnly, callback) + { + if (accessorPropertiesOnly) + callback([], null); + else + callback(this._children(), null); + }, + + /** + * @return {!Array.<!WebInspector.RemoteObjectProperty>} + */ + _children: function() + { + if (!this.hasChildren) + return []; + var value = /** @type {!Object} */ (this._value); + + /** + * @param {string} propName + * @this {WebInspector.LocalJSONObject} + */ + function buildProperty(propName) + { + return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName])); + } + if (!this._cachedChildren) + this._cachedChildren = Object.keys(value).map(buildProperty.bind(this)); + return this._cachedChildren; + }, + + /** + * @return {boolean} + */ + isError: function() + { + return false; + }, + + /** + * @return {number} + */ + arrayLength: function() + { + return this._value instanceof Array ? this._value.length : 0; + }, + + /** + * @param {function(this:Object, ...)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>=} args + * @param {function(?WebInspector.RemoteObject, boolean=)=} callback + */ + callFunction: function(functionDeclaration, args, callback) + { + var target = /** @type {?Object} */ (this._value); + var rawArgs = args ? args.map(function(arg) {return arg.value;}) : []; + + var result; + var wasThrown = false; + try { + result = functionDeclaration.apply(target, rawArgs); + } catch (e) { + wasThrown = true; + } + + if (!callback) + return; + callback(WebInspector.RemoteObject.fromLocalObject(result), wasThrown); + }, + + /** + * @param {function(this:Object)} functionDeclaration + * @param {!Array.<!RuntimeAgent.CallArgument>|undefined} args + * @param {function(*)} callback + */ + callFunctionJSON: function(functionDeclaration, args, callback) + { + var target = /** @type {?Object} */ (this._value); + var rawArgs = args ? args.map(function(arg) {return arg.value;}) : []; + + var result; + try { + result = functionDeclaration.apply(target, rawArgs); + } catch (e) { + result = null; + } + + callback(result); + }, + + __proto__: WebInspector.RemoteObject.prototype +} |