Reviewed by Tim H.
authorthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Oct 2006 04:42:06 +0000 (04:42 +0000)
committerthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Oct 2006 04:42:06 +0000 (04:42 +0000)
        Bug 11367: Inline Breakpoint Editor Improvements: Act III
        http://bugs.webkit.org/show_bug.cgi?id=11367

        Major breakpoint editor changes:
        * Breakpoints can now either pause or log to console
        * Code cleanup through use of XPath and converting breakpoints to objects
        * Breakpoints now track how many times they've been reached
        * UI tweaks
        * The breakpoint editor now saves changes as they're entered
        * Because changes are auto-saved now, the save button has been converted to a close button (images from PSMTabBarControl, BSD licensed)
        * If an expression with no return is entered as a condition, it will be wrapped transparently with a return statement.

        * Drosera/DebuggerDocument.m:
        (-[WebScriptObject breakpointEditorHTML]): A way of loading this from an external file, as it was getting too complex to include inline.
        * Drosera/Drosera.xcodeproj/project.pbxproj:
        * Drosera/Images/close.tif: Added.
        * Drosera/Images/close_active.tif: Added.
        * Drosera/Images/close_hover.tif: Added.
        * Drosera/breakpointEditor.html: Added.
        * Drosera/console.js: Added a way to append messages from outside the console window.
        * Drosera/debugger.js:
        * Drosera/viewer.css:
        * Drosera/viewer.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@17184 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/Drosera/DebuggerDocument.m
WebKitTools/Drosera/Drosera.xcodeproj/project.pbxproj
WebKitTools/Drosera/Images/close.tif [new file with mode: 0644]
WebKitTools/Drosera/Images/close_active.tif [new file with mode: 0644]
WebKitTools/Drosera/Images/close_hover.tif [new file with mode: 0644]
WebKitTools/Drosera/breakpointEditor.html [new file with mode: 0644]
WebKitTools/Drosera/console.js
WebKitTools/Drosera/debugger.js
WebKitTools/Drosera/viewer.css
WebKitTools/Drosera/viewer.html

index 7ffeda440d5443f2619682e7adfc47d1d4b34f68..82bd243cd9d249fbc488d77912cef4d7698f75db 100644 (file)
@@ -1,3 +1,31 @@
+2006-10-20  David Smith  <catfish.man@gmail.com>
+
+        Reviewed by Tim H.
+
+        Bug 11367: Inline Breakpoint Editor Improvements: Act III
+        http://bugs.webkit.org/show_bug.cgi?id=11367
+
+        Major breakpoint editor changes:
+        * Breakpoints can now either pause or log to console
+        * Code cleanup through use of XPath and converting breakpoints to objects
+        * Breakpoints now track how many times they've been reached
+        * UI tweaks
+        * The breakpoint editor now saves changes as they're entered
+        * Because changes are auto-saved now, the save button has been converted to a close button (images from PSMTabBarControl, BSD licensed)
+        * If an expression with no return is entered as a condition, it will be wrapped transparently with a return statement.
+
+        * Drosera/DebuggerDocument.m:
+        (-[WebScriptObject breakpointEditorHTML]): A way of loading this from an external file, as it was getting too complex to include inline.
+        * Drosera/Drosera.xcodeproj/project.pbxproj:
+        * Drosera/Images/close.tif: Added.
+        * Drosera/Images/close_active.tif: Added.
+        * Drosera/Images/close_hover.tif: Added.
+        * Drosera/breakpointEditor.html: Added.
+        * Drosera/console.js: Added a way to append messages from outside the console window.
+        * Drosera/debugger.js:
+        * Drosera/viewer.css:
+        * Drosera/viewer.html:
+
 2006-10-18  David Smith  <catfish.man@gmail.com>
 
         Reviewed by Tim H.
index 0c835a6fc7578b475fed3327a5cd3b80a0512399..b8443662aeee9695f4d3a9e6c5a15f142c2c0243 100644 (file)
@@ -176,6 +176,14 @@ static NSString *DebuggerStepOutToolbarItem = @"DebuggerStepOutToolbarItem";
     return ((double)GetDblTime() / 60.0) * 1000;
 }
 
+#pragma mark -
+#pragma mark File Loading
+
+- (NSString *)breakpointEditorHTML
+{
+    return [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"breakpointEditor" ofType:@"html"]];
+}
+
 #pragma mark -
 #pragma mark Pause & Step
 
