1/* 2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 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. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26WebInspector.DebuggerManager = function() 27{ 28 WebInspector.Object.call(this); 29 30 if (window.DebuggerAgent) 31 DebuggerAgent.enable(); 32 33 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this); 34 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisabledStateDidChange, this._breakpointDisabledStateDidChange, this); 35 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ConditionDidChange, this._breakpointEditablePropertyDidChange, this); 36 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.AutoContinueDidChange, this._breakpointEditablePropertyDidChange, this); 37 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ActionsDidChange, this._breakpointEditablePropertyDidChange, this); 38 39 window.addEventListener("pagehide", this._inspectorClosing.bind(this)); 40 41 this._allExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-exceptions", false); 42 this._allUncaughtExceptionsBreakpointEnabledSetting = new WebInspector.Setting("break-on-all-uncaught-exceptions", false); 43 44 var specialBreakpointLocation = new WebInspector.SourceCodeLocation(null, Infinity, Infinity); 45 46 this._allExceptionsBreakpoint = new WebInspector.Breakpoint(specialBreakpointLocation, !this._allExceptionsBreakpointEnabledSetting.value); 47 this._allExceptionsBreakpoint.resolved = true; 48 49 this._allUncaughtExceptionsBreakpoint = new WebInspector.Breakpoint(specialBreakpointLocation, !this._allUncaughtExceptionsBreakpointEnabledSetting.value); 50 51 this._breakpoints = []; 52 this._breakpointURLMap = {}; 53 this._breakpointScriptIdentifierMap = {}; 54 this._breakpointIdMap = {}; 55 56 this._nextBreakpointActionIdentifier = 1; 57 58 this._scriptIdMap = {}; 59 this._scriptURLMap = {}; 60 61 this._breakpointsSetting = new WebInspector.Setting("breakpoints", []); 62 this._breakpointsEnabledSetting = new WebInspector.Setting("breakpoints-enabled", true); 63 64 if (window.DebuggerAgent) 65 DebuggerAgent.setBreakpointsActive(this._breakpointsEnabledSetting.value); 66 67 this._updateBreakOnExceptionsState(); 68 69 function restoreBreakpointsSoon() { 70 this._restoringBreakpoints = true; 71 for (var cookie of this._breakpointsSetting.value) 72 this.addBreakpoint(new WebInspector.Breakpoint(cookie)); 73 delete this._restoringBreakpoints; 74 } 75 76 // Ensure that all managers learn about restored breakpoints, 77 // regardless of their initialization order. 78 setTimeout(restoreBreakpointsSoon.bind(this), 0); 79}; 80 81WebInspector.DebuggerManager.Event = { 82 BreakpointAdded: "debugger-manager-breakpoint-added", 83 BreakpointRemoved: "debugger-manager-breakpoint-removed", 84 BreakpointMoved: "debugger-manager-breakpoint-moved", 85 Paused: "debugger-manager-paused", 86 Resumed: "debugger-manager-resumed", 87 CallFramesDidChange: "debugger-manager-call-frames-did-change", 88 ActiveCallFrameDidChange: "debugger-manager-active-call-frame-did-change", 89 ScriptAdded: "debugger-manager-script-added", 90 ScriptsCleared: "debugger-manager-scripts-cleared", 91 BreakpointsEnabledDidChange: "debugger-manager-breakpoints-enabled-did-change" 92}; 93 94WebInspector.DebuggerManager.prototype = { 95 constructor: WebInspector.DebuggerManager, 96 97 // Public 98 99 get breakpointsEnabled() 100 { 101 return this._breakpointsEnabledSetting.value; 102 }, 103 104 set breakpointsEnabled(enabled) 105 { 106 if (this._breakpointsEnabledSetting.value === enabled) 107 return; 108 109 this._breakpointsEnabledSetting.value = enabled; 110 111 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange); 112 113 this._allExceptionsBreakpoint.dispatchEventToListeners(WebInspector.Breakpoint.Event.ResolvedStateDidChange); 114 this._allUncaughtExceptionsBreakpoint.dispatchEventToListeners(WebInspector.Breakpoint.Event.ResolvedStateDidChange); 115 116 for (var i = 0; i < this._breakpoints.length; ++i) 117 this._breakpoints[i].dispatchEventToListeners(WebInspector.Breakpoint.Event.ResolvedStateDidChange); 118 119 DebuggerAgent.setBreakpointsActive(enabled); 120 121 this._updateBreakOnExceptionsState(); 122 }, 123 124 get paused() 125 { 126 return this._paused; 127 }, 128 129 get callFrames() 130 { 131 return this._callFrames; 132 }, 133 134 get activeCallFrame() 135 { 136 return this._activeCallFrame; 137 }, 138 139 set activeCallFrame(callFrame) 140 { 141 if (callFrame === this._activeCallFrame) 142 return; 143 144 this._activeCallFrame = callFrame || null; 145 146 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange); 147 }, 148 149 pause: function() 150 { 151 DebuggerAgent.pause(); 152 }, 153 154 resume: function() 155 { 156 DebuggerAgent.resume(); 157 }, 158 159 stepOver: function() 160 { 161 DebuggerAgent.stepOver(); 162 }, 163 164 stepInto: function() 165 { 166 DebuggerAgent.stepInto(); 167 }, 168 169 stepOut: function() 170 { 171 DebuggerAgent.stepOut(); 172 }, 173 174 get allExceptionsBreakpoint() 175 { 176 return this._allExceptionsBreakpoint; 177 }, 178 179 get allUncaughtExceptionsBreakpoint() 180 { 181 return this._allUncaughtExceptionsBreakpoint; 182 }, 183 184 get breakpoints() 185 { 186 return this._breakpoints; 187 }, 188 189 breakpointsForSourceCode: function(sourceCode) 190 { 191 console.assert(sourceCode instanceof WebInspector.Resource || sourceCode instanceof WebInspector.Script); 192 193 if (sourceCode instanceof WebInspector.SourceMapResource) { 194 var mappedResourceBreakpoints = []; 195 var originalSourceCodeBreakpoints = this.breakpointsForSourceCode(sourceCode.sourceMap.originalSourceCode); 196 return originalSourceCodeBreakpoints.filter(function(breakpoint) { 197 return breakpoint.sourceCodeLocation.displaySourceCode === sourceCode; 198 }); 199 } 200 201 if (sourceCode.url in this._breakpointURLMap) { 202 var urlBreakpoint = this._breakpointURLMap[sourceCode.url] || []; 203 this._associateBreakpointsWithSourceCode(urlBreakpoint, sourceCode); 204 return urlBreakpoint; 205 } 206 207 if (sourceCode instanceof WebInspector.Script && sourceCode.id in this._breakpointScriptIdentifierMap) { 208 var scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap[sourceCode.id] || []; 209 this._associateBreakpointsWithSourceCode(scriptIdentifierBreakpoints, sourceCode); 210 return scriptIdentifierBreakpoints; 211 } 212 213 return []; 214 }, 215 216 scriptForIdentifier: function(id) 217 { 218 return this._scriptIdMap[id] || null; 219 }, 220 221 scriptsForURL: function(url) 222 { 223 // FIXME: This may not be safe. A Resource's URL may differ from a Script's URL. 224 return this._scriptURLMap[url] || []; 225 }, 226 227 continueToLocation: function(scriptIdentifier, lineNumber, columnNumber) 228 { 229 DebuggerAgent.continueToLocation({scriptId: scriptIdentifier, lineNumber: lineNumber, columnNumber: columnNumber}); 230 }, 231 232 addBreakpoint: function(breakpoint, skipEventDispatch) 233 { 234 console.assert(breakpoint instanceof WebInspector.Breakpoint, "Bad argument to DebuggerManger.addBreakpoint: ", breakpoint); 235 if (!breakpoint) 236 return; 237 238 if (breakpoint.url) { 239 var urlBreakpoints = this._breakpointURLMap[breakpoint.url]; 240 if (!urlBreakpoints) 241 urlBreakpoints = this._breakpointURLMap[breakpoint.url] = []; 242 urlBreakpoints.push(breakpoint); 243 } 244 245 if (breakpoint.scriptIdentifier) { 246 var scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap[breakpoint.scriptIdentifier]; 247 if (!scriptIdentifierBreakpoints) 248 scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap[breakpoint.scriptIdentifier] = []; 249 scriptIdentifierBreakpoints.push(breakpoint); 250 } 251 252 this._breakpoints.push(breakpoint); 253 254 if (!breakpoint.disabled) 255 this._setBreakpoint(breakpoint); 256 257 if (!skipEventDispatch) 258 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointAdded, {breakpoint: breakpoint}); 259 }, 260 261 removeBreakpoint: function(breakpoint) 262 { 263 console.assert(breakpoint); 264 if (!breakpoint) 265 return; 266 267 console.assert(this.isBreakpointRemovable(breakpoint)); 268 if (!this.isBreakpointRemovable(breakpoint)) 269 return; 270 271 this._breakpoints.remove(breakpoint); 272 273 if (breakpoint.identifier) 274 this._removeBreakpoint(breakpoint); 275 276 if (breakpoint.url) { 277 var urlBreakpoints = this._breakpointURLMap[breakpoint.url]; 278 if (urlBreakpoints) { 279 urlBreakpoints.remove(breakpoint); 280 if (!urlBreakpoints.length) 281 delete this._breakpointURLMap[breakpoint.url]; 282 } 283 } 284 285 if (breakpoint.scriptIdentifier) { 286 var scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap[breakpoint.scriptIdentifier]; 287 if (scriptIdentifierBreakpoints) { 288 scriptIdentifierBreakpoints.remove(breakpoint); 289 if (!scriptIdentifierBreakpoints.length) 290 delete this._breakpointScriptIdentifierMap[breakpoint.scriptIdentifier]; 291 } 292 } 293 294 // Disable the breakpoint first, so removing actions doesn't re-add the breakpoint. 295 breakpoint.disabled = true; 296 breakpoint.clearActions(); 297 298 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointRemoved, {breakpoint: breakpoint}); 299 }, 300 301 breakpointResolved: function(breakpointIdentifier, location) 302 { 303 // Called from WebInspector.DebuggerObserver. 304 305 var breakpoint = this._breakpointIdMap[breakpointIdentifier]; 306 console.assert(breakpoint); 307 if (!breakpoint) 308 return; 309 310 console.assert(breakpoint.identifier === breakpointIdentifier); 311 312 breakpoint.resolved = true; 313 }, 314 315 reset: function() 316 { 317 // Called from WebInspector.DebuggerObserver. 318 319 var wasPaused = this._paused; 320 321 WebInspector.Script.resetUniqueDisplayNameNumbers(); 322 323 this._paused = false; 324 this._scriptIdMap = {}; 325 this._scriptURLMap = {}; 326 327 this._ignoreBreakpointDisplayLocationDidChangeEvent = true; 328 329 // Mark all the breakpoints as unresolved. They will be reported as resolved when 330 // breakpointResolved is called as the page loads. 331 for (var i = 0; i < this._breakpoints.length; ++i) { 332 var breakpoint = this._breakpoints[i]; 333 breakpoint.resolved = false; 334 if (breakpoint.sourceCodeLocation.sourceCode) 335 breakpoint.sourceCodeLocation.sourceCode = null; 336 } 337 338 delete this._ignoreBreakpointDisplayLocationDidChangeEvent; 339 340 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ScriptsCleared); 341 342 if (wasPaused) 343 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Resumed); 344 }, 345 346 debuggerDidPause: function(callFramesPayload) 347 { 348 // Called from WebInspector.DebuggerObserver. 349 350 if (this._delayedResumeTimeout) { 351 clearTimeout(this._delayedResumeTimeout); 352 delete this._delayedResumeTimeout; 353 } 354 355 var wasStillPaused = this._paused; 356 357 this._paused = true; 358 this._callFrames = []; 359 360 for (var i = 0; i < callFramesPayload.length; ++i) { 361 var callFramePayload = callFramesPayload[i]; 362 var sourceCodeLocation = this._sourceCodeLocationFromPayload(callFramePayload.location); 363 // FIXME: There may be useful call frames without a source code location (native callframes), should we include them? 364 if (!sourceCodeLocation) 365 continue; 366 if (!sourceCodeLocation.sourceCode) 367 continue; 368 // Exclude the case where the call frame is in the inspector code. 369 if (sourceCodeLocation.sourceCode.url && sourceCodeLocation.sourceCode.url.startsWith("__WebInspector")) 370 continue; 371 var thisObject = WebInspector.RemoteObject.fromPayload(callFramePayload.this); 372 var scopeChain = this._scopeChainFromPayload(callFramePayload.scopeChain); 373 var callFrame = new WebInspector.CallFrame(callFramePayload.callFrameId, sourceCodeLocation, callFramePayload.functionName, thisObject, scopeChain); 374 this._callFrames.push(callFrame); 375 } 376 377 this._activeCallFrame = this._callFrames[0]; 378 379 if (!wasStillPaused) 380 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Paused); 381 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.CallFramesDidChange); 382 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange); 383 }, 384 385 debuggerDidResume: function() 386 { 387 // Called from WebInspector.DebuggerObserver. 388 389 function delayedWork() 390 { 391 delete this._delayedResumeTimeout; 392 393 this._paused = false; 394 this._callFrames = null; 395 this._activeCallFrame = null; 396 397 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.Resumed); 398 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.CallFramesDidChange); 399 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange); 400 } 401 402 // We delay clearing the state and firing events so the user interface does not flash 403 // between brief steps or successive breakpoints. 404 this._delayedResumeTimeout = setTimeout(delayedWork.bind(this), 50); 405 }, 406 407 playBreakpointActionSound: function(breakpointActionIdentifier) 408 { 409 InspectorFrontendHost.beep(); 410 }, 411 412 scriptDidParse: function(scriptIdentifier, url, isContentScript, startLine, startColumn, endLine, endColumn, sourceMapURL) 413 { 414 // Don't add the script again if it is already known. 415 if (this._scriptIdMap[scriptIdentifier]) { 416 console.assert(this._scriptIdMap[scriptIdentifier].url === (url || null)); 417 console.assert(this._scriptIdMap[scriptIdentifier].range.startLine === startLine); 418 console.assert(this._scriptIdMap[scriptIdentifier].range.startColumn === startColumn); 419 console.assert(this._scriptIdMap[scriptIdentifier].range.endLine === endLine); 420 console.assert(this._scriptIdMap[scriptIdentifier].range.endColumn === endColumn); 421 return; 422 } 423 424 var script = new WebInspector.Script(scriptIdentifier, new WebInspector.TextRange(startLine, startColumn, endLine, endColumn), url, isContentScript, sourceMapURL); 425 426 this._scriptIdMap[scriptIdentifier] = script; 427 428 if (script.url) { 429 var scripts = this._scriptURLMap[script.url]; 430 if (!scripts) 431 scripts = this._scriptURLMap[script.url] = []; 432 scripts.push(script); 433 } 434 435 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.ScriptAdded, {script: script}); 436 }, 437 438 isBreakpointRemovable: function(breakpoint) 439 { 440 return breakpoint !== this._allExceptionsBreakpoint && breakpoint !== this._allUncaughtExceptionsBreakpoint; 441 }, 442 443 isBreakpointEditable: function(breakpoint) 444 { 445 return this.isBreakpointRemovable(breakpoint); 446 }, 447 448 get nextBreakpointActionIdentifier() 449 { 450 return this._nextBreakpointActionIdentifier++; 451 }, 452 453 // Private 454 455 _sourceCodeLocationFromPayload: function(payload) 456 { 457 var script = this._scriptIdMap[payload.scriptId]; 458 console.assert(script); 459 if (!script) 460 return null; 461 462 return script.createSourceCodeLocation(payload.lineNumber, payload.columnNumber); 463 }, 464 465 _scopeChainFromPayload: function(payload) 466 { 467 var scopeChain = []; 468 for (var i = 0; i < payload.length; ++i) 469 scopeChain.push(this._scopeChainNodeFromPayload(payload[i])); 470 return scopeChain; 471 }, 472 473 _scopeChainNodeFromPayload: function(payload) 474 { 475 var type = null; 476 switch (payload.type) { 477 case "local": 478 type = WebInspector.ScopeChainNode.Type.Local; 479 break; 480 case "global": 481 type = WebInspector.ScopeChainNode.Type.Global; 482 break; 483 case "with": 484 type = WebInspector.ScopeChainNode.Type.With; 485 break; 486 case "closure": 487 type = WebInspector.ScopeChainNode.Type.Closure; 488 break; 489 case "catch": 490 type = WebInspector.ScopeChainNode.Type.Catch; 491 break; 492 default: 493 console.error("Unknown type: " + payload.type); 494 } 495 496 var object = WebInspector.RemoteObject.fromPayload(payload.object); 497 return new WebInspector.ScopeChainNode(type, object); 498 }, 499 500 _debuggerBreakpointActionType: function(type) 501 { 502 switch (type) { 503 case WebInspector.BreakpointAction.Type.Log: 504 return DebuggerAgent.BreakpointActionType.Log; 505 case WebInspector.BreakpointAction.Type.Evaluate: 506 return DebuggerAgent.BreakpointActionType.Evaluate; 507 case WebInspector.BreakpointAction.Type.Sound: 508 return DebuggerAgent.BreakpointActionType.Sound; 509 case WebInspector.BreakpointAction.Type.Probe: 510 return DebuggerAgent.BreakpointActionType.Probe; 511 default: 512 console.assert(false); 513 return DebuggerAgent.BreakpointActionType.Log; 514 } 515 }, 516 517 _setBreakpoint: function(breakpoint, callback) 518 { 519 console.assert(!breakpoint.identifier); 520 console.assert(!breakpoint.disabled); 521 522 if (breakpoint.identifier || breakpoint.disabled) 523 return; 524 525 if (!this._restoringBreakpoints) { 526 // Enable breakpoints since a breakpoint is being set. This eliminates 527 // a multi-step process for the user that can be confusing. 528 this.breakpointsEnabled = true; 529 } 530 531 function didSetBreakpoint(error, breakpointIdentifier) 532 { 533 if (error) 534 return; 535 536 this._breakpointIdMap[breakpointIdentifier] = breakpoint; 537 538 breakpoint.identifier = breakpointIdentifier; 539 breakpoint.resolved = true; 540 541 if (typeof callback === "function") 542 callback(); 543 } 544 545 // The breakpoint will be resolved again by calling DebuggerAgent, so mark it as unresolved. 546 // If something goes wrong it will stay unresolved and show up as such in the user interface. 547 breakpoint.resolved = false; 548 549 // Convert BreakpointAction types to DebuggerAgent protocol types. 550 // NOTE: Breakpoint.options returns new objects each time, so it is safe to modify. 551 var options; 552 if (DebuggerAgent.BreakpointActionType) { 553 options = breakpoint.options; 554 if (options.actions.length) { 555 for (var i = 0; i < options.actions.length; ++i) 556 options.actions[i].type = this._debuggerBreakpointActionType(options.actions[i].type); 557 } 558 } 559 560 // COMPATIBILITY (iOS 7): iOS 7 and earlier, DebuggerAgent.setBreakpoint* took a "condition" string argument. 561 // This has been replaced with an "options" BreakpointOptions object. 562 if (breakpoint.url) { 563 DebuggerAgent.setBreakpointByUrl.invoke({ 564 lineNumber: breakpoint.sourceCodeLocation.lineNumber, 565 url: breakpoint.url, 566 urlRegex: undefined, 567 columnNumber: breakpoint.sourceCodeLocation.columnNumber, 568 condition: breakpoint.condition, 569 options: options 570 }, didSetBreakpoint.bind(this)); 571 } else if (breakpoint.scriptIdentifier) { 572 DebuggerAgent.setBreakpoint.invoke({ 573 location: {scriptId: breakpoint.scriptIdentifier, lineNumber: breakpoint.sourceCodeLocation.lineNumber, columnNumber: breakpoint.sourceCodeLocation.columnNumber}, 574 condition: breakpoint.condition, 575 options: options 576 }, didSetBreakpoint.bind(this)); 577 } 578 }, 579 580 _removeBreakpoint: function(breakpoint, callback) 581 { 582 if (!breakpoint.identifier) 583 return; 584 585 function didRemoveBreakpoint(error) 586 { 587 if (error) 588 console.error(error); 589 590 delete this._breakpointIdMap[breakpoint.identifier]; 591 592 breakpoint.identifier = null; 593 594 // Don't reset resolved here since we want to keep disabled breakpoints looking like they 595 // are resolved in the user interface. They will get marked as unresolved in reset. 596 597 if (typeof callback === "function") 598 callback(); 599 } 600 601 DebuggerAgent.removeBreakpoint(breakpoint.identifier, didRemoveBreakpoint.bind(this)); 602 }, 603 604 _breakpointDisplayLocationDidChange: function(event) 605 { 606 if (this._ignoreBreakpointDisplayLocationDidChangeEvent) 607 return; 608 609 var breakpoint = event.target; 610 if (!breakpoint.identifier || breakpoint.disabled) 611 return; 612 613 // Remove the breakpoint with its old id. 614 this._removeBreakpoint(breakpoint, breakpointRemoved.bind(this)); 615 616 function breakpointRemoved() 617 { 618 // Add the breakpoint at its new lineNumber and get a new id. 619 this._setBreakpoint(breakpoint); 620 621 this.dispatchEventToListeners(WebInspector.DebuggerManager.Event.BreakpointMoved, {breakpoint: breakpoint}); 622 } 623 }, 624 625 _breakpointDisabledStateDidChange: function(event) 626 { 627 var breakpoint = event.target; 628 629 if (breakpoint === this._allExceptionsBreakpoint) { 630 if (!breakpoint.disabled) 631 this.breakpointsEnabled = true; 632 this._allExceptionsBreakpointEnabledSetting.value = !breakpoint.disabled; 633 this._updateBreakOnExceptionsState(); 634 return; 635 } 636 637 if (breakpoint === this._allUncaughtExceptionsBreakpoint) { 638 if (!breakpoint.disabled) 639 this.breakpointsEnabled = true; 640 this._allUncaughtExceptionsBreakpointEnabledSetting.value = !breakpoint.disabled; 641 this._updateBreakOnExceptionsState(); 642 return; 643 } 644 645 if (breakpoint.disabled) 646 this._removeBreakpoint(breakpoint); 647 else 648 this._setBreakpoint(breakpoint); 649 }, 650 651 _breakpointEditablePropertyDidChange: function(event) 652 { 653 var breakpoint = event.target; 654 if (breakpoint.disabled) 655 return; 656 657 console.assert(this.isBreakpointEditable(breakpoint)); 658 if (!this.isBreakpointEditable(breakpoint)) 659 return; 660 661 // Remove the breakpoint with its old id. 662 this._removeBreakpoint(breakpoint, breakpointRemoved.bind(this)); 663 664 function breakpointRemoved() 665 { 666 // Add the breakpoint with its new condition and get a new id. 667 this._setBreakpoint(breakpoint); 668 } 669 }, 670 671 _updateBreakOnExceptionsState: function() 672 { 673 var state = "none"; 674 675 if (this._breakpointsEnabledSetting.value) { 676 if (!this._allExceptionsBreakpoint.disabled) 677 state = "all"; 678 else if (!this._allUncaughtExceptionsBreakpoint.disabled) 679 state = "uncaught"; 680 } 681 682 switch (state) { 683 case "all": 684 // Mark the uncaught breakpoint as unresolved since "all" includes "uncaught". 685 // That way it is clear in the user interface that the breakpoint is ignored. 686 this._allUncaughtExceptionsBreakpoint.resolved = false; 687 break; 688 case "uncaught": 689 case "none": 690 // Mark the uncaught breakpoint as resolved again. 691 this._allUncaughtExceptionsBreakpoint.resolved = true; 692 break; 693 } 694 695 DebuggerAgent.setPauseOnExceptions(state); 696 }, 697 698 _inspectorClosing: function(event) 699 { 700 this._saveBreakpoints(); 701 }, 702 703 _saveBreakpoints: function() 704 { 705 var savedBreakpoints = []; 706 707 for (var i = 0; i < this._breakpoints.length; ++i) { 708 var breakpoint = this._breakpoints[i]; 709 710 // Only breakpoints with URLs can be saved. Breakpoints for transient scripts can't. 711 if (!breakpoint.url) 712 continue; 713 714 savedBreakpoints.push(breakpoint.info); 715 } 716 717 this._breakpointsSetting.value = savedBreakpoints; 718 }, 719 720 _associateBreakpointsWithSourceCode: function(breakpoints, sourceCode) 721 { 722 this._ignoreBreakpointDisplayLocationDidChangeEvent = true; 723 724 for (var i = 0; i < breakpoints.length; ++i) { 725 var breakpoint = breakpoints[i]; 726 if (breakpoint.sourceCodeLocation.sourceCode === null) 727 breakpoint.sourceCodeLocation.sourceCode = sourceCode; 728 // SourceCodes can be unequal if the SourceCodeLocation is associated with a Script and we are looking at the Resource. 729 console.assert(breakpoint.sourceCodeLocation.sourceCode === sourceCode || breakpoint.sourceCodeLocation.sourceCode.url === sourceCode.url); 730 } 731 732 delete this._ignoreBreakpointDisplayLocationDidChangeEvent; 733 } 734}; 735 736WebInspector.DebuggerManager.prototype.__proto__ = WebInspector.Object.prototype; 737