2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 WebInspector.ScriptsPanel = function()
28 WebInspector.Panel.call(this, "scripts");
30 this.topStatusBar = document.createElement("div");
31 this.topStatusBar.className = "status-bar";
32 this.topStatusBar.id = "scripts-status-bar";
33 this.element.appendChild(this.topStatusBar);
35 this.backButton = document.createElement("button");
36 this.backButton.className = "status-bar-item";
37 this.backButton.id = "scripts-back";
38 this.backButton.title = WebInspector.UIString("Show the previous script resource.");
39 this.backButton.disabled = true;
40 this.backButton.appendChild(document.createElement("img"));
41 this.backButton.addEventListener("click", this._goBack.bind(this), false);
42 this.topStatusBar.appendChild(this.backButton);
44 this.forwardButton = document.createElement("button");
45 this.forwardButton.className = "status-bar-item";
46 this.forwardButton.id = "scripts-forward";
47 this.forwardButton.title = WebInspector.UIString("Show the next script resource.");
48 this.forwardButton.disabled = true;
49 this.forwardButton.appendChild(document.createElement("img"));
50 this.forwardButton.addEventListener("click", this._goForward.bind(this), false);
51 this.topStatusBar.appendChild(this.forwardButton);
53 this.filesSelectElement = document.createElement("select");
54 this.filesSelectElement.className = "status-bar-item";
55 this.filesSelectElement.id = "scripts-files";
56 this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false);
57 this.topStatusBar.appendChild(this.filesSelectElement);
59 this.functionsSelectElement = document.createElement("select");
60 this.functionsSelectElement.className = "status-bar-item";
61 this.functionsSelectElement.id = "scripts-functions";
63 // FIXME: append the functions select element to the top status bar when it is implemented.
64 // this.topStatusBar.appendChild(this.functionsSelectElement);
66 this.sidebarButtonsElement = document.createElement("div");
67 this.sidebarButtonsElement.id = "scripts-sidebar-buttons";
68 this.topStatusBar.appendChild(this.sidebarButtonsElement);
70 this.pauseButton = document.createElement("button");
71 this.pauseButton.className = "status-bar-item";
72 this.pauseButton.id = "scripts-pause";
73 this.pauseButton.title = WebInspector.UIString("Pause script execution.");
74 this.pauseButton.disabled = true;
75 this.pauseButton.appendChild(document.createElement("img"));
76 this.pauseButton.addEventListener("click", this._togglePause.bind(this), false);
77 this.sidebarButtonsElement.appendChild(this.pauseButton);
79 this.stepOverButton = document.createElement("button");
80 this.stepOverButton.className = "status-bar-item";
81 this.stepOverButton.id = "scripts-step-over";
82 this.stepOverButton.title = WebInspector.UIString("Step over next function call.");
83 this.stepOverButton.disabled = true;
84 this.stepOverButton.addEventListener("click", this._stepOverClicked.bind(this), false);
85 this.stepOverButton.appendChild(document.createElement("img"));
86 this.sidebarButtonsElement.appendChild(this.stepOverButton);
88 this.stepIntoButton = document.createElement("button");
89 this.stepIntoButton.className = "status-bar-item";
90 this.stepIntoButton.id = "scripts-step-into";
91 this.stepIntoButton.title = WebInspector.UIString("Step into next function call.");
92 this.stepIntoButton.disabled = true;
93 this.stepIntoButton.addEventListener("click", this._stepIntoClicked.bind(this), false);
94 this.stepIntoButton.appendChild(document.createElement("img"));
95 this.sidebarButtonsElement.appendChild(this.stepIntoButton);
97 this.stepOutButton = document.createElement("button");
98 this.stepOutButton.className = "status-bar-item";
99 this.stepOutButton.id = "scripts-step-out";
100 this.stepOutButton.title = WebInspector.UIString("Step out of current function.");
101 this.stepOutButton.disabled = true;
102 this.stepOutButton.addEventListener("click", this._stepOutClicked.bind(this), false);
103 this.stepOutButton.appendChild(document.createElement("img"));
104 this.sidebarButtonsElement.appendChild(this.stepOutButton);
106 this.toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints");
107 this.toggleBreakpointsButton.toggled = true;
108 this.toggleBreakpointsButton.addEventListener("click", this.toggleBreakpointsClicked.bind(this), false);
109 this.sidebarButtonsElement.appendChild(this.toggleBreakpointsButton.element);
111 this.debuggerStatusElement = document.createElement("div");
112 this.debuggerStatusElement.id = "scripts-debugger-status";
113 this.sidebarButtonsElement.appendChild(this.debuggerStatusElement);
115 this.viewsContainerElement = document.createElement("div");
116 this.viewsContainerElement.id = "script-resource-views";
118 this.sidebarElement = document.createElement("div");
119 this.sidebarElement.id = "scripts-sidebar";
121 this.sidebarResizeElement = document.createElement("div");
122 this.sidebarResizeElement.className = "sidebar-resizer-vertical";
123 this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
125 this.sidebarResizeWidgetElement = document.createElement("div");
126 this.sidebarResizeWidgetElement.id = "scripts-sidebar-resizer-widget";
127 this.sidebarResizeWidgetElement.addEventListener("mousedown", this._startSidebarResizeDrag.bind(this), false);
128 this.topStatusBar.appendChild(this.sidebarResizeWidgetElement);
130 this.sidebarPanes = {};
131 this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane();
132 this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane();
133 this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane();
134 this.sidebarPanes.jsBreakpoints = WebInspector.createJSBreakpointsSidebarPane();
135 if (Preferences.nativeInstrumentationEnabled) {
136 this.sidebarPanes.domBreakpoints = WebInspector.createDOMBreakpointsSidebarPane();
137 this.sidebarPanes.xhrBreakpoints = WebInspector.createXHRBreakpointsSidebarPane();
139 this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
141 this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane();
143 for (var pane in this.sidebarPanes)
144 this.sidebarElement.appendChild(this.sidebarPanes[pane].element);
146 this.sidebarPanes.callstack.expanded = true;
147 this.sidebarPanes.callstack.addEventListener("call frame selected", this._callFrameSelected, this);
149 this.sidebarPanes.scopechain.expanded = true;
150 this.sidebarPanes.jsBreakpoints.expanded = true;
152 var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel.");
153 var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower.");
154 var panelEnablerButton = WebInspector.UIString("Enable Debugging");
156 this.panelEnablerView = new WebInspector.PanelEnablerView("scripts", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
157 this.panelEnablerView.addEventListener("enable clicked", this._enableDebugging, this);
159 this.element.appendChild(this.panelEnablerView.element);
160 this.element.appendChild(this.viewsContainerElement);
161 this.element.appendChild(this.sidebarElement);
162 this.element.appendChild(this.sidebarResizeElement);
164 this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
165 this.enableToggleButton.addEventListener("click", this._toggleDebugging.bind(this), false);
166 if (Preferences.debuggerAlwaysEnabled)
167 this.enableToggleButton.element.addStyleClass("hidden");
169 this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3);
170 this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false);
171 this._pauseOnExceptionButton.state = WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions;
172 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
174 this._registerShortcuts();
176 this._debuggerEnabled = Preferences.debuggerAlwaysEnabled;
178 WebInspector.breakpointManager.addEventListener("breakpoint-added", this._breakpointAdded, this);
183 // Keep these in sync with WebCore::ScriptDebugServer
184 WebInspector.ScriptsPanel.PauseOnExceptionsState = {
185 DontPauseOnExceptions : 0,
186 PauseOnAllExceptions : 1,
187 PauseOnUncaughtExceptions: 2
190 WebInspector.ScriptsPanel.prototype = {
191 get toolbarItemLabel()
193 return WebInspector.UIString("Scripts");
198 return [this.enableToggleButton.element, this._pauseOnExceptionButton.element];
201 get defaultFocusedElement()
203 return this.filesSelectElement;
213 WebInspector.Panel.prototype.show.call(this);
214 this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
216 if (this.visibleView) {
217 if (this.visibleView instanceof WebInspector.ResourceView)
218 this.visibleView.headersVisible = false;
219 this.visibleView.show(this.viewsContainerElement);
221 if (this._attachDebuggerWhenShown) {
222 InspectorBackend.enableDebugger(false);
223 delete this._attachDebuggerWhenShown;
229 if (this.visibleView)
230 this.visibleView.hide();
231 WebInspector.Panel.prototype.hide.call(this);
234 get breakpointsActivated()
236 return this.toggleBreakpointsButton.toggled;
239 addScript: function(sourceID, sourceURL, source, startingLine, errorLine, errorMessage, scriptWorldType)
241 var script = new WebInspector.Script(sourceID, sourceURL, source, startingLine, errorLine, errorMessage, scriptWorldType);
242 this._sourceIDMap[sourceID] = script;
244 var resource = WebInspector.resourceForURL(sourceURL);
246 if (resource.finished) {
247 // Resource is finished, bind the script right away.
248 resource.addScript(script);
249 this._sourceIDMap[sourceID] = resource;
251 // Resource is not finished, bind the script later.
252 if (!resource._scriptsPendingResourceLoad) {
253 resource._scriptsPendingResourceLoad = [];
254 resource.addEventListener("finished", this._resourceLoadingFinished, this);
256 resource._scriptsPendingResourceLoad.push(script);
259 this._addScriptToFilesMenu(script);
262 continueToLine: function(sourceID, line)
264 WebInspector.breakpointManager.setOneTimeBreakpoint(sourceID, line);
269 _resourceLoadingFinished: function(e)
271 var resource = e.target;
272 for (var i = 0; i < resource._scriptsPendingResourceLoad.length; ++i) {
273 // Bind script to resource.
274 var script = resource._scriptsPendingResourceLoad[i];
275 resource.addScript(script);
276 this._sourceIDMap[script.sourceID] = resource;
278 // Remove script from the files list.
279 script.filesSelectOption.parentElement.removeChild(script.filesSelectOption);
281 // Adding first script will add resource.
282 this._addScriptToFilesMenu(resource._scriptsPendingResourceLoad[0]);
283 delete resource._scriptsPendingResourceLoad;
286 _breakpointAdded: function(event)
288 var breakpoint = event.data;
291 if (breakpoint.url) {
292 var resource = WebInspector.resourceForURL(breakpoint.url);
293 if (resource && resource.finished)
294 sourceFrame = this._sourceFrameForScriptOrResource(resource);
297 if (breakpoint.sourceID && !sourceFrame) {
298 var object = this._sourceIDMap[breakpoint.sourceID]
299 sourceFrame = this._sourceFrameForScriptOrResource(object);
303 sourceFrame.addBreakpoint(breakpoint);
306 canEditScripts: function()
308 return Preferences.canEditScriptSource;
311 editScriptSource: function(sourceID, newContent, line, linesCountToShift, commitEditingCallback, cancelEditingCallback)
313 if (!this.canEditScripts())
316 // Need to clear breakpoints and re-create them later when editing source.
317 var breakpoints = WebInspector.breakpointManager.breakpointsForSourceID(sourceID);
318 for (var i = 0; i < breakpoints.length; ++i)
319 breakpoints[i].remove();
321 function mycallback(success, newBodyOrErrorMessage, callFrames)
324 commitEditingCallback(newBodyOrErrorMessage);
325 if (callFrames && callFrames.length)
326 this.debuggerPaused(callFrames);
328 cancelEditingCallback();
329 WebInspector.log(newBodyOrErrorMessage, WebInspector.ConsoleMessage.MessageLevel.Warning);
331 for (var i = 0; i < breakpoints.length; ++i) {
332 var breakpoint = breakpoints[i];
333 var newLine = breakpoint.line;
334 if (success && breakpoint.line >= line)
335 newLine += linesCountToShift;
336 WebInspector.breakpointManager.setBreakpoint(sourceID, breakpoint.url, newLine, breakpoint.enabled, breakpoint.condition);
339 InspectorBackend.editScriptSource(sourceID, newContent, mycallback.bind(this));
342 selectedCallFrameId: function()
344 var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame;
345 if (!selectedCallFrame)
347 return selectedCallFrame.id;
350 evaluateInSelectedCallFrame: function(code, updateInterface, objectGroup, callback)
352 var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame;
353 if (!this._paused || !selectedCallFrame)
356 if (typeof updateInterface === "undefined")
357 updateInterface = true;
360 function updatingCallbackWrapper(result)
364 self.sidebarPanes.scopechain.update(selectedCallFrame);
366 this.doEvalInCallFrame(selectedCallFrame, code, objectGroup, updatingCallbackWrapper);
369 doEvalInCallFrame: function(callFrame, code, objectGroup, callback)
371 function evalCallback(result)
374 callback(WebInspector.RemoteObject.fromPayload(result));
376 InjectedScriptAccess.get(callFrame.worldId).evaluateInCallFrame(callFrame.id, code, objectGroup, evalCallback);
379 debuggerPaused: function(callFrames)
381 WebInspector.breakpointManager.removeOneTimeBreakpoint();
383 this._waitingToPause = false;
384 this._stepping = false;
386 this._updateDebuggerButtons();
388 this.sidebarPanes.callstack.update(callFrames, this._sourceIDMap);
389 this.sidebarPanes.callstack.selectedCallFrame = callFrames[0];
391 WebInspector.currentPanel = this;
395 debuggerResumed: function()
397 this._paused = false;
398 this._waitingToPause = false;
399 this._stepping = false;
401 this._clearInterface();
404 attachDebuggerWhenShown: function()
406 if (this.element.parentElement) {
407 InspectorBackend.enableDebugger(false);
409 this._attachDebuggerWhenShown = true;
413 debuggerWasEnabled: function()
415 if (this._debuggerEnabled)
418 this._debuggerEnabled = true;
422 debuggerWasDisabled: function()
424 if (!this._debuggerEnabled)
427 this._debuggerEnabled = false;
431 reset: function(preserveItems)
433 this.visibleView = null;
435 delete this.currentQuery;
436 this.searchCanceled();
438 this.debuggerResumed();
440 this._backForwardList = [];
441 this._currentBackForwardIndex = -1;
442 this._updateBackAndForwardButtons();
444 this._resourceForURLInFilesSelect = {};
445 this.filesSelectElement.removeChildren();
446 this.functionsSelectElement.removeChildren();
447 this.viewsContainerElement.removeChildren();
449 if (this._sourceIDMap) {
450 for (var sourceID in this._sourceIDMap) {
451 var object = this._sourceIDMap[sourceID];
452 if (object instanceof WebInspector.Resource)
453 object.removeAllScripts();
457 this._sourceIDMap = {};
459 this.sidebarPanes.watchExpressions.refreshExpressions();
460 if (!preserveItems) {
461 this.sidebarPanes.jsBreakpoints.reset();
462 if (Preferences.nativeInstrumentationEnabled) {
463 this.sidebarPanes.domBreakpoints.reset();
464 this.sidebarPanes.xhrBreakpoints.reset();
466 this.sidebarPanes.eventListenerBreakpoints.reset();
467 this.sidebarPanes.workers.reset();
473 return this._visibleView;
478 if (this._visibleView === x)
481 if (this._visibleView)
482 this._visibleView.hide();
484 this._visibleView = x;
487 x.show(this.viewsContainerElement);
490 viewRecreated: function(oldView, newView)
492 if (this._visibleView === oldView)
493 this._visibleView = newView;
496 canShowSourceLine: function(url, line)
498 if (!this._debuggerEnabled)
500 return !!this._scriptOrResourceForURLAndLine(url, line);
503 showSourceLine: function(url, line)
505 var scriptOrResource = this._scriptOrResourceForURLAndLine(url, line);
506 this._showScriptOrResource(scriptOrResource, {line: line, shouldHighlightLine: true});
509 _scriptOrResourceForURLAndLine: function(url, line)
511 var scriptWithMatchingUrl = null;
512 for (var sourceID in this._sourceIDMap) {
513 var scriptOrResource = this._sourceIDMap[sourceID];
514 if (scriptOrResource instanceof WebInspector.Script) {
515 if (scriptOrResource.sourceURL !== url)
517 scriptWithMatchingUrl = scriptOrResource;
518 if (scriptWithMatchingUrl.startingLine <= line && scriptWithMatchingUrl.startingLine + scriptWithMatchingUrl.linesCount > line)
519 return scriptWithMatchingUrl;
521 var resource = scriptOrResource;
522 if (resource.url === url)
526 return scriptWithMatchingUrl;
529 showView: function(view)
533 this._showScriptOrResource(view.resource || view.script);
536 handleShortcut: function(event)
538 var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
539 var handler = this._shortcuts[shortcut];
542 event.handled = true;
544 this.sidebarPanes.callstack.handleShortcut(event);
547 scriptViewForScript: function(script)
551 if (!script._scriptView)
552 script._scriptView = new WebInspector.ScriptView(script);
553 return script._scriptView;
556 sourceFrameForScript: function(script)
558 var view = this.scriptViewForScript(script);
562 // Setting up the source frame requires that we be attached.
563 if (!this.element.parentNode)
566 view.setupSourceFrameIfNeeded();
567 return view.sourceFrame;
570 _sourceFrameForScriptOrResource: function(scriptOrResource)
572 if (scriptOrResource instanceof WebInspector.Resource)
573 return this._sourceFrameForResource(scriptOrResource);
574 if (scriptOrResource instanceof WebInspector.Script)
575 return this.sourceFrameForScript(scriptOrResource);
578 _sourceFrameForResource: function(resource)
580 var view = WebInspector.ResourceManager.resourceViewForResource(resource);
584 if (!view.setupSourceFrameIfNeeded)
587 view.setupSourceFrameIfNeeded();
588 return view.sourceFrame;
591 _showScriptOrResource: function(scriptOrResource, options)
593 // options = {line:, shouldHighlightLine:, fromBackForwardAction:, initialLoad:}
594 options = options || {};
596 if (!scriptOrResource)
600 if (scriptOrResource instanceof WebInspector.Resource) {
601 view = WebInspector.ResourceManager.resourceViewForResource(scriptOrResource);
602 view.headersVisible = false;
603 } else if (scriptOrResource instanceof WebInspector.Script)
604 view = this.scriptViewForScript(scriptOrResource);
609 var url = scriptOrResource.url || scriptOrResource.sourceURL;
610 if (url && !options.initialLoad)
611 WebInspector.settings.lastViewedScriptFile = url;
613 if (!options.fromBackForwardAction) {
614 var oldIndex = this._currentBackForwardIndex;
616 this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex);
618 // Check for a previous entry of the same object in _backForwardList.
619 // If one is found, remove it and update _currentBackForwardIndex to match.
620 var previousEntryIndex = this._backForwardList.indexOf(scriptOrResource);
621 if (previousEntryIndex !== -1) {
622 this._backForwardList.splice(previousEntryIndex, 1);
623 --this._currentBackForwardIndex;
626 this._backForwardList.push(scriptOrResource);
627 ++this._currentBackForwardIndex;
629 this._updateBackAndForwardButtons();
632 this.visibleView = view;
636 view.revealLine(options.line);
637 if (view.highlightLine && options.shouldHighlightLine)
638 view.highlightLine(options.line);
642 if (scriptOrResource instanceof WebInspector.Script) {
643 option = scriptOrResource.filesSelectOption;
645 // hasn't been added yet - happens for stepping in evals,
646 // so use the force option to force the script into the menu.
648 this._addScriptToFilesMenu(scriptOrResource, true);
649 option = scriptOrResource.filesSelectOption;
652 console.assert(option);
654 option = scriptOrResource.filesSelectOption;
657 this.filesSelectElement.selectedIndex = option.index;
660 _addScriptToFilesMenu: function(script, force)
662 if (!script.sourceURL && !force)
665 if (script.resource) {
666 if (this._resourceForURLInFilesSelect[script.resource.url])
668 this._resourceForURLInFilesSelect[script.resource.url] = script.resource;
671 var displayName = script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)");
673 var select = this.filesSelectElement;
674 var option = document.createElement("option");
675 option.representedObject = script.resource || script;
676 option.url = displayName;
677 option.startingLine = script.startingLine;
678 option.text = script.resource || script.startingLine === 1 ? displayName : String.sprintf("%s:%d", displayName, script.startingLine);
680 function optionCompare(a, b)
684 else if (a.url > b.url)
687 if (typeof a.startingLine !== "number")
689 if (typeof b.startingLine !== "number")
691 return a.startingLine - b.startingLine;
694 var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare);
695 if (insertionIndex < 0)
696 select.appendChild(option);
698 select.insertBefore(option, select.childNodes.item(insertionIndex));
701 script.resource.filesSelectOption = option;
703 script.filesSelectOption = option;
705 if (select.options[select.selectedIndex] === option) {
706 // Call _showScriptOrResource if the option we just appended ended up being selected.
707 // This will happen for the first item added to the menu.
708 this._showScriptOrResource(option.representedObject, {initialLoad: true});
710 // If not first item, check to see if this was the last viewed
711 var url = option.representedObject.url || option.representedObject.sourceURL;
712 var lastURL = WebInspector.settings.lastViewedScriptFile;
713 if (url && url === lastURL) {
714 // For resources containing multiple <script> tags, we first report them separately and
715 // then glue them all together. They all share url and there is no need to show them all one
717 var isResource = !!option.representedObject.url;
718 if (isResource || !this.visibleView || !this.visibleView.script || this.visibleView.script.sourceURL !== url)
719 this._showScriptOrResource(option.representedObject, {initialLoad: true});
723 if (script.worldType === WebInspector.Script.WorldType.EXTENSIONS_WORLD)
724 script.filesSelectOption.addStyleClass("extension-script");
727 _clearCurrentExecutionLine: function()
729 if (this._executionSourceFrame)
730 this._executionSourceFrame.executionLine = 0;
731 delete this._executionSourceFrame;
734 _callFrameSelected: function()
736 this._clearCurrentExecutionLine();
738 var callStackPane = this.sidebarPanes.callstack;
739 var currentFrame = callStackPane.selectedCallFrame;
743 this.sidebarPanes.scopechain.update(currentFrame);
744 this.sidebarPanes.watchExpressions.refreshExpressions();
746 var scriptOrResource = this._sourceIDMap[currentFrame.sourceID];
747 this._showScriptOrResource(scriptOrResource, {line: currentFrame.line});
749 this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource);
750 if (this._executionSourceFrame)
751 this._executionSourceFrame.executionLine = currentFrame.line;
754 _changeVisibleFile: function(event)
756 var select = this.filesSelectElement;
757 this._showScriptOrResource(select.options[select.selectedIndex].representedObject);
760 _startSidebarResizeDrag: function(event)
762 WebInspector.elementDragStart(this.sidebarElement, this._sidebarResizeDrag.bind(this), this._endSidebarResizeDrag.bind(this), event, "col-resize");
764 if (event.target === this.sidebarResizeWidgetElement)
765 this._dragOffset = (event.target.offsetWidth - (event.pageX - event.target.totalOffsetLeft));
767 this._dragOffset = 0;
770 _endSidebarResizeDrag: function(event)
772 WebInspector.elementDragEnd(event);
773 delete this._dragOffset;
774 this.saveSidebarWidth();
777 _sidebarResizeDrag: function(event)
779 var x = event.pageX + this._dragOffset;
780 var newWidth = Number.constrain(window.innerWidth - x, Preferences.minScriptsSidebarWidth, window.innerWidth * 0.66);
781 this.setSidebarWidth(newWidth);
782 event.preventDefault();
785 setSidebarWidth: function(newWidth)
787 this.sidebarElement.style.width = newWidth + "px";
788 this.sidebarButtonsElement.style.width = newWidth + "px";
789 this.viewsContainerElement.style.right = newWidth + "px";
790 this.sidebarResizeWidgetElement.style.right = newWidth + "px";
791 this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
796 updatePauseOnExceptionsState: function(pauseOnExceptionsState)
798 if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions)
799 this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions.");
800 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions)
801 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions.");
802 else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions)
803 this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions.");
805 this._pauseOnExceptionButton.state = pauseOnExceptionsState;
808 _updateDebuggerButtons: function()
810 if (this._debuggerEnabled) {
811 this.enableToggleButton.title = WebInspector.UIString("Debugging enabled. Click to disable.");
812 this.enableToggleButton.toggled = true;
813 this._pauseOnExceptionButton.visible = true;
814 this.panelEnablerView.visible = false;
816 this.enableToggleButton.title = WebInspector.UIString("Debugging disabled. Click to enable.");
817 this.enableToggleButton.toggled = false;
818 this._pauseOnExceptionButton.visible = false;
819 this.panelEnablerView.visible = true;
823 this.pauseButton.addStyleClass("paused");
825 this.pauseButton.disabled = false;
826 this.stepOverButton.disabled = false;
827 this.stepIntoButton.disabled = false;
828 this.stepOutButton.disabled = false;
830 this.debuggerStatusElement.textContent = WebInspector.UIString("Paused");
832 this.pauseButton.removeStyleClass("paused");
834 this.pauseButton.disabled = this._waitingToPause;
835 this.stepOverButton.disabled = true;
836 this.stepIntoButton.disabled = true;
837 this.stepOutButton.disabled = true;
839 if (this._waitingToPause)
840 this.debuggerStatusElement.textContent = WebInspector.UIString("Pausing");
841 else if (this._stepping)
842 this.debuggerStatusElement.textContent = WebInspector.UIString("Stepping");
844 this.debuggerStatusElement.textContent = "";
848 _updateBackAndForwardButtons: function()
850 this.backButton.disabled = this._currentBackForwardIndex <= 0;
851 this.forwardButton.disabled = this._currentBackForwardIndex >= (this._backForwardList.length - 1);
854 _clearInterface: function()
856 this.sidebarPanes.callstack.update(null);
857 this.sidebarPanes.scopechain.update(null);
859 this._clearCurrentExecutionLine();
860 this._updateDebuggerButtons();
865 if (this._currentBackForwardIndex <= 0) {
866 console.error("Can't go back from index " + this._currentBackForwardIndex);
870 this._showScriptOrResource(this._backForwardList[--this._currentBackForwardIndex], {fromBackForwardAction: true});
871 this._updateBackAndForwardButtons();
874 _goForward: function()
876 if (this._currentBackForwardIndex >= this._backForwardList.length - 1) {
877 console.error("Can't go forward from index " + this._currentBackForwardIndex);
881 this._showScriptOrResource(this._backForwardList[++this._currentBackForwardIndex], {fromBackForwardAction: true});
882 this._updateBackAndForwardButtons();
885 _enableDebugging: function()
887 if (this._debuggerEnabled)
889 this._toggleDebugging(this.panelEnablerView.alwaysEnabled);
892 _toggleDebugging: function(optionalAlways)
894 this._paused = false;
895 this._waitingToPause = false;
896 this._stepping = false;
898 if (this._debuggerEnabled)
899 InspectorBackend.disableDebugger(true);
901 InspectorBackend.enableDebugger(!!optionalAlways);
904 _togglePauseOnExceptions: function()
906 InspectorBackend.setPauseOnExceptionsState((this._pauseOnExceptionButton.state + 1) % this._pauseOnExceptionButton.states, this.updatePauseOnExceptionsState.bind(this));
909 _togglePause: function()
912 this._paused = false;
913 this._waitingToPause = false;
914 InspectorBackend.resume();
916 this._stepping = false;
917 this._waitingToPause = true;
918 InspectorBackend.pause();
921 this._clearInterface();
924 _stepOverClicked: function()
926 this._paused = false;
927 this._stepping = true;
929 this._clearInterface();
931 InspectorBackend.stepOverStatement();
934 _stepIntoClicked: function()
936 this._paused = false;
937 this._stepping = true;
939 this._clearInterface();
941 InspectorBackend.stepIntoStatement();
944 _stepOutClicked: function()
946 this._paused = false;
947 this._stepping = true;
949 this._clearInterface();
951 InspectorBackend.stepOutOfFunction();
954 toggleBreakpointsClicked: function()
956 this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled;
957 if (this.toggleBreakpointsButton.toggled) {
958 InspectorBackend.activateBreakpoints();
959 this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints.");
960 document.getElementById("main-panels").removeStyleClass("breakpoints-deactivated");
962 InspectorBackend.deactivateBreakpoints();
963 this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints.");
964 document.getElementById("main-panels").addStyleClass("breakpoints-deactivated");
968 elementsToRestoreScrollPositionsFor: function()
970 return [ this.sidebarElement ];
973 _registerShortcuts: function()
975 var section = WebInspector.shortcutsHelp.section(WebInspector.UIString("Scripts Panel"));
976 var handler, shortcut1, shortcut2;
977 var platformSpecificModifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
979 this._shortcuts = {};
982 handler = this.pauseButton.click.bind(this.pauseButton);
983 shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F8);
984 this._shortcuts[shortcut1.key] = handler;
985 shortcut2 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Slash, platformSpecificModifier);
986 this._shortcuts[shortcut2.key] = handler;
987 section.addAlternateKeys([ shortcut1.name, shortcut2.name ], WebInspector.UIString("Continue"));
990 handler = this.stepOverButton.click.bind(this.stepOverButton);
991 shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F10);
992 this._shortcuts[shortcut1.key] = handler;
993 shortcut2 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.SingleQuote, platformSpecificModifier);
994 this._shortcuts[shortcut2.key] = handler;
995 section.addAlternateKeys([ shortcut1.name, shortcut2.name ], WebInspector.UIString("Step over"));
998 handler = this.stepIntoButton.click.bind(this.stepIntoButton);
999 shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11);
1000 this._shortcuts[shortcut1.key] = handler;
1001 shortcut2 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, platformSpecificModifier);
1002 this._shortcuts[shortcut2.key] = handler;
1003 section.addAlternateKeys([ shortcut1.name, shortcut2.name ], WebInspector.UIString("Step into"));
1006 handler = this.stepOutButton.click.bind(this.stepOutButton);
1007 shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F11, WebInspector.KeyboardShortcut.Modifiers.Shift);
1008 this._shortcuts[shortcut1.key] = handler;
1009 shortcut2 = WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Semicolon, WebInspector.KeyboardShortcut.Modifiers.Shift, platformSpecificModifier);
1010 this._shortcuts[shortcut2.key] = handler;
1011 section.addAlternateKeys([ shortcut1.name, shortcut2.name ], WebInspector.UIString("Step out"));
1013 shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor("g", platformSpecificModifier);
1014 this._shortcuts[shortcut1.key] = this.showGoToLineDialog.bind(this);
1015 section.addAlternateKeys([ shortcut1.name ], WebInspector.UIString("Go to Line"));
1016 this.sidebarPanes.callstack.registerShortcuts(section);
1019 searchCanceled: function()
1021 WebInspector.updateSearchMatchesCount(0, this);
1023 if (this._searchView)
1024 this._searchView.searchCanceled();
1026 delete this._searchView;
1027 delete this._searchQuery;
1030 performSearch: function(query)
1032 if (!this.visibleView)
1035 // Call searchCanceled since it will reset everything we need before doing a new search.
1036 this.searchCanceled();
1038 this._searchView = this.visibleView;
1039 this._searchQuery = query;
1041 function finishedCallback(view, searchMatches)
1046 WebInspector.updateSearchMatchesCount(searchMatches, this);
1047 view.jumpToFirstSearchResult();
1050 this._searchView.performSearch(query, finishedCallback.bind(this));
1053 jumpToNextSearchResult: function()
1055 if (!this._searchView)
1058 if (this._searchView !== this.visibleView) {
1059 this.performSearch(this._searchQuery);
1063 if (this._searchView.showingLastSearchResult())
1064 this._searchView.jumpToFirstSearchResult();
1066 this._searchView.jumpToNextSearchResult();
1069 jumpToPreviousSearchResult: function()
1071 if (!this._searchView)
1074 if (this._searchView !== this.visibleView) {
1075 this.performSearch(this._searchQuery);
1076 if (this._searchView)
1077 this._searchView.jumpToLastSearchResult();
1081 if (this._searchView.showingFirstSearchResult())
1082 this._searchView.jumpToLastSearchResult();
1084 this._searchView.jumpToPreviousSearchResult();
1087 showGoToLineDialog: function(e)
1089 var view = this.visibleView;
1091 WebInspector.GoToLineDialog.show(view);
1095 WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype;