Changeset 65414 in webkit
- Timestamp:
- Aug 16, 2010 5:19:22 AM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r65412 r65414 1 2010-08-16 Pavel Feldman <pfeldman@chromium.org> 2 3 Reviewed by Yury Semikhatsky. 4 5 Web Inspector: Make InjectedScript proto-based. 6 https://bugs.webkit.org/show_bug.cgi?id=44028 7 8 * inspector/front-end/InjectedScript.js: 9 (injectedScriptConstructor): 10 (injectedScriptConstructor.): 11 * inspector/front-end/inspector.js: 12 (WebInspector.loaded): 13 1 14 2010-08-16 Pavel Feldman <pfeldman@chromium.org> 2 15 -
trunk/WebCore/inspector/front-end/InjectedScript.js
r65314 r65414 29 29 var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId, jsEngine) { 30 30 31 var InjectedScript = {}; 32 33 InjectedScript.lastBoundObjectId = 1; 34 InjectedScript.idToWrappedObject = {}; 35 InjectedScript.objectGroups = {}; 36 37 InjectedScript.wrapObjectForConsole = function(object, canAccessInspectedWindow) 31 var InjectedScript = function() 38 32 { 39 if (canAccessInspectedWindow) 40 return InjectedScript.wrapObject(object, "console"); 41 var result = {}; 42 result.type = typeof object; 43 result.description = InjectedScript._toString(object); 44 return result; 45 } 46 47 InjectedScript.wrapObject = function(object, objectGroupName) 48 { 49 try { 50 var objectId; 51 if (typeof object === "object" || typeof object === "function" || InjectedScript._isHTMLAllCollection(object)) { 52 var id = InjectedScript.lastBoundObjectId++; 53 objectId = id; 54 InjectedScript.idToWrappedObject[id] = object; 55 56 var group = InjectedScript.objectGroups[objectGroupName]; 57 if (!group) { 58 group = []; 59 InjectedScript.objectGroups[objectGroupName] = group; 33 this._lastBoundObjectId = 1; 34 this._idToWrappedObject = {}; 35 this._objectGroups = {}; 36 } 37 38 InjectedScript.prototype = { 39 wrapObjectForConsole: function(object, canAccessInspectedWindow) 40 { 41 if (canAccessInspectedWindow) 42 return this._wrapObject(object, "console"); 43 var result = {}; 44 result.type = typeof object; 45 result.description = this._toString(object); 46 return result; 47 }, 48 49 _wrapObject: function(object, objectGroupName) 50 { 51 try { 52 var objectId; 53 if (typeof object === "object" || typeof object === "function" || this._isHTMLAllCollection(object)) { 54 var id = this._lastBoundObjectId++; 55 objectId = id; 56 this._idToWrappedObject[id] = object; 57 58 var group = this._objectGroups[objectGroupName]; 59 if (!group) { 60 group = []; 61 this._objectGroups[objectGroupName] = group; 62 } 63 group.push(id); 64 objectId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.JsObject, id); 60 65 } 61 group.push(id); 62 objectId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.JsObject, id); 63 } 64 return InjectedScript.RemoteObject.fromObject(object, objectId); 65 } catch (e) { 66 return InjectedScript.RemoteObject.fromObject("[ Exception: " + e.toString() + " ]"); 67 } 68 }; 69 70 InjectedScript.unwrapObject = function(objectId) { 71 return InjectedScript.idToWrappedObject[objectId]; 72 }; 73 74 InjectedScript.releaseWrapperObjectGroup = function(objectGroupName) { 75 var group = InjectedScript.objectGroups[objectGroupName]; 76 if (!group) 77 return; 78 for (var i = 0; i < group.length; i++) 79 delete InjectedScript.idToWrappedObject[group[i]]; 80 delete InjectedScript.objectGroups[objectGroupName]; 81 }; 82 83 InjectedScript.dispatch = function(methodName, args) 84 { 85 var argsArray = eval("(" + args + ")"); 86 var result = InjectedScript[methodName].apply(InjectedScript, argsArray); 87 if (typeof result === "undefined") { 88 inspectedWindow.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName); 89 result = null; 90 } 91 return result; 92 } 93 94 InjectedScript.getPrototypes = function(nodeId) 95 { 96 var node = InjectedScript._nodeForId(nodeId); 97 if (!node) 98 return false; 99 100 var result = []; 101 var prototype = node; 102 var prototypeId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.Node, nodeId); 103 do { 104 result.push(InjectedScript.RemoteObject.fromObject(prototype, prototypeId)); 105 prototype = prototype.__proto__; 106 prototypeId = InjectedScript.RemoteObjectId.deriveProperty(prototypeId, "__proto__"); 107 } while (prototype) 108 109 return result; 110 } 111 112 InjectedScript.getProperties = function(objectId, ignoreHasOwnProperty, abbreviate) 113 { 114 var object = InjectedScript._objectForId(objectId); 115 if (!InjectedScript._isDefined(object)) 116 return false; 117 var properties = []; 118 119 var propertyNames = ignoreHasOwnProperty ? InjectedScript._getPropertyNames(object) : Object.getOwnPropertyNames(object); 120 if (!ignoreHasOwnProperty && object.__proto__) 121 propertyNames.push("__proto__"); 122 123 // Go over properties, prepare results. 124 for (var i = 0; i < propertyNames.length; ++i) { 125 var propertyName = propertyNames[i]; 126 127 var property = {}; 128 property.name = propertyName + ""; 129 var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName); 130 if (!isGetter) { 131 try { 132 var childObject = object[propertyName]; 133 var childObjectId = InjectedScript.RemoteObjectId.deriveProperty(objectId, propertyName); 134 var childObjectProxy = new InjectedScript.RemoteObject.fromObject(childObject, childObjectId, abbreviate); 135 property.value = childObjectProxy; 136 } catch(e) { 137 property.value = new InjectedScript.RemoteObject.fromException(e); 66 return InjectedScript.RemoteObject.fromObject(object, objectId); 67 } catch (e) { 68 return InjectedScript.RemoteObject.fromObject("[ Exception: " + e.toString() + " ]"); 69 } 70 }, 71 72 releaseWrapperObjectGroup: function(objectGroupName) 73 { 74 var group = this._objectGroups[objectGroupName]; 75 if (!group) 76 return; 77 for (var i = 0; i < group.length; i++) 78 delete this._idToWrappedObject[group[i]]; 79 delete this._objectGroups[objectGroupName]; 80 }, 81 82 dispatch: function(methodName, args) 83 { 84 var argsArray = eval("(" + args + ")"); 85 var result = this[methodName].apply(this, argsArray); 86 if (typeof result === "undefined") { 87 inspectedWindow.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName); 88 result = null; 89 } 90 return result; 91 }, 92 93 getPrototypes: function(nodeId) 94 { 95 var node = this._nodeForId(nodeId); 96 if (!node) 97 return false; 98 99 var result = []; 100 var prototype = node; 101 var prototypeId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.Node, nodeId); 102 do { 103 result.push(InjectedScript.RemoteObject.fromObject(prototype, prototypeId)); 104 prototype = prototype.__proto__; 105 prototypeId = InjectedScript.RemoteObjectId.deriveProperty(prototypeId, "__proto__"); 106 } while (prototype) 107 108 return result; 109 }, 110 111 getProperties: function(objectId, ignoreHasOwnProperty, abbreviate) 112 { 113 var object = this._objectForId(objectId); 114 if (!this._isDefined(object)) 115 return false; 116 var properties = []; 117 118 var propertyNames = ignoreHasOwnProperty ? this._getPropertyNames(object) : Object.getOwnPropertyNames(object); 119 if (!ignoreHasOwnProperty && object.__proto__) 120 propertyNames.push("__proto__"); 121 122 // Go over properties, prepare results. 123 for (var i = 0; i < propertyNames.length; ++i) { 124 var propertyName = propertyNames[i]; 125 126 var property = {}; 127 property.name = propertyName + ""; 128 var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName); 129 if (!isGetter) { 130 try { 131 var childObject = object[propertyName]; 132 var childObjectId = InjectedScript.RemoteObjectId.deriveProperty(objectId, propertyName); 133 var childObjectProxy = new InjectedScript.RemoteObject.fromObject(childObject, childObjectId, abbreviate); 134 property.value = childObjectProxy; 135 } catch(e) { 136 property.value = new InjectedScript.RemoteObject.fromException(e); 137 } 138 } else { 139 // FIXME: this should show something like "getter" (bug 16734). 140 property.value = new InjectedScript.RemoteObject.fromObject("\u2014"); // em dash 141 property.isGetter = true; 138 142 } 139 } else { 140 // FIXME: this should show something like "getter" (bug 16734). 141 property.value = new InjectedScript.RemoteObject.fromObject("\u2014"); // em dash 142 property.isGetter = true; 143 } 144 properties.push(property); 145 } 146 return properties; 147 } 148 149 InjectedScript.setPropertyValue = function(objectId, propertyName, expression) 150 { 151 var object = InjectedScript._objectForId(objectId); 152 if (!InjectedScript._isDefined(object)) 153 return false; 154 155 var expressionLength = expression.length; 156 if (!expressionLength) { 157 delete object[propertyName]; 158 return !(propertyName in object); 159 } 160 161 try { 162 // Surround the expression in parenthesis so the result of the eval is the result 163 // of the whole expression not the last potential sub-expression. 164 165 // There is a regression introduced here: eval is now happening against global object, 166 // not call frame while on a breakpoint. 167 // TODO: bring evaluation against call frame back. 168 var result = inspectedWindow.eval("(" + expression + ")"); 169 // Store the result in the property. 170 object[propertyName] = result; 171 return true; 172 } catch(e) { 143 properties.push(property); 144 } 145 return properties; 146 }, 147 148 setPropertyValue: function(objectId, propertyName, expression) 149 { 150 var object = this._objectForId(objectId); 151 if (!this._isDefined(object)) 152 return false; 153 154 var expressionLength = expression.length; 155 if (!expressionLength) { 156 delete object[propertyName]; 157 return !(propertyName in object); 158 } 159 173 160 try { 174 var result = inspectedWindow.eval("\"" + expression.replace(/"/g, "\\\"") + "\""); 161 // Surround the expression in parenthesis so the result of the eval is the result 162 // of the whole expression not the last potential sub-expression. 163 164 // There is a regression introduced here: eval is now happening against global object, 165 // not call frame while on a breakpoint. 166 // TODO: bring evaluation against call frame back. 167 var result = inspectedWindow.eval("(" + expression + ")"); 168 // Store the result in the property. 175 169 object[propertyName] = result; 176 170 return true; 177 171 } catch(e) { 172 try { 173 var result = inspectedWindow.eval("\"" + expression.replace(/"/g, "\\\"") + "\""); 174 object[propertyName] = result; 175 return true; 176 } catch(e) { 177 return false; 178 } 179 } 180 }, 181 182 _populatePropertyNames: function(object, resultSet) 183 { 184 for (var o = object; o; o = o.__proto__) { 185 try { 186 var names = Object.getOwnPropertyNames(o); 187 for (var i = 0; i < names.length; ++i) 188 resultSet[names[i]] = true; 189 } catch (e) { 190 } 191 } 192 }, 193 194 _getPropertyNames: function(object, resultSet) 195 { 196 var propertyNameSet = {}; 197 this._populatePropertyNames(object, propertyNameSet); 198 return Object.keys(propertyNameSet); 199 }, 200 201 getCompletions: function(expression, includeInspectorCommandLineAPI, callFrameId) 202 { 203 var props = {}; 204 try { 205 var expressionResult; 206 // Evaluate on call frame if call frame id is available. 207 if (typeof callFrameId === "number") { 208 var callFrame = this._callFrameForId(callFrameId); 209 if (!callFrame) 210 return props; 211 if (expression) 212 expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true); 213 else { 214 // Evaluate into properties in scope of the selected call frame. 215 var scopeChain = callFrame.scopeChain; 216 for (var i = 0; i < scopeChain.length; ++i) 217 this._populatePropertyNames(scopeChain[i], props); 218 } 219 } else { 220 if (!expression) 221 expression = "this"; 222 expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); 223 } 224 if (typeof expressionResult === "object") 225 this._populatePropertyNames(expressionResult, props); 226 227 if (includeInspectorCommandLineAPI) { 228 for (var prop in this._commandLineAPI) 229 props[prop] = true; 230 } 231 } catch(e) { 232 } 233 return props; 234 }, 235 236 evaluate: function(expression, objectGroup) 237 { 238 return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup); 239 }, 240 241 _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, dontUseCommandLineAPI) 242 { 243 try { 244 return this._wrapObject(this._evaluateOn(evalFunction, object, expression, dontUseCommandLineAPI), objectGroup); 245 } catch (e) { 246 return InjectedScript.RemoteObject.fromException(e); 247 } 248 }, 249 250 _evaluateOn: function(evalFunction, object, expression, dontUseCommandLineAPI) 251 { 252 if (!dontUseCommandLineAPI) { 253 // Only install command line api object for the time of evaluation. 254 255 // Surround the expression in with statements to inject our command line API so that 256 // the window object properties still take more precedent than our API functions. 257 inspectedWindow.console._commandLineAPI = this._commandLineAPI; 258 259 expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }"; 260 } 261 262 var value = evalFunction.call(object, expression); 263 264 if (!dontUseCommandLineAPI) 265 delete inspectedWindow.console._commandLineAPI; 266 267 // When evaluating on call frame error is not thrown, but returned as a value. 268 if (this._type(value) === "error") 269 throw value.toString(); 270 271 return value; 272 }, 273 274 getNodeId: function(node) 275 { 276 return InjectedScriptHost.pushNodePathToFrontend(node, false, false); 277 }, 278 279 callFrames: function() 280 { 281 var callFrame = InjectedScriptHost.currentCallFrame(); 282 if (!callFrame) 178 283 return false; 179 } 284 285 var result = []; 286 var depth = 0; 287 do { 288 result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); 289 callFrame = callFrame.caller; 290 } while (callFrame); 291 return result; 292 }, 293 294 evaluateInCallFrame: function(callFrameId, code, objectGroup) 295 { 296 var callFrame = this._callFrameForId(callFrameId); 297 if (!callFrame) 298 return false; 299 return this._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true); 300 }, 301 302 _callFrameForId: function(id) 303 { 304 var callFrame = InjectedScriptHost.currentCallFrame(); 305 while (--id >= 0 && callFrame) 306 callFrame = callFrame.caller; 307 return callFrame; 308 }, 309 310 _nodeForId: function(nodeId) 311 { 312 if (!nodeId) 313 return null; 314 return InjectedScriptHost.nodeForId(nodeId); 315 }, 316 317 _objectForId: function(objectId) 318 { 319 // There are three types of object ids used: 320 // - numbers point to DOM Node via the InspectorDOMAgent mapping 321 // - strings point to console objects cached in InspectorController for lazy evaluation upon them 322 // - objects contain complex ids and are currently used for scoped objects 323 var object; 324 if (objectId.type === InjectedScript.RemoteObjectId.Type.Node) 325 object = this._nodeForId(objectId.value); 326 else if (objectId.type === InjectedScript.RemoteObjectId.Type.JsObject) 327 object = this._idToWrappedObject[objectId.value]; 328 else if (objectId.type === InjectedScript.RemoteObjectId.Type.ScopeObject) { 329 var callFrame = this._callFrameForId(objectId.value.callFrame); 330 if (objectId.thisObject) 331 object = callFrame.thisObject; 332 else 333 object = callFrame.scopeChain[objectId.value.chainIndex]; 334 } else 335 return objectId; 336 337 var path = objectId.path; 338 339 // Follow the property path. 340 for (var i = 0; this._isDefined(object) && path && i < path.length; ++i) 341 object = object[path[i]]; 342 343 return object; 344 }, 345 346 pushNodeToFrontend: function(objectId) 347 { 348 var object = this._objectForId(objectId); 349 if (!object || this._type(object) !== "node") 350 return false; 351 return InjectedScriptHost.pushNodePathToFrontend(object, false, false); 352 }, 353 354 evaluateOnSelf: function(funcBody, args) 355 { 356 var func = window.eval("(" + funcBody + ")"); 357 return func.apply(this, args || []); 358 }, 359 360 _isDefined: function(object) 361 { 362 return object || this._isHTMLAllCollection(object); 363 }, 364 365 _isHTMLAllCollection: function(object) 366 { 367 // document.all is reported as undefined, but we still want to process it. 368 return (typeof object === "undefined") && inspectedWindow.HTMLAllCollection && object instanceof inspectedWindow.HTMLAllCollection; 369 }, 370 371 _type: function(obj) 372 { 373 if (obj === null) 374 return "null"; 375 376 var type = typeof obj; 377 if (type !== "object" && type !== "function") { 378 // FIXME(33716): typeof document.all is always 'undefined'. 379 if (this._isHTMLAllCollection(obj)) 380 return "array"; 381 return type; 382 } 383 384 // If owning frame has navigated to somewhere else window properties will be undefined. 385 // In this case just return result of the typeof. 386 if (!inspectedWindow.document) 387 return type; 388 389 if (obj instanceof inspectedWindow.Node) 390 return (obj.nodeType === undefined ? type : "node"); 391 if (obj instanceof inspectedWindow.String) 392 return "string"; 393 if (obj instanceof inspectedWindow.Array) 394 return "array"; 395 if (obj instanceof inspectedWindow.Boolean) 396 return "boolean"; 397 if (obj instanceof inspectedWindow.Number) 398 return "number"; 399 if (obj instanceof inspectedWindow.Date) 400 return "date"; 401 if (obj instanceof inspectedWindow.RegExp) 402 return "regexp"; 403 // FireBug's array detection. 404 if (isFinite(obj.length) && typeof obj.splice === "function") 405 return "array"; 406 if (isFinite(obj.length) && typeof obj.callee === "function") // arguments. 407 return "array"; 408 if (obj instanceof inspectedWindow.NodeList) 409 return "array"; 410 if (obj instanceof inspectedWindow.HTMLCollection) 411 return "array"; 412 if (obj instanceof inspectedWindow.Error) 413 return "error"; 414 return type; 415 }, 416 417 _describe: function(obj, abbreviated) 418 { 419 var type = this._type(obj); 420 421 switch (type) { 422 case "object": 423 case "node": 424 case "array": 425 var className = this._className(obj); 426 if (typeof obj.length === "number") 427 className += "[" + obj.length + "]"; 428 return className; 429 case "string": 430 if (!abbreviated) 431 return obj; 432 if (obj.length > 100) 433 return "\"" + obj.substring(0, 100) + "\u2026\""; 434 return "\"" + obj + "\""; 435 case "function": 436 var objectText = this._toString(obj); 437 if (abbreviated) 438 objectText = /.*/.exec(objectText)[0].replace(/ +$/g, ""); 439 return objectText; 440 default: 441 return this._toString(obj); 442 } 443 }, 444 445 _toString: function(obj) 446 { 447 // We don't use String(obj) because inspectedWindow.String is undefined if owning frame navigated to another page. 448 return "" + obj; 449 }, 450 451 _className: function(obj) 452 { 453 // We can't use the same code for fetching class names of the dom bindings prototype chain. 454 // Both of the methods below result in "Object" names on the foreign engine bindings. 455 // I gave up and am using a check below to distinguish between the egine bingings. 456 457 if (jsEngine == "JSC") { 458 var str = inspectedWindow.Object ? inspectedWindow.Object.prototype.toString.call(obj) : this._toString(obj); 459 return str.replace(/^\[object (.*)\]$/i, "$1"); 460 } else { 461 // V8 462 return obj.constructor && obj.constructor.name || "Object"; 463 } 464 }, 465 466 _logEvent: function(event) 467 { 468 console.log(event.type, event); 469 }, 470 471 _normalizeEventTypes: function(types) 472 { 473 if (typeof types === "undefined") 474 types = [ "mouse", "key", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ]; 475 else if (typeof types === "string") 476 types = [ types ]; 477 478 var result = []; 479 for (var i = 0; i < types.length; i++) { 480 if (types[i] === "mouse") 481 result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout"); 482 else if (types[i] === "key") 483 result.splice(0, 0, "keydown", "keyup", "keypress"); 484 else 485 result.push(types[i]); 486 } 487 return result; 488 }, 489 490 _inspectedNode: function(num) 491 { 492 var nodeId = InjectedScriptHost.inspectedNode(num); 493 return this._nodeForId(nodeId); 494 }, 495 496 _bindToScript: function(func) 497 { 498 var args = Array.prototype.slice.call(arguments, 1); 499 function bound() 500 { 501 return func.apply(injectedScript, args.concat(Array.prototype.slice.call(arguments))); 502 } 503 bound.toString = function() { 504 return "bound: " + func; 505 }; 506 return bound; 180 507 } 181 508 } 182 509 183 InjectedScript._populatePropertyNames = function(object, resultSet) 184 { 185 for (var o = object; o; o = o.__proto__) { 186 try { 187 var names = Object.getOwnPropertyNames(o); 188 for (var i = 0; i < names.length; ++i) 189 resultSet[names[i]] = true; 190 } catch (e) { 191 } 192 } 193 } 194 195 InjectedScript._getPropertyNames = function(object, resultSet) 196 { 197 var propertyNameSet = {}; 198 InjectedScript._populatePropertyNames(object, propertyNameSet); 199 return Object.keys(propertyNameSet); 200 } 201 202 InjectedScript.getCompletions = function(expression, includeInspectorCommandLineAPI, callFrameId) 203 { 204 var props = {}; 205 try { 206 var expressionResult; 207 // Evaluate on call frame if call frame id is available. 208 if (typeof callFrameId === "number") { 209 var callFrame = InjectedScript._callFrameForId(callFrameId); 210 if (!callFrame) 211 return props; 212 if (expression) 213 expressionResult = InjectedScript._evaluateOn(callFrame.evaluate, callFrame, expression, true); 214 else { 215 // Evaluate into properties in scope of the selected call frame. 216 var scopeChain = callFrame.scopeChain; 217 for (var i = 0; i < scopeChain.length; ++i) 218 InjectedScript._populatePropertyNames(scopeChain[i], props); 219 } 220 } else { 221 if (!expression) 222 expression = "this"; 223 expressionResult = InjectedScript._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); 224 } 225 if (typeof expressionResult === "object") 226 InjectedScript._populatePropertyNames(expressionResult, props); 227 228 if (includeInspectorCommandLineAPI) { 229 for (var prop in InjectedScript._commandLineAPI) 230 props[prop] = true; 231 } 232 } catch(e) { 233 } 234 return props; 235 } 236 237 InjectedScript.evaluate = function(expression, objectGroup) 238 { 239 return InjectedScript._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup); 240 } 241 242 InjectedScript._evaluateAndWrap = function(evalFunction, object, expression, objectGroup, dontUseCommandLineAPI) 243 { 244 try { 245 return InjectedScript.wrapObject(InjectedScript._evaluateOn(evalFunction, object, expression, dontUseCommandLineAPI), objectGroup); 246 } catch (e) { 247 return InjectedScript.RemoteObject.fromException(e); 248 } 249 } 250 251 InjectedScript._evaluateOn = function(evalFunction, object, expression, dontUseCommandLineAPI) 252 { 253 if (!dontUseCommandLineAPI) { 254 // Only install command line api object for the time of evaluation. 255 256 // Surround the expression in with statements to inject our command line API so that 257 // the window object properties still take more precedent than our API functions. 258 inspectedWindow.console._commandLineAPI = InjectedScript._commandLineAPI; 259 260 expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }"; 261 } 262 263 var value = evalFunction.call(object, expression); 264 265 if (!dontUseCommandLineAPI) 266 delete inspectedWindow.console._commandLineAPI; 267 268 // When evaluating on call frame error is not thrown, but returned as a value. 269 if (InjectedScript._type(value) === "error") 270 throw value.toString(); 271 272 return value; 273 } 274 275 InjectedScript.getNodeId = function(node) 276 { 277 return InjectedScriptHost.pushNodePathToFrontend(node, false, false); 278 } 279 280 InjectedScript.callFrames = function() 281 { 282 var callFrame = InjectedScriptHost.currentCallFrame(); 283 if (!callFrame) 284 return false; 285 286 var result = []; 287 var depth = 0; 288 do { 289 result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); 290 callFrame = callFrame.caller; 291 } while (callFrame); 292 return result; 293 } 294 295 InjectedScript.evaluateInCallFrame = function(callFrameId, code, objectGroup) 296 { 297 var callFrame = InjectedScript._callFrameForId(callFrameId); 298 if (!callFrame) 299 return false; 300 return InjectedScript._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true); 301 } 302 303 InjectedScript._callFrameForId = function(id) 304 { 305 var callFrame = InjectedScriptHost.currentCallFrame(); 306 while (--id >= 0 && callFrame) 307 callFrame = callFrame.caller; 308 return callFrame; 309 } 310 311 InjectedScript._nodeForId = function(nodeId) 312 { 313 if (!nodeId) 314 return null; 315 return InjectedScriptHost.nodeForId(nodeId); 316 } 317 318 InjectedScript._objectForId = function(objectId) 319 { 320 // There are three types of object ids used: 321 // - numbers point to DOM Node via the InspectorDOMAgent mapping 322 // - strings point to console objects cached in InspectorController for lazy evaluation upon them 323 // - objects contain complex ids and are currently used for scoped objects 324 var object; 325 if (objectId.type === InjectedScript.RemoteObjectId.Type.Node) 326 object = InjectedScript._nodeForId(objectId.value); 327 else if (objectId.type === InjectedScript.RemoteObjectId.Type.JsObject) 328 object = InjectedScript.unwrapObject(objectId.value); 329 else if (objectId.type === InjectedScript.RemoteObjectId.Type.ScopeObject) { 330 var callFrame = InjectedScript._callFrameForId(objectId.value.callFrame); 331 if (objectId.thisObject) 332 object = callFrame.thisObject; 333 else 334 object = callFrame.scopeChain[objectId.value.chainIndex]; 335 } else 336 return objectId; 337 338 var path = objectId.path; 339 340 // Follow the property path. 341 for (var i = 0; InjectedScript._isDefined(object) && path && i < path.length; ++i) 342 object = object[path[i]]; 343 344 return object; 345 } 346 347 InjectedScript.pushNodeToFrontend = function(objectId) 348 { 349 var object = InjectedScript._objectForId(objectId); 350 if (!object || InjectedScript._type(object) !== "node") 351 return false; 352 return InjectedScriptHost.pushNodePathToFrontend(object, false, false); 353 } 510 var injectedScript = new InjectedScript(); 354 511 355 512 // FIXME: RemoteObjectId and RemoteObject structs must match the WebInspector.* ones. Should reuse same file instead. … … 390 547 InjectedScript.RemoteObject.fromObject = function(object, objectId, abbreviate) 391 548 { 392 var type = InjectedScript._type(object);549 var type = injectedScript._type(object); 393 550 var rawType = typeof object; 394 551 var hasChildren = (rawType === "object" && object !== null && (Object.getOwnPropertyNames(object).length || !!object.__proto__)) || rawType === "function"; 395 552 var description = ""; 396 553 try { 397 var description = InjectedScript._describe(object, abbreviate);554 var description = injectedScript._describe(object, abbreviate); 398 555 return new InjectedScript.RemoteObject(objectId, type, description, hasChildren); 399 556 } catch (e) { 400 557 return InjectedScript.RemoteObject.fromException(e); 401 558 } 402 }403 404 InjectedScript.evaluateOnSelf = function(funcBody, args)405 {406 var func = window.eval("(" + funcBody + ")");407 return func.apply(this, args || []);408 559 } 409 560 … … 466 617 } 467 618 468 InjectedScript._isDefined = function(object)469 {470 return object || InjectedScript._isHTMLAllCollection(object);471 }472 473 InjectedScript._isHTMLAllCollection = function(object)474 {475 // document.all is reported as undefined, but we still want to process it.476 return (typeof object === "undefined") && inspectedWindow.HTMLAllCollection && object instanceof inspectedWindow.HTMLAllCollection;477 }478 479 InjectedScript._type = function(obj)480 {481 if (obj === null)482 return "null";483 484 var type = typeof obj;485 if (type !== "object" && type !== "function") {486 // FIXME(33716): typeof document.all is always 'undefined'.487 if (InjectedScript._isHTMLAllCollection(obj))488 return "array";489 return type;490 }491 492 // If owning frame has navigated to somewhere else window properties will be undefined.493 // In this case just return result of the typeof.494 if (!inspectedWindow.document)495 return type;496 497 if (obj instanceof inspectedWindow.Node)498 return (obj.nodeType === undefined ? type : "node");499 if (obj instanceof inspectedWindow.String)500 return "string";501 if (obj instanceof inspectedWindow.Array)502 return "array";503 if (obj instanceof inspectedWindow.Boolean)504 return "boolean";505 if (obj instanceof inspectedWindow.Number)506 return "number";507 if (obj instanceof inspectedWindow.Date)508 return "date";509 if (obj instanceof inspectedWindow.RegExp)510 return "regexp";511 // FireBug's array detection.512 if (isFinite(obj.length) && typeof obj.splice === "function")513 return "array";514 if (isFinite(obj.length) && typeof obj.callee === "function") // arguments.515 return "array";516 if (obj instanceof inspectedWindow.NodeList)517 return "array";518 if (obj instanceof inspectedWindow.HTMLCollection)519 return "array";520 if (obj instanceof inspectedWindow.Error)521 return "error";522 return type;523 }524 525 InjectedScript._describe = function(obj, abbreviated)526 {527 var type = InjectedScript._type(obj);528 529 switch (type) {530 case "object":531 case "node":532 case "array":533 var className = InjectedScript._className(obj);534 if (typeof obj.length === "number")535 className += "[" + obj.length + "]";536 return className;537 case "string":538 if (!abbreviated)539 return obj;540 if (obj.length > 100)541 return "\"" + obj.substring(0, 100) + "\u2026\"";542 return "\"" + obj + "\"";543 case "function":544 var objectText = InjectedScript._toString(obj);545 if (abbreviated)546 objectText = /.*/.exec(objectText)[0].replace(/ +$/g, "");547 return objectText;548 default:549 return InjectedScript._toString(obj);550 }551 }552 553 InjectedScript._toString = function(obj)554 {555 // We don't use String(obj) because inspectedWindow.String is undefined if owning frame navigated to another page.556 return "" + obj;557 }558 559 InjectedScript._className = function(obj)560 {561 // We can't use the same code for fetching class names of the dom bindings prototype chain.562 // Both of the methods below result in "Object" names on the foreign engine bindings.563 // I gave up and am using a check below to distinguish between the egine bingings.564 565 if (jsEngine == "JSC") {566 var str = inspectedWindow.Object ? inspectedWindow.Object.prototype.toString.call(obj) : InjectedScript._toString(obj);567 return str.replace(/^\[object (.*)\]$/i, "$1");568 } else {569 // V8570 return obj.constructor && obj.constructor.name || "Object";571 }572 }573 574 InjectedScript._logEvent = function(event)575 {576 console.log(event.type, event);577 }578 579 InjectedScript._normalizeEventTypes = function(types)580 {581 if (typeof types === "undefined")582 types = [ "mouse", "key", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ];583 else if (typeof types === "string")584 types = [ types ];585 586 var result = [];587 for (var i = 0; i < types.length; i++) {588 if (types[i] === "mouse")589 result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout");590 else if (types[i] === "key")591 result.splice(0, 0, "keydown", "keyup", "keypress");592 else593 result.push(types[i]);594 }595 return result;596 }597 598 InjectedScript._inspectedNode = function(num)599 {600 var nodeId = InjectedScriptHost.inspectedNode(num);601 return InjectedScript._nodeForId(nodeId);602 }603 604 619 function CommandLineAPI() 605 620 { 621 for (var i = 0; i < 5; ++i) 622 this.__defineGetter__("$" + i, injectedScript._bindToScript(injectedScript._inspectedNode, i)); 606 623 } 607 624 … … 670 687 if (!object || !object.addEventListener || !object.removeEventListener) 671 688 return; 672 types = InjectedScript._normalizeEventTypes(types);689 types = injectedScript._normalizeEventTypes(types); 673 690 for (var i = 0; i < types.length; ++i) { 674 object.removeEventListener(types[i], InjectedScript._logEvent, false);675 object.addEventListener(types[i], InjectedScript._logEvent, false);691 object.removeEventListener(types[i], injectedScript._logEvent, false); 692 object.addEventListener(types[i], injectedScript._logEvent, false); 676 693 } 677 694 }, … … 681 698 if (!object || !object.addEventListener || !object.removeEventListener) 682 699 return; 683 types = InjectedScript._normalizeEventTypes(types);700 types = injectedScript._normalizeEventTypes(types); 684 701 for (var i = 0; i < types.length; ++i) 685 object.removeEventListener(types[i], InjectedScript._logEvent, false);702 object.removeEventListener(types[i], injectedScript._logEvent, false); 686 703 }, 687 704 … … 692 709 693 710 inspectedWindow.console.log(object); 694 if ( InjectedScript._type(object) === "node")711 if (injectedScript._type(object) === "node") 695 712 InjectedScriptHost.pushNodePathToFrontend(object, false, true); 696 713 else { 697 switch ( InjectedScript._describe(object)) {714 switch (injectedScript._describe(object)) { 698 715 case "Database": 699 716 InjectedScriptHost.selectDatabase(object); … … 708 725 copy: function(object) 709 726 { 710 if ( InjectedScript._type(object) === "node") {727 if (injectedScript._type(object) === "node") { 711 728 var nodeId = InjectedScriptHost.pushNodePathToFrontend(object, false, false); 712 729 InjectedScriptHost.copyNode(nodeId); … … 718 735 { 719 736 InjectedScriptHost.clearConsoleMessages(); 720 },721 722 get $0()723 {724 return InjectedScript._inspectedNode(0);725 },726 727 get $1()728 {729 return InjectedScript._inspectedNode(1);730 },731 732 get $2()733 {734 return InjectedScript._inspectedNode(2);735 },736 737 get $3()738 {739 return InjectedScript._inspectedNode(3);740 },741 742 get $4()743 {744 return InjectedScript._inspectedNode(4);745 737 } 746 738 } 747 739 748 InjectedScript._commandLineAPI = new CommandLineAPI(); 749 750 return InjectedScript; 740 injectedScript._commandLineAPI = new CommandLineAPI(); 741 return injectedScript; 751 742 });
Note: See TracChangeset
for help on using the changeset viewer.