1 |
|
2 if (!("console" in window) || !("firebug" in console)) { |
|
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 = "2147483647"; |
|
221 consoleFrame.style.position = "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 } |
|