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 27importScript("BreakpointsSidebarPane.js"); 28importScript("CallStackSidebarPane.js"); 29importScript("FilePathScoreFunction.js"); 30importScript("FilteredItemSelectionDialog.js"); 31importScript("UISourceCodeFrame.js"); 32importScript("JavaScriptSourceFrame.js"); 33importScript("CSSSourceFrame.js"); 34importScript("NavigatorOverlayController.js"); 35importScript("NavigatorView.js"); 36importScript("RevisionHistoryView.js"); 37importScript("ScopeChainSidebarPane.js"); 38importScript("SourcesNavigator.js"); 39importScript("SourcesSearchScope.js"); 40importScript("StyleSheetOutlineDialog.js"); 41importScript("TabbedEditorContainer.js"); 42importScript("WatchExpressionsSidebarPane.js"); 43importScript("WorkersSidebarPane.js"); 44 45/** 46 * @constructor 47 * @implements {WebInspector.TabbedEditorContainerDelegate} 48 * @implements {WebInspector.ContextMenu.Provider} 49 * @implements {WebInspector.Searchable} 50 * @extends {WebInspector.Panel} 51 * @param {!WebInspector.Workspace=} workspaceForTest 52 */ 53WebInspector.SourcesPanel = function(workspaceForTest) 54{ 55 WebInspector.Panel.call(this, "sources"); 56 this.registerRequiredCSS("sourcesPanel.css"); 57 this.registerRequiredCSS("textPrompt.css"); // Watch Expressions autocomplete. 58 59 WebInspector.settings.navigatorWasOnceHidden = WebInspector.settings.createSetting("navigatorWasOnceHidden", false); 60 WebInspector.settings.debuggerSidebarHidden = WebInspector.settings.createSetting("debuggerSidebarHidden", false); 61 WebInspector.settings.showEditorInDrawer = WebInspector.settings.createSetting("showEditorInDrawer", true); 62 63 this._workspace = workspaceForTest || WebInspector.workspace; 64 65 /** 66 * @return {!WebInspector.View} 67 * @this {WebInspector.SourcesPanel} 68 */ 69 function viewGetter() 70 { 71 return this.visibleView; 72 } 73 WebInspector.GoToLineDialog.install(this, viewGetter.bind(this)); 74 75 var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Sources Panel")); 76 this.debugToolbar = this._createDebugToolbar(); 77 78 const initialDebugSidebarWidth = 225; 79 const minimumDebugSidebarWidthPercent = 0.5; 80 this.createSidebarView(this.element, WebInspector.SidebarView.SidebarPosition.End, initialDebugSidebarWidth); 81 this.splitView.element.id = "scripts-split-view"; 82 this.splitView.setSidebarElementConstraints(Preferences.minScriptsSidebarWidth); 83 this.splitView.setMainElementConstraints(minimumDebugSidebarWidthPercent); 84 85 // Create scripts navigator 86 const initialNavigatorWidth = 225; 87 const minimumViewsContainerWidthPercent = 0.5; 88 this.editorView = new WebInspector.SidebarView(WebInspector.SidebarView.SidebarPosition.Start, "scriptsPanelNavigatorSidebarWidth", initialNavigatorWidth); 89 this.editorView.element.id = "scripts-editor-split-view"; 90 this.editorView.element.tabIndex = 0; 91 92 this.editorView.setSidebarElementConstraints(Preferences.minScriptsSidebarWidth); 93 this.editorView.setMainElementConstraints(minimumViewsContainerWidthPercent); 94 this.editorView.show(this.splitView.mainElement); 95 96 this._navigator = new WebInspector.SourcesNavigator(); 97 this._navigator.view.show(this.editorView.sidebarElement); 98 99 var tabbedEditorPlaceholderText = WebInspector.isMac() ? WebInspector.UIString("Hit Cmd+O to open a file") : WebInspector.UIString("Hit Ctrl+O to open a file"); 100 101 this.editorView.mainElement.classList.add("vbox"); 102 this.editorView.sidebarElement.classList.add("vbox"); 103 104 this.sourcesView = new WebInspector.SourcesView(); 105 106 this._searchableView = new WebInspector.SearchableView(this); 107 this._searchableView.setMinimalSearchQuerySize(0); 108 this._searchableView.show(this.sourcesView.element); 109 110 this._editorContainer = new WebInspector.TabbedEditorContainer(this, "previouslyViewedFiles", tabbedEditorPlaceholderText); 111 this._editorContainer.show(this._searchableView.element); 112 113 this._navigatorController = new WebInspector.NavigatorOverlayController(this.editorView, this._navigator.view, this._editorContainer.view); 114 115 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.SourceSelected, this._sourceSelected, this); 116 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.ItemSearchStarted, this._itemSearchStarted, this); 117 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.ItemCreationRequested, this._itemCreationRequested, this); 118 this._navigator.addEventListener(WebInspector.SourcesNavigator.Events.ItemRenamingRequested, this._itemRenamingRequested, this); 119 120 this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorSelected, this._editorSelected, this); 121 this._editorContainer.addEventListener(WebInspector.TabbedEditorContainer.Events.EditorClosed, this._editorClosed, this); 122 123 this._debugSidebarResizeWidgetElement = document.createElementWithClass("div", "resizer-widget"); 124 this._debugSidebarResizeWidgetElement.id = "scripts-debug-sidebar-resizer-widget"; 125 this.splitView.installResizer(this._debugSidebarResizeWidgetElement); 126 127 this.sidebarPanes = {}; 128 this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane(); 129 this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); 130 this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, this._callFrameSelectedInSidebar.bind(this)); 131 this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, this._callFrameRestartedInSidebar.bind(this)); 132 133 this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); 134 this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(WebInspector.breakpointManager, this._showSourceLocation.bind(this)); 135 this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this); 136 this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane(); 137 this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane(); 138 139 if (Capabilities.canInspectWorkers && !WebInspector.WorkerManager.isWorkerFrontend()) { 140 WorkerAgent.enable(); 141 this.sidebarPanes.workerList = new WebInspector.WorkersSidebarPane(WebInspector.workerManager); 142 } 143 144 this.sidebarPanes.callstack.registerShortcuts(this.registerShortcuts.bind(this)); 145 this.registerShortcuts(WebInspector.SourcesPanelDescriptor.ShortcutKeys.GoToMember, this._showOutlineDialog.bind(this)); 146 this.registerShortcuts(WebInspector.SourcesPanelDescriptor.ShortcutKeys.ToggleBreakpoint, this._toggleBreakpoint.bind(this)); 147 148 this._extensionSidebarPanes = []; 149 150 this._toggleFormatSourceButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "sources-toggle-pretty-print-status-bar-item"); 151 this._toggleFormatSourceButton.toggled = false; 152 this._toggleFormatSourceButton.addEventListener("click", this._toggleFormatSource, this); 153 154 this._scriptViewStatusBarItemsContainer = document.createElement("div"); 155 this._scriptViewStatusBarItemsContainer.className = "inline-block"; 156 157 this._scriptViewStatusBarTextContainer = document.createElement("div"); 158 this._scriptViewStatusBarTextContainer.className = "inline-block"; 159 160 this._statusBarContainerElement = this.sourcesView.element.createChild("div", "sources-status-bar"); 161 this._statusBarContainerElement.appendChild(this._toggleFormatSourceButton.element); 162 this._statusBarContainerElement.appendChild(this._scriptViewStatusBarItemsContainer); 163 this._statusBarContainerElement.appendChild(this._scriptViewStatusBarTextContainer); 164 165 this._installDebuggerSidebarController(); 166 167 WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this)); 168 WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this)); 169 this._dockSideChanged(); 170 171 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.SourceFrame>} */ 172 this._sourceFramesByUISourceCode = new Map(); 173 this._updateDebuggerButtons(); 174 this._pauseOnExceptionStateChanged(); 175 if (WebInspector.debuggerModel.isPaused()) 176 this._showDebuggerPausedDetails(); 177 178 WebInspector.settings.pauseOnExceptionStateString.addChangeListener(this._pauseOnExceptionStateChanged, this); 179 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this); 180 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerWasDisabled, this); 181 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); 182 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); 183 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this); 184 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this); 185 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this); 186 187 WebInspector.startBatchUpdate(); 188 this._workspace.uiSourceCodes().forEach(this._addUISourceCode.bind(this)); 189 WebInspector.endBatchUpdate(); 190 191 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); 192 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this); 193 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectWillReset, this._projectWillReset.bind(this), this); 194 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this); 195 196 WebInspector.advancedSearchController.registerSearchScope(new WebInspector.SourcesSearchScope(this._workspace)); 197 198 this._boundOnKeyUp = this._onKeyUp.bind(this); 199 this._boundOnKeyDown = this._onKeyDown.bind(this); 200 201 function handleBeforeUnload(event) 202 { 203 if (event.returnValue) 204 return; 205 var unsavedSourceCodes = WebInspector.workspace.unsavedSourceCodes(); 206 if (!unsavedSourceCodes.length) 207 return; 208 209 event.returnValue = WebInspector.UIString("DevTools have unsaved changes that will be permanently lost."); 210 WebInspector.showPanel("sources"); 211 for (var i = 0; i < unsavedSourceCodes.length; ++i) 212 WebInspector.panels.sources.showUISourceCode(unsavedSourceCodes[i]); 213 } 214 window.addEventListener("beforeunload", handleBeforeUnload.bind(this), true); 215} 216 217WebInspector.SourcesPanel.prototype = { 218 defaultFocusedElement: function() 219 { 220 return this._editorContainer.view.defaultFocusedElement() || this._navigator.view.defaultFocusedElement(); 221 }, 222 223 get paused() 224 { 225 return this._paused; 226 }, 227 228 wasShown: function() 229 { 230 WebInspector.inspectorView.closeViewInDrawer("editor"); 231 this.sourcesView.show(this.editorView.mainElement); 232 WebInspector.Panel.prototype.wasShown.call(this); 233 this._navigatorController.wasShown(); 234 235 this.element.addEventListener("keydown", this._boundOnKeyDown, false); 236 this.element.addEventListener("keyup", this._boundOnKeyUp, false); 237 }, 238 239 willHide: function() 240 { 241 this.element.removeEventListener("keydown", this._boundOnKeyDown, false); 242 this.element.removeEventListener("keyup", this._boundOnKeyUp, false); 243 244 WebInspector.Panel.prototype.willHide.call(this); 245 }, 246 247 /** 248 * @return {!WebInspector.SearchableView} 249 */ 250 searchableView: function() 251 { 252 return this._searchableView; 253 }, 254 255 /** 256 * @param {!WebInspector.Event} event 257 */ 258 _uiSourceCodeAdded: function(event) 259 { 260 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 261 this._addUISourceCode(uiSourceCode); 262 }, 263 264 /** 265 * @param {!WebInspector.UISourceCode} uiSourceCode 266 */ 267 _addUISourceCode: function(uiSourceCode) 268 { 269 if (this._toggleFormatSourceButton.toggled) 270 uiSourceCode.setFormatted(true); 271 if (uiSourceCode.project().isServiceProject()) 272 return; 273 this._navigator.addUISourceCode(uiSourceCode); 274 this._editorContainer.addUISourceCode(uiSourceCode); 275 // Replace debugger script-based uiSourceCode with a network-based one. 276 var currentUISourceCode = this._currentUISourceCode; 277 if (currentUISourceCode && currentUISourceCode.project().isServiceProject() && currentUISourceCode !== uiSourceCode && currentUISourceCode.url === uiSourceCode.url) { 278 this._showFile(uiSourceCode); 279 this._editorContainer.removeUISourceCode(currentUISourceCode); 280 } 281 }, 282 283 _uiSourceCodeRemoved: function(event) 284 { 285 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 286 this._removeUISourceCodes([uiSourceCode]); 287 }, 288 289 /** 290 * @param {!Array.<!WebInspector.UISourceCode>} uiSourceCodes 291 */ 292 _removeUISourceCodes: function(uiSourceCodes) 293 { 294 for (var i = 0; i < uiSourceCodes.length; ++i) { 295 this._navigator.removeUISourceCode(uiSourceCodes[i]); 296 this._removeSourceFrame(uiSourceCodes[i]); 297 } 298 this._editorContainer.removeUISourceCodes(uiSourceCodes); 299 }, 300 301 _consoleCommandEvaluatedInSelectedCallFrame: function(event) 302 { 303 this.sidebarPanes.scopechain.update(WebInspector.debuggerModel.selectedCallFrame()); 304 }, 305 306 _debuggerPaused: function() 307 { 308 WebInspector.inspectorView.setCurrentPanel(this); 309 this._showDebuggerPausedDetails(); 310 }, 311 312 _showDebuggerPausedDetails: function() 313 { 314 var details = WebInspector.debuggerModel.debuggerPausedDetails(); 315 316 this._paused = true; 317 this._waitingToPause = false; 318 this._stepping = false; 319 320 this._updateDebuggerButtons(); 321 322 this.sidebarPanes.callstack.update(details.callFrames, details.asyncStackTrace); 323 324 /** 325 * @param {!Element} element 326 * @this {WebInspector.SourcesPanel} 327 */ 328 function didCreateBreakpointHitStatusMessage(element) 329 { 330 this.sidebarPanes.callstack.setStatus(element); 331 } 332 333 /** 334 * @param {!WebInspector.UILocation} uiLocation 335 * @this {WebInspector.SourcesPanel} 336 */ 337 function didGetUILocation(uiLocation) 338 { 339 var breakpoint = WebInspector.breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber); 340 if (!breakpoint) 341 return; 342 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(breakpoint); 343 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint.")); 344 } 345 346 if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) { 347 WebInspector.domBreakpointsSidebarPane.highlightBreakpoint(details.auxData); 348 WebInspector.domBreakpointsSidebarPane.createBreakpointHitStatusMessage(details.auxData, didCreateBreakpointHitStatusMessage.bind(this)); 349 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) { 350 var eventName = details.auxData.eventName; 351 this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.auxData.eventName); 352 var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName, details.auxData); 353 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI)); 354 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) { 355 this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]); 356 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest.")); 357 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception) 358 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData.description)); 359 else if (details.reason === WebInspector.DebuggerModel.BreakReason.Assert) 360 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on assertion.")); 361 else if (details.reason === WebInspector.DebuggerModel.BreakReason.CSPViolation) 362 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a script blocked due to Content Security Policy directive: \"%s\".", details.auxData["directiveText"])); 363 else if (details.reason === WebInspector.DebuggerModel.BreakReason.DebugCommand) 364 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a debugged function")); 365 else { 366 if (details.callFrames.length) 367 details.callFrames[0].createLiveLocation(didGetUILocation.bind(this)); 368 else 369 console.warn("ScriptsPanel paused, but callFrames.length is zero."); // TODO remove this once we understand this case better 370 } 371 372 this._enableDebuggerSidebar(true); 373 this._toggleDebuggerSidebarButton.setEnabled(false); 374 window.focus(); 375 InspectorFrontendHost.bringToFront(); 376 }, 377 378 _debuggerResumed: function() 379 { 380 this._paused = false; 381 this._waitingToPause = false; 382 this._stepping = false; 383 384 this._clearInterface(); 385 this._toggleDebuggerSidebarButton.setEnabled(true); 386 }, 387 388 _debuggerWasEnabled: function() 389 { 390 this._updateDebuggerButtons(); 391 }, 392 393 _debuggerWasDisabled: function() 394 { 395 this._debuggerReset(); 396 }, 397 398 _debuggerReset: function() 399 { 400 this._debuggerResumed(); 401 this.sidebarPanes.watchExpressions.reset(); 402 delete this._skipExecutionLineRevealing; 403 }, 404 405 _projectWillReset: function(event) 406 { 407 var project = event.data; 408 var uiSourceCodes = project.uiSourceCodes(); 409 this._removeUISourceCodes(uiSourceCodes); 410 if (project.type() === WebInspector.projectTypes.Network) 411 this._editorContainer.reset(); 412 }, 413 414 get visibleView() 415 { 416 return this._editorContainer.visibleView; 417 }, 418 419 _updateScriptViewStatusBarItems: function() 420 { 421 this._scriptViewStatusBarItemsContainer.removeChildren(); 422 this._scriptViewStatusBarTextContainer.removeChildren(); 423 424 var sourceFrame = this.visibleView; 425 if (sourceFrame) { 426 var statusBarItems = sourceFrame.statusBarItems() || []; 427 for (var i = 0; i < statusBarItems.length; ++i) 428 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]); 429 var statusBarText = sourceFrame.statusBarText(); 430 if (statusBarText) 431 this._scriptViewStatusBarTextContainer.appendChild(statusBarText); 432 } 433 }, 434 435 /** 436 * @param {!Element} anchor 437 * @return {boolean} 438 */ 439 showAnchorLocation: function(anchor) 440 { 441 if (!anchor.uiSourceCode) { 442 var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(anchor.href); 443 if (uiSourceCode) 444 anchor.uiSourceCode = uiSourceCode; 445 } 446 if (!anchor.uiSourceCode) 447 return false; 448 449 this._showSourceLocation(anchor.uiSourceCode, anchor.lineNumber, anchor.columnNumber); 450 return true; 451 }, 452 453 /** 454 * @param {!WebInspector.UISourceCode} uiSourceCode 455 * @param {number=} lineNumber 456 * @param {number=} columnNumber 457 * @param {boolean=} forceShowInPanel 458 */ 459 showUISourceCode: function(uiSourceCode, lineNumber, columnNumber, forceShowInPanel) 460 { 461 this._showSourceLocation(uiSourceCode, lineNumber, columnNumber, forceShowInPanel); 462 }, 463 464 /** 465 * @param {boolean=} forceShowInPanel 466 */ 467 _showEditor: function(forceShowInPanel) 468 { 469 if (this.sourcesView.isShowing()) 470 return; 471 if (this._canShowEditorInDrawer() && !forceShowInPanel) { 472 var drawerEditorView = new WebInspector.DrawerEditorView(); 473 this.sourcesView.show(drawerEditorView.element); 474 WebInspector.inspectorView.showCloseableViewInDrawer("editor", WebInspector.UIString("Editor"), drawerEditorView); 475 } else { 476 WebInspector.showPanel("sources"); 477 } 478 }, 479 480 /** 481 * @return {?WebInspector.UISourceCode} 482 */ 483 currentUISourceCode: function() 484 { 485 return this._currentUISourceCode; 486 }, 487 488 /** 489 * @param {!WebInspector.UILocation} uiLocation 490 * @param {boolean=} forceShowInPanel 491 */ 492 showUILocation: function(uiLocation, forceShowInPanel) 493 { 494 this._showSourceLocation(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, forceShowInPanel); 495 }, 496 497 /** 498 * @return {boolean} 499 */ 500 _canShowEditorInDrawer: function() 501 { 502 return WebInspector.experimentsSettings.showEditorInDrawer.isEnabled() && WebInspector.settings.showEditorInDrawer.get(); 503 }, 504 505 /** 506 * @param {!WebInspector.UISourceCode} uiSourceCode 507 * @param {number=} lineNumber 508 * @param {number=} columnNumber 509 * @param {boolean=} forceShowInPanel 510 */ 511 _showSourceLocation: function(uiSourceCode, lineNumber, columnNumber, forceShowInPanel) 512 { 513 this._showEditor(forceShowInPanel); 514 var sourceFrame = this._showFile(uiSourceCode); 515 if (typeof lineNumber === "number") 516 sourceFrame.highlightPosition(lineNumber, columnNumber); 517 sourceFrame.focus(); 518 519 WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, { 520 action: WebInspector.UserMetrics.UserActionNames.OpenSourceLink, 521 url: uiSourceCode.originURL(), 522 lineNumber: lineNumber 523 }); 524 }, 525 526 /** 527 * @param {!WebInspector.UISourceCode} uiSourceCode 528 * @return {!WebInspector.SourceFrame} 529 */ 530 _showFile: function(uiSourceCode) 531 { 532 var sourceFrame = this._getOrCreateSourceFrame(uiSourceCode); 533 if (this._currentUISourceCode === uiSourceCode) 534 return sourceFrame; 535 this._currentUISourceCode = uiSourceCode; 536 if (!uiSourceCode.project().isServiceProject()) 537 this._navigator.revealUISourceCode(uiSourceCode, true); 538 this._editorContainer.showFile(uiSourceCode); 539 this._updateScriptViewStatusBarItems(); 540 541 if (this._currentUISourceCode.project().type() === WebInspector.projectTypes.Snippets) 542 this._runSnippetButton.element.classList.remove("hidden"); 543 else 544 this._runSnippetButton.element.classList.add("hidden"); 545 546 return sourceFrame; 547 }, 548 549 /** 550 * @param {!WebInspector.UISourceCode} uiSourceCode 551 * @return {!WebInspector.SourceFrame} 552 */ 553 _createSourceFrame: function(uiSourceCode) 554 { 555 var sourceFrame; 556 switch (uiSourceCode.contentType()) { 557 case WebInspector.resourceTypes.Script: 558 sourceFrame = new WebInspector.JavaScriptSourceFrame(this, uiSourceCode); 559 break; 560 case WebInspector.resourceTypes.Document: 561 sourceFrame = new WebInspector.JavaScriptSourceFrame(this, uiSourceCode); 562 break; 563 case WebInspector.resourceTypes.Stylesheet: 564 sourceFrame = new WebInspector.CSSSourceFrame(uiSourceCode); 565 break; 566 default: 567 sourceFrame = new WebInspector.UISourceCodeFrame(uiSourceCode); 568 break; 569 } 570 sourceFrame.setHighlighterType(uiSourceCode.highlighterType()); 571 this._sourceFramesByUISourceCode.put(uiSourceCode, sourceFrame); 572 return sourceFrame; 573 }, 574 575 /** 576 * @param {!WebInspector.UISourceCode} uiSourceCode 577 * @return {!WebInspector.SourceFrame} 578 */ 579 _getOrCreateSourceFrame: function(uiSourceCode) 580 { 581 return this._sourceFramesByUISourceCode.get(uiSourceCode) || this._createSourceFrame(uiSourceCode); 582 }, 583 584 /** 585 * @param {!WebInspector.SourceFrame} sourceFrame 586 * @param {!WebInspector.UISourceCode} uiSourceCode 587 * @return {boolean} 588 */ 589 _sourceFrameMatchesUISourceCode: function(sourceFrame, uiSourceCode) 590 { 591 switch (uiSourceCode.contentType()) { 592 case WebInspector.resourceTypes.Script: 593 case WebInspector.resourceTypes.Document: 594 return sourceFrame instanceof WebInspector.JavaScriptSourceFrame; 595 case WebInspector.resourceTypes.Stylesheet: 596 return sourceFrame instanceof WebInspector.CSSSourceFrame; 597 default: 598 return !(sourceFrame instanceof WebInspector.JavaScriptSourceFrame); 599 } 600 }, 601 602 /** 603 * @param {!WebInspector.UISourceCode} uiSourceCode 604 */ 605 _recreateSourceFrameIfNeeded: function(uiSourceCode) 606 { 607 var oldSourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode); 608 if (!oldSourceFrame) 609 return; 610 if (this._sourceFrameMatchesUISourceCode(oldSourceFrame, uiSourceCode)) { 611 oldSourceFrame.setHighlighterType(uiSourceCode.highlighterType()); 612 } else { 613 this._editorContainer.removeUISourceCode(uiSourceCode); 614 this._removeSourceFrame(uiSourceCode); 615 } 616 }, 617 618 /** 619 * @param {!WebInspector.UISourceCode} uiSourceCode 620 * @return {!WebInspector.SourceFrame} 621 */ 622 viewForFile: function(uiSourceCode) 623 { 624 return this._getOrCreateSourceFrame(uiSourceCode); 625 }, 626 627 /** 628 * @param {!WebInspector.UISourceCode} uiSourceCode 629 */ 630 _removeSourceFrame: function(uiSourceCode) 631 { 632 var sourceFrame = this._sourceFramesByUISourceCode.get(uiSourceCode); 633 if (!sourceFrame) 634 return; 635 this._sourceFramesByUISourceCode.remove(uiSourceCode); 636 sourceFrame.dispose(); 637 }, 638 639 _clearCurrentExecutionLine: function() 640 { 641 if (this._executionSourceFrame) 642 this._executionSourceFrame.clearExecutionLine(); 643 delete this._executionSourceFrame; 644 }, 645 646 _setExecutionLine: function(uiLocation) 647 { 648 var callFrame = WebInspector.debuggerModel.selectedCallFrame() 649 var sourceFrame = this._getOrCreateSourceFrame(uiLocation.uiSourceCode); 650 sourceFrame.setExecutionLine(uiLocation.lineNumber, callFrame); 651 this._executionSourceFrame = sourceFrame; 652 }, 653 654 _executionLineChanged: function(uiLocation) 655 { 656 this._clearCurrentExecutionLine(); 657 this._setExecutionLine(uiLocation); 658 659 var uiSourceCode = uiLocation.uiSourceCode; 660 var scriptFile = this._currentUISourceCode ? this._currentUISourceCode.scriptFile() : null; 661 if (this._skipExecutionLineRevealing) 662 return; 663 this._skipExecutionLineRevealing = true; 664 var sourceFrame = this._showFile(uiSourceCode); 665 sourceFrame.revealLine(uiLocation.lineNumber); 666 if (sourceFrame.canEditSource()) 667 sourceFrame.setSelection(WebInspector.TextRange.createFromLocation(uiLocation.lineNumber, 0)); 668 sourceFrame.focus(); 669 }, 670 671 _callFrameSelected: function(event) 672 { 673 var callFrame = event.data; 674 675 if (!callFrame) 676 return; 677 678 this.sidebarPanes.scopechain.update(callFrame); 679 this.sidebarPanes.watchExpressions.refreshExpressions(); 680 this.sidebarPanes.callstack.setSelectedCallFrame(callFrame); 681 callFrame.createLiveLocation(this._executionLineChanged.bind(this)); 682 }, 683 684 _editorClosed: function(event) 685 { 686 this._navigatorController.hideNavigatorOverlay(); 687 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 688 689 if (this._currentUISourceCode === uiSourceCode) 690 delete this._currentUISourceCode; 691 692 // SourcesNavigator does not need to update on EditorClosed. 693 this._updateScriptViewStatusBarItems(); 694 this._searchableView.resetSearch(); 695 }, 696 697 _editorSelected: function(event) 698 { 699 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 700 var sourceFrame = this._showFile(uiSourceCode); 701 this._navigatorController.hideNavigatorOverlay(); 702 if (!this._navigatorController.isNavigatorPinned()) 703 sourceFrame.focus(); 704 this._searchableView.setCanReplace(!!sourceFrame && sourceFrame.canEditSource()); 705 this._searchableView.resetSearch(); 706 }, 707 708 _sourceSelected: function(event) 709 { 710 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.uiSourceCode); 711 var sourceFrame = this._showFile(uiSourceCode); 712 this._navigatorController.hideNavigatorOverlay(); 713 if (sourceFrame && (!this._navigatorController.isNavigatorPinned() || event.data.focusSource)) 714 sourceFrame.focus(); 715 }, 716 717 _itemSearchStarted: function(event) 718 { 719 var searchText = /** @type {string} */ (event.data); 720 WebInspector.OpenResourceDialog.show(this, this.editorView.mainElement, searchText); 721 }, 722 723 _pauseOnExceptionStateChanged: function() 724 { 725 var pauseOnExceptionsState = WebInspector.settings.pauseOnExceptionStateString.get(); 726 switch (pauseOnExceptionsState) { 727 case WebInspector.DebuggerModel.PauseOnExceptionsState.DontPauseOnExceptions: 728 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions."); 729 break; 730 case WebInspector.DebuggerModel.PauseOnExceptionsState.PauseOnAllExceptions: 731 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions."); 732 break; 733 case WebInspector.DebuggerModel.PauseOnExceptionsState.PauseOnUncaughtExceptions: 734 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions."); 735 break; 736 } 737 this._pauseOnExceptionButton.state = pauseOnExceptionsState; 738 }, 739 740 _updateDebuggerButtons: function() 741 { 742 if (this._paused) { 743 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Resume script execution (%s).")) 744 this._pauseButton.state = true; 745 this._pauseButton.setLongClickOptionsEnabled((function() { return [ this._longResumeButton ] }).bind(this)); 746 747 this._pauseButton.setEnabled(true); 748 this._stepOverButton.setEnabled(true); 749 this._stepIntoButton.setEnabled(true); 750 this._stepOutButton.setEnabled(true); 751 } else { 752 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Pause script execution (%s).")) 753 this._pauseButton.state = false; 754 this._pauseButton.setLongClickOptionsEnabled(null); 755 756 this._pauseButton.setEnabled(!this._waitingToPause); 757 this._stepOverButton.setEnabled(false); 758 this._stepIntoButton.setEnabled(false); 759 this._stepOutButton.setEnabled(false); 760 } 761 }, 762 763 _clearInterface: function() 764 { 765 this.sidebarPanes.callstack.update(null, null); 766 this.sidebarPanes.scopechain.update(null); 767 this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight(); 768 WebInspector.domBreakpointsSidebarPane.clearBreakpointHighlight(); 769 this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight(); 770 this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight(); 771 772 this._clearCurrentExecutionLine(); 773 this._updateDebuggerButtons(); 774 }, 775 776 _togglePauseOnExceptions: function() 777 { 778 var nextStateMap = {}; 779 var stateEnum = WebInspector.DebuggerModel.PauseOnExceptionsState; 780 nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions; 781 nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions; 782 nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions; 783 WebInspector.settings.pauseOnExceptionStateString.set(nextStateMap[this._pauseOnExceptionButton.state]); 784 }, 785 786 /** 787 * @return {boolean} 788 */ 789 _runSnippet: function() 790 { 791 if (this._currentUISourceCode.project().type() !== WebInspector.projectTypes.Snippets) 792 return false; 793 WebInspector.scriptSnippetModel.evaluateScriptSnippet(this._currentUISourceCode); 794 return true; 795 }, 796 797 /** 798 * @return {boolean} 799 */ 800 _togglePause: function() 801 { 802 if (this._paused) { 803 delete this._skipExecutionLineRevealing; 804 this._paused = false; 805 this._waitingToPause = false; 806 WebInspector.debuggerModel.resume(); 807 } else { 808 this._stepping = false; 809 this._waitingToPause = true; 810 // Make sure pauses didn't stick skipped. 811 WebInspector.debuggerModel.skipAllPauses(false); 812 DebuggerAgent.pause(); 813 } 814 815 this._clearInterface(); 816 return true; 817 }, 818 819 /** 820 * @return {boolean} 821 */ 822 _longResume: function() 823 { 824 if (!this._paused) 825 return true; 826 827 this._paused = false; 828 this._waitingToPause = false; 829 WebInspector.debuggerModel.skipAllPausesUntilReloadOrTimeout(500); 830 WebInspector.debuggerModel.resume(); 831 832 this._clearInterface(); 833 return true; 834 }, 835 836 /** 837 * @return {boolean} 838 */ 839 _stepOverClicked: function() 840 { 841 if (!this._paused) 842 return true; 843 844 delete this._skipExecutionLineRevealing; 845 this._paused = false; 846 this._stepping = true; 847 848 this._clearInterface(); 849 850 WebInspector.debuggerModel.stepOver(); 851 return true; 852 }, 853 854 /** 855 * @return {boolean} 856 */ 857 _stepIntoClicked: function() 858 { 859 if (!this._paused) 860 return true; 861 862 delete this._skipExecutionLineRevealing; 863 this._paused = false; 864 this._stepping = true; 865 866 this._clearInterface(); 867 868 WebInspector.debuggerModel.stepInto(); 869 return true; 870 }, 871 872 /** 873 * @param {?Event=} event 874 * @return {boolean} 875 */ 876 _stepIntoSelectionClicked: function(event) 877 { 878 if (!this._paused) 879 return true; 880 881 if (this._executionSourceFrame) { 882 var stepIntoMarkup = this._executionSourceFrame.stepIntoMarkup(); 883 if (stepIntoMarkup) 884 stepIntoMarkup.iterateSelection(event.shiftKey); 885 } 886 return true; 887 }, 888 889 doStepIntoSelection: function(rawLocation) 890 { 891 if (!this._paused) 892 return; 893 894 delete this._skipExecutionLineRevealing; 895 this._paused = false; 896 this._stepping = true; 897 this._clearInterface(); 898 WebInspector.debuggerModel.stepIntoSelection(rawLocation); 899 }, 900 901 /** 902 * @return {boolean} 903 */ 904 _stepOutClicked: function() 905 { 906 if (!this._paused) 907 return true; 908 909 delete this._skipExecutionLineRevealing; 910 this._paused = false; 911 this._stepping = true; 912 913 this._clearInterface(); 914 915 WebInspector.debuggerModel.stepOut(); 916 return true; 917 }, 918 919 /** 920 * @param {!WebInspector.Event} event 921 */ 922 _callFrameSelectedInSidebar: function(event) 923 { 924 var callFrame = /** @type {!WebInspector.DebuggerModel.CallFrame} */ (event.data); 925 delete this._skipExecutionLineRevealing; 926 WebInspector.debuggerModel.setSelectedCallFrame(callFrame); 927 }, 928 929 _callFrameRestartedInSidebar: function() 930 { 931 delete this._skipExecutionLineRevealing; 932 }, 933 934 continueToLocation: function(rawLocation) 935 { 936 if (!this._paused) 937 return; 938 939 delete this._skipExecutionLineRevealing; 940 this._paused = false; 941 this._stepping = true; 942 this._clearInterface(); 943 WebInspector.debuggerModel.continueToLocation(rawLocation); 944 }, 945 946 _toggleBreakpointsClicked: function(event) 947 { 948 WebInspector.debuggerModel.setBreakpointsActive(!WebInspector.debuggerModel.breakpointsActive()); 949 }, 950 951 _breakpointsActiveStateChanged: function(event) 952 { 953 var active = event.data; 954 this._toggleBreakpointsButton.toggled = !active; 955 if (active) { 956 this._toggleBreakpointsButton.title = WebInspector.UIString("Deactivate breakpoints."); 957 this._editorContainer.view.element.classList.remove("breakpoints-deactivated"); 958 this.sidebarPanes.jsBreakpoints.listElement.classList.remove("breakpoints-list-deactivated"); 959 } else { 960 this._toggleBreakpointsButton.title = WebInspector.UIString("Activate breakpoints."); 961 this._editorContainer.view.element.classList.add("breakpoints-deactivated"); 962 this.sidebarPanes.jsBreakpoints.listElement.classList.add("breakpoints-list-deactivated"); 963 } 964 }, 965 966 _createDebugToolbar: function() 967 { 968 var debugToolbar = document.createElement("div"); 969 debugToolbar.className = "status-bar"; 970 debugToolbar.id = "scripts-debug-toolbar"; 971 972 var title, handler; 973 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta; 974 975 // Run snippet. 976 title = WebInspector.UIString("Run snippet (%s)."); 977 handler = this._runSnippet.bind(this); 978 this._runSnippetButton = this._createButtonAndRegisterShortcuts("scripts-run-snippet", title, handler, WebInspector.SourcesPanelDescriptor.ShortcutKeys.RunSnippet); 979 debugToolbar.appendChild(this._runSnippetButton.element); 980 this._runSnippetButton.element.classList.add("hidden"); 981 982 // Continue. 983 handler = this._togglePause.bind(this); 984 this._pauseButton = this._createButtonAndRegisterShortcuts("scripts-pause", "", handler, WebInspector.SourcesPanelDescriptor.ShortcutKeys.PauseContinue); 985 debugToolbar.appendChild(this._pauseButton.element); 986 987 // Long resume. 988 title = WebInspector.UIString("Resume with all pauses blocked for 500 ms"); 989 this._longResumeButton = new WebInspector.StatusBarButton(title, "scripts-long-resume"); 990 this._longResumeButton.addEventListener("click", this._longResume.bind(this), this); 991 992 // Step over. 993 title = WebInspector.UIString("Step over next function call (%s)."); 994 handler = this._stepOverClicked.bind(this); 995 this._stepOverButton = this._createButtonAndRegisterShortcuts("scripts-step-over", title, handler, WebInspector.SourcesPanelDescriptor.ShortcutKeys.StepOver); 996 debugToolbar.appendChild(this._stepOverButton.element); 997 998 // Step into. 999 title = WebInspector.UIString("Step into next function call (%s)."); 1000 handler = this._stepIntoClicked.bind(this); 1001 this._stepIntoButton = this._createButtonAndRegisterShortcuts("scripts-step-into", title, handler, WebInspector.SourcesPanelDescriptor.ShortcutKeys.StepInto); 1002 debugToolbar.appendChild(this._stepIntoButton.element); 1003 1004 // Step into selection (keyboard shortcut only). 1005 this.registerShortcuts(WebInspector.SourcesPanelDescriptor.ShortcutKeys.StepIntoSelection, this._stepIntoSelectionClicked.bind(this)) 1006 1007 // Step out. 1008 title = WebInspector.UIString("Step out of current function (%s)."); 1009 handler = this._stepOutClicked.bind(this); 1010 this._stepOutButton = this._createButtonAndRegisterShortcuts("scripts-step-out", title, handler, WebInspector.SourcesPanelDescriptor.ShortcutKeys.StepOut); 1011 debugToolbar.appendChild(this._stepOutButton.element); 1012 1013 // Toggle Breakpoints 1014 this._toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate breakpoints."), "scripts-toggle-breakpoints"); 1015 this._toggleBreakpointsButton.toggled = false; 1016 this._toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this); 1017 debugToolbar.appendChild(this._toggleBreakpointsButton.element); 1018 1019 // Pause on Exception 1020 this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3); 1021 this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this); 1022 debugToolbar.appendChild(this._pauseOnExceptionButton.element); 1023 1024 return debugToolbar; 1025 }, 1026 1027 /** 1028 * @param {!WebInspector.StatusBarButton} button 1029 * @param {string} buttonTitle 1030 */ 1031 _updateButtonTitle: function(button, buttonTitle) 1032 { 1033 var hasShortcuts = button.shortcuts && button.shortcuts.length; 1034 if (hasShortcuts) 1035 button.title = String.vsprintf(buttonTitle, [button.shortcuts[0].name]); 1036 else 1037 button.title = buttonTitle; 1038 }, 1039 1040 /** 1041 * @param {string} buttonId 1042 * @param {string} buttonTitle 1043 * @param {function(?Event=):boolean} handler 1044 * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts 1045 * @return {!WebInspector.StatusBarButton} 1046 */ 1047 _createButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts) 1048 { 1049 var button = new WebInspector.StatusBarButton(buttonTitle, buttonId); 1050 button.element.addEventListener("click", handler, false); 1051 button.shortcuts = shortcuts; 1052 this._updateButtonTitle(button, buttonTitle); 1053 this.registerShortcuts(shortcuts, handler); 1054 return button; 1055 }, 1056 1057 searchCanceled: function() 1058 { 1059 if (this._searchView) 1060 this._searchView.searchCanceled(); 1061 1062 delete this._searchView; 1063 delete this._searchQuery; 1064 }, 1065 1066 /** 1067 * @param {string} query 1068 * @param {boolean} shouldJump 1069 */ 1070 performSearch: function(query, shouldJump) 1071 { 1072 this._searchableView.updateSearchMatchesCount(0); 1073 1074 if (!this.visibleView) 1075 return; 1076 1077 this._searchView = this.visibleView; 1078 this._searchQuery = query; 1079 1080 /** 1081 * @param {!WebInspector.View} view 1082 * @param {number} searchMatches 1083 * @this {WebInspector.SourcesPanel} 1084 */ 1085 function finishedCallback(view, searchMatches) 1086 { 1087 if (!searchMatches) 1088 return; 1089 1090 this._searchableView.updateSearchMatchesCount(searchMatches); 1091 } 1092 1093 /** 1094 * @param {number} currentMatchIndex 1095 * @this {WebInspector.SourcesPanel} 1096 */ 1097 function currentMatchChanged(currentMatchIndex) 1098 { 1099 this._searchableView.updateCurrentMatchIndex(currentMatchIndex); 1100 } 1101 1102 /** 1103 * @this {WebInspector.SourcesPanel} 1104 */ 1105 function searchResultsChanged() 1106 { 1107 this._searchableView.cancelSearch(); 1108 } 1109 1110 this._searchView.performSearch(query, shouldJump, finishedCallback.bind(this), currentMatchChanged.bind(this), searchResultsChanged.bind(this)); 1111 }, 1112 1113 jumpToNextSearchResult: function() 1114 { 1115 if (!this._searchView) 1116 return; 1117 1118 if (this._searchView !== this.visibleView) { 1119 this.performSearch(this._searchQuery, true); 1120 return; 1121 } 1122 1123 this._searchView.jumpToNextSearchResult(); 1124 return true; 1125 }, 1126 1127 jumpToPreviousSearchResult: function() 1128 { 1129 if (!this._searchView) 1130 return; 1131 1132 if (this._searchView !== this.visibleView) { 1133 this.performSearch(this._searchQuery, true); 1134 if (this._searchView) 1135 this._searchView.jumpToLastSearchResult(); 1136 return; 1137 } 1138 1139 this._searchView.jumpToPreviousSearchResult(); 1140 }, 1141 1142 /** 1143 * @param {string} text 1144 */ 1145 replaceSelectionWith: function(text) 1146 { 1147 var view = /** @type {!WebInspector.SourceFrame} */ (this.visibleView); 1148 view.replaceSearchMatchWith(text); 1149 }, 1150 1151 /** 1152 * @param {string} query 1153 * @param {string} text 1154 */ 1155 replaceAllWith: function(query, text) 1156 { 1157 var view = /** @type {!WebInspector.SourceFrame} */ (this.visibleView); 1158 view.replaceAllWith(query, text); 1159 }, 1160 1161 _onKeyDown: function(event) 1162 { 1163 if (event.keyCode !== WebInspector.KeyboardShortcut.Keys.CtrlOrMeta.code) 1164 return; 1165 if (!this._paused || !this._executionSourceFrame) 1166 return; 1167 var stepIntoMarkup = this._executionSourceFrame.stepIntoMarkup(); 1168 if (stepIntoMarkup) 1169 stepIntoMarkup.startIteratingSelection(); 1170 }, 1171 1172 _onKeyUp: function(event) 1173 { 1174 if (event.keyCode !== WebInspector.KeyboardShortcut.Keys.CtrlOrMeta.code) 1175 return; 1176 if (!this._paused || !this._executionSourceFrame) 1177 return; 1178 var stepIntoMarkup = this._executionSourceFrame.stepIntoMarkup(); 1179 if (!stepIntoMarkup) 1180 return; 1181 var currentPosition = stepIntoMarkup.getSelectedItemIndex(); 1182 if (typeof currentPosition === "undefined") { 1183 stepIntoMarkup.stopIteratingSelection(); 1184 } else { 1185 var rawLocation = stepIntoMarkup.getRawPosition(currentPosition); 1186 this.doStepIntoSelection(rawLocation); 1187 } 1188 }, 1189 1190 _toggleFormatSource: function() 1191 { 1192 delete this._skipExecutionLineRevealing; 1193 this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled; 1194 var uiSourceCodes = this._workspace.uiSourceCodes(); 1195 for (var i = 0; i < uiSourceCodes.length; ++i) 1196 uiSourceCodes[i].setFormatted(this._toggleFormatSourceButton.toggled); 1197 1198 var currentFile = this._editorContainer.currentFile(); 1199 1200 WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, { 1201 action: WebInspector.UserMetrics.UserActionNames.TogglePrettyPrint, 1202 enabled: this._toggleFormatSourceButton.toggled, 1203 url: currentFile ? currentFile.originURL() : null 1204 }); 1205 }, 1206 1207 addToWatch: function(expression) 1208 { 1209 this.sidebarPanes.watchExpressions.addExpression(expression); 1210 }, 1211 1212 /** 1213 * @return {boolean} 1214 */ 1215 _toggleBreakpoint: function() 1216 { 1217 var sourceFrame = this.visibleView; 1218 if (!sourceFrame) 1219 return false; 1220 1221 if (sourceFrame instanceof WebInspector.JavaScriptSourceFrame) { 1222 var javaScriptSourceFrame = /** @type {!WebInspector.JavaScriptSourceFrame} */ (sourceFrame); 1223 javaScriptSourceFrame.toggleBreakpointOnCurrentLine(); 1224 return true; 1225 } 1226 return false; 1227 }, 1228 1229 /** 1230 * @param {?Event=} event 1231 * @return {boolean} 1232 */ 1233 _showOutlineDialog: function(event) 1234 { 1235 var uiSourceCode = this._editorContainer.currentFile(); 1236 if (!uiSourceCode) 1237 return false; 1238 1239 switch (uiSourceCode.contentType()) { 1240 case WebInspector.resourceTypes.Document: 1241 case WebInspector.resourceTypes.Script: 1242 WebInspector.JavaScriptOutlineDialog.show(this.visibleView, uiSourceCode, this.highlightPosition.bind(this)); 1243 return true; 1244 case WebInspector.resourceTypes.Stylesheet: 1245 WebInspector.StyleSheetOutlineDialog.show(this.visibleView, uiSourceCode, this.highlightPosition.bind(this)); 1246 return true; 1247 } 1248 return false; 1249 }, 1250 1251 _installDebuggerSidebarController: function() 1252 { 1253 this._toggleDebuggerSidebarButton = new WebInspector.StatusBarButton("", "right-sidebar-show-hide-button scripts-debugger-show-hide-button", 3); 1254 this._toggleDebuggerSidebarButton.addEventListener("click", clickHandler, this); 1255 1256 if (this.splitView.isVertical()) { 1257 this.editorView.element.appendChild(this._toggleDebuggerSidebarButton.element); 1258 this.splitView.mainElement.appendChild(this._debugSidebarResizeWidgetElement); 1259 } else { 1260 this._statusBarContainerElement.appendChild(this._debugSidebarResizeWidgetElement); 1261 this._statusBarContainerElement.appendChild(this._toggleDebuggerSidebarButton.element); 1262 } 1263 1264 this._enableDebuggerSidebar(!WebInspector.settings.debuggerSidebarHidden.get()); 1265 1266 /** 1267 * @this {WebInspector.SourcesPanel} 1268 */ 1269 function clickHandler() 1270 { 1271 this._enableDebuggerSidebar(this._toggleDebuggerSidebarButton.state === "left"); 1272 } 1273 }, 1274 1275 /** 1276 * @param {boolean} show 1277 */ 1278 _enableDebuggerSidebar: function(show) 1279 { 1280 this._toggleDebuggerSidebarButton.state = show ? "right" : "left"; 1281 this._toggleDebuggerSidebarButton.title = show ? WebInspector.UIString("Hide debugger") : WebInspector.UIString("Show debugger"); 1282 if (show) 1283 this.splitView.showSidebarElement(); 1284 else 1285 this.splitView.hideSidebarElement(); 1286 this._debugSidebarResizeWidgetElement.enableStyleClass("hidden", !show); 1287 WebInspector.settings.debuggerSidebarHidden.set(!show); 1288 }, 1289 1290 /** 1291 * @param {!WebInspector.Event} event 1292 */ 1293 _itemCreationRequested: function(event) 1294 { 1295 var project = event.data.project; 1296 var path = event.data.path; 1297 var uiSourceCodeToCopy = event.data.uiSourceCode; 1298 var filePath; 1299 var shouldHideNavigator; 1300 var uiSourceCode; 1301 1302 /** 1303 * @param {?string} content 1304 * @this {WebInspector.SourcesPanel} 1305 */ 1306 function contentLoaded(content) 1307 { 1308 createFile.call(this, content || ""); 1309 } 1310 1311 if (uiSourceCodeToCopy) 1312 uiSourceCodeToCopy.requestContent(contentLoaded.bind(this)); 1313 else 1314 createFile.call(this); 1315 1316 /** 1317 * @param {string=} content 1318 * @this {WebInspector.SourcesPanel} 1319 */ 1320 function createFile(content) 1321 { 1322 project.createFile(path, null, content || "", fileCreated.bind(this)); 1323 } 1324 1325 /** 1326 * @param {?string} path 1327 * @this {WebInspector.SourcesPanel} 1328 */ 1329 function fileCreated(path) 1330 { 1331 if (!path) 1332 return; 1333 filePath = path; 1334 uiSourceCode = project.uiSourceCode(filePath); 1335 this._showSourceLocation(uiSourceCode); 1336 1337 shouldHideNavigator = !this._navigatorController.isNavigatorPinned(); 1338 if (this._navigatorController.isNavigatorHidden()) 1339 this._navigatorController.showNavigatorOverlay(); 1340 this._navigator.rename(uiSourceCode, callback.bind(this)); 1341 } 1342 1343 /** 1344 * @param {boolean} committed 1345 * @this {WebInspector.SourcesPanel} 1346 */ 1347 function callback(committed) 1348 { 1349 if (shouldHideNavigator) 1350 this._navigatorController.hideNavigatorOverlay(); 1351 1352 if (!committed) { 1353 project.deleteFile(uiSourceCode); 1354 return; 1355 } 1356 1357 this._recreateSourceFrameIfNeeded(uiSourceCode); 1358 this._navigator.updateIcon(uiSourceCode); 1359 this._showSourceLocation(uiSourceCode); 1360 } 1361 }, 1362 1363 /** 1364 * @param {!WebInspector.Event} event 1365 */ 1366 _itemRenamingRequested: function(event) 1367 { 1368 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 1369 1370 var shouldHideNavigator = !this._navigatorController.isNavigatorPinned(); 1371 if (this._navigatorController.isNavigatorHidden()) 1372 this._navigatorController.showNavigatorOverlay(); 1373 this._navigator.rename(uiSourceCode, callback.bind(this)); 1374 1375 /** 1376 * @param {boolean} committed 1377 * @this {WebInspector.SourcesPanel} 1378 */ 1379 function callback(committed) 1380 { 1381 if (shouldHideNavigator && committed) 1382 this._navigatorController.hideNavigatorOverlay(); 1383 this._recreateSourceFrameIfNeeded(uiSourceCode); 1384 this._navigator.updateIcon(uiSourceCode); 1385 this._showSourceLocation(uiSourceCode); 1386 } 1387 }, 1388 1389 /** 1390 * @param {!WebInspector.UISourceCode} uiSourceCode 1391 */ 1392 _showLocalHistory: function(uiSourceCode) 1393 { 1394 WebInspector.RevisionHistoryView.showHistory(uiSourceCode); 1395 }, 1396 1397 /** 1398 * @param {!WebInspector.ContextMenu} contextMenu 1399 * @param {!Object} target 1400 */ 1401 appendApplicableItems: function(event, contextMenu, target) 1402 { 1403 this._appendUISourceCodeItems(contextMenu, target); 1404 this._appendFunctionItems(contextMenu, target); 1405 }, 1406 1407 /** 1408 * @param {!WebInspector.UISourceCode} uiSourceCode 1409 */ 1410 _mapFileSystemToNetwork: function(uiSourceCode) 1411 { 1412 WebInspector.SelectUISourceCodeForProjectTypeDialog.show(uiSourceCode.name(), WebInspector.projectTypes.Network, mapFileSystemToNetwork.bind(this), this.editorView.mainElement) 1413 1414 /** 1415 * @param {!WebInspector.UISourceCode} networkUISourceCode 1416 * @this {WebInspector.SourcesPanel} 1417 */ 1418 function mapFileSystemToNetwork(networkUISourceCode) 1419 { 1420 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceProvider); 1421 } 1422 }, 1423 1424 /** 1425 * @param {!WebInspector.UISourceCode} uiSourceCode 1426 */ 1427 _removeNetworkMapping: function(uiSourceCode) 1428 { 1429 if (confirm(WebInspector.UIString("Are you sure you want to remove network mapping?"))) 1430 this._workspace.removeMapping(uiSourceCode); 1431 }, 1432 1433 /** 1434 * @param {!WebInspector.UISourceCode} networkUISourceCode 1435 */ 1436 _mapNetworkToFileSystem: function(networkUISourceCode) 1437 { 1438 WebInspector.SelectUISourceCodeForProjectTypeDialog.show(networkUISourceCode.name(), WebInspector.projectTypes.FileSystem, mapNetworkToFileSystem.bind(this), this.editorView.mainElement) 1439 1440 /** 1441 * @param {!WebInspector.UISourceCode} uiSourceCode 1442 * @this {WebInspector.SourcesPanel} 1443 */ 1444 function mapNetworkToFileSystem(uiSourceCode) 1445 { 1446 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceProvider); 1447 } 1448 }, 1449 1450 /** 1451 * @param {!WebInspector.ContextMenu} contextMenu 1452 * @param {!WebInspector.UISourceCode} uiSourceCode 1453 */ 1454 _appendUISourceCodeMappingItems: function(contextMenu, uiSourceCode) 1455 { 1456 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) { 1457 var hasMappings = !!uiSourceCode.url; 1458 if (!hasMappings) 1459 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to network resource\u2026" : "Map to Network Resource\u2026"), this._mapFileSystemToNetwork.bind(this, uiSourceCode)); 1460 else 1461 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove network mapping" : "Remove Network Mapping"), this._removeNetworkMapping.bind(this, uiSourceCode)); 1462 } 1463 1464 /** 1465 * @param {!WebInspector.Project} project 1466 */ 1467 function filterProject(project) 1468 { 1469 return project.type() === WebInspector.projectTypes.FileSystem; 1470 } 1471 1472 if (uiSourceCode.project().type() === WebInspector.projectTypes.Network) { 1473 if (!this._workspace.projects().filter(filterProject).length) 1474 return; 1475 if (this._workspace.uiSourceCodeForURL(uiSourceCode.url) === uiSourceCode) 1476 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to file system resource\u2026" : "Map to File System Resource\u2026"), this._mapNetworkToFileSystem.bind(this, uiSourceCode)); 1477 } 1478 }, 1479 1480 /** 1481 * @param {!WebInspector.ContextMenu} contextMenu 1482 * @param {!Object} target 1483 */ 1484 _appendUISourceCodeItems: function(contextMenu, target) 1485 { 1486 if (!(target instanceof WebInspector.UISourceCode)) 1487 return; 1488 1489 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target); 1490 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Local modifications\u2026" : "Local Modifications\u2026"), this._showLocalHistory.bind(this, uiSourceCode)); 1491 1492 if (WebInspector.isolatedFileSystemManager.supportsFileSystems()) 1493 this._appendUISourceCodeMappingItems(contextMenu, uiSourceCode); 1494 }, 1495 1496 /** 1497 * @param {!WebInspector.ContextMenu} contextMenu 1498 * @param {!Object} target 1499 */ 1500 _appendFunctionItems: function(contextMenu, target) 1501 { 1502 if (!(target instanceof WebInspector.RemoteObject)) 1503 return; 1504 var remoteObject = /** @type {!WebInspector.RemoteObject} */ (target); 1505 if (remoteObject.type !== "function") 1506 return; 1507 1508 /** 1509 * @param {?Protocol.Error} error 1510 * @param {!DebuggerAgent.FunctionDetails} response 1511 * @this {WebInspector.SourcesPanel} 1512 */ 1513 function didGetDetails(error, response) 1514 { 1515 if (error) { 1516 console.error(error); 1517 return; 1518 } 1519 1520 var uiLocation = WebInspector.debuggerModel.rawLocationToUILocation(response.location); 1521 if (!uiLocation) 1522 return; 1523 1524 this.showUILocation(uiLocation, true); 1525 } 1526 1527 /** 1528 * @this {WebInspector.SourcesPanel} 1529 */ 1530 function revealFunction() 1531 { 1532 DebuggerAgent.getFunctionDetails(remoteObject.objectId, didGetDetails.bind(this)); 1533 } 1534 1535 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show function definition" : "Show Function Definition"), revealFunction.bind(this)); 1536 }, 1537 1538 showGoToSourceDialog: function() 1539 { 1540 var uiSourceCodes = this._editorContainer.historyUISourceCodes(); 1541 /** @type {!Map.<!WebInspector.UISourceCode, number>} */ 1542 var defaultScores = new Map(); 1543 for (var i = 1; i < uiSourceCodes.length; ++i) // Skip current element 1544 defaultScores.put(uiSourceCodes[i], uiSourceCodes.length - i); 1545 WebInspector.OpenResourceDialog.show(this, this.editorView.mainElement, undefined, defaultScores); 1546 }, 1547 1548 _dockSideChanged: function() 1549 { 1550 var dockSide = WebInspector.dockController.dockSide(); 1551 var vertically = dockSide === WebInspector.DockController.State.DockedToRight && WebInspector.settings.splitVerticallyWhenDockedToRight.get(); 1552 this._splitVertically(vertically); 1553 }, 1554 1555 /** 1556 * @param {boolean} vertically 1557 */ 1558 _splitVertically: function(vertically) 1559 { 1560 if (this.sidebarPaneView && vertically === !this.splitView.isVertical()) 1561 return; 1562 1563 if (this.sidebarPaneView) 1564 this.sidebarPaneView.detach(); 1565 1566 this.splitView.setVertical(!vertically); 1567 1568 if (!vertically) { 1569 this.splitView.uninstallResizer(this._statusBarContainerElement); 1570 this.sidebarPaneView = new WebInspector.SidebarPaneStack(); 1571 for (var pane in this.sidebarPanes) 1572 this.sidebarPaneView.addPane(this.sidebarPanes[pane]); 1573 this._extensionSidebarPanesContainer = this.sidebarPaneView; 1574 this.sidebarElement.appendChild(this.debugToolbar); 1575 this.editorView.element.appendChild(this._toggleDebuggerSidebarButton.element); 1576 this.splitView.mainElement.appendChild(this._debugSidebarResizeWidgetElement); 1577 } else { 1578 this.splitView.installResizer(this._statusBarContainerElement); 1579 this.sidebarPaneView = new WebInspector.SplitView(true, this.name + "PanelSplitSidebarRatio", 0.5); 1580 1581 var group1 = new WebInspector.SidebarPaneStack(); 1582 group1.show(this.sidebarPaneView.firstElement()); 1583 group1.element.id = "scripts-sidebar-stack-pane"; 1584 group1.addPane(this.sidebarPanes.callstack); 1585 group1.addPane(this.sidebarPanes.jsBreakpoints); 1586 group1.addPane(this.sidebarPanes.domBreakpoints); 1587 group1.addPane(this.sidebarPanes.xhrBreakpoints); 1588 group1.addPane(this.sidebarPanes.eventListenerBreakpoints); 1589 if (this.sidebarPanes.workerList) 1590 group1.addPane(this.sidebarPanes.workerList); 1591 1592 var group2 = new WebInspector.SidebarTabbedPane(); 1593 group2.show(this.sidebarPaneView.secondElement()); 1594 group2.addPane(this.sidebarPanes.scopechain); 1595 group2.addPane(this.sidebarPanes.watchExpressions); 1596 this._extensionSidebarPanesContainer = group2; 1597 this.sidebarPaneView.firstElement().appendChild(this.debugToolbar); 1598 this._statusBarContainerElement.appendChild(this._debugSidebarResizeWidgetElement); 1599 this._statusBarContainerElement.appendChild(this._toggleDebuggerSidebarButton.element) 1600 } 1601 for (var i = 0; i < this._extensionSidebarPanes.length; ++i) 1602 this._extensionSidebarPanesContainer.addPane(this._extensionSidebarPanes[i]); 1603 1604 this.sidebarPaneView.element.id = "scripts-debug-sidebar-contents"; 1605 this.sidebarPaneView.show(this.splitView.sidebarElement); 1606 1607 this.sidebarPanes.scopechain.expand(); 1608 this.sidebarPanes.jsBreakpoints.expand(); 1609 this.sidebarPanes.callstack.expand(); 1610 1611 if (WebInspector.settings.watchExpressions.get().length > 0) 1612 this.sidebarPanes.watchExpressions.expand(); 1613 }, 1614 1615 canHighlightPosition: function() 1616 { 1617 return this.visibleView && this.visibleView.canHighlightPosition(); 1618 }, 1619 1620 /** 1621 * @param {number} line 1622 * @param {number=} column 1623 */ 1624 highlightPosition: function(line, column) 1625 { 1626 if (!this.canHighlightPosition()) 1627 return; 1628 this.visibleView.highlightPosition(line, column); 1629 }, 1630 1631 /** 1632 * @param {string} id 1633 * @param {!WebInspector.SidebarPane} pane 1634 */ 1635 addExtensionSidebarPane: function(id, pane) 1636 { 1637 this._extensionSidebarPanes.push(pane); 1638 this._extensionSidebarPanesContainer.addPane(pane); 1639 this.setHideOnDetach(); 1640 }, 1641 1642 /** 1643 * @return {!WebInspector.TabbedEditorContainer} 1644 */ 1645 get tabbedEditorContainer() 1646 { 1647 return this._editorContainer; 1648 }, 1649 1650 __proto__: WebInspector.Panel.prototype 1651} 1652 1653/** 1654 * @constructor 1655 * @extends {WebInspector.View} 1656 */ 1657WebInspector.SourcesView = function() 1658{ 1659 WebInspector.View.call(this); 1660 this.registerRequiredCSS("sourcesView.css"); 1661 this.element.id = "sources-panel-sources-view"; 1662 this.element.classList.add("vbox"); 1663 this.element.addEventListener("dragenter", this._onDragEnter.bind(this), true); 1664 this.element.addEventListener("dragover", this._onDragOver.bind(this), true); 1665} 1666 1667WebInspector.SourcesView.dragAndDropFilesType = "Files"; 1668 1669WebInspector.SourcesView.prototype = { 1670 _onDragEnter: function (event) 1671 { 1672 if (event.dataTransfer.types.indexOf(WebInspector.SourcesView.dragAndDropFilesType) === -1) 1673 return; 1674 event.consume(true); 1675 }, 1676 1677 _onDragOver: function (event) 1678 { 1679 if (event.dataTransfer.types.indexOf(WebInspector.SourcesView.dragAndDropFilesType) === -1) 1680 return; 1681 event.consume(true); 1682 if (this._dragMaskElement) 1683 return; 1684 this._dragMaskElement = this.element.createChild("div", "fill drag-mask"); 1685 this._dragMaskElement.addEventListener("drop", this._onDrop.bind(this), true); 1686 this._dragMaskElement.addEventListener("dragleave", this._onDragLeave.bind(this), true); 1687 }, 1688 1689 _onDrop: function (event) 1690 { 1691 event.consume(true); 1692 this._removeMask(); 1693 var items = /** @type {!Array.<!DataTransferItem>} */ (event.dataTransfer.items); 1694 if (!items.length) 1695 return; 1696 var entry = items[0].webkitGetAsEntry(); 1697 if (!entry.isDirectory) 1698 return; 1699 InspectorFrontendHost.upgradeDraggedFileSystemPermissions(entry.filesystem); 1700 }, 1701 1702 _onDragLeave: function (event) 1703 { 1704 event.consume(true); 1705 this._removeMask(); 1706 }, 1707 1708 _removeMask: function () 1709 { 1710 this._dragMaskElement.remove(); 1711 delete this._dragMaskElement; 1712 }, 1713 1714 __proto__: WebInspector.View.prototype 1715} 1716 1717/** 1718 * @constructor 1719 * @extends {WebInspector.View} 1720 */ 1721WebInspector.DrawerEditorView = function() 1722{ 1723 WebInspector.View.call(this); 1724 this.element.id = "drawer-editor-view"; 1725 this.element.classList.add("vbox"); 1726} 1727 1728WebInspector.DrawerEditorView.prototype = { 1729 __proto__: WebInspector.View.prototype 1730} 1731