2010-08-12 Pavel Feldman <pfeldman@chromium.org>
[WebKit-https.git] / WebCore / inspector / front-end / SourceFrame.js
1 /*
2  * Copyright (C) 2009 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate, removeBreakpointDelegate, editDelegate, continueToHereDelegate)
32 {
33     this._parentElement = parentElement;
34
35     this._textModel = new WebInspector.TextEditorModel();
36     this._textModel.replaceTabsWithSpaces = true;
37
38     this._messages = [];
39     this._rowMessages = {};
40     this._messageBubbles = {};
41     this.breakpoints = [];
42
43     this._loaded = false;
44
45     this._continueToHereDelegate = continueToHereDelegate;
46     this._addBreakpointDelegate = addBreakpointDelegate;
47     this._removeBreakpointDelegate = removeBreakpointDelegate;
48     this._editDelegate = editDelegate;
49     this._popoverObjectGroup = "popover";
50 }
51
52 WebInspector.SourceFrame.prototype = {
53
54     set visible(visible)
55     {
56         this._visible = visible;
57         this._createViewerIfNeeded();
58         
59         if (visible) {
60             if (this._textViewer && this._scrollTop)
61                 this._textViewer.element.scrollTop = this._scrollTop;
62             if (this._textViewer && this._scrollLeft)
63                 this._textViewer.element.scrollLeft = this._scrollLeft;
64         } else {
65             this._hidePopup();
66             if (this._textViewer) {
67                 this._scrollTop = this._textViewer.element.scrollTop;
68                 this._scrollLeft = this._textViewer.element.scrollLeft;
69                 this._textViewer.freeCachedElements();
70             }
71         }
72     },
73
74     get executionLine()
75     {
76         return this._executionLine;
77     },
78
79     set executionLine(x)
80     {
81         if (this._executionLine === x)
82             return;
83
84         var previousLine = this._executionLine;
85         this._executionLine = x;
86
87         if (this._textViewer)
88             this._updateExecutionLine(previousLine);
89     },
90
91     revealLine: function(lineNumber)
92     {
93         if (this._textViewer)
94             this._textViewer.revealLine(lineNumber - 1, 0);
95         else
96             this._lineNumberToReveal = lineNumber;
97     },
98
99     addBreakpoint: function(breakpoint)
100     {
101         this.breakpoints.push(breakpoint);
102         breakpoint.addEventListener("enabled", this._breakpointChanged, this);
103         breakpoint.addEventListener("disabled", this._breakpointChanged, this);
104         breakpoint.addEventListener("condition-changed", this._breakpointChanged, this);
105         if (this._textViewer)
106             this._addBreakpointToSource(breakpoint);
107     },
108
109     removeBreakpoint: function(breakpoint)
110     {
111         this.breakpoints.remove(breakpoint);
112         breakpoint.removeEventListener("enabled", null, this);
113         breakpoint.removeEventListener("disabled", null, this);
114         breakpoint.removeEventListener("condition-changed", null, this);
115         if (this._textViewer)
116             this._removeBreakpointFromSource(breakpoint);
117     },
118
119     addMessage: function(msg)
120     {
121         // Don't add the message if there is no message or valid line or if the msg isn't an error or warning.
122         if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning())
123             return;
124         this._messages.push(msg)
125         if (this._textViewer)
126             this._addMessageToSource(msg);
127     },
128
129     clearMessages: function()
130     {
131         for (var line in this._messageBubbles) {
132             var bubble = this._messageBubbles[line];
133             bubble.parentNode.removeChild(bubble);
134         }
135
136         this._messages = [];
137         this._rowMessages = {};
138         this._messageBubbles = {};
139         if (this._textViewer)
140             this._textViewer.resize();
141     },
142
143     sizeToFitContentHeight: function()
144     {
145         if (this._textViewer)
146             this._textViewer.revalidateDecorationsAndPaint();
147     },
148
149     setContent: function(mimeType, content, url)
150     {
151         this._loaded = true;
152         this._textModel.setText(null, content);
153         this._mimeType = mimeType;
154         this._url = url;
155         this._createViewerIfNeeded();
156     },
157
158     updateContent: function(content)
159     {
160         this._textModel.setText(null, content);
161     },
162
163     get textModel()
164     {
165         return this._textModel;
166     },
167
168     highlightLine: function(line)
169     {
170         if (this._textViewer)
171             this._textViewer.highlightLine(line - 1);
172         else
173             this._lineToHighlight = line;
174     },
175
176     _createViewerIfNeeded: function()
177     {
178         if (!this._visible || !this._loaded || this._textViewer)
179             return;
180
181         this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url);
182         var element = this._textViewer.element;
183         element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
184         element.addEventListener("mousedown", this._mouseDown.bind(this), true);
185         element.addEventListener("mousemove", this._mouseMove.bind(this), true);
186         element.addEventListener("scroll", this._scroll.bind(this), true);
187         this._parentElement.appendChild(element);
188
189         this._needsProgramCounterImage = true;
190         this._needsBreakpointImages = true;
191
192         this._textViewer.beginUpdates();
193
194         this._textViewer.mimeType = this._mimeType;
195         this._addExistingMessagesToSource();
196         this._addExistingBreakpointsToSource();
197         this._updateExecutionLine();
198         this._textViewer.resize();
199
200         if (this._lineNumberToReveal) {
201             this.revealLine(this._lineNumberToReveal);
202             delete this._lineNumberToReveal;
203         }
204
205         if (this._pendingMarkRange) {
206             var range = this._pendingMarkRange;
207             this.markAndRevealRange(range);
208             delete this._pendingMarkRange;
209         }
210
211         if (this._lineToHighlight) {
212             this.highlightLine(this._lineToHighlight);
213             delete this._lineToHighlight;
214         }
215         this._textViewer.endUpdates();
216         if (this._editDelegate)
217             this._textViewer.editCallback = this._editDelegate;
218     },
219
220     findSearchMatches: function(query)
221     {
222         var ranges = [];
223
224         // First do case-insensitive search.
225         var regexObject = createSearchRegex(query);
226         this._collectRegexMatches(regexObject, ranges);
227
228         // Then try regex search if user knows the / / hint.
229         try {
230             if (/^\/.*\/$/.test(query))
231                 this._collectRegexMatches(new RegExp(query.substring(1, query.length - 1)), ranges);
232         } catch (e) {
233             // Silent catch.
234         }
235         return ranges;
236     },
237
238     _collectRegexMatches: function(regexObject, ranges)
239     {
240         for (var i = 0; i < this._textModel.linesCount; ++i) {
241             var line = this._textModel.line(i);
242             var offset = 0;
243             do {
244                 var match = regexObject.exec(line);
245                 if (match) {
246                     ranges.push(new WebInspector.TextRange(i, offset + match.index, i, offset + match.index + match[0].length));
247                     offset += match.index + 1;
248                     line = line.substring(match.index + 1);
249                 }
250             } while (match)
251         }
252         return ranges;
253     },
254
255     markAndRevealRange: function(range)
256     {
257         if (this._textViewer)
258             this._textViewer.markAndRevealRange(range);
259         else
260             this._pendingMarkRange = range;
261     },
262
263     clearMarkedRange: function()
264     {
265         if (this._textViewer) {
266             this._textViewer.markAndRevealRange(null);
267         } else
268             delete this._pendingMarkRange;
269     },
270
271     _incrementMessageRepeatCount: function(msg, repeatDelta)
272     {
273         if (!msg._resourceMessageLineElement)
274             return;
275
276         if (!msg._resourceMessageRepeatCountElement) {
277             var repeatedElement = document.createElement("span");
278             msg._resourceMessageLineElement.appendChild(repeatedElement);
279             msg._resourceMessageRepeatCountElement = repeatedElement;
280         }
281
282         msg.repeatCount += repeatDelta;
283         msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount);
284     },
285
286     _breakpointChanged: function(event)
287     {
288         var breakpoint = event.target;
289         var lineNumber = breakpoint.line - 1;
290         if (lineNumber >= this._textModel.linesCount)
291             return;
292
293         if (breakpoint.enabled)
294             this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
295         else
296             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
297
298         if (breakpoint.condition)
299             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
300         else
301             this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
302     },
303
304     _updateExecutionLine: function(previousLine)
305     {
306         if (previousLine) {
307             if (previousLine - 1 < this._textModel.linesCount)
308                 this._textViewer.removeDecoration(previousLine - 1, "webkit-execution-line");
309         }
310
311         if (!this._executionLine)
312             return;
313
314         if (this._executionLine < this._textModel.linesCount)
315             this._textViewer.addDecoration(this._executionLine - 1, "webkit-execution-line");
316     },
317
318     _addExistingMessagesToSource: function()
319     {
320         var length = this._messages.length;
321         for (var i = 0; i < length; ++i)
322             this._addMessageToSource(this._messages[i]);
323     },
324
325     _addMessageToSource: function(msg)
326     {
327         if (msg.line >= this._textModel.linesCount)
328             return;
329
330         var messageBubbleElement = this._messageBubbles[msg.line];
331         if (!messageBubbleElement || messageBubbleElement.nodeType !== Node.ELEMENT_NODE || !messageBubbleElement.hasStyleClass("webkit-html-message-bubble")) {
332             messageBubbleElement = document.createElement("div");
333             messageBubbleElement.className = "webkit-html-message-bubble";
334             this._messageBubbles[msg.line] = messageBubbleElement;
335             this._textViewer.addDecoration(msg.line - 1, messageBubbleElement);
336         }
337
338         var rowMessages = this._rowMessages[msg.line];
339         if (!rowMessages) {
340             rowMessages = [];
341             this._rowMessages[msg.line] = rowMessages;
342         }
343
344         for (var i = 0; i < rowMessages.length; ++i) {
345             if (rowMessages[i].isEqual(msg, true)) {
346                 this._incrementMessageRepeatCount(rowMessages[i], msg.repeatDelta);
347                 return;
348             }
349         }
350
351         rowMessages.push(msg);
352
353         var imageURL;
354         switch (msg.level) {
355             case WebInspector.ConsoleMessage.MessageLevel.Error:
356                 messageBubbleElement.addStyleClass("webkit-html-error-message");
357                 imageURL = "Images/errorIcon.png";
358                 break;
359             case WebInspector.ConsoleMessage.MessageLevel.Warning:
360                 messageBubbleElement.addStyleClass("webkit-html-warning-message");
361                 imageURL = "Images/warningIcon.png";
362                 break;
363         }
364
365         var messageLineElement = document.createElement("div");
366         messageLineElement.className = "webkit-html-message-line";
367         messageBubbleElement.appendChild(messageLineElement);
368
369         // Create the image element in the Inspector's document so we can use relative image URLs.
370         var image = document.createElement("img");
371         image.src = imageURL;
372         image.className = "webkit-html-message-icon";
373         messageLineElement.appendChild(image);
374         messageLineElement.appendChild(document.createTextNode(msg.message));
375
376         msg._resourceMessageLineElement = messageLineElement;
377     },
378
379     _addExistingBreakpointsToSource: function()
380     {
381         for (var i = 0; i < this.breakpoints.length; ++i)
382             this._addBreakpointToSource(this.breakpoints[i]);
383     },
384
385     _addBreakpointToSource: function(breakpoint)
386     {
387         var lineNumber = breakpoint.line - 1;
388         if (lineNumber >= this._textModel.linesCount)
389             return;
390
391         this._textModel.setAttribute(lineNumber, "breakpoint", breakpoint);
392         breakpoint.sourceText = this._textModel.line(breakpoint.line - 1);
393
394         this._textViewer.beginUpdates();
395         this._textViewer.addDecoration(lineNumber, "webkit-breakpoint");
396         if (!breakpoint.enabled)
397             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
398         if (breakpoint.condition)
399             this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
400         this._textViewer.endUpdates();
401     },
402
403     _removeBreakpointFromSource: function(breakpoint)
404     {
405         var lineNumber = breakpoint.line - 1;
406         this._textViewer.beginUpdates();
407         this._textModel.removeAttribute(lineNumber, "breakpoint");
408         this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint");
409         this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
410         this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
411         this._textViewer.endUpdates();
412     },
413
414     _contextMenu: function(event)
415     {
416         var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number");
417         if (!target)
418             return;
419         var row = target.parentElement;
420
421         if (!WebInspector.panels.scripts)
422             return;
423
424         var lineNumber = row.lineNumber;
425         var contextMenu = new WebInspector.ContextMenu();
426
427         contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToHereDelegate.bind(this, lineNumber + 1));
428
429         var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
430         if (!breakpoint) {
431             // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint.
432             contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._addBreakpointDelegate.bind(this, lineNumber + 1));
433
434             function addConditionalBreakpoint() 
435             {
436                 this._addBreakpointDelegate(lineNumber + 1);
437                 var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
438                 if (breakpoint)
439                     this._editBreakpointCondition(breakpoint);
440             }
441
442             contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this));
443         } else {
444             // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable.
445             contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), this._removeBreakpointDelegate.bind(this, breakpoint));
446             contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), this._editBreakpointCondition.bind(this, breakpoint));
447             if (breakpoint.enabled)
448                 contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), function() { breakpoint.enabled = false; });
449             else
450                 contextMenu.appendItem(WebInspector.UIString("Enable Breakpoint"), function() { breakpoint.enabled = true; });
451         }
452         contextMenu.show(event);
453     },
454
455     _scroll: function(event)
456     {
457         this._hidePopup();
458     },
459
460     _mouseDown: function(event)
461     {
462         this._resetHoverTimer();
463         this._hidePopup();
464         if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey)
465             return;
466         var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number");
467         if (!target)
468             return;
469         var row = target.parentElement;
470
471         var lineNumber = row.lineNumber;
472
473         var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
474         if (breakpoint) {
475             if (event.shiftKey)
476                 breakpoint.enabled = !breakpoint.enabled;
477             else
478                 this._removeBreakpointDelegate(breakpoint);
479         } else
480             this._addBreakpointDelegate(lineNumber + 1);
481         event.preventDefault();
482     },
483
484     _mouseMove: function(event)
485     {
486         // Pretend that nothing has happened.
487         if (this._hoverElement === event.target || event.target.hasStyleClass("source-frame-eval-expression"))
488             return;
489
490         this._resetHoverTimer();
491         // User has 500ms to reach the popup.
492         if (this._popup) {
493             var self = this;
494             function doHide()
495             {
496                 self._hidePopup();
497                 delete self._hidePopupTimer;
498             }
499             this._hidePopupTimer = setTimeout(doHide, 500);
500         }
501
502         this._hoverElement = event.target;
503
504         // Now that cleanup routines are set up above, leave this in case we are not on a break.
505         if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused)
506             return;
507
508         // We are interested in identifiers and "this" keyword.
509         if (this._hoverElement.hasStyleClass("webkit-javascript-keyword")) {
510             if (this._hoverElement.textContent !== "this")
511                 return;
512         } else if (!this._hoverElement.hasStyleClass("webkit-javascript-ident"))
513             return;
514
515         const toolTipDelay = this._popup ? 600 : 1000;
516         this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay);
517     },
518
519     _resetHoverTimer: function()
520     {
521         if (this._hoverTimer) {
522             clearTimeout(this._hoverTimer);
523             delete this._hoverTimer;
524         }
525     },
526
527     _hidePopup: function()
528     {
529         if (!this._popup)
530             return;
531
532         // Replace higlight element with its contents inplace.
533         var parentElement = this._popup.highlightElement.parentElement;
534         var child = this._popup.highlightElement.firstChild;
535         while (child) {
536             var nextSibling = child.nextSibling;
537             parentElement.insertBefore(child, this._popup.highlightElement);
538             child = nextSibling;
539         }
540         parentElement.removeChild(this._popup.highlightElement);
541
542         this._popup.hide();
543         delete this._popup;
544         InspectorBackend.releaseWrapperObjectGroup(0, this._popoverObjectGroup);
545     },
546
547     _mouseHover: function(element)
548     {
549         delete this._hoverTimer;
550
551         if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused)
552             return;
553
554         var lineRow = element.enclosingNodeOrSelfWithNodeName("tr");
555         if (!lineRow)
556             return;
557
558         // Collect tokens belonging to evaluated exression.
559         var tokens = [ element ];
560         var token = element.previousSibling;
561         while (token && (token.className === "webkit-javascript-ident" || token.className === "webkit-javascript-keyword" || token.textContent.trim() === ".")) {
562             tokens.push(token);
563             token = token.previousSibling;
564         }
565         tokens.reverse();
566
567         // Wrap them with highlight element.
568         var parentElement = element.parentElement;
569         var nextElement = element.nextSibling;
570         var container = document.createElement("span");
571         for (var i = 0; i < tokens.length; ++i)
572             container.appendChild(tokens[i]);
573         parentElement.insertBefore(container, nextElement);
574         this._showPopup(container);
575     },
576
577     _showPopup: function(element)
578     {
579         function killHidePopupTimer()
580         {
581             if (this._hidePopupTimer) {
582                 clearTimeout(this._hidePopupTimer);
583                 delete this._hidePopupTimer;
584
585                 // We know that we reached the popup, but we might have moved over other elements.
586                 // Discard pending command.
587                 this._resetHoverTimer();
588             }
589         }
590
591         function showObjectPopup(result)
592         {
593             if (!WebInspector.panels.scripts.paused)
594                 return;
595
596             var popupContentElement = null;
597             if (result.type !== "object" && result.type !== "node" && result.type !== "array") {
598                 popupContentElement = document.createElement("span");
599                 popupContentElement.className = "monospace";
600                 popupContentElement.style.whiteSpace = "pre";
601                 popupContentElement.textContent = result.description;
602                 this._popup = new WebInspector.Popover(popupContentElement);
603                 this._popup.show(element);
604             } else {
605                 var popupContentElement = document.createElement("div");
606
607                 var titleElement = document.createElement("div");
608                 titleElement.className = "source-frame-popover-title monospace";
609                 titleElement.textContent = result.description;
610                 popupContentElement.appendChild(titleElement);
611
612                 var section = new WebInspector.ObjectPropertiesSection(result, "", null, false);
613                 section.expanded = true;
614                 section.element.addStyleClass("source-frame-popover-tree");
615                 section.headerElement.addStyleClass("hidden");
616                 popupContentElement.appendChild(section.element);
617
618                 this._popup = new WebInspector.Popover(popupContentElement);
619                 const popupWidth = 300;
620                 const popupHeight = 250;
621                 this._popup.show(element, popupWidth, popupHeight);
622             }
623             this._popup.highlightElement = element;
624             this._popup.highlightElement.addStyleClass("source-frame-eval-expression");
625             popupContentElement.addEventListener("mousemove", killHidePopupTimer.bind(this), true);
626         }
627
628         function evaluateCallback(result)
629         {
630             if (result.isError())
631                 return;
632             if (!WebInspector.panels.scripts.paused)
633                 return;
634             showObjectPopup.call(this, result);
635         }
636         WebInspector.panels.scripts.evaluateInSelectedCallFrame(element.textContent, false, this._popoverObjectGroup, evaluateCallback.bind(this));
637     },
638
639     _editBreakpointCondition: function(breakpoint)
640     {
641         this._showBreakpointConditionPopup(breakpoint.line);
642
643         function committed(element, newText)
644         {
645             breakpoint.condition = newText;
646             dismissed.call(this);
647         }
648
649         function dismissed()
650         {
651             if (this._conditionElement)
652                 this._textViewer.removeDecoration(breakpoint.line - 1, this._conditionElement);
653             delete this._conditionEditorElement;
654             delete this._conditionElement;
655         }
656
657         var dismissedHandler = dismissed.bind(this);
658         this._conditionEditorElement.addEventListener("blur", dismissedHandler, false);
659
660         WebInspector.startEditing(this._conditionEditorElement, committed.bind(this), dismissedHandler);
661         this._conditionEditorElement.value = breakpoint.condition;
662         this._conditionEditorElement.select();
663     },
664
665     _showBreakpointConditionPopup: function(lineNumber)
666     {
667         this._conditionElement = this._createConditionElement(lineNumber);
668         this._textViewer.addDecoration(lineNumber - 1, this._conditionElement);
669     },
670
671     _createConditionElement: function(lineNumber)
672     {
673         var conditionElement = document.createElement("div");
674         conditionElement.className = "source-frame-breakpoint-condition";
675
676         var labelElement = document.createElement("label");
677         labelElement.className = "source-frame-breakpoint-message";
678         labelElement.htmlFor = "source-frame-breakpoint-condition";
679         labelElement.appendChild(document.createTextNode(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber)));
680         conditionElement.appendChild(labelElement);
681
682         var editorElement = document.createElement("input");
683         editorElement.id = "source-frame-breakpoint-condition";
684         editorElement.className = "monospace";
685         editorElement.type = "text"
686         conditionElement.appendChild(editorElement);
687         this._conditionEditorElement = editorElement;
688
689         return conditionElement;
690     },
691
692     _evalSelectionInCallFrame: function(event)
693     {
694         if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused)
695             return;
696
697         var selection = this.element.contentWindow.getSelection();
698         if (!selection.rangeCount)
699             return;
700
701         var expression = selection.getRangeAt(0).toString().trim();
702         WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, "console", function(result) {
703             WebInspector.showConsole();
704             var commandMessage = new WebInspector.ConsoleCommand(expression);
705             WebInspector.console.addMessage(commandMessage);
706             WebInspector.console.addMessage(new WebInspector.ConsoleCommandResult(result, commandMessage));
707         });
708     },
709
710     resize: function()
711     {
712         if (this._textViewer)
713             this._textViewer.resize();
714     }
715 }
716
717
718 WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;