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