1 
  2 if (!window.console || !console.firebug) {
  3 (function()
  4 {
  5     window.console = 
  6     {
  7         log: function()
  8         {
  9             logFormatted(arguments, "");
 10         },
 11         
 12         debug: function()
 13         {
 14             logFormatted(arguments, "debug");
 15         },
 16         
 17         info: function()
 18         {
 19             logFormatted(arguments, "info");
 20         },
 21         
 22         warn: function()
 23         {
 24             logFormatted(arguments, "warning");
 25         },
 26         
 27         error: function()
 28         {
 29             logFormatted(arguments, "error");
 30         },
 31         
 32         assert: function(truth, message)
 33         {
 34             if (!truth)
 35             {
 36                 var args = [];
 37                 for (var i = 1; i < arguments.length; ++i)
 38                     args.push(arguments[i]);
 39                 
 40                 logFormatted(args.length ? args : ["Assertion Failure"], "error");
 41                 throw message ? message : "Assertion Failure";
 42             }
 43         },
 44         
 45         dir: function(object)
 46         {
 47             var html = [];
 48                         
 49             var pairs = [];
 50             for (var name in object)
 51             {
 52                 try
 53                 {
 54                     pairs.push([name, object[name]]);
 55                 }
 56                 catch (exc)
 57                 {
 58                 }
 59             }
 60             
 61             pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
 62             
 63             html.push('<table>');
 64             for (var i = 0; i < pairs.length; ++i)
 65             {
 66                 var name = pairs[i][0], value = pairs[i][1];
 67                 
 68                 html.push('<tr>', 
 69                 '<td class="propertyNameCell"><span class="propertyName">',
 70                     escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
 71                 appendObject(value, html);
 72                 html.push('</span></td></tr>');
 73             }
 74             html.push('</table>');
 75             
 76             logRow(html, "dir");
 77         },
 78         
 79         dirxml: function(node)
 80         {
 81             var html = [];
 82             
 83             appendNode(node, html);
 84             logRow(html, "dirxml");
 85         },
 86         
 87         group: function()
 88         {
 89             logRow(arguments, "group", pushGroup);
 90         },
 91         
 92         groupEnd: function()
 93         {
 94             logRow(arguments, "", popGroup);
 95         },
 96         
 97         time: function(name)
 98         {
 99             timeMap[name] = (new Date()).getTime();
100         },
101         
102         timeEnd: function(name)
103         {
104             if (name in timeMap)
105             {
106                 var delta = (new Date()).getTime() - timeMap[name];
107                 logFormatted([name+ ":", delta+"ms"]);
108                 delete timeMap[name];
109             }
110         },
111         
112         count: function()
113         {
114             this.warn(["count() not supported."]);
115         },
116         
117         trace: function()
118         {
119             this.warn(["trace() not supported."]);
120         },
121         
122         profile: function()
123         {
124             this.warn(["profile() not supported."]);
125         },
126         
127         profileEnd: function()
128         {
129         },
130         
131         clear: function()
132         {
133             consoleBody.innerHTML = "";
134         },
135 
136         open: function()
137         {
138             toggleConsole(true);
139         },
140         
141         close: function()
142         {
143             if (frameVisible)
144                 toggleConsole();
145         }
146     };
147  
148     // ********************************************************************************************
149        
150     var consoleFrame = null;
151     var consoleBody = null;
152     var commandLine = null;
153     
154     var frameVisible = false;
155     var messageQueue = [];
156     var groupStack = [];
157     var timeMap = {};
158     
159     var clPrefix = ">>> ";
160     
161     var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
162     var isIE = navigator.userAgent.indexOf("MSIE") != -1;
163     var isOpera = navigator.userAgent.indexOf("Opera") != -1;
164     var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;
165 
166     // ********************************************************************************************
167 
168     function toggleConsole(forceOpen)
169     {
170         frameVisible = forceOpen || !frameVisible;
171         if (consoleFrame)
172             consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
173         else
174             waitForBody();
175     }
176 
177     function focusCommandLine()
178     {
179         toggleConsole(true);
180         if (commandLine)
181             commandLine.focus();
182     }
183 
184     function waitForBody()
185     {
186         if (document.body)
187             createFrame();
188         else
189             setTimeout(waitForBody, 200);
190     }    
191 
192     function createFrame()
193     {
194         if (consoleFrame)
195             return;
196         
197         window.onFirebugReady = function(doc)
198         {
199             window.onFirebugReady = null;
200 
201             var toolbar = doc.getElementById("toolbar");
202             toolbar.onmousedown = onSplitterMouseDown;
203 
204             commandLine = doc.getElementById("commandLine");
205             addEvent(commandLine, "keydown", onCommandLineKeyDown);
206 
207             addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
208             
209             consoleBody = doc.getElementById("log");
210             layout();
211             flush();
212         }
213 
214         var baseURL = getFirebugURL();
215 
216         consoleFrame = document.createElement("iframe");
217         consoleFrame.setAttribute("src", baseURL+"/firebug.html");
218         consoleFrame.setAttribute("frameBorder", "0");
219         consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");    
220         consoleFrame.style.zIndex = "2147483583";
221         consoleFrame.style.position = document.all ? "absolute" : "fixed";
222         consoleFrame.style.width = "100%";
223         consoleFrame.style.left = "0";
224         consoleFrame.style.bottom = "0";
225         consoleFrame.style.height = "200px";
226         document.body.appendChild(consoleFrame);
227     }
228     
229     function getFirebugURL()
230     {
231         var scripts = document.getElementsByTagName("script");
232         for (var i = 0; i < scripts.length; ++i)
233         {
234             if (scripts[i].src.indexOf("firebug.js") != -1)
235             {
236                 var lastSlash = scripts[i].src.lastIndexOf("/");
237                 return scripts[i].src.substr(0, lastSlash);
238             }
239         }
240     }
241     
242     function evalCommandLine()
243     {
244         var text = commandLine.value;
245         commandLine.value = "";
246 
247         logRow([clPrefix, text], "command");
248         
249         var value;
250         try
251         {
252             value = eval(text);
253         }
254         catch (exc)
255         {
256         }
257 
258         console.log(value);
259     }
260     
261     function layout()
262     {
263         var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
264         var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
265         consoleBody.style.top = toolbar.offsetHeight + "px";
266         consoleBody.style.height = height + "px";
267         
268         commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
269     }
270     
271     function logRow(message, className, handler)
272     {
273         if (consoleBody)
274             writeMessage(message, className, handler);
275         else
276         {
277             messageQueue.push([message, className, handler]);
278             waitForBody();
279         }
280     }
281     
282     function flush()
283     {
284         var queue = messageQueue;
285         messageQueue = [];
286         
287         for (var i = 0; i < queue.length; ++i)
288             writeMessage(queue[i][0], queue[i][1], queue[i][2]);
289     }
290 
291     function writeMessage(message, className, handler)
292     {
293         var isScrolledToBottom =
294             consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
295 
296         if (!handler)
297             handler = writeRow;
298         
299         handler(message, className);
300         
301         if (isScrolledToBottom)
302             consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
303     }
304     
305     function appendRow(row)
306     {
307         var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
308         container.appendChild(row);
309     }
310 
311     function writeRow(message, className)
312     {
313         var row = consoleBody.ownerDocument.createElement("div");
314         row.className = "logRow" + (className ? " logRow-"+className : "");
315         row.innerHTML = message.join("");
316         appendRow(row);
317     }
318 
319     function pushGroup(message, className)
320     {
321         logFormatted(message, className);
322 
323         var groupRow = consoleBody.ownerDocument.createElement("div");
324         groupRow.className = "logGroup";
325         var groupRowBox = consoleBody.ownerDocument.createElement("div");
326         groupRowBox.className = "logGroupBox";
327         groupRow.appendChild(groupRowBox);
328         appendRow(groupRowBox);
329         groupStack.push(groupRowBox);
330     }
331 
332     function popGroup()
333     {
334         groupStack.pop();
335     }
336     
337     // ********************************************************************************************
338 
339     function logFormatted(objects, className)
340     {
341         var html = [];
342 
343         var format = objects[0];
344         var objIndex = 0;
345 
346         if (typeof(format) != "string")
347         {
348             format = "";
349             objIndex = -1;
350         }
351 
352         var parts = parseFormat(format);
353         for (var i = 0; i < parts.length; ++i)
354         {
355             var part = parts[i];
356             if (part && typeof(part) == "object")
357             {
358                 var object = objects[++objIndex];
359                 part.appender(object, html);
360             }
361             else
362                 appendText(part, html);
363         }
364 
365         for (var i = objIndex+1; i < objects.length; ++i)
366         {
367             appendText(" ", html);
368             
369             var object = objects[i];
370             if (typeof(object) == "string")
371                 appendText(object, html);
372             else
373                 appendObject(object, html);
374         }
375         
376         logRow(html, className);
377     }
378 
379     function parseFormat(format)
380     {
381         var parts = [];
382 
383         var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;    
384         var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
385 
386         for (var m = reg.exec(format); m; m = reg.exec(format))
387         {
388             var type = m[8] ? m[8] : m[5];
389             var appender = type in appenderMap ? appenderMap[type] : appendObject;
390             var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
391 
392             parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
393             parts.push({appender: appender, precision: precision});
394 
395             format = format.substr(m.index+m[0].length);
396         }
397 
398         parts.push(format);
399 
400         return parts;
401     }
402 
403     function escapeHTML(value)
404     {
405         function replaceChars(ch)
406         {
407             switch (ch)
408             {
409                 case "<":
410                     return "<";
411                 case ">":
412                     return ">";
413                 case "&":
414                     return "&";
415                 case "'":
416                     return "'";
417                 case '"':
418                     return """;
419             }
420             return "?";
421         };
422         return String(value).replace(/[<>&"']/g, replaceChars);
423     }
424 
425     function objectToString(object)
426     {
427         try
428         {
429             return object+"";
430         }
431         catch (exc)
432         {
433             return null;
434         }
435     }
436 
437     // ********************************************************************************************
438 
439     function appendText(object, html)
440     {
441         html.push(escapeHTML(objectToString(object)));
442     }
443 
444     function appendNull(object, html)
445     {
446         html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
447     }
448 
449     function appendString(object, html)
450     {
451         html.push('<span class="objectBox-string">"', escapeHTML(objectToString(object)),
452             '"</span>');
453     }
454 
455     function appendInteger(object, html)
456     {
457         html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
458     }
459 
460     function appendFloat(object, html)
461     {
462         html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
463     }
464 
465     function appendFunction(object, html)
466     {
467         var reName = /function ?(.*?)\(/;
468         var m = reName.exec(objectToString(object));
469         var name = m ? m[1] : "function";
470         html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
471     }
472     
473     function appendObject(object, html)
474     {
475         try
476         {
477             if (object == undefined)
478                 appendNull("undefined", html);
479             else if (object == null)
480                 appendNull("null", html);
481             else if (typeof object == "string")
482                 appendString(object, html);
483             else if (typeof object == "number")
484                 appendInteger(object, html);
485             else if (typeof object == "function")
486                 appendFunction(object, html);
487             else if (object.nodeType == 1)
488                 appendSelector(object, html);
489             else if (typeof object == "object")
490                 appendObjectFormatted(object, html);
491             else
492                 appendText(object, html);
493         }
494         catch (exc)
495         {
496         }
497     }
498         
499     function appendObjectFormatted(object, html)
500     {
501         var text = objectToString(object);
502         var reObject = /\[object (.*?)\]/;
503 
504         var m = reObject.exec(text);
505         html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
506     }
507     
508     function appendSelector(object, html)
509     {
510         html.push('<span class="objectBox-selector">');
511 
512         html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
513         if (object.id)
514             html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
515         if (object.className)
516             html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
517 
518         html.push('</span>');
519     }
520 
521     function appendNode(node, html)
522     {
523         if (node.nodeType == 1)
524         {
525             html.push(
526                 '<div class="objectBox-element">',
527                     '<<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
528 
529             for (var i = 0; i < node.attributes.length; ++i)
530             {
531                 var attr = node.attributes[i];
532                 if (!attr.specified)
533                     continue;
534                 
535                 html.push(' <span class="nodeName">', attr.nodeName.toLowerCase(),
536                     '</span>="<span class="nodeValue">', escapeHTML(attr.nodeValue),
537                     '</span>"')
538             }
539 
540             if (node.firstChild)
541             {
542                 html.push('></div><div class="nodeChildren">');
543 
544                 for (var child = node.firstChild; child; child = child.nextSibling)
545                     appendNode(child, html);
546                     
547                 html.push('</div><div class="objectBox-element"></<span class="nodeTag">', 
548                     node.nodeName.toLowerCase(), '></span></div>');
549             }
550             else
551                 html.push('/></div>');
552         }
553         else if (node.nodeType == 3)
554         {
555             html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
556                 '</div>');
557         }
558     }
559 
560     // ********************************************************************************************
561     
562     function addEvent(object, name, handler)
563     {
564         if (document.all)
565             object.attachEvent("on"+name, handler);
566         else
567             object.addEventListener(name, handler, false);
568     }
569     
570     function removeEvent(object, name, handler)
571     {
572         if (document.all)
573             object.detachEvent("on"+name, handler);
574         else
575             object.removeEventListener(name, handler, false);
576     }
577     
578     function cancelEvent(event)
579     {
580         if (document.all)
581             event.cancelBubble = true;
582         else
583             event.stopPropagation();        
584     }
585 
586     function onError(msg, href, lineNo)
587     {
588         var html = [];
589         
590         var lastSlash = href.lastIndexOf("/");
591         var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
592         
593         html.push(
594             '<span class="errorMessage">', msg, '</span>', 
595             '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
596         );
597         
598         logRow(html, "error");
599     };
600 
601     function onKeyDown(event)
602     {
603         if (event.keyCode == 123)
604             toggleConsole();
605         else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
606                  && (event.metaKey || event.ctrlKey))
607             focusCommandLine();
608         else
609             return;
610         
611         cancelEvent(event);
612     }
613 
614     function onSplitterMouseDown(event)
615     {
616         if (isSafari || isOpera)
617             return;
618         
619         addEvent(document, "mousemove", onSplitterMouseMove);
620         addEvent(document, "mouseup", onSplitterMouseUp);
621 
622         for (var i = 0; i < frames.length; ++i)
623         {
624             addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
625             addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
626         }
627     }
628     
629     function onSplitterMouseMove(event)
630     {
631         var win = document.all
632             ? event.srcElement.ownerDocument.parentWindow
633             : event.target.ownerDocument.defaultView;
634 
635         var clientY = event.clientY;
636         if (win != win.parent)
637             clientY += win.frameElement ? win.frameElement.offsetTop : 0;
638         
639         var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
640         var y = height - clientY;
641         
642         consoleFrame.style.height = y + "px";
643         layout();
644     }
645     
646     function onSplitterMouseUp(event)
647     {
648         removeEvent(document, "mousemove", onSplitterMouseMove);
649         removeEvent(document, "mouseup", onSplitterMouseUp);
650 
651         for (var i = 0; i < frames.length; ++i)
652         {
653             removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
654             removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
655         }
656     }
657     
658     function onCommandLineKeyDown(event)
659     {
660         if (event.keyCode == 13)
661             evalCommandLine();
662         else if (event.keyCode == 27)
663             commandLine.value = "";
664     }
665     
666     window.onerror = onError;
667     addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
668     
669     if (document.documentElement.getAttribute("debug") == "true")
670         toggleConsole(true);
671 })();
672 }
673