01aa097e2299f9a696f12a360ba1d0f35a6290c5
[WebKit-https.git] / WebKitTools / Drosera / debugger.js
1 /*
2  * Copyright (C) 2006 Apple Computer, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 var files = new Array();
30 var filesLookup = new Object();
31 var scripts = new Array();
32 var currentFile = -1;
33 var currentRow = null;
34 var currentStack = null;
35 var previousFiles = new Array();
36 var nextFiles = new Array();
37 var isResizingColumn = false;
38 var draggingBreakpoint = null;
39
40 function sleep(numberMillis) {
41     var now = new Date();
42     var exitTime = now.getTime() + numberMillis;
43     while (true) {
44         now = new Date();
45         if (now.getTime() > exitTime)
46             return;
47     }
48 }
49
50 function columnResizerMouseOver(element) {
51     element.style.cursor = "move";
52 }
53
54 function columnResizerMouseOut(element) {
55
56     element.style.cursor = "arrow";
57 }
58
59 function headerMouseDown(element) {
60     if (!isResizingColumn) 
61         element.style.background = "url(glossyHeaderPressed.png) repeat-x";
62 }
63
64 function headerMouseUp(element) {
65     element.style.background = "url(glossyHeader.png) repeat-x";
66 }
67
68 function headerMouseOut(element) {
69     element.style.background = "url(glossyHeader.png) repeat-x";
70 }
71
72 function dividerDragStart(element, dividerDrag, dividerDragEnd, event) {
73     element.dragging = true;
74     element.dragLastY = event.clientY + window.scrollY;
75     element.dragLastX = event.clientX + window.scrollX;
76     document.addEventListener("mousemove", dividerDrag, true);
77     document.addEventListener("mouseup", dividerDragEnd, true);
78     event.preventDefault();
79 }
80
81 function sourceDividerDragStart(event) {
82     dividerDragStart(document.getElementById("divider"), dividerDrag, sourceDividerDragEnd, event);
83 }
84
85 function infoDividerDragStart(event) {
86     dividerDragStart(document.getElementById("infoDivider"), infoDividerDrag, infoDividerDragEnd, event);
87 }
88
89 function columnResizerDragStart(event) {
90     isResizingColumn = true;
91     dividerDragStart(document.getElementById("variableColumnResizer"), columnResizerDrag, columnResizerDragEnd, event);
92 }
93
94 function columnResizerDragEnd(event) {
95     isResizingColumn = false;
96     dividerDragEnd(document.getElementById("variableColumnResizer"), columnResizerDrag, columnResizerDragEnd, event);
97 }
98
99 function infoDividerDragEnd(event) {
100     dividerDragEnd(document.getElementById("infoDivider"), infoDividerDrag, infoDividerDragEnd);
101 }
102
103 function sourceDividerDragEnd(event) {
104     dividerDragEnd(document.getElementById("divider"), dividerDrag, sourceDividerDragEnd);
105 }
106
107 function dividerDragEnd(element, dividerDrag, dividerDragEnd, event) {
108     element.dragging = false;
109     document.removeEventListener("mousemove", dividerDrag, true);
110     document.removeEventListener("mouseup", dividerDragEnd, true);
111 }
112
113 function columnResizerDrag(event) {
114     var element = document.getElementById("variableColumnResizer");
115     if (element.dragging == true) {
116         var main = document.getElementById("rightPane");
117         var variableColumn = document.getElementById("variable");
118         var x = event.clientX + window.scrollX;
119         var delta = element.dragLastX - x;
120         var newWidth = constrainedWidthFromElement(variableColumn.clientWidth - delta, main);
121         variableColumn.style.width = newWidth + "px";
122         element.style.left = newWidth + "px";
123         element.dragLastX = x;
124         event.preventDefault();
125     }
126 }
127
128 function constrainedWidthFromElement(width, element) {
129     if (width < element.clientWidth * 0.25)
130         width = element.clientWidth * 0.25;
131     else if (width > element.clientWidth * 0.75)
132         width = element.clientWidth * 0.75;
133
134     return width;
135 }
136
137 function constrainedHeightFromElement(height, element) {
138     if (height < element.clientHeight * 0.25)
139         height = element.clientHeight * 0.25;
140     else if (height > element.clientHeight * 0.75)
141         height = element.clientHeight * 0.75;
142
143     return height;
144 }
145
146 function infoDividerDrag(event) {
147     var element = document.getElementById("infoDivider");
148     if (document.getElementById("infoDivider").dragging == true) {
149         var main = document.getElementById("main");
150         var leftPane = document.getElementById("leftPane");
151         var rightPane = document.getElementById("rightPane");
152         var x = event.clientX + window.scrollX;
153         var delta = element.dragLastX - x;
154         var newWidth = constrainedWidthFromElement(leftPane.clientWidth - delta, main);
155         leftPane.style.width = newWidth + "px";
156         rightPane.style.left = newWidth + "px";
157         element.dragLastX = x;
158         event.preventDefault();
159     }
160 }
161
162 function dividerDrag(event) {
163     var element = document.getElementById("divider");
164     if (document.getElementById("divider").dragging == true) {
165         var main = document.getElementById("main");
166         var top = document.getElementById("info");
167         var bottom = document.getElementById("body");
168         var y = event.clientY + window.scrollY;
169         var delta = element.dragLastY - y;
170         var newHeight = constrainedHeightFromElement(top.clientHeight - delta, main);
171         top.style.height = newHeight + "px";
172         bottom.style.top = newHeight + "px";
173         element.dragLastY = y;
174         event.preventDefault();
175     }
176 }
177
178 function loaded() {
179     document.getElementById("divider").addEventListener("mousedown", sourceDividerDragStart, false);
180     document.getElementById("infoDivider").addEventListener("mousedown", infoDividerDragStart, false);
181     document.getElementById("variableColumnResizer").addEventListener("mousedown", columnResizerDragStart, false);
182 }
183
184 function isPaused() {
185     return DebuggerDocument.isPaused();
186 }
187
188 function pause() {
189     DebuggerDocument.pause();
190 }
191
192 function resume()
193 {
194     if (currentRow) {
195         removeStyleClass(currentRow, "current");
196         currentRow = null;
197     }
198
199     if (currentStack) {
200         var stackframeTable = document.getElementById("stackframeTable");
201         stackframeTable.innerHTML = ""; // clear the content
202         currentStack = null;
203     }
204
205     DebuggerDocument.resume();
206 }
207
208 function stepInto()
209 {
210     DebuggerDocument.stepInto();
211 }
212
213 function hasStyleClass(element, className)
214 {
215     return ( element.className.indexOf(className) != -1 );
216 }
217
218 function addStyleClass(element, className)
219 {
220     if (!hasStyleClass(element, className))
221         element.className += (element.className.length ? " " + className : className);
222 }
223
224 function removeStyleClass(element, className)
225 {
226     if (hasStyleClass(element, className))
227         element.className = element.className.replace(className, "");
228 }
229
230 function addBreakPoint(event)
231 {
232     var row = event.target.parentNode;
233     if (hasStyleClass(row, "breakpoint")) {
234         if (hasStyleClass(row, "disabled")) {
235             removeStyleClass(row, "disabled");
236             files[currentFile].breakpoints[parseInt(event.target.title)] = 1;
237         } else {
238             addStyleClass(row, "disabled");
239             files[currentFile].breakpoints[parseInt(event.target.title)] = -1;
240         }
241     } else {
242         addStyleClass(row, "breakpoint");
243         removeStyleClass(row, "disabled");
244         files[currentFile].breakpoints[parseInt(event.target.title)] = 1;
245     }
246 }
247
248 function moveBreakPoint(event)
249 {
250     if (hasStyleClass(event.target.parentNode, "breakpoint")) {
251         files[currentFile].breakpoints[parseInt(event.target.title)] = 0;
252         draggingBreakpoint = event.target;
253         draggingBreakpoint.started = false;
254         draggingBreakpoint.dragLastY = event.clientY + window.scrollY;
255         draggingBreakpoint.dragLastX = event.clientX + window.scrollX;
256         var sourcesDocument = document.getElementById("sources").contentDocument;
257         sourcesDocument.addEventListener("mousemove", breakpointDrag, true);
258         sourcesDocument.addEventListener("mouseup", breakpointDragEnd, true);
259     }
260 }
261
262 function breakpointDrag(event)
263 {
264     if (!draggingBreakpoint) {
265         sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
266         sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
267         return;
268     }
269
270     var x = event.clientX + window.scrollX;
271     var y = event.clientY + window.scrollY;
272     var deltaX = draggingBreakpoint.dragLastX - x;
273     var deltaY = draggingBreakpoint.dragLastY - y;
274     if (draggingBreakpoint.started || deltaX > 4 || deltaY > 4 || deltaX < -4 || deltaY < -4) {
275         if (!draggingBreakpoint.started) {
276             draggingBreakpoint.isDisabled = hasStyleClass(draggingBreakpoint.parentNode, "disabled");
277             removeStyleClass(draggingBreakpoint.parentNode, "breakpoint");
278             removeStyleClass(draggingBreakpoint.parentNode, "disabled");
279             draggingBreakpoint.started = true;
280
281             var sourcesDocument = document.getElementById("sources").contentDocument;
282             var dragImage = sourcesDocument.createElement("img");
283             if (draggingBreakpoint.isDisabled)
284                 dragImage.src = "breakPointDisabled.tif";
285             else
286                 dragImage.src = "breakPoint.tif";
287             dragImage.id = "breakpointDrag";
288             dragImage.style.top = y - 8 + "px";
289             dragImage.style.left = x - 12 + "px";
290             sourcesDocument.body.appendChild(dragImage);
291         } else {
292             var sourcesDocument = document.getElementById("sources").contentDocument;
293             var dragImage = sourcesDocument.getElementById("breakpointDrag");
294             if (!dragImage) {
295                 sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
296                 sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
297                 return;
298             }
299
300             dragImage.style.top = y - 8 + "px";
301             dragImage.style.left = x - 12 + "px";
302             if (x > 40)
303                 dragImage.style.opacity = "0";
304             else
305                 dragImage.style.opacity = null;
306         }
307
308         draggingBreakpoint.dragLastX = x;
309         draggingBreakpoint.dragLastY = y;
310     }
311 }
312
313 function breakpointDragEnd(event)
314 {
315     var y = event.clientY + window.scrollY;
316     var x = event.clientX + window.scrollX;
317     var sourcesDocument = document.getElementById("sources").contentDocument;
318     sourcesDocument.removeEventListener("mousemove", breakpointDrag, true);
319     sourcesDocument.removeEventListener("mouseup", breakpointDragEnd, true);
320
321     var sourcesDocument = document.getElementById("sources").contentDocument;
322     var dragImage = sourcesDocument.getElementById("breakpointDrag");
323     if (!dragImage)
324         return;
325
326     dragImage.parentNode.removeChild(dragImage);
327
328     if (x > 40 || !draggingBreakpoint)
329         return;
330
331     var rowHeight = draggingBreakpoint.parentNode.offsetHeight;
332     var row = Math.ceil(y / rowHeight);
333     if (!row)
334         row = 1;
335
336     var file = files[currentFile];
337     var table = file.element.firstChild;
338     if (row > table.childNodes.length)
339         return;
340
341     var tr = table.childNodes.item(row - 1);
342
343     if (draggingBreakpoint.isDisabled)
344         addStyleClass(tr, "disabled");
345     addStyleClass(tr, "breakpoint");
346     file.breakpoints[row] = (draggingBreakpoint.isDisabled ? -1 : 1);
347
348     draggingBreakpoint = null;
349 }
350
351 function totalOffsetTop(element, stop)
352 {
353     var currentTop = 0;
354     if (element.offsetParent) {
355         while (element.offsetParent) {
356             currentTop += element.offsetTop
357             element = element.offsetParent;
358             if (element == stop)
359                 break;
360         }
361     }
362     return currentTop;
363 }
364
365 function switchFile()
366 {
367     var filesSelect = document.getElementById("files");
368     loadFile(filesSelect.options[filesSelect.selectedIndex].value, true);
369 }
370
371 function syntaxHighlight(code)
372 {
373     var keywords = { 'abstract': 1, 'boolean': 1, 'break': 1, 'byte': 1, 'case': 1, 'catch': 1, 'char': 1, 'class': 1, 'const': 1, 'continue': 1, 'debugger': 1, 'default': 1, 'delete': 1, 'do': 1, 'double': 1, 'else': 1, 'enum': 1, 'export': 1, 'extends': 1, 'false': 1, 'final': 1, 'finally': 1, 'float': 1, 'for': 1, 'function': 1, 'goto': 1, 'if': 1, 'implements': 1, 'import': 1, 'in': 1, 'instanceof': 1, 'int': 1, 'interface': 1, 'long': 1, 'native': 1, 'new': 1, 'null': 1, 'package': 1, 'private': 1, 'protected': 1, 'public': 1, 'return': 1, 'short': 1, 'static': 1, 'super': 1, 'switch': 1, 'synchronized': 1, 'this': 1, 'throw': 1, 'throws': 1, 'transient': 1, 'true': 1, 'try': 1, 'typeof': 1, 'var': 1, 'void': 1, 'volatile': 1, 'while': 1, 'with': 1 };
374
375     function echoChar(c) {
376         if (c == '<')
377             result += '&lt;';
378         else if (c == '>')
379             result += '&gt;';
380         else if (c == '&')
381             result += '&amp;';
382         else if (c == '\t')
383             result += '    ';
384         else
385             result += c;
386     }
387
388     function isDigit(number) {
389         var string = "1234567890";
390         if (string.indexOf(number) != -1)
391             return true;
392         return false;
393     }
394
395     function isHex(hex) {
396         var string = "1234567890abcdefABCDEF";
397         if (string.indexOf(hex) != -1)
398             return true;
399         return false;
400     }
401
402     function isLetter(letter) {
403         var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
404         if (string.indexOf(letter) != -1)
405             return true;
406         return false;
407     }
408
409     var result = "";
410     var cPrev = "";
411     var c = "";
412     var cNext = "";
413     for (var i = 0; i < code.length; i++) {
414         cPrev = c;
415         c = code.charAt(i);
416         cNext = code.charAt(i + 1);
417
418         if (c == "/" && cNext == "*") {
419             result += "<span class=\"comment\">";
420             echoChar(c);
421             echoChar(cNext);
422             for (i += 2; i < code.length; i++) {
423                 c = code.charAt(i);
424                 if (c == "\n" || c == "\r")
425                     result += "</span>";
426                 echoChar(c);
427                 if (c == "\n" || c == "\r")
428                     result += "<span class=\"comment\">";
429                 if (cPrev == "*" && c == "/")
430                     break;
431                 cPrev = c;
432             }
433             result += "</span>";
434             continue;
435         } else if (c == "/" && cNext == "/") {
436             result += "<span class=\"comment\">";
437             echoChar(c);
438             echoChar(cNext);
439             for (i += 2; i < code.length; i++) {
440                 c = code.charAt(i);
441                 if (c == "\n" || c == "\r")
442                     break;
443                 echoChar(c);
444             }
445             result += "</span>";
446             echoChar(c);
447             continue;
448         } else if (c == "\"" || c == "'") {
449             var instringtype = c;
450             var stringstart = i;
451             result += "<span class=\"string\">";
452             echoChar(c);
453             for (i += 1; i < code.length; i++) {
454                 c = code.charAt(i);
455                 if (stringstart < (i - 1) && cPrev == instringtype && code.charAt(i - 2) != "\\")
456                     break;
457                 echoChar(c);
458                 cPrev = c;
459             }
460             result += "</span>";
461             echoChar(c);
462             continue;
463         } else if (c == "0" && cNext == "x" && (i == 0 || (!isLetter(cPrev) && !isDigit(cPrev)))) {
464             result += "<span class=\"number\">";
465             echoChar(c);
466             echoChar(cNext);
467             for (i += 2; i < code.length; i++) {
468                 c = code.charAt(i);
469                 if (!isHex(c))
470                     break;
471                 echoChar(c);
472             }
473             result += "</span>";
474             echoChar(c);
475             continue;
476         } else if ((isDigit(c) || ((c == "-" || c == ".") && isDigit(cNext))) && (i == 0 || (!isLetter(cPrev) && !isDigit(cPrev)))) {
477             result += "<span class=\"number\">";
478             echoChar(c);
479             for (i += 1; i < code.length; i++) {
480                 c = code.charAt(i);
481                 if (!isDigit(c) && c != ".")
482                     break;
483                 echoChar(c);
484             }
485             result += "</span>";
486             echoChar(c);
487             continue;
488         } else if(isLetter(c) && (i == 0 || !isLetter(cPrev))) {
489             var keyword = c;
490             var cj = "";
491             for (var j = i + 1; j < i + 12 && j < code.length; j++) {
492                 cj = code.charAt(j);
493                 if (!isLetter(cj))
494                     break;
495                 keyword += cj;
496             }
497
498             if (keywords[keyword]) {
499                 result += "<span class=\"keyword\">" + keyword + "</span>";
500                 i += keyword.length - 1;
501                 continue;
502             }
503         }
504
505         echoChar(c);
506     }
507
508     return result;
509 }
510
511 function navFilePrevious(element)
512 {
513     if (element.disabled)
514         return;
515     var lastFile = previousFiles.pop();
516     if (currentFile != -1)
517         nextFiles.unshift(currentFile);
518     loadFile(lastFile, false);
519 }
520
521 function navFileNext(element)
522 {
523     if (element.disabled)
524         return;
525     var lastFile = nextFiles.shift();
526     if (currentFile != -1)
527         previousFiles.push(currentFile);
528     loadFile(lastFile, false);
529 }
530
531 function updateFunctionStack()
532 {
533     var stackframeTable = document.getElementById("stackframeTable");
534     stackframeTable.innerHTML = ""; // clear the content
535
536     currentStack = DebuggerDocument.currentFunctionStack();
537     for(var i = 0; i < currentStack.length; i++) {
538         var tr = document.createElement("tr");
539         var td = document.createElement("td");
540         td.className = "stackNumber";
541         td.innerText = i;
542         tr.appendChild(td);
543
544         td = document.createElement("td");
545         td.innerText = currentStack[i];
546         tr.appendChild(td);
547
548         stackframeTable.appendChild(tr);
549     }
550
551     var tr = document.createElement("tr");
552     var td = document.createElement("td");
553     td.className = "stackNumber";
554     td.innerText = i;
555     tr.appendChild(td);
556
557     td = document.createElement("td");
558     td.innerText = "Global";
559     tr.appendChild(td);
560
561     stackframeTable.appendChild(tr);
562 }
563
564 function loadFile(fileIndex, manageNavLists)
565 {
566     var file = files[fileIndex];
567     if (!file)
568         return;
569
570     if (currentFile != -1 && files[currentFile] && files[currentFile].element)
571         files[currentFile].element.style.display = "none";
572
573     if (!file.loaded) {
574         file.lines = file.source.split(/[\n\r]/);
575
576         var sourcesDocument = document.getElementById("sources").contentDocument;
577         var sourcesDiv = sourcesDocument.body;
578         var sourceDiv = sourcesDocument.createElement("div");
579         sourceDiv.id = "file" + fileIndex;
580         sourcesDiv.appendChild(sourceDiv);
581         file.element = sourceDiv;
582
583         var table = sourcesDocument.createElement("table");
584         sourceDiv.appendChild(table);
585
586         var lines = syntaxHighlight(file.source).split(/[\n\r]/);
587         for( var i = 0; i < lines.length; i++ ) {
588             var tr = sourcesDocument.createElement("tr");
589             var td = sourcesDocument.createElement("td");
590             td.className = "gutter";
591             td.title = (i + 1);
592             td.addEventListener("click", addBreakPoint, true);
593             td.addEventListener("mousedown", moveBreakPoint, true);
594             tr.appendChild(td);
595
596             td = sourcesDocument.createElement("td");
597             td.className = "source";
598             td.innerHTML = lines[i];
599             tr.appendChild(td);
600             table.appendChild(tr);
601         }
602
603         file.loaded = true;
604     }
605
606     file.element.style.display = null;
607
608     document.getElementById("filesPopupButtonContent").innerText = (file.url ? file.url : "(unknown script)");
609     
610     var filesSelect = document.getElementById("files");
611     for (var i = 0; i < filesSelect.childNodes.length; i++) {
612         if (filesSelect.childNodes[i].value == fileIndex) {
613             filesSelect.selectedIndex = i;
614             break;
615         }
616     }
617
618     if (manageNavLists) {
619         nextFiles = new Array();
620         if (currentFile != -1)
621             previousFiles.push(currentFile);
622     }
623
624     document.getElementById("navFileLeftButton").disabled = (previousFiles.length == 0);
625     document.getElementById("navFileRightButton").disabled = (nextFiles.length == 0);
626
627     currentFile = fileIndex;
628 }
629
630 function updateFileSource(source, url, force)
631 {
632     var fileIndex = filesLookup[url];
633     if (!fileIndex || !source.length)
634         return;
635
636     var file = files[fileIndex];
637     if (force || file.source.length != source.length || file.source != source) {
638         file.source = source;
639         file.loaded = false;
640         file.lines = null;
641
642         if (file.element) {
643             file.element.parentNode.removeChild(file.element);
644             file.element = null;
645         }
646
647         if (currentFile == fileIndex)
648             loadFile(fileIndex, false);
649     }
650 }
651
652 function didParseScript(source, fileSource, url, sourceId, baseLineNumber)
653 {
654     var fileIndex = filesLookup[url];
655     var file = files[fileIndex];
656     var firstLoad = false;
657     if (!fileIndex || !file) {
658         fileIndex = files.length + 1;
659         if (url.length)
660             filesLookup[url] = fileIndex;
661
662         file = new Object();
663         file.scripts = new Array();
664         file.breakpoints = new Array();
665         file.source = (fileSource.length ? fileSource : source);
666         file.url = (url.length ? url : null);
667         file.loaded = false;
668
669         files[fileIndex] = file;
670
671         var filesSelect = document.getElementById("files");
672         var option = document.createElement("option");
673         files[fileIndex].menuOption = option;
674         option.value = fileIndex;
675         option.text = (file.url ? file.url : "(unknown script)");
676         filesSelect.appendChild(option);
677         firstLoad = true;
678     }
679
680     var sourceObj = new Object();
681     sourceObj.source = source;
682     sourceObj.file = fileIndex;
683     sourceObj.baseLineNumber = baseLineNumber;
684     file.scripts.push(sourceId);
685     scripts[sourceId] = sourceObj;
686
687     if (!firstLoad)
688         updateFileSource((fileSource.length ? fileSource : source), url, false);
689
690     if (currentFile == -1)
691         loadFile(fileIndex, true);
692 }
693
694 function willExecuteStatement(sourceId, line)
695 {
696     var script = scripts[sourceId];
697     if (line <= 0 || !script)
698         return;
699
700     var file = files[script.file];
701     if (!file)
702         return;
703
704     if (file.breakpoints[line] == 1)
705         pause();
706
707     if (isPaused()) {
708         if (currentFile != script.file)
709             loadFile(script.file, true);
710         if (currentRow)
711             removeStyleClass(currentRow, "current");
712         if (!file.element)
713             return;
714         if (file.element.firstChild.childNodes.length < line)
715             return;
716
717         updateFunctionStack();
718
719         currentRow = file.element.firstChild.childNodes.item(line - 1);
720         addStyleClass(currentRow, "current");
721
722         var sourcesDiv = document.getElementById("sources");
723         var sourcesDocument = document.getElementById("sources").contentDocument;
724         var parent = sourcesDocument.body;
725         var offset = totalOffsetTop(currentRow, parent);
726         if (offset < (parent.scrollTop + 20) || offset > (parent.scrollTop + sourcesDiv.clientHeight - 20))
727             parent.scrollTop = totalOffsetTop(currentRow, parent) - (sourcesDiv.clientHeight / 2) + 10;
728     }
729 }
730
731 function didEnterCallFrame(sourceId, line)
732 {
733     willExecuteStatement(sourceId, line);
734 }
735
736 function willLeaveCallFrame(sourceId, line)
737 {
738     willExecuteStatement(sourceId, line);
739 }