Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(307)

Side by Side Diff: sky/engine/core/inspector/InjectedScriptSource.js

Issue 727593004: Wire up the Inspector V8 Debugger (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Actually works Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /**
31 * @param {InjectedScriptHost} InjectedScriptHost
32 * @param {Window} inspectedWindow
33 * @param {number} injectedScriptId
34 */
35 (function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
36
37 /**
38 * Protect against Object overwritten by the user code.
39 * @suppress {duplicate}
40 */
41 var Object = /** @type {function(new:Object, *=)} */ ({}.constructor);
42
43 /**
44 * @param {!Array.<T>} array
45 * @param {...} var_args
46 * @template T
47 */
48 function push(array, var_args)
49 {
50 for (var i = 1; i < arguments.length; ++i)
51 array[array.length] = arguments[i];
52 }
53
54 /**
55 * @param {!Arguments.<T>} array
56 * @param {number=} index
57 * @return {!Array.<T>}
58 * @template T
59 */
60 function slice(array, index)
61 {
62 var result = [];
63 for (var i = index || 0, j = 0; i < array.length; ++i, ++j)
64 result[j] = array[i];
65 return result;
66 }
67
68 /**
69 * @param {!Array.<T>} array1
70 * @param {!Array.<T>} array2
71 * @return {!Array.<T>}
72 * @template T
73 */
74 function concat(array1, array2)
75 {
76 var result = [];
77 for (var i = 0; i < array1.length; ++i)
78 push(result, array1[i]);
79 for (var i = 0; i < array2.length; ++i)
80 push(result, array2[i]);
81 return result;
82 }
83
84 /**
85 * @param {*} obj
86 * @return {string}
87 */
88 function toString(obj)
89 {
90 // We don't use String(obj) because it could be overriden.
91 return "" + obj;
92 }
93
94 /**
95 * @param {*} obj
96 * @return {string}
97 */
98 function toStringDescription(obj)
99 {
100 if (typeof obj === "number" && obj === 0 && 1 / obj < 0)
101 return "-0"; // Negative zero.
102 return "" + obj;
103 }
104
105 /**
106 * Please use this bind, not the one from Function.prototype
107 * @param {function(...)} func
108 * @param {?Object} thisObject
109 * @param {...} var_args
110 * @return {function(...)}
111 */
112 function bind(func, thisObject, var_args)
113 {
114 var args = slice(arguments, 2);
115
116 /**
117 * @param {...} var_args
118 */
119 function bound(var_args)
120 {
121 return InjectedScriptHost.callFunction(func, thisObject, concat(args, sl ice(arguments)));
122 }
123 bound.toString = function()
124 {
125 return "bound: " + func;
126 };
127 return bound;
128 }
129
130 /**
131 * @param {T} obj
132 * @return {T}
133 * @template T
134 */
135 function nullifyObjectProto(obj)
136 {
137 if (obj && typeof obj === "object")
138 obj.__proto__ = null;
139 return obj;
140 }
141
142 /**
143 * @param {*} obj
144 * @return {boolean}
145 */
146 function isUInt32(obj)
147 {
148 return typeof obj === "number" && obj >>> 0 === obj && (obj > 0 || 1 / obj > 0);
149 }
150
151 /**
152 * FireBug's array detection.
153 * @param {*} obj
154 * @return {boolean}
155 */
156 function isArrayLike(obj)
157 {
158 if (typeof obj !== "object")
159 return false;
160 try {
161 if (typeof obj.splice === "function")
162 return isUInt32(obj.length);
163 } catch (e) {
164 }
165 return false;
166 }
167
168 /**
169 * @param {number} a
170 * @param {number} b
171 * @return {number}
172 */
173 function max(a, b)
174 {
175 return a > b ? a : b;
176 }
177
178 /**
179 * FIXME: Remove once ES6 is supported natively by JS compiler.
180 * @param {*} obj
181 * @return {boolean}
182 */
183 function isSymbol(obj)
184 {
185 var type = typeof obj;
186 return (type === "symbol");
187 }
188
189 /**
190 * @constructor
191 */
192 var InjectedScript = function()
193 {
194 /** @type {number} */
195 this._lastBoundObjectId = 1;
196 /** @type {!Object.<number, (!Object|symbol)>} */
197 this._idToWrappedObject = { __proto__: null };
198 /** @type {!Object.<number, string>} */
199 this._idToObjectGroupName = { __proto__: null };
200 /** @type {!Object.<string, !Array.<number>>} */
201 this._objectGroups = { __proto__: null };
202 /** @type {!Object.<string, !Object>} */
203 this._modules = { __proto__: null };
204 }
205
206 /**
207 * @type {!Object.<string, boolean>}
208 * @const
209 */
210 InjectedScript.primitiveTypes = {
211 "undefined": true,
212 "boolean": true,
213 "number": true,
214 "string": true,
215 __proto__: null
216 }
217
218 InjectedScript.prototype = {
219 /**
220 * @param {*} object
221 * @return {boolean}
222 */
223 isPrimitiveValue: function(object)
224 {
225 // FIXME(33716): typeof document.all is always 'undefined'.
226 return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllC ollection(object);
227 },
228
229 /**
230 * @param {*} object
231 * @param {string} groupName
232 * @param {boolean} canAccessInspectedWindow
233 * @param {boolean} generatePreview
234 * @return {!RuntimeAgent.RemoteObject}
235 */
236 wrapObject: function(object, groupName, canAccessInspectedWindow, generatePr eview)
237 {
238 if (canAccessInspectedWindow)
239 return this._wrapObject(object, groupName, false, generatePreview);
240 return this._fallbackWrapper(object);
241 },
242
243 /**
244 * @param {*} object
245 * @return {!RuntimeAgent.RemoteObject}
246 */
247 _fallbackWrapper: function(object)
248 {
249 var result = { __proto__: null };
250 result.type = typeof object;
251 if (this.isPrimitiveValue(object))
252 result.value = object;
253 else
254 result.description = toString(object);
255 return /** @type {!RuntimeAgent.RemoteObject} */ (result);
256 },
257
258 /**
259 * @param {boolean} canAccessInspectedWindow
260 * @param {!Object} table
261 * @param {!Array.<string>|string|boolean} columns
262 * @return {!RuntimeAgent.RemoteObject}
263 */
264 wrapTable: function(canAccessInspectedWindow, table, columns)
265 {
266 if (!canAccessInspectedWindow)
267 return this._fallbackWrapper(table);
268 var columnNames = null;
269 if (typeof columns === "string")
270 columns = [columns];
271 if (InjectedScriptHost.subtype(columns) === "array") {
272 columnNames = [];
273 for (var i = 0; i < columns.length; ++i)
274 columnNames[i] = toString(columns[i]);
275 }
276 return this._wrapObject(table, "console", false, true, columnNames, true );
277 },
278
279 /**
280 * @param {*} object
281 */
282 inspectNode: function(object)
283 {
284 this._inspect(object);
285 },
286
287 /**
288 * @param {*} object
289 * @return {*}
290 */
291 _inspect: function(object)
292 {
293 if (arguments.length === 0)
294 return;
295
296 var objectId = this._wrapObject(object, "");
297 var hints = { __proto__: null };
298
299 InjectedScriptHost.inspect(objectId, hints);
300 return object;
301 },
302
303 /**
304 * This method cannot throw.
305 * @param {*} object
306 * @param {string=} objectGroupName
307 * @param {boolean=} forceValueType
308 * @param {boolean=} generatePreview
309 * @param {?Array.<string>=} columnNames
310 * @param {boolean=} isTable
311 * @return {!RuntimeAgent.RemoteObject}
312 * @suppress {checkTypes}
313 */
314 _wrapObject: function(object, objectGroupName, forceValueType, generatePrevi ew, columnNames, isTable)
315 {
316 try {
317 return new InjectedScript.RemoteObject(object, objectGroupName, forc eValueType, generatePreview, columnNames, isTable);
318 } catch (e) {
319 try {
320 var description = injectedScript._describe(e);
321 } catch (ex) {
322 var description = "<failed to convert exception to string>";
323 }
324 return new InjectedScript.RemoteObject(description);
325 }
326 },
327
328 /**
329 * @param {!Object|symbol} object
330 * @param {string=} objectGroupName
331 * @return {string}
332 */
333 _bind: function(object, objectGroupName)
334 {
335 var id = this._lastBoundObjectId++;
336 this._idToWrappedObject[id] = object;
337 var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "}";
338 if (objectGroupName) {
339 var group = this._objectGroups[objectGroupName];
340 if (!group) {
341 group = [];
342 this._objectGroups[objectGroupName] = group;
343 }
344 push(group, id);
345 this._idToObjectGroupName[id] = objectGroupName;
346 }
347 return objectId;
348 },
349
350 /**
351 * @param {string} objectId
352 * @return {!Object}
353 */
354 _parseObjectId: function(objectId)
355 {
356 return nullifyObjectProto(InjectedScriptHost.eval("(" + objectId + ")")) ;
357 },
358
359 /**
360 * @param {string} objectGroupName
361 */
362 releaseObjectGroup: function(objectGroupName)
363 {
364 if (objectGroupName === "console")
365 delete this._lastResult;
366 var group = this._objectGroups[objectGroupName];
367 if (!group)
368 return;
369 for (var i = 0; i < group.length; i++)
370 this._releaseObject(group[i]);
371 delete this._objectGroups[objectGroupName];
372 },
373
374 /**
375 * @param {string} methodName
376 * @param {string} args
377 * @return {*}
378 */
379 dispatch: function(methodName, args)
380 {
381 var argsArray = InjectedScriptHost.eval("(" + args + ")");
382 var result = InjectedScriptHost.callFunction(this[methodName], this, arg sArray);
383 if (typeof result === "undefined") {
384 inspectedWindow.console.error("Web Inspector error: InjectedScript.% s returns undefined", methodName);
385 result = null;
386 }
387 return result;
388 },
389
390 /**
391 * @param {string} objectId
392 * @param {boolean} ownProperties
393 * @param {boolean} accessorPropertiesOnly
394 * @return {!Array.<!RuntimeAgent.PropertyDescriptor>|boolean}
395 */
396 getProperties: function(objectId, ownProperties, accessorPropertiesOnly)
397 {
398 var parsedObjectId = this._parseObjectId(objectId);
399 var object = this._objectForId(parsedObjectId);
400 var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
401
402 if (!this._isDefined(object) || isSymbol(object))
403 return false;
404 object = /** @type {!Object} */ (object);
405 var descriptors = this._propertyDescriptors(object, ownProperties, acces sorPropertiesOnly);
406
407 // Go over properties, wrap object values.
408 for (var i = 0; i < descriptors.length; ++i) {
409 var descriptor = descriptors[i];
410 if ("get" in descriptor)
411 descriptor.get = this._wrapObject(descriptor.get, objectGroupNam e);
412 if ("set" in descriptor)
413 descriptor.set = this._wrapObject(descriptor.set, objectGroupNam e);
414 if ("value" in descriptor)
415 descriptor.value = this._wrapObject(descriptor.value, objectGrou pName);
416 if (!("configurable" in descriptor))
417 descriptor.configurable = false;
418 if (!("enumerable" in descriptor))
419 descriptor.enumerable = false;
420 if ("symbol" in descriptor)
421 descriptor.symbol = this._wrapObject(descriptor.symbol, objectGr oupName);
422 }
423 return descriptors;
424 },
425
426 /**
427 * @param {string} objectId
428 * @return {!Array.<!Object>|boolean}
429 */
430 getInternalProperties: function(objectId)
431 {
432 var parsedObjectId = this._parseObjectId(objectId);
433 var object = this._objectForId(parsedObjectId);
434 var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
435 if (!this._isDefined(object) || isSymbol(object))
436 return false;
437 object = /** @type {!Object} */ (object);
438 var descriptors = [];
439 var internalProperties = InjectedScriptHost.getInternalProperties(object );
440 if (internalProperties) {
441 for (var i = 0; i < internalProperties.length; i++) {
442 var property = internalProperties[i];
443 var descriptor = {
444 name: property.name,
445 value: this._wrapObject(property.value, objectGroupName),
446 __proto__: null
447 };
448 push(descriptors, descriptor);
449 }
450 }
451 return descriptors;
452 },
453
454 /**
455 * @param {string} functionId
456 * @return {!DebuggerAgent.FunctionDetails|string}
457 */
458 getFunctionDetails: function(functionId)
459 {
460 var parsedFunctionId = this._parseObjectId(functionId);
461 var func = this._objectForId(parsedFunctionId);
462 if (typeof func !== "function")
463 return "Cannot resolve function by id.";
464 var details = nullifyObjectProto(InjectedScriptHost.functionDetails(func ));
465 if ("rawScopes" in details) {
466 var objectGroupName = this._idToObjectGroupName[parsedFunctionId.id] ;
467 var rawScopes = details.rawScopes;
468 delete details.rawScopes;
469 var scopes = [];
470 for (var i = 0; i < rawScopes.length; ++i)
471 scopes[i] = InjectedScript.CallFrameProxy._createScopeJson(rawSc opes[i].type, rawScopes[i].object, objectGroupName);
472 details.scopeChain = scopes;
473 }
474 return details;
475 },
476
477 /**
478 * @param {string} objectId
479 * @return {!Array.<!Object>|string}
480 */
481 getCollectionEntries: function(objectId)
482 {
483 var parsedObjectId = this._parseObjectId(objectId);
484 var object = this._objectForId(parsedObjectId);
485 if (!object || typeof object !== "object")
486 return "Could not find object with given id";
487 var entries = InjectedScriptHost.collectionEntries(object);
488 if (!entries)
489 return "Object with given id is not a collection";
490 var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
491 for (var i = 0; i < entries.length; ++i) {
492 var entry = nullifyObjectProto(entries[i]);
493 if ("key" in entry)
494 entry.key = this._wrapObject(entry.key, objectGroupName);
495 entry.value = this._wrapObject(entry.value, objectGroupName);
496 entries[i] = entry;
497 }
498 return entries;
499 },
500
501 /**
502 * @param {string} objectId
503 */
504 releaseObject: function(objectId)
505 {
506 var parsedObjectId = this._parseObjectId(objectId);
507 this._releaseObject(parsedObjectId.id);
508 },
509
510 /**
511 * @param {number} id
512 */
513 _releaseObject: function(id)
514 {
515 delete this._idToWrappedObject[id];
516 delete this._idToObjectGroupName[id];
517 },
518
519 /**
520 * @param {!Object} object
521 * @param {boolean=} ownProperties
522 * @param {boolean=} accessorPropertiesOnly
523 * @return {!Array.<!Object>}
524 */
525 _propertyDescriptors: function(object, ownProperties, accessorPropertiesOnly )
526 {
527 var descriptors = [];
528 var propertyProcessed = { __proto__: null };
529
530 /**
531 * @param {?Object} o
532 * @param {!Array.<string|symbol>} properties
533 */
534 function process(o, properties)
535 {
536 for (var i = 0; i < properties.length; ++i) {
537 var property = properties[i];
538 if (propertyProcessed[property])
539 continue;
540
541 var name = property;
542 if (isSymbol(property))
543 name = injectedScript._describe(property);
544
545 try {
546 propertyProcessed[property] = true;
547 var descriptor = nullifyObjectProto(InjectedScriptHost.suppr essWarningsAndCallFunction(Object.getOwnPropertyDescriptor, Object, [o, property ]));
548 if (descriptor) {
549 if (accessorPropertiesOnly && !("get" in descriptor || " set" in descriptor))
550 continue;
551 } else {
552 // Not all bindings provide proper descriptors. Fall bac k to the writable, configurable property.
553 if (accessorPropertiesOnly)
554 continue;
555 try {
556 descriptor = { name: name, value: o[property], writa ble: false, configurable: false, enumerable: false, __proto__: null };
557 if (o === object)
558 descriptor.isOwn = true;
559 push(descriptors, descriptor);
560 } catch (e) {
561 // Silent catch.
562 }
563 continue;
564 }
565 } catch (e) {
566 if (accessorPropertiesOnly)
567 continue;
568 var descriptor = { __proto__: null };
569 descriptor.value = e;
570 descriptor.wasThrown = true;
571 }
572
573 descriptor.name = name;
574 if (o === object)
575 descriptor.isOwn = true;
576 if (isSymbol(property))
577 descriptor.symbol = property;
578 push(descriptors, descriptor);
579 }
580 }
581
582 for (var o = object; this._isDefined(o); o = o.__proto__) {
583 // First call Object.keys() to enforce ordering of the property desc riptors.
584 process(o, Object.keys(/** @type {!Object} */ (o)));
585 process(o, Object.getOwnPropertyNames(/** @type {!Object} */ (o)));
586 if (Object.getOwnPropertySymbols)
587 process(o, Object.getOwnPropertySymbols(/** @type {!Object} */ ( o)));
588
589 if (ownProperties) {
590 if (object.__proto__ && !accessorPropertiesOnly)
591 push(descriptors, { name: "__proto__", value: object.__proto __, writable: true, configurable: true, enumerable: false, isOwn: true, __proto_ _: null });
592 break;
593 }
594 }
595
596 return descriptors;
597 },
598
599 /**
600 * @param {string} expression
601 * @param {string} objectGroup
602 * @param {boolean} injectCommandLineAPI
603 * @param {boolean} returnByValue
604 * @param {boolean} generatePreview
605 * @return {*}
606 */
607 evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByVa lue, generatePreview)
608 {
609 return this._evaluateAndWrap(null, null, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview);
610 },
611
612 /**
613 * @param {string} objectId
614 * @param {string} expression
615 * @param {string} args
616 * @param {boolean} returnByValue
617 * @return {!Object|string}
618 */
619 callFunctionOn: function(objectId, expression, args, returnByValue)
620 {
621 var parsedObjectId = this._parseObjectId(objectId);
622 var object = this._objectForId(parsedObjectId);
623 if (!this._isDefined(object))
624 return "Could not find object with given id";
625
626 if (args) {
627 var resolvedArgs = [];
628 args = InjectedScriptHost.eval(args);
629 for (var i = 0; i < args.length; ++i) {
630 try {
631 resolvedArgs[i] = this._resolveCallArgument(args[i]);
632 } catch (e) {
633 return toString(e);
634 }
635 }
636 }
637
638 try {
639 var objectGroup = this._idToObjectGroupName[parsedObjectId.id];
640 var func = InjectedScriptHost.eval("(" + expression + ")");
641 if (typeof func !== "function")
642 return "Given expression does not evaluate to a function";
643
644 return { wasThrown: false,
645 result: this._wrapObject(InjectedScriptHost.callFunction(fu nc, object, resolvedArgs), objectGroup, returnByValue),
646 __proto__: null };
647 } catch (e) {
648 return this._createThrownValue(e, objectGroup, false);
649 }
650 },
651
652 /**
653 * Resolves a value from CallArgument description.
654 * @param {!RuntimeAgent.CallArgument} callArgumentJson
655 * @return {*} resolved value
656 * @throws {string} error message
657 */
658 _resolveCallArgument: function(callArgumentJson)
659 {
660 callArgumentJson = nullifyObjectProto(callArgumentJson);
661 var objectId = callArgumentJson.objectId;
662 if (objectId) {
663 var parsedArgId = this._parseObjectId(objectId);
664 if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScri ptId)
665 throw "Arguments should belong to the same JavaScript world as t he target object.";
666
667 var resolvedArg = this._objectForId(parsedArgId);
668 if (!this._isDefined(resolvedArg))
669 throw "Could not find object with given id";
670
671 return resolvedArg;
672 } else if ("value" in callArgumentJson) {
673 var value = callArgumentJson.value;
674 if (callArgumentJson.type === "number" && typeof value !== "number")
675 value = Number(value);
676 return value;
677 }
678 return undefined;
679 },
680
681 /**
682 * @param {?function(string):*} evalFunction
683 * @param {?Object} object
684 * @param {string} expression
685 * @param {string} objectGroup
686 * @param {boolean} isEvalOnCallFrame
687 * @param {boolean} injectCommandLineAPI
688 * @param {boolean} returnByValue
689 * @param {boolean} generatePreview
690 * @param {!Array.<!Object>=} scopeChain
691 * @return {!Object}
692 */
693 _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, is EvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, scopeChai n)
694 {
695 var wrappedResult = this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, scopeChain);
696 if (!wrappedResult.exceptionDetails) {
697 return { wasThrown: false,
698 result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
699 __proto__: null };
700 }
701 return this._createThrownValue(wrappedResult.result, objectGroup, genera tePreview, wrappedResult.exceptionDetails);
702 },
703
704 /**
705 * @param {*} value
706 * @param {string} objectGroup
707 * @param {boolean} generatePreview
708 * @param {!DebuggerAgent.ExceptionDetails=} exceptionDetails
709 * @return {!Object}
710 */
711 _createThrownValue: function(value, objectGroup, generatePreview, exceptionD etails)
712 {
713 var remoteObject = this._wrapObject(value, objectGroup, false, generateP review && !(value instanceof Error));
714 if (!remoteObject.description){
715 try {
716 remoteObject.description = toStringDescription(value);
717 } catch (e) {}
718 }
719 return { wasThrown: true, result: remoteObject, exceptionDetails: except ionDetails, __proto__: null };
720 },
721
722 /**
723 * @param {?function(string):*} evalFunction
724 * @param {?Object} object
725 * @param {string} objectGroup
726 * @param {string} expression
727 * @param {boolean} isEvalOnCallFrame
728 * @param {boolean} injectCommandLineAPI
729 * @param {!Array.<!Object>=} scopeChain
730 * @return {*}
731 */
732 _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalO nCallFrame, injectCommandLineAPI, scopeChain)
733 {
734 // Only install command line api object for the time of evaluation.
735 // Surround the expression in with statements to inject our command line API so that
736 // the window object properties still take more precedent than our API f unctions.
737
738 injectCommandLineAPI = injectCommandLineAPI && !("__commandLineAPI" in i nspectedWindow);
739 var injectScopeChain = scopeChain && scopeChain.length && !("__scopeChai nForEval" in inspectedWindow);
740
741 try {
742 var prefix = "";
743 var suffix = "";
744 if (injectCommandLineAPI) {
745 inspectedWindow.__commandLineAPI = new CommandLineAPI(this._comm andLineAPIImpl, isEvalOnCallFrame ? object : null);
746 prefix = "with (__commandLineAPI || { __proto__: null }) {";
747 suffix = "}";
748 }
749 if (injectScopeChain) {
750 inspectedWindow.__scopeChainForEval = scopeChain;
751 for (var i = 0; i < scopeChain.length; ++i) {
752 prefix = "with (__scopeChainForEval[" + i + "] || { __proto_ _: null }) {" + (suffix ? " " : "") + prefix;
753 if (suffix)
754 suffix += " }";
755 else
756 suffix = "}";
757 }
758 }
759
760 if (prefix)
761 expression = prefix + "\n" + expression + "\n" + suffix;
762 var wrappedResult = evalFunction ? InjectedScriptHost.callFunction(e valFunction, object, [expression]) : InjectedScriptHost.evaluateWithExceptionDet ails(expression);
763 if (objectGroup === "console" && !wrappedResult.exceptionDetails)
764 this._lastResult = wrappedResult.result;
765 return wrappedResult;
766 } finally {
767 if (injectCommandLineAPI)
768 delete inspectedWindow.__commandLineAPI;
769 if (injectScopeChain)
770 delete inspectedWindow.__scopeChainForEval;
771 }
772 },
773
774 /**
775 * @param {?Object} callFrame
776 * @param {number} asyncOrdinal
777 * @return {!Array.<!InjectedScript.CallFrameProxy>|boolean}
778 */
779 wrapCallFrames: function(callFrame, asyncOrdinal)
780 {
781 if (!callFrame)
782 return false;
783
784 var result = [];
785 var depth = 0;
786 do {
787 result[depth] = new InjectedScript.CallFrameProxy(depth, callFrame, asyncOrdinal);
788 callFrame = callFrame.caller;
789 ++depth;
790 } while (callFrame);
791 return result;
792 },
793
794 /**
795 * @param {!Object} topCallFrame
796 * @param {!Array.<!Object>} asyncCallStacks
797 * @param {string} callFrameId
798 * @param {string} expression
799 * @param {string} objectGroup
800 * @param {boolean} injectCommandLineAPI
801 * @param {boolean} returnByValue
802 * @param {boolean} generatePreview
803 * @return {*}
804 */
805 evaluateOnCallFrame: function(topCallFrame, asyncCallStacks, callFrameId, ex pression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
806 {
807 var parsedCallFrameId = nullifyObjectProto(InjectedScriptHost.eval("(" + callFrameId + ")"));
808 var callFrame = this._callFrameForParsedId(topCallFrame, parsedCallFrame Id, asyncCallStacks);
809 if (!callFrame)
810 return "Could not find call frame with given id";
811 if (parsedCallFrameId["asyncOrdinal"])
812 return this._evaluateAndWrap(null, null, expression, objectGroup, fa lse, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain) ;
813 return this._evaluateAndWrap(callFrame.evaluateWithExceptionDetails, cal lFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, gene ratePreview);
814 },
815
816 /**
817 * @param {!Object} topCallFrame
818 * @param {string} callFrameId
819 * @return {*}
820 */
821 restartFrame: function(topCallFrame, callFrameId)
822 {
823 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
824 if (!callFrame)
825 return "Could not find call frame with given id";
826 var result = callFrame.restart();
827 if (result === false)
828 result = "Restart frame is not supported";
829 return result;
830 },
831
832 /**
833 * @param {!Object} topCallFrame
834 * @param {string} callFrameId
835 * @return {*} a stepIn position array ready for protocol JSON or a string e rror
836 */
837 getStepInPositions: function(topCallFrame, callFrameId)
838 {
839 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
840 if (!callFrame)
841 return "Could not find call frame with given id";
842 var stepInPositionsUnpacked = JSON.parse(callFrame.stepInPositions);
843 if (typeof stepInPositionsUnpacked !== "object")
844 return "Step in positions not available";
845 return stepInPositionsUnpacked;
846 },
847
848 /**
849 * Either callFrameId or functionObjectId must be specified.
850 * @param {!Object} topCallFrame
851 * @param {string|boolean} callFrameId or false
852 * @param {string|boolean} functionObjectId or false
853 * @param {number} scopeNumber
854 * @param {string} variableName
855 * @param {string} newValueJsonString RuntimeAgent.CallArgument structure se rialized as string
856 * @return {string|undefined} undefined if success or an error message
857 */
858 setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scop eNumber, variableName, newValueJsonString)
859 {
860 var setter;
861 if (typeof callFrameId === "string") {
862 var callFrame = this._callFrameForId(topCallFrame, callFrameId);
863 if (!callFrame)
864 return "Could not find call frame with given id";
865 setter = bind(callFrame.setVariableValue, callFrame);
866 } else {
867 var parsedFunctionId = this._parseObjectId(/** @type {string} */ (fu nctionObjectId));
868 var func = this._objectForId(parsedFunctionId);
869 if (typeof func !== "function")
870 return "Cannot resolve function by id.";
871 setter = bind(InjectedScriptHost.setFunctionVariableValue, InjectedS criptHost, func);
872 }
873 var newValueJson;
874 try {
875 newValueJson = InjectedScriptHost.eval("(" + newValueJsonString + ") ");
876 } catch (e) {
877 return "Failed to parse new value JSON " + newValueJsonString + " : " + e;
878 }
879 var resolvedValue;
880 try {
881 resolvedValue = this._resolveCallArgument(newValueJson);
882 } catch (e) {
883 return toString(e);
884 }
885 try {
886 setter(scopeNumber, variableName, resolvedValue);
887 } catch (e) {
888 return "Failed to change variable value: " + e;
889 }
890 return undefined;
891 },
892
893 /**
894 * @param {!Object} topCallFrame
895 * @param {string} callFrameId
896 * @return {?Object}
897 */
898 _callFrameForId: function(topCallFrame, callFrameId)
899 {
900 var parsedCallFrameId = nullifyObjectProto(InjectedScriptHost.eval("(" + callFrameId + ")"));
901 return this._callFrameForParsedId(topCallFrame, parsedCallFrameId, []);
902 },
903
904 /**
905 * @param {!Object} topCallFrame
906 * @param {!Object} parsedCallFrameId
907 * @param {!Array.<!Object>} asyncCallStacks
908 * @return {?Object}
909 */
910 _callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallSt acks)
911 {
912 var asyncOrdinal = parsedCallFrameId["asyncOrdinal"]; // 1-based index
913 if (asyncOrdinal)
914 topCallFrame = asyncCallStacks[asyncOrdinal - 1];
915 var ordinal = parsedCallFrameId["ordinal"];
916 var callFrame = topCallFrame;
917 while (--ordinal >= 0 && callFrame)
918 callFrame = callFrame.caller;
919 return callFrame;
920 },
921
922 /**
923 * @param {!Object} objectId
924 * @return {!Object|symbol}
925 */
926 _objectForId: function(objectId)
927 {
928 return this._idToWrappedObject[objectId.id];
929 },
930
931 /**
932 * @param {string} objectId
933 * @return {!Object|symbol}
934 */
935 findObjectById: function(objectId)
936 {
937 var parsedObjectId = this._parseObjectId(objectId);
938 return this._objectForId(parsedObjectId);
939 },
940
941 /**
942 * @param {string} objectId
943 * @return {?Node}
944 */
945 nodeForObjectId: function(objectId)
946 {
947 var object = this.findObjectById(objectId);
948 if (!object || this._subtype(object) !== "node")
949 return null;
950 return /** @type {!Node} */ (object);
951 },
952
953 /**
954 * @param {string} name
955 * @return {!Object}
956 */
957 module: function(name)
958 {
959 return this._modules[name];
960 },
961
962 /**
963 * @param {string} name
964 * @param {string} source
965 * @return {?Object}
966 */
967 injectModule: function(name, source)
968 {
969 delete this._modules[name];
970 var moduleFunction = InjectedScriptHost.eval("(" + source + ")");
971 if (typeof moduleFunction !== "function") {
972 inspectedWindow.console.error("Web Inspector error: A function was e xpected for module %s evaluation", name);
973 return null;
974 }
975 var module = InjectedScriptHost.callFunction(moduleFunction, inspectedWi ndow, [InjectedScriptHost, inspectedWindow, injectedScriptId, this]);
976 this._modules[name] = module;
977 return module;
978 },
979
980 /**
981 * @param {*} object
982 * @return {boolean}
983 */
984 _isDefined: function(object)
985 {
986 return !!object || this._isHTMLAllCollection(object);
987 },
988
989 /**
990 * @param {*} object
991 * @return {boolean}
992 */
993 _isHTMLAllCollection: function(object)
994 {
995 // document.all is reported as undefined, but we still want to process i t.
996 return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCo llection(object);
997 },
998
999 /**
1000 * @param {*} obj
1001 * @return {?string}
1002 */
1003 _subtype: function(obj)
1004 {
1005 if (obj === null)
1006 return "null";
1007
1008 if (this.isPrimitiveValue(obj))
1009 return null;
1010
1011 var subtype = InjectedScriptHost.subtype(obj);
1012 if (subtype)
1013 return subtype;
1014
1015 if (isArrayLike(obj))
1016 return "array";
1017
1018 // If owning frame has navigated to somewhere else window properties wil l be undefined.
1019 return null;
1020 },
1021
1022 /**
1023 * @param {*} obj
1024 * @return {?string}
1025 */
1026 _describe: function(obj)
1027 {
1028 if (this.isPrimitiveValue(obj))
1029 return null;
1030
1031 var subtype = this._subtype(obj);
1032
1033 if (subtype === "regexp")
1034 return toString(obj);
1035
1036 if (subtype === "date")
1037 return toString(obj);
1038
1039 if (subtype === "node") {
1040 var description = obj.nodeName.toLowerCase();
1041 switch (obj.nodeType) {
1042 case 1 /* Node.ELEMENT_NODE */:
1043 description += obj.id ? "#" + obj.id : "";
1044 var className = obj.className;
1045 description += (className && typeof className === "string") ? ". " + className.trim().replace(/\s+/g, ".") : "";
1046 break;
1047 case 10 /*Node.DOCUMENT_TYPE_NODE */:
1048 description = "<!DOCTYPE " + description + ">";
1049 break;
1050 }
1051 return description;
1052 }
1053
1054 var className = InjectedScriptHost.internalConstructorName(obj);
1055 if (subtype === "array") {
1056 if (typeof obj.length === "number")
1057 className += "[" + obj.length + "]";
1058 return className;
1059 }
1060
1061 // NodeList in JSC is a function, check for array prior to this.
1062 if (typeof obj === "function")
1063 return toString(obj);
1064
1065 if (isSymbol(obj)) {
1066 try {
1067 return InjectedScriptHost.callFunction(Symbol.prototype.toString , obj) || "Symbol";
1068 } catch (e) {
1069 return "Symbol";
1070 }
1071 }
1072
1073 if (obj instanceof Error && !!obj.message)
1074 return className + ": " + obj.message;
1075
1076 return className;
1077 }
1078 }
1079
1080 /**
1081 * @type {!InjectedScript}
1082 * @const
1083 */
1084 var injectedScript = new InjectedScript();
1085
1086 /**
1087 * @constructor
1088 * @param {*} object
1089 * @param {string=} objectGroupName
1090 * @param {boolean=} forceValueType
1091 * @param {boolean=} generatePreview
1092 * @param {?Array.<string>=} columnNames
1093 * @param {boolean=} isTable
1094 */
1095 InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames, isTable)
1096 {
1097 this.type = typeof object;
1098 if (injectedScript.isPrimitiveValue(object) || object === null || forceValue Type) {
1099 // We don't send undefined values over JSON.
1100 if (this.type !== "undefined")
1101 this.value = object;
1102
1103 // Null object is object with 'null' subtype.
1104 if (object === null)
1105 this.subtype = "null";
1106
1107 // Provide user-friendly number values.
1108 if (this.type === "number") {
1109 this.description = toStringDescription(object);
1110 // Override "value" property for values that can not be JSON-stringi fied.
1111 switch (this.description) {
1112 case "NaN":
1113 case "Infinity":
1114 case "-Infinity":
1115 case "-0":
1116 this.value = this.description;
1117 break;
1118 }
1119 }
1120
1121 return;
1122 }
1123
1124 object = /** @type {!Object} */ (object);
1125
1126 this.objectId = injectedScript._bind(object, objectGroupName);
1127 var subtype = injectedScript._subtype(object);
1128 if (subtype)
1129 this.subtype = subtype;
1130 var className = InjectedScriptHost.internalConstructorName(object);
1131 if (className)
1132 this.className = className;
1133 this.description = injectedScript._describe(object);
1134
1135 if (generatePreview && (this.type === "object" || injectedScript._isHTMLAllC ollection(object)))
1136 this.preview = this._generatePreview(object, undefined, columnNames, isT able);
1137 }
1138
1139 InjectedScript.RemoteObject.prototype = {
1140 /**
1141 * @param {!Object} object
1142 * @param {?Array.<string>=} firstLevelKeys
1143 * @param {?Array.<string>=} secondLevelKeys
1144 * @param {boolean=} isTable
1145 * @return {!RuntimeAgent.ObjectPreview} preview
1146 */
1147 _generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable)
1148 {
1149 var preview = { __proto__: null };
1150 preview.lossless = true;
1151 preview.overflow = false;
1152 preview.properties = [];
1153
1154 var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
1155
1156 var propertiesThreshold = {
1157 properties: isTable ? 1000 : max(5, firstLevelKeysCount),
1158 indexes: isTable ? 1000 : max(100, firstLevelKeysCount)
1159 };
1160
1161 try {
1162 var descriptors = injectedScript._propertyDescriptors(object);
1163
1164 if (firstLevelKeys) {
1165 var nameToDescriptors = { __proto__: null };
1166 for (var i = 0; i < descriptors.length; ++i) {
1167 var descriptor = descriptors[i];
1168 nameToDescriptors["#" + descriptor.name] = descriptor;
1169 }
1170 descriptors = [];
1171 for (var i = 0; i < firstLevelKeys.length; ++i)
1172 descriptors[i] = nameToDescriptors["#" + firstLevelKeys[i]];
1173 }
1174
1175 this._appendPropertyDescriptors(preview, descriptors, propertiesThre shold, secondLevelKeys, isTable);
1176 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
1177 return preview;
1178
1179 // Add internal properties to preview.
1180 var internalProperties = InjectedScriptHost.getInternalProperties(ob ject) || [];
1181 for (var i = 0; i < internalProperties.length; ++i) {
1182 internalProperties[i] = nullifyObjectProto(internalProperties[i] );
1183 internalProperties[i].enumerable = true;
1184 }
1185 this._appendPropertyDescriptors(preview, internalProperties, propert iesThreshold, secondLevelKeys, isTable);
1186
1187 } catch (e) {
1188 preview.lossless = false;
1189 }
1190
1191 return preview;
1192 },
1193
1194 /**
1195 * @param {!RuntimeAgent.ObjectPreview} preview
1196 * @param {!Array.<!Object>} descriptors
1197 * @param {!Object} propertiesThreshold
1198 * @param {?Array.<string>=} secondLevelKeys
1199 * @param {boolean=} isTable
1200 */
1201 _appendPropertyDescriptors: function(preview, descriptors, propertiesThresho ld, secondLevelKeys, isTable)
1202 {
1203 for (var i = 0; i < descriptors.length; ++i) {
1204 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie s < 0)
1205 break;
1206
1207 var descriptor = descriptors[i];
1208 if (!descriptor)
1209 continue;
1210 if (descriptor.wasThrown) {
1211 preview.lossless = false;
1212 continue;
1213 }
1214 if (!descriptor.enumerable && !descriptor.isOwn)
1215 continue;
1216
1217 var name = descriptor.name;
1218 if (name === "__proto__")
1219 continue;
1220 if (this.subtype === "array" && name === "length")
1221 continue;
1222
1223 if (!("value" in descriptor)) {
1224 preview.lossless = false;
1225 this._appendPropertyPreview(preview, { name: name, type: "access or", __proto__: null }, propertiesThreshold);
1226 continue;
1227 }
1228
1229 var value = descriptor.value;
1230 if (value === null) {
1231 this._appendPropertyPreview(preview, { name: name, type: "object ", subtype: "null", value: "null", __proto__: null }, propertiesThreshold);
1232 continue;
1233 }
1234
1235 var type = typeof value;
1236 if (!descriptor.enumerable && type === "function")
1237 continue;
1238 if (type === "undefined" && injectedScript._isHTMLAllCollection(valu e))
1239 type = "object";
1240
1241 var maxLength = 100;
1242 if (InjectedScript.primitiveTypes[type]) {
1243 if (type === "string" && value.length > maxLength) {
1244 value = this._abbreviateString(value, maxLength, true);
1245 preview.lossless = false;
1246 }
1247 this._appendPropertyPreview(preview, { name: name, type: type, v alue: toStringDescription(value), __proto__: null }, propertiesThreshold);
1248 continue;
1249 }
1250
1251 var property = { name: name, type: type, __proto__: null };
1252 var subtype = injectedScript._subtype(value);
1253 if (subtype)
1254 property.subtype = subtype;
1255
1256 if (secondLevelKeys === null || secondLevelKeys) {
1257 var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined, isTable);
1258 property.valuePreview = subPreview;
1259 if (!subPreview.lossless)
1260 preview.lossless = false;
1261 if (subPreview.overflow)
1262 preview.overflow = true;
1263 } else {
1264 var description = "";
1265 if (type !== "function")
1266 description = this._abbreviateString(/** @type {string} */ ( injectedScript._describe(value)), maxLength, subtype === "regexp");
1267 property.value = description;
1268 preview.lossless = false;
1269 }
1270 this._appendPropertyPreview(preview, property, propertiesThreshold);
1271 }
1272 },
1273
1274 /**
1275 * @param {!RuntimeAgent.ObjectPreview} preview
1276 * @param {!Object} property
1277 * @param {!Object} propertiesThreshold
1278 */
1279 _appendPropertyPreview: function(preview, property, propertiesThreshold)
1280 {
1281 if (toString(property.name >>> 0) === property.name)
1282 propertiesThreshold.indexes--;
1283 else
1284 propertiesThreshold.properties--;
1285 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) {
1286 preview.overflow = true;
1287 preview.lossless = false;
1288 } else {
1289 push(preview.properties, property);
1290 }
1291 },
1292
1293 /**
1294 * @param {string} string
1295 * @param {number} maxLength
1296 * @param {boolean=} middle
1297 * @return {string}
1298 */
1299 _abbreviateString: function(string, maxLength, middle)
1300 {
1301 if (string.length <= maxLength)
1302 return string;
1303 if (middle) {
1304 var leftHalf = maxLength >> 1;
1305 var rightHalf = maxLength - leftHalf - 1;
1306 return string.substr(0, leftHalf) + "\u2026" + string.substr(string. length - rightHalf, rightHalf);
1307 }
1308 return string.substr(0, maxLength) + "\u2026";
1309 },
1310
1311 __proto__: null
1312 }
1313 /**
1314 * @constructor
1315 * @param {number} ordinal
1316 * @param {!Object} callFrame
1317 * @param {number} asyncOrdinal
1318 */
1319 InjectedScript.CallFrameProxy = function(ordinal, callFrame, asyncOrdinal)
1320 {
1321 this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + in jectedScriptId + (asyncOrdinal ? ",\"asyncOrdinal\":" + asyncOrdinal : "") + "}" ;
1322 this.functionName = (callFrame.type === "function" ? callFrame.functionName : "");
1323 this.location = { scriptId: toString(callFrame.sourceID), lineNumber: callFr ame.line, columnNumber: callFrame.column, __proto__: null };
1324 this.scopeChain = this._wrapScopeChain(callFrame);
1325 this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace");
1326 if (callFrame.isAtReturn)
1327 this.returnValue = injectedScript._wrapObject(callFrame.returnValue, "ba cktrace");
1328 }
1329
1330 InjectedScript.CallFrameProxy.prototype = {
1331 /**
1332 * @param {!Object} callFrame
1333 * @return {!Array.<!DebuggerAgent.Scope>}
1334 */
1335 _wrapScopeChain: function(callFrame)
1336 {
1337 var scopeChain = callFrame.scopeChain;
1338 var scopeChainProxy = [];
1339 for (var i = 0; i < scopeChain.length; ++i)
1340 scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson( callFrame.scopeType(i), scopeChain[i], "backtrace");
1341 return scopeChainProxy;
1342 },
1343
1344 __proto__: null
1345 }
1346
1347 /**
1348 * @param {number} scopeTypeCode
1349 * @param {*} scopeObject
1350 * @param {string} groupId
1351 * @return {!DebuggerAgent.Scope}
1352 */
1353 InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb ject, groupId)
1354 {
1355 var GLOBAL_SCOPE = 0;
1356 var LOCAL_SCOPE = 1;
1357 var WITH_SCOPE = 2;
1358 var CLOSURE_SCOPE = 3;
1359 var CATCH_SCOPE = 4;
1360
1361 /** @type {!Object.<number, string>} */
1362 var scopeTypeNames = { __proto__: null };
1363 scopeTypeNames[GLOBAL_SCOPE] = "global";
1364 scopeTypeNames[LOCAL_SCOPE] = "local";
1365 scopeTypeNames[WITH_SCOPE] = "with";
1366 scopeTypeNames[CLOSURE_SCOPE] = "closure";
1367 scopeTypeNames[CATCH_SCOPE] = "catch";
1368
1369 return {
1370 object: injectedScript._wrapObject(scopeObject, groupId),
1371 type: /** @type {!DebuggerAgent.ScopeType} */ (scopeTypeNames[scopeTypeC ode]),
1372 __proto__: null
1373 };
1374 }
1375
1376 /**
1377 * @constructor
1378 * @param {!CommandLineAPIImpl} commandLineAPIImpl
1379 * @param {?Object} callFrame
1380 */
1381 function CommandLineAPI(commandLineAPIImpl, callFrame)
1382 {
1383 /**
1384 * @param {string} member
1385 * @return {boolean}
1386 */
1387 function inScopeVariables(member)
1388 {
1389 if (!callFrame)
1390 return false;
1391
1392 var scopeChain = callFrame.scopeChain;
1393 for (var i = 0; i < scopeChain.length; ++i) {
1394 if (member in scopeChain[i])
1395 return true;
1396 }
1397 return false;
1398 }
1399
1400 /**
1401 * @param {string} name The name of the method for which a toString method s hould be generated.
1402 * @return {function():string}
1403 */
1404 function customToStringMethod(name)
1405 {
1406 return function()
1407 {
1408 var funcArgsSyntax = "";
1409 try {
1410 var funcSyntax = "" + commandLineAPIImpl[name];
1411 funcSyntax = funcSyntax.replace(/\n/g, " ");
1412 funcSyntax = funcSyntax.replace(/^function[^\(]*\(([^\)]*)\).*$/ , "$1");
1413 funcSyntax = funcSyntax.replace(/\s*,\s*/g, ", ");
1414 funcSyntax = funcSyntax.replace(/\bopt_(\w+)\b/g, "[$1]");
1415 funcArgsSyntax = funcSyntax.trim();
1416 } catch (e) {
1417 }
1418 return "function " + name + "(" + funcArgsSyntax + ") { [Command Lin e API] }";
1419 };
1420 }
1421
1422 for (var i = 0; i < CommandLineAPI.members_.length; ++i) {
1423 var member = CommandLineAPI.members_[i];
1424 if (member in inspectedWindow || inScopeVariables(member))
1425 continue;
1426
1427 this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
1428 this[member].toString = customToStringMethod(member);
1429 }
1430
1431 for (var i = 0; i < 5; ++i) {
1432 var member = "$" + i;
1433 if (member in inspectedWindow || inScopeVariables(member))
1434 continue;
1435
1436 this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
1437 }
1438
1439 this.$_ = injectedScript._lastResult;
1440
1441 this.__proto__ = null;
1442 }
1443
1444 // NOTE: Please keep the list of API methods below snchronized to that in WebIns pector.RuntimeModel!
1445 // NOTE: Argument names of these methods will be printed in the console, so use pretty names!
1446 /**
1447 * @type {!Array.<string>}
1448 * @const
1449 */
1450 CommandLineAPI.members_ = [
1451 "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd",
1452 "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventLis teners",
1453 "debug", "undebug", "monitor", "unmonitor", "table"
1454 ];
1455
1456 /**
1457 * @constructor
1458 */
1459 function CommandLineAPIImpl()
1460 {
1461 }
1462
1463 CommandLineAPIImpl.prototype = {
1464 /**
1465 * @param {string} selector
1466 * @param {!Node=} opt_startNode
1467 * @return {*}
1468 */
1469 $: function (selector, opt_startNode)
1470 {
1471 if (this._canQuerySelectorOnNode(opt_startNode))
1472 return opt_startNode.querySelector(selector);
1473
1474 return inspectedWindow.document.querySelector(selector);
1475 },
1476
1477 /**
1478 * @param {string} selector
1479 * @param {!Node=} opt_startNode
1480 * @return {*}
1481 */
1482 $$: function (selector, opt_startNode)
1483 {
1484 if (this._canQuerySelectorOnNode(opt_startNode))
1485 return opt_startNode.querySelectorAll(selector);
1486 return inspectedWindow.document.querySelectorAll(selector);
1487 },
1488
1489 /**
1490 * @param {!Node=} node
1491 * @return {boolean}
1492 */
1493 _canQuerySelectorOnNode: function(node)
1494 {
1495 return !!node && InjectedScriptHost.subtype(node) === "node" && (node.no deType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nod eType === Node.DOCUMENT_FRAGMENT_NODE);
1496 },
1497
1498 /**
1499 * @param {string} xpath
1500 * @param {!Node=} opt_startNode
1501 * @return {*}
1502 */
1503 $x: function(xpath, opt_startNode)
1504 {
1505 var doc = (opt_startNode && opt_startNode.ownerDocument) || inspectedWin dow.document;
1506 var result = doc.evaluate(xpath, opt_startNode || doc, null, XPathResult .ANY_TYPE, null);
1507 switch (result.resultType) {
1508 case XPathResult.NUMBER_TYPE:
1509 return result.numberValue;
1510 case XPathResult.STRING_TYPE:
1511 return result.stringValue;
1512 case XPathResult.BOOLEAN_TYPE:
1513 return result.booleanValue;
1514 default:
1515 var nodes = [];
1516 var node;
1517 while (node = result.iterateNext())
1518 push(nodes, node);
1519 return nodes;
1520 }
1521 },
1522
1523 /**
1524 * @return {*}
1525 */
1526 dir: function(var_args)
1527 {
1528 return InjectedScriptHost.callFunction(inspectedWindow.console.dir, insp ectedWindow.console, slice(arguments));
1529 },
1530
1531 /**
1532 * @return {*}
1533 */
1534 dirxml: function(var_args)
1535 {
1536 return InjectedScriptHost.callFunction(inspectedWindow.console.dirxml, i nspectedWindow.console, slice(arguments));
1537 },
1538
1539 /**
1540 * @return {!Array.<string>}
1541 */
1542 keys: function(object)
1543 {
1544 return Object.keys(object);
1545 },
1546
1547 /**
1548 * @return {!Array.<*>}
1549 */
1550 values: function(object)
1551 {
1552 var result = [];
1553 for (var key in object)
1554 push(result, object[key]);
1555 return result;
1556 },
1557
1558 /**
1559 * @return {*}
1560 */
1561 profile: function(opt_title)
1562 {
1563 return InjectedScriptHost.callFunction(inspectedWindow.console.profile, inspectedWindow.console, slice(arguments));
1564 },
1565
1566 /**
1567 * @return {*}
1568 */
1569 profileEnd: function(opt_title)
1570 {
1571 return InjectedScriptHost.callFunction(inspectedWindow.console.profileEn d, inspectedWindow.console, slice(arguments));
1572 },
1573
1574 /**
1575 * @param {!Object} object
1576 * @param {!Array.<string>|string=} opt_types
1577 */
1578 monitorEvents: function(object, opt_types)
1579 {
1580 if (!object || !object.addEventListener || !object.removeEventListener)
1581 return;
1582 var types = this._normalizeEventTypes(opt_types);
1583 for (var i = 0; i < types.length; ++i) {
1584 object.removeEventListener(types[i], this._logEvent, false);
1585 object.addEventListener(types[i], this._logEvent, false);
1586 }
1587 },
1588
1589 /**
1590 * @param {!Object} object
1591 * @param {!Array.<string>|string=} opt_types
1592 */
1593 unmonitorEvents: function(object, opt_types)
1594 {
1595 if (!object || !object.addEventListener || !object.removeEventListener)
1596 return;
1597 var types = this._normalizeEventTypes(opt_types);
1598 for (var i = 0; i < types.length; ++i)
1599 object.removeEventListener(types[i], this._logEvent, false);
1600 },
1601
1602 /**
1603 * @param {*} object
1604 * @return {*}
1605 */
1606 inspect: function(object)
1607 {
1608 return injectedScript._inspect(object);
1609 },
1610
1611 copy: function(object)
1612 {
1613 var string;
1614 if (injectedScript._subtype(object) === "node") {
1615 string = object.outerHTML;
1616 } else if (injectedScript.isPrimitiveValue(object)) {
1617 string = toString(object);
1618 } else {
1619 try {
1620 string = JSON.stringify(object, null, " ");
1621 } catch (e) {
1622 string = toString(object);
1623 }
1624 }
1625
1626 var hints = { copyToClipboard: true, __proto__: null };
1627 var remoteObject = injectedScript._wrapObject(string, "")
1628 InjectedScriptHost.inspect(remoteObject, hints);
1629 },
1630
1631 clear: function()
1632 {
1633 InjectedScriptHost.clearConsoleMessages();
1634 },
1635
1636 /**
1637 * @param {!Node} node
1638 * @return {!{type: string, listener: function(), useCapture: boolean, remov e: function()}|undefined}
1639 */
1640 getEventListeners: function(node)
1641 {
1642 var result = nullifyObjectProto(InjectedScriptHost.getEventListeners(nod e));
1643 if (!result)
1644 return result;
1645 /** @this {{type: string, listener: function(), useCapture: boolean}} */
1646 var removeFunc = function()
1647 {
1648 node.removeEventListener(this.type, this.listener, this.useCapture);
1649 }
1650 for (var type in result) {
1651 var listeners = result[type];
1652 for (var i = 0, listener; listener = listeners[i]; ++i) {
1653 listener["type"] = type;
1654 listener["remove"] = removeFunc;
1655 }
1656 }
1657 return result;
1658 },
1659
1660 debug: function(fn)
1661 {
1662 InjectedScriptHost.debugFunction(fn);
1663 },
1664
1665 undebug: function(fn)
1666 {
1667 InjectedScriptHost.undebugFunction(fn);
1668 },
1669
1670 monitor: function(fn)
1671 {
1672 InjectedScriptHost.monitorFunction(fn);
1673 },
1674
1675 unmonitor: function(fn)
1676 {
1677 InjectedScriptHost.unmonitorFunction(fn);
1678 },
1679
1680 table: function(data, opt_columns)
1681 {
1682 InjectedScriptHost.callFunction(inspectedWindow.console.table, inspected Window.console, slice(arguments));
1683 },
1684
1685 /**
1686 * @param {number} num
1687 */
1688 _inspectedObject: function(num)
1689 {
1690 return InjectedScriptHost.inspectedObject(num);
1691 },
1692
1693 /**
1694 * @param {!Array.<string>|string=} types
1695 * @return {!Array.<string>}
1696 */
1697 _normalizeEventTypes: function(types)
1698 {
1699 if (typeof types === "undefined")
1700 types = ["mouse", "key", "touch", "control", "load", "unload", "abor t", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", " scroll", "search", "devicemotion", "deviceorientation"];
1701 else if (typeof types === "string")
1702 types = [types];
1703
1704 var result = [];
1705 for (var i = 0; i < types.length; ++i) {
1706 if (types[i] === "mouse")
1707 push(result, "mousedown", "mouseup", "click", "dblclick", "mouse move", "mouseover", "mouseout", "mousewheel");
1708 else if (types[i] === "key")
1709 push(result, "keydown", "keyup", "keypress", "textInput");
1710 else if (types[i] === "touch")
1711 push(result, "touchstart", "touchmove", "touchend", "touchcancel ");
1712 else if (types[i] === "control")
1713 push(result, "resize", "scroll", "zoom", "focus", "blur", "selec t", "change", "submit", "reset");
1714 else
1715 push(result, types[i]);
1716 }
1717 return result;
1718 },
1719
1720 /**
1721 * @param {!Event} event
1722 */
1723 _logEvent: function(event)
1724 {
1725 inspectedWindow.console.log(event.type, event);
1726 }
1727 }
1728
1729 injectedScript._commandLineAPIImpl = new CommandLineAPIImpl();
1730 return injectedScript;
1731 })
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698