Home | History | Annotate | Download | only in main
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2007 Matt Lilek (pewtermoose (at) 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 /**
     32  * @constructor
     33  * @implements {InspectorAgent.Dispatcher}
     34  * @implements {WebInspector.Console.UIDelegate}
     35  */
     36 WebInspector.Main = function()
     37 {
     38     var boundListener = windowLoaded.bind(this);
     39     WebInspector.console.setUIDelegate(this);
     40 
     41     /**
     42      * @this {WebInspector.Main}
     43      */
     44     function windowLoaded()
     45     {
     46         this._loaded();
     47         window.removeEventListener("DOMContentLoaded", boundListener, false);
     48     }
     49     window.addEventListener("DOMContentLoaded", boundListener, false);
     50 }
     51 
     52 WebInspector.Main.prototype = {
     53     showConsole: function()
     54     {
     55         WebInspector.Revealer.reveal(WebInspector.console);
     56     },
     57 
     58     _createGlobalStatusBarItems: function()
     59     {
     60         var extensions = self.runtime.extensions(WebInspector.StatusBarItem.Provider);
     61 
     62         /**
     63          * @param {!Runtime.Extension} left
     64          * @param {!Runtime.Extension} right
     65          */
     66         function orderComparator(left, right)
     67         {
     68             return left.descriptor()["order"] - right.descriptor()["order"];
     69         }
     70         extensions.sort(orderComparator);
     71         extensions.forEach(function(extension) {
     72             var item;
     73             switch (extension.descriptor()["location"]) {
     74             case "toolbar-left":
     75                 item = createItem(extension);
     76                 if (item)
     77                     WebInspector.inspectorView.appendToLeftToolbar(item);
     78                 break;
     79             case "toolbar-right":
     80                 item = createItem(extension);
     81                 if (item)
     82                     WebInspector.inspectorView.appendToRightToolbar(item);
     83                 break;
     84             }
     85             if (item && extension.descriptor()["actionId"]) {
     86                 item.addEventListener("click", function() {
     87                     WebInspector.actionRegistry.execute(extension.descriptor()["actionId"]);
     88                 });
     89             }
     90         });
     91 
     92         function createItem(extension)
     93         {
     94             var descriptor = extension.descriptor();
     95             if (descriptor.className)
     96                 return extension.instance().item();
     97             return new WebInspector.StatusBarButton(WebInspector.UIString(descriptor["title"]), descriptor["elementClass"]);
     98         }
     99     },
    100 
    101     _calculateWorkerInspectorTitle: function()
    102     {
    103         var expression = "location.href";
    104         if (Runtime.queryParam("isSharedWorker"))
    105             expression += " + (this.name ? ' (' + this.name + ')' : '')";
    106         RuntimeAgent.invoke_evaluate({expression:expression, doNotPauseOnExceptionsAndMuteConsole:true, returnByValue: true}, evalCallback);
    107 
    108         /**
    109          * @param {?Protocol.Error} error
    110          * @param {!RuntimeAgent.RemoteObject} result
    111          * @param {boolean=} wasThrown
    112          */
    113         function evalCallback(error, result, wasThrown)
    114         {
    115             if (error || wasThrown) {
    116                 console.error(error);
    117                 return;
    118             }
    119             InspectorFrontendHost.inspectedURLChanged(String(result.value));
    120         }
    121     },
    122 
    123     _loadCompletedForWorkers: function()
    124     {
    125         // Make sure script execution of dedicated worker or service worker is
    126         // resumed and then paused on the first script statement in case we
    127         // autoattached to it.
    128         if (Runtime.queryParam("workerPaused")) {
    129             pauseAndResume.call(this);
    130         } else{
    131             RuntimeAgent.isRunRequired(isRunRequiredCallback.bind(this));
    132         }
    133 
    134         /**
    135          * @this {WebInspector.Main}
    136          */
    137         function isRunRequiredCallback(error, result)
    138         {
    139             if (result) {
    140                 pauseAndResume.call(this);
    141             } else if (WebInspector.isWorkerFrontend()) {
    142                 calculateTitle.call(this);
    143             }
    144         }
    145 
    146         /**
    147          * @this {WebInspector.Main}
    148          */
    149         function pauseAndResume()
    150         {
    151             DebuggerAgent.pause();
    152             RuntimeAgent.run(calculateTitle.bind(this));
    153         }
    154 
    155         /**
    156          * @this {WebInspector.Main}
    157          */
    158         function calculateTitle()
    159         {
    160             this._calculateWorkerInspectorTitle();
    161         }
    162     },
    163 
    164     _loaded: function()
    165     {
    166         console.timeStamp("Main._loaded");
    167 
    168         this._createSettings();
    169         this._createAppUI();
    170     },
    171 
    172     _createSettings: function()
    173     {
    174         WebInspector.settings = new WebInspector.Settings();
    175         this._initializeExperiments();
    176         // This setting is needed for backwards compatibility with Devtools CodeSchool extension. DO NOT REMOVE
    177         WebInspector.settings.pauseOnExceptionStateString = new WebInspector.PauseOnExceptionStateSetting();
    178         new WebInspector.VersionController().updateVersion();
    179     },
    180 
    181     _initializeExperiments: function()
    182     {
    183         Runtime.experiments.register("applyCustomStylesheet", "Allow custom UI themes");
    184         Runtime.experiments.register("canvasInspection", "Canvas inspection");
    185         Runtime.experiments.register("devicesPanel", "Devices panel");
    186         Runtime.experiments.register("disableAgentsWhenProfile", "Disable other agents and UI when profiler is active", true);
    187         Runtime.experiments.register("dockToLeft", "Dock to left", true);
    188         Runtime.experiments.register("documentation", "JavaScript documentation", true);
    189         Runtime.experiments.register("fileSystemInspection", "FileSystem inspection");
    190         Runtime.experiments.register("gpuTimeline", "GPU data on timeline", true);
    191         Runtime.experiments.register("layersPanel", "Layers panel");
    192         Runtime.experiments.register("promiseTracker", "Enable Promise inspection", true);
    193         Runtime.experiments.register("suggestUsingWorkspace", "Suggest using workspace", true);
    194         Runtime.experiments.register("timelineOnTraceEvents", "Timeline on trace events");
    195         Runtime.experiments.register("timelinePowerProfiler", "Timeline power profiler");
    196         Runtime.experiments.register("timelineJSCPUProfile", "Timeline with JS sampling");
    197         Runtime.experiments.cleanUpStaleExperiments();
    198     },
    199 
    200     _createAppUI: function()
    201     {
    202         console.timeStamp("Main._createApp");
    203 
    204         WebInspector.installPortStyles();
    205         if (Runtime.queryParam("toolbarColor") && Runtime.queryParam("textColor"))
    206             WebInspector.setToolbarColors(Runtime.queryParam("toolbarColor"), Runtime.queryParam("textColor"));
    207         InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.SetToolbarColors, updateToolbarColors);
    208         /**
    209          * @param {!WebInspector.Event} event
    210          */
    211         function updateToolbarColors(event)
    212         {
    213             WebInspector.setToolbarColors(/** @type {string} */ (event.data["backgroundColor"]), /** @type {string} */ (event.data["color"]));
    214         }
    215 
    216         this._addMainEventListeners(document);
    217 
    218         var canDock = !!Runtime.queryParam("can_dock");
    219         WebInspector.zoomManager = new WebInspector.ZoomManager(InspectorFrontendHost);
    220         WebInspector.inspectorView = new WebInspector.InspectorView();
    221         WebInspector.ContextMenu.initialize();
    222         WebInspector.dockController = new WebInspector.DockController(canDock);
    223         WebInspector.overridesSupport = new WebInspector.OverridesSupport(canDock);
    224         WebInspector.multitargetConsoleModel = new WebInspector.MultitargetConsoleModel();
    225 
    226         WebInspector.shortcutsScreen = new WebInspector.ShortcutsScreen();
    227         // set order of some sections explicitly
    228         WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
    229         WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel"));
    230 
    231         WebInspector.isolatedFileSystemManager = new WebInspector.IsolatedFileSystemManager();
    232         WebInspector.workspace = new WebInspector.Workspace(WebInspector.isolatedFileSystemManager.mapping());
    233         WebInspector.networkWorkspaceBinding = new WebInspector.NetworkWorkspaceBinding(WebInspector.workspace);
    234         new WebInspector.NetworkUISourceCodeProvider(WebInspector.networkWorkspaceBinding, WebInspector.workspace);
    235         WebInspector.presentationConsoleMessageHelper = new WebInspector.PresentationConsoleMessageHelper(WebInspector.workspace);
    236         WebInspector.cssWorkspaceBinding = new WebInspector.CSSWorkspaceBinding();
    237         WebInspector.debuggerWorkspaceBinding = new WebInspector.DebuggerWorkspaceBinding(WebInspector.targetManager, WebInspector.workspace, WebInspector.networkWorkspaceBinding);
    238         WebInspector.fileSystemWorkspaceBinding = new WebInspector.FileSystemWorkspaceBinding(WebInspector.isolatedFileSystemManager, WebInspector.workspace);
    239         WebInspector.breakpointManager = new WebInspector.BreakpointManager(WebInspector.settings.breakpoints, WebInspector.workspace, WebInspector.targetManager, WebInspector.debuggerWorkspaceBinding);
    240         WebInspector.scriptSnippetModel = new WebInspector.ScriptSnippetModel(WebInspector.workspace);
    241         new WebInspector.ContentScriptProjectDecorator();
    242         new WebInspector.ExecutionContextSelector();
    243 
    244         var autoselectPanel = WebInspector.UIString("a panel chosen automatically");
    245         var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel);
    246         WebInspector.openAnchorLocationRegistry = new WebInspector.HandlerRegistry(openAnchorLocationSetting);
    247         WebInspector.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; });
    248         WebInspector.Linkifier.setLinkHandler(new WebInspector.HandlerRegistry.LinkHandler());
    249 
    250         new WebInspector.WorkspaceController(WebInspector.workspace);
    251         new WebInspector.RenderingOptions();
    252         new WebInspector.Main.PauseListener();
    253         new WebInspector.Main.InspectedNodeRevealer();
    254         WebInspector.domBreakpointsSidebarPane = new WebInspector.DOMBreakpointsSidebarPane();
    255 
    256         WebInspector.actionRegistry = new WebInspector.ActionRegistry();
    257         WebInspector.shortcutRegistry = new WebInspector.ShortcutRegistry(WebInspector.actionRegistry);
    258         WebInspector.ShortcutsScreen.registerShortcuts();
    259         this._registerForwardedShortcuts();
    260         this._registerMessageSinkListener();
    261 
    262         if (canDock)
    263             WebInspector.app = new WebInspector.AdvancedApp();
    264         else if (Runtime.queryParam("remoteFrontend"))
    265             WebInspector.app = new WebInspector.ScreencastApp();
    266         else
    267             WebInspector.app = new WebInspector.SimpleApp();
    268 
    269         // It is important to kick controller lifetime after apps are instantiated.
    270         WebInspector.dockController.initialize();
    271         console.timeStamp("Main._presentUI");
    272         WebInspector.app.presentUI();
    273 
    274         if (!WebInspector.isWorkerFrontend())
    275             WebInspector.inspectElementModeController = new WebInspector.InspectElementModeController();
    276         this._createGlobalStatusBarItems();
    277 
    278         WebInspector.extensionServerProxy.setFrontendReady();
    279         InspectorFrontendAPI.loadCompleted();
    280 
    281         // Give UI cycles to repaint, then proceed with creating connection.
    282         setTimeout(this._createConnection.bind(this), 0);
    283     },
    284 
    285     _createConnection: function()
    286     {
    287         console.timeStamp("Main._createConnection");
    288         InspectorBackend.loadFromJSONIfNeeded("../protocol.json");
    289 
    290         var workerId = Runtime.queryParam("dedicatedWorkerId");
    291         if (workerId) {
    292             this._connectionEstablished(new WebInspector.ExternalWorkerConnection(workerId));
    293             return;
    294         }
    295 
    296         if (Runtime.queryParam("ws")) {
    297             var ws = "ws://" + Runtime.queryParam("ws");
    298             InspectorBackendClass.WebSocketConnection.Create(ws, this._connectionEstablished.bind(this));
    299             return;
    300         }
    301 
    302         if (!InspectorFrontendHost.isHostedMode()) {
    303             this._connectionEstablished(new InspectorBackendClass.MainConnection());
    304             return;
    305         }
    306 
    307         this._connectionEstablished(new InspectorBackendClass.StubConnection());
    308     },
    309 
    310     /**
    311      * @param {!InspectorBackendClass.Connection} connection
    312      */
    313     _connectionEstablished: function(connection)
    314     {
    315         console.timeStamp("Main._connectionEstablished");
    316         connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, onDisconnected);
    317 
    318         /**
    319          * @param {!WebInspector.Event} event
    320          */
    321         function onDisconnected(event)
    322         {
    323             if (WebInspector._disconnectedScreenWithReasonWasShown)
    324                 return;
    325             new WebInspector.RemoteDebuggingTerminatedScreen(event.data.reason).showModal();
    326         }
    327 
    328         InspectorBackend.setConnection(connection);
    329         WebInspector.targetManager.createTarget(WebInspector.UIString("Main"), connection, this._mainTargetCreated.bind(this));
    330     },
    331 
    332     /**
    333      * @param {?WebInspector.Target} target
    334      */
    335     _mainTargetCreated: function(target)
    336     {
    337         console.timeStamp("Main._mainTargetCreated");
    338 
    339         var mainTarget = /** @type {!WebInspector.Target} */(target);
    340         this._registerShortcuts();
    341 
    342         WebInspector.workerTargetManager = new WebInspector.WorkerTargetManager(mainTarget, WebInspector.targetManager);
    343 
    344         mainTarget.registerInspectorDispatcher(this);
    345 
    346         if (WebInspector.isWorkerFrontend()) {
    347             mainTarget.runtimeAgent().run();
    348             mainTarget.workerManager.addEventListener(WebInspector.WorkerManager.Events.WorkerDisconnected, onWorkerDisconnected);
    349         }
    350 
    351         function onWorkerDisconnected()
    352         {
    353             var screen = new WebInspector.WorkerTerminatedScreen();
    354             var listener = hideScreen.bind(null, screen);
    355             mainTarget.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, listener);
    356 
    357             /**
    358              * @param {!WebInspector.WorkerTerminatedScreen} screen
    359              */
    360             function hideScreen(screen)
    361             {
    362                 mainTarget.debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, listener);
    363                 screen.hide();
    364             }
    365 
    366             screen.showModal();
    367         }
    368 
    369         InspectorAgent.enable(inspectorAgentEnableCallback);
    370 
    371         function inspectorAgentEnableCallback()
    372         {
    373             console.timeStamp("Main.inspectorAgentEnableCallback");
    374             WebInspector.notifications.dispatchEventToListeners(WebInspector.NotificationService.Events.InspectorAgentEnabledForTests);
    375         }
    376 
    377         WebInspector.overridesSupport.applyInitialOverrides();
    378         if (!WebInspector.overridesSupport.responsiveDesignAvailable() && WebInspector.overridesSupport.emulationEnabled())
    379             WebInspector.inspectorView.showViewInDrawer("emulation", true);
    380 
    381         this._loadCompletedForWorkers();
    382     },
    383 
    384     _registerForwardedShortcuts: function()
    385     {
    386         /** @const */ var forwardedActions = ["main.reload", "main.hard-reload"];
    387         var actionKeys = WebInspector.shortcutRegistry.keysForActions(forwardedActions).map(WebInspector.KeyboardShortcut.keyCodeAndModifiersFromKey);
    388 
    389         actionKeys.push({keyCode: WebInspector.KeyboardShortcut.Keys.F8.code});
    390         InspectorFrontendHost.setWhitelistedShortcuts(JSON.stringify(actionKeys));
    391     },
    392 
    393     _registerMessageSinkListener: function()
    394     {
    395         WebInspector.console.addEventListener(WebInspector.Console.Events.MessageAdded, messageAdded);
    396 
    397         /**
    398          * @param {!WebInspector.Event} event
    399          */
    400         function messageAdded(event)
    401         {
    402             var message = /** @type {!WebInspector.Console.Message} */ (event.data);
    403             if (message.show)
    404                 WebInspector.console.show();
    405         }
    406     },
    407 
    408     _documentClick: function(event)
    409     {
    410         var anchor = event.target.enclosingNodeOrSelfWithNodeName("a");
    411         if (!anchor || !anchor.href)
    412             return;
    413 
    414         // Prevent the link from navigating, since we don't do any navigation by following links normally.
    415         event.consume(true);
    416 
    417         if (anchor.target === "_blank") {
    418             InspectorFrontendHost.openInNewTab(anchor.href);
    419             return;
    420         }
    421 
    422         function followLink()
    423         {
    424             if (WebInspector.isBeingEdited(event.target))
    425                 return;
    426             if (WebInspector.openAnchorLocationRegistry.dispatch({ url: anchor.href, lineNumber: anchor.lineNumber}))
    427                 return;
    428 
    429             var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(anchor.href);
    430             if (uiSourceCode) {
    431                 WebInspector.Revealer.reveal(uiSourceCode.uiLocation(anchor.lineNumber || 0, anchor.columnNumber || 0));
    432                 return;
    433             }
    434 
    435             var resource = WebInspector.resourceForURL(anchor.href);
    436             if (resource) {
    437                 WebInspector.Revealer.reveal(resource);
    438                 return;
    439             }
    440 
    441             var request = WebInspector.networkLog.requestForURL(anchor.href);
    442             if (request) {
    443                 WebInspector.Revealer.reveal(request);
    444                 return;
    445             }
    446             InspectorFrontendHost.openInNewTab(anchor.href);
    447         }
    448 
    449         if (WebInspector.followLinkTimeout)
    450             clearTimeout(WebInspector.followLinkTimeout);
    451 
    452         if (anchor.preventFollowOnDoubleClick) {
    453             // Start a timeout if this is the first click, if the timeout is canceled
    454             // before it fires, then a double clicked happened or another link was clicked.
    455             if (event.detail === 1)
    456                 WebInspector.followLinkTimeout = setTimeout(followLink, 333);
    457             return;
    458         }
    459 
    460         followLink();
    461     },
    462 
    463     _registerShortcuts: function()
    464     {
    465         var shortcut = WebInspector.KeyboardShortcut;
    466         var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("All Panels"));
    467         var keys = [
    468             shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta),
    469             shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta)
    470         ];
    471         section.addRelatedKeys(keys, WebInspector.UIString("Go to the panel to the left/right"));
    472 
    473         keys = [
    474             shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt),
    475             shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt)
    476         ];
    477         section.addRelatedKeys(keys, WebInspector.UIString("Go back/forward in panel history"));
    478 
    479         var toggleConsoleLabel = WebInspector.UIString("Show console");
    480         section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tilde, shortcut.Modifiers.Ctrl), toggleConsoleLabel);
    481         section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), WebInspector.UIString("Toggle drawer"));
    482         if (WebInspector.overridesSupport.responsiveDesignAvailable())
    483             section.addKey(shortcut.makeDescriptor("M", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Shift), WebInspector.UIString("Toggle device mode"));
    484         section.addKey(shortcut.makeDescriptor("f", shortcut.Modifiers.CtrlOrMeta), WebInspector.UIString("Search"));
    485 
    486         var advancedSearchShortcutModifier = WebInspector.isMac()
    487                 ? WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Alt
    488                 : WebInspector.KeyboardShortcut.Modifiers.Ctrl | WebInspector.KeyboardShortcut.Modifiers.Shift;
    489         var advancedSearchShortcut = shortcut.makeDescriptor("f", advancedSearchShortcutModifier);
    490         section.addKey(advancedSearchShortcut, WebInspector.UIString("Search across all sources"));
    491 
    492         var inspectElementModeShortcut = WebInspector.InspectElementModeController.createShortcut();
    493         section.addKey(inspectElementModeShortcut, WebInspector.UIString("Select node to inspect"));
    494 
    495         var openResourceShortcut = WebInspector.KeyboardShortcut.makeDescriptor("p", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta);
    496         section.addKey(openResourceShortcut, WebInspector.UIString("Go to source"));
    497 
    498         if (WebInspector.isMac()) {
    499             keys = [
    500                 shortcut.makeDescriptor("g", shortcut.Modifiers.Meta),
    501                 shortcut.makeDescriptor("g", shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
    502             ];
    503             section.addRelatedKeys(keys, WebInspector.UIString("Find next/previous"));
    504         }
    505     },
    506 
    507     _postDocumentKeyDown: function(event)
    508     {
    509         if (event.handled)
    510             return;
    511 
    512         if (!WebInspector.Dialog.currentInstance() && WebInspector.inspectorView.currentPanel()) {
    513             WebInspector.inspectorView.currentPanel().handleShortcut(event);
    514             if (event.handled) {
    515                 event.consume(true);
    516                 return;
    517             }
    518         }
    519 
    520         WebInspector.shortcutRegistry.handleShortcut(event);
    521     },
    522 
    523     _documentCanCopy: function(event)
    524     {
    525         var panel = WebInspector.inspectorView.currentPanel();
    526         if (panel && panel["handleCopyEvent"])
    527             event.preventDefault();
    528     },
    529 
    530     _documentCopy: function(event)
    531     {
    532         var panel = WebInspector.inspectorView.currentPanel();
    533         if (panel && panel["handleCopyEvent"])
    534             panel["handleCopyEvent"](event);
    535     },
    536 
    537     _documentCut: function(event)
    538     {
    539         var panel = WebInspector.inspectorView.currentPanel();
    540         if (panel && panel["handleCutEvent"])
    541             panel["handleCutEvent"](event);
    542     },
    543 
    544     _documentPaste: function(event)
    545     {
    546         var panel = WebInspector.inspectorView.currentPanel();
    547         if (panel && panel["handlePasteEvent"])
    548             panel["handlePasteEvent"](event);
    549     },
    550 
    551     _contextMenuEventFired: function(event)
    552     {
    553         if (event.handled || event.target.classList.contains("popup-glasspane"))
    554             event.preventDefault();
    555     },
    556 
    557     _addMainEventListeners: function(doc)
    558     {
    559         doc.addEventListener("keydown", this._postDocumentKeyDown.bind(this), false);
    560         doc.addEventListener("beforecopy", this._documentCanCopy.bind(this), true);
    561         doc.addEventListener("copy", this._documentCopy.bind(this), false);
    562         doc.addEventListener("cut", this._documentCut.bind(this), false);
    563         doc.addEventListener("paste", this._documentPaste.bind(this), false);
    564         doc.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
    565         doc.addEventListener("click", this._documentClick.bind(this), false);
    566     },
    567 
    568     /**
    569      * @override
    570      * @param {!RuntimeAgent.RemoteObject} payload
    571      * @param {!Object=} hints
    572      */
    573     inspect: function(payload, hints)
    574     {
    575         var object = WebInspector.runtimeModel.createRemoteObject(payload);
    576         if (object.isNode()) {
    577             var nodeObjectInspector = runtime.instance(WebInspector.NodeRemoteObjectInspector, object);
    578             if (nodeObjectInspector)
    579                 nodeObjectInspector.inspectNodeObject(object);
    580             return;
    581         }
    582 
    583         if (object.type === "function") {
    584             object.functionDetails(didGetDetails);
    585             return;
    586         }
    587 
    588         /**
    589          * @param {?WebInspector.DebuggerModel.FunctionDetails} response
    590          */
    591         function didGetDetails(response)
    592         {
    593             object.release();
    594 
    595             if (!response || !response.location)
    596                 return;
    597 
    598             WebInspector.Revealer.reveal(WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(response.location));
    599         }
    600 
    601         if (hints.copyToClipboard)
    602             InspectorFrontendHost.copyText(object.value);
    603         object.release();
    604     },
    605 
    606     /**
    607      * @override
    608      * @param {string} reason
    609      */
    610     detached: function(reason)
    611     {
    612         WebInspector._disconnectedScreenWithReasonWasShown = true;
    613         new WebInspector.RemoteDebuggingTerminatedScreen(reason).showModal();
    614     },
    615 
    616     /**
    617      * @override
    618      */
    619     targetCrashed: function()
    620     {
    621         (new WebInspector.HelpScreenUntilReload(
    622             WebInspector.UIString("Inspected target crashed"),
    623             WebInspector.UIString("Inspected target has crashed. Once it reloads we will attach to it automatically."))).showModal();
    624     },
    625 
    626     /**
    627      * @override
    628      * @param {number} callId
    629      * @param {string} script
    630      */
    631     evaluateForTestInFrontend: function(callId, script)
    632     {
    633         WebInspector.evaluateForTestInFrontend(callId, script);
    634     }
    635 }
    636 
    637 WebInspector.reload = function()
    638 {
    639     InspectorAgent.reset();
    640     window.location.reload();
    641 }
    642 
    643 /**
    644  * @constructor
    645  * @implements {WebInspector.ActionDelegate}
    646  */
    647 WebInspector.Main.ReloadActionDelegate = function()
    648 {
    649 }
    650 
    651 WebInspector.Main.ReloadActionDelegate.prototype = {
    652     /**
    653      * @return {boolean}
    654      */
    655     handleAction: function()
    656     {
    657         return WebInspector.Main._reloadPage(false);
    658     }
    659 }
    660 
    661 /**
    662  * @constructor
    663  * @implements {WebInspector.ActionDelegate}
    664  */
    665 WebInspector.Main.HardReloadActionDelegate = function()
    666 {
    667 }
    668 
    669 WebInspector.Main.HardReloadActionDelegate.prototype = {
    670     /**
    671      * @return {boolean}
    672      */
    673     handleAction: function()
    674     {
    675         return WebInspector.Main._reloadPage(true);
    676     }
    677 }
    678 
    679 /**
    680  * @constructor
    681  * @implements {WebInspector.ActionDelegate}
    682  */
    683 WebInspector.Main.DebugReloadActionDelegate = function()
    684 {
    685 }
    686 
    687 WebInspector.Main.DebugReloadActionDelegate.prototype = {
    688     /**
    689      * @return {boolean}
    690      */
    691     handleAction: function()
    692     {
    693         WebInspector.reload();
    694         return true;
    695     }
    696 }
    697 
    698 /**
    699  * @constructor
    700  * @implements {WebInspector.ActionDelegate}
    701  */
    702 WebInspector.Main.ZoomInActionDelegate = function()
    703 {
    704 }
    705 
    706 WebInspector.Main.ZoomInActionDelegate.prototype = {
    707     /**
    708      * @return {boolean}
    709      */
    710     handleAction: function()
    711     {
    712         if (InspectorFrontendHost.isHostedMode())
    713             return false;
    714 
    715         InspectorFrontendHost.zoomIn();
    716         return true;
    717     }
    718 }
    719 
    720 /**
    721  * @constructor
    722  * @implements {WebInspector.ActionDelegate}
    723  */
    724 WebInspector.Main.ZoomOutActionDelegate = function()
    725 {
    726 }
    727 
    728 WebInspector.Main.ZoomOutActionDelegate.prototype = {
    729     /**
    730      * @return {boolean}
    731      */
    732     handleAction: function()
    733     {
    734         if (InspectorFrontendHost.isHostedMode())
    735             return false;
    736 
    737         InspectorFrontendHost.zoomOut();
    738         return true;
    739     }
    740 }
    741 
    742 /**
    743  * @constructor
    744  * @implements {WebInspector.ActionDelegate}
    745  */
    746 WebInspector.Main.ZoomResetActionDelegate = function()
    747 {
    748 }
    749 
    750 WebInspector.Main.ZoomResetActionDelegate.prototype = {
    751     /**
    752      * @return {boolean}
    753      */
    754     handleAction: function()
    755     {
    756         if (InspectorFrontendHost.isHostedMode())
    757             return false;
    758 
    759         InspectorFrontendHost.resetZoom();
    760         return true;
    761     }
    762 }
    763 
    764 /**
    765  * @constructor
    766  * @extends {WebInspector.UISettingDelegate}
    767  */
    768 WebInspector.Main.ShortcutPanelSwitchSettingDelegate = function()
    769 {
    770     WebInspector.UISettingDelegate.call(this);
    771 }
    772 
    773 WebInspector.Main.ShortcutPanelSwitchSettingDelegate.prototype = {
    774     /**
    775      * @override
    776      * @return {!Element}
    777      */
    778     settingElement: function()
    779     {
    780         var modifier = WebInspector.platform() === "mac" ? "Cmd" : "Ctrl";
    781         return WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Enable %s + 1-9 shortcut to switch panels", modifier), WebInspector.settings.shortcutPanelSwitch);
    782     },
    783 
    784     __proto__: WebInspector.UISettingDelegate.prototype
    785 }
    786 
    787 /**
    788  * @param {boolean} hard
    789  * @return {boolean}
    790  */
    791 WebInspector.Main._reloadPage = function(hard)
    792 {
    793     if (!WebInspector.targetManager.hasTargets())
    794         return false;
    795 
    796     var targets = WebInspector.targetManager.targets();
    797     for (var i = 0; i < targets.length; ++i)
    798         targets[i].debuggerModel.skipAllPauses(true, true);
    799     WebInspector.targetManager.reloadPage(hard);
    800     return true;
    801 }
    802 
    803 /**
    804  * @param {string} ws
    805  */
    806 WebInspector.Main._addWebSocketTarget = function(ws)
    807 {
    808     /**
    809      * @param {!InspectorBackendClass.Connection} connection
    810      */
    811     function callback(connection)
    812     {
    813         WebInspector.targetManager.createTarget(ws, connection);
    814     }
    815     new InspectorBackendClass.WebSocketConnection(ws, callback);
    816 }
    817 
    818 new WebInspector.Main();
    819 
    820 // These methods are added for backwards compatibility with Devtools CodeSchool extension.
    821 // DO NOT REMOVE
    822 
    823 WebInspector.__defineGetter__("inspectedPageURL", function()
    824 {
    825     return WebInspector.targetManager.inspectedPageURL();
    826 });
    827 
    828 /**
    829  * @param {string} name
    830  * @return {?WebInspector.Panel}
    831  */
    832 WebInspector.panel = function(name)
    833 {
    834     return WebInspector.inspectorView.panel(name);
    835 }
    836 
    837 /**
    838  * @constructor
    839  * @implements {WebInspector.StatusBarItem.Provider}
    840  */
    841 WebInspector.Main.WarningErrorCounter = function()
    842 {
    843     this._counter = new WebInspector.StatusBarCounter(["error-icon-small", "warning-icon-small"]);
    844     this._counter.addEventListener("click", showConsole);
    845 
    846     function showConsole()
    847     {
    848         WebInspector.console.show();
    849     }
    850 
    851     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._updateErrorAndWarningCounts, this);
    852     WebInspector.multitargetConsoleModel.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this);
    853 }
    854 
    855 WebInspector.Main.WarningErrorCounter.prototype = {
    856     _updateErrorAndWarningCounts: function()
    857     {
    858         var errors = 0;
    859         var warnings = 0;
    860         var targets = WebInspector.targetManager.targets();
    861         for (var i = 0; i < targets.length; ++i) {
    862             errors = errors + targets[i].consoleModel.errors;
    863             warnings = warnings + targets[i].consoleModel.warnings;
    864         }
    865         this._counter.setCounter("error-icon-small", errors, WebInspector.UIString(errors > 1 ? "%d errors" : "%d error", errors));
    866         this._counter.setCounter("warning-icon-small", warnings, WebInspector.UIString(warnings > 1 ? "%d warnings" : "%d warning", warnings));
    867         WebInspector.inspectorView.toolbarItemResized();
    868     },
    869 
    870     /**
    871      * @return {?WebInspector.StatusBarItem}
    872      */
    873     item: function()
    874     {
    875         return this._counter;
    876     }
    877 }
    878 
    879 /**
    880  * @constructor
    881  */
    882 WebInspector.Main.PauseListener = function()
    883 {
    884     WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
    885 }
    886 
    887 WebInspector.Main.PauseListener.prototype = {
    888     /**
    889      * @param {!WebInspector.Event} event
    890      */
    891     _debuggerPaused: function(event)
    892     {
    893         WebInspector.targetManager.removeModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
    894         var debuggerModel = /** @type {!WebInspector.DebuggerModel} */ (event.target);
    895         WebInspector.context.setFlavor(WebInspector.Target, debuggerModel.target());
    896         WebInspector.inspectorView.showPanel("sources");
    897     }
    898 }
    899 
    900 /**
    901  * @constructor
    902  */
    903 WebInspector.Main.InspectedNodeRevealer = function()
    904 {
    905     WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspector.DOMModel.Events.NodeInspected, this._inspectNode, this);
    906 }
    907 
    908 WebInspector.Main.InspectedNodeRevealer.prototype = {
    909     /**
    910      * @param {!WebInspector.Event} event
    911      */
    912     _inspectNode: function(event)
    913     {
    914         WebInspector.Revealer.reveal(/** @type {!WebInspector.DOMNode} */ (event.data));
    915     }
    916 }
    917