1/* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29//# sourceURL=__WebInspectorCommandLineAPIModuleSource__ 30 31/** 32 * @param {InjectedScriptHost} InjectedScriptHost 33 * @param {Window} inspectedWindow 34 * @param {number} injectedScriptId 35 * @param {InjectedScript} injectedScript 36 * @param {CommandLineAPIHost} CommandLineAPIHost 37 */ 38(function (InjectedScriptHost, inspectedWindow, injectedScriptId, injectedScript, CommandLineAPIHost) { 39 40/** 41 * @param {Arguments} array 42 * @param {number=} index 43 * @return {Array.<*>} 44 */ 45function slice(array, index) 46{ 47 var result = []; 48 for (var i = index || 0; i < array.length; ++i) 49 result.push(array[i]); 50 return result; 51} 52 53/** 54 * Please use this bind, not the one from Function.prototype 55 * @param {function(...)} func 56 * @param {Object} thisObject 57 * @param {...number} var_args 58 */ 59function bind(func, thisObject, var_args) 60{ 61 var args = slice(arguments, 2); 62 63 /** 64 * @param {...number} var_args 65 */ 66 function bound(var_args) 67 { 68 return func.apply(thisObject, args.concat(slice(arguments))); 69 } 70 bound.toString = function() { 71 return "bound: " + func; 72 }; 73 return bound; 74} 75 76/** 77 * @constructor 78 * @param {CommandLineAPIImpl} commandLineAPIImpl 79 * @param {Object} callFrame 80 */ 81function CommandLineAPI(commandLineAPIImpl, callFrame) 82{ 83 /** 84 * @param {string} member 85 * @return {boolean} 86 */ 87 function inScopeVariables(member) 88 { 89 if (!callFrame) 90 return false; 91 92 var scopeChain = callFrame.scopeChain; 93 for (var i = 0; i < scopeChain.length; ++i) { 94 if (member in scopeChain[i]) 95 return true; 96 } 97 return false; 98 } 99 100 /** 101 * @param {string} name The name of the method for which a toString method should be generated. 102 * @return {function():string} 103 */ 104 function customToStringMethod(name) 105 { 106 return function () { return "function " + name + "() { [Command Line API] }"; }; 107 } 108 109 for (var i = 0; i < CommandLineAPI.members_.length; ++i) { 110 var member = CommandLineAPI.members_[i]; 111 if (member in inspectedWindow || inScopeVariables(member)) 112 continue; 113 114 this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl); 115 this[member].toString = customToStringMethod(member); 116 } 117 118 for (var i = 0; i < 5; ++i) { 119 var member = "$" + i; 120 if (member in inspectedWindow || inScopeVariables(member)) 121 continue; 122 123 this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i)); 124 } 125 126 this.$_ = injectedScript._lastResult; 127} 128 129/** 130 * @type {Array.<string>} 131 * @const 132 */ 133CommandLineAPI.members_ = [ 134 "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", 135 "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners" 136]; 137 138/** 139 * @constructor 140 */ 141function CommandLineAPIImpl() 142{ 143} 144 145CommandLineAPIImpl.prototype = { 146 /** 147 * @param {string} selector 148 * @param {Node=} start 149 */ 150 $: function (selector, start) 151 { 152 if (this._canQuerySelectorOnNode(start)) 153 return start.querySelector(selector); 154 155 var result = inspectedWindow.document.querySelector(selector); 156 if (result) 157 return result; 158 if (selector && selector[0] !== "#") { 159 result = inspectedWindow.document.getElementById(selector); 160 if (result) { 161 inspectedWindow.console.warn("The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $(\"#%s\")", selector ); 162 return null; 163 } 164 } 165 return result; 166 }, 167 168 /** 169 * @param {string} selector 170 * @param {Node=} start 171 */ 172 $$: function (selector, start) 173 { 174 if (this._canQuerySelectorOnNode(start)) 175 return start.querySelectorAll(selector); 176 return inspectedWindow.document.querySelectorAll(selector); 177 }, 178 179 /** 180 * @param {Node=} node 181 * @return {boolean} 182 */ 183 _canQuerySelectorOnNode: function(node) 184 { 185 return !!node && InjectedScriptHost.type(node) === "node" && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE); 186 }, 187 188 /** 189 * @param {string} xpath 190 * @param {Node=} context 191 */ 192 $x: function(xpath, context) 193 { 194 var doc = (context && context.ownerDocument) || inspectedWindow.document; 195 var result = doc.evaluate(xpath, context || doc, null, XPathResult.ANY_TYPE, null); 196 switch (result.resultType) { 197 case XPathResult.NUMBER_TYPE: 198 return result.numberValue; 199 case XPathResult.STRING_TYPE: 200 return result.stringValue; 201 case XPathResult.BOOLEAN_TYPE: 202 return result.booleanValue; 203 default: 204 var nodes = []; 205 var node; 206 while (node = result.iterateNext()) 207 nodes.push(node); 208 return nodes; 209 } 210 }, 211 212 dir: function() 213 { 214 return inspectedWindow.console.dir.apply(inspectedWindow.console, arguments) 215 }, 216 217 dirxml: function() 218 { 219 return inspectedWindow.console.dirxml.apply(inspectedWindow.console, arguments) 220 }, 221 222 keys: function(object) 223 { 224 return Object.keys(object); 225 }, 226 227 values: function(object) 228 { 229 var result = []; 230 for (var key in object) 231 result.push(object[key]); 232 return result; 233 }, 234 235 profile: function() 236 { 237 return inspectedWindow.console.profile.apply(inspectedWindow.console, arguments) 238 }, 239 240 profileEnd: function() 241 { 242 return inspectedWindow.console.profileEnd.apply(inspectedWindow.console, arguments) 243 }, 244 245 /** 246 * @param {Object} object 247 * @param {Array.<string>|string=} types 248 */ 249 monitorEvents: function(object, types) 250 { 251 if (!object || !object.addEventListener || !object.removeEventListener) 252 return; 253 types = this._normalizeEventTypes(types); 254 for (var i = 0; i < types.length; ++i) { 255 object.removeEventListener(types[i], this._logEvent, false); 256 object.addEventListener(types[i], this._logEvent, false); 257 } 258 }, 259 260 /** 261 * @param {Object} object 262 * @param {Array.<string>|string=} types 263 */ 264 unmonitorEvents: function(object, types) 265 { 266 if (!object || !object.addEventListener || !object.removeEventListener) 267 return; 268 types = this._normalizeEventTypes(types); 269 for (var i = 0; i < types.length; ++i) 270 object.removeEventListener(types[i], this._logEvent, false); 271 }, 272 273 /** 274 * @param {*} object 275 * @return {*} 276 */ 277 inspect: function(object) 278 { 279 return this._inspect(object); 280 }, 281 282 copy: function(object) 283 { 284 if (injectedScript._subtype(object) === "node") 285 object = object.outerHTML; 286 CommandLineAPIHost.copyText(object); 287 }, 288 289 clear: function() 290 { 291 CommandLineAPIHost.clearConsoleMessages(); 292 }, 293 294 /** 295 * @param {Node} node 296 */ 297 getEventListeners: function(node) 298 { 299 return CommandLineAPIHost.getEventListeners(node); 300 }, 301 302 /** 303 * @param {number} num 304 */ 305 _inspectedObject: function(num) 306 { 307 return CommandLineAPIHost.inspectedObject(num); 308 }, 309 310 /** 311 * @param {Array.<string>|string=} types 312 * @return {Array.<string>} 313 */ 314 _normalizeEventTypes: function(types) 315 { 316 if (typeof types === "undefined") 317 types = [ "mouse", "key", "touch", "control", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation" ]; 318 else if (typeof types === "string") 319 types = [ types ]; 320 321 var result = []; 322 for (var i = 0; i < types.length; i++) { 323 if (types[i] === "mouse") 324 result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel"); 325 else if (types[i] === "key") 326 result.splice(0, 0, "keydown", "keyup", "keypress", "textInput"); 327 else if (types[i] === "touch") 328 result.splice(0, 0, "touchstart", "touchmove", "touchend", "touchcancel"); 329 else if (types[i] === "control") 330 result.splice(0, 0, "resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"); 331 else 332 result.push(types[i]); 333 } 334 return result; 335 }, 336 337 /** 338 * @param {Event} event 339 */ 340 _logEvent: function(event) 341 { 342 inspectedWindow.console.log(event.type, event); 343 }, 344 345 /** 346 * @param {*} object 347 * @return {*} 348 */ 349 _inspect: function(object) 350 { 351 if (arguments.length === 0) 352 return; 353 354 var objectId = injectedScript._wrapObject(object, ""); 355 var hints = {}; 356 357 switch (injectedScript._describe(object)) { 358 case "Database": 359 var databaseId = CommandLineAPIHost.databaseId(object) 360 if (databaseId) 361 hints.databaseId = databaseId; 362 break; 363 case "Storage": 364 var storageId = CommandLineAPIHost.storageId(object) 365 if (storageId) 366 hints.domStorageId = InjectedScriptHost.evaluate("(" + storageId + ")"); 367 break; 368 } 369 370 CommandLineAPIHost.inspect(objectId, hints); 371 return object; 372 } 373} 374 375injectedScript.CommandLineAPI = CommandLineAPI; 376injectedScript._commandLineAPIImpl = new CommandLineAPIImpl(); 377 378// This Module doesn't expose an object, it just adds an extension that InjectedScript uses. 379// However, we return an empty object, so that InjectedScript knows this module has been loaded. 380return {}; 381 382}) 383