Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / inspector.js
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
3  * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
4  * Copyright (C) 2009 Joseph Pecoraro
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 var WebInspector = {
32     _registerModules: function()
33     {
34         var configuration;
35         if (WebInspector.isWorkerFrontend()) {
36             configuration = ["sources", "timeline", "profiles", "console", "codemirror"];
37         } else {
38             configuration = ["elements", "network", "sources", "timeline", "profiles", "resources", "audits", "console", "codemirror", "extensions"];
39             if (WebInspector.experimentsSettings.layersPanel.isEnabled())
40                 configuration.push("layers");
41         }
42         WebInspector.moduleManager.registerModules(configuration);
43     },
44
45     _createGlobalStatusBarItems: function()
46     {
47         if (this.inspectElementModeController)
48             this.inspectorView.appendToLeftToolbar(this.inspectElementModeController.toggleSearchButton.element);
49
50         this.inspectorView.appendToRightToolbar(this.settingsController.statusBarItem);
51         if (this.dockController.element)
52             this.inspectorView.appendToRightToolbar(this.dockController.element);
53
54         if (Capabilities.canScreencast) {
55             var placeholder = document.createElement("div");
56             this._screencastView = new WebInspector.ScreencastView(placeholder);
57             this.inspectorView.appendToRightToolbar(placeholder);
58         }
59     },
60
61     /**
62      * @return {boolean}
63      */
64     isInspectingDevice: function()
65     {
66         return !!WebInspector.queryParamsObject["remoteFrontend"];
67     },
68
69     /**
70      * @return {boolean}
71      */
72     isDedicatedWorkerFrontend: function()
73     {
74         return !!WebInspector.queryParamsObject["dedicatedWorkerId"];
75     },
76
77     _calculateWorkerInspectorTitle: function()
78     {
79         var expression = "location.href";
80         if (WebInspector.queryParamsObject["isSharedWorker"])
81             expression += " + (this.name ? ' (' + this.name + ')' : '')";
82         RuntimeAgent.evaluate.invoke({expression:expression, doNotPauseOnExceptionsAndMuteConsole:true, returnByValue: true}, evalCallback.bind(this));
83
84         /**
85          * @param {?Protocol.Error} error
86          * @param {!RuntimeAgent.RemoteObject} result
87          * @param {boolean=} wasThrown
88          */
89         function evalCallback(error, result, wasThrown)
90         {
91             if (error || wasThrown) {
92                 console.error(error);
93                 return;
94             }
95             InspectorFrontendHost.inspectedURLChanged(result.value);
96         }
97     },
98
99     _initializeDedicatedWorkerFrontend: function(workerId)
100     {
101         function receiveMessage(event)
102         {
103             var message = event.data;
104             InspectorBackend.dispatch(message);
105         }
106         window.addEventListener("message", receiveMessage, true);
107
108
109         InspectorBackend.sendMessageObjectToBackend = function(message)
110         {
111             window.opener.postMessage({workerId: workerId, command: "sendMessageToBackend", message: message}, "*");
112         }
113     },
114
115     _loadCompletedForWorkers: function()
116     {
117         // Make sure script execution of dedicated worker is resumed and then paused
118         // on the first script statement in case we autoattached to it.
119         if (WebInspector.queryParamsObject["workerPaused"]) {
120             DebuggerAgent.pause();
121             RuntimeAgent.run(calculateTitle);
122         } else if (WebInspector.isWorkerFrontend())
123             calculateTitle();
124
125         function calculateTitle()
126         {
127             WebInspector._calculateWorkerInspectorTitle();
128         }
129     },
130
131     /**
132      * @return {boolean}
133      */
134     isWorkerFrontend: function()
135     {
136         return !!WebInspector.queryParamsObject["dedicatedWorkerId"] ||
137                 !!WebInspector.queryParamsObject["isSharedWorker"];
138     },
139
140     showConsole: function()
141     {
142         if (this.consoleView.isShowing())
143             return;
144         this.inspectorView.showViewInDrawer("console");
145     },
146
147     _resetErrorAndWarningCounts: function()
148     {
149         WebInspector.inspectorView.setErrorAndWarningCounts(0, 0);
150     },
151
152     _updateErrorAndWarningCounts: function()
153     {
154         var errors = WebInspector.console.errors;
155         var warnings = WebInspector.console.warnings;
156         WebInspector.inspectorView.setErrorAndWarningCounts(errors, warnings);
157     },
158
159     get inspectedPageDomain()
160     {
161         var parsedURL = WebInspector.inspectedPageURL && WebInspector.inspectedPageURL.asParsedURL();
162         return parsedURL ? parsedURL.host : "";
163     },
164
165     _initializeCapability: function(name, callback, error, result)
166     {
167         Capabilities[name] = result;
168         if (callback)
169             callback();
170     },
171
172     _debuggerPaused: function()
173     {
174         this.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
175         WebInspector.showPanel("sources");
176     }
177 }
178
179 WebInspector.Events = {
180     InspectorLoaded: "InspectorLoaded"
181 }
182
183 {(function parseQueryParameters()
184 {
185     WebInspector.queryParamsObject = {};
186     var queryParams = window.location.search;
187     if (!queryParams)
188         return;
189     var params = queryParams.substring(1).split("&");
190     for (var i = 0; i < params.length; ++i) {
191         var pair = params[i].split("=");
192         WebInspector.queryParamsObject[pair[0]] = pair[1];
193     }
194
195     // Patch settings from the URL param (for tests).
196     var settingsParam = WebInspector.queryParamsObject["settings"];
197     if (settingsParam) {
198         try {
199             var settings = JSON.parse(window.decodeURI(settingsParam));
200             for (var key in settings)
201                 localStorage[key] = settings[key];
202         } catch(e) {
203             // Ignore malformed settings.
204         }
205     }
206 })();}
207
208 WebInspector.suggestReload = function()
209 {
210     if (window.confirm(WebInspector.UIString("It is recommended to restart inspector after making these changes. Would you like to restart it?")))
211         this.reload();
212 }
213
214 WebInspector.reload = function()
215 {
216     InspectorAgent.reset();
217     window.location.reload();
218 }
219
220 WebInspector.loaded = function()
221 {
222     if (!InspectorFrontendHost.sendMessageToEmbedder) {
223         var helpScreen = new WebInspector.HelpScreen(WebInspector.UIString("Incompatible Chrome version"));
224         var p = helpScreen.contentElement.createChild("p", "help-section");
225         p.textContent = WebInspector.UIString("Please upgrade to a newer Chrome version (you might need a Dev or Canary build).");
226         helpScreen.showModal();
227         return;
228     }
229
230     InspectorBackend.loadFromJSONIfNeeded("../protocol.json");
231     WebInspector.dockController = new WebInspector.DockController();
232
233     if (WebInspector.isDedicatedWorkerFrontend()) {
234         // Do not create socket for the worker front-end.
235         WebInspector.doLoadedDone();
236         return;
237     }
238
239     var ws;
240     if ("ws" in WebInspector.queryParamsObject)
241         ws = "ws://" + WebInspector.queryParamsObject.ws;
242     else if ("page" in WebInspector.queryParamsObject) {
243         var page = WebInspector.queryParamsObject.page;
244         var host = "host" in WebInspector.queryParamsObject ? WebInspector.queryParamsObject.host : window.location.host;
245         ws = "ws://" + host + "/devtools/page/" + page;
246     }
247
248     if (ws) {
249         WebInspector.socket = new WebSocket(ws);
250         WebInspector.socket.onmessage = function(message) { InspectorBackend.dispatch(message.data); }
251         WebInspector.socket.onerror = function(error) { console.error(error); }
252         WebInspector.socket.onopen = function() {
253             InspectorFrontendHost.sendMessageToBackend = WebInspector.socket.send.bind(WebInspector.socket);
254             WebInspector.doLoadedDone();
255         }
256         WebInspector.socket.onclose = function() {
257             if (!WebInspector.socket._detachReason)
258                 (new WebInspector.RemoteDebuggingTerminatedScreen("websocket_closed")).showModal();
259         }
260         return;
261     }
262
263     WebInspector.doLoadedDone();
264
265     // In case of loading as a web page with no bindings / harness, kick off initialization manually.
266     if (InspectorFrontendHost.isStub) {
267         InspectorFrontendAPI.dispatchQueryParameters(WebInspector.queryParamsObject);
268         WebInspector._doLoadedDoneWithCapabilities();
269     }
270 }
271
272 WebInspector.doLoadedDone = function()
273 {
274     // Install styles and themes
275     WebInspector.installPortStyles();
276     if (WebInspector.socket)
277         document.body.classList.add("remote");
278
279     if (WebInspector.queryParamsObject.toolbarColor && WebInspector.queryParamsObject.textColor)
280         WebInspector.setToolbarColors(WebInspector.queryParamsObject.toolbarColor, WebInspector.queryParamsObject.textColor);
281
282     var workerId = WebInspector.queryParamsObject["dedicatedWorkerId"];
283     if (workerId)
284         this._initializeDedicatedWorkerFrontend(workerId);
285
286     PageAgent.canScreencast(WebInspector._initializeCapability.bind(WebInspector, "canScreencast", null));
287     WorkerAgent.canInspectWorkers(WebInspector._initializeCapability.bind(WebInspector, "canInspectWorkers", WebInspector._doLoadedDoneWithCapabilities.bind(WebInspector)));
288 }
289
290 WebInspector._doLoadedDoneWithCapabilities = function()
291 {
292     new WebInspector.VersionController().updateVersion();
293
294     WebInspector.shortcutsScreen = new WebInspector.ShortcutsScreen();
295     this._registerShortcuts();
296
297     // set order of some sections explicitly
298     WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
299     WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel"));
300     WebInspector.ShortcutsScreen.registerShortcuts();
301
302     this.console = new WebInspector.ConsoleModel();
303     this.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._resetErrorAndWarningCounts, this);
304     this.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this);
305     this.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._updateErrorAndWarningCounts, this);
306     this.networkManager = new WebInspector.NetworkManager();
307     this.resourceTreeModel = new WebInspector.ResourceTreeModel(this.networkManager);
308     this.debuggerModel = new WebInspector.DebuggerModel();
309     this.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
310     this.networkLog = new WebInspector.NetworkLog();
311     this.domAgent = new WebInspector.DOMAgent();
312     this.domAgent.addEventListener(WebInspector.DOMAgent.Events.InspectNodeRequested, this._inspectNodeRequested, this);
313     this.workerManager = new WebInspector.WorkerManager(Capabilities.canInspectWorkers);
314     this.runtimeModel = new WebInspector.RuntimeModel(this.resourceTreeModel);
315
316     this.zoomManager = new WebInspector.ZoomManager();
317
318     this.advancedSearchController = new WebInspector.AdvancedSearchController();
319     this.consoleView = new WebInspector.ConsoleView(WebInspector.isWorkerFrontend());
320
321     InspectorBackend.registerInspectorDispatcher(this);
322
323     this.isolatedFileSystemManager = new WebInspector.IsolatedFileSystemManager();
324     this.isolatedFileSystemDispatcher = new WebInspector.IsolatedFileSystemDispatcher(this.isolatedFileSystemManager);
325     this.workspace = new WebInspector.Workspace(this.isolatedFileSystemManager.mapping());
326
327     this.cssModel = new WebInspector.CSSStyleModel(this.workspace);
328     this.timelineManager = new WebInspector.TimelineManager();
329     this.tracingAgent = new WebInspector.TracingAgent();
330
331     if (!WebInspector.isWorkerFrontend()) {
332         this.inspectElementModeController = new WebInspector.InspectElementModeController();
333         this.workerFrontendManager = new WebInspector.WorkerFrontendManager();
334     }
335
336     this.settingsController = new WebInspector.SettingsController();
337
338     this.domBreakpointsSidebarPane = new WebInspector.DOMBreakpointsSidebarPane();
339
340     var autoselectPanel = WebInspector.UIString("a panel chosen automatically");
341     var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel);
342     this.openAnchorLocationRegistry = new WebInspector.HandlerRegistry(openAnchorLocationSetting);
343     this.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; });
344     WebInspector.Linkifier.setLinkHandler(new WebInspector.HandlerRegistry.LinkHandler());
345
346     new WebInspector.WorkspaceController(this.workspace);
347
348     this.fileSystemWorkspaceProvider = new WebInspector.FileSystemWorkspaceProvider(this.isolatedFileSystemManager, this.workspace);
349
350     this.networkWorkspaceProvider = new WebInspector.SimpleWorkspaceProvider(this.workspace, WebInspector.projectTypes.Network);
351     new WebInspector.NetworkUISourceCodeProvider(this.networkWorkspaceProvider, this.workspace);
352
353     this.breakpointManager = new WebInspector.BreakpointManager(WebInspector.settings.breakpoints, this.debuggerModel, this.workspace);
354
355     this.scriptSnippetModel = new WebInspector.ScriptSnippetModel(this.workspace);
356
357     this.overridesSupport = new WebInspector.OverridesSupport();
358     this.overridesSupport.applyInitialOverrides();
359
360     new WebInspector.DebuggerScriptMapping(this.debuggerModel, this.workspace, this.networkWorkspaceProvider);
361     this.liveEditSupport = new WebInspector.LiveEditSupport(this.workspace);
362     new WebInspector.CSSStyleSheetMapping(this.cssModel, this.workspace, this.networkWorkspaceProvider);
363     new WebInspector.PresentationConsoleMessageHelper(this.workspace);
364
365     // Create settings before loading modules.
366     WebInspector.settings.initializeBackendSettings();
367
368     this._registerModules();
369
370     this.panels = {};
371     WebInspector.inspectorView = new WebInspector.InspectorView();
372     WebInspector.inspectorView.show(document.body);
373     this._createGlobalStatusBarItems();
374
375     this.addMainEventListeners(document);
376
377     window.addEventListener("resize", this.windowResize.bind(this), true);
378
379     var errorWarningCount = document.getElementById("error-warning-count");
380     errorWarningCount.addEventListener("click", this.showConsole.bind(this), false);
381     this._updateErrorAndWarningCounts();
382
383     WebInspector.extensionServerProxy.setFrontendReady();
384
385     this.console.enableAgent();
386
387     this.databaseModel = new WebInspector.DatabaseModel();
388     this.domStorageModel = new WebInspector.DOMStorageModel();
389     this.cpuProfilerModel = new WebInspector.CPUProfilerModel();
390
391     InspectorAgent.enable(inspectorAgentEnableCallback.bind(this));
392     /**
393      * @this {WebInspector}
394      */
395     function inspectorAgentEnableCallback()
396     {
397         WebInspector.inspectorView.showInitialPanel();
398
399         if (WebInspector.overridesSupport.hasActiveOverrides()) {
400             if (!WebInspector.settings.showEmulationViewInDrawer.get())
401                 WebInspector.settings.showEmulationViewInDrawer.set(true);
402             WebInspector.inspectorView.showViewInDrawer("emulation", true);
403         }
404
405         if (WebInspector.settings.showPaintRects.get() || WebInspector.settings.showDebugBorders.get() || WebInspector.settings.continuousPainting.get() ||
406                 WebInspector.settings.showFPSCounter.get() || WebInspector.settings.showScrollBottleneckRects.get()) {
407             WebInspector.settings.showRenderingViewInDrawer.set(true);
408         }
409
410         WebInspector.settings.showMetricsRulers.addChangeListener(showRulersChanged);
411         function showRulersChanged()
412         {
413             PageAgent.setShowViewportSizeOnResize(true, WebInspector.settings.showMetricsRulers.get());
414         }
415         showRulersChanged();
416
417         if (Capabilities.canScreencast)
418             this._screencastView.initialize();
419     }
420
421     this._loadCompletedForWorkers()
422     InspectorFrontendAPI.loadCompleted();
423     WebInspector.notifications.dispatchEventToListeners(WebInspector.Events.InspectorLoaded);
424 }
425
426 var windowLoaded = function()
427 {
428     WebInspector.loaded();
429     window.removeEventListener("DOMContentLoaded", windowLoaded, false);
430     delete windowLoaded;
431 };
432
433 window.addEventListener("DOMContentLoaded", windowLoaded, false);
434
435 // We'd like to enforce asynchronous interaction between the inspector controller and the frontend.
436 // It is needed to prevent re-entering the backend code.
437 // Also, native dispatches do not guarantee setTimeouts to be serialized, so we
438 // enforce serialization using 'messagesToDispatch' queue. It is also important that JSC debugger
439 // tests require that each command was dispatch within individual timeout callback, so we don't batch them.
440
441 var messagesToDispatch = [];
442
443 WebInspector.dispatchQueueIsEmpty = function() {
444     return messagesToDispatch.length == 0;
445 }
446
447 WebInspector.dispatch = function(message) {
448     messagesToDispatch.push(message);
449     setTimeout(function() {
450         InspectorBackend.dispatch(messagesToDispatch.shift());
451     }, 0);
452 }
453
454 WebInspector.windowResize = function(event)
455 {
456     if (WebInspector.settingsController)
457         WebInspector.settingsController.resize();
458 }
459
460 WebInspector.close = function(event)
461 {
462     InspectorFrontendHost.closeWindow();
463 }
464
465 WebInspector.documentClick = function(event)
466 {
467     var anchor = event.target.enclosingNodeOrSelfWithNodeName("a");
468     if (!anchor || !anchor.href || (anchor.target === "_blank"))
469         return;
470
471     // Prevent the link from navigating, since we don't do any navigation by following links normally.
472     event.consume(true);
473
474     function followLink()
475     {
476         if (WebInspector.isBeingEdited(event.target))
477             return;
478         if (WebInspector.openAnchorLocationRegistry.dispatch({ url: anchor.href, lineNumber: anchor.lineNumber}))
479             return;
480
481         var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(anchor.href);
482         if (uiSourceCode) {
483             WebInspector.Revealer.reveal(new WebInspector.UILocation(uiSourceCode, anchor.lineNumber || 0, anchor.columnNumber || 0));
484             return;
485         }
486
487         var resource = WebInspector.resourceForURL(anchor.href);
488         if (resource) {
489             WebInspector.Revealer.reveal(resource);
490             return;
491         }
492
493         var request = WebInspector.networkLog.requestForURL(anchor.href);
494         if (request) {
495             WebInspector.Revealer.reveal(request);
496             return;
497         }
498         InspectorFrontendHost.openInNewTab(anchor.href);
499     }
500
501     if (WebInspector.followLinkTimeout)
502         clearTimeout(WebInspector.followLinkTimeout);
503
504     if (anchor.preventFollowOnDoubleClick) {
505         // Start a timeout if this is the first click, if the timeout is canceled
506         // before it fires, then a double clicked happened or another link was clicked.
507         if (event.detail === 1)
508             WebInspector.followLinkTimeout = setTimeout(followLink, 333);
509         return;
510     }
511
512     followLink();
513 }
514
515 WebInspector.openResource = function(resourceURL, inResourcesPanel)
516 {
517     var resource = WebInspector.resourceForURL(resourceURL);
518     if (inResourcesPanel && resource)
519         WebInspector.showPanel("resources").showResource(resource);
520     else
521         InspectorFrontendHost.openInNewTab(resourceURL);
522 }
523
524 WebInspector._registerShortcuts = function()
525 {
526     var shortcut = WebInspector.KeyboardShortcut;
527     var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("All Panels"));
528     var keys = [
529         shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta),
530         shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta)
531     ];
532     section.addRelatedKeys(keys, WebInspector.UIString("Go to the panel to the left/right"));
533
534     keys = [
535         shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt),
536         shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt)
537     ];
538     section.addRelatedKeys(keys, WebInspector.UIString("Go back/forward in panel history"));
539
540     var toggleConsoleLabel = WebInspector.UIString("Show console");
541     section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
542     var doNotOpenDrawerOnEsc = WebInspector.experimentsSettings.doNotOpenDrawerOnEsc.isEnabled();
543     var toggleDrawerLabel = doNotOpenDrawerOnEsc ? WebInspector.UIString("Hide drawer") : WebInspector.UIString("Toggle drawer");
544     section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), toggleDrawerLabel);
545     section.addKey(shortcut.makeDescriptor("f", shortcut.Modifiers.CtrlOrMeta), WebInspector.UIString("Search"));
546
547     var advancedSearchShortcut = WebInspector.AdvancedSearchController.createShortcut();
548     section.addKey(advancedSearchShortcut, WebInspector.UIString("Search across all sources"));
549
550     var inspectElementModeShortcut = WebInspector.InspectElementModeController.createShortcut();
551     section.addKey(inspectElementModeShortcut, WebInspector.UIString("Select node to inspect"));
552
553     var openResourceShortcut = WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta);
554     section.addKey(openResourceShortcut, WebInspector.UIString("Go to source"));
555
556     if (WebInspector.isMac()) {
557         keys = [
558             shortcut.makeDescriptor("g", shortcut.Modifiers.Meta),
559             shortcut.makeDescriptor("g", shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
560         ];
561         section.addRelatedKeys(keys, WebInspector.UIString("Find next/previous"));
562     }
563
564     var goToShortcut = WebInspector.GoToLineDialog.createShortcut();
565     section.addKey(goToShortcut, WebInspector.UIString("Go to line"));
566
567     keys = [
568         shortcut.Keys.F1,
569         shortcut.makeDescriptor("?")
570     ];
571     section.addAlternateKeys(keys, WebInspector.UIString("Show general settings"));
572 }
573
574 WebInspector.handleZoomEvent = function(event)
575 {
576     switch (event.keyCode) {
577     case 107: // +
578     case 187: // +
579         InspectorFrontendHost.zoomIn();
580         return true;
581     case 109: // -
582     case 189: // -
583         InspectorFrontendHost.zoomOut();
584         return true;
585     case 48: // 0
586     case 96: // Numpad 0
587         // Zoom reset shortcut does not allow "Shift" when handled by the browser.
588         if (!event.shiftKey) {
589             InspectorFrontendHost.resetZoom();
590             return true;
591         }
592         break;
593     }
594     return false;
595 };
596
597 WebInspector.postDocumentKeyDown = function(event)
598 {
599     if (event.handled)
600         return;
601
602     if (WebInspector.inspectorView.currentPanel()) {
603         WebInspector.inspectorView.currentPanel().handleShortcut(event);
604         if (event.handled) {
605             event.consume(true);
606             return;
607         }
608     }
609
610     if (WebInspector.advancedSearchController.handleShortcut(event))
611         return;
612     if (WebInspector.inspectElementModeController && WebInspector.inspectElementModeController.handleShortcut(event))
613         return;
614
615     switch (event.keyIdentifier) {
616         case "U+004F": // O key
617         case "U+0050": // P key
618             if (!event.shiftKey && !event.altKey && WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) {
619                 WebInspector.showPanel("sources").showGoToSourceDialog();
620                 event.consume(true);
621             }
622             break;
623         case "U+0052": // R key
624             if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) {
625                 WebInspector.debuggerModel.skipAllPauses(true, true);
626                 WebInspector.resourceTreeModel.reloadPage(event.shiftKey);
627                 event.consume(true);
628             }
629             if (window.DEBUG && event.altKey) {
630                 WebInspector.reload();
631                 return;
632             }
633             break;
634         case "F5":
635             if (!WebInspector.isMac()) {
636                 WebInspector.resourceTreeModel.reloadPage(event.ctrlKey || event.shiftKey);
637                 event.consume(true);
638             }
639             break;
640     }
641
642     var isValidZoomShortcut = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) &&
643         !event.altKey &&
644         !InspectorFrontendHost.isStub;
645     if (isValidZoomShortcut && WebInspector.handleZoomEvent(event)) {
646         event.consume(true);
647         return;
648     }
649
650     if (event.keyCode === WebInspector.KeyboardShortcut.Keys.F1.code ||
651         (event.keyCode === WebInspector.KeyboardShortcut.Keys.QuestionMark.code && event.shiftKey && (!WebInspector.isBeingEdited(event.target) || event.metaKey))) {
652         this.settingsController.showSettingsScreen(WebInspector.SettingsScreen.Tabs.General);
653         event.consume(true);
654         return;
655     }
656
657     var Esc = "U+001B";
658     var doNotOpenDrawerOnEsc = WebInspector.experimentsSettings.doNotOpenDrawerOnEsc.isEnabled();
659     if (event.keyIdentifier === Esc) {
660         if (this.inspectorView.drawerVisible())
661             this.inspectorView.closeDrawer();
662         else if (!doNotOpenDrawerOnEsc)
663             this.inspectorView.showDrawer();
664     }
665
666     if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tilde.code && event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
667         this.showConsole();
668 }
669
670 WebInspector.documentCanCopy = function(event)
671 {
672     if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent)
673         event.preventDefault();
674 }
675
676 WebInspector.documentCopy = function(event)
677 {
678     if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent)
679         WebInspector.inspectorView.currentPanel().handleCopyEvent(event);
680 }
681
682 WebInspector.contextMenuEventFired = function(event)
683 {
684     if (event.handled || event.target.classList.contains("popup-glasspane"))
685         event.preventDefault();
686 }
687
688 /**
689  * @param {string} panel
690  */
691 WebInspector.showPanel = function(panel)
692 {
693     return WebInspector.inspectorView.showPanel(panel);
694 }
695
696 /**
697  * @param {string} panel
698  */
699 WebInspector.panel = function(panel)
700 {
701     return WebInspector.inspectorView.panel(panel);
702 }
703
704 WebInspector.bringToFront = function()
705 {
706     InspectorFrontendHost.bringToFront();
707 }
708
709 /**
710  * @param {string=} messageLevel
711  * @param {boolean=} showConsole
712  */
713 WebInspector.log = function(message, messageLevel, showConsole)
714 {
715     // remember 'this' for setInterval() callback
716     var self = this;
717
718     // return indication if we can actually log a message
719     function isLogAvailable()
720     {
721         return WebInspector.ConsoleMessage && WebInspector.RemoteObject && self.console;
722     }
723
724     // flush the queue of pending messages
725     function flushQueue()
726     {
727         var queued = WebInspector.log.queued;
728         if (!queued)
729             return;
730
731         for (var i = 0; i < queued.length; ++i)
732             logMessage(queued[i]);
733
734         delete WebInspector.log.queued;
735     }
736
737     // flush the queue if it console is available
738     // - this function is run on an interval
739     function flushQueueIfAvailable()
740     {
741         if (!isLogAvailable())
742             return;
743
744         clearInterval(WebInspector.log.interval);
745         delete WebInspector.log.interval;
746
747         flushQueue();
748     }
749
750     // actually log the message
751     function logMessage(message)
752     {
753         // post the message
754         var msg = WebInspector.ConsoleMessage.create(
755             WebInspector.ConsoleMessage.MessageSource.Other,
756             messageLevel || WebInspector.ConsoleMessage.MessageLevel.Debug,
757             message);
758
759         self.console.addMessage(msg);
760         if (showConsole)
761             WebInspector.showConsole();
762     }
763
764     // if we can't log the message, queue it
765     if (!isLogAvailable()) {
766         if (!WebInspector.log.queued)
767             WebInspector.log.queued = [];
768
769         WebInspector.log.queued.push(message);
770
771         if (!WebInspector.log.interval)
772             WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000);
773
774         return;
775     }
776
777     // flush the pending queue if any
778     flushQueue();
779
780     // log the message
781     logMessage(message);
782 }
783
784 WebInspector.showErrorMessage = function(error)
785 {
786     WebInspector.log(error, WebInspector.ConsoleMessage.MessageLevel.Error, true);
787 }
788
789 // Inspector.inspect protocol event
790 WebInspector.inspect = function(payload, hints)
791 {
792     var object = WebInspector.RemoteObject.fromPayload(payload);
793     if (object.subtype === "node") {
794         function callback(nodeId)
795         {
796             WebInspector._updateFocusedNode(nodeId);
797             InspectorFrontendHost.inspectElementCompleted();
798             object.release();
799         }
800         object.pushNodeToFrontend(callback);
801         WebInspector.showPanel("elements");
802         return;
803     }
804
805     if (object.type === "function") {
806         /**
807          * @param {?Protocol.Error} error
808          * @param {!DebuggerAgent.FunctionDetails} response
809          */
810         function didGetDetails(error, response)
811         {
812             object.release();
813
814             if (error) {
815                 console.error(error);
816                 return;
817             }
818
819             var uiLocation = WebInspector.debuggerModel.rawLocationToUILocation(response.location);
820             if (!uiLocation)
821                 return;
822
823             WebInspector.panel("sources").showUILocation(uiLocation, true);
824         }
825         DebuggerAgent.getFunctionDetails(object.objectId, didGetDetails.bind(this));
826         return;
827     }
828
829     if (hints.copyToClipboard)
830         InspectorFrontendHost.copyText(object.value);
831     object.release();
832 }
833
834 // Inspector.detached protocol event
835 WebInspector.detached = function(reason)
836 {
837     WebInspector.socket._detachReason = reason;
838     (new WebInspector.RemoteDebuggingTerminatedScreen(reason)).showModal();
839 }
840
841 WebInspector.targetCrashed = function()
842 {
843     (new WebInspector.HelpScreenUntilReload(
844         WebInspector.UIString("Inspected target crashed"),
845         WebInspector.UIString("Inspected target has crashed. Once it reloads we will attach to it automatically."))).showModal();
846 }
847
848 WebInspector._inspectNodeRequested = function(event)
849 {
850     WebInspector._updateFocusedNode(event.data);
851 }
852
853 WebInspector._updateFocusedNode = function(nodeId)
854 {
855     if (WebInspector.inspectElementModeController && WebInspector.inspectElementModeController.enabled()) {
856         InspectorFrontendHost.bringToFront();
857         WebInspector.inspectElementModeController.disable();
858     }
859     WebInspector.showPanel("elements").revealAndSelectNode(nodeId);
860 }
861
862 WebInspector.evaluateInConsole = function(expression, showResultOnly)
863 {
864     this.showConsole();
865     this.consoleView.evaluateUsingTextPrompt(expression, showResultOnly);
866 }
867
868 WebInspector.addMainEventListeners = function(doc)
869 {
870     doc.addEventListener("keydown", this.postDocumentKeyDown.bind(this), false);
871     doc.addEventListener("beforecopy", this.documentCanCopy.bind(this), true);
872     doc.addEventListener("copy", this.documentCopy.bind(this), false);
873     doc.addEventListener("contextmenu", this.contextMenuEventFired.bind(this), true);
874     doc.addEventListener("click", this.documentClick.bind(this), false);
875 }
876
877 window.DEBUG = true;