2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 * @extends {WebInspector.Panel}
30 * @implements {WebInspector.ContextMenu.Provider}
31 * @implements {WebInspector.TargetManager.Observer}
32 * @param {!WebInspector.Workspace=} workspaceForTest
34 WebInspector.SourcesPanel = function(workspaceForTest)
36 WebInspector.Panel.call(this, "sources");
37 this.registerRequiredCSS("sourcesPanel.css");
38 new WebInspector.UpgradeFileSystemDropTarget(this.element);
40 this._workspace = workspaceForTest || WebInspector.workspace;
42 this.debugToolbar = this._createDebugToolbar();
43 this._debugToolbarDrawer = this._createDebugToolbarDrawer();
45 const initialDebugSidebarWidth = 225;
46 this._splitView = new WebInspector.SplitView(true, true, "sourcesPanelSplitViewState", initialDebugSidebarWidth);
47 this._splitView.enableShowModeSaving();
48 this._splitView.show(this.element);
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());
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);
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());
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);
76 this.sidebarPanes = {};
77 this.sidebarPanes.threads = new WebInspector.ThreadsSidebarPane();
78 this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
79 this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
80 this.sidebarPanes.callstack.addEventListener(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, this._callFrameSelectedInSidebar.bind(this));
81 this.sidebarPanes.callstack.registerShortcuts(this.registerShortcuts.bind(this));
83 this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
84 this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(WebInspector.breakpointManager, this.showUISourceCode.bind(this));
85 this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this);
86 this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
87 this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
89 this._extensionSidebarPanes = [];
90 this._installDebuggerSidebarController();
92 WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this));
93 WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this));
94 this._dockSideChanged();
96 this._updateDebuggerButtons();
97 this._pauseOnExceptionEnabledChanged();
98 WebInspector.settings.pauseOnExceptionEnabled.addChangeListener(this._pauseOnExceptionEnabledChanged, this);
99 this._setTarget(WebInspector.context.flavor(WebInspector.Target));
100 WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointsActiveStateChanged, this._breakpointsActiveStateChanged, this);
101 WebInspector.context.addFlavorChangeListener(WebInspector.Target, this._onCurrentTargetChanged, this);
102 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
103 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerReset, this);
104 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
105 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
106 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.CallFrameSelected, this._callFrameSelected, this);
107 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame, this._consoleCommandEvaluatedInSelectedCallFrame, this);
108 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
109 WebInspector.targetManager.observeTargets(this);
112 WebInspector.SourcesPanel.minToolbarWidth = 215;
114 WebInspector.SourcesPanel.prototype = {
116 * @param {?WebInspector.Target} target
118 _setTarget: function(target)
123 if (target.debuggerModel.isPaused()) {
124 this._showDebuggerPausedDetails(/** @type {!WebInspector.DebuggerPausedDetails} */ (target.debuggerModel.debuggerPausedDetails()));
125 var callFrame = target.debuggerModel.selectedCallFrame();
127 this._selectCallFrame(callFrame);
129 this._paused = false;
130 this._clearInterface();
131 this._toggleDebuggerSidebarButton.setEnabled(true);
136 * @param {!WebInspector.Event} event
138 _onCurrentTargetChanged: function(event)
140 var target = /** @type {?WebInspector.Target} */ (event.data);
141 this._setTarget(target);
147 defaultFocusedElement: function()
149 return this._sourcesView.defaultFocusedElement();
162 WebInspector.context.setFlavor(WebInspector.SourcesPanel, this);
163 WebInspector.Panel.prototype.wasShown.call(this);
168 WebInspector.Panel.prototype.willHide.call(this);
169 WebInspector.context.setFlavor(WebInspector.SourcesPanel, null);
173 * @return {!WebInspector.SearchableView}
175 searchableView: function()
177 return this._sourcesView.searchableView();
180 _consoleCommandEvaluatedInSelectedCallFrame: function(event)
182 var target = /** @type {!WebInspector.Target} */ (event.target.target());
183 if (WebInspector.context.flavor(WebInspector.Target) !== target)
185 this.sidebarPanes.scopechain.update(target.debuggerModel.selectedCallFrame());
189 * @param {!WebInspector.Event} event
191 _debuggerPaused: function(event)
193 var details = /** @type {!WebInspector.DebuggerPausedDetails} */ (event.data);
195 WebInspector.inspectorView.setCurrentPanel(this);
197 if (WebInspector.context.flavor(WebInspector.Target) === details.target())
198 this._showDebuggerPausedDetails(details);
199 else if (!this._paused)
200 WebInspector.context.setFlavor(WebInspector.Target, details.target());
204 * @param {!WebInspector.DebuggerPausedDetails} details
206 _showDebuggerPausedDetails: function(details)
209 this._updateDebuggerButtons();
211 this.sidebarPanes.callstack.update(details);
214 * @param {!Element} element
215 * @this {WebInspector.SourcesPanel}
217 function didCreateBreakpointHitStatusMessage(element)
219 this.sidebarPanes.callstack.setStatus(element);
223 * @param {!WebInspector.UILocation} uiLocation
224 * @this {WebInspector.SourcesPanel}
226 function didGetUILocation(uiLocation)
228 var breakpoint = WebInspector.breakpointManager.findBreakpointOnLine(uiLocation.uiSourceCode, uiLocation.lineNumber);
231 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(breakpoint);
232 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
235 if (details.reason === WebInspector.DebuggerModel.BreakReason.DOM) {
236 WebInspector.domBreakpointsSidebarPane.highlightBreakpoint(details.auxData);
237 WebInspector.domBreakpointsSidebarPane.createBreakpointHitStatusMessage(details, didCreateBreakpointHitStatusMessage.bind(this));
238 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.EventListener) {
239 var eventName = details.auxData["eventName"];
240 var targetName = details.auxData["targetName"];
241 this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(eventName, targetName);
242 var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName, details.auxData);
243 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
244 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.XHR) {
245 this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData["breakpointURL"]);
246 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
247 } else if (details.reason === WebInspector.DebuggerModel.BreakReason.Exception)
248 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData["description"]));
249 else if (details.reason === WebInspector.DebuggerModel.BreakReason.Assert)
250 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on assertion."));
251 else if (details.reason === WebInspector.DebuggerModel.BreakReason.CSPViolation)
252 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a script blocked due to Content Security Policy directive: \"%s\".", details.auxData["directiveText"]));
253 else if (details.reason === WebInspector.DebuggerModel.BreakReason.DebugCommand)
254 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a debugged function"));
256 if (details.callFrames.length)
257 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(details.callFrames[0], didGetUILocation.bind(this));
259 console.warn("ScriptsPanel paused, but callFrames.length is zero."); // TODO remove this once we understand this case better
262 this._splitView.showBoth(true);
263 this._toggleDebuggerSidebarButton.setEnabled(false);
265 InspectorFrontendHost.bringToFront();
269 * @param {!WebInspector.Event} event
271 _debuggerResumed: function(event)
273 var target = /** @type {!WebInspector.Target} */ (event.target.target());
274 if (WebInspector.context.flavor(WebInspector.Target) !== target)
276 this._paused = false;
277 this._clearInterface();
278 this._toggleDebuggerSidebarButton.setEnabled(true);
282 * @param {!WebInspector.Event} event
284 _debuggerWasEnabled: function(event)
286 var target = /** @type {!WebInspector.Target} */ (event.target.target());
287 if (WebInspector.context.flavor(WebInspector.Target) !== target)
290 this._updateDebuggerButtons();
294 * @param {!WebInspector.Event} event
296 _debuggerReset: function(event)
298 this._debuggerResumed(event);
302 * @return {!WebInspector.View}
306 return this._sourcesView.visibleView();
310 * @param {!WebInspector.UISourceCode} uiSourceCode
311 * @param {number=} lineNumber
312 * @param {number=} columnNumber
313 * @param {boolean=} forceShowInPanel
315 showUISourceCode: function(uiSourceCode, lineNumber, columnNumber, forceShowInPanel)
317 this._showEditor(forceShowInPanel);
318 this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber);
321 _showEditor: function(forceShowInPanel)
323 WebInspector.inspectorView.showPanel("sources");
327 * @param {!WebInspector.UILocation} uiLocation
328 * @param {boolean=} forceShowInPanel
330 showUILocation: function(uiLocation, forceShowInPanel)
332 this.showUISourceCode(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, forceShowInPanel);
336 * @param {!WebInspector.UISourceCode} uiSourceCode
338 _revealInNavigator: function(uiSourceCode)
340 this._navigator.revealUISourceCode(uiSourceCode);
344 * @param {boolean} ignoreExecutionLineEvents
346 setIgnoreExecutionLineEvents: function(ignoreExecutionLineEvents)
348 this._ignoreExecutionLineEvents = ignoreExecutionLineEvents;
351 _executionLineChanged: function(uiLocation)
353 this._sourcesView.clearCurrentExecutionLine();
354 this._sourcesView.setExecutionLine(uiLocation);
355 if (this._ignoreExecutionLineEvents)
357 this._sourcesView.showSourceLocation(uiLocation.uiSourceCode, uiLocation.lineNumber, 0, undefined, true);
361 * @param {!WebInspector.Event} event
363 _callFrameSelected: function(event)
365 var callFrame = /** @type {?WebInspector.DebuggerModel.CallFrame} */ (event.data);
367 if (!callFrame || callFrame.target() !== WebInspector.context.flavor(WebInspector.Target))
370 this._selectCallFrame(callFrame);
374 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
376 _selectCallFrame: function(callFrame)
378 this.sidebarPanes.scopechain.update(callFrame);
379 this.sidebarPanes.watchExpressions.refreshExpressions();
380 this.sidebarPanes.callstack.setSelectedCallFrame(callFrame);
381 WebInspector.debuggerWorkspaceBinding.createCallFrameLiveLocation(callFrame, this._executionLineChanged.bind(this));
385 * @param {!WebInspector.Event} event
387 _sourceSelected: function(event)
389 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data.uiSourceCode);
390 this._sourcesView.showSourceLocation(uiSourceCode, undefined, undefined, !event.data.focusSource)
394 * @param {!WebInspector.Event} event
396 _sourceRenamed: function(event)
398 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
399 this._sourcesView.sourceRenamed(uiSourceCode);
402 _pauseOnExceptionEnabledChanged: function()
404 var enabled = WebInspector.settings.pauseOnExceptionEnabled.get();
405 this._pauseOnExceptionButton.toggled = enabled;
406 this._pauseOnExceptionButton.title = WebInspector.UIString(enabled ? "Don't pause on exceptions." : "Pause on exceptions.");
407 this._debugToolbarDrawer.classList.toggle("expanded", enabled);
410 _updateDebuggerButtons: function()
412 var currentTarget = WebInspector.context.flavor(WebInspector.Target);
417 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Resume script execution (%s)."))
418 this._pauseButton.state = true;
419 this._pauseButton.setLongClickOptionsEnabled((function() { return [ this._longResumeButton ] }).bind(this));
421 this._pauseButton.setEnabled(true);
422 this._stepOverButton.setEnabled(true);
423 this._stepIntoButton.setEnabled(true);
424 this._stepOutButton.setEnabled(true);
426 this._updateButtonTitle(this._pauseButton, WebInspector.UIString("Pause script execution (%s)."))
427 this._pauseButton.state = false;
428 this._pauseButton.setLongClickOptionsEnabled(null);
430 this._pauseButton.setEnabled(!currentTarget.debuggerModel.isPausing());
431 this._stepOverButton.setEnabled(false);
432 this._stepIntoButton.setEnabled(false);
433 this._stepOutButton.setEnabled(false);
437 _clearInterface: function()
439 this.sidebarPanes.callstack.update(null);
440 this.sidebarPanes.scopechain.update(null);
441 this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
442 WebInspector.domBreakpointsSidebarPane.clearBreakpointHighlight();
443 this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
444 this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
446 this._sourcesView.clearCurrentExecutionLine();
447 this._updateDebuggerButtons();
450 _togglePauseOnExceptions: function()
452 WebInspector.settings.pauseOnExceptionEnabled.set(!this._pauseOnExceptionButton.toggled);
458 _runSnippet: function()
460 var uiSourceCode = this._sourcesView.currentUISourceCode();
461 if (uiSourceCode.project().type() !== WebInspector.projectTypes.Snippets)
464 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
465 if (!currentExecutionContext)
468 WebInspector.scriptSnippetModel.evaluateScriptSnippet(currentExecutionContext, uiSourceCode);
473 * @param {!WebInspector.Event} event
475 _editorSelected: function(event)
477 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
478 this._editorChanged(uiSourceCode);
482 * @param {!WebInspector.Event} event
484 _editorClosed: function(event)
486 var wasSelected = /** @type {boolean} */ (event.data.wasSelected);
488 this._editorChanged(null);
492 * @param {?WebInspector.UISourceCode} uiSourceCode
494 _editorChanged: function(uiSourceCode)
496 var isSnippet = uiSourceCode && uiSourceCode.project().type() === WebInspector.projectTypes.Snippets;
497 this._runSnippetButton.element.classList.toggle("hidden", !isSnippet);
503 togglePause: function()
505 var target = WebInspector.context.flavor(WebInspector.Target);
510 this._paused = false;
511 target.debuggerModel.resume();
513 // Make sure pauses didn't stick skipped.
514 target.debuggerModel.pause();
517 this._clearInterface();
522 * @return {?WebInspector.DebuggerModel}
524 _prepareToResume: function()
529 this._paused = false;
531 this._clearInterface();
532 var target = WebInspector.context.flavor(WebInspector.Target);
533 return target ? target.debuggerModel : null;
539 _longResume: function()
541 var debuggerModel = this._prepareToResume();
545 debuggerModel.skipAllPausesUntilReloadOrTimeout(500);
546 debuggerModel.resume();
553 _stepOverClicked: function()
555 var debuggerModel = this._prepareToResume();
559 debuggerModel.stepOver();
566 _stepIntoClicked: function()
568 var debuggerModel = this._prepareToResume();
572 debuggerModel.stepInto();
579 _stepOutClicked: function()
581 var debuggerModel = this._prepareToResume();
585 debuggerModel.stepOut();
590 * @param {!WebInspector.Event} event
592 _callFrameSelectedInSidebar: function(event)
594 var callFrame = /** @type {!WebInspector.DebuggerModel.CallFrame} */ (event.data);
595 callFrame.target().debuggerModel.setSelectedCallFrame(callFrame);
599 * @param {!WebInspector.DebuggerModel.Location} rawLocation
601 continueToLocation: function(rawLocation)
603 if (!this._prepareToResume())
606 rawLocation.continueToLocation();
609 _toggleBreakpointsClicked: function(event)
611 WebInspector.breakpointManager.setBreakpointsActive(!WebInspector.breakpointManager.breakpointsActive());
614 _breakpointsActiveStateChanged: function(event)
616 var active = event.data;
617 this._toggleBreakpointsButton.toggled = !active;
618 this.sidebarPanes.jsBreakpoints.listElement.classList.toggle("breakpoints-list-deactivated", !active);
619 this._sourcesView.toggleBreakpointsActiveState(active);
621 this._toggleBreakpointsButton.title = WebInspector.UIString("Deactivate breakpoints.");
623 this._toggleBreakpointsButton.title = WebInspector.UIString("Activate breakpoints.");
626 _createDebugToolbar: function()
628 var debugToolbar = document.createElementWithClass("div", "scripts-debug-toolbar");
631 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
634 title = WebInspector.UIString("Run snippet (%s).");
635 handler = this._runSnippet.bind(this);
636 this._runSnippetButton = this._createButtonAndRegisterShortcuts("scripts-run-snippet", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.RunSnippet);
637 debugToolbar.appendChild(this._runSnippetButton.element);
638 this._runSnippetButton.element.classList.add("hidden");
641 this._pauseButton = this._createButtonAndRegisterShortcutsForAction("scripts-pause", "", "debugger.toggle-pause");
642 debugToolbar.appendChild(this._pauseButton.element);
645 title = WebInspector.UIString("Resume with all pauses blocked for 500 ms");
646 this._longResumeButton = new WebInspector.StatusBarButton(title, "scripts-long-resume");
647 this._longResumeButton.addEventListener("click", this._longResume.bind(this), this);
650 title = WebInspector.UIString("Step over next function call (%s).");
651 handler = this._stepOverClicked.bind(this);
652 this._stepOverButton = this._createButtonAndRegisterShortcuts("scripts-step-over", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOver);
653 debugToolbar.appendChild(this._stepOverButton.element);
656 title = WebInspector.UIString("Step into next function call (%s).");
657 handler = this._stepIntoClicked.bind(this);
658 this._stepIntoButton = this._createButtonAndRegisterShortcuts("scripts-step-into", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepInto);
659 debugToolbar.appendChild(this._stepIntoButton.element);
662 title = WebInspector.UIString("Step out of current function (%s).");
663 handler = this._stepOutClicked.bind(this);
664 this._stepOutButton = this._createButtonAndRegisterShortcuts("scripts-step-out", title, handler, WebInspector.ShortcutsScreen.SourcesPanelShortcuts.StepOut);
665 debugToolbar.appendChild(this._stepOutButton.element);
667 // Toggle Breakpoints
668 this._toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate breakpoints."), "scripts-toggle-breakpoints");
669 this._toggleBreakpointsButton.toggled = false;
670 this._toggleBreakpointsButton.addEventListener("click", this._toggleBreakpointsClicked, this);
671 debugToolbar.appendChild(this._toggleBreakpointsButton.element);
673 // Pause on Exception
674 this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item");
675 this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions, this);
676 debugToolbar.appendChild(this._pauseOnExceptionButton.element);
681 _createDebugToolbarDrawer: function()
683 var debugToolbarDrawer = document.createElementWithClass("div", "scripts-debug-toolbar-drawer");
685 var label = WebInspector.UIString("Pause On Caught Exceptions");
686 var setting = WebInspector.settings.pauseOnCaughtException;
687 debugToolbarDrawer.appendChild(WebInspector.SettingsUI.createSettingCheckbox(label, setting, true));
689 return debugToolbarDrawer;
693 * @param {!WebInspector.StatusBarButton} button
694 * @param {string} buttonTitle
696 _updateButtonTitle: function(button, buttonTitle)
698 var hasShortcuts = button.shortcuts && button.shortcuts.length;
700 button.title = String.vsprintf(buttonTitle, [button.shortcuts[0].name]);
702 button.title = buttonTitle;
706 * @param {string} buttonId
707 * @param {string} buttonTitle
708 * @param {function(!Event=):boolean} handler
709 * @param {!Array.<!WebInspector.KeyboardShortcut.Descriptor>} shortcuts
710 * @return {!WebInspector.StatusBarButton}
712 _createButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts)
714 var button = new WebInspector.StatusBarButton(buttonTitle, buttonId);
715 button.element.addEventListener("click", handler, false);
716 button.shortcuts = shortcuts;
717 this._updateButtonTitle(button, buttonTitle);
718 this.registerShortcuts(shortcuts, handler);
723 * @param {string} buttonId
724 * @param {string} buttonTitle
725 * @param {string} actionId
726 * @return {!WebInspector.StatusBarButton}
728 _createButtonAndRegisterShortcutsForAction: function(buttonId, buttonTitle, actionId)
735 return WebInspector.actionRegistry.execute(actionId);
737 var shortcuts = WebInspector.shortcutRegistry.shortcutDescriptorsForAction(actionId);
738 return this._createButtonAndRegisterShortcuts(buttonId, buttonTitle, handler, shortcuts);
741 addToWatch: function(expression)
743 this.sidebarPanes.watchExpressions.addExpression(expression);
746 _installDebuggerSidebarController: function()
748 this._toggleNavigatorSidebarButton = this.editorView.createShowHideSidebarButton("navigator", "scripts-navigator-show-hide-button");
749 this.editorView.mainElement().appendChild(this._toggleNavigatorSidebarButton.element);
751 this._toggleDebuggerSidebarButton = this._splitView.createShowHideSidebarButton("debugger", "scripts-debugger-show-hide-button");
753 this._splitView.mainElement().appendChild(this._toggleDebuggerSidebarButton.element);
754 this._splitView.mainElement().appendChild(this._debugSidebarResizeWidgetElement);
757 _updateDebugSidebarResizeWidget: function()
759 this._debugSidebarResizeWidgetElement.classList.toggle("hidden", this._splitView.showMode() !== WebInspector.SplitView.ShowMode.Both);
763 * @param {!WebInspector.UISourceCode} uiSourceCode
765 _showLocalHistory: function(uiSourceCode)
767 WebInspector.RevisionHistoryView.showHistory(uiSourceCode);
771 * @param {!Event} event
772 * @param {!WebInspector.ContextMenu} contextMenu
773 * @param {!Object} target
775 appendApplicableItems: function(event, contextMenu, target)
777 this._appendUISourceCodeItems(event, contextMenu, target);
778 this._appendRemoteObjectItems(contextMenu, target);
781 _suggestReload: function()
783 if (window.confirm(WebInspector.UIString("It is recommended to restart inspector after making these changes. Would you like to restart it?")))
784 WebInspector.reload();
788 * @param {!WebInspector.UISourceCode} uiSourceCode
790 _mapFileSystemToNetwork: function(uiSourceCode)
792 WebInspector.SelectUISourceCodeForProjectTypesDialog.show(uiSourceCode.name(), [WebInspector.projectTypes.Network, WebInspector.projectTypes.ContentScripts], mapFileSystemToNetwork.bind(this), this.editorView.mainElement())
795 * @param {!WebInspector.UISourceCode} networkUISourceCode
796 * @this {WebInspector.SourcesPanel}
798 function mapFileSystemToNetwork(networkUISourceCode)
800 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding);
801 this._suggestReload();
806 * @param {!WebInspector.UISourceCode} uiSourceCode
808 _removeNetworkMapping: function(uiSourceCode)
810 if (confirm(WebInspector.UIString("Are you sure you want to remove network mapping?"))) {
811 this._workspace.removeMapping(uiSourceCode);
812 this._suggestReload();
817 * @param {!WebInspector.UISourceCode} networkUISourceCode
819 _mapNetworkToFileSystem: function(networkUISourceCode)
821 WebInspector.SelectUISourceCodeForProjectTypesDialog.show(networkUISourceCode.name(), [WebInspector.projectTypes.FileSystem], mapNetworkToFileSystem.bind(this), this.editorView.mainElement())
824 * @param {!WebInspector.UISourceCode} uiSourceCode
825 * @this {WebInspector.SourcesPanel}
827 function mapNetworkToFileSystem(uiSourceCode)
829 this._workspace.addMapping(networkUISourceCode, uiSourceCode, WebInspector.fileSystemWorkspaceBinding);
830 this._suggestReload();
835 * @param {!WebInspector.ContextMenu} contextMenu
836 * @param {!WebInspector.UISourceCode} uiSourceCode
838 _appendUISourceCodeMappingItems: function(contextMenu, uiSourceCode)
840 if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) {
841 var hasMappings = !!uiSourceCode.url;
843 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to network resource\u2026" : "Map to Network Resource\u2026"), this._mapFileSystemToNetwork.bind(this, uiSourceCode));
845 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove network mapping" : "Remove Network Mapping"), this._removeNetworkMapping.bind(this, uiSourceCode));
849 * @param {!WebInspector.Project} project
851 function filterProject(project)
853 return project.type() === WebInspector.projectTypes.FileSystem;
856 if (uiSourceCode.project().type() === WebInspector.projectTypes.Network || uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts) {
857 if (!this._workspace.projects().filter(filterProject).length)
859 if (this._workspace.uiSourceCodeForURL(uiSourceCode.url) === uiSourceCode)
860 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Map to file system resource\u2026" : "Map to File System Resource\u2026"), this._mapNetworkToFileSystem.bind(this, uiSourceCode));
865 * @param {!Event} event
866 * @param {!WebInspector.ContextMenu} contextMenu
867 * @param {!Object} target
869 _appendUISourceCodeItems: function(event, contextMenu, target)
871 if (!(target instanceof WebInspector.UISourceCode))
874 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (target);
875 var project = uiSourceCode.project();
876 if (project.type() !== WebInspector.projectTypes.FileSystem)
877 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Local modifications\u2026" : "Local Modifications\u2026"), this._showLocalHistory.bind(this, uiSourceCode));
878 this._appendUISourceCodeMappingItems(contextMenu, uiSourceCode);
880 if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script && project.type() !== WebInspector.projectTypes.Snippets)
881 this.sidebarPanes.callstack.appendBlackboxURLContextMenuItems(contextMenu, uiSourceCode.url);
883 if (!event.target.isSelfOrDescendant(this.editorView.sidebarElement())) {
884 contextMenu.appendSeparator();
885 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in navigator" : "Reveal in Navigator"), this._handleContextMenuReveal.bind(this, uiSourceCode));
890 * @param {!WebInspector.UISourceCode} uiSourceCode
892 _handleContextMenuReveal: function(uiSourceCode)
894 this.editorView.showBoth();
895 this._revealInNavigator(uiSourceCode);
899 * @param {!WebInspector.ContextMenu} contextMenu
900 * @param {!Object} target
902 _appendRemoteObjectItems: function(contextMenu, target)
904 if (!(target instanceof WebInspector.RemoteObject))
906 var remoteObject = /** @type {!WebInspector.RemoteObject} */ (target);
907 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Store as global variable" : "Store as Global Variable"), this._saveToTempVariable.bind(this, remoteObject));
908 if (remoteObject.type === "function")
909 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Show function definition" : "Show Function Definition"), this._showFunctionDefinition.bind(this, remoteObject));
913 * @param {!WebInspector.RemoteObject} remoteObject
915 _saveToTempVariable: function(remoteObject)
917 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
918 if (!currentExecutionContext)
921 currentExecutionContext.evaluate("window", "", false, true, false, false, didGetGlobalObject.bind(null, currentExecutionContext.target()));
923 * @param {!WebInspector.Target} target
924 * @param {?WebInspector.RemoteObject} global
925 * @param {boolean=} wasThrown
927 function didGetGlobalObject(target, global, wasThrown)
930 * @suppressReceiverCheck
933 function remoteFunction(value)
937 while ((prefix + index) in this)
939 var name = prefix + index;
944 if (wasThrown || !global)
945 failedToSave(target, global);
947 global.callFunction(remoteFunction, [WebInspector.RemoteObject.toCallArgument(remoteObject)], didSave.bind(null, global));
951 * @param {!WebInspector.RemoteObject} global
952 * @param {?WebInspector.RemoteObject} result
953 * @param {boolean=} wasThrown
955 function didSave(global, result, wasThrown)
957 var currentExecutionContext = WebInspector.context.flavor(WebInspector.ExecutionContext);
959 if (!currentExecutionContext || wasThrown || !result || result.type !== "string")
960 failedToSave(global.target(), result);
962 WebInspector.ConsoleModel.evaluateCommandInConsole(currentExecutionContext, result.value);
966 * @param {!WebInspector.Target} target
967 * @param {?WebInspector.RemoteObject} result
969 function failedToSave(target, result)
971 var message = WebInspector.UIString("Failed to save to temp variable.");
973 message += " " + result.description;
976 WebInspector.console.error(message);
981 * @param {!WebInspector.RemoteObject} remoteObject
983 _showFunctionDefinition: function(remoteObject)
985 var debuggerModel = remoteObject.target().debuggerModel;
988 * @param {?WebInspector.DebuggerModel.FunctionDetails} response
989 * @this {WebInspector.SourcesPanel}
991 function didGetFunctionDetails(response)
993 if (!response || !response.location)
996 var location = response.location;
1000 var uiLocation = WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(location);
1002 this.showUILocation(uiLocation, true);
1004 debuggerModel.functionDetails(remoteObject, didGetFunctionDetails.bind(this));
1007 showGoToSourceDialog: function()
1009 this._sourcesView.showOpenResourceDialog();
1012 _dockSideChanged: function()
1014 var vertically = WebInspector.dockController.isVertical() && WebInspector.settings.splitVerticallyWhenDockedToRight.get();
1015 this._splitVertically(vertically);
1019 * @param {boolean} vertically
1021 _splitVertically: function(vertically)
1023 if (this.sidebarPaneView && vertically === !this._splitView.isVertical())
1026 if (this.sidebarPaneView)
1027 this.sidebarPaneView.detach();
1029 this._splitView.setVertical(!vertically);
1032 this._splitView.uninstallResizer(this._sourcesView.statusBarContainerElement());
1034 this._splitView.installResizer(this._sourcesView.statusBarContainerElement());
1036 // Create vertical box with stack.
1037 var vbox = new WebInspector.VBox();
1038 vbox.element.appendChild(this._debugToolbarDrawer);
1039 vbox.element.appendChild(this.debugToolbar);
1040 vbox.setMinimumAndPreferredSizes(25, 25, WebInspector.SourcesPanel.minToolbarWidth, 100);
1041 var sidebarPaneStack = new WebInspector.SidebarPaneStack();
1042 sidebarPaneStack.element.classList.add("flex-auto");
1043 sidebarPaneStack.show(vbox.element);
1046 // Populate the only stack.
1047 for (var pane in this.sidebarPanes)
1048 sidebarPaneStack.addPane(this.sidebarPanes[pane]);
1049 this._extensionSidebarPanesContainer = sidebarPaneStack;
1050 this.sidebarPaneView = vbox;
1052 var splitView = new WebInspector.SplitView(true, true, "sourcesPanelDebuggerSidebarSplitViewState", 0.5);
1053 vbox.show(splitView.mainElement());
1055 // Populate the left stack.
1056 sidebarPaneStack.addPane(this.sidebarPanes.threads);
1057 sidebarPaneStack.addPane(this.sidebarPanes.callstack);
1058 sidebarPaneStack.addPane(this.sidebarPanes.jsBreakpoints);
1059 sidebarPaneStack.addPane(this.sidebarPanes.domBreakpoints);
1060 sidebarPaneStack.addPane(this.sidebarPanes.xhrBreakpoints);
1061 sidebarPaneStack.addPane(this.sidebarPanes.eventListenerBreakpoints);
1062 if (this.sidebarPanes.workerList)
1063 sidebarPaneStack.addPane(this.sidebarPanes.workerList);
1065 var tabbedPane = new WebInspector.SidebarTabbedPane();
1066 tabbedPane.show(splitView.sidebarElement());
1067 tabbedPane.addPane(this.sidebarPanes.scopechain);
1068 tabbedPane.addPane(this.sidebarPanes.watchExpressions);
1069 this._extensionSidebarPanesContainer = tabbedPane;
1071 this.sidebarPaneView = splitView;
1073 for (var i = 0; i < this._extensionSidebarPanes.length; ++i)
1074 this._extensionSidebarPanesContainer.addPane(this._extensionSidebarPanes[i]);
1076 this.sidebarPaneView.show(this._splitView.sidebarElement());
1077 this.sidebarPanes.threads.expand();
1078 this.sidebarPanes.scopechain.expand();
1079 this.sidebarPanes.jsBreakpoints.expand();
1080 this.sidebarPanes.callstack.expand();
1081 this._sidebarPaneStack = sidebarPaneStack;
1082 this._updateTargetsSidebarVisibility();
1083 if (WebInspector.settings.watchExpressions.get().length > 0)
1084 this.sidebarPanes.watchExpressions.expand();
1088 * @param {string} id
1089 * @param {!WebInspector.SidebarPane} pane
1091 addExtensionSidebarPane: function(id, pane)
1093 this._extensionSidebarPanes.push(pane);
1094 this._extensionSidebarPanesContainer.addPane(pane);
1095 this.setHideOnDetach();
1099 * @return {!WebInspector.SourcesView}
1101 sourcesView: function()
1103 return this._sourcesView;
1107 * @param {!WebInspector.Target} target
1109 targetAdded: function(target)
1111 this._updateTargetsSidebarVisibility();
1115 * @param {!WebInspector.Target} target
1117 targetRemoved: function(target)
1119 this._updateTargetsSidebarVisibility();
1122 _updateTargetsSidebarVisibility: function()
1124 if (!this._sidebarPaneStack)
1126 this._sidebarPaneStack.togglePaneHidden(this.sidebarPanes.threads, WebInspector.targetManager.targets().length < 2);
1129 __proto__: WebInspector.Panel.prototype
1134 * @param {!Element} element
1136 WebInspector.UpgradeFileSystemDropTarget = function(element)
1138 element.addEventListener("dragenter", this._onDragEnter.bind(this), true);
1139 element.addEventListener("dragover", this._onDragOver.bind(this), true);
1140 this._element = element;
1143 WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType = "Files";
1145 WebInspector.UpgradeFileSystemDropTarget.prototype = {
1146 _onDragEnter: function (event)
1148 if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1)
1150 event.consume(true);
1153 _onDragOver: function (event)
1155 if (event.dataTransfer.types.indexOf(WebInspector.UpgradeFileSystemDropTarget.dragAndDropFilesType) === -1)
1157 event.dataTransfer.dropEffect = "copy";
1158 event.consume(true);
1159 if (this._dragMaskElement)
1161 this._dragMaskElement = this._element.createChild("div", "fill drag-mask");
1162 this._dragMaskElement.createChild("div", "fill drag-mask-inner").textContent = WebInspector.UIString("Drop workspace folder here");
1163 this._dragMaskElement.addEventListener("drop", this._onDrop.bind(this), true);
1164 this._dragMaskElement.addEventListener("dragleave", this._onDragLeave.bind(this), true);
1167 _onDrop: function (event)
1169 event.consume(true);
1171 var items = /** @type {!Array.<!DataTransferItem>} */ (event.dataTransfer.items);
1174 var entry = items[0].webkitGetAsEntry();
1175 if (!entry.isDirectory)
1177 InspectorFrontendHost.upgradeDraggedFileSystemPermissions(entry.filesystem);
1180 _onDragLeave: function (event)
1182 event.consume(true);
1186 _removeMask: function ()
1188 this._dragMaskElement.remove();
1189 delete this._dragMaskElement;
1195 * @implements {WebInspector.ContextMenu.Provider}
1197 WebInspector.SourcesPanel.ContextMenuProvider = function()
1201 WebInspector.SourcesPanel.ContextMenuProvider.prototype = {
1203 * @param {!Event} event
1204 * @param {!WebInspector.ContextMenu} contextMenu
1205 * @param {!Object} target
1207 appendApplicableItems: function(event, contextMenu, target)
1209 WebInspector.inspectorView.panel("sources").appendApplicableItems(event, contextMenu, target);
1215 * @implements {WebInspector.Revealer}
1217 WebInspector.SourcesPanel.UILocationRevealer = function()
1221 WebInspector.SourcesPanel.UILocationRevealer.prototype = {
1223 * @param {!Object} uiLocation
1225 reveal: function(uiLocation)
1227 if (uiLocation instanceof WebInspector.UILocation)
1228 /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUILocation(uiLocation);
1234 * @implements {WebInspector.Revealer}
1236 WebInspector.SourcesPanel.UISourceCodeRevealer = function()
1240 WebInspector.SourcesPanel.UISourceCodeRevealer.prototype = {
1242 * @param {!Object} uiSourceCode
1244 reveal: function(uiSourceCode)
1246 if (uiSourceCode instanceof WebInspector.UISourceCode)
1247 /** @type {!WebInspector.SourcesPanel} */ (WebInspector.inspectorView.panel("sources")).showUISourceCode(uiSourceCode);
1253 * @implements {WebInspector.ActionDelegate}
1255 WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate = function() {}
1257 WebInspector.SourcesPanel.ShowGoToSourceDialogActionDelegate.prototype = {
1261 handleAction: function()
1263 var panel = /** @type {?WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources"));
1266 panel.showGoToSourceDialog();
1273 * @extends {WebInspector.UISettingDelegate}
1275 WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate = function()
1277 WebInspector.UISettingDelegate.call(this);
1280 WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate.prototype = {
1283 * @return {!Element}
1285 settingElement: function()
1287 var disableJSElement = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Disable JavaScript"), WebInspector.settings.javaScriptDisabled);
1288 this._disableJSCheckbox = disableJSElement.getElementsByTagName("input")[0];
1289 WebInspector.settings.javaScriptDisabled.addChangeListener(this._settingChanged, this);
1290 var disableJSInfoParent = this._disableJSCheckbox.parentElement.createChild("span", "monospace");
1291 this._disableJSInfo = disableJSInfoParent.createChild("span", "object-info-state-note hidden");
1292 this._disableJSInfo.title = WebInspector.UIString("JavaScript is blocked on the inspected page (may be disabled in browser settings).");
1294 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._updateScriptDisabledCheckbox, this);
1295 this._updateScriptDisabledCheckbox();
1296 return disableJSElement;
1300 * @param {!WebInspector.Event} event
1302 _settingChanged: function(event)
1304 PageAgent.setScriptExecutionDisabled(event.data, this._updateScriptDisabledCheckbox.bind(this));
1307 _updateScriptDisabledCheckbox: function()
1309 PageAgent.getScriptExecutionStatus(executionStatusCallback.bind(this));
1312 * @param {?Protocol.Error} error
1313 * @param {string} status
1314 * @this {WebInspector.SourcesPanel.DisableJavaScriptSettingDelegate}
1316 function executionStatusCallback(error, status)
1318 if (error || !status)
1321 var forbidden = (status === "forbidden");
1322 var disabled = forbidden || (status === "disabled");
1324 this._disableJSInfo.classList.toggle("hidden", !forbidden);
1325 this._disableJSCheckbox.checked = disabled;
1326 this._disableJSCheckbox.disabled = forbidden;
1330 __proto__: WebInspector.UISettingDelegate.prototype
1335 * @implements {WebInspector.ActionDelegate}
1337 WebInspector.SourcesPanel.TogglePauseActionDelegate = function()
1341 WebInspector.SourcesPanel.TogglePauseActionDelegate.prototype = {
1345 handleAction: function()
1347 var panel = /** @type {?WebInspector.SourcesPanel} */ (WebInspector.inspectorView.showPanel("sources"));
1350 panel.togglePause();