18d632619b429ab54d4f85e00e76c31994e5cff0
[WebKit-https.git] / Source / WebCore / inspector / CommandLineAPIModuleSource.js
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=__InjectedScript_CommandLineAPIModuleSource.js
30
31 (function (InjectedScriptHost, inspectedWindow, injectedScriptId, injectedScript, RemoteObject, CommandLineAPIHost) {
32
33 // FIXME: <https://webkit.org/b/152294> Web Inspector: Parse InjectedScriptSource as a built-in to get guaranteed non-user-overridden built-ins
34
35 function bind(func, thisObject, ...outerArgs)
36 {
37     return function(...innerArgs) {
38         return func.apply(thisObject, outerArgs.concat(innerArgs));
39     };
40 }
41
42 /**
43  * @constructor
44  * @param {CommandLineAPIImpl} commandLineAPIImpl
45  * @param {Object} callFrame
46  */
47 function CommandLineAPI(commandLineAPIImpl, callFrame)
48 {
49     this.$_ = injectedScript._lastResult;
50     this.$exception = injectedScript._exceptionValue;
51
52     // $0
53     this.__defineGetter__("$0", bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl));
54
55     // $1-$99
56     for (let i = 1; i <= injectedScript._savedResults.length; ++i)
57         this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i));
58
59     // Command Line API methods.
60     for (let i = 0; i < CommandLineAPI.methods.length; ++i) {
61         let method = CommandLineAPI.methods[i];
62         this[method] = bind(commandLineAPIImpl[method], commandLineAPIImpl);
63         this[method].toString = function() { return "function " + method + "() { [Command Line API] }" };
64     }
65 }
66
67 /**
68  * @type {Array.<string>}
69  * @const
70  */
71 CommandLineAPI.methods = [
72     "$",
73     "$$",
74     "$x",
75     "clear",
76     "copy",
77     "dir",
78     "dirxml",
79     "getEventListeners",
80     "inspect",
81     "keys",
82     "monitorEvents",
83     "profile",
84     "profileEnd",
85     "queryObjects",
86     "screenshot",
87     "table",
88     "unmonitorEvents",
89     "values",
90 ];
91
92 /**
93  * @constructor
94  */
95 function CommandLineAPIImpl()
96 {
97 }
98
99 CommandLineAPIImpl.prototype = {
100     /**
101      * @param {string} selector
102      * @param {Node=} start
103      */
104     $: function (selector, start)
105     {
106         if (this._canQuerySelectorOnNode(start))
107             return start.querySelector(selector);
108
109         var result = inspectedWindow.document.querySelector(selector);
110         if (result)
111             return result;
112         if (selector && selector[0] !== "#") {
113             result = inspectedWindow.document.getElementById(selector);
114             if (result) {
115                 inspectedWindow.console.warn("The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $(\"#%s\")", selector);
116                 return null;
117             }
118         }
119         return result;
120     },
121
122     /**
123      * @param {string} selector
124      * @param {Node=} start
125      */
126     $$: function (selector, start)
127     {
128         if (this._canQuerySelectorOnNode(start))
129             return Array.from(start.querySelectorAll(selector));
130         return Array.from(inspectedWindow.document.querySelectorAll(selector));
131     },
132
133     /**
134      * @param {Node=} node
135      * @return {boolean}
136      */
137     _canQuerySelectorOnNode: function(node)
138     {
139         return !!node && InjectedScriptHost.subtype(node) === "node" && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE);
140     },
141
142     /**
143      * @param {string} xpath
144      * @param {Node=} context
145      */
146     $x: function(xpath, context)
147     {
148         var doc = (context && context.ownerDocument) || inspectedWindow.document;
149         var result = doc.evaluate(xpath, context || doc, null, XPathResult.ANY_TYPE, null);
150         switch (result.resultType) {
151         case XPathResult.NUMBER_TYPE:
152             return result.numberValue;
153         case XPathResult.STRING_TYPE:
154             return result.stringValue;
155         case XPathResult.BOOLEAN_TYPE:
156             return result.booleanValue;
157         default:
158             var nodes = [];
159             var node;
160             while (node = result.iterateNext())
161                 nodes.push(node);
162             return nodes;
163         }
164     },
165
166     dir: function()
167     {
168         return inspectedWindow.console.dir.apply(inspectedWindow.console, arguments)
169     },
170
171     dirxml: function()
172     {
173         return inspectedWindow.console.dirxml.apply(inspectedWindow.console, arguments)
174     },
175
176     keys: function(object)
177     {
178         return Object.keys(object);
179     },
180
181     values: function(object)
182     {
183         var result = [];
184         for (var key in object)
185             result.push(object[key]);
186         return result;
187     },
188
189     profile: function()
190     {
191         return inspectedWindow.console.profile.apply(inspectedWindow.console, arguments)
192     },
193
194     profileEnd: function()
195     {
196         return inspectedWindow.console.profileEnd.apply(inspectedWindow.console, arguments)
197     },
198
199     table: function()
200     {
201         return inspectedWindow.console.table.apply(inspectedWindow.console, arguments)
202     },
203
204     screenshot: function()
205     {
206         return inspectedWindow.console.screenshot.apply(inspectedWindow.console, arguments)
207     },
208
209     /**
210      * @param {Object} object
211      * @param {Array.<string>|string=} types
212      */
213     monitorEvents: function(object, types)
214     {
215         if (!object || !object.addEventListener || !object.removeEventListener)
216             return;
217         types = this._normalizeEventTypes(types);
218         for (var i = 0; i < types.length; ++i) {
219             object.removeEventListener(types[i], this._logEvent, false);
220             object.addEventListener(types[i], this._logEvent, false);
221         }
222     },
223
224     /**
225      * @param {Object} object
226      * @param {Array.<string>|string=} types
227      */
228     unmonitorEvents: function(object, types)
229     {
230         if (!object || !object.addEventListener || !object.removeEventListener)
231             return;
232         types = this._normalizeEventTypes(types);
233         for (var i = 0; i < types.length; ++i)
234             object.removeEventListener(types[i], this._logEvent, false);
235     },
236
237     /**
238      * @param {*} object
239      * @return {*}
240      */
241     inspect: function(object)
242     {
243         return this._inspect(object);
244     },
245
246     queryObjects()
247     {
248         return InjectedScriptHost.queryObjects(...arguments);
249     },
250
251     copy: function(object)
252     {
253         var string;
254         var subtype = RemoteObject.subtype(object);
255         if (subtype === "node")
256             string = object.outerHTML;
257         else if (subtype === "regexp")
258             string = "" + object;
259         else if (injectedScript.isPrimitiveValue(object))
260             string = "" + object;
261         else if (typeof object === "symbol")
262             string = String(object);
263         else if (typeof object === "function")
264             string = "" + object;
265         else {
266             try {
267                 string = JSON.stringify(object, null, "  ");
268             } catch (e) {
269                 string = "" + object;
270             }
271         }
272
273         CommandLineAPIHost.copyText(string);
274     },
275
276     clear: function()
277     {
278         CommandLineAPIHost.clearConsoleMessages();
279     },
280
281     getEventListeners: function(target)
282     {
283         return CommandLineAPIHost.getEventListeners(target);
284     },
285
286     _inspectedObject: function()
287     {
288         return CommandLineAPIHost.inspectedObject();
289     },
290
291     /**
292      * @param {Array.<string>|string=} types
293      * @return {Array.<string>}
294      */
295     _normalizeEventTypes: function(types)
296     {
297         if (typeof types === "undefined")
298             types = [ "mouse", "key", "touch", "control", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll", "search", "devicemotion", "deviceorientation" ];
299         else if (typeof types === "string")
300             types = [ types ];
301
302         var result = [];
303         for (var i = 0; i < types.length; i++) {
304             if (types[i] === "mouse")
305                 result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel");
306             else if (types[i] === "key")
307                 result.splice(0, 0, "keydown", "keyup", "keypress", "textInput");
308             else if (types[i] === "touch")
309                 result.splice(0, 0, "touchstart", "touchmove", "touchend", "touchcancel");
310             else if (types[i] === "control")
311                 result.splice(0, 0, "resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset");
312             else
313                 result.push(types[i]);
314         }
315         return result;
316     },
317
318     /**
319      * @param {Event} event
320      */
321     _logEvent: function(event)
322     {
323         inspectedWindow.console.log(event.type, event);
324     },
325
326     /**
327      * @param {*} object
328      * @return {*}
329      */
330     _inspect: function(object)
331     {
332         if (arguments.length === 0)
333             return;
334
335         var objectId = RemoteObject.create(object, "");
336         var hints = {};
337
338         switch (RemoteObject.describe(object)) {
339         case "Database":
340             var databaseId = CommandLineAPIHost.databaseId(object)
341             if (databaseId)
342                 hints.databaseId = databaseId;
343             break;
344         case "Storage":
345             var storageId = CommandLineAPIHost.storageId(object)
346             if (storageId)
347                 hints.domStorageId = InjectedScriptHost.evaluate("(" + storageId + ")");
348             break;
349         }
350
351         CommandLineAPIHost.inspect(objectId, hints);
352         return object;
353     }
354 }
355
356 injectedScript.CommandLineAPI = CommandLineAPI;
357 injectedScript._commandLineAPIImpl = new CommandLineAPIImpl();
358
359 // This Module doesn't expose an object, it just adds an extension that InjectedScript uses.
360 // However, we return an empty object, so that InjectedScript knows this module has been loaded.
361 return {};
362
363 })