1 /* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2011 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /** 28 * @constructor 29 * @extends {WebInspector.Panel} 30 * @implements {WebInspector.ContextMenu.Provider} 31 * @implements {WebInspector.TargetManager.Observer} 32 * @param {!WebInspector.Workspace=} workspaceForTest 33 */ 34 WebInspector.SourcesPanel = function(workspaceForTest) 35 { 36 WebInspector.Panel.call(this, "sources"); 37 this.registerRequiredCSS("sourcesPanel.css"); 38 new WebInspector.UpgradeFileSystemDropTarget(this.element); 39 40 this._workspace = workspaceForTest || WebInspector.workspace; 41 42 this.debugToolbar = this._createDebugToolbar(); 43 this._debugToolbarDrawer = this._createDebugToolbarDrawer(); 44 45 const initialDebugSidebarWidth = 225; 46 this._splitView = new WebInspector.SplitView(true, true, "sourcesPanelSplitViewState", initialDebugSidebarWidth); 47 this._splitView.enableShowModeSaving(); 48 this._splitView.show(this.element); 49 50 // Create scripts navigator 51 const initialNavigatorWidth = 225; 52 this.editorView = new WebInspector.SplitView(true, false, "sourcesPanelNavigatorSplitViewState", initialNavigatorWidth); 53 this.editorView.enableShowModeSaving(); 54 this.editorView.element.id = "scripts-editor-split-view"; 55 this.editorView.element.tabIndex = 0; 56 this.editorView.show(this._splitView.mainElement()); 57 58 this._navigator = new WebInspector.SourcesNavigator(this._workspace); 59 this._navigator.view.setMinimumSize(100, 25); 60 this._navigator.view.show(this.editorView.sidebarElement()); 61 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.SourceSelected, this._sourceSelected, this); 62 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.SourceRenamed, this._sourceRenamed, this); 63 64 this._sourcesView = new WebInspector.SourcesView(this._workspace, this); 65 this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorSelected, this._editorSelected.bind(this)); 66 this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorClosed, this._editorClosed.bind(this)); 67 this._sourcesView.registerShortcuts(this.registerShortcuts.bind(this)); 68 this._sourcesView.show(this.editorView.mainElement()); 69 70 this._debugSidebarResizeWidgetElement = document.createElementWithClass("div", "resizer-widget"); 71 this._debugSidebarResizeWidgetElement.id = "scripts-debug-sidebar-resizer-widget"; 72 this._splitView.addEventListener(WebInspector.SplitView.Events.ShowModeChanged, this._updateDebugSidebarResizeWidget, this); 73 this._updateDebugSidebarResizeWidget(); 74 this._splitView.installResizer(this._debugSidebarResizeWidgetElement); 75 76 // FIXME: This is a temporary solution which should be removed as soon as the documentation module is released from experiment. 77 if (Runtime.experiments.isEnabled("documentation")) 78 self.runtime.loadModule("documentation"); 79 80 this.sidebarPanes = {}; 81 this.sidebarPanes.threads = new WebInspector.ThreadsSidebarPane(); 82 this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane(); 83 this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); 84 this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, this._callFrameSelectedInSidebar.bind(this)); 85 this.sidebarPanes.callstack.registerShortcuts(this.registerShortcuts.bind(this)); 86 87 this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); 88 this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(WebInspector.breakpointManager, this.showUISourceCode.bind(this)); 89 this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this); 90 this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane(); 91 this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane(); 92 93 this._extensionSidebarPanes = []; 94 this._installDebuggerSidebarController(); 95 96 WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this)); 97 WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this)); 98 this._dockSideChanged(); 99 100 this._updateDebuggerButtons(); 101 this._pauseOnExceptionEnabledChanged(); 102 WebInspector.settings.pauseOnExceptionEnabled.addChangeListener(this._pauseOnExceptionEnabledChanged, this); 103 this._setTarget(WebInspector.context.flavor(WebInspector.Target)); 104 WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this); 105 WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._onCurrentTargetChanged, this); 106 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this); 107 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerReset, this); 108 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); 109 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); 110 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this); 111 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this); 112 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this); 113 WebInspector.targetManager.observeTargets(this); 114 } 115 116 WebInspector.SourcesPanel.minToolbarWidth = 215; 117 118 WebInspector.SourcesPanel._infobarSymbol = Symbol("infobar"); 119 120 WebInspector.SourcesPanel.prototype = { 121 /** 122 * @param {?WebInspector.Target} target 123 */ 124 _setTarget: function(target) 125 { 126 if (!target) 127 return; 128 129 if (target.debuggerModel.isPaused()) { 130 this._showDebuggerPausedDetails(/** @type {!WebInspector.DebuggerPausedDetails} */ (target.debuggerModel.debuggerPausedDetails())); 131 var callFrame = target.debuggerModel.selectedCallFrame(); 132 if (callFrame) 133 this._selectCallFrame(callFrame); 134 } else { 135 this._paused = false; 136 this._clearInterface(); 137 this._toggleDebuggerSidebarButton.setEnabled(true); 138 } 139 }, 140 141 /** 142 * @param {!WebInspector.Event} event 143 */ 144 _onCurrentTargetChanged: function(event) 145 { 146 var target = /** @type {?WebInspector.Target} */ (event.data); 147 this._setTarget(target); 148 }, 149 150 /** 151 * @return {!Element} 152 */ 153 defaultFocusedElement: function() 154 { 155 return this._sourcesView.defaultFocusedElement(); 156 }, 157 158 /** 159 * @return {boolean} 160 */ 161 paused: function() 162 { 163 return this._paused; 164 }, 165 166 wasShown: function() 167 { 168 WebInspector.context.setFlavor(WebInspector.SourcesPanel, this); 169 WebInspector.Panel.prototype.wasShown.call(this); 170 }, 171 172 willHide: function() 173 { 174 WebInspector.Panel.prototype.willHide.call(this); 175 WebInspector.context.setFlavor(WebInspector.SourcesPanel, null); 176 }, 177 178 /** 179 * @return {!WebInspector.SearchableView} 180 */ 181 searchableView: function() 182 { 183 return this._sourcesView.searchableView(); 184 }, 185 186 _consoleCommandEvaluatedInSelectedCallFrame: function(event) 187 { 188 var target = /** @type {!WebInspector.Target} */ (event.target.target()); 189 if (WebInspector.context.flavor(WebInspector.Target) !== target) 190 return; 191 this.sidebarPanes.scopechain.update(target.debuggerModel.selectedCallFrame()); 192 }, 193 194 /** 195 * @param {!WebInspector.Event} event 196 */ 197 _debuggerPaused: function(event) 198 { 199 var details = /** @type {!WebInspector.DebuggerPausedDetails} */ (event.data); 200 if (!this._paused) 201 WebInspector.inspectorView.setCurrentPanel(this); 202 203 if (WebInspector.context.flavor(WebInspector.Target) === details.target()) 204 this._showDebuggerPausedDetails(details); 205 else if (!this._paused) 206 WebInspector.context.setFlavor(WebInspector.Target, details.target()); 207 }, 208 209 /** 210 * @param {!WebInspector.DebuggerPausedDetails} details 211 */ 212 _showDebuggerPausedDetails: function(details) 213 { 214 this._paused = true; 215 this._updateDebuggerButtons(); 216 217 this.sidebarPanes.callstack.update(details); 218 219 /** 220 * @param {!Element} element 221 * @this {WebInspector.SourcesPanel} 222 */ 223 function didCreateBreakpointHitStatusMessage(element) 224 { 225 this.sidebarPanes.callstack.setStatus(element); 226 } 227 228 /** 229 * @param {!WebInspector.UILocation} uiLocation 230 * @this {WebInspector.SourcesPanel} 231 */ 232 function didGetUILocation(uiLocation) 233 { 234 var breakpoint = WebInspector.breakpointManager.findBreakpointOnLine(uiLocation.uiSourceCode, uiLocation.lineNumber); 235 if (!breakpoint) 236 return; 237 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(breakpoint); 238 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint.")); 239 } 240 241 if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) { 242 WebInspector.domBreakpointsSidebarPane.highlightBreakpoint(details.auxData); 243 WebInspector.domBreakpointsSidebarPane.createBreakpointHitStatusMessage(details, didCreateBreakpointHitStatusMessage.bind(this)); 244 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) { 245 var eventName = details.auxData["eventName"]; 246 var targetName = details.auxData["targetName"]; 247 this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(eventName, targetName); 248 var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName, details.auxData); 249 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI)); 250 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) { 251 this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]); 252 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest.")); 253 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception) 254 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData["description"])); 255 else if (details.reason === WebInspector.DebuggerModel.BreakReason.Assert) 256 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on assertion.")); 257 else if (details.reason === WebInspector.DebuggerModel.BreakReason.CSPViolation) 258 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a script blocked due to Content Security Policy directive: \"%s\".", details.auxData["directiveText"])); 259 else if (details.reason === WebInspector.DebuggerModel.BreakReason.DebugCommand) 260 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a debugged function")); 261 else { 262 if (details.callFrames.length) 263 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(details.callFrames[0], didGetUILocation.bind(this)); 264 else 265 console.warn("ScriptsPanel paused, but callFrames.length is zero."); // TODO remove this once we understand this case better 266 } 267 268 this._splitView.showBoth(true); 269 this._toggleDebuggerSidebarButton.setEnabled(false); 270 window.focus(); 271 InspectorFrontendHost.bringToFront(); 272 }, 273 274 /** 275 * @param {!WebInspector.Event} event 276 */ 277 _debuggerResumed: function(event) 278 { 279 var target = /** @type {!WebInspector.Target} */ (event.target.target()); 280 if (WebInspector.context.flavor(WebInspector.Target) !== target) 281 return; 282 this._paused = false; 283 this._clearInterface(); 284 this._toggleDebuggerSidebarButton.setEnabled(true); 285 }, 286 287 /** 288 * @param {!WebInspector.Event} event 289 */ 290 _debuggerWasEnabled: function(event) 291 { 292 var target = /** @type {!WebInspector.Target} */ (event.target.target()); 293 if (WebInspector.context.flavor(WebInspector.Target) !== target) 294 return; 295 296 this._updateDebuggerButtons(); 297 }, 298 299 /** 300 * @param {!WebInspector.Event} event 301 */ 302 _debuggerReset: function(event) 303 { 304 this._debuggerResumed(event); 305 }, 306 307 /** 308 * @return {!WebInspector.View} 309 */ 310 get visibleView() 311 { 312 return this._sourcesView.visibleView(); 313 }, 314 315 /** 316 * @param {!WebInspector.UISourceCode} uiSourceCode 317 * @param {number=} lineNumber 0-based 318 * @param {number=} columnNumber 319 * @param {boolean=} forceShowInPanel 320 */ 321 showUISourceCode: function(uiSourceCode, lineNumber, columnNumber, forceShowInPanel) 322 { 323 this._showEditor(forceShowInPanel); 324 this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber); 325 }, 326 327 _showEditor: function(forceShowInPanel) 328 { 329 WebInspector.inspectorView.showPanel("sources"); 330 }, 331 332 /** 333 * @param {!WebInspector.UILocation} uiLocation 334 * @param {boolean=} forceShowInPanel 335 */ 336 showUILocation: function(uiLocation, forceShowInPanel) 337 { 338 this.showUISourceCode(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, forceShowInPanel); 339 }, 340 341 /** 342 * @param {!WebInspector.UISourceCode} uiSourceCode 343 */ 344 _revealInNavigator: function(uiSourceCode) 345 { 346 this._navigator.revealUISourceCode(uiSourceCode); 347 }, 348 349 /** 350 * @param {boolean} ignoreExecutionLineEvents 351 */ 352 setIgnoreExecutionLineEvents: function(ignoreExecutionLineEvents) 353 { 354 this._ignoreExecutionLineEvents = ignoreExecutionLineEvents; 355 }, 356 357 _executionLineChanged: function(uiLocation) 358 { 359 this._sourcesView.clearCurrentExecutionLine(); 360 this._sourcesView.setExecutionLine(uiLocation); 361 if (this._ignoreExecutionLineEvents) 362 return; 363 this._sourcesView.showSourceLocation(uiLocation.uiSourceCode, uiLocation.lineNumber, 0, undefined, true); 364 }, 365 366 /** 367 * @param {!WebInspector.Event} event 368 */ 369 _callFrameSelected: function(event) 370 { 371 var callFrame = /** @type {?WebInspector.DebuggerModel.CallFrame} */ (event.data); 372 373 if (!callFrame || callFrame.target() !== WebInspector.context.flavor(WebInspector.Target)) 374 return; 375 376 this._selectCallFrame(callFrame); 377 }, 378 379 /** 380 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame 381 */ 382 _selectCallFrame: function(callFrame) 383 { 384 this.sidebarPanes.scopechain.update(callFrame); 385 this.sidebarPanes.watchExpressions.refreshExpressions(); 386 this.sidebarPanes.callstack.setSelectedCallFrame(callFrame); 387 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(callFrame, this._executionLineChanged.bind(this)); 388 }, 389 390 /** 391 * @param {!WebInspector.Event} event 392 */ 393 _sourceSelected: function(event) 394 { 395 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.uiSourceCode); 396 this._sourcesView.showSourceLocation(uiSourceCode, undefined, undefined, !event.data.focusSource) 397 }, 398 399 /** 400 * @param {!WebInspector.Event} event 401 */ 402 _sourceRenamed: function(event) 403 { 404 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 405 this._sourcesView.sourceRenamed(uiSourceCode); 406 }, 407 408 _pauseOnExceptionEnabledChanged: function() 409 { 410 var enabled = WebInspector.settings.pauseOnExceptionEnabled.get(); 411 this._pauseOnExceptionButton.toggled = enabled; 412 this._pauseOnExceptionButton.title = WebInspector.UIString(enabled ? "Don't pause on exceptions." : "Pause on exceptions."); 413 this._debugToolbarDrawer.classList.toggle("expanded", enabled); 414 }, 415 416 _updateDebuggerButtons: function() 417 { 418 var currentTarget = WebInspector.context.flavor(WebInspector.Target); 419 if (!currentTarget) 420 return; 421 422 if (this._paused) { 423 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Resume script execution (%s).")) 424 this._pauseButton.state = true; 425 this._pauseButton.setLongClickOptionsEnabled((function() { return [ this._longResumeButton ] }).bind(this)); 426 427 this._pauseButton.setEnabled(true); 428 this._stepOverButton.setEnabled(true); 429 this._stepIntoButton.setEnabled(true); 430 this._stepOutButton.setEnabled(true); 431 } else { 432 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Pause script execution (%s).")) 433 this._pauseButton.state = false; 434 this._pauseButton.setLongClickOptionsEnabled(null); 435 436 this._pauseButton.setEnabled(!currentTarget.debuggerModel.isPausing()); 437 this._stepOverButton.setEnabled(false); 438 this._stepIntoButton.setEnabled(false); 439 this._stepOutButton.setEnabled(false); 440 } 441 }, 442 443 _clearInterface: function() 444 { 445 this.sidebarPanes.callstack.update(null); 446 this.sidebarPanes.scopechain.update(null); 447 this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight(); 448 WebInspector.domBreakpointsSidebarPane.clearBreakpointHighlight(); 449 this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight(); 450 this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight(); 451 452 this._sourcesView.clearCurrentExecutionLine(); 453 this._updateDebuggerButtons(); 454 }, 455 456 _togglePauseOnExceptions: function() 457 { 458 WebInspector.settings.pauseOnExceptionEnabled.set(!this._pauseOnExceptionButton.toggled); 459 }, 460 461 /** 462 * @return {boolean} 463 */ 464 _runSnippet: function() 465 { 466 var uiSourceCode = this._sourcesView.currentUISourceCode(); 467 if (uiSourceCode.project().type() !== WebInspector.projectTypes.Snippets) 468 return false; 469 470 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext); 471 if (!currentExecutionContext) 472 return false; 473 474 WebInspector.scriptSnippetModel.evaluateScriptSnippet(currentExecutionContext, uiSourceCode); 475 return true; 476 }, 477 478 /** 479 * @param {!WebInspector.Event} event 480 */ 481 _editorSelected: function(event) 482 { 483 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 484 this._editorChanged(uiSourceCode); 485 if (Runtime.experiments.isEnabled("suggestUsingWorkspace")) { 486 if (this._editorSelectedTimer) 487 clearTimeout(this._editorSelectedTimer); 488 this._editorSelectedTimer = setTimeout(this._updateSuggestedMappingInfobar.bind(this, uiSourceCode), 3000); 489 } 490 }, 491 492 /** 493 * @param {!WebInspector.UISourceCode} uiSourceCode 494 */ 495 _updateSuggestedMappingInfobar: function(uiSourceCode) 496 { 497 if (!this.isShowing()) 498 return; 499 if (uiSourceCode[WebInspector.SourcesPanel._infobarSymbol]) 500 return; 501 502 // First try mapping filesystem -> network. 503 var uiSourceCodeFrame = this._sourcesView.viewForFile(uiSourceCode); 504 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) { 505 var hasMappings = !!uiSourceCode.url; 506 if (hasMappings) 507 return; 508 509 var targets = WebInspector.targetManager.targets(); 510 for (var i = 0; i < targets.length; ++i) 511 targets[i].resourceTreeModel.forAllResources(matchResource.bind(this)); 512 } 513 514 /** 515 * @param {!WebInspector.Resource} resource 516 * @return {boolean} 517 * @this {WebInspector.SourcesPanel} 518 */ 519 function matchResource(resource) 520 { 521 if (resource.contentURL().endsWith(uiSourceCode.name())) { 522 createMappingInfobar.call(this, false); 523 return true; 524 } 525 return false; 526 } 527 528 // Then map network -> filesystem. 529 if (uiSourceCode.project().type() === WebInspector.projectTypes.Network || uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts) { 530 if (this._workspace.uiSourceCodeForURL(uiSourceCode.url) !== uiSourceCode) 531 return; 532 533 var filesystemProjects = this._workspace.projectsForType(WebInspector.projectTypes.FileSystem); 534 for (var i = 0; i < filesystemProjects.length; ++i) { 535 var name = uiSourceCode.name(); 536 var fsUiSourceCodes = filesystemProjects[i].uiSourceCodes(); 537 for (var j = 0; j < fsUiSourceCodes.length; ++j) { 538 if (fsUiSourceCodes[j].name() === name) { 539 createMappingInfobar.call(this, true); 540 return; 541 } 542 } 543 } 544 545 // There are no matching filesystems. Suggest adding a filesystem in case of localhost. 546 var originURL = uiSourceCode.originURL().asParsedURL(); 547 if (originURL && originURL.host === "localhost") 548 createWorkspaceInfobar(); 549 } 550 551 /** 552 * @param {boolean} isNetwork 553 * @this {WebInspector.SourcesPanel} 554 */ 555 function createMappingInfobar(isNetwork) 556 { 557 var title; 558 if (isNetwork) 559 title = WebInspector.UIString("Map network resource '%s' to workspace?", uiSourceCode.originURL()); 560 else 561 title = WebInspector.UIString("Map workspace resource '%s' to network?", uiSourceCode.path()); 562 563 var infobar = new WebInspector.UISourceCodeFrame.Infobar(WebInspector.UISourceCodeFrame.Infobar.Level.Info, title); 564 infobar.createDetailsRowMessage(WebInspector.UIString("You can map files in your workspace to the ones loaded over the network. As a result, changes made in DevTools will be persisted to disk.")); 565 infobar.createDetailsRowMessage(WebInspector.UIString("Use context menu to establish the mapping at any time.")); 566 var actionLink = infobar.createDetailsRowMessage("").createChild("a"); 567 actionLink.href = ""; 568 actionLink.onclick = establishTheMapping.bind(this); 569 actionLink.textContent = WebInspector.UIString("Establish the mapping now..."); 570 appendInfobar(infobar); 571 } 572 573 /** 574 * @param {?Event} event 575 * @this {WebInspector.SourcesPanel} 576 */ 577 function establishTheMapping(event) 578 { 579 event.consume(true); 580 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) 581 this._mapFileSystemToNetwork(uiSourceCode); 582 else 583 this._mapNetworkToFileSystem(uiSourceCode); 584 } 585 586 function createWorkspaceInfobar() 587 { 588 var infobar = new WebInspector.UISourceCodeFrame.Infobar(WebInspector.UISourceCodeFrame.Infobar.Level.Info, WebInspector.UIString("Serving from the file system? Add your files into the workspace.")); 589 infobar.createDetailsRowMessage(WebInspector.UIString("If you add files into your DevTools workspace, your changes will be persisted to disk.")); 590 infobar.createDetailsRowMessage(WebInspector.UIString("To add a folder into the workspace, drag and drop it into the Sources panel.")); 591 appendInfobar(infobar); 592 } 593 594 /** 595 * @param {!WebInspector.UISourceCodeFrame.Infobar} infobar 596 */ 597 function appendInfobar(infobar) 598 { 599 infobar.createDetailsRowMessage("").createChild("br"); 600 var rowElement = infobar.createDetailsRowMessage(WebInspector.UIString("For more information on workspaces, refer to the ")); 601 var a = rowElement.createChild("a"); 602 a.textContent = "workspaces documentation"; 603 a.href = "https://developer.chrome.com/devtools/docs/workspaces"; 604 rowElement.createTextChild("."); 605 uiSourceCode[WebInspector.SourcesPanel._infobarSymbol] = infobar; 606 uiSourceCodeFrame.attachInfobars([infobar]); 607 } 608 }, 609 610 /** 611 * @param {!WebInspector.Event} event 612 */ 613 _editorClosed: function(event) 614 { 615 var wasSelected = /** @type {boolean} */ (event.data.wasSelected); 616 if (wasSelected) 617 this._editorChanged(null); 618 }, 619 620 /** 621 * @param {?WebInspector.UISourceCode} uiSourceCode 622 */ 623 _editorChanged: function(uiSourceCode) 624 { 625 var isSnippet = uiSourceCode && uiSourceCode.project().type() === WebInspector.projectTypes.Snippets; 626 this._runSnippetButton.element.classList.toggle("hidden", !isSnippet); 627 }, 628 629 /** 630 * @return {boolean} 631 */ 632 togglePause: function() 633 { 634 var target = WebInspector.context.flavor(WebInspector.Target); 635 if (!target) 636 return true; 637 638 if (this._paused) { 639 this._paused = false; 640 target.debuggerModel.resume(); 641 } else { 642 // Make sure pauses didn't stick skipped. 643 target.debuggerModel.pause(); 644 } 645 646 this._clearInterface(); 647 return true; 648 }, 649 650 /** 651 * @return {?WebInspector.DebuggerModel} 652 */ 653 _prepareToResume: function() 654 { 655 if (!this._paused) 656 return null; 657 658 this._paused = false; 659 660 this._clearInterface(); 661 var target = WebInspector.context.flavor(WebInspector.Target); 662 return target ? target.debuggerModel : null; 663 }, 664 665 /** 666 * @return {boolean} 667 */ 668 _longResume: function() 669 { 670 var debuggerModel = this._prepareToResume(); 671 if (!debuggerModel) 672 return true; 673 674 debuggerModel.skipAllPausesUntilReloadOrTimeout(500); 675 debuggerModel.resume(); 676 return true; 677 }, 678 679 /** 680 * @return {boolean} 681 */ 682 _stepOverClicked: function() 683 { 684 var debuggerModel = this._prepareToResume(); 685 if (!debuggerModel) 686 return true; 687 688 debuggerModel.stepOver(); 689 return true; 690 }, 691 692 /** 693 * @return {boolean} 694 */ 695 _stepIntoClicked: function() 696 { 697 var debuggerModel = this._prepareToResume(); 698 if (!debuggerModel) 699 return true; 700 701 debuggerModel.stepInto(); 702 return true; 703 }, 704 705 /** 706 * @return {boolean} 707 */ 708 _stepOutClicked: function() 709 { 710 var debuggerModel = this._prepareToResume(); 711 if (!debuggerModel) 712 return true; 713 714 debuggerModel.stepOut(); 715 return true; 716 }, 717 718 /** 719 * @param {!WebInspector.Event} event 720 */ 721 _callFrameSelectedInSidebar: function(event) 722 { 723 var callFrame = /** @type {!WebInspector.DebuggerModel.CallFrame} */ (event.data); 724 callFrame.target().debuggerModel.setSelectedCallFrame(callFrame); 725 }, 726 727 /** 728 * @param {!WebInspector.DebuggerModel.Location} rawLocation 729 */ 730 continueToLocation: function(rawLocation) 731 { 732 if (!this._prepareToResume()) 733 return; 734 735 rawLocation.continueToLocation(); 736 }, 737 738 _toggleBreakpointsClicked: function(event) 739 { 740 WebInspector.breakpointManager.setBreakpointsActive(!WebInspector.breakpointManager.breakpointsActive()); 741 }, 742 743 _breakpointsActiveStateChanged: function(event) 744 { 745 var active = event.data; 746 this._toggleBreakpointsButton.toggled = !active; 747 this.sidebarPanes.jsBreakpoints.listElement.classList.toggle("breakpoints-list-deactivated", !active); 748 this._sourcesView.toggleBreakpointsActiveState(active); 749 if (active) 750 this._toggleBreakpointsButton.title = WebInspector.UIString("Deactivate breakpoints."); 751 else 752 this._toggleBreakpointsButton.title = WebInspector.UIString("Activate breakpoints."); 753 }, 754 755 _createDebugToolbar: function() 756 { 757 var debugToolbar = document.createElementWithClass("div", "scripts-debug-toolbar"); 758 759 var title, handler; 760 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta; 761 762 // Run snippet. 763 title = WebInspector.UIString("Run snippet (%s)."); 764 handler = this._runSnippet.bind(this); 765 this._runSnippetButton = this._createButtonAndRegisterShortcuts("scripts-run-snippet", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.RunSnippet); 766 debugToolbar.appendChild(this._runSnippetButton.element); 767 this._runSnippetButton.element.classList.add("hidden"); 768 769 // Continue. 770 this._pauseButton = this._createButtonAndRegisterShortcutsForAction("scripts-pause", "", "debugger.toggle-pause"); 771 debugToolbar.appendChild(this._pauseButton.element); 772 773 // Long resume. 774 title = WebInspector.UIString("Resume with all pauses blocked for 500 ms"); 775 this._longResumeButton = new WebInspector.StatusBarButton(title, "scripts-long-resume"); 776 this._longResumeButton.addEventListener("click", this._longResume.bind(this), this); 777 778 // Step over. 779 title = WebInspector.UIString("Step over next function call (%s)."); 780 handler = this._stepOverClicked.bind(this); 781 this._stepOverButton = this._createButtonAndRegisterShortcuts("scripts-step-over", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOver); 782 debugToolbar.appendChild(this._stepOverButton.element); 783 784 // Step into. 785 title = WebInspector.UIString("Step into next function call (%s)."); 786 handler = this._stepIntoClicked.bind(this); 787 this._stepIntoButton = this._createButtonAndRegisterShortcuts("scripts-step-into", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepInto); 788 debugToolbar.appendChild(this._stepIntoButton.element); 789 790 // Step out. 791 title = WebInspector.UIString("Step out of current function (%s)."); 792 handler = this._stepOutClicked.bind(this); 793 this._stepOutButton = this._createButtonAndRegisterShortcuts("scripts-step-out", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOut); 794 debugToolbar.appendChild(this._stepOutButton.element); 795 796 // Toggle Breakpoints 797 this._toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate breakpoints."), "scripts-toggle-breakpoints"); 798 this._toggleBreakpointsButton.toggled = false; 799 this._toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this); 800 debugToolbar.appendChild(this._toggleBreakpointsButton.element); 801 802 // Pause on Exception 803 this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item"); 804 this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this); 805 debugToolbar.appendChild(this._pauseOnExceptionButton.element); 806 807 return debugToolbar; 808 }, 809 810 _createDebugToolbarDrawer: function() 811 { 812 var debugToolbarDrawer = document.createElementWithClass("div", "scripts-debug-toolbar-drawer"); 813 814 var label = WebInspector.UIString("Pause On Caught Exceptions"); 815 var setting = WebInspector.settings.pauseOnCaughtException; 816 debugToolbarDrawer.appendChild(WebInspector.SettingsUI.createSettingCheckbox(label, setting, true)); 817 818 return debugToolbarDrawer; 819 }, 820 821 /** 822 * @param {!WebInspector.StatusBarButton} button 823 * @param {string} buttonTitle 824 */ 825 _updateButtonTitle: function(button, buttonTitle) 826 { 827 var hasShortcuts = button.shortcuts && button.shortcuts.length; 828 if (hasShortcuts) 829 button.title = String.vsprintf(buttonTitle, [button.shortcuts[0].name]); 830 else 831 button.title = buttonTitle; 832 }, 833 834 /** 835 * @param {string} buttonId 836 * @param {string} buttonTitle 837 * @param {function(!Event=):boolean} handler 838 * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts 839 * @return {!WebInspector.StatusBarButton} 840 */ 841 _createButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts) 842 { 843 var button = new WebInspector.StatusBarButton(buttonTitle, buttonId); 844 button.element.addEventListener("click", handler, false); 845 button.shortcuts = shortcuts; 846 this._updateButtonTitle(button, buttonTitle); 847 this.registerShortcuts(shortcuts, handler); 848 return button; 849 }, 850 851 /** 852 * @param {string} buttonId 853 * @param {string} buttonTitle 854 * @param {string} actionId 855 * @return {!WebInspector.StatusBarButton} 856 */ 857 _createButtonAndRegisterShortcutsForAction: function(buttonId, buttonTitle, actionId) 858 { 859 /** 860 * @return {boolean} 861 */ 862 function handler() 863 { 864 return WebInspector.actionRegistry.execute(actionId); 865 } 866 var shortcuts = WebInspector.shortcutRegistry.shortcutDescriptorsForAction(actionId); 867 return this._createButtonAndRegisterShortcuts(buttonId, buttonTitle, handler, shortcuts); 868 }, 869 870 addToWatch: function(expression) 871 { 872 this.sidebarPanes.watchExpressions.addExpression(expression); 873 }, 874 875 _installDebuggerSidebarController: function() 876 { 877 this._toggleNavigatorSidebarButton = this.editorView.createShowHideSidebarButton("navigator", "scripts-navigator-show-hide-button"); 878 this.editorView.mainElement().appendChild(this._toggleNavigatorSidebarButton.element); 879 880 this._toggleDebuggerSidebarButton = this._splitView.createShowHideSidebarButton("debugger", "scripts-debugger-show-hide-button"); 881 882 this._splitView.mainElement().appendChild(this._toggleDebuggerSidebarButton.element); 883 this._splitView.mainElement().appendChild(this._debugSidebarResizeWidgetElement); 884 }, 885 886 _updateDebugSidebarResizeWidget: function() 887 { 888 this._debugSidebarResizeWidgetElement.classList.toggle("hidden", this._splitView.showMode() !== WebInspector.SplitView.ShowMode.Both); 889 }, 890 891 /** 892 * @param {!WebInspector.UISourceCode} uiSourceCode 893 */ 894 _showLocalHistory: function(uiSourceCode) 895 { 896 WebInspector.RevisionHistoryView.showHistory(uiSourceCode); 897 }, 898 899 /** 900 * @param {!Event} event 901 * @param {!WebInspector.ContextMenu} contextMenu 902 * @param {!Object} target 903 */ 904 appendApplicableItems: function(event, contextMenu, target) 905 { 906 this._appendUISourceCodeItems(event, contextMenu, target); 907 this._appendRemoteObjectItems(contextMenu, target); 908 }, 909 910 _suggestReload: function() 911 { 912 if (window.confirm(WebInspector.UIString("It is recommended to restart inspector after making these changes. Would you like to restart it?"))) 913 WebInspector.reload(); 914 }, 915 916 /** 917 * @param {!WebInspector.UISourceCode} uiSourceCode 918 */ 919 _mapFileSystemToNetwork: function(uiSourceCode) 920 { 921 WebInspector.SelectUISourceCodeForProjectTypesDialog.show(uiSourceCode.name(), [WebInspector.projectTypes.Network, WebInspector.projectTypes.ContentScripts], mapFileSystemToNetwork.bind(this), this.editorView.mainElement()) 922 923 /** 924 * @param {!WebInspector.UISourceCode} networkUISourceCode 925 * @this {WebInspector.SourcesPanel} 926 */ 927 function mapFileSystemToNetwork(networkUISourceCode) 928 { 929 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding); 930 this._suggestReload(); 931 } 932 }, 933 934 /** 935 * @param {!WebInspector.UISourceCode} uiSourceCode 936 */ 937 _removeNetworkMapping: function(uiSourceCode) 938 { 939 if (confirm(WebInspector.UIString("Are you sure you want to remove network mapping?"))) { 940 this._workspace.removeMapping(uiSourceCode); 941 this._suggestReload(); 942 } 943 }, 944 945 /** 946 * @param {!WebInspector.UISourceCode} networkUISourceCode 947 */ 948 _mapNetworkToFileSystem: function(networkUISourceCode) 949 { 950 WebInspector.SelectUISourceCodeForProjectTypesDialog.show(networkUISourceCode.name(), [WebInspector.projectTypes.FileSystem], mapNetworkToFileSystem.bind(this), this.editorView.mainElement()) 951 952 /** 953 * @param {!WebInspector.UISourceCode} uiSourceCode 954 * @this {WebInspector.SourcesPanel} 955 */ 956 function mapNetworkToFileSystem(uiSourceCode) 957 { 958 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding); 959 this._suggestReload(); 960 } 961 }, 962 963 /** 964 * @param {!WebInspector.ContextMenu} contextMenu 965 * @param {!WebInspector.UISourceCode} uiSourceCode 966 */ 967 _appendUISourceCodeMappingItems: function(contextMenu, uiSourceCode) 968 { 969 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) { 970 var hasMappings = !!uiSourceCode.url; 971 if (!hasMappings) 972 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to network resource\u2026" : "Map to Network Resource\u2026"), this._mapFileSystemToNetwork.bind(this, uiSourceCode)); 973 else 974 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove network mapping" : "Remove Network Mapping"), this._removeNetworkMapping.bind(this, uiSourceCode)); 975 } 976 977 /** 978 * @param {!WebInspector.Project} project 979 */ 980 function filterProject(project) 981 { 982 return project.type() === WebInspector.projectTypes.FileSystem; 983 } 984 985 if (uiSourceCode.project().type() === WebInspector.projectTypes.Network || uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts) { 986 if (!this._workspace.projects().filter(filterProject).length) 987 return; 988 if (this._workspace.uiSourceCodeForURL(uiSourceCode.url) === uiSourceCode) 989 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to file system resource\u2026" : "Map to File System Resource\u2026"), this._mapNetworkToFileSystem.bind(this, uiSourceCode)); 990 } 991 }, 992 993 /** 994 * @param {!Event} event 995 * @param {!WebInspector.ContextMenu} contextMenu 996 * @param {!Object} target 997 */ 998 _appendUISourceCodeItems: function(event, contextMenu, target) 999 { 1000 if (!(target instanceof WebInspector.UISourceCode)) 1001 return; 1002 1003 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target); 1004 var projectType = uiSourceCode.project().type(); 1005 if (projectType !== WebInspector.projectTypes.FileSystem) 1006 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Local modifications\u2026" : "Local Modifications\u2026"), this._showLocalHistory.bind(this, uiSourceCode)); 1007 this._appendUISourceCodeMappingItems(contextMenu, uiSourceCode); 1008 1009 var contentType = uiSourceCode.contentType(); 1010 if ((contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document) && projectType !== WebInspector.projectTypes.Snippets) 1011 this.sidebarPanes.callstack.appendBlackboxURLContextMenuItems(contextMenu, uiSourceCode.url, projectType === WebInspector.projectTypes.ContentScripts); 1012 1013 if (!event.target.isSelfOrDescendant(this.editorView.sidebarElement())) { 1014 contextMenu.appendSeparator(); 1015 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in navigator" : "Reveal in Navigator"), this._handleContextMenuReveal.bind(this, uiSourceCode)); 1016 } 1017 }, 1018 1019 /** 1020 * @param {!WebInspector.UISourceCode} uiSourceCode 1021 */ 1022 _handleContextMenuReveal: function(uiSourceCode) 1023 { 1024 this.editorView.showBoth(); 1025 this._revealInNavigator(uiSourceCode); 1026 }, 1027 1028 /** 1029 * @param {!WebInspector.ContextMenu} contextMenu 1030 * @param {!Object} target 1031 */ 1032 _appendRemoteObjectItems: function(contextMenu, target) 1033 { 1034 if (!(target instanceof WebInspector.RemoteObject)) 1035 return; 1036 var remoteObject = /** @type {!WebInspector.RemoteObject} */ (target); 1037 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Store as global variable" : "Store as Global Variable"), this._saveToTempVariable.bind(this, remoteObject)); 1038 if (remoteObject.type === "function") 1039 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show function definition" : "Show Function Definition"), this._showFunctionDefinition.bind(this, remoteObject)); 1040 }, 1041 1042 /** 1043 * @param {!WebInspector.RemoteObject} remoteObject 1044 */ 1045 _saveToTempVariable: function(remoteObject) 1046 { 1047 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext); 1048 if (!currentExecutionContext) 1049 return; 1050 1051 currentExecutionContext.evaluate("this", "", false, true, false, false, didGetGlobalObject.bind(null, currentExecutionContext.target())); 1052 /** 1053 * @param {!WebInspector.Target} target 1054 * @param {?WebInspector.RemoteObject} global 1055 * @param {boolean=} wasThrown 1056 */ 1057 function didGetGlobalObject(target, global, wasThrown) 1058 { 1059 /** 1060 * @suppressReceiverCheck 1061 * @this {Window} 1062 */ 1063 function remoteFunction(value) 1064 { 1065 var prefix = "temp"; 1066 var index = 1; 1067 while ((prefix + index) in this) 1068 ++index; 1069 var name = prefix + index; 1070 this[name] = value; 1071 return name; 1072 } 1073 1074 if (wasThrown || !global) 1075 failedToSave(target, global); 1076 else 1077 global.callFunction(remoteFunction, [WebInspector.RemoteObject.toCallArgument(remoteObject)], didSave.bind(null, global)); 1078 } 1079 1080 /** 1081 * @param {!WebInspector.RemoteObject} global 1082 * @param {?WebInspector.RemoteObject} result 1083 * @param {boolean=} wasThrown 1084 */ 1085 function didSave(global, result, wasThrown) 1086 { 1087 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext); 1088 global.release(); 1089 if (!currentExecutionContext || wasThrown || !result || result.type !== "string") 1090 failedToSave(global.target(), result); 1091 else 1092 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, result.value); 1093 } 1094 1095 /** 1096 * @param {!WebInspector.Target} target 1097 * @param {?WebInspector.RemoteObject} result 1098 */ 1099 function failedToSave(target, result) 1100 { 1101 var message = WebInspector.UIString("Failed to save to temp variable."); 1102 if (result) { 1103 message += " " + result.description; 1104 result.release(); 1105 } 1106 WebInspector.console.error(message); 1107 } 1108 }, 1109 1110 /** 1111 * @param {!WebInspector.RemoteObject} remoteObject 1112 */ 1113 _showFunctionDefinition: function(remoteObject) 1114 { 1115 var debuggerModel = remoteObject.target().debuggerModel; 1116 1117 /** 1118 * @param {?WebInspector.DebuggerModel.FunctionDetails} response 1119 * @this {WebInspector.SourcesPanel} 1120 */ 1121 function didGetFunctionDetails(response) 1122 { 1123 if (!response || !response.location) 1124 return; 1125 1126 var location = response.location; 1127 if (!location) 1128 return; 1129 1130 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(location); 1131 if (uiLocation) 1132 this.showUILocation(uiLocation, true); 1133 } 1134 debuggerModel.functionDetails(remoteObject, didGetFunctionDetails.bind(this)); 1135 }, 1136 1137 showGoToSourceDialog: function() 1138 { 1139 this._sourcesView.showOpenResourceDialog(); 1140 }, 1141 1142 _dockSideChanged: function() 1143 { 1144 var vertically = WebInspector.dockController.isVertical() && WebInspector.settings.splitVerticallyWhenDockedToRight.get(); 1145 this._splitVertically(vertically); 1146 }, 1147 1148 /** 1149 * @param {boolean} vertically 1150 */ 1151 _splitVertically: function(vertically) 1152 { 1153 if (this.sidebarPaneView && vertically === !this._splitView.isVertical()) 1154 return; 1155 1156 if (this.sidebarPaneView) 1157 this.sidebarPaneView.detach(); 1158 1159 this._splitView.setVertical(!vertically); 1160 1161 if (!vertically) 1162 this._splitView.uninstallResizer(this._sourcesView.statusBarContainerElement()); 1163 else 1164 this._splitView.installResizer(this._sourcesView.statusBarContainerElement()); 1165 1166 // Create vertical box with stack. 1167 var vbox = new WebInspector.VBox(); 1168 vbox.element.appendChild(this._debugToolbarDrawer); 1169 vbox.element.appendChild(this.debugToolbar); 1170 vbox.setMinimumAndPreferredSizes(25, 25, WebInspector.SourcesPanel.minToolbarWidth, 100); 1171 var sidebarPaneStack = new WebInspector.SidebarPaneStack(); 1172 sidebarPaneStack.element.classList.add("flex-auto"); 1173 sidebarPaneStack.show(vbox.element); 1174 1175 if (!vertically) { 1176 // Populate the only stack. 1177 for (var pane in this.sidebarPanes) 1178 sidebarPaneStack.addPane(this.sidebarPanes[pane]); 1179 this._extensionSidebarPanesContainer = sidebarPaneStack; 1180 this.sidebarPaneView = vbox; 1181 } else { 1182 var splitView = new WebInspector.SplitView(true, true, "sourcesPanelDebuggerSidebarSplitViewState", 0.5); 1183 vbox.show(splitView.mainElement()); 1184 1185 // Populate the left stack. 1186 sidebarPaneStack.addPane(this.sidebarPanes.threads); 1187 sidebarPaneStack.addPane(this.sidebarPanes.callstack); 1188 sidebarPaneStack.addPane(this.sidebarPanes.jsBreakpoints); 1189 sidebarPaneStack.addPane(this.sidebarPanes.domBreakpoints); 1190 sidebarPaneStack.addPane(this.sidebarPanes.xhrBreakpoints); 1191 sidebarPaneStack.addPane(this.sidebarPanes.eventListenerBreakpoints); 1192 1193 var tabbedPane = new WebInspector.SidebarTabbedPane(); 1194 tabbedPane.show(splitView.sidebarElement()); 1195 tabbedPane.addPane(this.sidebarPanes.scopechain); 1196 tabbedPane.addPane(this.sidebarPanes.watchExpressions); 1197 this._extensionSidebarPanesContainer = tabbedPane; 1198 1199 this.sidebarPaneView = splitView; 1200 } 1201 for (var i = 0; i < this._extensionSidebarPanes.length; ++i) 1202 this._extensionSidebarPanesContainer.addPane(this._extensionSidebarPanes[i]); 1203 1204 this.sidebarPaneView.show(this._splitView.sidebarElement()); 1205 this.sidebarPanes.threads.expand(); 1206 this.sidebarPanes.scopechain.expand(); 1207 this.sidebarPanes.jsBreakpoints.expand(); 1208 this.sidebarPanes.callstack.expand(); 1209 this._sidebarPaneStack = sidebarPaneStack; 1210 this._updateTargetsSidebarVisibility(); 1211 if (WebInspector.settings.watchExpressions.get().length > 0) 1212 this.sidebarPanes.watchExpressions.expand(); 1213 }, 1214 1215 /** 1216 * @param {string} id 1217 * @param {!WebInspector.SidebarPane} pane 1218 */ 1219 addExtensionSidebarPane: function(id, pane) 1220 { 1221 this._extensionSidebarPanes.push(pane); 1222 this._extensionSidebarPanesContainer.addPane(pane); 1223 this.setHideOnDetach(); 1224 }, 1225 1226 /** 1227 * @return {!WebInspector.SourcesView} 1228 */ 1229 sourcesView: function() 1230 { 1231 return this._sourcesView; 1232 }, 1233 1234 /** 1235 * @param {!WebInspector.Target} target 1236 */ 1237 targetAdded: function(target) 1238 { 1239 this._updateTargetsSidebarVisibility(); 1240 }, 1241 1242 /** 1243 * @param {!WebInspector.Target} target 1244 */ 1245 targetRemoved: function(target) 1246 { 1247 this._updateTargetsSidebarVisibility(); 1248 }, 1249 1250 _updateTargetsSidebarVisibility: function() 1251 { 1252 if (!this._sidebarPaneStack) 1253 return; 1254 this._sidebarPaneStack.togglePaneHidden(this.sidebarPanes.threads, WebInspector.targetManager.targets().length < 2); 1255 }, 1256 1257 __proto__: WebInspector.Panel.prototype 1258 } 1259 1260 /** 1261 * @constructor 1262 * @param {!Element} element 1263 */ 1264 WebInspector.UpgradeFileSystemDropTarget = function(element) 1265 { 1266 element.addEventListener("dragenter", this._onDragEnter.bind(this), true); 1267 element.addEventListener("dragover", this._onDragOver.bind(this), true); 1268 this._element = element; 1269 } 1270 1271 WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType = "Files"; 1272 1273 WebInspector.UpgradeFileSystemDropTarget.prototype = { 1274 _onDragEnter: function (event) 1275 { 1276 if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1) 1277 return; 1278 event.consume(true); 1279 }, 1280 1281 _onDragOver: function (event) 1282 { 1283 if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1) 1284 return; 1285 event.dataTransfer.dropEffect = "copy"; 1286 event.consume(true); 1287 if (this._dragMaskElement) 1288 return; 1289 this._dragMaskElement = this._element.createChild("div", "fill drag-mask"); 1290 this._dragMaskElement.createChild("div", "fill drag-mask-inner").textContent = WebInspector.UIString("Drop workspace folder here"); 1291 this._dragMaskElement.addEventListener("drop", this._onDrop.bind(this), true); 1292 this._dragMaskElement.addEventListener("dragleave", this._onDragLeave.bind(this), true); 1293 }, 1294 1295 _onDrop: function (event) 1296 { 1297 event.consume(true); 1298 this._removeMask(); 1299 var items = /** @type {!Array.<!DataTransferItem>} */ (event.dataTransfer.items); 1300 if (!items.length) 1301 return; 1302 var entry = items[0].webkitGetAsEntry(); 1303 if (!entry.isDirectory) 1304 return; 1305 InspectorFrontendHost.upgradeDraggedFileSystemPermissions(entry.filesystem); 1306 }, 1307 1308 _onDragLeave: function (event) 1309 { 1310 event.consume(true); 1311 this._removeMask(); 1312 }, 1313 1314 _removeMask: function () 1315 { 1316 this._dragMaskElement.remove(); 1317 delete this._dragMaskElement; 1318 } 1319 } 1320 1321 /** 1322 * @constructor 1323 * @implements {WebInspector.ContextMenu.Provider} 1324 */ 1325 WebInspector.SourcesPanel.ContextMenuProvider = function() 1326 { 1327 } 1328 1329 WebInspector.SourcesPanel.ContextMenuProvider.prototype = { 1330 /** 1331 * @param {!Event} event 1332 * @param {!WebInspector.ContextMenu} contextMenu 1333 * @param {!Object} target 1334 */ 1335 appendApplicableItems: function(event, contextMenu, target) 1336 { 1337 WebInspector.inspectorView.panel("sources").appendApplicableItems(event, contextMenu, target); 1338 } 1339 } 1340 1341 /** 1342 * @constructor 1343 * @implements {WebInspector.Revealer} 1344 */ 1345 WebInspector.SourcesPanel.UILocationRevealer = function() 1346 { 1347 } 1348 1349 WebInspector.SourcesPanel.UILocationRevealer.prototype = { 1350 /** 1351 * @param {!Object} uiLocation 1352 */ 1353 reveal: function(uiLocation) 1354 { 1355 if (uiLocation instanceof WebInspector.UILocation) 1356 /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUILocation(uiLocation); 1357 } 1358 } 1359 1360 /** 1361 * @constructor 1362 * @implements {WebInspector.Revealer} 1363 */ 1364 WebInspector.SourcesPanel.UISourceCodeRevealer = function() 1365 { 1366 } 1367 1368 WebInspector.SourcesPanel.UISourceCodeRevealer.prototype = { 1369 /** 1370 * @param {!Object} uiSourceCode 1371 */ 1372 reveal: function(uiSourceCode) 1373 { 1374 if (uiSourceCode instanceof WebInspector.UISourceCode) 1375 /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUISourceCode(uiSourceCode); 1376 } 1377 } 1378 1379 /** 1380 * @constructor 1381 * @implements {WebInspector.ActionDelegate} 1382 */ 1383 WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate = function() {} 1384 1385 WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate.prototype = { 1386 /** 1387 * @return {boolean} 1388 */ 1389 handleAction: function() 1390 { 1391 var panel = /** @type {?WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources")); 1392 if (!panel) 1393 return false; 1394 panel.showGoToSourceDialog(); 1395 return true; 1396 } 1397 } 1398 1399 /** 1400 * @constructor 1401 * @extends {WebInspector.UISettingDelegate} 1402 */ 1403 WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate = function() 1404 { 1405 WebInspector.UISettingDelegate.call(this); 1406 } 1407 1408 WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate.prototype = { 1409 /** 1410 * @override 1411 * @return {!Element} 1412 */ 1413 settingElement: function() 1414 { 1415 var disableJSElement = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Disable JavaScript"), WebInspector.settings.javaScriptDisabled); 1416 this._disableJSCheckbox = disableJSElement.getElementsByTagName("input")[0]; 1417 WebInspector.settings.javaScriptDisabled.addChangeListener(this._settingChanged, this); 1418 var disableJSInfoParent = this._disableJSCheckbox.parentElement.createChild("span", "monospace"); 1419 this._disableJSInfo = disableJSInfoParent.createChild("span", "object-info-state-note hidden"); 1420 this._disableJSInfo.title = WebInspector.UIString("JavaScript is blocked on the inspected page (may be disabled in browser settings)."); 1421 1422 WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.MainFrameNavigated, this._updateScriptDisabledCheckbox, this); 1423 this._updateScriptDisabledCheckbox(); 1424 return disableJSElement; 1425 }, 1426 1427 /** 1428 * @param {!WebInspector.Event} event 1429 */ 1430 _settingChanged: function(event) 1431 { 1432 PageAgent.setScriptExecutionDisabled(event.data, this._updateScriptDisabledCheckbox.bind(this)); 1433 }, 1434 1435 _updateScriptDisabledCheckbox: function() 1436 { 1437 PageAgent.getScriptExecutionStatus(executionStatusCallback.bind(this)); 1438 1439 /** 1440 * @param {?Protocol.Error} error 1441 * @param {string} status 1442 * @this {WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate} 1443 */ 1444 function executionStatusCallback(error, status) 1445 { 1446 if (error || !status) 1447 return; 1448 1449 var forbidden = (status === "forbidden"); 1450 var disabled = forbidden || (status === "disabled"); 1451 1452 this._disableJSInfo.classList.toggle("hidden", !forbidden); 1453 this._disableJSCheckbox.checked = disabled; 1454 this._disableJSCheckbox.disabled = forbidden; 1455 } 1456 }, 1457 1458 __proto__: WebInspector.UISettingDelegate.prototype 1459 } 1460 1461 /** 1462 * @constructor 1463 * @implements {WebInspector.ActionDelegate} 1464 */ 1465 WebInspector.SourcesPanel.TogglePauseActionDelegate = function() 1466 { 1467 } 1468 1469 WebInspector.SourcesPanel.TogglePauseActionDelegate.prototype = { 1470 /** 1471 * @return {boolean} 1472 */ 1473 handleAction: function() 1474 { 1475 var panel = /** @type {?WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources")); 1476 if (!panel) 1477 return false; 1478 panel.togglePause(); 1479 return true; 1480 } 1481 } 1482