123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- /*
- * 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.
- */
- /**
- * @constructor
- * @param {string|undefined} objectId
- * @param {string} type
- * @param {string|undefined} subtype
- * @param {*} value
- * @param {string=} description
- * @param {RuntimeAgent.ObjectPreview=} preview
- * @param {WebInspector.ScopeRef=} scopeRef
- */
- WebInspector.RemoteObject = function(objectId, type, subtype, value, description, preview, scopeRef)
- {
- this._type = type;
- this._subtype = subtype;
- if (objectId) {
- // handle
- this._objectId = objectId;
- this._description = description;
- this._hasChildren = true;
- this._preview = preview;
- } else {
- // Primitive or null object.
- console.assert(type !== "object" || value === null);
- this._description = description || (value + "");
- this._hasChildren = false;
- this.value = value;
- }
- this._scopeRef = scopeRef;
- }
- /**
- * @param {number|string|boolean} value
- * @return {WebInspector.RemoteObject}
- */
- WebInspector.RemoteObject.fromPrimitiveValue = function(value)
- {
- return new WebInspector.RemoteObject(undefined, typeof value, undefined, value);
- }
- /**
- * @param {Object} value
- * @return {WebInspector.RemoteObject}
- */
- WebInspector.RemoteObject.fromLocalObject = function(value)
- {
- return new WebInspector.LocalJSONObject(value);
- }
- /**
- * @param {WebInspector.DOMNode} node
- * @param {string} objectGroup
- * @param {function(?WebInspector.RemoteObject)} callback
- */
- WebInspector.RemoteObject.resolveNode = function(node, objectGroup, callback)
- {
- /**
- * @param {?Protocol.Error} error
- * @param {RuntimeAgent.RemoteObject} object
- */
- function mycallback(error, object)
- {
- if (!callback)
- return;
- if (error || !object)
- callback(null);
- else
- callback(WebInspector.RemoteObject.fromPayload(object));
- }
- DOMAgent.resolveNode(node.id, objectGroup, mycallback);
- }
- /**
- * @param {RuntimeAgent.RemoteObject=} payload
- * @return {WebInspector.RemoteObject}
- */
- WebInspector.RemoteObject.fromPayload = function(payload)
- {
- console.assert(typeof payload === "object", "Remote object payload should only be an object");
- return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview);
- }
- /**
- * @param {RuntimeAgent.RemoteObject} payload
- * @param {WebInspector.ScopeRef=} scopeRef
- * @return {WebInspector.RemoteObject}
- */
- WebInspector.RemoteObject.fromScopePayload = function(payload, scopeRef)
- {
- return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview, scopeRef);
- }
- /**
- * @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;
- }
- WebInspector.RemoteObject.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._getProperties(true, callback);
- },
- /**
- * @param {function(Array.<WebInspector.RemoteObjectProperty>, Array.<WebInspector.RemoteObjectProperty>=)} callback
- */
- getAllProperties: function(callback)
- {
- this._getProperties(false, callback);
- },
- /**
- * @param {boolean} ownProperties
- * @param {function(Array.<WebInspector.RemoteObjectProperty>, Array.<WebInspector.RemoteObjectProperty>=)} callback
- */
- _getProperties: function(ownProperties, callback)
- {
- if (!this._objectId) {
- callback([]);
- return;
- }
- /**
- * @param {?Protocol.Error} error
- * @param {Array.<RuntimeAgent.PropertyDescriptor>} properties
- * @param {Array.<RuntimeAgent.InternalPropertyDescriptor>=} internalProperties
- */
- function remoteObjectBinder(error, properties, internalProperties)
- {
- if (error) {
- callback(null);
- return;
- }
- var result = [];
- for (var i = 0; properties && i < properties.length; ++i) {
- var property = properties[i];
- if (property.get || property.set) {
- if (property.get)
- result.push(new WebInspector.RemoteObjectProperty("get " + property.name, WebInspector.RemoteObject.fromPayload(property.get), property));
- if (property.set)
- result.push(new WebInspector.RemoteObjectProperty("set " + property.name, WebInspector.RemoteObject.fromPayload(property.set), property));
- } else
- result.push(new WebInspector.RemoteObjectProperty(property.name, WebInspector.RemoteObject.fromPayload(property.value), property));
- }
- var internalPropertiesResult;
- if (internalProperties) {
- internalPropertiesResult = [];
- for (var i = 0; i < internalProperties.length; i++) {
- var property = internalProperties[i];
- internalPropertiesResult.push(new WebInspector.RemoteObjectProperty(property.name, WebInspector.RemoteObject.fromPayload(property.value)));
- }
- }
- callback(result, internalPropertiesResult);
- }
- RuntimeAgent.getProperties(this._objectId, ownProperties, remoteObjectBinder);
- },
- /**
- * @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;
- }
- RuntimeAgent.evaluate.invoke({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this));
- /**
- * @param {?Protocol.Error} error
- * @param {RuntimeAgent.RemoteObject} result
- * @param {boolean=} wasThrown
- */
- function evaluatedCallback(error, result, wasThrown)
- {
- if (error || wasThrown) {
- callback(error || result.description);
- return;
- }
-
- if (this._scopeRef)
- this._setDeclarativeVariableValue(result, name, callback);
- else
- this._setObjectPropertyValue(result, name, callback);
- if (result._objectId)
- RuntimeAgent.releaseObject(result._objectId);
- }
- },
-
- /**
- * @param {WebInspector.RemoteObject} result
- * @param {string} name
- * @param {function(string=)} callback
- */
- _setObjectPropertyValue: function(result, name, callback)
- {
- // Note that it is not that simple with accessor properties. The proto object may contain the property,
- // however not the proto object must be 'this', but the main object.
- var setPropertyValueFunction = "function(a, b) { this[a] = b; }";
- // Special case for NaN, Infinity and -Infinity
- if (result.type === "number" && typeof result.value !== "number")
- setPropertyValueFunction = "function(a) { this[a] = " + result.description + "; }";
- delete result.description; // Optimize on traffic.
- RuntimeAgent.callFunctionOn(this._objectId, setPropertyValueFunction, [{ value:name }, result], true, undefined, undefined, propertySetCallback.bind(this));
- /**
- * @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 {WebInspector.RemoteObject} result
- * @param {string} name
- * @param {function(string=)} callback
- */
- _setDeclarativeVariableValue: function(result, name, callback)
- {
- var newValue;
-
- switch (result.type) {
- case "undefined":
- newValue = {};
- break;
- case "object":
- case "function":
- newValue = { objectId: result.objectId };
- break;
- default:
- newValue = { value: result.value };
- }
-
- DebuggerAgent.setVariableValue(this._scopeRef.number, name, newValue, this._scopeRef.callFrameId, this._scopeRef.functionId, setVariableValueCallback.bind(this));
- /**
- * @param {?Protocol.Error} error
- */
- function setVariableValueCallback(error)
- {
- if (error) {
- callback(error);
- return;
- }
- callback();
- }
- },
- /**
- * @param {function(?DOMAgent.NodeId)} callback
- */
- pushNodeToFrontend: function(callback)
- {
- if (this._objectId)
- WebInspector.domAgent.pushNodeToFrontend(this._objectId, callback);
- else
- callback(0);
- },
- highlightAsDOMNode: function()
- {
- WebInspector.domAgent.highlightDOMNode(undefined, undefined, this._objectId);
- },
- hideDOMNodeHighlight: function()
- {
- WebInspector.domAgent.hideDOMNodeHighlight();
- },
- /**
- * @param {function(this:Object)} functionDeclaration
- * @param {Array.<RuntimeAgent.CallArgument>=} args
- * @param {function(?WebInspector.RemoteObject)=} callback
- */
- callFunction: function(functionDeclaration, args, callback)
- {
- /**
- * @param {?Protocol.Error} error
- * @param {RuntimeAgent.RemoteObject} result
- * @param {boolean=} wasThrown
- */
- function mycallback(error, result, wasThrown)
- {
- if (!callback)
- return;
- callback((error || wasThrown) ? null : WebInspector.RemoteObject.fromPayload(result));
- }
- RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, undefined, mycallback);
- },
- /**
- * @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);
- }
- RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, false, mycallback);
- },
- release: function()
- {
- if (!this._objectId)
- return;
- 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);
- }
- }
- /**
- * 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 {Object=} descriptor
- */
- WebInspector.RemoteObjectProperty = function(name, value, descriptor)
- {
- this.name = name;
- this.value = value;
- this.enumerable = descriptor ? !!descriptor.enumerable : true;
- this.writable = descriptor ? !!descriptor.writable : true;
- if (descriptor && descriptor.wasThrown)
- this.wasThrown = true;
- }
- /**
- * @param {string} name
- * @param {string} value
- * @return {WebInspector.RemoteObjectProperty}
- */
- WebInspector.RemoteObjectProperty.fromPrimitiveValue = function(name, value)
- {
- return new WebInspector.RemoteObjectProperty(name, WebInspector.RemoteObject.fromPrimitiveValue(value));
- }
- /**
- * @param {string} name
- * @param {WebInspector.RemoteObject} value
- * @return {WebInspector.RemoteObjectProperty}
- */
- WebInspector.RemoteObjectProperty.fromScopeValue = function(name, value)
- {
- var result = new WebInspector.RemoteObjectProperty(name, value);
- result.writable = false;
- return result;
- }
- // The below is a wrapper around a local object that provides an interface comaptible
- // with RemoteObject, to 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 constuctor, handling properties
- // or functions.
- /**
- * @constructor
- * @extends {WebInspector.RemoteObject}
- * @param {Object} value
- */
- WebInspector.LocalJSONObject = function(value)
- {
- this._value = value;
- }
- WebInspector.LocalJSONObject.prototype = {
- /**
- * @return {string}
- */
- get description()
- {
- if (this._cachedDescription)
- return this._cachedDescription;
- if (this.type === "object") {
- switch (this.subtype) {
- case "array":
- function formatArrayItem(property)
- {
- return property.value.description;
- }
- this._cachedDescription = this._concatenate("[", "]", formatArrayItem);
- break;
- case "date":
- this._cachedDescription = "" + this._value;
- break;
- case "null":
- this._cachedDescription = "null";
- break;
- default:
- function formatObjectItem(property)
- {
- return property.name + ":" + property.value.description;
- }
- this._cachedDescription = this._concatenate("{", "}", formatObjectItem);
- }
- } else
- this._cachedDescription = String(this._value);
- return this._cachedDescription;
- },
- /**
- * @param {string} prefix
- * @param {string} suffix
- * @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()
- {
- return typeof this._value === "object" && this._value !== null && !!Object.keys(this._value).length;
- },
- /**
- * @param {function(Array.<WebInspector.RemoteObjectProperty>)} callback
- */
- getOwnProperties: function(callback)
- {
- callback(this._children());
- },
- /**
- * @param {function(Array.<WebInspector.RemoteObjectProperty>)} callback
- */
- getAllProperties: function(callback)
- {
- callback(this._children());
- },
- /**
- * @return {Array.<WebInspector.RemoteObjectProperty>}
- */
- _children: function()
- {
- if (!this.hasChildren)
- return [];
- function buildProperty(propName)
- {
- return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName]));
- }
- if (!this._cachedChildren)
- this._cachedChildren = Object.keys(this._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;
- }
- }
|