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 31var WebInspector = { 32 _panelDescriptors: function() 33 { 34 this.panels = {}; 35 WebInspector.inspectorView = new WebInspector.InspectorView(); 36 var parentElement = document.getElementById("main"); 37 WebInspector.inspectorView.show(parentElement); 38 WebInspector.inspectorView.addEventListener(WebInspector.InspectorView.Events.PanelSelected, this._panelSelected, this); 39 40 var elements = new WebInspector.ElementsPanelDescriptor(); 41 var resources = new WebInspector.PanelDescriptor("resources", WebInspector.UIString("Resources"), "ResourcesPanel", "ResourcesPanel.js"); 42 var network = new WebInspector.NetworkPanelDescriptor(); 43 var scripts = new WebInspector.ScriptsPanelDescriptor(); 44 var timeline = new WebInspector.TimelinePanelDescriptor(); 45 var profiles = new WebInspector.ProfilesPanelDescriptor(); 46 var audits = new WebInspector.PanelDescriptor("audits", WebInspector.UIString("Audits"), "AuditsPanel", "AuditsPanel.js"); 47 var console = new WebInspector.PanelDescriptor("console", WebInspector.UIString("Console"), "ConsolePanel"); 48 var allDescriptors = [elements, resources, network, scripts, timeline, profiles, audits, console]; 49 var allProfilers = [profiles]; 50 if (WebInspector.experimentsSettings.separateProfilers.isEnabled()) { 51 allProfilers = []; 52 allProfilers.push(new WebInspector.PanelDescriptor("cpu-profiler", WebInspector.UIString("CPU Profiler"), "CPUProfilerPanel", "ProfilesPanel.js")); 53 if (!WebInspector.WorkerManager.isWorkerFrontend()) 54 allProfilers.push(new WebInspector.PanelDescriptor("css-profiler", WebInspector.UIString("CSS Profiler"), "CSSSelectorProfilerPanel", "ProfilesPanel.js")); 55 if (Capabilities.heapProfilerPresent) 56 allProfilers.push(new WebInspector.PanelDescriptor("heap-profiler", WebInspector.UIString("Heap Profiler"), "HeapProfilerPanel", "ProfilesPanel.js")); 57 if (!WebInspector.WorkerManager.isWorkerFrontend() && WebInspector.experimentsSettings.canvasInspection.isEnabled()) 58 allProfilers.push(new WebInspector.PanelDescriptor("canvas-profiler", WebInspector.UIString("Canvas Profiler"), "CanvasProfilerPanel", "ProfilesPanel.js")); 59 Array.prototype.splice.bind(allDescriptors, allDescriptors.indexOf(profiles), 1).apply(null, allProfilers); 60 } 61 62 var panelDescriptors = []; 63 if (WebInspector.WorkerManager.isWorkerFrontend()) { 64 panelDescriptors.push(scripts); 65 panelDescriptors.push(timeline); 66 panelDescriptors = panelDescriptors.concat(allProfilers); 67 panelDescriptors.push(console); 68 return panelDescriptors; 69 } 70 for (var i = 0; i < allDescriptors.length; ++i) 71 panelDescriptors.push(allDescriptors[i]); 72 return panelDescriptors; 73 }, 74 75 _panelSelected: function() 76 { 77 this._toggleConsoleButton.setEnabled(WebInspector.inspectorView.currentPanel().name !== "console"); 78 }, 79 80 _createGlobalStatusBarItems: function() 81 { 82 var bottomStatusBarContainer = document.getElementById("bottom-status-bar-container"); 83 84 // Create main dock button and options. 85 var mainStatusBar = document.getElementById("main-status-bar"); 86 mainStatusBar.insertBefore(this.dockController.element, bottomStatusBarContainer); 87 88 this._toggleConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Show console."), "console-status-bar-item"); 89 this._toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false); 90 mainStatusBar.insertBefore(this._toggleConsoleButton.element, bottomStatusBarContainer); 91 92 if (this.inspectElementModeController) 93 mainStatusBar.insertBefore(this.inspectElementModeController.toggleSearchButton.element, bottomStatusBarContainer); 94 95 mainStatusBar.appendChild(this.settingsController.statusBarItem); 96 }, 97 98 _toggleConsoleButtonClicked: function() 99 { 100 if (!this._toggleConsoleButton.enabled()) 101 return; 102 103 this._toggleConsoleButton.toggled = !this._toggleConsoleButton.toggled; 104 105 var animationType = window.event && window.event.shiftKey ? WebInspector.Drawer.AnimationType.Slow : WebInspector.Drawer.AnimationType.Normal; 106 if (this._toggleConsoleButton.toggled) { 107 this._toggleConsoleButton.title = WebInspector.UIString("Hide console."); 108 this.drawer.show(this.consoleView, animationType); 109 this._consoleWasShown = true; 110 } else { 111 this._toggleConsoleButton.title = WebInspector.UIString("Show console."); 112 this.drawer.hide(animationType); 113 delete this._consoleWasShown; 114 } 115 }, 116 117 /** 118 * @param {Element} statusBarElement 119 * @param {WebInspector.View} view 120 * @param {function()=} onclose 121 */ 122 showViewInDrawer: function(statusBarElement, view, onclose) 123 { 124 this._toggleConsoleButton.title = WebInspector.UIString("Hide console."); 125 this._toggleConsoleButton.toggled = false; 126 this._closePreviousDrawerView(); 127 128 var drawerStatusBarHeader = document.createElement("div"); 129 drawerStatusBarHeader.className = "drawer-header status-bar-item"; 130 drawerStatusBarHeader.appendChild(statusBarElement); 131 drawerStatusBarHeader.onclose = onclose; 132 133 var closeButton = drawerStatusBarHeader.createChild("span"); 134 closeButton.textContent = WebInspector.UIString("\u00D7"); 135 closeButton.addStyleClass("drawer-header-close-button"); 136 closeButton.addEventListener("click", this.closeViewInDrawer.bind(this), false); 137 138 var panelStatusBar = document.getElementById("panel-status-bar"); 139 var drawerViewAnchor = document.getElementById("drawer-view-anchor"); 140 panelStatusBar.insertBefore(drawerStatusBarHeader, drawerViewAnchor); 141 this._drawerStatusBarHeader = drawerStatusBarHeader; 142 this.drawer.show(view, WebInspector.Drawer.AnimationType.Immediately); 143 }, 144 145 closeViewInDrawer: function() 146 { 147 if (this._drawerStatusBarHeader) { 148 this._closePreviousDrawerView(); 149 150 // Once drawer is closed console should be shown if it was shown before current view replaced it in drawer. 151 if (!this._consoleWasShown) 152 this.drawer.hide(WebInspector.Drawer.AnimationType.Immediately); 153 else 154 this._toggleConsoleButtonClicked(); 155 } 156 }, 157 158 _closePreviousDrawerView: function() 159 { 160 if (this._drawerStatusBarHeader) { 161 this._drawerStatusBarHeader.parentElement.removeChild(this._drawerStatusBarHeader); 162 if (this._drawerStatusBarHeader.onclose) 163 this._drawerStatusBarHeader.onclose(); 164 delete this._drawerStatusBarHeader; 165 } 166 }, 167 168 _updateErrorAndWarningCounts: function() 169 { 170 var errorWarningElement = document.getElementById("error-warning-count"); 171 if (!errorWarningElement) 172 return; 173 174 var errors = WebInspector.console.errors; 175 var warnings = WebInspector.console.warnings; 176 if (!errors && !warnings) { 177 errorWarningElement.addStyleClass("hidden"); 178 return; 179 } 180 181 errorWarningElement.removeStyleClass("hidden"); 182 183 errorWarningElement.removeChildren(); 184 185 if (errors) { 186 var errorImageElement = document.createElement("img"); 187 errorImageElement.id = "error-count-img"; 188 errorWarningElement.appendChild(errorImageElement); 189 var errorElement = document.createElement("span"); 190 errorElement.id = "error-count"; 191 errorElement.textContent = errors; 192 errorWarningElement.appendChild(errorElement); 193 } 194 195 if (warnings) { 196 var warningsImageElement = document.createElement("img"); 197 warningsImageElement.id = "warning-count-img"; 198 errorWarningElement.appendChild(warningsImageElement); 199 var warningsElement = document.createElement("span"); 200 warningsElement.id = "warning-count"; 201 warningsElement.textContent = warnings; 202 errorWarningElement.appendChild(warningsElement); 203 } 204 205 if (errors) { 206 if (warnings) { 207 if (errors == 1) { 208 if (warnings == 1) 209 errorWarningElement.title = WebInspector.UIString("%d error, %d warning", errors, warnings); 210 else 211 errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", errors, warnings); 212 } else if (warnings == 1) 213 errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", errors, warnings); 214 else 215 errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", errors, warnings); 216 } else if (errors == 1) 217 errorWarningElement.title = WebInspector.UIString("%d error", errors); 218 else 219 errorWarningElement.title = WebInspector.UIString("%d errors", errors); 220 } else if (warnings == 1) 221 errorWarningElement.title = WebInspector.UIString("%d warning", warnings); 222 else if (warnings) 223 errorWarningElement.title = WebInspector.UIString("%d warnings", warnings); 224 else 225 errorWarningElement.title = null; 226 }, 227 228 get inspectedPageDomain() 229 { 230 var parsedURL = WebInspector.inspectedPageURL && WebInspector.inspectedPageURL.asParsedURL(); 231 return parsedURL ? parsedURL.host : ""; 232 }, 233 234 _initializeCapability: function(name, callback, error, result) 235 { 236 Capabilities[name] = result; 237 if (callback) 238 callback(); 239 }, 240 241 _zoomIn: function() 242 { 243 this._zoomLevel = Math.min(this._zoomLevel + 1, WebInspector.Zoom.Table.length - WebInspector.Zoom.DefaultOffset - 1); 244 this._requestZoom(); 245 }, 246 247 _zoomOut: function() 248 { 249 this._zoomLevel = Math.max(this._zoomLevel - 1, -WebInspector.Zoom.DefaultOffset); 250 this._requestZoom(); 251 }, 252 253 _resetZoom: function() 254 { 255 this._zoomLevel = 0; 256 this._requestZoom(); 257 }, 258 259 _requestZoom: function() 260 { 261 WebInspector.settings.zoomLevel.set(this._zoomLevel); 262 // For backwards compatibility, zoomLevel takes integers (with 0 being default zoom). 263 var index = this._zoomLevel + WebInspector.Zoom.DefaultOffset; 264 index = Math.min(WebInspector.Zoom.Table.length - 1, index); 265 index = Math.max(0, index); 266 InspectorFrontendHost.setZoomFactor(WebInspector.Zoom.Table[index]); 267 }, 268 269 _debuggerPaused: function() 270 { 271 // Create scripts panel upon demand. 272 WebInspector.panel("scripts"); 273 } 274} 275 276WebInspector.Events = { 277 InspectorLoaded: "InspectorLoaded", 278 InspectorClosing: "InspectorClosing" 279} 280 281{(function parseQueryParameters() 282{ 283 WebInspector.queryParamsObject = {}; 284 var queryParams = window.location.search; 285 if (!queryParams) 286 return; 287 var params = queryParams.substring(1).split("&"); 288 for (var i = 0; i < params.length; ++i) { 289 var pair = params[i].split("="); 290 WebInspector.queryParamsObject[pair[0]] = pair[1]; 291 } 292})();} 293 294WebInspector.suggestReload = function() 295{ 296 if (window.confirm(WebInspector.UIString("It is recommended to restart inspector after making these changes. Would you like to restart it?"))) 297 this.reload(); 298} 299 300WebInspector.reload = function() 301{ 302 var queryParams = window.location.search; 303 var url = window.location.href; 304 url = url.substring(0, url.length - queryParams.length); 305 var queryParamsObject = {}; 306 for (var name in WebInspector.queryParamsObject) 307 queryParamsObject[name] = WebInspector.queryParamsObject[name]; 308 if (this.dockController) 309 queryParamsObject["dockSide"] = this.dockController.dockSide(); 310 var names = Object.keys(queryParamsObject); 311 for (var i = 0; i < names.length; ++i) 312 url += (i ? "&" : "?") + names[i] + "=" + queryParamsObject[names[i]]; 313 314 InspectorBackend.disconnect(); 315 document.location = url; 316} 317 318WebInspector.loaded = function() 319{ 320 InspectorBackend.loadFromJSONIfNeeded("../Inspector.json"); 321 WebInspector.dockController = new WebInspector.DockController(); 322 323 if (WebInspector.WorkerManager.isDedicatedWorkerFrontend()) { 324 // Do not create socket for the worker front-end. 325 WebInspector.doLoadedDone(); 326 return; 327 } 328 329 var ws; 330 if ("ws" in WebInspector.queryParamsObject) 331 ws = "ws://" + WebInspector.queryParamsObject.ws; 332 else if ("page" in WebInspector.queryParamsObject) { 333 var page = WebInspector.queryParamsObject.page; 334 var host = "host" in WebInspector.queryParamsObject ? WebInspector.queryParamsObject.host : window.location.host; 335 ws = "ws://" + host + "/devtools/page/" + page; 336 } 337 338 if (ws) { 339 WebInspector.socket = new WebSocket(ws); 340 WebInspector.socket.onmessage = function(message) { InspectorBackend.dispatch(message.data); } 341 WebInspector.socket.onerror = function(error) { console.error(error); } 342 WebInspector.socket.onopen = function() { 343 InspectorFrontendHost.sendMessageToBackend = WebInspector.socket.send.bind(WebInspector.socket); 344 WebInspector.doLoadedDone(); 345 } 346 WebInspector.socket.onclose = function() { 347 if (!WebInspector.socket._detachReason) 348 (new WebInspector.RemoteDebuggingTerminatedScreen("websocket_closed")).showModal(); 349 } 350 return; 351 } 352 353 WebInspector.doLoadedDone(); 354 355 // In case of loading as a web page with no bindings / harness, kick off initialization manually. 356 if (InspectorFrontendHost.isStub) { 357 InspectorFrontendAPI.dispatchQueryParameters(); 358 WebInspector._doLoadedDoneWithCapabilities(); 359 } 360} 361 362WebInspector.doLoadedDone = function() 363{ 364 // Install styles and themes 365 WebInspector.installPortStyles(); 366 if (WebInspector.socket) 367 document.body.addStyleClass("remote"); 368 369 if (WebInspector.queryParamsObject.toolbarColor && WebInspector.queryParamsObject.textColor) 370 WebInspector.setToolbarColors(WebInspector.queryParamsObject.toolbarColor, WebInspector.queryParamsObject.textColor); 371 372 InspectorFrontendHost.loaded(); 373 WebInspector.WorkerManager.loaded(); 374 375 DebuggerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "debuggerCausesRecompilation", null)); 376 DebuggerAgent.supportsSeparateScriptCompilationAndExecution(WebInspector._initializeCapability.bind(WebInspector, "separateScriptCompilationAndExecutionEnabled", null)); 377 ProfilerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "profilerCausesRecompilation", null)); 378 ProfilerAgent.isSampling(WebInspector._initializeCapability.bind(WebInspector, "samplingCPUProfiler", null)); 379 HeapProfilerAgent.hasHeapProfiler(WebInspector._initializeCapability.bind(WebInspector, "heapProfilerPresent", null)); 380 TimelineAgent.supportsFrameInstrumentation(WebInspector._initializeCapability.bind(WebInspector, "timelineSupportsFrameInstrumentation", null)); 381 TimelineAgent.canMonitorMainThread(WebInspector._initializeCapability.bind(WebInspector, "timelineCanMonitorMainThread", null)); 382 PageAgent.canShowDebugBorders(WebInspector._initializeCapability.bind(WebInspector, "canShowDebugBorders", null)); 383 PageAgent.canShowFPSCounter(WebInspector._initializeCapability.bind(WebInspector, "canShowFPSCounter", null)); 384 PageAgent.canContinuouslyPaint(WebInspector._initializeCapability.bind(WebInspector, "canContinuouslyPaint", null)); 385 PageAgent.canOverrideDeviceMetrics(WebInspector._initializeCapability.bind(WebInspector, "canOverrideDeviceMetrics", null)); 386 PageAgent.canOverrideGeolocation(WebInspector._initializeCapability.bind(WebInspector, "canOverrideGeolocation", null)); 387 WorkerAgent.canInspectWorkers(WebInspector._initializeCapability.bind(WebInspector, "canInspectWorkers", null)); 388 PageAgent.canOverrideDeviceOrientation(WebInspector._initializeCapability.bind(WebInspector, "canOverrideDeviceOrientation", WebInspector._doLoadedDoneWithCapabilities.bind(WebInspector))); 389} 390 391WebInspector._doLoadedDoneWithCapabilities = function() 392{ 393 new WebInspector.VersionController().updateVersion(); 394 395 WebInspector.shortcutsScreen = new WebInspector.ShortcutsScreen(); 396 this._registerShortcuts(); 397 398 // set order of some sections explicitly 399 WebInspector.shortcutsScreen.section(WebInspector.UIString("Console")); 400 WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel")); 401 402 var panelDescriptors = this._panelDescriptors(); 403 for (var i = 0; i < panelDescriptors.length; ++i) 404 panelDescriptors[i].registerShortcuts(); 405 406 this.console = new WebInspector.ConsoleModel(); 407 this.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._updateErrorAndWarningCounts, this); 408 this.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this); 409 this.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._updateErrorAndWarningCounts, this); 410 411 WebInspector.CSSMetadata.requestCSSShorthandData(); 412 413 this.drawer = new WebInspector.Drawer(); 414 415 this.networkManager = new WebInspector.NetworkManager(); 416 this.resourceTreeModel = new WebInspector.ResourceTreeModel(this.networkManager); 417 this.debuggerModel = new WebInspector.DebuggerModel(); 418 this.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); 419 this.networkLog = new WebInspector.NetworkLog(); 420 this.domAgent = new WebInspector.DOMAgent(); 421 this.runtimeModel = new WebInspector.RuntimeModel(this.resourceTreeModel); 422 423 this.consoleView = new WebInspector.ConsoleView(WebInspector.WorkerManager.isWorkerFrontend()); 424 425 InspectorBackend.registerInspectorDispatcher(this); 426 427 this.isolatedFileSystemManager = new WebInspector.IsolatedFileSystemManager(); 428 this.isolatedFileSystemDispatcher = new WebInspector.IsolatedFileSystemDispatcher(this.isolatedFileSystemManager); 429 this.fileMapping = new WebInspector.FileMapping(); 430 this.workspace = new WebInspector.Workspace(this.fileMapping, this.isolatedFileSystemManager.mapping()); 431 432 this.cssModel = new WebInspector.CSSStyleModel(this.workspace); 433 this.timelineManager = new WebInspector.TimelineManager(); 434 this.userAgentSupport = new WebInspector.UserAgentSupport(); 435 436 this.searchController = new WebInspector.SearchController(); 437 this.advancedSearchController = new WebInspector.AdvancedSearchController(); 438 if (!WebInspector.WorkerManager.isWorkerFrontend()) 439 this.inspectElementModeController = new WebInspector.InspectElementModeController(); 440 441 this.settingsController = new WebInspector.SettingsController(); 442 443 this.domBreakpointsSidebarPane = new WebInspector.DOMBreakpointsSidebarPane(); 444 445 this._zoomLevel = WebInspector.settings.zoomLevel.get(); 446 if (this._zoomLevel) 447 this._requestZoom(); 448 449 var autoselectPanel = WebInspector.UIString("a panel chosen automatically"); 450 var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel); 451 this.openAnchorLocationRegistry = new WebInspector.HandlerRegistry(openAnchorLocationSetting); 452 this.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; }); 453 454 this.workspaceController = new WebInspector.WorkspaceController(this.workspace); 455 456 this.fileSystemWorkspaceProvider = new WebInspector.FileSystemWorkspaceProvider(this.isolatedFileSystemManager, this.workspace); 457 458 this.networkWorkspaceProvider = new WebInspector.SimpleWorkspaceProvider(this.workspace, WebInspector.projectTypes.Network); 459 new WebInspector.NetworkUISourceCodeProvider(this.networkWorkspaceProvider, this.workspace); 460 461 this.breakpointManager = new WebInspector.BreakpointManager(WebInspector.settings.breakpoints, this.debuggerModel, this.workspace); 462 463 this.scriptSnippetModel = new WebInspector.ScriptSnippetModel(this.workspace); 464 465 new WebInspector.DebuggerScriptMapping(this.workspace, this.networkWorkspaceProvider); 466 this.liveEditSupport = new WebInspector.LiveEditSupport(this.workspace); 467 this.styleContentBinding = new WebInspector.StyleContentBinding(this.cssModel, this.workspace); 468 new WebInspector.StylesSourceMapping(this.cssModel, this.workspace); 469 if (WebInspector.experimentsSettings.sass.isEnabled()) 470 new WebInspector.SASSSourceMapping(this.cssModel, this.workspace, this.networkWorkspaceProvider); 471 472 new WebInspector.PresentationConsoleMessageHelper(this.workspace); 473 474 this._createGlobalStatusBarItems(); 475 476 this.toolbar = new WebInspector.Toolbar(); 477 WebInspector.startBatchUpdate(); 478 for (var i = 0; i < panelDescriptors.length; ++i) 479 WebInspector.inspectorView.addPanel(panelDescriptors[i]); 480 WebInspector.endBatchUpdate(); 481 482 this.addMainEventListeners(document); 483 484 window.addEventListener("resize", this.windowResize.bind(this), true); 485 486 var errorWarningCount = document.getElementById("error-warning-count"); 487 errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); 488 this._updateErrorAndWarningCounts(); 489 490 this.extensionServer.initExtensions(); 491 492 this.console.enableAgent(); 493 494 function showInitialPanel() 495 { 496 if (!WebInspector.inspectorView.currentPanel()) 497 WebInspector.showPanel(WebInspector.settings.lastActivePanel.get()); 498 } 499 500 InspectorAgent.enable(showInitialPanel); 501 this.databaseModel = new WebInspector.DatabaseModel(); 502 this.domStorageModel = new WebInspector.DOMStorageModel(); 503 504 if (!Capabilities.profilerCausesRecompilation || WebInspector.settings.profilerEnabled.get()) 505 ProfilerAgent.enable(); 506 507 if (WebInspector.settings.showPaintRects.get()) 508 PageAgent.setShowPaintRects(true); 509 510 if (WebInspector.settings.showDebugBorders.get()) 511 PageAgent.setShowDebugBorders(true); 512 513 if (WebInspector.settings.continuousPainting.get()) 514 PageAgent.setContinuousPaintingEnabled(true); 515 516 if (WebInspector.settings.javaScriptDisabled.get()) 517 PageAgent.setScriptExecutionDisabled(true); 518 519 if (WebInspector.settings.showFPSCounter.get()) 520 PageAgent.setShowFPSCounter(true); 521 522 this.domAgent._emulateTouchEventsChanged(); 523 524 WebInspector.WorkerManager.loadCompleted(); 525 InspectorFrontendAPI.loadCompleted(); 526 527 WebInspector.notifications.dispatchEventToListeners(WebInspector.Events.InspectorLoaded); 528} 529 530var windowLoaded = function() 531{ 532 var localizedStringsURL = InspectorFrontendHost.localizedStringsURL(); 533 if (localizedStringsURL) { 534 var localizedStringsScriptElement = document.createElement("script"); 535 localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false); 536 localizedStringsScriptElement.type = "text/javascript"; 537 localizedStringsScriptElement.src = localizedStringsURL; 538 document.head.appendChild(localizedStringsScriptElement); 539 } else 540 WebInspector.loaded(); 541 542 window.removeEventListener("DOMContentLoaded", windowLoaded, false); 543 delete windowLoaded; 544}; 545 546window.addEventListener("DOMContentLoaded", windowLoaded, false); 547 548// We'd like to enforce asynchronous interaction between the inspector controller and the frontend. 549// It is needed to prevent re-entering the backend code. 550// Also, native dispatches do not guarantee setTimeouts to be serialized, so we 551// enforce serialization using 'messagesToDispatch' queue. It is also important that JSC debugger 552// tests require that each command was dispatch within individual timeout callback, so we don't batch them. 553 554var messagesToDispatch = []; 555 556WebInspector.dispatchQueueIsEmpty = function() { 557 return messagesToDispatch.length == 0; 558} 559 560WebInspector.dispatch = function(message) { 561 messagesToDispatch.push(message); 562 setTimeout(function() { 563 InspectorBackend.dispatch(messagesToDispatch.shift()); 564 }, 0); 565} 566 567WebInspector.windowResize = function(event) 568{ 569 if (WebInspector.inspectorView) 570 WebInspector.inspectorView.doResize(); 571 if (WebInspector.drawer) 572 WebInspector.drawer.resize(); 573 if (WebInspector.toolbar) 574 WebInspector.toolbar.resize(); 575 if (WebInspector.settingsController) 576 WebInspector.settingsController.resize(); 577} 578 579WebInspector.setDockingUnavailable = function(unavailable) 580{ 581 if (this.dockController) 582 this.dockController.setDockingUnavailable(unavailable); 583} 584 585WebInspector.close = function(event) 586{ 587 if (this._isClosing) 588 return; 589 this._isClosing = true; 590 this.notifications.dispatchEventToListeners(WebInspector.Events.InspectorClosing); 591 InspectorFrontendHost.closeWindow(); 592} 593 594WebInspector.documentClick = function(event) 595{ 596 var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); 597 if (!anchor || (anchor.target === "_blank")) 598 return; 599 600 // Prevent the link from navigating, since we don't do any navigation by following links normally. 601 event.consume(true); 602 603 function followLink() 604 { 605 if (WebInspector.isBeingEdited(event.target) || WebInspector._showAnchorLocation(anchor)) 606 return; 607 608 const profileMatch = WebInspector.ProfilesPanelDescriptor.ProfileURLRegExp.exec(anchor.href); 609 if (profileMatch) { 610 WebInspector.showPanel("profiles").showProfile(profileMatch[1], profileMatch[2]); 611 return; 612 } 613 614 var parsedURL = anchor.href.asParsedURL(); 615 if (parsedURL && parsedURL.scheme === "webkit-link-action") { 616 if (parsedURL.host === "show-panel") { 617 var panel = parsedURL.path.substring(1); 618 if (WebInspector.panel(panel)) 619 WebInspector.showPanel(panel); 620 } 621 return; 622 } 623 624 InspectorFrontendHost.openInNewTab(anchor.href); 625 } 626 627 if (WebInspector.followLinkTimeout) 628 clearTimeout(WebInspector.followLinkTimeout); 629 630 if (anchor.preventFollowOnDoubleClick) { 631 // Start a timeout if this is the first click, if the timeout is canceled 632 // before it fires, then a double clicked happened or another link was clicked. 633 if (event.detail === 1) 634 WebInspector.followLinkTimeout = setTimeout(followLink, 333); 635 return; 636 } 637 638 followLink(); 639} 640 641WebInspector.openResource = function(resourceURL, inResourcesPanel) 642{ 643 var resource = WebInspector.resourceForURL(resourceURL); 644 if (inResourcesPanel && resource) 645 WebInspector.showPanel("resources").showResource(resource); 646 else 647 InspectorFrontendHost.openInNewTab(resourceURL); 648} 649 650WebInspector._registerShortcuts = function() 651{ 652 var shortcut = WebInspector.KeyboardShortcut; 653 var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("All Panels")); 654 var keys = [ 655 shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta), 656 shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta) 657 ]; 658 section.addRelatedKeys(keys, WebInspector.UIString("Go to the panel to the left/right")); 659 660 keys = [ 661 shortcut.makeDescriptor("[", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt), 662 shortcut.makeDescriptor("]", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt) 663 ]; 664 section.addRelatedKeys(keys, WebInspector.UIString("Go back/forward in panel history")); 665 666 section.addKey(shortcut.makeDescriptor(shortcut.Keys.Esc), WebInspector.UIString("Toggle console")); 667 section.addKey(shortcut.makeDescriptor("f", shortcut.Modifiers.CtrlOrMeta), WebInspector.UIString("Search")); 668 669 var advancedSearchShortcut = WebInspector.AdvancedSearchController.createShortcut(); 670 section.addKey(advancedSearchShortcut, WebInspector.UIString("Search across all sources")); 671 672 var inspectElementModeShortcut = WebInspector.InspectElementModeController.createShortcut(); 673 section.addKey(inspectElementModeShortcut, WebInspector.UIString("Select node to inspect")); 674 675 var openResourceShortcut = WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta); 676 section.addKey(openResourceShortcut, WebInspector.UIString("Go to source")); 677 678 if (WebInspector.isMac()) { 679 keys = [ 680 shortcut.makeDescriptor("g", shortcut.Modifiers.Meta), 681 shortcut.makeDescriptor("g", shortcut.Modifiers.Meta | shortcut.Modifiers.Shift) 682 ]; 683 section.addRelatedKeys(keys, WebInspector.UIString("Find next/previous")); 684 } 685 686 var goToShortcut = WebInspector.GoToLineDialog.createShortcut(); 687 section.addKey(goToShortcut, WebInspector.UIString("Go to line")); 688 689 keys = [ 690 shortcut.Keys.F1, 691 shortcut.makeDescriptor("?") 692 ]; 693 section.addAlternateKeys(keys, WebInspector.UIString("Show keyboard shortcuts")); 694} 695 696/** 697 * @param {KeyboardEvent} event 698 */ 699WebInspector.documentKeyDown = function(event) 700{ 701 const helpKey = WebInspector.isMac() ? "U+003F" : "U+00BF"; // "?" for both platforms 702 703 if (event.keyIdentifier === "F1" || 704 (event.keyIdentifier === helpKey && event.shiftKey && (!WebInspector.isBeingEdited(event.target) || event.metaKey))) { 705 this.settingsController.showSettingsScreen(WebInspector.SettingsScreen.Tabs.Shortcuts); 706 event.consume(true); 707 return; 708 } 709 710 if (WebInspector.currentFocusElement() && WebInspector.currentFocusElement().handleKeyEvent) { 711 WebInspector.currentFocusElement().handleKeyEvent(event); 712 if (event.handled) { 713 event.consume(true); 714 return; 715 } 716 } 717 718 if (WebInspector.inspectorView.currentPanel()) { 719 WebInspector.inspectorView.currentPanel().handleShortcut(event); 720 if (event.handled) { 721 event.consume(true); 722 return; 723 } 724 } 725 726 if (WebInspector.searchController.handleShortcut(event)) 727 return; 728 if (WebInspector.advancedSearchController.handleShortcut(event)) 729 return; 730 if (WebInspector.inspectElementModeController && WebInspector.inspectElementModeController.handleShortcut(event)) 731 return; 732 733 switch (event.keyIdentifier) { 734 case "U+004F": // O key 735 if (!event.shiftKey && !event.altKey && WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) { 736 WebInspector.showPanel("scripts").showGoToSourceDialog(); 737 event.consume(true); 738 } 739 break; 740 case "U+0052": // R key 741 if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) { 742 PageAgent.reload(event.shiftKey); 743 event.consume(true); 744 } 745 if (window.DEBUG && event.altKey) { 746 WebInspector.reload(); 747 return; 748 } 749 break; 750 case "F5": 751 if (!WebInspector.isMac()) { 752 PageAgent.reload(event.ctrlKey || event.shiftKey); 753 event.consume(true); 754 } 755 break; 756 } 757 758 var isValidZoomShortcut = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && 759 !event.altKey && 760 !InspectorFrontendHost.isStub; 761 switch (event.keyCode) { 762 case 107: // + 763 case 187: // + 764 if (isValidZoomShortcut) { 765 WebInspector._zoomIn(); 766 event.consume(true); 767 } 768 break; 769 case 109: // - 770 case 189: // - 771 if (isValidZoomShortcut) { 772 WebInspector._zoomOut(); 773 event.consume(true); 774 } 775 break; 776 case 48: // 0 777 // Zoom reset shortcut does not allow "Shift" when handled by the browser. 778 if (isValidZoomShortcut && !event.shiftKey) { 779 WebInspector._resetZoom(); 780 event.consume(true); 781 } 782 break; 783 } 784} 785 786WebInspector.postDocumentKeyDown = function(event) 787{ 788 if (event.handled) 789 return; 790 791 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) { 792 // If drawer is open with some view other than console then close it. 793 if (!this._toggleConsoleButton.toggled && WebInspector.drawer.visible) 794 this.closeViewInDrawer(); 795 else 796 this._toggleConsoleButtonClicked(); 797 } 798} 799 800WebInspector.documentCanCopy = function(event) 801{ 802 if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent) 803 event.preventDefault(); 804} 805 806WebInspector.documentCopy = function(event) 807{ 808 if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent) 809 WebInspector.inspectorView.currentPanel().handleCopyEvent(event); 810 WebInspector.documentCopyEventFired(event); 811} 812 813WebInspector.documentCopyEventFired = function(event) 814{ 815} 816 817WebInspector.contextMenuEventFired = function(event) 818{ 819 if (event.handled || event.target.hasStyleClass("popup-glasspane")) 820 event.preventDefault(); 821} 822 823WebInspector.showConsole = function() 824{ 825 if (WebInspector._toggleConsoleButton && !WebInspector._toggleConsoleButton.toggled) { 826 if (WebInspector.drawer.visible) 827 this._closePreviousDrawerView(); 828 WebInspector._toggleConsoleButtonClicked(); 829 } 830} 831 832WebInspector.showPanel = function(panel) 833{ 834 return WebInspector.inspectorView.showPanel(panel); 835} 836 837WebInspector.panel = function(panel) 838{ 839 return WebInspector.inspectorView.panel(panel); 840} 841 842WebInspector.bringToFront = function() 843{ 844 InspectorFrontendHost.bringToFront(); 845} 846 847/** 848 * @param {string=} messageLevel 849 * @param {boolean=} showConsole 850 */ 851WebInspector.log = function(message, messageLevel, showConsole) 852{ 853 // remember 'this' for setInterval() callback 854 var self = this; 855 856 // return indication if we can actually log a message 857 function isLogAvailable() 858 { 859 return WebInspector.ConsoleMessage && WebInspector.RemoteObject && self.console; 860 } 861 862 // flush the queue of pending messages 863 function flushQueue() 864 { 865 var queued = WebInspector.log.queued; 866 if (!queued) 867 return; 868 869 for (var i = 0; i < queued.length; ++i) 870 logMessage(queued[i]); 871 872 delete WebInspector.log.queued; 873 } 874 875 // flush the queue if it console is available 876 // - this function is run on an interval 877 function flushQueueIfAvailable() 878 { 879 if (!isLogAvailable()) 880 return; 881 882 clearInterval(WebInspector.log.interval); 883 delete WebInspector.log.interval; 884 885 flushQueue(); 886 } 887 888 // actually log the message 889 function logMessage(message) 890 { 891 // post the message 892 var msg = WebInspector.ConsoleMessage.create( 893 WebInspector.ConsoleMessage.MessageSource.Other, 894 messageLevel || WebInspector.ConsoleMessage.MessageLevel.Debug, 895 message); 896 897 self.console.addMessage(msg); 898 if (showConsole) 899 WebInspector.showConsole(); 900 } 901 902 // if we can't log the message, queue it 903 if (!isLogAvailable()) { 904 if (!WebInspector.log.queued) 905 WebInspector.log.queued = []; 906 907 WebInspector.log.queued.push(message); 908 909 if (!WebInspector.log.interval) 910 WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000); 911 912 return; 913 } 914 915 // flush the pending queue if any 916 flushQueue(); 917 918 // log the message 919 logMessage(message); 920} 921 922WebInspector.showErrorMessage = function(error) 923{ 924 WebInspector.log(error, WebInspector.ConsoleMessage.MessageLevel.Error, true); 925} 926 927// Inspector.inspect protocol event 928WebInspector.inspect = function(payload, hints) 929{ 930 var object = WebInspector.RemoteObject.fromPayload(payload); 931 if (object.subtype === "node") { 932 function callback(nodeId) 933 { 934 WebInspector._updateFocusedNode(nodeId); 935 object.release(); 936 } 937 object.pushNodeToFrontend(callback); 938 return; 939 } 940 941 if (hints.databaseId) 942 WebInspector.showPanel("resources").selectDatabase(WebInspector.databaseModel.databaseForId(hints.databaseId)); 943 else if (hints.domStorageId) 944 WebInspector.showPanel("resources").selectDOMStorage(WebInspector.domStorageModel.storageForId(hints.domStorageId)); 945 946 object.release(); 947} 948 949// Inspector.detached protocol event 950WebInspector.detached = function(reason) 951{ 952 WebInspector.socket._detachReason = reason; 953 (new WebInspector.RemoteDebuggingTerminatedScreen(reason)).showModal(); 954} 955 956WebInspector.targetCrashed = function() 957{ 958 (new WebInspector.HelpScreenUntilReload( 959 WebInspector.UIString("Inspected target crashed"), 960 WebInspector.UIString("Inspected target has crashed. Once it reloads we will attach to it automatically."))).showModal(); 961} 962 963WebInspector._updateFocusedNode = function(nodeId) 964{ 965 if (WebInspector.inspectElementModeController && WebInspector.inspectElementModeController.enabled()) { 966 InspectorFrontendHost.bringToFront(); 967 WebInspector.inspectElementModeController.disable(); 968 } 969 WebInspector.showPanel("elements").revealAndSelectNode(nodeId); 970} 971 972WebInspector._showAnchorLocation = function(anchor) 973{ 974 if (WebInspector.openAnchorLocationRegistry.dispatch({ url: anchor.href, lineNumber: anchor.lineNumber})) 975 return true; 976 var preferredPanel = this.panels[anchor.preferredPanel]; 977 if (preferredPanel && WebInspector._showAnchorLocationInPanel(anchor, preferredPanel)) 978 return true; 979 if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("scripts"))) 980 return true; 981 if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("resources"))) 982 return true; 983 if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("network"))) 984 return true; 985 return false; 986} 987 988WebInspector._showAnchorLocationInPanel = function(anchor, panel) 989{ 990 if (!panel || !panel.canShowAnchorLocation(anchor)) 991 return false; 992 993 // FIXME: support webkit-html-external-link links here. 994 if (anchor.hasStyleClass("webkit-html-external-link")) { 995 anchor.removeStyleClass("webkit-html-external-link"); 996 anchor.addStyleClass("webkit-html-resource-link"); 997 } 998 999 WebInspector.inspectorView.showPanelForAnchorNavigation(panel); 1000 panel.showAnchorLocation(anchor); 1001 return true; 1002} 1003 1004WebInspector.evaluateInConsole = function(expression, showResultOnly) 1005{ 1006 this.showConsole(); 1007 this.consoleView.evaluateUsingTextPrompt(expression, showResultOnly); 1008} 1009 1010WebInspector.addMainEventListeners = function(doc) 1011{ 1012 doc.addEventListener("keydown", this.documentKeyDown.bind(this), true); 1013 doc.addEventListener("keydown", this.postDocumentKeyDown.bind(this), false); 1014 doc.addEventListener("beforecopy", this.documentCanCopy.bind(this), true); 1015 doc.addEventListener("copy", this.documentCopy.bind(this), false); 1016 doc.addEventListener("contextmenu", this.contextMenuEventFired.bind(this), true); 1017 doc.addEventListener("click", this.documentClick.bind(this), true); 1018} 1019 1020WebInspector.Zoom = { 1021 Table: [0.25, 0.33, 0.5, 0.66, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5], 1022 DefaultOffset: 6 1023} 1024