index f0d0f19918f1ce8a424d9b299f121d30714a648d..18fb2a26927ea3747d3f145f74a406efb78a0881 100644 (file)
                5D2C827F0A816BA700C193FD /* Drosera.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1C3487970A81208400101C5C /* Drosera.icns */; };
                63D54BD70AE600560064C440 /* breakpointeditor.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D54BD60AE600560064C440 /* breakpointeditor.png */; };
                63D54CBD0AE72C990064C440 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63D54CBC0AE72C990064C440 /* Carbon.framework */; };
+               63D54D7E0AE75CF10064C440 /* close_active.tif in Resources */ = {isa = PBXBuildFile; fileRef = 63D54D7B0AE75CF10064C440 /* close_active.tif */; };
+               63D54D7F0AE75CF10064C440 /* close_hover.tif in Resources */ = {isa = PBXBuildFile; fileRef = 63D54D7C0AE75CF10064C440 /* close_hover.tif */; };
+               63D54D800AE75CF10064C440 /* close.tif in Resources */ = {isa = PBXBuildFile; fileRef = 63D54D7D0AE75CF10064C440 /* close.tif */; };
+               63D54F780AE8280F0064C440 /* breakpointEditor.html in Resources */ = {isa = PBXBuildFile; fileRef = 63D54F770AE8280F0064C440 /* breakpointEditor.html */; };
                8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */; };
                8D15AC2E0486D014006FF6A4 /* Debugger.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B4FDCFA73011CA2CEA /* Debugger.nib */; };
                8D15AC310486D014006FF6A4 /* DebuggerDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* DebuggerDocument.m */; settings = {ATTRIBUTES = (); }; };
                32DBCF750370BD2300C91783 /* Drosera.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drosera.pch; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                63D54BD60AE600560064C440 /* breakpointeditor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = breakpointeditor.png; sourceTree = "<group>"; };
                63D54CBC0AE72C990064C440 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+               63D54D7B0AE75CF10064C440 /* close_active.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = close_active.tif; sourceTree = "<group>"; };
+               63D54D7C0AE75CF10064C440 /* close_hover.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = close_hover.tif; sourceTree = "<group>"; };
+               63D54D7D0AE75CF10064C440 /* close.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = close.tif; sourceTree = "<group>"; };
+               63D54F770AE8280F0064C440 /* breakpointEditor.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; path = breakpointEditor.html; sourceTree = "<group>"; };
                8D15AC360486D014006FF6A4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
                8D15AC370486D014006FF6A4 /* Drosera.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Drosera.app; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
                1CC058B70A44A210006FE533 /* Images */ = {
                        isa = PBXGroup;
                        children = (
+                               63D54D7B0AE75CF10064C440 /* close_active.tif */,
+                               63D54D7C0AE75CF10064C440 /* close_hover.tif */,
+                               63D54D7D0AE75CF10064C440 /* close.tif */,
                                63D54BD60AE600560064C440 /* breakpointeditor.png */,
                                15CE854F0ADBEA610078A734 /* fileIcon.jpg */,
                                15CE85500ADBEA610078A734 /* siteCollapsed.tif */,
                                1C6F861F0A599F65004FCD89 /* console.js */,
                                1C6F84540A58EE06004FCD89 /* console.html */,
                                1C6F84530A58EE06004FCD89 /* console.css */,
+                               63D54F770AE8280F0064C440 /* breakpointEditor.html */,
                        );
                        name = Classes;
                        sourceTree = "<group>";
                                15CE85570ADBEA620078A734 /* siteIcon.tif in Resources */,
                                15CE85580ADBEA620078A734 /* SourceArrowOpen.png in Resources */,
                                63D54BD70AE600560064C440 /* breakpointeditor.png in Resources */,
+                               63D54D7E0AE75CF10064C440 /* close_active.tif in Resources */,
+                               63D54D7F0AE75CF10064C440 /* close_hover.tif in Resources */,
+                               63D54D800AE75CF10064C440 /* close.tif in Resources */,
+                               63D54F780AE8280F0064C440 /* breakpointEditor.html in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/WebKitTools/Drosera/Images/close.tif b/WebKitTools/Drosera/Images/close.tif
new file mode 100644 (file)
index 0000000..a221ac7
Binary files /dev/null and b/WebKitTools/Drosera/Images/close.tif differ
diff --git a/WebKitTools/Drosera/Images/close_active.tif b/WebKitTools/Drosera/Images/close_active.tif
new file mode 100644 (file)
index 0000000..104799d
Binary files /dev/null and b/WebKitTools/Drosera/Images/close_active.tif differ
diff --git a/WebKitTools/Drosera/Images/close_hover.tif b/WebKitTools/Drosera/Images/close_hover.tif
new file mode 100644 (file)
index 0000000..cd86fa5
Binary files /dev/null and b/WebKitTools/Drosera/Images/close_hover.tif differ
diff --git a/WebKitTools/Drosera/breakpointEditor.html b/WebKitTools/Drosera/breakpointEditor.html
new file mode 100644 (file)
index 0000000..30ef0c9
--- /dev/null
@@ -0,0 +1 @@
+<div class="top">Breakpoint:<label>Enable:<input class="enable" type="checkbox" onclick="window.parent.toggleBreakpointOnLine(this.firstParentWithClass('editor').id)"></input></label><label>Hit Count:<span class="hitCounter">0</span></label><label>Action:<select class="editorDropdown" onchange="window.parent.updateBreakpointTypeOnLine(this.firstParentWithClass('editor').id)"><option value="pause">Pause</option><option value="log">Log</option></select></label><input type="button" class="close" onmouseup="window.parent.toggleBreakpointEditorOnLine(this.firstParentWithClass('editor').id)">&nbsp;</input></div><div class="bottom"><label class="conditionLabel" for="editorCondition">Condition:</label><div class="condition"></div></div>
\ No newline at end of file
index f1707690d5d4639e682e99946aae3f5cfee2eb23..e2c9e4ad5fad5b64144244fa74da527fa3cdbc40 100644 (file)
@@ -51,50 +51,69 @@ function inputKeyDown(event)
         event.preventDefault();
     } else if (event.keyCode == 38 && !event.altKey) {
         var history = document.getElementById("history");
-        if(historyIndex == -1)
+        if (historyIndex == -1)
             storedInput = inputElement.innerText;
         var historyArray = history.childNodes;
         var historySize = historyArray.length - 1;
-        if(historyIndex < historySize) {
+        if (historyIndex < historySize) {
             historyIndex++;
-            inputElement.innerText = historyArray[historySize - historyIndex].childNodes[0].innerText;
+            var item = historyArray[historySize - historyIndex].childNodes[0];
+            while(item.className.indexOf("expression") == -1) {
+                historyIndex++;
+                item = historyArray[historySize - historyIndex].childNodes[0];
+            }
+            inputElement.innerText = item.innerText;
         }
         event.preventDefault();
     } else if (event.keyCode == 40 && !event.altKey) {
-        if(historyIndex >= 0) {
+        if (historyIndex >= 0) {
             var history = document.getElementById("history");
             historyIndex--;
             if (historyIndex == -1)
                 inputElement.innerText = storedInput;
             else {
                 var historyArray = history.childNodes;
-                inputElement.innerText = historyArray[(historyArray.length - 1) - historyIndex].childNodes[0].innerText;
+                var historySize = historyArray.length - 1;
+                var item = historyArray[historySize - historyIndex].childNodes[0];
+                while(item.className.indexOf("expression") == -1) {
+                    historyIndex--;
+                    item = historyArray[historySize - historyIndex].childNodes[0];
+                }
+                inputElement.innerText = item.innerText;
             }
         }
         event.preventDefault();
     }
 }
 
-function sendScript(script)
+function appendMessage(exp, msg)
 {
     var history = document.getElementById("history");
     var row = document.createElement("div");
     row.className = "row";
     if (history.childNodes.length % 2)
         row.className += " alt";
-
-    var expression = document.createElement("div");
-    expression.className = "expression";
-    expression.innerText = script;
-    row.appendChild(expression);
-
+    
+    if (exp.length > 0) {
+        var expression = document.createElement("div");
+        expression.className = "expression";
+        expression.innerText = exp;
+        row.appendChild(expression);
+    }
+    
     var result = document.createElement("div");
     result.className = "result";
-    result.innerText = mainWindow.DebuggerDocument.evaluateScript_inCallFrame_(script, mainWindow.currentCallFrame.index);
+    result.innerText = msg;
+    
     row.appendChild(result);
-
+    
     history.appendChild(row);
     history.scrollTop = history.scrollHeight;
+}
+
+function sendScript(script)
+{
+    appendMessage(script, mainWindow.DebuggerDocument.evaluateScript_inCallFrame_(script, mainWindow.currentCallFrame.index));
 
     if (script.indexOf("=") >= 0)
         mainWindow.currentCallFrame.loadVariables();
index ecb7e3c0f98255687c060f092c052f4a1abdc6af..15ca916cdc157668a1405d6fd9e0c8903953081f 100644 (file)
@@ -47,8 +47,7 @@ var steppingStack = 0;
 var pauseOnNextStatement = false;
 var pausedWhileLeavingFrame = false;
 var consoleWindow = null;
-var enabledBreakpoint = "break";
-var breakpointEditorHTML = '<div class="top">Edit Breakpoint:<label><input type="checkbox" onclick="window.parent.toggleBreakpointForEditor(this.parentNode.parentNode.parentNode)"></input>Enable</label><button class="save" onclick="window.parent.saveBreakpointForEditor(this.parentNode.parentNode)">Save</button></div><div class="bottom"><label for="editorCondition">Condition:</label><div class="condition"></div></div>';
+var breakpointEditorHTML = DebuggerDocument.breakpointEditorHTML();
 var pendingAction = null;
 
 ScriptCallFrame = function (functionName, index, row)
@@ -88,7 +87,8 @@ ScriptCallFrame.prototype.loadVariables = function ()
     }
 }
 
-function sleep(numberMillis) {
+function sleep(numberMillis) 
+{
     var now = new Date();
     var exitTime = now.getTime() + numberMillis;
     while (true) {
@@ -98,16 +98,19 @@ function sleep(numberMillis) {
     }
 }
 
-function headerMouseDown(element) {
+function headerMouseDown(element) 
+{
     if (!isResizingColumn) 
         element.style.background = "url(glossyHeaderPressed.png) repeat-x";
 }
 
-function headerMouseUp(element) {
+function headerMouseUp(element) 
+{
     element.style.background = "url(glossyHeader.png) repeat-x";
 }
 
-function headerMouseOut(element) {
+function headerMouseOut(element) 
+{
     element.style.background = "url(glossyHeader.png) repeat-x";
 }
 
@@ -139,7 +142,8 @@ function filesDividerDrag(event)
     }
 }
 
-function dividerDragStart(element, dividerDrag, dividerDragEnd, event, cursor) {
+function dividerDragStart(element, dividerDrag, dividerDragEnd, event, cursor) 
+{
     element.dragging = true;
     element.dragLastY = event.clientY + window.scrollY;
     element.dragLastX = event.clientX + window.scrollX;
@@ -149,14 +153,16 @@ function dividerDragStart(element, dividerDrag, dividerDragEnd, event, cursor) {
     event.preventDefault();
 }
 
-function dividerDragEnd(element, dividerDrag, dividerDragEnd, event) {
+function dividerDragEnd(element, dividerDrag, dividerDragEnd, event) 
+{
     element.dragging = false;
     document.removeEventListener("mousemove", dividerDrag, true);
     document.removeEventListener("mouseup", dividerDragEnd, true);
     document.body.style.cursor = null;
 }
 
-function dividerDrag(event) {
+function dividerDrag(event) 
+{
     var element = document.getElementById("divider");
     if (document.getElementById("divider").dragging == true) {
         var main = document.getElementById("main");
@@ -173,23 +179,28 @@ function dividerDrag(event) {
     }
 }
 
-function sourceDividerDragStart(event) {
+function sourceDividerDragStart(event) 
+{
     dividerDragStart(document.getElementById("divider"), dividerDrag, sourceDividerDragEnd, event, "row-resize");
 }
 
-function sourceDividerDragEnd(event) {
+function sourceDividerDragEnd(event) 
+{
     dividerDragEnd(document.getElementById("divider"), dividerDrag, sourceDividerDragEnd, event);
 }
 
-function infoDividerDragStart(event) {
+function infoDividerDragStart(event) 
+{
     dividerDragStart(document.getElementById("infoDivider"), infoDividerDrag, infoDividerDragEnd, event, "col-resize");
 }
 
-function infoDividerDragEnd(event) {
+function infoDividerDragEnd(event) 
+{
     dividerDragEnd(document.getElementById("infoDivider"), infoDividerDrag, infoDividerDragEnd, event);
 }
 
-function infoDividerDrag(event) {
+function infoDividerDrag(event) 
+{
     var element = document.getElementById("infoDivider");
     if (document.getElementById("infoDivider").dragging == true) {
         var main = document.getElementById("main");
@@ -206,17 +217,20 @@ function infoDividerDrag(event) {
     }
 }
 
-function columnResizerDragStart(event) {
+function columnResizerDragStart(event) 
+{
     isResizingColumn = true;
     dividerDragStart(document.getElementById("variableColumnResizer"), columnResizerDrag, columnResizerDragEnd, event, "col-resize");
 }
 
-function columnResizerDragEnd(event) {
+function columnResizerDragEnd(event) 
+{
     isResizingColumn = false;
     dividerDragEnd(document.getElementById("variableColumnResizer"), columnResizerDrag, columnResizerDragEnd, event);
 }
 
-function columnResizerDrag(event) {
+function columnResizerDrag(event) 
+{
     var element = document.getElementById("variableColumnResizer");
     if (element.dragging == true) {
         var main = document.getElementById("rightPane");
@@ -240,7 +254,8 @@ function columnResizerDrag(event) {
     }
 }
 
-function constrainedWidthFromElement(width, element, constrainLeft, constrainRight) {
+function constrainedWidthFromElement(width, element, constrainLeft, constrainRight) 
+{
     if (constrainLeft === undefined) constrainLeft = 0.25;
     if (constrainRight === undefined) constrainRight = 0.75;
     
@@ -251,7 +266,8 @@ function constrainedWidthFromElement(width, element, constrainLeft, constrainRig
     return width;
 }
 
-function constrainedHeightFromElement(height, element) {
+function constrainedHeightFromElement(height, element) 
+{
     if (height < element.clientHeight * 0.25)
         height = element.clientHeight * 0.25;
     else if (height > element.clientHeight * 0.75)
@@ -259,18 +275,21 @@ function constrainedHeightFromElement(height, element) {
     return height;
 }
 
-function loaded() {
+function loaded() 
+{
     document.getElementById("divider").addEventListener("mousedown", sourceDividerDragStart, false);
     document.getElementById("infoDivider").addEventListener("mousedown", infoDividerDragStart, false);
     document.getElementById("filesDivider").addEventListener("mousedown", filesDividerDragStart, false);
     document.getElementById("variableColumnResizer").addEventListener("mousedown", columnResizerDragStart, false);
 }
 
-function isPaused() {
+function isPaused() 
+{
     return DebuggerDocument.isPaused();
 }
 
-function pause() {
+function pause() 
+{
     DebuggerDocument.pause();
 }
 
@@ -323,122 +342,174 @@ function stepOut()
     DebuggerDocument.resume();
 }
 
-Element.prototype.removeStyleClass = function(className) {
+Element.prototype.removeStyleClass = function(className) 
+{
     if (this.hasStyleClass(className))
         this.className = this.className.replace(className, "");
 }
 
-Element.prototype.addStyleClass = function(className) {
+Element.prototype.addStyleClass = function(className) 
+{
     if (!this.hasStyleClass(className))
         this.className += (this.className.length ? " " + className : className);
 }
 
-Element.prototype.hasStyleClass = function(className) {
+Element.prototype.hasStyleClass = function(className) 
+{
     return this.className.indexOf(className) != -1;
 }
 
+Element.prototype.firstParentWithClass = function(className) 
+{
+    var node = this.parentNode;
+    while(!node.hasStyleClass(className)) {
+        if (node == document) 
+            return null;
+        node = node.parentNode;
+    }
+    return node;
+}
+
+Element.prototype.query = function(query) 
+{
+    return document.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+}
+
 function breakpointAction(event)
 {
-    var row = event.target.parentNode;
     var file = files[currentFile];
-    var lineNum = parseInt(event.target.title);
+    var lineNum = event.target.title;
     
-    if (row.hasStyleClass("breakpoint")) {
+    if (file.breakpoints[lineNum]) {
         if (!pendingAction)
-            pendingAction = setTimeout(toggleBreakpoint, DebuggerDocument.doubleClickMilliseconds(), row, file, lineNum);  
+            pendingAction = setTimeout(toggleBreakpointOnLine, DebuggerDocument.doubleClickMilliseconds(), lineNum);  
     } else
-        createBreakpoint(row, file, lineNum);
+        file.breakpoints[lineNum] = new BreakPoint(event.target.parentNode, file, lineNum);
 }
 
-function createBreakpoint(row, file, lineNum)
+BreakPoint = function(row, file, line) 
 {
+    this.row = row;
+    this.file = file;
+    this.line = line;
     row.addStyleClass("breakpoint");
     row.removeStyleClass("disabled");
-    file.breakpoints[lineNum] = enabledBreakpoint;
-    file.disabledBreakpoints[lineNum] = null;
+    this.value = "break";
+    this.enabled = true;
+    this.editor = null;
+    this.type = 0;
+    this.hitcount = 0;
 }
 
-function toggleBreakpointEditor(event)
+function toggleBreakpointEditorOnLine(lineNum)
 {
     if (pendingAction) {
         clearTimeout(pendingAction);
         pendingAction = null;
     }
-    var row = event.target.parentNode;
     var file = files[currentFile];
-    var lineNum = parseInt(event.target.title);
-    if (row.hasStyleClass("breakpoint")) {
-        var editor = file.breakpointEditors[lineNum];
+    bp = file.breakpoints[lineNum];
+    if (bp) {
+        var editor = bp.editor;
         if (!editor) {
             var sourcesDocument = document.getElementById("sources").contentDocument;
             editor = sourcesDocument.createElement("div");
             editor.className = "editor";
             editor.id = lineNum;
             editor.innerHTML = breakpointEditorHTML;
-
-            // set the enabled checkbox to the correct state
-            editor.getElementsByTagName("input")[0].checked = !row.hasStyleClass("disabled");
             
-            // set the condition field to reflect the breakpoint
-            setConditionFieldText(editor, lineNum);
+            bp.row.childNodes[1].appendChild(editor);
             
-            row.childNodes[1].appendChild(editor);
-            file.breakpointEditors[lineNum] = editor; 
+            bp.editor = editor;
+            file.breakpoints[lineNum] = bp;
+
+            editor.query('//input[@class="enable"]').checked = bp.enabled;
+
+            editor.query('//select[@class="editorDropdown"]').selectedIndex = bp.type;
+            updateBreakpointTypeOnLine(lineNum);
+
+            editor.query('//span[@class="hitCounter"]').innerText = bp.hitcount;
+                
+            setConditionFieldText(bp);
         } else {
-            row.childNodes[1].removeChild(editor);
-            file.breakpointEditors[lineNum] = null;
+            saveBreakpointOnLine(lineNum);
+            bp.row.childNodes[1].removeChild(editor);
+            bp.editor = null;
         }
     }
 }
 
-function setConditionFieldText(editor, lineNum)
+function updateBreakpointTypeOnLine(line)
 {
-    var conditionField = editor.childNodes[1].childNodes[1];
-    var functionBody = files[currentFile].breakpoints[lineNum];
+    var breakpoint = files[currentFile].breakpoints[line];
+    var editor = breakpoint.editor;
+    var label = editor.query('//label[@class="conditionLabel"]');
+    var dropdown = editor.query('//select[@class="editorDropdown"]');
+    breakpoint.type = dropdown.selectedIndex;
+    switch(breakpoint.type) {
+        case 0:
+            label.innerText = "Condition:";
+            break;
+        case 1:
+            label.innerText = "Expression:";
+            break;
+    }
+}
+
+function setConditionFieldText(breakpoint)
+{
+    var conditionField = breakpoint.editor.query('//div[@class="condition"]');
+    
+    var functionBody = breakpoint.value;
     if (!functionBody || functionBody == "break")
         functionBody = "";
     else {
-        var startIndex = functionBody.indexOf("{") + 1;
-        var endIndex = functionBody.lastIndexOf("}");
+        var startIndex = functionBody.indexOf("return((") + 8;
+        var endIndex = null;
+        if (startIndex != 7) //-1 + 8, yes, that's lame
+            endIndex = functionBody.lastIndexOf("))");
+        else {
+            startIndex = functionBody.indexOf("{") + 1;
+            endIndex = functionBody.lastIndexOf("}"); 
+        }
         functionBody = functionBody.substring(startIndex, endIndex);
     }
     conditionField.innerText = functionBody;
+    conditionField.addEventListener("keyup", new Function("saveBreakpointOnLine(" + breakpoint.line + ");"), false);
+    conditionField.focus();
 }
 
-function toggleBreakpointForEditor(editor)
+function saveBreakpointOnLine(lineNum)
 {
     var file = files[currentFile];
-    var lineNum = parseInt(editor.id);
+    var breakpoint = file.breakpoints[lineNum];
     row = file.element.firstChild.childNodes.item(lineNum - 1);
-    toggleBreakpoint(row, file, lineNum);
-}
-
-function saveBreakpointForEditor(editor)
-{
-    var file = files[currentFile];
-    var lineNum = parseInt(editor.id);
-    row = file.element.firstChild.childNodes.item(lineNum - 1);
-    file.breakpoints[lineNum] = "__drosera_breakpoint_conditional_func = function() { " + editor.childNodes[1].childNodes[1].innerText + " }; __drosera_breakpoint_conditional_func();";
-    row.childNodes[1].removeChild(editor);
-    file.breakpointEditors[lineNum] = null;
+    var editor = breakpoint.editor;
+    var body = editor.query('//div[@class="condition"]').innerText;
+    var actionIndex = editor.query('//select[@class="editorDropdown"]').selectedIndex;
+    if (body.length == 0)
+        breakpoint.value = "break";
+    else if (body.indexOf("return") != -1)
+        breakpoint.value = "__drosera_breakpoint_conditional_func = function() {" + body + "}; __drosera_breakpoint_conditional_func();";
+    else
+        breakpoint.value = "__drosera_breakpoint_conditional_func = function() { return((" + body + ")); }; __drosera_breakpoint_conditional_func();";
 }
 
-function toggleBreakpoint(row, file, lineNum)
+function toggleBreakpointOnLine(lineNum)
 {
+    var breakpoint = files[currentFile].breakpoints[lineNum];
     pendingAction = null;
-    if (row.hasStyleClass("disabled"))
-        row.removeStyleClass("disabled");    
+    if (breakpoint.enabled)
+        breakpoint.row.addStyleClass("disabled");    
     else
-        row.addStyleClass("disabled");
+        breakpoint.row.removeStyleClass("disabled");
     
-    var hack = row.offsetTop; // force a relayout if needed.
+    var hack = breakpoint.row.offsetTop; // force a relayout if needed.
     
-    var temp = file.breakpoints[lineNum];
-    file.breakpoints[lineNum] = file.disabledBreakpoints[lineNum];
-    file.disabledBreakpoints[lineNum] = temp;
-    var editor = file.breakpointEditors[lineNum];
+    breakpoint.enabled = !breakpoint.enabled;
+    var editor = breakpoint.editor;
     if (editor) {
-        editor.childNodes[0].childNodes[1].childNodes[0].checked = !row.hasStyleClass("disabled");
+        editor.query('//input[@class="enable"]').checked = breakpoint.enabled;
         setConditionFieldText(editor, lineNum);
     }
 }
@@ -474,34 +545,27 @@ function breakpointDrag(event)
     if (draggingBreakpoint.started || deltaX > 4 || deltaY > 4 || deltaX < -4 || deltaY < -4) {
     
         if (!draggingBreakpoint.started) {
-            var node = draggingBreakpoint.parentNode;
-            draggingBreakpoint.isDisabled = node.hasStyleClass("disabled");
-            node.removeStyleClass("breakpoint");
-            node.removeStyleClass("disabled");
-            
-            var lineNum = parseInt(draggingBreakpoint.title);
+            var lineNum = draggingBreakpoint.title;
             var file = files[currentFile];
-            
-            var editor = file.breakpointEditors[lineNum];
-            if (editor) {
-                node.childNodes[1].removeChild(editor);
-                file.breakpointEditors[lineNum] = null;
-            }
+            var breakpoint = file.breakpoints[lineNum];
+            draggingBreakpoint.breakpoint = breakpoint;
+            breakpoint.row.removeStyleClass("breakpoint");
+            breakpoint.row.removeStyleClass("disabled");
+
+            var editor = breakpoint.editor;
+            if (editor)
+                toggleBreakpointEditorOnLine(lineNum);
             
             draggingBreakpoint.started = true;
                         
-            if (draggingBreakpoint.isDisabled)
-                draggingBreakpoint.breakFunction = files[currentFile].disabledBreakpoints[lineNum];
-            else
-                draggingBreakpoint.breakFunction = files[currentFile].breakpoints[lineNum];
             file.breakpoints[lineNum] = null;
-            file.disabledBreakpoints[lineNum] = null;
 
             var dragImage = sourcesDocument.createElement("img");
-            if (draggingBreakpoint.isDisabled)
-                dragImage.src = "breakPointDisabled.tif";
-            else
+            if (draggingBreakpoint.breakpoint.enabled)
                 dragImage.src = "breakPoint.tif";
+            else
+                dragImage.src = "breakPointDisabled.tif";
+
             dragImage.id = "breakpointDrag";
             dragImage.style.top = y - 8 + "px";
             dragImage.style.left = x - 12 + "px";
@@ -560,14 +624,12 @@ function breakpointDragEnd(event)
     if (!tr)
         return;
         
-    if (draggingBreakpoint.isDisabled) {
+    var breakpoint = draggingBreakpoint.breakpoint;
+    breakpoint.row = tr;
+    file.breakpoints[row] = breakpoint;
+    
+    if (!breakpoint.enabled)
         tr.addStyleClass("disabled");
-        file.disabledBreakpoints[row] = draggingBreakpoint.breakFunction;
-        file.breakpoints[row] = null;
-    } else {
-        file.disabledBreakpoints[row] = null;
-        file.breakpoints[row] = draggingBreakpoint.breakFunction;
-    }
 
     tr.addStyleClass("breakpoint");
     
@@ -839,7 +901,7 @@ function loadFile(fileIndex, manageNavLists)
             td.className = "gutter";
             td.title = (i + 1);
             td.addEventListener("click", breakpointAction, true);
-            td.addEventListener("dblclick", toggleBreakpointEditor, true);
+            td.addEventListener("dblclick", function() { toggleBreakpointEditorOnLine(event.target.title); }, true);
             td.addEventListener("mousedown", moveBreakPoint, true);
             tr.appendChild(td);
 
@@ -1031,8 +1093,6 @@ function didParseScript(source, fileSource, url, sourceId, baseLineNumber)
         file = new Object();
         file.scripts = new Array();
         file.breakpoints = new Array();
-        file.disabledBreakpoints = new Array();
-        file.breakpointEditors = new Array();
         file.source = (fileSource.length ? fileSource : source);
         file.url = (url.length ? url : null);
         file.loaded = false;
@@ -1112,7 +1172,32 @@ function willExecuteStatement(sourceId, line, fromLeavingFrame)
     lastStatement = [sourceId, line];
     
     var breakpoint = file.breakpoints[line];
-    var shouldBreak = breakpoint && (breakpoint == "break" || DebuggerDocument.evaluateScript_inCallFrame_(breakpoint, 0) == 1);
+
+    var shouldBreak = false;
+
+    if (breakpoint && breakpoint.enabled) {
+        switch(breakpoint.type) {
+            case 0:
+                shouldBreak = (breakpoint.value == "break" || DebuggerDocument.evaluateScript_inCallFrame_(breakpoint.value, 0) == 1);
+                if (shouldBreak)
+                    breakpoint.hitcount++;
+                break;
+            case 1:
+                var message = "Hit breakpoint on line " + line;
+                if (breakpoint.value != "break")
+                    message = DebuggerDocument.evaluateScript_inCallFrame_(breakpoint.value, 0);
+                if (consoleWindow)
+                    consoleWindow.appendMessage("", message);
+                breakpoint.hitcount++;
+                break;
+        }
+        var editor = breakpoint.editor;
+        var counter = null;
+        if (editor)
+            counter = breakpoint.editor.query('//span[@class="hitCounter"]');
+        if (counter)
+            counter.innerText = breakpoint.hitcount;
+    }
     
     if (pauseOnNextStatement || shouldBreak || (steppingOver && !steppingStack)) {
         pause();
index 29202ae77b5ab3e29c6289da005979253db90245..dec55d606e69744f6cfda828a00241c0e4ca1097 100644 (file)
@@ -92,6 +92,21 @@ td.gutter:after { content: attr(title); -webkit-user-select: none; }
     top: 20px;
 }
 
+.editor .top label {
+    margin-left: 15px;
+}
+
+.editor span.hitCounter {
+    margin-right: 4px;
+    margin-top: 1px;
+    padding-right: 2px;
+    padding-left: 2px;
+}
+
+.editor select.editorDropdown {
+    margin-top: -1px;
+}
+
 .editor div.condition {
     position: relative;
     background-color: white;
@@ -106,22 +121,26 @@ td.gutter:after { content: attr(title); -webkit-user-select: none; }
     padding: 3px;
     border: 1px solid darkgray;
     top: -15px;
-    left: 60px;
-    margin-right: 60px;
+    left: 65px;
+    margin-right: 65px;
 }
 
-.editor button.save {
-    margin-right: 1px;
-    padding: 1px;
-    padding-right: 5px;
-    padding-left: 5px;
+.editor input.close {
+    margin:0px;
+    margin-right: -4px;
     float: right;
-    font-size: 10px;
-    background-color: rgb(34, 128, 186);
-    height: 18px;
-    border: 1px solid rgb(20, 114, 172);
+    background-color: transparent;
+    background-image:url("close.tif");
+    background-repeat: no-repeat;
+    height: 13px;
+    width: 12px;
+    border: none;
+}
+
+.editor input.close:active {
+    background-image:url("close_active.tif");
 }
 
-.editor button.save:active {
-    background-color: rgb(14, 98, 166);
+.editor input.close:hover {
+    background-image:url("close_hover.tif");
 }
index 8eed5804344bd1b480401528a9553cafbea62ee7..070960137a0ed32394d81787ab6b57d0102a1a32 100644 (file)
@@ -29,6 +29,17 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+    <script type="text/javascript">
+        Element.prototype.firstParentWithClass = function(className) {
+            var node = this.parentNode;
+            while(node.className.indexOf(className) == -1) {
+                if(node == document) 
+                    return null;
+                node = node.parentNode;
+            }
+            return node;
+        }
+    </script>
     <style type="text/css">
         @import "viewer.css";
     </style>