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.BrowserBreakpointTypes = {
190 EventListener: "EventListener",
194 WebInspector.ScriptsPanel.prototype = {
195 get toolbarItemLabel()
197 return WebInspector.UIString("Scripts");
202 return [this.enableToggleButton.element, this._pauseOnExceptionButton.element, this._toggleFormatSourceButton.element, this._scriptViewStatusBarItemsContainer];
205 get defaultFocusedElement()
207 return this._filesSelectElement;
217 WebInspector.Panel.prototype.show.call(this);
218 this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
219 if (Preferences.nativeInstrumentationEnabled)
220 this.sidebarElement.insertBefore(this.sidebarPanes.domBreakpoints.element, this.sidebarPanes.xhrBreakpoints.element);
221 this.sidebarPanes.watchExpressions.show();
224 get breakpointsActivated()
226 return this.toggleBreakpointsButton.toggled;
229 _uiSourceCodeAdded: function(event)
231 var uiSourceCode = event.data;
233 if (!uiSourceCode.url) {
234 // Anonymous sources are shown only when stepping.
238 this._addOptionToFilesSelect(uiSourceCode);
240 var lastViewedURL = WebInspector.settings.lastViewedScriptFile.get();
241 if (!this._filesSelectElement.initialSelectionProcessed) {
242 this._filesSelectElement.initialSelectionProcessed = true;
243 // Option we just added is the only option in files select.
244 // We have to show corresponding source frame immediately.
245 this._showSourceFrameAndAddToHistory(uiSourceCode);
246 // Restore original value of lastViewedScriptFile because
247 // source frame was shown as a result of initial load.
248 WebInspector.settings.lastViewedScriptFile.set(lastViewedURL);
249 } else if (uiSourceCode.url === lastViewedURL)
250 this._showSourceFrameAndAddToHistory(uiSourceCode);
253 _showScriptFoldersSettingChanged: function()
255 var selectedOption = this._filesSelectElement[this._filesSelectElement.selectedIndex];
256 var uiSourceCode = selectedOption ? selectedOption._uiSourceCode : null;
258 var options = Array.prototype.slice.call(this._filesSelectElement);
259 this._resetFilesSelect();
260 for (var i = 0; i < options.length; ++i) {
261 if (options[i]._uiSourceCode)
262 this._addOptionToFilesSelect(options[i]._uiSourceCode);
266 var index = uiSourceCode._option.index;
267 if (typeof index === "number")
268 this._filesSelectElement.selectedIndex = index;
272 _addOptionToFilesSelect: function(uiSourceCode)
274 var showScriptFolders = WebInspector.settings.showScriptFolders.get();
276 var select = this._filesSelectElement;
277 if (!select.domainOptions)
278 select.domainOptions = {};
279 if (!select.folderOptions)
280 select.folderOptions = {};
282 var option = document.createElement("option");
283 option._uiSourceCode = uiSourceCode;
284 var parsedURL = uiSourceCode.url.asParsedURL();
286 var names = this._folderAndDisplayNameForScriptURL(uiSourceCode.url);
287 const indent = (!showScriptFolders || WebInspector.isMac()) ? "" : "\u00a0\u00a0\u00a0\u00a0";
288 option.text = indent + (names.displayName ? names.displayName : WebInspector.UIString("(program)"));
289 option.displayName = names.displayName;
291 var folderNameForSorting;
292 if (uiSourceCode.isContentScript)
293 folderNameForSorting = "2:" + names.folderName;
295 folderNameForSorting = "0:" + (names.domain ? names.domain + "\t\t" : "") + names.folderName;
297 option.nameForSorting = folderNameForSorting + "\t/\t" + names.displayName; // Use '\t' to make files stick to their folder.
298 option.title = uiSourceCode.url;
299 if (uiSourceCode.isContentScript)
300 option.addStyleClass("extension-script");
302 function insertOrdered(option)
304 function optionCompare(a, b)
306 if (showScriptFolders)
307 return a.nameForSorting.localeCompare(b.nameForSorting);
309 return a.displayName.localeCompare(b.displayName);
311 var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
312 select.insertBefore(option, insertionIndex < 0 ? null : select.childNodes.item(insertionIndex));
315 insertOrdered(option);
317 if (uiSourceCode.isContentScript && !select.contentScriptSection) {
318 var contentScriptSection = document.createElement("option");
319 contentScriptSection.text = "\u2014 " + WebInspector.UIString("Content scripts") + " \u2014";
320 contentScriptSection.disabled = true;
321 contentScriptSection.nameForSorting = "1/ContentScriptSeparator";
322 select.contentScriptSection = contentScriptSection;
323 insertOrdered(contentScriptSection);
326 if (showScriptFolders && !uiSourceCode.isContentScript && names.domain && !select.domainOptions[names.domain]) {
327 var domainOption = document.createElement("option");
328 domainOption.text = "\u2014 " + names.domain + " \u2014";
329 domainOption.nameForSorting = "0:" + names.domain;
330 domainOption.disabled = true;
331 select.domainOptions[names.domain] = domainOption;
332 insertOrdered(domainOption);
335 if (showScriptFolders && names.folderName && !select.folderOptions[names.folderName]) {
336 var folderOption = document.createElement("option");
337 folderOption.text = names.folderName;
338 folderOption.nameForSorting = folderNameForSorting;
339 folderOption.disabled = true;
340 select.folderOptions[names.folderName] = folderOption;
341 insertOrdered(folderOption);
344 option._uiSourceCode = uiSourceCode;
345 uiSourceCode._option = option;
348 _folderAndDisplayNameForScriptURL: function(url)
350 var parsedURL = url.asParsedURL();
352 url = parsedURL.path;
355 var displayName = url;
357 var pathLength = displayName.indexOf("?");
358 if (pathLength === -1)
359 pathLength = displayName.length;
361 var fromIndex = displayName.lastIndexOf("/", pathLength - 2);
362 if (fromIndex !== -1) {
363 folderName = displayName.substring(0, fromIndex);
364 displayName = displayName.substring(fromIndex + 1);
367 if (displayName.length > 80)
368 displayName = "\u2026" + displayName.substring(displayName.length - 80);
370 if (folderName.length > 80)
371 folderName = "\u2026" + folderName.substring(folderName.length - 80);
373 return { domain: (parsedURL ? parsedURL.host : ""), folderName: folderName, displayName: displayName };
376 setScriptSourceIsBeingEdited: function(uiSourceCode, inEditMode)
378 var option = uiSourceCode._option;
382 option.text = option.text.replace(/[^*]$/, "$&*");
384 option.text = option.text.replace(/[*]$/, "");
387 _consoleMessagesCleared: function()
389 for (var i = 0; i < this._filesSelectElement.length; ++i) {
390 var option = this._filesSelectElement[i];
391 if (option._uiSourceCode && option._uiSourceCode._sourceFrame)
392 option._uiSourceCode._sourceFrame.clearMessages();
396 _consoleMessageAdded: function(event)
398 var message = event.data;
400 var sourceFrame = message.uiSourceCode._sourceFrame;
401 if (sourceFrame && sourceFrame.loaded)
402 sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
405 _breakpointAdded: function(event)
407 var breakpoint = event.data;
409 var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
410 if (sourceFrame && sourceFrame.loaded)
411 sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
413 this.sidebarPanes.jsBreakpoints.addBreakpoint(breakpoint);
416 _breakpointRemoved: function(event)
418 var breakpoint = event.data;
420 var sourceFrame = breakpoint.uiSourceCode._sourceFrame;
421 if (sourceFrame && sourceFrame.loaded)
422 sourceFrame.removeBreakpoint(breakpoint.lineNumber);
424 this.sidebarPanes.jsBreakpoints.removeBreakpoint(breakpoint.uiSourceCode, breakpoint.lineNumber);
427 evaluateInSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, returnByValue, callback)
429 function didEvaluate()
431 if (objectGroup === "console")
432 this.sidebarPanes.scopechain.update(this._presentationModel.selectedCallFrame);
433 callback.apply(null, arguments);
435 var selectedCallFrame = this._presentationModel.selectedCallFrame;
436 selectedCallFrame.evaluate(code, objectGroup, includeCommandLineAPI, returnByValue, didEvaluate.bind(this));
439 getSelectedCallFrameVariables: function(callback)
441 var result = { this: true };
443 var selectedCallFrame = this._presentationModel.selectedCallFrame;
444 if (!selectedCallFrame)
447 var pendingRequests = 0;
449 function propertiesCollected(properties)
451 for (var i = 0; properties && i < properties.length; ++i)
452 result[properties[i].name] = true;
453 if (--pendingRequests == 0)
457 for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
458 var scope = selectedCallFrame.scopeChain[i];
459 var object = WebInspector.RemoteObject.fromPayload(scope.object);
461 object.getAllProperties(propertiesCollected);
465 _debuggerPaused: function(event)
467 var callFrames = event.data.callFrames;
468 var details = event.data.details;
471 this._waitingToPause = false;
472 this._stepping = false;
474 this._updateDebuggerButtons();
476 WebInspector.currentPanel = this;
478 this.sidebarPanes.callstack.update(callFrames, details);
479 this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
481 if (details.eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint) {
482 if (details.eventData.breakpointType === WebInspector.ScriptsPanel.BrowserBreakpointTypes.DOM) {
483 this.sidebarPanes.domBreakpoints.highlightBreakpoint(details.eventData);
484 function didCreateBreakpointHitStatusMessage(element)
486 this.sidebarPanes.callstack.setStatus(element);
488 this.sidebarPanes.domBreakpoints.createBreakpointHitStatusMessage(details.eventData, didCreateBreakpointHitStatusMessage.bind(this));
489 } else if (details.eventData.breakpointType === WebInspector.ScriptsPanel.BrowserBreakpointTypes.EventListener) {
490 var eventName = details.eventData.eventName;
491 this.sidebarPanes.eventListenerBreakpoints.highlightBreakpoint(details.eventData.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.eventData.breakpointType === WebInspector.ScriptsPanel.BrowserBreakpointTypes.XHR) {
495 this.sidebarPanes.xhrBreakpoints.highlightBreakpoint(details.eventData.breakpointURL);
496 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a XMLHttpRequest."));
499 function didGetSourceLocation(uiSourceCode, lineNumber)
501 var exception = WebInspector.debuggerModel.debuggerPausedDetails.exception;
503 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on exception: '%s'.", exception.description));
507 if (!uiSourceCode || !this._presentationModel.findBreakpoint(uiSourceCode, lineNumber))
509 this.sidebarPanes.jsBreakpoints.highlightBreakpoint(uiSourceCode, lineNumber);
510 this.sidebarPanes.callstack.setStatus(WebInspector.UIString("Paused on a JavaScript breakpoint."));
512 callFrames[0].sourceLine(didGetSourceLocation.bind(this));
516 InspectorFrontendHost.bringToFront();
519 _debuggerResumed: function()
521 this._paused = false;
522 this._waitingToPause = false;
523 this._stepping = false;
525 this._clearInterface();
528 _debuggerWasEnabled: function()
530 this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
532 if (this._debuggerEnabled)
535 this._debuggerEnabled = true;
539 _debuggerWasDisabled: function()
541 if (!this._debuggerEnabled)
544 this._debuggerEnabled = false;
548 reset: function(preserveItems)
550 this.visibleView = null;
552 delete this.currentQuery;
553 this.searchCanceled();
555 this._debuggerResumed();
557 this._backForwardList = [];
558 this._currentBackForwardIndex = -1;
559 this._updateBackAndForwardButtons();
561 this._resetFilesSelect();
562 delete this._filesSelectElement.initialSelectionProcessed;
564 this.functionsSelectElement.removeChildren();
565 this.viewsContainerElement.removeChildren();
567 this.sidebarPanes.jsBreakpoints.reset();
568 this.sidebarPanes.watchExpressions.reset();
569 if (!preserveItems && this.sidebarPanes.workers)
570 this.sidebarPanes.workers.reset();
573 _resetFilesSelect: function()
575 this._filesSelectElement.removeChildren();
576 this._filesSelectElement.domainOptions = {};
577 this._filesSelectElement.folderOptions = {};
578 delete this._filesSelectElement.contentScriptSection;
583 return this._visibleView;
588 if (this._visibleView === x)
591 if (this._visibleView)
592 this._visibleView.hide();
594 this._visibleView = x;
597 x.show(this.viewsContainerElement);
598 this._scriptViewStatusBarItemsContainer.removeChildren();
599 var statusBarItems = x.statusBarItems || [];
600 for (var i = 0; i < statusBarItems.length; ++i)
601 this._scriptViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
605 canShowAnchorLocation: function(anchor)
607 return this._debuggerEnabled && WebInspector.debuggerModel.scriptsForURL(anchor.href).length;
610 showAnchorLocation: function(anchor)
612 this._showSourceLine(anchor.uiSourceCode, anchor.lineNumber);
615 _showSourceLine: function(uiSourceCode, lineNumber)
617 var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
618 sourceFrame.highlightLine(lineNumber);
621 _showSourceFrameAndAddToHistory: function(uiSourceCode)
623 if (!uiSourceCode._option)
626 var sourceFrame = this._showSourceFrame(uiSourceCode);
628 var oldIndex = this._currentBackForwardIndex;
630 this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
632 // Check for a previous entry of the same object in _backForwardList.
633 // If one is found, remove it.
634 var previousEntryIndex = this._backForwardList.indexOf(uiSourceCode);
635 if (previousEntryIndex !== -1)
636 this._backForwardList.splice(previousEntryIndex, 1);
638 this._backForwardList.push(uiSourceCode);
639 this._currentBackForwardIndex = this._backForwardList.length - 1;
641 this._updateBackAndForwardButtons();
646 _showSourceFrame: function(uiSourceCode)
648 this._filesSelectElement.selectedIndex = uiSourceCode._option.index;
650 var sourceFrame = uiSourceCode._sourceFrame || this._createSourceFrame(uiSourceCode);
651 this.visibleView = sourceFrame;
653 if (uiSourceCode.url)
654 WebInspector.settings.lastViewedScriptFile.set(uiSourceCode.url);
659 _createSourceFrame: function(uiSourceCode)
661 var sourceFrame = new WebInspector.JavaScriptSourceFrame(this._presentationModel, uiSourceCode);
662 this.addChildView(sourceFrame);
663 sourceFrame._uiSourceCode = uiSourceCode;
664 sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
665 uiSourceCode._sourceFrame = sourceFrame;
669 _removeSourceFrame: function(uiSourceCode)
671 var sourceFrame = uiSourceCode._sourceFrame;
674 delete uiSourceCode._sourceFrame;
675 this.removeChildView(sourceFrame);
676 sourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this);
679 _uiSourceCodeReplaced: function(event)
681 var oldUISourceCode = event.data.oldUISourceCode;
682 var uiSourceCode = event.data.uiSourceCode;
684 // Re-bind file select option from old source file to new one.
685 var option = oldUISourceCode._option;
688 delete oldUISourceCode._option;
689 option._uiSourceCode = uiSourceCode;
690 uiSourceCode._option = option;
692 // Remove old source frame and create new one if needed.
693 this._removeSourceFrame(oldUISourceCode);
694 if (option === this._filesSelectElement[this._filesSelectElement.selectedIndex])
695 this._showSourceFrame(uiSourceCode);
698 _sourceFrameLoaded: function(event)
700 var sourceFrame = event.target;
701 var uiSourceCode = sourceFrame._uiSourceCode;
703 var messages = this._presentationModel.messagesForUISourceCode(uiSourceCode);
704 for (var i = 0; i < messages.length; ++i) {
705 var message = messages[i];
706 sourceFrame.addMessageToSource(message.lineNumber, message.originalMessage);
709 var breakpoints = this._presentationModel.breakpointsForUISourceCode(uiSourceCode);
710 for (var i = 0; i < breakpoints.length; ++i) {
711 var breakpoint = breakpoints[i];
712 sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled);
716 _clearCurrentExecutionLine: function()
718 if (this._executionSourceFrame)
719 this._executionSourceFrame.clearExecutionLine();
720 delete this._executionSourceFrame;
723 _callFrameSelected: function(event)
725 var callFrame = event.data;
727 this._clearCurrentExecutionLine();
732 this.sidebarPanes.scopechain.update(callFrame);
733 this.sidebarPanes.watchExpressions.refreshExpressions();
734 this.sidebarPanes.callstack.selectedCallFrame = this._presentationModel.selectedCallFrame;
736 function didGetSourceLocation(uiSourceCode, lineNumber)
741 if (!uiSourceCode._option) {
742 // Anonymous scripts are not added to files select by default.
743 this._addOptionToFilesSelect(uiSourceCode);
745 var sourceFrame = this._showSourceFrameAndAddToHistory(uiSourceCode);
746 sourceFrame.setExecutionLine(lineNumber);
747 this._executionSourceFrame = sourceFrame;
749 callFrame.sourceLine(didGetSourceLocation.bind(this));
752 _filesSelectChanged: function()
754 if (this._filesSelectElement.selectedIndex === -1)
757 var uiSourceCode = this._filesSelectElement[this._filesSelectElement.selectedIndex]._uiSourceCode;
758 this._showSourceFrameAndAddToHistory(uiSourceCode);
761 _startSidebarResizeDrag: function(event)
763 WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "ew-resize");
765 if (event.target === this.sidebarResizeWidgetElement)
766 this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft()));
768 this._dragOffset = 0;
771 _endSidebarResizeDrag: function(event)
773 WebInspector.elementDragEnd(event);
774 delete this._dragOffset;
775 this.saveSidebarWidth();
778 _sidebarResizeDrag: function(event)
780 var x = event.pageX + this._dragOffset;
781 var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66);
782 this.setSidebarWidth(newWidth);
783 event.preventDefault();
786 setSidebarWidth: function(newWidth)
788 this.sidebarElement.style.width = newWidth + "px";
789 this.sidebarButtonsElement.style.width = newWidth + "px";
790 this.viewsContainerElement.style.right = newWidth + "px";
791 this.sidebarResizeWidgetElement.style.right = newWidth + "px";
792 this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
797 _setPauseOnExceptions: function(pauseOnExceptionsState)
799 pauseOnExceptionsState = pauseOnExceptionsState || WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions;
800 function callback(error)
804 if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions)
805 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
806 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions)
807 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions.");
808 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
809 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions.");
811 this._pauseOnExceptionButton.state = pauseOnExceptionsState;
812 WebInspector.settings.pauseOnExceptionStateString.set(pauseOnExceptionsState);
814 DebuggerAgent.setPauseOnExceptions(pauseOnExceptionsState, callback.bind(this));
817 _updateDebuggerButtons: function()
819 if (this._debuggerEnabled) {
820 this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
821 this.enableToggleButton.toggled = true;
822 this._pauseOnExceptionButton.visible = true;
823 this.panelEnablerView.visible = false;
825 this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
826 this.enableToggleButton.toggled = false;
827 this._pauseOnExceptionButton.visible = false;
828 this.panelEnablerView.visible = true;
832 this.pauseButton.addStyleClass("paused");
834 this.pauseButton.disabled = false;
835 this.stepOverButton.disabled = false;
836 this.stepIntoButton.disabled = false;
837 this.stepOutButton.disabled = false;
839 this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
841 this.pauseButton.removeStyleClass("paused");
843 this.pauseButton.disabled = this._waitingToPause;
844 this.stepOverButton.disabled = true;
845 this.stepIntoButton.disabled = true;
846 this.stepOutButton.disabled = true;
848 if (this._waitingToPause)
849 this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
850 else if (this._stepping)
851 this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
853 this.debuggerStatusElement.textContent = "";
857 _updateBackAndForwardButtons: function()
859 this.backButton.disabled = this._currentBackForwardIndex <= 0;
860 this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1);
863 _clearInterface: function()
865 this.sidebarPanes.callstack.update(null);
866 this.sidebarPanes.scopechain.update(null);
867 this.sidebarPanes.jsBreakpoints.clearBreakpointHighlight();
868 if (Preferences.nativeInstrumentationEnabled) {
869 this.sidebarPanes.domBreakpoints.clearBreakpointHighlight();
870 this.sidebarPanes.eventListenerBreakpoints.clearBreakpointHighlight();
871 this.sidebarPanes.xhrBreakpoints.clearBreakpointHighlight();
874 this._clearCurrentExecutionLine();
875 this._updateDebuggerButtons();
880 if (this._currentBackForwardIndex <= 0) {
881 console.error("Can't go back from index " + this._currentBackForwardIndex);
885 this._showSourceFrame(this._backForwardList[--this._currentBackForwardIndex]);
886 this._updateBackAndForwardButtons();
889 _goForward: function()
891 if (this._currentBackForwardIndex >= this._backForwardList.length - 1) {
892 console.error("Can't go forward from index " + this._currentBackForwardIndex);
896 this._showSourceFrame(this._backForwardList[++this._currentBackForwardIndex]);
897 this._updateBackAndForwardButtons();
900 _enableDebugging: function()
902 if (this._debuggerEnabled)
904 this._toggleDebugging(this.panelEnablerView.alwaysEnabled);
907 _toggleDebugging: function(optionalAlways)
909 this._paused = false;
910 this._waitingToPause = false;
911 this._stepping = false;
913 if (this._debuggerEnabled) {
914 WebInspector.settings.debuggerEnabled.set(false);
915 WebInspector.debuggerModel.disableDebugger();
917 WebInspector.settings.debuggerEnabled.set(!!optionalAlways);
918 WebInspector.debuggerModel.enableDebugger();
922 _togglePauseOnExceptions: function()
924 var nextStateMap = {};
925 var stateEnum = WebInspector.ScriptsPanel.PauseOnExceptionsState;
926 nextStateMap[stateEnum.DontPauseOnExceptions] = stateEnum.PauseOnAllExceptions;
927 nextStateMap[stateEnum.PauseOnAllExceptions] = stateEnum.PauseOnUncaughtExceptions;
928 nextStateMap[stateEnum.PauseOnUncaughtExceptions] = stateEnum.DontPauseOnExceptions;
929 this._setPauseOnExceptions(nextStateMap[this._pauseOnExceptionButton.state]);
932 _togglePause: function()
935 this._paused = false;
936 this._waitingToPause = false;
937 DebuggerAgent.resume();
939 this._stepping = false;
940 this._waitingToPause = true;
941 DebuggerAgent.pause();
944 this._clearInterface();
947 _stepOverClicked: function()
952 this._paused = false;
953 this._stepping = true;
955 this._clearInterface();
957 DebuggerAgent.stepOver();
960 _stepIntoClicked: function()
965 this._paused = false;
966 this._stepping = true;
968 this._clearInterface();
970 DebuggerAgent.stepInto();
973 _stepOutClicked: function()
978 this._paused = false;
979 this._stepping = true;
981 this._clearInterface();
983 DebuggerAgent.stepOut();
986 toggleBreakpointsClicked: function()
988 this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled;
989 if (this.toggleBreakpointsButton.toggled) {
990 DebuggerAgent.setBreakpointsActive(true);
991 this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
992 document.getElementById("main-panels").removeStyleClass("breakpoints-deactivated");
994 DebuggerAgent.setBreakpointsActive(false);
995 this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
996 document.getElementById("main-panels").addStyleClass("breakpoints-deactivated");
1000 elementsToRestoreScrollPositionsFor: function()
1002 return [ this.sidebarElement ];
1005 _createSidebarButtons: function()
1007 this.sidebarButtonsElement = document.createElement("div");
1008 this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
1009 this.topStatusBar.appendChild(this.sidebarButtonsElement);
1011 var title, handler, shortcuts;
1012 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
1015 title = WebInspector.UIString("Pause script execution (%s).");
1016 handler = this._togglePause.bind(this);
1018 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8));
1019 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier));
1020 this.pauseButton = this._createSidebarButtonAndRegisterShortcuts("scripts-pause", title, handler, shortcuts, WebInspector.UIString("Pause/Continue"));
1023 title = WebInspector.UIString("Step over next function call (%s).");
1024 handler = this._stepOverClicked.bind(this);
1026 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10));
1027 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier));
1028 this.stepOverButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-over", title, handler, shortcuts, WebInspector.UIString("Step over"));
1031 title = WebInspector.UIString("Step into next function call (%s).");
1032 handler = this._stepIntoClicked.bind(this);
1034 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11));
1035 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier));
1036 this.stepIntoButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-into", title, handler, shortcuts, WebInspector.UIString("Step into"));
1039 title = WebInspector.UIString("Step out of current function (%s).");
1040 handler = this._stepOutClicked.bind(this);
1042 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift));
1043 shortcuts.push(WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift, platformSpecificModifier));
1044 this.stepOutButton = this._createSidebarButtonAndRegisterShortcuts("scripts-step-out", title, handler, shortcuts, WebInspector.UIString("Step out"));
1047 _createSidebarButtonAndRegisterShortcuts: function(buttonId, buttonTitle, handler, shortcuts, shortcutDescription)
1049 var button = document.createElement("button");
1050 button.className = "status-bar-item";
1051 button.id = buttonId;
1052 button.title = String.vsprintf(buttonTitle, [shortcuts[0].name]);
1053 button.disabled = true;
1054 button.appendChild(document.createElement("img"));
1055 button.addEventListener("click", handler, false);
1056 this.sidebarButtonsElement.appendChild(button);
1058 var shortcutNames = [];
1059 for (var i = 0; i < shortcuts.length; ++i) {
1060 this.registerShortcut(shortcuts[i].key, handler);
1061 shortcutNames.push(shortcuts[i].name);
1063 var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Scripts Panel"));
1064 section.addAlternateKeys(shortcutNames, shortcutDescription);
1069 searchCanceled: function()
1071 if (this._searchView)
1072 this._searchView.searchCanceled();
1074 delete this._searchView;
1075 delete this._searchQuery;
1078 performSearch: function(query)
1080 WebInspector.searchController.updateSearchMatchesCount(0, this);
1082 if (!this.visibleView)
1085 // Call searchCanceled since it will reset everything we need before doing a new search.
1086 this.searchCanceled();
1088 this._searchView = this.visibleView;
1089 this._searchQuery = query;
1091 function finishedCallback(view, searchMatches)
1096 WebInspector.searchController.updateSearchMatchesCount(searchMatches, this);
1097 view.jumpToFirstSearchResult();
1098 WebInspector.searchController.updateCurrentMatchIndex(view.currentSearchResultIndex + 1, this);
1101 this._searchView.performSearch(query, finishedCallback.bind(this));
1104 jumpToNextSearchResult: function()
1106 if (!this._searchView)
1109 if (this._searchView !== this.visibleView) {
1110 this.performSearch(this._searchQuery);
1114 if (this._searchView.showingLastSearchResult())
1115 this._searchView.jumpToFirstSearchResult();
1117 this._searchView.jumpToNextSearchResult();
1118 WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1121 jumpToPreviousSearchResult: function()
1123 if (!this._searchView)
1126 if (this._searchView !== this.visibleView) {
1127 this.performSearch(this._searchQuery);
1128 if (this._searchView)
1129 this._searchView.jumpToLastSearchResult();
1133 if (this._searchView.showingFirstSearchResult())
1134 this._searchView.jumpToLastSearchResult();
1136 this._searchView.jumpToPreviousSearchResult();
1137 WebInspector.searchController.updateCurrentMatchIndex(this._searchView.currentSearchResultIndex + 1, this);
1140 _toggleFormatSource: function()
1142 this._toggleFormatSourceButton.toggled = !this._toggleFormatSourceButton.toggled;
1143 this._presentationModel.setFormatSource(this._toggleFormatSourceButton.toggled);
1146 _contextMenu: function(event)
1148 var contextMenu = new WebInspector.ContextMenu();
1150 function enableWorkerInspection()
1152 var newValue = !WebInspector.settings.workerInspectionEnabled.get();
1153 WebInspector.settings.workerInspectionEnabled.set(newValue);
1154 WorkerAgent.setWorkerInspectionEnabled(newValue);
1156 var element = this.sidebarPanes.workers.element;
1157 delete this.sidebarPanes.workers;
1158 this.sidebarPanes.workerList = new WebInspector.WorkerListSidebarPane(WebInspector.workerManager);
1159 element.parentNode.replaceChild(this.sidebarPanes.workerList.element, element);
1161 var element = this.sidebarPanes.workerList.element;
1162 delete this.sidebarPanes.workerList;
1163 this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
1164 element.parentNode.replaceChild(this.sidebarPanes.workers.element, element);
1167 contextMenu.appendCheckboxItem(WebInspector.UIString("Enable worker inspection"), enableWorkerInspection.bind(this), WebInspector.settings.workerInspectionEnabled.get());
1169 contextMenu.show(event);
1173 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;