OLD | NEW |
| (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 "use strict"; | |
31 | |
32 /** | |
33 * @param {!InjectedScriptHostClass} InjectedScriptHost | |
34 * @param {!Window|!WorkerGlobalScope} inspectedGlobalObject | |
35 * @param {number} injectedScriptId | |
36 */ | |
37 (function (InjectedScriptHost, inspectedGlobalObject, injectedScriptId) { | |
38 | |
39 /** | |
40 * Protect against Object overwritten by the user code. | |
41 * @suppress {duplicate} | |
42 */ | |
43 var Object = /** @type {function(new:Object, *=)} */ ({}.constructor); | |
44 | |
45 /** | |
46 * @param {!Array.<T>} array | |
47 * @param {...} var_args | |
48 * @template T | |
49 */ | |
50 function push(array, var_args) | |
51 { | |
52 for (var i = 1; i < arguments.length; ++i) | |
53 array[array.length] = arguments[i]; | |
54 } | |
55 | |
56 /** | |
57 * @param {(!Arguments.<T>|!NodeList)} array | |
58 * @param {number=} index | |
59 * @return {!Array.<T>} | |
60 * @template T | |
61 */ | |
62 function slice(array, index) | |
63 { | |
64 var result = []; | |
65 for (var i = index || 0, j = 0; i < array.length; ++i, ++j) | |
66 result[j] = array[i]; | |
67 return result; | |
68 } | |
69 | |
70 /** | |
71 * @param {!Array.<T>} array1 | |
72 * @param {!Array.<T>} array2 | |
73 * @return {!Array.<T>} | |
74 * @template T | |
75 */ | |
76 function concat(array1, array2) | |
77 { | |
78 var result = []; | |
79 for (var i = 0; i < array1.length; ++i) | |
80 push(result, array1[i]); | |
81 for (var i = 0; i < array2.length; ++i) | |
82 push(result, array2[i]); | |
83 return result; | |
84 } | |
85 | |
86 /** | |
87 * @param {*} obj | |
88 * @return {string} | |
89 * @suppress {uselessCode} | |
90 */ | |
91 function toString(obj) | |
92 { | |
93 // We don't use String(obj) because String could be overridden. | |
94 // Also the ("" + obj) expression may throw. | |
95 try { | |
96 return "" + obj; | |
97 } catch (e) { | |
98 var name = InjectedScriptHost.internalConstructorName(obj) || InjectedSc
riptHost.subtype(obj) || (typeof obj); | |
99 return "#<" + name + ">"; | |
100 } | |
101 } | |
102 | |
103 /** | |
104 * @param {*} obj | |
105 * @return {string} | |
106 */ | |
107 function toStringDescription(obj) | |
108 { | |
109 if (typeof obj === "number" && obj === 0 && 1 / obj < 0) | |
110 return "-0"; // Negative zero. | |
111 return toString(obj); | |
112 } | |
113 | |
114 /** | |
115 * Please use this bind, not the one from Function.prototype | |
116 * @param {function(...)} func | |
117 * @param {?Object} thisObject | |
118 * @param {...} var_args | |
119 * @return {function(...)} | |
120 */ | |
121 function bind(func, thisObject, var_args) | |
122 { | |
123 var args = slice(arguments, 2); | |
124 | |
125 /** | |
126 * @param {...} var_args | |
127 */ | |
128 function bound(var_args) | |
129 { | |
130 return InjectedScriptHost.callFunction(func, thisObject, concat(args, sl
ice(arguments))); | |
131 } | |
132 bound.toString = function() | |
133 { | |
134 return "bound: " + toString(func); | |
135 }; | |
136 return bound; | |
137 } | |
138 | |
139 /** | |
140 * @param {T} obj | |
141 * @return {T} | |
142 * @template T | |
143 */ | |
144 function nullifyObjectProto(obj) | |
145 { | |
146 if (obj && typeof obj === "object") | |
147 obj.__proto__ = null; | |
148 return obj; | |
149 } | |
150 | |
151 /** | |
152 * @param {number|string} obj | |
153 * @return {boolean} | |
154 */ | |
155 function isUInt32(obj) | |
156 { | |
157 if (typeof obj === "number") | |
158 return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0); | |
159 return "" + (obj >>> 0) === obj; | |
160 } | |
161 | |
162 /** | |
163 * FireBug's array detection. | |
164 * @param {*} obj | |
165 * @return {boolean} | |
166 */ | |
167 function isArrayLike(obj) | |
168 { | |
169 if (typeof obj !== "object") | |
170 return false; | |
171 try { | |
172 if (typeof obj.splice === "function") { | |
173 if (!InjectedScriptHost.suppressWarningsAndCallFunction(Object.proto
type.hasOwnProperty, obj, ["length"])) | |
174 return false; | |
175 var len = obj.length; | |
176 return typeof len === "number" && isUInt32(len); | |
177 } | |
178 } catch (e) { | |
179 } | |
180 return false; | |
181 } | |
182 | |
183 /** | |
184 * @param {number} a | |
185 * @param {number} b | |
186 * @return {number} | |
187 */ | |
188 function max(a, b) | |
189 { | |
190 return a > b ? a : b; | |
191 } | |
192 | |
193 /** | |
194 * FIXME: Remove once ES6 is supported natively by JS compiler. | |
195 * @param {*} obj | |
196 * @return {boolean} | |
197 */ | |
198 function isSymbol(obj) | |
199 { | |
200 var type = typeof obj; | |
201 return (type === "symbol"); | |
202 } | |
203 | |
204 /** | |
205 * @param {string} str | |
206 * @param {string} searchElement | |
207 * @param {number=} fromIndex | |
208 * @return {number} | |
209 */ | |
210 function indexOf(str, searchElement, fromIndex) | |
211 { | |
212 var len = str.length; | |
213 var n = fromIndex || 0; | |
214 var k = max(n >= 0 ? n : len + n, 0); | |
215 | |
216 while (k < len) { | |
217 if (str[k] === searchElement) | |
218 return k; | |
219 ++k; | |
220 } | |
221 return -1; | |
222 } | |
223 | |
224 /** | |
225 * DOM Attributes which have observable side effect on getter, in the form of | |
226 * {interfaceName1: {attributeName1: true, | |
227 * attributeName2: true, | |
228 * ...}, | |
229 * interfaceName2: {...}, | |
230 * ...} | |
231 * @type {!Object<string, !Object<string, boolean>>} | |
232 * @const | |
233 */ | |
234 var domAttributesWithObservableSideEffectOnGet = nullifyObjectProto({}); | |
235 domAttributesWithObservableSideEffectOnGet["Request"] = nullifyObjectProto({}); | |
236 domAttributesWithObservableSideEffectOnGet["Request"]["body"] = true; | |
237 domAttributesWithObservableSideEffectOnGet["Response"] = nullifyObjectProto({}); | |
238 domAttributesWithObservableSideEffectOnGet["Response"]["body"] = true; | |
239 | |
240 /** | |
241 * @param {!Object} object | |
242 * @param {string} attribute | |
243 * @return {boolean} | |
244 */ | |
245 function doesAttributeHaveObservableSideEffectOnGet(object, attribute) | |
246 { | |
247 for (var interfaceName in domAttributesWithObservableSideEffectOnGet) { | |
248 var isInstance = InjectedScriptHost.suppressWarningsAndCallFunction(func
tion(object, interfaceName) { | |
249 return /* suppressBlacklist */ typeof inspectedGlobalObject[interfac
eName] === "function" && object instanceof inspectedGlobalObject[interfaceName]; | |
250 }, null, [object, interfaceName]); | |
251 if (isInstance) { | |
252 return attribute in domAttributesWithObservableSideEffectOnGet[inter
faceName]; | |
253 } | |
254 } | |
255 return false; | |
256 } | |
257 | |
258 /** | |
259 * @constructor | |
260 */ | |
261 var InjectedScript = function() | |
262 { | |
263 } | |
264 | |
265 /** | |
266 * @type {!Object.<string, boolean>} | |
267 * @const | |
268 */ | |
269 InjectedScript.primitiveTypes = { | |
270 "undefined": true, | |
271 "boolean": true, | |
272 "number": true, | |
273 "string": true, | |
274 __proto__: null | |
275 } | |
276 | |
277 InjectedScript.prototype = { | |
278 /** | |
279 * @param {*} object | |
280 * @return {boolean} | |
281 */ | |
282 isPrimitiveValue: function(object) | |
283 { | |
284 // FIXME(33716): typeof document.all is always 'undefined'. | |
285 return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllC
ollection(object); | |
286 }, | |
287 | |
288 /** | |
289 * @param {*} object | |
290 * @param {string} groupName | |
291 * @param {boolean} canAccessInspectedGlobalObject | |
292 * @param {boolean} generatePreview | |
293 * @return {!RuntimeAgent.RemoteObject} | |
294 */ | |
295 wrapObject: function(object, groupName, canAccessInspectedGlobalObject, gene
ratePreview) | |
296 { | |
297 if (canAccessInspectedGlobalObject) | |
298 return this._wrapObject(object, groupName, false, generatePreview); | |
299 return this._fallbackWrapper(object); | |
300 }, | |
301 | |
302 /** | |
303 * @param {*} object | |
304 * @return {!RuntimeAgent.RemoteObject} | |
305 */ | |
306 _fallbackWrapper: function(object) | |
307 { | |
308 var result = { __proto__: null }; | |
309 result.type = typeof object; | |
310 if (this.isPrimitiveValue(object)) | |
311 result.value = object; | |
312 else | |
313 result.description = toString(object); | |
314 return /** @type {!RuntimeAgent.RemoteObject} */ (result); | |
315 }, | |
316 | |
317 /** | |
318 * @param {boolean} canAccessInspectedGlobalObject | |
319 * @param {!Object} table | |
320 * @param {!Array.<string>|string|boolean} columns | |
321 * @return {!RuntimeAgent.RemoteObject} | |
322 */ | |
323 wrapTable: function(canAccessInspectedGlobalObject, table, columns) | |
324 { | |
325 if (!canAccessInspectedGlobalObject) | |
326 return this._fallbackWrapper(table); | |
327 var columnNames = null; | |
328 if (typeof columns === "string") | |
329 columns = [columns]; | |
330 if (InjectedScriptHost.subtype(columns) === "array") { | |
331 columnNames = []; | |
332 for (var i = 0; i < columns.length; ++i) | |
333 columnNames[i] = toString(columns[i]); | |
334 } | |
335 return this._wrapObject(table, "console", false, true, columnNames, true
); | |
336 }, | |
337 | |
338 /** | |
339 * @param {*} object | |
340 * @return {*} | |
341 */ | |
342 _inspect: function(object) | |
343 { | |
344 if (arguments.length === 0) | |
345 return; | |
346 | |
347 var objectId = this._wrapObject(object, ""); | |
348 var hints = { __proto__: null }; | |
349 | |
350 InjectedScriptHost.inspect(objectId, hints); | |
351 return object; | |
352 }, | |
353 | |
354 /** | |
355 * This method cannot throw. | |
356 * @param {*} object | |
357 * @param {string=} objectGroupName | |
358 * @param {boolean=} forceValueType | |
359 * @param {boolean=} generatePreview | |
360 * @param {?Array.<string>=} columnNames | |
361 * @param {boolean=} isTable | |
362 * @param {boolean=} doNotBind | |
363 * @param {*=} customObjectConfig | |
364 * @return {!RuntimeAgent.RemoteObject} | |
365 * @suppress {checkTypes} | |
366 */ | |
367 _wrapObject: function(object, objectGroupName, forceValueType, generatePrevi
ew, columnNames, isTable, doNotBind, customObjectConfig) | |
368 { | |
369 try { | |
370 return new InjectedScript.RemoteObject(object, objectGroupName, doNo
tBind, forceValueType, generatePreview, columnNames, isTable, undefined, customO
bjectConfig); | |
371 } catch (e) { | |
372 try { | |
373 var description = injectedScript._describe(e); | |
374 } catch (ex) { | |
375 var description = "<failed to convert exception to string>"; | |
376 } | |
377 return new InjectedScript.RemoteObject(description); | |
378 } | |
379 }, | |
380 | |
381 /** | |
382 * @param {!Object|symbol} object | |
383 * @param {string=} objectGroupName | |
384 * @return {string} | |
385 */ | |
386 _bind: function(object, objectGroupName) | |
387 { | |
388 var id = InjectedScriptHost.bind(object, objectGroupName || ""); | |
389 return "{\"injectedScriptId\":" + injectedScriptId + ",\"id\":" + id + "
}"; | |
390 }, | |
391 | |
392 /** | |
393 * @param {string} objectId | |
394 * @return {!Object} | |
395 */ | |
396 _parseObjectId: function(objectId) | |
397 { | |
398 return nullifyObjectProto(/** @type {!Object} */ (InjectedScriptHost.eva
l("(" + objectId + ")"))); | |
399 }, | |
400 | |
401 clearLastEvaluationResult: function() | |
402 { | |
403 delete this._lastResult; | |
404 }, | |
405 | |
406 /** | |
407 * @param {string} objectId | |
408 * @param {boolean} ownProperties | |
409 * @param {boolean} accessorPropertiesOnly | |
410 * @param {boolean} generatePreview | |
411 * @return {!Array.<!RuntimeAgent.PropertyDescriptor>|boolean} | |
412 */ | |
413 getProperties: function(objectId, ownProperties, accessorPropertiesOnly, gen
eratePreview) | |
414 { | |
415 var parsedObjectId = this._parseObjectId(objectId); | |
416 var object = this._objectForId(parsedObjectId); | |
417 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec
tId.id); | |
418 | |
419 if (!this._isDefined(object) || isSymbol(object)) | |
420 return false; | |
421 object = /** @type {!Object} */ (object); | |
422 var descriptors = []; | |
423 var iter = this._propertyDescriptors(object, ownProperties, accessorProp
ertiesOnly, undefined); | |
424 // Go over properties, wrap object values. | |
425 for (var descriptor of iter) { | |
426 if ("get" in descriptor) | |
427 descriptor.get = this._wrapObject(descriptor.get, objectGroupNam
e); | |
428 if ("set" in descriptor) | |
429 descriptor.set = this._wrapObject(descriptor.set, objectGroupNam
e); | |
430 if ("value" in descriptor) | |
431 descriptor.value = this._wrapObject(descriptor.value, objectGrou
pName, false, generatePreview); | |
432 if (!("configurable" in descriptor)) | |
433 descriptor.configurable = false; | |
434 if (!("enumerable" in descriptor)) | |
435 descriptor.enumerable = false; | |
436 if ("symbol" in descriptor) | |
437 descriptor.symbol = this._wrapObject(descriptor.symbol, objectGr
oupName); | |
438 push(descriptors, descriptor); | |
439 } | |
440 return descriptors; | |
441 }, | |
442 | |
443 /** | |
444 * @param {string} objectId | |
445 * @return {!Array.<!Object>|boolean} | |
446 */ | |
447 getInternalProperties: function(objectId) | |
448 { | |
449 var parsedObjectId = this._parseObjectId(objectId); | |
450 var object = this._objectForId(parsedObjectId); | |
451 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec
tId.id); | |
452 if (!this._isDefined(object) || isSymbol(object)) | |
453 return false; | |
454 object = /** @type {!Object} */ (object); | |
455 var descriptors = []; | |
456 var internalProperties = InjectedScriptHost.getInternalProperties(object
); | |
457 if (internalProperties) { | |
458 for (var i = 0; i < internalProperties.length; i += 2) { | |
459 var descriptor = { | |
460 name: internalProperties[i], | |
461 value: this._wrapObject(internalProperties[i + 1], objectGro
upName), | |
462 __proto__: null | |
463 }; | |
464 push(descriptors, descriptor); | |
465 } | |
466 } | |
467 return descriptors; | |
468 }, | |
469 | |
470 /** | |
471 * @param {string} functionId | |
472 * @return {!DebuggerAgent.FunctionDetails|string} | |
473 */ | |
474 getFunctionDetails: function(functionId) | |
475 { | |
476 var parsedFunctionId = this._parseObjectId(functionId); | |
477 var func = this._objectForId(parsedFunctionId); | |
478 if (typeof func !== "function") | |
479 return "Cannot resolve function by id."; | |
480 var details = nullifyObjectProto(/** @type {!DebuggerAgent.FunctionDetai
ls} */ (InjectedScriptHost.functionDetails(func))); | |
481 if ("rawScopes" in details) { | |
482 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedF
unctionId.id); | |
483 var rawScopes = details["rawScopes"]; | |
484 delete details["rawScopes"]; | |
485 var scopes = []; | |
486 for (var i = 0; i < rawScopes.length; ++i) | |
487 scopes[i] = InjectedScript.CallFrameProxy._createScopeJson(rawSc
opes[i].type, rawScopes[i].name, rawScopes[i].object, objectGroupName); | |
488 details.scopeChain = scopes; | |
489 } | |
490 return details; | |
491 }, | |
492 | |
493 /** | |
494 * @param {string} objectId | |
495 * @return {!DebuggerAgent.GeneratorObjectDetails|string} | |
496 */ | |
497 getGeneratorObjectDetails: function(objectId) | |
498 { | |
499 var parsedObjectId = this._parseObjectId(objectId); | |
500 var object = this._objectForId(parsedObjectId); | |
501 if (!object || typeof object !== "object") | |
502 return "Could not find object with given id"; | |
503 var details = nullifyObjectProto(/** @type {?DebuggerAgent.GeneratorObje
ctDetails} */ (InjectedScriptHost.generatorObjectDetails(object))); | |
504 if (!details) | |
505 return "Object is not a generator"; | |
506 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec
tId.id); | |
507 details["function"] = this._wrapObject(details["function"], objectGroupN
ame); | |
508 return details; | |
509 }, | |
510 | |
511 /** | |
512 * @param {string} objectId | |
513 * @return {!Array.<!Object>|string} | |
514 */ | |
515 getCollectionEntries: function(objectId) | |
516 { | |
517 var parsedObjectId = this._parseObjectId(objectId); | |
518 var object = this._objectForId(parsedObjectId); | |
519 if (!object || typeof object !== "object") | |
520 return "Could not find object with given id"; | |
521 var entries = InjectedScriptHost.collectionEntries(object); | |
522 if (!entries) | |
523 return "Object with given id is not a collection"; | |
524 var objectGroupName = InjectedScriptHost.idToObjectGroupName(parsedObjec
tId.id); | |
525 for (var i = 0; i < entries.length; ++i) { | |
526 var entry = nullifyObjectProto(entries[i]); | |
527 if ("key" in entry) | |
528 entry.key = this._wrapObject(entry.key, objectGroupName); | |
529 entry.value = this._wrapObject(entry.value, objectGroupName); | |
530 entries[i] = entry; | |
531 } | |
532 return entries; | |
533 }, | |
534 | |
535 /** | |
536 * @param {!Object} object | |
537 * @param {boolean=} ownProperties | |
538 * @param {boolean=} accessorPropertiesOnly | |
539 * @param {?Array.<string>=} propertyNamesOnly | |
540 */ | |
541 _propertyDescriptors: function*(object, ownProperties, accessorPropertiesOnl
y, propertyNamesOnly) | |
542 { | |
543 var propertyProcessed = { __proto__: null }; | |
544 | |
545 /** | |
546 * @param {?Object} o | |
547 * @param {!Iterable.<string|symbol>|!Array.<string|symbol>} properties | |
548 */ | |
549 function* process(o, properties) | |
550 { | |
551 for (var property of properties) { | |
552 if (propertyProcessed[property]) | |
553 continue; | |
554 | |
555 var name = property; | |
556 if (isSymbol(property)) | |
557 name = /** @type {string} */ (injectedScript._describe(prope
rty)); | |
558 | |
559 try { | |
560 propertyProcessed[property] = true; | |
561 var descriptor = nullifyObjectProto(InjectedScriptHost.suppr
essWarningsAndCallFunction(Object.getOwnPropertyDescriptor, Object, [o, property
])); | |
562 if (descriptor) { | |
563 if (accessorPropertiesOnly && !("get" in descriptor || "
set" in descriptor)) | |
564 continue; | |
565 if ("get" in descriptor && "set" in descriptor && name !
= "__proto__" && InjectedScriptHost.isDOMWrapper(object) && !doesAttributeHaveOb
servableSideEffectOnGet(object, name)) { | |
566 descriptor.value = InjectedScriptHost.suppressWarnin
gsAndCallFunction(function(attribute) { return this[attribute]; }, object, [name
]); | |
567 descriptor.isOwn = true; | |
568 delete descriptor.get; | |
569 delete descriptor.set; | |
570 } | |
571 } else { | |
572 // Not all bindings provide proper descriptors. Fall bac
k to the writable, configurable property. | |
573 if (accessorPropertiesOnly) | |
574 continue; | |
575 try { | |
576 descriptor = { name: name, value: o[property], writa
ble: false, configurable: false, enumerable: false, __proto__: null }; | |
577 if (o === object) | |
578 descriptor.isOwn = true; | |
579 yield descriptor; | |
580 } catch (e) { | |
581 // Silent catch. | |
582 } | |
583 continue; | |
584 } | |
585 } catch (e) { | |
586 if (accessorPropertiesOnly) | |
587 continue; | |
588 var descriptor = { __proto__: null }; | |
589 descriptor.value = e; | |
590 descriptor.wasThrown = true; | |
591 } | |
592 | |
593 descriptor.name = name; | |
594 if (o === object) | |
595 descriptor.isOwn = true; | |
596 if (isSymbol(property)) | |
597 descriptor.symbol = property; | |
598 yield descriptor; | |
599 } | |
600 } | |
601 | |
602 /** | |
603 * @param {number} length | |
604 */ | |
605 function* arrayIndexNames(length) | |
606 { | |
607 for (var i = 0; i < length; ++i) | |
608 yield "" + i; | |
609 } | |
610 | |
611 if (propertyNamesOnly) { | |
612 for (var i = 0; i < propertyNamesOnly.length; ++i) { | |
613 var name = propertyNamesOnly[i]; | |
614 for (var o = object; this._isDefined(o); o = o.__proto__) { | |
615 if (InjectedScriptHost.suppressWarningsAndCallFunction(Objec
t.prototype.hasOwnProperty, o, [name])) { | |
616 for (var descriptor of process(o, [name])) | |
617 yield descriptor; | |
618 break; | |
619 } | |
620 if (ownProperties) | |
621 break; | |
622 } | |
623 } | |
624 return; | |
625 } | |
626 | |
627 var skipGetOwnPropertyNames; | |
628 try { | |
629 skipGetOwnPropertyNames = InjectedScriptHost.isTypedArray(object) &&
object.length > 500000; | |
630 } catch (e) { | |
631 } | |
632 | |
633 for (var o = object; this._isDefined(o); o = o.__proto__) { | |
634 if (skipGetOwnPropertyNames && o === object) { | |
635 // Avoid OOM crashes from getting all own property names of a la
rge TypedArray. | |
636 for (var descriptor of process(o, arrayIndexNames(o.length))) | |
637 yield descriptor; | |
638 } else { | |
639 // First call Object.keys() to enforce ordering of the property
descriptors. | |
640 for (var descriptor of process(o, Object.keys(/** @type {!Object
} */ (o)))) | |
641 yield descriptor; | |
642 for (var descriptor of process(o, Object.getOwnPropertyNames(/**
@type {!Object} */ (o)))) | |
643 yield descriptor; | |
644 } | |
645 if (Object.getOwnPropertySymbols) { | |
646 for (var descriptor of process(o, Object.getOwnPropertySymbols(/
** @type {!Object} */ (o)))) | |
647 yield descriptor; | |
648 } | |
649 if (ownProperties) { | |
650 if (object.__proto__ && !accessorPropertiesOnly) | |
651 yield { name: "__proto__", value: object.__proto__, writable
: true, configurable: true, enumerable: false, isOwn: true, __proto__: null }; | |
652 break; | |
653 } | |
654 } | |
655 }, | |
656 | |
657 /** | |
658 * @param {string} expression | |
659 * @param {string} objectGroup | |
660 * @param {boolean} injectCommandLineAPI | |
661 * @param {boolean} returnByValue | |
662 * @param {boolean} generatePreview | |
663 * @return {*} | |
664 */ | |
665 evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByVa
lue, generatePreview) | |
666 { | |
667 return this._evaluateAndWrap(null, expression, objectGroup, injectComman
dLineAPI, returnByValue, generatePreview); | |
668 }, | |
669 | |
670 /** | |
671 * @param {string} objectId | |
672 * @param {string} expression | |
673 * @param {string} args | |
674 * @param {boolean} returnByValue | |
675 * @return {!Object|string} | |
676 */ | |
677 callFunctionOn: function(objectId, expression, args, returnByValue) | |
678 { | |
679 var parsedObjectId = this._parseObjectId(objectId); | |
680 var object = this._objectForId(parsedObjectId); | |
681 if (!this._isDefined(object)) | |
682 return "Could not find object with given id"; | |
683 | |
684 if (args) { | |
685 var resolvedArgs = []; | |
686 var callArgs = /** @type {!Array.<!RuntimeAgent.CallArgument>} */ (I
njectedScriptHost.eval(args)); | |
687 for (var i = 0; i < callArgs.length; ++i) { | |
688 try { | |
689 resolvedArgs[i] = this._resolveCallArgument(callArgs[i]); | |
690 } catch (e) { | |
691 return toString(e); | |
692 } | |
693 } | |
694 } | |
695 | |
696 var objectGroup = InjectedScriptHost.idToObjectGroupName(parsedObjectId.
id); | |
697 | |
698 /** | |
699 * @suppressReceiverCheck | |
700 * @param {*} object | |
701 * @param {boolean=} forceValueType | |
702 * @param {boolean=} generatePreview | |
703 * @param {?Array.<string>=} columnNames | |
704 * @param {boolean=} isTable | |
705 * @param {*=} customObjectConfig | |
706 * @return {!RuntimeAgent.RemoteObject} | |
707 * @this {InjectedScript} | |
708 */ | |
709 function wrap(object, forceValueType, generatePreview, columnNames, isTa
ble, customObjectConfig) | |
710 { | |
711 return this._wrapObject(object, objectGroup, forceValueType, generat
ePreview, columnNames, isTable, false, customObjectConfig); | |
712 } | |
713 | |
714 try { | |
715 | |
716 var remoteObjectAPI = { bindRemoteObject: bind(wrap, this), __proto_
_: null}; | |
717 InjectedScriptHost.setNonEnumProperty(inspectedGlobalObject, "__remo
teObjectAPI", remoteObjectAPI); | |
718 | |
719 var func = InjectedScriptHost.eval("with (typeof __remoteObjectAPI !
== 'undefined' ? __remoteObjectAPI : { __proto__: null }) {(" + expression + ")}
"); | |
720 if (typeof func !== "function") | |
721 return "Given expression does not evaluate to a function"; | |
722 | |
723 return { wasThrown: false, | |
724 result: this._wrapObject(InjectedScriptHost.callFunction(fu
nc, object, resolvedArgs), objectGroup, returnByValue), | |
725 __proto__: null }; | |
726 } catch (e) { | |
727 return this._createThrownValue(e, objectGroup, false); | |
728 } finally { | |
729 try { | |
730 delete inspectedGlobalObject["__remoteObjectAPI"]; | |
731 } catch(e) { | |
732 } | |
733 } | |
734 }, | |
735 | |
736 /** | |
737 * @param {string|undefined} objectGroupName | |
738 * @param {*} jsonMLObject | |
739 * @throws {string} error message | |
740 */ | |
741 _substituteObjectTagsInCustomPreview: function(objectGroupName, jsonMLObject
) | |
742 { | |
743 var maxCustomPreviewRecursionDepth = 20; | |
744 this._customPreviewRecursionDepth = (this._customPreviewRecursionDepth |
| 0) + 1 | |
745 try { | |
746 if (this._customPreviewRecursionDepth >= maxCustomPreviewRecursionDe
pth) | |
747 throw new Error("Too deep hierarchy of inlined custom previews")
; | |
748 | |
749 if (!isArrayLike(jsonMLObject)) | |
750 return; | |
751 | |
752 if (jsonMLObject[0] === "object") { | |
753 var attributes = jsonMLObject[1]; | |
754 var originObject = attributes["object"]; | |
755 var config = attributes["config"]; | |
756 if (typeof originObject === "undefined") | |
757 throw new Error("Illegal format: obligatory attribute \"obje
ct\" isn't specified"); | |
758 | |
759 jsonMLObject[1] = this._wrapObject(originObject, objectGroupName
, false, false, null, false, false, config); | |
760 return; | |
761 } | |
762 | |
763 for (var i = 0; i < jsonMLObject.length; ++i) | |
764 this._substituteObjectTagsInCustomPreview(objectGroupName, jsonM
LObject[i]); | |
765 } finally { | |
766 this._customPreviewRecursionDepth--; | |
767 } | |
768 }, | |
769 | |
770 /** | |
771 * Resolves a value from CallArgument description. | |
772 * @param {!RuntimeAgent.CallArgument} callArgumentJson | |
773 * @return {*} resolved value | |
774 * @throws {string} error message | |
775 */ | |
776 _resolveCallArgument: function(callArgumentJson) | |
777 { | |
778 callArgumentJson = nullifyObjectProto(callArgumentJson); | |
779 var objectId = callArgumentJson.objectId; | |
780 if (objectId) { | |
781 var parsedArgId = this._parseObjectId(objectId); | |
782 if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScri
ptId) | |
783 throw "Arguments should belong to the same JavaScript world as t
he target object."; | |
784 | |
785 var resolvedArg = this._objectForId(parsedArgId); | |
786 if (!this._isDefined(resolvedArg)) | |
787 throw "Could not find object with given id"; | |
788 | |
789 return resolvedArg; | |
790 } else if ("value" in callArgumentJson) { | |
791 var value = callArgumentJson.value; | |
792 if (callArgumentJson.type === "number" && typeof value !== "number") | |
793 value = Number(value); | |
794 return value; | |
795 } | |
796 return undefined; | |
797 }, | |
798 | |
799 /** | |
800 * @param {?JavaScriptCallFrame} callFrame | |
801 * @param {string} expression | |
802 * @param {string} objectGroup | |
803 * @param {boolean} injectCommandLineAPI | |
804 * @param {boolean} returnByValue | |
805 * @param {boolean} generatePreview | |
806 * @param {!Array.<!Object>=} scopeChain | |
807 * @return {!Object} | |
808 */ | |
809 _evaluateAndWrap: function(callFrame, expression, objectGroup, injectCommand
LineAPI, returnByValue, generatePreview, scopeChain) | |
810 { | |
811 var wrappedResult = this._evaluateOn(callFrame, objectGroup, expression,
injectCommandLineAPI, scopeChain); | |
812 if (!wrappedResult.exceptionDetails) { | |
813 return { wasThrown: false, | |
814 result: this._wrapObject(wrappedResult.result, objectGroup,
returnByValue, generatePreview), | |
815 __proto__: null }; | |
816 } | |
817 return this._createThrownValue(wrappedResult.result, objectGroup, genera
tePreview, wrappedResult.exceptionDetails); | |
818 }, | |
819 | |
820 /** | |
821 * @param {*} value | |
822 * @param {string|undefined} objectGroup | |
823 * @param {boolean} generatePreview | |
824 * @param {!DebuggerAgent.ExceptionDetails=} exceptionDetails | |
825 * @return {!Object} | |
826 */ | |
827 _createThrownValue: function(value, objectGroup, generatePreview, exceptionD
etails) | |
828 { | |
829 var remoteObject = this._wrapObject(value, objectGroup, false, generateP
review && InjectedScriptHost.subtype(value) !== "error"); | |
830 if (!remoteObject.description){ | |
831 try { | |
832 remoteObject.description = toStringDescription(value); | |
833 } catch (e) {} | |
834 } | |
835 return { wasThrown: true, result: remoteObject, exceptionDetails: except
ionDetails, __proto__: null }; | |
836 }, | |
837 | |
838 /** | |
839 * @param {?JavaScriptCallFrame} callFrame | |
840 * @param {string} objectGroup | |
841 * @param {string} expression | |
842 * @param {boolean} injectCommandLineAPI | |
843 * @param {!Array.<!Object>=} scopeChain | |
844 * @return {*} | |
845 */ | |
846 _evaluateOn: function(callFrame, objectGroup, expression, injectCommandLineA
PI, scopeChain) | |
847 { | |
848 // Only install command line api object for the time of evaluation. | |
849 // Surround the expression in with statements to inject our command line
API so that | |
850 // the window object properties still take more precedent than our API f
unctions. | |
851 | |
852 var scopeExtensionForEval = (callFrame && injectCommandLineAPI) ? new Co
mmandLineAPI(this._commandLineAPIImpl, callFrame) : undefined; | |
853 var injectScopeChain = scopeChain && scopeChain.length && !("__scopeChai
nForEval" in inspectedGlobalObject); | |
854 | |
855 try { | |
856 var prefix = ""; | |
857 var suffix = ""; | |
858 if (injectScopeChain) { | |
859 InjectedScriptHost.setNonEnumProperty(inspectedGlobalObject, "__
scopeChainForEval", scopeChain); | |
860 for (var i = 0; i < scopeChain.length; ++i) { | |
861 prefix = "with (typeof __scopeChainForEval !== 'undefined' ?
__scopeChainForEval[" + i + "] : { __proto__: null }) {" + (suffix ? " " : "")
+ prefix; | |
862 if (suffix) | |
863 suffix += " }"; | |
864 else | |
865 suffix = "}"; | |
866 } | |
867 } | |
868 | |
869 if (prefix) | |
870 expression = prefix + "\n" + expression + "\n" + suffix; | |
871 var wrappedResult = callFrame ? callFrame.evaluateWithExceptionDetai
ls(expression, scopeExtensionForEval) : InjectedScriptHost.evaluateWithException
Details(expression, injectCommandLineAPI ? new CommandLineAPI(this._commandLineA
PIImpl, callFrame) : undefined); | |
872 if (objectGroup === "console" && !wrappedResult.exceptionDetails) | |
873 this._lastResult = wrappedResult.result; | |
874 return wrappedResult; | |
875 } finally { | |
876 if (injectScopeChain) { | |
877 try { | |
878 delete inspectedGlobalObject["__scopeChainForEval"]; | |
879 } catch(e) { | |
880 } | |
881 } | |
882 } | |
883 }, | |
884 | |
885 /** | |
886 * @param {?Object} callFrame | |
887 * @param {number} asyncOrdinal | |
888 * @return {!Array.<!InjectedScript.CallFrameProxy>|boolean} | |
889 */ | |
890 wrapCallFrames: function(callFrame, asyncOrdinal) | |
891 { | |
892 if (!callFrame) | |
893 return false; | |
894 | |
895 var result = []; | |
896 var depth = 0; | |
897 do { | |
898 result[depth] = new InjectedScript.CallFrameProxy(depth, callFrame,
asyncOrdinal); | |
899 callFrame = callFrame.caller; | |
900 ++depth; | |
901 } while (callFrame); | |
902 return result; | |
903 }, | |
904 | |
905 /** | |
906 * @param {!JavaScriptCallFrame} topCallFrame | |
907 * @param {boolean} isAsyncStack | |
908 * @param {string} callFrameId | |
909 * @param {string} expression | |
910 * @param {string} objectGroup | |
911 * @param {boolean} injectCommandLineAPI | |
912 * @param {boolean} returnByValue | |
913 * @param {boolean} generatePreview | |
914 * @return {*} | |
915 */ | |
916 evaluateOnCallFrame: function(topCallFrame, isAsyncStack, callFrameId, expre
ssion, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) | |
917 { | |
918 var callFrame = this._callFrameForId(topCallFrame, callFrameId); | |
919 if (!callFrame) | |
920 return "Could not find call frame with given id"; | |
921 if (isAsyncStack) | |
922 return this._evaluateAndWrap(null, expression, objectGroup, injectCo
mmandLineAPI, returnByValue, generatePreview, callFrame.scopeChain); | |
923 return this._evaluateAndWrap(callFrame, expression, objectGroup, injectC
ommandLineAPI, returnByValue, generatePreview); | |
924 }, | |
925 | |
926 /** | |
927 * @param {!JavaScriptCallFrame} topCallFrame | |
928 * @param {string} callFrameId | |
929 * @return {*} | |
930 */ | |
931 restartFrame: function(topCallFrame, callFrameId) | |
932 { | |
933 var callFrame = this._callFrameForId(topCallFrame, callFrameId); | |
934 if (!callFrame) | |
935 return "Could not find call frame with given id"; | |
936 return callFrame.restart(); | |
937 }, | |
938 | |
939 /** | |
940 * @param {!JavaScriptCallFrame} topCallFrame | |
941 * @param {string} callFrameId | |
942 * @return {*} a stepIn position array ready for protocol JSON or a string e
rror | |
943 */ | |
944 getStepInPositions: function(topCallFrame, callFrameId) | |
945 { | |
946 var callFrame = this._callFrameForId(topCallFrame, callFrameId); | |
947 if (!callFrame) | |
948 return "Could not find call frame with given id"; | |
949 var stepInPositionsUnpacked = JSON.parse(callFrame.stepInPositions); | |
950 if (typeof stepInPositionsUnpacked !== "object") | |
951 return "Step in positions not available"; | |
952 return stepInPositionsUnpacked; | |
953 }, | |
954 | |
955 /** | |
956 * Either callFrameId or functionObjectId must be specified. | |
957 * @param {!JavaScriptCallFrame} topCallFrame | |
958 * @param {string|boolean} callFrameId or false | |
959 * @param {string|boolean} functionObjectId or false | |
960 * @param {number} scopeNumber | |
961 * @param {string} variableName | |
962 * @param {string} newValueJsonString RuntimeAgent.CallArgument structure se
rialized as string | |
963 * @return {string|undefined} undefined if success or an error message | |
964 */ | |
965 setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scop
eNumber, variableName, newValueJsonString) | |
966 { | |
967 try { | |
968 var newValueJson = /** @type {!RuntimeAgent.CallArgument} */ (Inject
edScriptHost.eval("(" + newValueJsonString + ")")); | |
969 var resolvedValue = this._resolveCallArgument(newValueJson); | |
970 if (typeof callFrameId === "string") { | |
971 var callFrame = this._callFrameForId(topCallFrame, callFrameId); | |
972 if (!callFrame) | |
973 return "Could not find call frame with given id"; | |
974 callFrame.setVariableValue(scopeNumber, variableName, resolvedVa
lue) | |
975 } else { | |
976 var parsedFunctionId = this._parseObjectId(/** @type {string} */
(functionObjectId)); | |
977 var func = this._objectForId(parsedFunctionId); | |
978 if (typeof func !== "function") | |
979 return "Could not resolve function by id"; | |
980 InjectedScriptHost.setFunctionVariableValue(func, scopeNumber, v
ariableName, resolvedValue); | |
981 } | |
982 } catch (e) { | |
983 return toString(e); | |
984 } | |
985 return undefined; | |
986 }, | |
987 | |
988 /** | |
989 * @param {!JavaScriptCallFrame} topCallFrame | |
990 * @param {string} callFrameId | |
991 * @return {?JavaScriptCallFrame} | |
992 */ | |
993 _callFrameForId: function(topCallFrame, callFrameId) | |
994 { | |
995 var parsedCallFrameId = nullifyObjectProto(/** @type {!Object} */ (Injec
tedScriptHost.eval("(" + callFrameId + ")"))); | |
996 var ordinal = parsedCallFrameId["ordinal"]; | |
997 var callFrame = topCallFrame; | |
998 while (--ordinal >= 0 && callFrame) | |
999 callFrame = callFrame.caller; | |
1000 return callFrame; | |
1001 }, | |
1002 | |
1003 /** | |
1004 * @param {!Object} objectId | |
1005 * @return {!Object|symbol|undefined} | |
1006 */ | |
1007 _objectForId: function(objectId) | |
1008 { | |
1009 return objectId.injectedScriptId === injectedScriptId ? /** @type{!Objec
t|symbol|undefined} */ (InjectedScriptHost.objectForId(objectId.id)) : void 0; | |
1010 }, | |
1011 | |
1012 /** | |
1013 * @param {*} object | |
1014 * @return {boolean} | |
1015 */ | |
1016 _isDefined: function(object) | |
1017 { | |
1018 return !!object || this._isHTMLAllCollection(object); | |
1019 }, | |
1020 | |
1021 /** | |
1022 * @param {*} object | |
1023 * @return {boolean} | |
1024 */ | |
1025 _isHTMLAllCollection: function(object) | |
1026 { | |
1027 // document.all is reported as undefined, but we still want to process i
t. | |
1028 return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCo
llection(object); | |
1029 }, | |
1030 | |
1031 /** | |
1032 * @param {*} obj | |
1033 * @return {?string} | |
1034 */ | |
1035 _subtype: function(obj) | |
1036 { | |
1037 if (obj === null) | |
1038 return "null"; | |
1039 | |
1040 if (this.isPrimitiveValue(obj)) | |
1041 return null; | |
1042 | |
1043 var subtype = InjectedScriptHost.subtype(obj); | |
1044 if (subtype) | |
1045 return subtype; | |
1046 | |
1047 if (isArrayLike(obj)) | |
1048 return "array"; | |
1049 | |
1050 // If owning frame has navigated to somewhere else window properties wil
l be undefined. | |
1051 return null; | |
1052 }, | |
1053 | |
1054 /** | |
1055 * @param {*} obj | |
1056 * @return {?string} | |
1057 */ | |
1058 _describe: function(obj) | |
1059 { | |
1060 if (this.isPrimitiveValue(obj)) | |
1061 return null; | |
1062 | |
1063 var subtype = this._subtype(obj); | |
1064 | |
1065 if (subtype === "regexp") | |
1066 return toString(obj); | |
1067 | |
1068 if (subtype === "date") | |
1069 return toString(obj); | |
1070 | |
1071 if (subtype === "node") { | |
1072 var description = obj.nodeName.toLowerCase(); | |
1073 switch (obj.nodeType) { | |
1074 case 1 /* Node.ELEMENT_NODE */: | |
1075 description += obj.id ? "#" + obj.id : ""; | |
1076 var className = obj.className; | |
1077 description += (className && typeof className === "string") ? ".
" + className.trim().replace(/\s+/g, ".") : ""; | |
1078 break; | |
1079 case 10 /*Node.DOCUMENT_TYPE_NODE */: | |
1080 description = "<!DOCTYPE " + description + ">"; | |
1081 break; | |
1082 } | |
1083 return description; | |
1084 } | |
1085 | |
1086 var className = InjectedScriptHost.internalConstructorName(obj); | |
1087 if (subtype === "array") { | |
1088 if (typeof obj.length === "number") | |
1089 className += "[" + obj.length + "]"; | |
1090 return className; | |
1091 } | |
1092 | |
1093 // NodeList in JSC is a function, check for array prior to this. | |
1094 if (typeof obj === "function") | |
1095 return toString(obj); | |
1096 | |
1097 if (isSymbol(obj)) { | |
1098 try { | |
1099 return /** @type {string} */ (InjectedScriptHost.callFunction(Sy
mbol.prototype.toString, obj)) || "Symbol"; | |
1100 } catch (e) { | |
1101 return "Symbol"; | |
1102 } | |
1103 } | |
1104 | |
1105 if (InjectedScriptHost.subtype(obj) === "error") { | |
1106 try { | |
1107 var stack = obj.stack; | |
1108 var message = obj.message && obj.message.length ? ": " + obj.mes
sage : ""; | |
1109 var firstCallFrame = /^\s+at\s/m.exec(stack); | |
1110 var stackMessageEnd = firstCallFrame ? firstCallFrame.index : -1
; | |
1111 if (stackMessageEnd !== -1) { | |
1112 var stackTrace = stack.substr(stackMessageEnd); | |
1113 return className + message + "\n" + stackTrace; | |
1114 } | |
1115 return className + message; | |
1116 } catch(e) { | |
1117 } | |
1118 } | |
1119 | |
1120 return className; | |
1121 }, | |
1122 | |
1123 /** | |
1124 * @param {boolean} enabled | |
1125 */ | |
1126 setCustomObjectFormatterEnabled: function(enabled) | |
1127 { | |
1128 this._customObjectFormatterEnabled = enabled; | |
1129 } | |
1130 } | |
1131 | |
1132 /** | |
1133 * @type {!InjectedScript} | |
1134 * @const | |
1135 */ | |
1136 var injectedScript = new InjectedScript(); | |
1137 | |
1138 /** | |
1139 * @constructor | |
1140 * @param {*} object | |
1141 * @param {string=} objectGroupName | |
1142 * @param {boolean=} doNotBind | |
1143 * @param {boolean=} forceValueType | |
1144 * @param {boolean=} generatePreview | |
1145 * @param {?Array.<string>=} columnNames | |
1146 * @param {boolean=} isTable | |
1147 * @param {boolean=} skipEntriesPreview | |
1148 * @param {*=} customObjectConfig | |
1149 */ | |
1150 InjectedScript.RemoteObject = function(object, objectGroupName, doNotBind, force
ValueType, generatePreview, columnNames, isTable, skipEntriesPreview, customObje
ctConfig) | |
1151 { | |
1152 this.type = typeof object; | |
1153 if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object)
) | |
1154 this.type = "object"; | |
1155 | |
1156 if (injectedScript.isPrimitiveValue(object) || object === null || forceValue
Type) { | |
1157 // We don't send undefined values over JSON. | |
1158 if (this.type !== "undefined") | |
1159 this.value = object; | |
1160 | |
1161 // Null object is object with 'null' subtype. | |
1162 if (object === null) | |
1163 this.subtype = "null"; | |
1164 | |
1165 // Provide user-friendly number values. | |
1166 if (this.type === "number") { | |
1167 this.description = toStringDescription(object); | |
1168 // Override "value" property for values that can not be JSON-stringi
fied. | |
1169 switch (this.description) { | |
1170 case "NaN": | |
1171 case "Infinity": | |
1172 case "-Infinity": | |
1173 case "-0": | |
1174 this.value = this.description; | |
1175 break; | |
1176 } | |
1177 } | |
1178 | |
1179 return; | |
1180 } | |
1181 | |
1182 object = /** @type {!Object} */ (object); | |
1183 | |
1184 if (!doNotBind) | |
1185 this.objectId = injectedScript._bind(object, objectGroupName); | |
1186 var subtype = injectedScript._subtype(object); | |
1187 if (subtype) | |
1188 this.subtype = subtype; | |
1189 var className = InjectedScriptHost.internalConstructorName(object); | |
1190 if (className) | |
1191 this.className = className; | |
1192 this.description = injectedScript._describe(object); | |
1193 | |
1194 if (generatePreview && this.type === "object" && this.subtype !== "node") | |
1195 this.preview = this._generatePreview(object, undefined, columnNames, isT
able, skipEntriesPreview); | |
1196 | |
1197 if (injectedScript._customObjectFormatterEnabled) { | |
1198 var customPreview = this._customPreview(object, objectGroupName, customO
bjectConfig); | |
1199 if (customPreview) | |
1200 this.customPreview = customPreview; | |
1201 } | |
1202 } | |
1203 | |
1204 InjectedScript.RemoteObject.prototype = { | |
1205 | |
1206 /** | |
1207 * @param {*} object | |
1208 * @param {string=} objectGroupName | |
1209 * @param {*=} customObjectConfig | |
1210 * @return {?RuntimeAgent.CustomPreview} | |
1211 */ | |
1212 _customPreview: function(object, objectGroupName, customObjectConfig) | |
1213 { | |
1214 /** | |
1215 * @param {!Error} error | |
1216 */ | |
1217 function logError(error) | |
1218 { | |
1219 Promise.resolve().then(inspectedGlobalObject.console.error.bind(insp
ectedGlobalObject.console, "Custom Formatter Failed: " + error.message)); | |
1220 } | |
1221 | |
1222 try { | |
1223 var formatters = inspectedGlobalObject["devtoolsFormatters"]; | |
1224 if (!formatters || !isArrayLike(formatters)) | |
1225 return null; | |
1226 | |
1227 for (var i = 0; i < formatters.length; ++i) { | |
1228 try { | |
1229 var formatted = formatters[i].header(object, customObjectCon
fig); | |
1230 if (!formatted) | |
1231 continue; | |
1232 | |
1233 var hasBody = formatters[i].hasBody(object, customObjectConf
ig); | |
1234 injectedScript._substituteObjectTagsInCustomPreview(objectGr
oupName, formatted); | |
1235 var formatterObjectId = injectedScript._bind(formatters[i],
objectGroupName); | |
1236 var result = {header: JSON.stringify(formatted), hasBody: !!
hasBody, formatterObjectId: formatterObjectId}; | |
1237 if (customObjectConfig) | |
1238 result["configObjectId"] = injectedScript._bind(customOb
jectConfig, objectGroupName); | |
1239 return result; | |
1240 } catch (e) { | |
1241 logError(e); | |
1242 } | |
1243 } | |
1244 } catch (e) { | |
1245 logError(e); | |
1246 } | |
1247 return null; | |
1248 }, | |
1249 | |
1250 /** | |
1251 * @return {!RuntimeAgent.ObjectPreview} preview | |
1252 */ | |
1253 _createEmptyPreview: function() | |
1254 { | |
1255 var preview = { | |
1256 type: /** @type {!RuntimeAgent.ObjectPreviewType.<string>} */ (this.
type), | |
1257 description: this.description || toStringDescription(this.value), | |
1258 lossless: true, | |
1259 overflow: false, | |
1260 properties: [], | |
1261 __proto__: null | |
1262 }; | |
1263 if (this.subtype) | |
1264 preview.subtype = /** @type {!RuntimeAgent.ObjectPreviewSubtype.<str
ing>} */ (this.subtype); | |
1265 return preview; | |
1266 }, | |
1267 | |
1268 /** | |
1269 * @param {!Object} object | |
1270 * @param {?Array.<string>=} firstLevelKeys | |
1271 * @param {?Array.<string>=} secondLevelKeys | |
1272 * @param {boolean=} isTable | |
1273 * @param {boolean=} skipEntriesPreview | |
1274 * @return {!RuntimeAgent.ObjectPreview} preview | |
1275 */ | |
1276 _generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable,
skipEntriesPreview) | |
1277 { | |
1278 var preview = this._createEmptyPreview(); | |
1279 var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0; | |
1280 | |
1281 var propertiesThreshold = { | |
1282 properties: isTable ? 1000 : max(5, firstLevelKeysCount), | |
1283 indexes: isTable ? 1000 : max(100, firstLevelKeysCount), | |
1284 __proto__: null | |
1285 }; | |
1286 | |
1287 try { | |
1288 var descriptors = injectedScript._propertyDescriptors(object, undefi
ned, undefined, firstLevelKeys); | |
1289 | |
1290 this._appendPropertyDescriptors(preview, descriptors, propertiesThre
shold, secondLevelKeys, isTable); | |
1291 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie
s < 0) | |
1292 return preview; | |
1293 | |
1294 // Add internal properties to preview. | |
1295 var rawInternalProperties = InjectedScriptHost.getInternalProperties
(object) || []; | |
1296 var internalProperties = []; | |
1297 for (var i = 0; i < rawInternalProperties.length; i += 2) { | |
1298 push(internalProperties, { | |
1299 name: rawInternalProperties[i], | |
1300 value: rawInternalProperties[i + 1], | |
1301 isOwn: true, | |
1302 enumerable: true, | |
1303 __proto__: null | |
1304 }); | |
1305 } | |
1306 this._appendPropertyDescriptors(preview, internalProperties, propert
iesThreshold, secondLevelKeys, isTable); | |
1307 | |
1308 if (this.subtype === "map" || this.subtype === "set" || this.subtype
=== "iterator") | |
1309 this._appendEntriesPreview(object, preview, skipEntriesPreview); | |
1310 | |
1311 } catch (e) { | |
1312 preview.lossless = false; | |
1313 } | |
1314 | |
1315 return preview; | |
1316 }, | |
1317 | |
1318 /** | |
1319 * @param {!RuntimeAgent.ObjectPreview} preview | |
1320 * @param {!Array.<*>|!Iterable.<*>} descriptors | |
1321 * @param {!Object} propertiesThreshold | |
1322 * @param {?Array.<string>=} secondLevelKeys | |
1323 * @param {boolean=} isTable | |
1324 */ | |
1325 _appendPropertyDescriptors: function(preview, descriptors, propertiesThresho
ld, secondLevelKeys, isTable) | |
1326 { | |
1327 for (var descriptor of descriptors) { | |
1328 if (propertiesThreshold.indexes < 0 || propertiesThreshold.propertie
s < 0) | |
1329 break; | |
1330 if (!descriptor) | |
1331 continue; | |
1332 if (descriptor.wasThrown) { | |
1333 preview.lossless = false; | |
1334 continue; | |
1335 } | |
1336 | |
1337 var name = descriptor.name; | |
1338 | |
1339 // Ignore __proto__ property, stay lossless. | |
1340 if (name === "__proto__") | |
1341 continue; | |
1342 | |
1343 // Ignore non-enumerable members on prototype, stay lossless. | |
1344 if (!descriptor.isOwn && !descriptor.enumerable) | |
1345 continue; | |
1346 | |
1347 // Ignore length property of array, stay lossless. | |
1348 if (this.subtype === "array" && name === "length") | |
1349 continue; | |
1350 | |
1351 // Ignore size property of map, set, stay lossless. | |
1352 if ((this.subtype === "map" || this.subtype === "set") && name === "
size") | |
1353 continue; | |
1354 | |
1355 // Never preview prototype properties, turn lossy. | |
1356 if (!descriptor.isOwn) { | |
1357 preview.lossless = false; | |
1358 continue; | |
1359 } | |
1360 | |
1361 // Ignore computed properties, turn lossy. | |
1362 if (!("value" in descriptor)) { | |
1363 preview.lossless = false; | |
1364 continue; | |
1365 } | |
1366 | |
1367 var value = descriptor.value; | |
1368 var type = typeof value; | |
1369 | |
1370 // Never render functions in object preview, turn lossy | |
1371 if (type === "function" && (this.subtype !== "array" || !isUInt32(na
me))) { | |
1372 preview.lossless = false; | |
1373 continue; | |
1374 } | |
1375 | |
1376 // Special-case HTMLAll. | |
1377 if (type === "undefined" && injectedScript._isHTMLAllCollection(valu
e)) | |
1378 type = "object"; | |
1379 | |
1380 // Render own properties. | |
1381 if (value === null) { | |
1382 this._appendPropertyPreview(preview, { name: name, type: "object
", subtype: "null", value: "null", __proto__: null }, propertiesThreshold); | |
1383 continue; | |
1384 } | |
1385 | |
1386 var maxLength = 100; | |
1387 if (InjectedScript.primitiveTypes[type]) { | |
1388 if (type === "string" && value.length > maxLength) { | |
1389 value = this._abbreviateString(value, maxLength, true); | |
1390 preview.lossless = false; | |
1391 } | |
1392 this._appendPropertyPreview(preview, { name: name, type: type, v
alue: toStringDescription(value), __proto__: null }, propertiesThreshold); | |
1393 continue; | |
1394 } | |
1395 | |
1396 var property = { name: name, type: type, __proto__: null }; | |
1397 var subtype = injectedScript._subtype(value); | |
1398 if (subtype) | |
1399 property.subtype = subtype; | |
1400 | |
1401 if (secondLevelKeys === null || secondLevelKeys) { | |
1402 var subPreview = this._generatePreview(value, secondLevelKeys ||
undefined, undefined, isTable); | |
1403 property.valuePreview = subPreview; | |
1404 if (!subPreview.lossless) | |
1405 preview.lossless = false; | |
1406 if (subPreview.overflow) | |
1407 preview.overflow = true; | |
1408 } else { | |
1409 var description = ""; | |
1410 if (type !== "function") | |
1411 description = this._abbreviateString(/** @type {string} */ (
injectedScript._describe(value)), maxLength, subtype === "regexp"); | |
1412 property.value = description; | |
1413 preview.lossless = false; | |
1414 } | |
1415 this._appendPropertyPreview(preview, property, propertiesThreshold); | |
1416 } | |
1417 }, | |
1418 | |
1419 /** | |
1420 * @param {!RuntimeAgent.ObjectPreview} preview | |
1421 * @param {!Object} property | |
1422 * @param {!Object} propertiesThreshold | |
1423 */ | |
1424 _appendPropertyPreview: function(preview, property, propertiesThreshold) | |
1425 { | |
1426 if (toString(property.name >>> 0) === property.name) | |
1427 propertiesThreshold.indexes--; | |
1428 else | |
1429 propertiesThreshold.properties--; | |
1430 if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties <
0) { | |
1431 preview.overflow = true; | |
1432 preview.lossless = false; | |
1433 } else { | |
1434 push(preview.properties, property); | |
1435 } | |
1436 }, | |
1437 | |
1438 /** | |
1439 * @param {!Object} object | |
1440 * @param {!RuntimeAgent.ObjectPreview} preview | |
1441 * @param {boolean=} skipEntriesPreview | |
1442 */ | |
1443 _appendEntriesPreview: function(object, preview, skipEntriesPreview) | |
1444 { | |
1445 var entries = InjectedScriptHost.collectionEntries(object); | |
1446 if (!entries) | |
1447 return; | |
1448 if (skipEntriesPreview) { | |
1449 if (entries.length) { | |
1450 preview.overflow = true; | |
1451 preview.lossless = false; | |
1452 } | |
1453 return; | |
1454 } | |
1455 preview.entries = []; | |
1456 var entriesThreshold = 5; | |
1457 for (var i = 0; i < entries.length; ++i) { | |
1458 if (preview.entries.length >= entriesThreshold) { | |
1459 preview.overflow = true; | |
1460 preview.lossless = false; | |
1461 break; | |
1462 } | |
1463 var entry = nullifyObjectProto(entries[i]); | |
1464 var previewEntry = { | |
1465 value: generateValuePreview(entry.value), | |
1466 __proto__: null | |
1467 }; | |
1468 if ("key" in entry) | |
1469 previewEntry.key = generateValuePreview(entry.key); | |
1470 push(preview.entries, previewEntry); | |
1471 } | |
1472 | |
1473 /** | |
1474 * @param {*} value | |
1475 * @return {!RuntimeAgent.ObjectPreview} | |
1476 */ | |
1477 function generateValuePreview(value) | |
1478 { | |
1479 var remoteObject = new InjectedScript.RemoteObject(value, undefined,
true, undefined, true, undefined, undefined, true); | |
1480 var valuePreview = remoteObject.preview || remoteObject._createEmpty
Preview(); | |
1481 if (!valuePreview.lossless) | |
1482 preview.lossless = false; | |
1483 return valuePreview; | |
1484 } | |
1485 }, | |
1486 | |
1487 /** | |
1488 * @param {string} string | |
1489 * @param {number} maxLength | |
1490 * @param {boolean=} middle | |
1491 * @return {string} | |
1492 */ | |
1493 _abbreviateString: function(string, maxLength, middle) | |
1494 { | |
1495 if (string.length <= maxLength) | |
1496 return string; | |
1497 if (middle) { | |
1498 var leftHalf = maxLength >> 1; | |
1499 var rightHalf = maxLength - leftHalf - 1; | |
1500 return string.substr(0, leftHalf) + "\u2026" + string.substr(string.
length - rightHalf, rightHalf); | |
1501 } | |
1502 return string.substr(0, maxLength) + "\u2026"; | |
1503 }, | |
1504 | |
1505 __proto__: null | |
1506 } | |
1507 | |
1508 /** | |
1509 * @constructor | |
1510 * @param {number} ordinal | |
1511 * @param {!JavaScriptCallFrame} callFrame | |
1512 * @param {number} asyncOrdinal | |
1513 */ | |
1514 InjectedScript.CallFrameProxy = function(ordinal, callFrame, asyncOrdinal) | |
1515 { | |
1516 this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + in
jectedScriptId + (asyncOrdinal ? ",\"asyncOrdinal\":" + asyncOrdinal : "") + "}"
; | |
1517 this.functionName = callFrame.functionName; | |
1518 this.functionLocation = { scriptId: toString(callFrame.sourceID), lineNumber
: callFrame.functionLine, columnNumber: callFrame.functionColumn, __proto__: nul
l }; | |
1519 this.location = { scriptId: toString(callFrame.sourceID), lineNumber: callFr
ame.line, columnNumber: callFrame.column, __proto__: null }; | |
1520 this.scopeChain = this._wrapScopeChain(callFrame); | |
1521 this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace"); | |
1522 if (callFrame.isAtReturn) | |
1523 this.returnValue = injectedScript._wrapObject(callFrame.returnValue, "ba
cktrace"); | |
1524 } | |
1525 | |
1526 InjectedScript.CallFrameProxy.prototype = { | |
1527 /** | |
1528 * @param {!JavaScriptCallFrame} callFrame | |
1529 * @return {!Array.<!DebuggerAgent.Scope>} | |
1530 */ | |
1531 _wrapScopeChain: function(callFrame) | |
1532 { | |
1533 var scopeChain = callFrame.scopeChain; | |
1534 var scopeChainProxy = []; | |
1535 for (var i = 0; i < scopeChain.length; ++i) | |
1536 scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(
callFrame.scopeType(i), callFrame.scopeName(i), scopeChain[i], "backtrace"); | |
1537 return scopeChainProxy; | |
1538 }, | |
1539 | |
1540 __proto__: null | |
1541 } | |
1542 | |
1543 /** | |
1544 * @const | |
1545 * @type {!Object.<number, !DebuggerAgent.ScopeType>} | |
1546 */ | |
1547 InjectedScript.CallFrameProxy._scopeTypeNames = { | |
1548 0: "global", | |
1549 1: "local", | |
1550 2: "with", | |
1551 3: "closure", | |
1552 4: "catch", | |
1553 5: "block", | |
1554 6: "script", | |
1555 __proto__: null | |
1556 }; | |
1557 | |
1558 /** | |
1559 * @param {number} scopeTypeCode | |
1560 * @param {string} scopeName | |
1561 * @param {*} scopeObject | |
1562 * @param {string} groupId | |
1563 * @return {!DebuggerAgent.Scope} | |
1564 */ | |
1565 InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeNa
me, scopeObject, groupId) | |
1566 { | |
1567 var scope = { | |
1568 object: injectedScript._wrapObject(scopeObject, groupId), | |
1569 type: InjectedScript.CallFrameProxy._scopeTypeNames[scopeTypeCode], | |
1570 __proto__: null | |
1571 }; | |
1572 if (scopeName) | |
1573 scope.name = scopeName; | |
1574 return scope; | |
1575 } | |
1576 | |
1577 /** | |
1578 * @constructor | |
1579 * @param {!CommandLineAPIImpl} commandLineAPIImpl | |
1580 * @param {?JavaScriptCallFrame} callFrame | |
1581 */ | |
1582 function CommandLineAPI(commandLineAPIImpl, callFrame) | |
1583 { | |
1584 /** | |
1585 * @param {string} member | |
1586 * @return {boolean} | |
1587 */ | |
1588 function inScopeVariables(member) | |
1589 { | |
1590 if (!callFrame) | |
1591 return (member in inspectedGlobalObject); | |
1592 | |
1593 var scopeChain = callFrame.scopeChain; | |
1594 for (var i = 0; i < scopeChain.length; ++i) { | |
1595 if (member in scopeChain[i]) | |
1596 return true; | |
1597 } | |
1598 return false; | |
1599 } | |
1600 | |
1601 /** | |
1602 * @param {string} name The name of the method for which a toString method s
hould be generated. | |
1603 * @return {function():string} | |
1604 */ | |
1605 function customToStringMethod(name) | |
1606 { | |
1607 return function() | |
1608 { | |
1609 var funcArgsSyntax = ""; | |
1610 try { | |
1611 var funcSyntax = "" + commandLineAPIImpl[name]; | |
1612 funcSyntax = funcSyntax.replace(/\n/g, " "); | |
1613 funcSyntax = funcSyntax.replace(/^function[^\(]*\(([^\)]*)\).*$/
, "$1"); | |
1614 funcSyntax = funcSyntax.replace(/\s*,\s*/g, ", "); | |
1615 funcSyntax = funcSyntax.replace(/\bopt_(\w+)\b/g, "[$1]"); | |
1616 funcArgsSyntax = funcSyntax.trim(); | |
1617 } catch (e) { | |
1618 } | |
1619 return "function " + name + "(" + funcArgsSyntax + ") { [Command Lin
e API] }"; | |
1620 }; | |
1621 } | |
1622 | |
1623 for (var i = 0; i < CommandLineAPI.members_.length; ++i) { | |
1624 var member = CommandLineAPI.members_[i]; | |
1625 if (inScopeVariables(member)) | |
1626 continue; | |
1627 | |
1628 this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl); | |
1629 this[member].toString = customToStringMethod(member); | |
1630 } | |
1631 | |
1632 for (var i = 0; i < 5; ++i) { | |
1633 var member = "$" + i; | |
1634 if (inScopeVariables(member)) | |
1635 continue; | |
1636 | |
1637 this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject,
commandLineAPIImpl, i)); | |
1638 } | |
1639 | |
1640 this.$_ = injectedScript._lastResult; | |
1641 | |
1642 this.__proto__ = null; | |
1643 } | |
1644 | |
1645 // NOTE: Please keep the list of API methods below synchronized to that in WebIn
spector.RuntimeModel | |
1646 // and V8InjectedScriptHost! | |
1647 // NOTE: Argument names of these methods will be printed in the console, so use
pretty names! | |
1648 /** | |
1649 * @type {!Array.<string>} | |
1650 * @const | |
1651 */ | |
1652 CommandLineAPI.members_ = [ | |
1653 "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", | |
1654 "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventLis
teners", | |
1655 "debug", "undebug", "monitor", "unmonitor", "table" | |
1656 ]; | |
1657 | |
1658 /** | |
1659 * @constructor | |
1660 */ | |
1661 function CommandLineAPIImpl() | |
1662 { | |
1663 } | |
1664 | |
1665 CommandLineAPIImpl.prototype = { | |
1666 /** | |
1667 * @param {string} selector | |
1668 * @param {!Node=} opt_startNode | |
1669 * @return {*} | |
1670 */ | |
1671 $: function (selector, opt_startNode) | |
1672 { | |
1673 if (this._canQuerySelectorOnNode(opt_startNode)) | |
1674 return opt_startNode.querySelector(selector); | |
1675 | |
1676 return inspectedGlobalObject.document.querySelector(selector); | |
1677 }, | |
1678 | |
1679 /** | |
1680 * @param {string} selector | |
1681 * @param {!Node=} opt_startNode | |
1682 * @return {*} | |
1683 */ | |
1684 $$: function (selector, opt_startNode) | |
1685 { | |
1686 if (this._canQuerySelectorOnNode(opt_startNode)) | |
1687 return slice(opt_startNode.querySelectorAll(selector)); | |
1688 return slice(inspectedGlobalObject.document.querySelectorAll(selector)); | |
1689 }, | |
1690 | |
1691 /** | |
1692 * @param {!Node=} node | |
1693 * @return {boolean} | |
1694 */ | |
1695 _canQuerySelectorOnNode: function(node) | |
1696 { | |
1697 return !!node && InjectedScriptHost.subtype(node) === "node" && (node.no
deType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nod
eType === Node.DOCUMENT_FRAGMENT_NODE); | |
1698 }, | |
1699 | |
1700 /** | |
1701 * @param {string} xpath | |
1702 * @param {!Node=} opt_startNode | |
1703 * @return {*} | |
1704 */ | |
1705 $x: function(xpath, opt_startNode) | |
1706 { | |
1707 var doc = (opt_startNode && opt_startNode.ownerDocument) || inspectedGlo
balObject.document; | |
1708 var result = doc.evaluate(xpath, opt_startNode || doc, null, XPathResult
.ANY_TYPE, null); | |
1709 switch (result.resultType) { | |
1710 case XPathResult.NUMBER_TYPE: | |
1711 return result.numberValue; | |
1712 case XPathResult.STRING_TYPE: | |
1713 return result.stringValue; | |
1714 case XPathResult.BOOLEAN_TYPE: | |
1715 return result.booleanValue; | |
1716 default: | |
1717 var nodes = []; | |
1718 var node; | |
1719 while (node = result.iterateNext()) | |
1720 push(nodes, node); | |
1721 return nodes; | |
1722 } | |
1723 }, | |
1724 | |
1725 /** | |
1726 * @return {*} | |
1727 */ | |
1728 dir: function(var_args) | |
1729 { | |
1730 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.dir
, inspectedGlobalObject.console, slice(arguments)); | |
1731 }, | |
1732 | |
1733 /** | |
1734 * @return {*} | |
1735 */ | |
1736 dirxml: function(var_args) | |
1737 { | |
1738 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.dir
xml, inspectedGlobalObject.console, slice(arguments)); | |
1739 }, | |
1740 | |
1741 /** | |
1742 * @return {!Array.<string>} | |
1743 */ | |
1744 keys: function(object) | |
1745 { | |
1746 return Object.keys(object); | |
1747 }, | |
1748 | |
1749 /** | |
1750 * @return {!Array.<*>} | |
1751 */ | |
1752 values: function(object) | |
1753 { | |
1754 var result = []; | |
1755 for (var key in object) | |
1756 push(result, object[key]); | |
1757 return result; | |
1758 }, | |
1759 | |
1760 /** | |
1761 * @return {*} | |
1762 */ | |
1763 profile: function(opt_title) | |
1764 { | |
1765 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.pro
file, inspectedGlobalObject.console, slice(arguments)); | |
1766 }, | |
1767 | |
1768 /** | |
1769 * @return {*} | |
1770 */ | |
1771 profileEnd: function(opt_title) | |
1772 { | |
1773 return InjectedScriptHost.callFunction(inspectedGlobalObject.console.pro
fileEnd, inspectedGlobalObject.console, slice(arguments)); | |
1774 }, | |
1775 | |
1776 /** | |
1777 * @param {!Object} object | |
1778 * @param {!Array.<string>|string=} opt_types | |
1779 */ | |
1780 monitorEvents: function(object, opt_types) | |
1781 { | |
1782 if (!object || !object.addEventListener || !object.removeEventListener) | |
1783 return; | |
1784 var types = this._normalizeEventTypes(opt_types); | |
1785 for (var i = 0; i < types.length; ++i) { | |
1786 object.removeEventListener(types[i], this._logEvent, false); | |
1787 object.addEventListener(types[i], this._logEvent, false); | |
1788 } | |
1789 }, | |
1790 | |
1791 /** | |
1792 * @param {!Object} object | |
1793 * @param {!Array.<string>|string=} opt_types | |
1794 */ | |
1795 unmonitorEvents: function(object, opt_types) | |
1796 { | |
1797 if (!object || !object.addEventListener || !object.removeEventListener) | |
1798 return; | |
1799 var types = this._normalizeEventTypes(opt_types); | |
1800 for (var i = 0; i < types.length; ++i) | |
1801 object.removeEventListener(types[i], this._logEvent, false); | |
1802 }, | |
1803 | |
1804 /** | |
1805 * @param {*} object | |
1806 * @return {*} | |
1807 */ | |
1808 inspect: function(object) | |
1809 { | |
1810 return injectedScript._inspect(object); | |
1811 }, | |
1812 | |
1813 copy: function(object) | |
1814 { | |
1815 var string; | |
1816 if (injectedScript._subtype(object) === "node") { | |
1817 string = object.outerHTML; | |
1818 } else if (injectedScript.isPrimitiveValue(object)) { | |
1819 string = toString(object); | |
1820 } else { | |
1821 try { | |
1822 string = JSON.stringify(object, null, " "); | |
1823 } catch (e) { | |
1824 string = toString(object); | |
1825 } | |
1826 } | |
1827 | |
1828 var hints = { copyToClipboard: true, __proto__: null }; | |
1829 var remoteObject = injectedScript._wrapObject(string, "") | |
1830 InjectedScriptHost.inspect(remoteObject, hints); | |
1831 }, | |
1832 | |
1833 clear: function() | |
1834 { | |
1835 InjectedScriptHost.clearConsoleMessages(); | |
1836 }, | |
1837 | |
1838 /** | |
1839 * @param {!Node} node | |
1840 * @return {!Array.<!{type: string, listener: function(), useCapture: boolea
n, remove: function()}>|undefined} | |
1841 */ | |
1842 getEventListeners: function(node) | |
1843 { | |
1844 var result = nullifyObjectProto(InjectedScriptHost.getEventListeners(nod
e)); | |
1845 if (!result) | |
1846 return result; | |
1847 /** @this {{type: string, listener: function(), useCapture: boolean}} */ | |
1848 var removeFunc = function() | |
1849 { | |
1850 node.removeEventListener(this.type, this.listener, this.useCapture); | |
1851 } | |
1852 for (var type in result) { | |
1853 var listeners = result[type]; | |
1854 for (var i = 0, listener; listener = listeners[i]; ++i) { | |
1855 listener["type"] = type; | |
1856 listener["remove"] = removeFunc; | |
1857 } | |
1858 } | |
1859 return result; | |
1860 }, | |
1861 | |
1862 debug: function(fn) | |
1863 { | |
1864 InjectedScriptHost.debugFunction(fn); | |
1865 }, | |
1866 | |
1867 undebug: function(fn) | |
1868 { | |
1869 InjectedScriptHost.undebugFunction(fn); | |
1870 }, | |
1871 | |
1872 monitor: function(fn) | |
1873 { | |
1874 InjectedScriptHost.monitorFunction(fn); | |
1875 }, | |
1876 | |
1877 unmonitor: function(fn) | |
1878 { | |
1879 InjectedScriptHost.unmonitorFunction(fn); | |
1880 }, | |
1881 | |
1882 table: function(data, opt_columns) | |
1883 { | |
1884 InjectedScriptHost.callFunction(inspectedGlobalObject.console.table, ins
pectedGlobalObject.console, slice(arguments)); | |
1885 }, | |
1886 | |
1887 /** | |
1888 * @param {number} num | |
1889 */ | |
1890 _inspectedObject: function(num) | |
1891 { | |
1892 return InjectedScriptHost.inspectedObject(num); | |
1893 }, | |
1894 | |
1895 /** | |
1896 * @param {!Array.<string>|string=} types | |
1897 * @return {!Array.<string>} | |
1898 */ | |
1899 _normalizeEventTypes: function(types) | |
1900 { | |
1901 if (typeof types === "undefined") | |
1902 types = ["mouse", "key", "touch", "pointer", "control", "load", "unl
oad", "abort", "error", "select", "input", "change", "submit", "reset", "focus",
"blur", "resize", "scroll", "search", "devicemotion", "deviceorientation"]; | |
1903 else if (typeof types === "string") | |
1904 types = [types]; | |
1905 | |
1906 var result = []; | |
1907 for (var i = 0; i < types.length; ++i) { | |
1908 if (types[i] === "mouse") | |
1909 push(result, "click", "dblclick", "mousedown", "mouseeenter", "m
ouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mouseleave", "mous
ewheel"); | |
1910 else if (types[i] === "key") | |
1911 push(result, "keydown", "keyup", "keypress", "textInput"); | |
1912 else if (types[i] === "touch") | |
1913 push(result, "touchstart", "touchmove", "touchend", "touchcancel
"); | |
1914 else if (types[i] === "pointer") | |
1915 push(result, "pointerover", "pointerout", "pointerenter", "point
erleave", "pointerdown", "pointerup", "pointermove", "pointercancel", "gotpointe
rcapture", "lostpointercapture"); | |
1916 else if (types[i] === "control") | |
1917 push(result, "resize", "scroll", "zoom", "focus", "blur", "selec
t", "input", "change", "submit", "reset"); | |
1918 else | |
1919 push(result, types[i]); | |
1920 } | |
1921 return result; | |
1922 }, | |
1923 | |
1924 /** | |
1925 * @param {!Event} event | |
1926 */ | |
1927 _logEvent: function(event) | |
1928 { | |
1929 inspectedGlobalObject.console.log(event.type, event); | |
1930 } | |
1931 } | |
1932 | |
1933 injectedScript._commandLineAPIImpl = new CommandLineAPIImpl(); | |
1934 return injectedScript; | |
1935 }) | |
OLD | NEW |