console.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Depends on ECMAScript 5 or appropriate polyfill for:
  2. // Array.prototype.map, JSON.stringify
  3. (function () {
  4. var MAX_LINES = 1000,
  5. CONSOLE_CSS = "#SHIMCONSOLE { visibility: hidden; position: fixed; z-index: 9999; left: 0; right: 0; bottom: 0; height: 200px; border-top: solid 1px #808080; overflow: auto; word-wrap: break-word; padding: 5px; background-color: #eeeeee; color: #000000; font-family: monospace; font-size: 10pt; font-weight: normal; font-style: normal; }"
  6. + "#SHIMCONSOLE .SHIMCONSOLE_GROUP { margin-left: 20px; }"
  7. + "#SHIMCONSOLE .SHIMCONSOLE_ERROR { color: #ff0000; }"
  8. + "#SHIMCONSOLE .SHIMCONSOLE_WARN { color: #ff8000; }",
  9. FORMAT_REGEXP = /([^%]|%([\-+0]*)(\d+)?(\.\d+)?([%sdilfox]))/g;
  10. function Console() {
  11. // Add stylesheet
  12. (function () {
  13. var style = document.createElement('style');
  14. (document.getElementsByTagName('HEAD')[0] || document.documentElement).appendChild(style);
  15. if ('styleSheet' in style) {
  16. style.styleSheet.cssText = CONSOLE_CSS;
  17. } else {
  18. style.appendChild(document.createTextNode(CONSOLE_CSS));
  19. }
  20. }());
  21. var display;
  22. var counts = {};
  23. var times = {};
  24. var groups = [];
  25. display = document.createElement('div');
  26. display.id = 'SHIMCONSOLE';
  27. (document.body || document.documentElement).appendChild(display);
  28. function format(o) {
  29. var span = document.createElement('span'), text, color, classOf;
  30. switch (typeof o) {
  31. case 'undefined':
  32. text = String(o);
  33. color = 'gray';
  34. break;
  35. case 'boolean':
  36. text = String(o);
  37. color = 'green';
  38. break;
  39. case 'number':
  40. text = String(o);
  41. color = 'blue';
  42. break;
  43. case 'string':
  44. text = o;
  45. break;
  46. default: // object and null
  47. if (!o) {
  48. text = String(o);
  49. color = 'gray';
  50. } else {
  51. classOf = Object.prototype.toString.call(o);
  52. if (classOf === '[object Array]' || classOf === '[object Object]') {
  53. try {
  54. text = JSON.stringify(o);
  55. } catch (e) {
  56. // Cyclic, use fallback
  57. text = classOf;
  58. }
  59. } else {
  60. text = String(o);
  61. }
  62. }
  63. }
  64. span.appendChild(document.createTextNode(text));
  65. if (color) {
  66. span.style.color = color;
  67. }
  68. return span;
  69. }
  70. function show(args, type, prefix) {
  71. if (!args.length) {
  72. return;
  73. }
  74. var line = document.createElement('div');
  75. line.className = 'SHIMCONSOLE_' + type;
  76. line.style.whiteSpace = 'pre';
  77. if (prefix) {
  78. line.appendChild(document.createTextNode(prefix));
  79. }
  80. function trunc(n) {
  81. return n < 0 ? Math.ceil(n) : Math.floor(n);
  82. }
  83. function repl(str, unit, flags, width, precision, specifier) {
  84. if (unit.charAt(0) != '%' || !args.length) {
  85. return unit;
  86. } else if (specifier === '%') {
  87. return '%';
  88. }
  89. var arg = args.shift();
  90. switch (specifier) {
  91. case 's': return String(arg);
  92. case 'd':
  93. case 'i':
  94. case 'l': return String(trunc(Number(arg)));
  95. case 'f': return String(Number(arg));
  96. default:
  97. case 'o':
  98. try {
  99. return JSON.stringify(arg);
  100. } catch (e) {
  101. return String(arg);
  102. }
  103. }
  104. return void 0;
  105. }
  106. if (typeof args[0] === 'string') {
  107. line.appendChild(document.createTextNode(args.shift().replace(FORMAT_REGEXP, repl)));
  108. line.appendChild(document.createTextNode(' '));
  109. }
  110. // pretty-print remaining arguments
  111. while (args.length) {
  112. line.appendChild(format(args.shift()));
  113. line.appendChild(document.createTextNode(' '));
  114. }
  115. var parent = groups.length ? groups[groups.length - 1] : display;
  116. parent.appendChild(line);
  117. while (display.children.length > MAX_LINES) {
  118. display.removeChild(display.firstChild);
  119. }
  120. display.scrollTop = display.scrollHeight;
  121. display.style.visibility = 'visible';
  122. }
  123. function toArray(a) {
  124. var result = [], i;
  125. for (i = 0; i < a.length; i += 1) {
  126. result[i] = a[i];
  127. }
  128. return result;
  129. }
  130. this.log = function log(messageObject) { show(toArray(arguments), 'LOG'); };
  131. this.debug = function debug(messageObject) { show(toArray(arguments), 'DEBUG'); };
  132. this.info = function info(messageObject) { show(toArray(arguments), 'INFO'); };
  133. this.warn = function warn(messageObject) { show(toArray(arguments), 'WARN', 'Warning: '); };
  134. this.error = function error(messageObject) { show(toArray(arguments), 'ERROR', 'Error: '); };
  135. this.assert = function assert(a, messageObject) {
  136. if (!a) {
  137. var args = toArray(arguments);
  138. args.shift();
  139. show(args, 'ERROR', 'Assertion failed: ');
  140. }
  141. };
  142. this.count = function count(name) {
  143. name = (name || '');
  144. if (!(('$' + name) in counts)) {
  145. counts['$' + name] = 0;
  146. }
  147. counts['$' + name] += 1;
  148. show([name + ": " + counts['$' + name]], 'INFO');
  149. };
  150. this.time = function time(name) {
  151. name = (name || '');
  152. times['$' + name] = Number(new Date);
  153. };
  154. this.timeEnd = function timeEnd(name) {
  155. name = (name || '');
  156. if (('$' + name) in times) {
  157. show([name + ": " + (Number(new Date) - times['$' + name]) + "ms"], 'INFO');
  158. delete times['$' + name];
  159. }
  160. };
  161. this.group = function group(name) {
  162. name = (name || '');
  163. show(['>' + name], 'INFO');
  164. var div = document.createElement('div');
  165. div.className = 'SHIMCONSOLE_GROUP';
  166. var parent = groups.length ? groups[groups.length - 1] : display;
  167. parent.appendChild(div);
  168. groups.push(div);
  169. };
  170. this.groupEnd = function groupEnd() {
  171. groups.pop();
  172. };
  173. this.dir = function dir(name) {
  174. show([name], 'INFO');
  175. };
  176. this.dirxml = this.dir;
  177. this.trace = function trace() {
  178. try {
  179. this.wont.work = 0;
  180. } catch (e) {
  181. if (e.stack) {
  182. show([e.stack.replace(/^[^\n]*\n/, 'Stack trace:\n')], 'INFO');
  183. }
  184. }
  185. };
  186. this.clear = function clear() {
  187. while (display.children.length) {
  188. display.removeChild(display.firstChild);
  189. }
  190. };
  191. }
  192. window.console = window.console || new Console();
  193. }());