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.
27 WebInspector.ScriptsPanel = function(presentationModel)
29 WebInspector.Panel.call(this, "scripts");
31 WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions);
33 this._presentationModel = presentationModel;
35 this.registerShortcuts();
37 this.topStatusBar = document.createElement("div");
38 this.topStatusBar.className = "status-bar";
39 this.topStatusBar.id = "scripts-status-bar";
40 this.element.appendChild(this.topStatusBar);
42 this.backButton = document.createElement("button");
43 this.backButton.className = "status-bar-item";
44 this.backButton.id = "scripts-back";
45 this.backButton.title = WebInspector.UIString("Show the previous script resource.");
46 this.backButton.disabled = true;
47 this.backButton.appendChild(document.createElement("img"));
48 this.backButton.addEventListener("click", this._goBack.bind(this), false);
49 this.topStatusBar.appendChild(this.backButton);
51 this.forwardButton = document.createElement("button");
52 this.forwardButton.className = "status-bar-item";
53 this.forwardButton.id = "scripts-forward";
54 this.forwardButton.title = WebInspector.UIString("Show the next script resource.");
55 this.forwardButton.disabled = true;
56 this.forwardButton.appendChild(document.createElement("img"));
57 this.forwardButton.addEventListener("click", this._goForward.bind(this), false);
58 this.topStatusBar.appendChild(this.forwardButton);
60 this._filesSelectElement = document.createElement("select");
61 this._filesSelectElement.className = "status-bar-item";
62 this._filesSelectElement.id = "scripts-files";
63 this._filesSelectElement.addEventListener("change", this._filesSelectChanged.bind(this), false);
64 this._filesSelectElement.addEventListener("keyup", this._filesSelectChanged.bind(this), false);
65 this.topStatusBar.appendChild(this._filesSelectElement);
67 this.functionsSelectElement = document.createElement("select");
68 this.functionsSelectElement.className = "status-bar-item";
69 this.functionsSelectElement.id = "scripts-functions";
71 // FIXME: append the functions select element to the top status bar when it is implemented.
72 // this.topStatusBar.appendChild(this.functionsSelectElement);
74 this._createSidebarButtons();
76 this.toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints");
77 this.toggleBreakpointsButton.toggled = true;
78 this.toggleBreakpointsButton.addEventListener("click", this.toggleBreakpointsClicked.bind(this), false);
79 this.sidebarButtonsElement.appendChild(this.toggleBreakpointsButton.element);
81 this.debuggerStatusElement = document.createElement("div");
82 this.debuggerStatusElement.id = "scripts-debugger-status";
83 this.sidebarButtonsElement.appendChild(this.debuggerStatusElement);
85 this.viewsContainerElement = document.createElement("div");
86 this.viewsContainerElement.id = "script-resource-views";
88 this.sidebarElement = document.createElement("div");
89 this.sidebarElement.id = "scripts-sidebar";
91 this.sidebarResizeElement = document.createElement("div");
92 this.sidebarResizeElement.className = "sidebar-resizer-vertical";
93 this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
95 this.sidebarResizeWidgetElement = document.createElement("div");
96 this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget";
97 this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
98 this.topStatusBar.appendChild(this.sidebarResizeWidgetElement);
100 this.sidebarPanes = {};
101 this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
102 this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(this._presentationModel);
103 this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
104 this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(this._presentationModel, this._showSourceLine.bind(this));
105 if (Preferences.nativeInstrumentationEnabled) {
106 this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane;
107 this.sidebarPanes.xhrBreakpoints = new WebInspector.XHRBreakpointsSidebarPane();
108 this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
111 if (Preferences.canInspectWorkers && WebInspector.workerManager)
112 this.sidebarElement.addEventListener("contextmenu", this._contextMenu.bind(this), false);
113 if (Preferences.canInspectWorkers && WebInspector.workerManager && WebInspector.settings.workerInspectionEnabled.get()) {
114 WorkerAgent.setWorkerInspectionEnabled(true);
115 this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
117 this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
119 for (var pane in this.sidebarPanes)
120 this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
122 this.sidebarPanes.callstack.expanded = true;
124 this.sidebarPanes.scopechain.expanded = true;
125 this.sidebarPanes.jsBreakpoints.expanded = true;
127 var helpSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
128 this.sidebarPanes.callstack.registerShortcuts(helpSection, this.registerShortcut.bind(this));
130 var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
131 var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
132 var panelEnablerButton = WebInspector.UIString("Enable Debugging");
134 this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
135 this.panelEnablerView.addEventListener("enable clicked", this._enableDebugging, this);
137 this.element.appendChild(this.panelEnablerView.element);
138 this.element.appendChild(this.viewsContainerElement);
139 this.element.appendChild(this.sidebarElement);
140 this.element.appendChild(this.sidebarResizeElement);
142 this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
143 this.enableToggleButton.addEventListener("click", this._toggleDebugging.bind(this), false);
144 if (Preferences.debuggerAlwaysEnabled)
145 this.enableToggleButton.element.addStyleClass("hidden");
147 this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3);
148 this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false);
150 this._toggleFormatSourceButton = new WebInspector.StatusBarButton(WebInspector.UIString("Pretty print"), "scripts-toggle-pretty-print-status-bar-item");
151 this._toggleFormatSourceButton.toggled = false;
152 this._toggleFormatSourceButton.addEventListener("click", this._toggleFormatSource.bind(this), false);
154 this._scriptViewStatusBarItemsContainer = document.createElement("div");
155 this._scriptViewStatusBarItemsContainer.style.display = "inline-block";
157 this._debuggerEnabled = Preferences.debuggerAlwaysEnabled;
161 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
162 WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._debuggerWasDisabled, this);
164 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this)
165 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.UISourceCodeReplaced, this._uiSourceCodeReplaced, this);
166 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessageAdded, this._consoleMessageAdded, this);
167 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.ConsoleMessagesCleared, this._consoleMessagesCleared, this);
168 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, this._breakpointAdded, this);
169 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
170 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerPaused, this._debuggerPaused, this);
171 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.DebuggerResumed, this._debuggerResumed, this);
172 this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, this._callFrameSelected, this);
174 var enableDebugger = Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled.get();
176 WebInspector.debuggerModel.enableDebugger();
178 WebInspector.settings.showScriptFolders.addChangeListener(this._showScriptFoldersSettingChanged.bind(this));
181 // Keep these in sync with WebCore::ScriptDebugServer
182 WebInspector.ScriptsPanel.PauseOnExceptionsState = {
183 DontPauseOnExceptions : "none",
184 PauseOnAllExceptions : "all",
185 PauseOnUncaughtExceptions: "uncaught"
188 WebInspector.ScriptsPanel.BreakReason = {
190 EventListener: "EventListener",
192 Exception: "exception"
195 WebInspector.ScriptsPanel.prototype = {
196 get toolbarItemLabel()
198 return WebInspector.UIString("Scripts");
203 return [this.enableToggleButton.element, this._pauseOnExceptionButton.element, this._toggleFormatSourceButton.element, this._scriptViewStatusBarItemsContainer];
206 get defaultFocusedElement()
208 return this._filesSelectElement;
218 WebInspector.Panel.prototype.show.call(this);
219 this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
220 if (Preferences.nativeInstrumentationEnabled)
221 this.sidebarElement.insertBefore(this.sidebarPanes.domBreakpoints.element, this.sidebarPanes.xhrBreakpoints.element);
222 this.sidebarPanes.watchExpressions.show();
225 get breakpointsActivated()
227 return this.toggleBreakpointsButton.toggled;
230 _uiSourceCodeAdded: function(event)
232 var uiSourceCode = event.data;
234 if (!uiSourceCode.url) {
235 // Anonymous sources are shown only when stepping.
239 this._addOptionToFilesSelect(uiSourceCode);
241 var lastViewedURL = WebInspector.settings.lastViewedScriptFile.get();
242 if (!this._filesSelectElement.initialSelectionProcessed) {
243 this._filesSelectElement.initialSelectionProcessed = true;
244 // Option we just added is the only option in files select.
245 // We have to show corresponding source frame immediately.
246 this._showSourceFrameAndAddToHistory(uiSourceCode);
247 // Restore original value of lastViewedScriptFile because
248 // source frame was shown as a result of initial load.
249 WebInspector.settings.lastViewedScriptFile.set(lastViewedURL);
250 } else if (uiSourceCode.url === lastViewedURL)
251 this._showSourceFrameAndAddToHistory(uiSourceCode);
254 _showScriptFoldersSettingChanged: function()
256 var selectedOption = this._filesSelectElement[this._filesSelectElement.selectedIndex];
257 var uiSourceCode = selectedOption ? selectedOption._uiSourceCode : null;
259 var options = Array.prototype.slice.call(this._filesSelectElement);
260 this._resetFilesSelect();
261 for (var i = 0; i < options.length; ++i) {
262 if (options[i]._uiSourceCode)
263 this._addOptionToFilesSelect(options[i]._uiSourceCode);
267 var index = uiSourceCode._option.index;
268 if (typeof index === "number")
269 this._filesSelectElement.selectedIndex = index;
273 _addOptionToFilesSelect: function(uiSourceCode)
275 var showScriptFolders = WebInspector.settings.showScriptFolders.get();
277 var select = this._filesSelectElement;
278 if (!select.domainOptions)
279 select.domainOptions = {};
280 if (!select.folderOptions)
281 select.folderOptions = {};
283 var option = document.createElement("option");
284 option._uiSourceCode = uiSourceCode;
285 var parsedURL = uiSourceCode.url.asParsedURL();
287 var names = this._folderAndDisplayNameForScriptURL(uiSourceCode.url);
288 const indent = (!showScriptFolders || WebInspector.isMac()) ? "" : "\u00a0\u00a0\u00a0\u00a0";
289 option.text = indent + (names.displayName ? names.displayName : WebInspector.UIString("(program)"));
290 option.displayName = names.displayName;
292 var folderNameForSorting;
293 if (uiSourceCode.isContentScript)
294 folderNameForSorting = "2:" + names.folderName;
296 folderNameForSorting = "0:" + (names.domain ? names.domain + "\t\t" : "") + names.folderName;
298 option.nameForSorting = folderNameForSorting + "\t/\t" + names.displayName; // Use '\t' to make files stick to their folder.
299 option.title = uiSourceCode.url;
300 if (uiSourceCode.isContentScript)
301 option.addStyleClass("extension-script");
303 function insertOrdered(option)
305 function optionCompare(a, b)
307 if (showScriptFolders)
308 return a.nameForSorting.localeCompare(b.nameForSorting);
310 return a.displayName.localeCompare(b.displayName);
312 var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
313 select.insertBefore(option, insertionIndex < 0 ? null : select.childNodes.item(insertionIndex));
316 insertOrdered(option);
318 if (uiSourceCode.isContentScript && !select.contentScriptSection) {
319 var contentScriptSection = document.createElement("option");
320 contentScriptSection.text = "\u2014 " + WebInspector.UIString("Content scripts") + " \u2014";
321 contentScriptSection.disabled = true;
322 contentScriptSection.nameForSorting = "1/ContentScriptSeparator";
323 select.contentScriptSection = contentScriptSection;
324 insertOrdered(contentScriptSection);
327 if (showScriptFolders && !uiSourceCode.isContentScript && names.domain && !select.domainOptions[names.domain]) {
328 var domainOption = document.createElement("option");
329 domainOption.text = "\u2014 " + names.domain + " \u2014";
330 domainOption.nameForSorting = "0:" + names.domain;
331 domainOption.disabled = true;
332 select.domainOptions[names.domain] = domainOption;
333 insertOrdered(domainOption);
336 if (showScriptFolders && names.folderName && !select.folderOptions[names.folderName]) {
337 var folderOption = document.createElement("option");
338 folderOption.text = names.folderName;
339 folderOption.nameForSorting = folderNameForSorting;
340 folderOption.disabled = true;
341 select.folderOptions[names.folderName] = folderOption;
342 insertOrdered(folderOption);
345 option._uiSourceCode = uiSourceCode;
346 uiSourceCode._option = option;
349 _folderAndDisplayNameForScriptURL: function(url)
351 var parsedURL = url.asParsedURL();
353 url = parsedURL.path;
356 var displayName = url;
358 var pathLength = displayName.indexOf("?");
359 if (pathLength === -1)
360 pathLength = displayName.length;
362 var fromIndex = displayName.lastIndexOf("/", pathLength - 2);
363 if (fromIndex !== -1) {
364 folderName = displayName.substring(0, fromIndex);
365 displayName = displayName.substring(fromIndex + 1);
368 if (displayName.length > 80)
369 displayName = "\u2026" + displayName.substring(displayName.length - 80);
371 if (folderName.length > 80)
372 folderName = "\u2026" + folderName.substring(folderName.length - 80);
374 return { domain: (parsedURL ? parsedURL.host : ""), folderName: folderName, displayName: displayName };
377 setScriptSourceIsBeingEdited: function(uiSourceCode, inEditMode)
379 var option = uiSourceCode._option;
383 option.text = option.text.replace(/[^*]$/, "$&*");
385 option.text = option.text.replace(/[*]$/, "");
388 _consoleMessagesCleared: function()
390 for (var i = 0; i < this._filesSelectElement.length; ++i) {
391 var option = this._filesSelectElement[i];
392 if (option._uiSourceCode && option._uiSourceCode._sourceFrame)
393 option._uiSourceCode._sourceFrame.clearMessages();
397 _consoleMessageAdded: function(event)
399 var message = event.data;
401 var sourceFrame = message.uiSourceCode._sourceFrame;
402 if (sourceFrame && sourceFrame.loaded)
403 sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
406 _breakpointAdded: function(event)
408 var breakpoint = event.data;
410 var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
411 if (sourceFrame && sourceFrame.loaded)
412 sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
414 this.sidebarPanes.jsBreakpoints.addBreakpoint(breakpoint);
417 _breakpointRemoved: function(event)
419 var breakpoint = event.data;
421 var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
422 if (sourceFrame && sourceFrame.loaded)
423 sourceFrame.removeBreakpoint(breakpoint.lineNumber);
425 this.sidebarPanes.jsBreakpoints.removeBreakpoint(breakpoint.uiSourceCode, breakpoint.lineNumber);
428 evaluateInSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, returnByValue, callback)
430 function didEvaluate()
432 if (objectGroup === "console")
433 this.sidebarPanes.scopechain.update(this._presentationModel.selectedCallFrame);
434 callback.apply(null, arguments);
436 var selectedCallFrame = this._presentationModel.selectedCallFrame;
437 selectedCallFrame.evaluate(code, objectGroup, includeCommandLineAPI, returnByValue, didEvaluate.bind(this));
440 getSelectedCallFrameVariables: function(callback)
442 var result = { this: true };
444 var selectedCallFrame = this._presentationModel.selectedCallFrame;
445 if (!selectedCallFrame)
448 var pendingRequests = 0;
450 function propertiesCollected(properties)
452 for (var i = 0; properties && i < properties.length; ++i)
453 result[properties[i].name] = true;
454 if (--pendingRequests == 0)
458 for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
459 var scope = selectedCallFrame.scopeChain[i];
460 var object = WebInspector.RemoteObject.fromPayload(scope.object);
462 object.getAllProperties(propertiesCollected);
466 _debuggerPaused: function(event)
468 var callFrames = event.data.callFrames;
469 var details = event.data.details;
472 this._waitingToPause = false;
473 this._stepping = false;
475 this._updateDebuggerButtons();
477 WebInspector.setCurrentPanel(this);
479 this.sidebarPanes.callstack.update(callFrames, details);
480 this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
482 if (details.reason === WebInspector.ScriptsPanel.BreakReason.DOM) {
483 this.sidebarPanes.domBreakpoints.highlightBreakpoint(details.auxData);
484 function didCreateBreakpointHitStatusMessage(element)
486 this.sidebarPanes.callstack.setStatus(element);
488 this.sidebarPanes.domBreakpoints.createBreakpointHitStatusMessage(details.auxData, didCreateBreakpointHitStatusMessage.bind(this));
489 } else if (details.reason === WebInspector.ScriptsPanel.BreakReason.EventListener) {
490 var eventName = details.auxData.eventName;
491 this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.auxData.eventName);
492 var eventNameForUI = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
493 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a \"%s\" Event Listener.", eventNameForUI));
494 } else if (details.reason === WebInspector.ScriptsPanel.BreakReason.XHR) {
495 this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.auxData.breakpointURL);
496 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
497 } else if (details.reason === WebInspector.ScriptsPanel.BreakReason.Exception) {
498 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", details.auxData.description));
500 function didGetSourceLocation(uiSourceCode, lineNumber)
502 if (!uiSourceCode || !this._presentationModel.findBreakpoint(uiSourceCode, lineNumber))
504 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(uiSourceCode, lineNumber);
505 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
507 callFrames[0].sourceLine(didGetSourceLocation.bind(this));
511 InspectorFrontendHost.bringToFront();
514 _debuggerResumed: function()
516 this._paused = false;
517 this._waitingToPause = false;
518 this._stepping = false;
520 this._clearInterface();
523 _debuggerWasEnabled: function()
525 this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
527 if (this._debuggerEnabled)
530 this._debuggerEnabled = true;
534 _debuggerWasDisabled: function()
536 if (!this._debuggerEnabled)
539 this._debuggerEnabled = false;
543 reset: function(preserveItems)
545 this.visibleView = null;
547 delete this.currentQuery;
548 this.searchCanceled();
550 this._debuggerResumed();
552 this._backForwardList = [];
553 this._currentBackForwardIndex = -1;
554 this._updateBackAndForwardButtons();
556 this._resetFilesSelect();
557 delete this._filesSelectElement.initialSelectionProcessed;
559 this.functionsSelectElement.removeChildren();
560 this.viewsContainerElement.removeChildren();
562 this.sidebarPanes.jsBreakpoints.reset();
563 this.sidebarPanes.watchExpressions.reset();
564 if (!preserveItems && this.sidebarPanes.workers)
565 this.sidebarPanes.workers.reset();
568 _resetFilesSelect: function()
570 this._filesSelectElement.removeChildren();
571 this._filesSelectElement.domainOptions = {};
572 this._filesSelectElement.folderOptions = {};
573 delete this._filesSelectElement.contentScriptSection;
578 return this._visibleView;
583 if (this._visibleView === x)
586 if (this._visibleView)
587 this._visibleView.hide();
589 this._visibleView = x;
592 x.show(this.viewsContainerElement);
593 this._scriptViewStatusBarItemsContainer.removeChildren();
594 var statusBarItems = x.statusBarItems || [];
595 for (var i = 0; i < statusBarItems.length; ++i)
596 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
600 canShowAnchorLocation: function(anchor)
602 return this._debuggerEnabled && WebInspector.debuggerModel.scriptsForURL(anchor.href).length;
605 showAnchorLocation: function(anchor)
607 this._showSourceLine(anchor.uiSourceCode, anchor.lineNumber);
610 _showSourceLine: function(uiSourceCode, lineNumber)
612 var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
613 sourceFrame.highlightLine(lineNumber);
616 _showSourceFrameAndAddToHistory: function(uiSourceCode)
618 if (!uiSourceCode._option)
621 var sourceFrame = this._showSourceFrame(uiSourceCode);
623 var oldIndex = this._currentBackForwardIndex;
625 this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
627 // Check for a previous entry of the same object in _backForwardList.
628 // If one is found, remove it.
629 var previousEntryIndex = this._backForwardList.indexOf(uiSourceCode);
630 if (previousEntryIndex !== -1)
631 this._backForwardList.splice(previousEntryIndex, 1);
633 this._backForwardList.push(uiSourceCode);
634 this._currentBackForwardIndex = this._backForwardList.length - 1;
636 this._updateBackAndForwardButtons();
641 _showSourceFrame: function(uiSourceCode)
643 this._filesSelectElement.selectedIndex = uiSourceCode._option.index;
645 var sourceFrame = uiSourceCode._sourceFrame || this._createSourceFrame(uiSourceCode);
646 this.visibleView = sourceFrame;
648 if (uiSourceCode.url)
649 WebInspector.settings.lastViewedScriptFile.set(uiSourceCode.url);
654 _createSourceFrame: function(uiSourceCode)
656 var sourceFrame = new WebInspector.JavaScriptSourceFrame(this._presentationModel, uiSourceCode);
657 this.addChildView(sourceFrame);
658 sourceFrame._uiSourceCode = uiSourceCode;
659 sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
660 uiSourceCode._sourceFrame = sourceFrame;
664 _removeSourceFrame: function(uiSourceCode)
666 var sourceFrame = uiSourceCode._sourceFrame;
669 delete uiSourceCode._sourceFrame;
670 this.removeChildView(sourceFrame);
671 sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
674 _uiSourceCodeReplaced: function(event)
676 var oldUISourceCode = event.data.oldUISourceCode;
677 var uiSourceCode = event.data.uiSourceCode;
679 // Re-bind file select option from old source file to new one.
680 var option = oldUISourceCode._option;
683 delete oldUISourceCode._option;
684 option._uiSourceCode = uiSourceCode;
685 uiSourceCode._option = option;
687 // Remove old source frame and create new one if needed.
688 this._removeSourceFrame(oldUISourceCode);
689 if (option === this._filesSelectElement[this._filesSelectElement.selectedIndex])
690 this._showSourceFrame(uiSourceCode);
693 _sourceFrameLoaded: function(event)
695 var sourceFrame = event.target;
696 var uiSourceCode = sourceFrame._uiSourceCode;
698 var messages = this._presentationModel.messagesForUISourceCode(uiSourceCode);
699 for (var i = 0; i < messages.length; ++i) {
700 var message = messages[i];
701 sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
704 var breakpoints = this._presentationModel.breakpointsForUISourceCode(uiSourceCode);
705 for (var i = 0; i < breakpoints.length; ++i) {
706 var breakpoint = breakpoints[i];
707 sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
711 _clearCurrentExecutionLine: function()
713 if (this._executionSourceFrame)
714 this._executionSourceFrame.clearExecutionLine();
715 delete this._executionSourceFrame;
718 _callFrameSelected: function(event)
720 var callFrame = event.data;
722 this._clearCurrentExecutionLine();
727 this.sidebarPanes.scopechain.update(callFrame);
728 this.sidebarPanes.watchExpressions.refreshExpressions();
729 this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
731 function didGetSourceLocation(uiSourceCode, lineNumber)
736 if (!uiSourceCode._option) {
737 // Anonymous scripts are not added to files select by default.
738 this._addOptionToFilesSelect(uiSourceCode);
740 var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
741 sourceFrame.setExecutionLine(lineNumber);
742 this._executionSourceFrame = sourceFrame;
744 callFrame.sourceLine(didGetSourceLocation.bind(this));
747 _filesSelectChanged: function()
749 if (this._filesSelectElement.selectedIndex === -1)
752 var uiSourceCode = this._filesSelectElement[this._filesSelectElement.selectedIndex]._uiSourceCode;
753 this._showSourceFrameAndAddToHistory(uiSourceCode);
756 _startSidebarResizeDrag: function(event)
758 WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "ew-resize");
760 if (event.target === this.sidebarResizeWidgetElement)
761 this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft()));
763 this._dragOffset = 0;
766 _endSidebarResizeDrag: function(event)
768 WebInspector.elementDragEnd(event);
769 delete this._dragOffset;
770 this.saveSidebarWidth();
773 _sidebarResizeDrag: function(event)
775 var x = event.pageX + this._dragOffset;
776 var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66);
777 this.setSidebarWidth(newWidth);
778 event.preventDefault();
781 setSidebarWidth: function(newWidth)
783 this.sidebarElement.style.width = newWidth + "px";
784 this.sidebarButtonsElement.style.width = newWidth + "px";
785 this.viewsContainerElement.style.right = newWidth + "px";
786 this.sidebarResizeWidgetElement.style.right = newWidth + "px";
787 this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
792 _setPauseOnExceptions: function(pauseOnExceptionsState)
794 pauseOnExceptionsState = pauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions;
795 function callback(error)
799 if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions)
800 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
801 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions)
802 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions.");
803 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
804 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions.");
806 this._pauseOnExceptionButton.state = pauseOnExceptionsState;
807 WebInspector.settings.pauseOnExceptionStateString.set(pauseOnExceptionsState);
809 DebuggerAgent.setPauseOnExceptions(pauseOnExceptionsState, callback.bind(this));
812 _updateDebuggerButtons: function()
814 if (this._debuggerEnabled) {
815 this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
816 this.enableToggleButton.toggled = true;
817 this._pauseOnExceptionButton.visible = true;
818 this.panelEnablerView.visible = false;
820 this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
821 this.enableToggleButton.toggled = false;
822 this._pauseOnExceptionButton.visible = false;
823 this.panelEnablerView.visible = true;
827 this.pauseButton.addStyleClass("paused");
829 this.pauseButton.disabled = false;
830 this.stepOverButton.disabled = false;
831 this.stepIntoButton.disabled = false;
832 this.stepOutButton.disabled = false;
834 this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
836 this.pauseButton.removeStyleClass("paused");
838 this.pauseButton.disabled = this._waitingToPause;
839 this.stepOverButton.disabled = true;
840 this.stepIntoButton.disabled = true;
841 this.stepOutButton.disabled = true;
843 if (this._waitingToPause)
844 this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
845 else if (this._stepping)
846 this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
848 this.debuggerStatusElement.textContent = "";
852 _updateBackAndForwardButtons: function()
854 this.backButton.disabled = this._currentBackForwardIndex <= 0;
855 this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1);
858 _clearInterface: function()
860 this.sidebarPanes.callstack.update(null);
861 this.sidebarPanes.scopechain.update(null);
862 this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
863 if (Preferences.nativeInstrumentationEnabled) {
864 this.sidebarPanes.domBreakpoints.clearBreakpointHighlight();
865 this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
866 this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
869 this._clearCurrentExecutionLine();
870 this._updateDebuggerButtons();
875 if (this._currentBackForwardIndex <= 0) {
876 console.error("Can't go back from index " + this._currentBackForwardIndex);
880 this._showSourceFrame(this._backForwardList[--this._currentBackForwardIndex]);
881 this._updateBackAndForwardButtons();
884 _goForward: function()
886 if (this._currentBackForwardIndex >= this._backForwardList.length - 1) {
887 console.error("Can't go forward from index " + this._currentBackForwardIndex);
891 this._showSourceFrame(this._backForwardList[++this._currentBackForwardIndex]);
892 this._updateBackAndForwardButtons();
895 _enableDebugging: function()
897 if (this._debuggerEnabled)
899 this._toggleDebugging(this.panelEnablerView.alwaysEnabled);
902 _toggleDebugging: function(optionalAlways)
904 this._paused = false;
905 this._waitingToPause = false;
906 this._stepping = false;
908 if (this._debuggerEnabled) {
909 WebInspector.settings.debuggerEnabled.set(false);
910 WebInspector.debuggerModel.disableDebugger();
912 WebInspector.settings.debuggerEnabled.set(!!optionalAlways);
913 WebInspector.debuggerModel.enableDebugger();
917 _togglePauseOnExceptions: function()
919 var nextStateMap = {};
920 var stateEnum = WebInspector.ScriptsPanel.PauseOnExceptionsState;
921 nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions;
922 nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions;
923 nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions;
924 this._setPauseOnExceptions(nextStateMap[this._pauseOnExceptionButton.state]);
927 _togglePause: function()
930 this._paused = false;
931 this._waitingToPause = false;
932 DebuggerAgent.resume();
934 this._stepping = false;
935 this._waitingToPause = true;
936 DebuggerAgent.pause();
939 this._clearInterface();
942 _stepOverClicked: function()
947 this._paused = false;
948 this._stepping = true;
950 this._clearInterface();
952 DebuggerAgent.stepOver();
955 _stepIntoClicked: function()
960 this._paused = false;
961 this._stepping = true;
963 this._clearInterface();
965 DebuggerAgent.stepInto();
968 _stepOutClicked: function()
973 this._paused = false;
974 this._stepping = true;
976 this._clearInterface();
978 DebuggerAgent.stepOut();
981 toggleBreakpointsClicked: function()
983 this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled;
984 if (this.toggleBreakpointsButton.toggled) {
985 DebuggerAgent.setBreakpointsActive(true);
986 this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
987 document.getElementById("main-panels").removeStyleClass("breakpoints-deactivated");
989 DebuggerAgent.setBreakpointsActive(false);
990 this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
991 document.getElementById("main-panels").addStyleClass("breakpoints-deactivated");
995 elementsToRestoreScrollPositionsFor: function()
997 return [ this.sidebarElement ];
1000 _createSidebarButtons: function()
1002 this.sidebarButtonsElement = document.createElement("div");
1003 this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
1004 this.topStatusBar.appendChild(this.sidebarButtonsElement);
1006 var title, handler, shortcuts;
1007 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
1010 title = WebInspector.UIString("Pause script execution (%s).");
1011 handler = this._togglePause.bind(this);
1013 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8));
1014 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier));
1015 this.pauseButton = this._createSidebarButtonAndRegisterShortcuts("scripts-pause", title, handler, shortcuts, WebInspector.UIString("Pause/Continue"));
1018 title = WebInspector.UIString("Step over next function call (%s).");
1019 handler = this._stepOverClicked.bind(this);
1021 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10));
1022 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier));
1023 this.stepOverButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-over", title, handler, shortcuts, WebInspector.UIString("Step over"));
1026 title = WebInspector.UIString("Step into next function call (%s).");
1027 handler = this._stepIntoClicked.bind(this);
1029 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11));
1030 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier));
1031 this.stepIntoButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-into", title, handler, shortcuts, WebInspector.UIString("Step into"));
1034 title = WebInspector.UIString("Step out of current function (%s).");
1035 handler = this._stepOutClicked.bind(this);
1037 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift));
1038 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift, platformSpecificModifier));
1039 this.stepOutButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-out", title, handler, shortcuts, WebInspector.UIString("Step out"));
1042 _createSidebarButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts, shortcutDescription)
1044 var button = document.createElement("button");
1045 button.className = "status-bar-item";
1046 button.id = buttonId;
1047 button.title = String.vsprintf(buttonTitle, [shortcuts[0].name]);
1048 button.disabled = true;
1049 button.appendChild(document.createElement("img"));
1050 button.addEventListener("click", handler, false);
1051 this.sidebarButtonsElement.appendChild(button);
1053 var shortcutNames = [];
1054 for (var i = 0; i < shortcuts.length; ++i) {
1055 this.registerShortcut(shortcuts[i].key, handler);
1056 shortcutNames.push(shortcuts[i].name);
1058 var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
1059 section.addAlternateKeys(shortcutNames, shortcutDescription);
1064 searchCanceled: function()
1066 if (this._searchView)
1067 this._searchView.searchCanceled();
1069 delete this._searchView;
1070 delete this._searchQuery;
1073 performSearch: function(query)
1075 WebInspector.searchController.updateSearchMatchesCount(0, this);
1077 if (!this.visibleView)
1080 // Call searchCanceled since it will reset everything we need before doing a new search.
1081 this.searchCanceled();
1083 this._searchView = this.visibleView;
1084 this._searchQuery = query;
1086 function finishedCallback(view, searchMatches)
1091 WebInspector.searchController.updateSearchMatchesCount(searchMatches, this);
1092 view.jumpToFirstSearchResult();
1093 WebInspector.searchController.updateCurrentMatchIndex(view.currentSearchResultIndex + 1, this);
1096 this._searchView.performSearch(query, finishedCallback.bind(this));
1099 jumpToNextSearchResult: function()
1101 if (!this._searchView)
1104 if (this._searchView !== this.visibleView) {
1105 this.performSearch(this._searchQuery);
1109 if (this._searchView.showingLastSearchResult())
1110 this._searchView.jumpToFirstSearchResult();
1112 this._searchView.jumpToNextSearchResult();
1113 WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1116 jumpToPreviousSearchResult: function()
1118 if (!this._searchView)
1121 if (this._searchView !== this.visibleView) {
1122 this.performSearch(this._searchQuery);
1123 if (this._searchView)
1124 this._searchView.jumpToLastSearchResult();
1128 if (this._searchView.showingFirstSearchResult())
1129 this._searchView.jumpToLastSearchResult();
1131 this._searchView.jumpToPreviousSearchResult();
1132 WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1135 _toggleFormatSource: function()
1137 this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled;
1138 this._presentationModel.setFormatSource(this._toggleFormatSourceButton.toggled);
1141 _contextMenu: function(event)
1143 var contextMenu = new WebInspector.ContextMenu();
1145 function enableWorkerInspection()
1147 var newValue = !WebInspector.settings.workerInspectionEnabled.get();
1148 WebInspector.settings.workerInspectionEnabled.set(newValue);
1149 WorkerAgent.setWorkerInspectionEnabled(newValue);
1151 var element = this.sidebarPanes.workers.element;
1152 delete this.sidebarPanes.workers;
1153 this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
1154 element.parentNode.replaceChild(this.sidebarPanes.workerList.element, element);
1156 var element = this.sidebarPanes.workerList.element;
1157 delete this.sidebarPanes.workerList;
1158 this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
1159 element.parentNode.replaceChild(this.sidebarPanes.workers.element, element);
1162 contextMenu.appendCheckboxItem(WebInspector.UIString("Enable worker inspection"), enableWorkerInspection.bind(this), WebInspector.settings.workerInspectionEnabled.get());
1164 contextMenu.show(event);
1168 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;