LoggingPane.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /***
  2. MochiKit.LoggingPane 1.4
  3. See <http://mochikit.com/> for documentation, downloads, license, etc.
  4. (c) 2005 Bob Ippolito. All rights Reserved.
  5. ***/
  6. if (typeof(dojo) != 'undefined') {
  7. dojo.provide('MochiKit.LoggingPane');
  8. dojo.require('MochiKit.Logging');
  9. dojo.require('MochiKit.Base');
  10. }
  11. if (typeof(JSAN) != 'undefined') {
  12. JSAN.use("MochiKit.Logging", []);
  13. JSAN.use("MochiKit.Base", []);
  14. }
  15. try {
  16. if (typeof(MochiKit.Base) == 'undefined' || typeof(MochiKit.Logging) == 'undefined') {
  17. throw "";
  18. }
  19. } catch (e) {
  20. throw "MochiKit.LoggingPane depends on MochiKit.Base and MochiKit.Logging!";
  21. }
  22. if (typeof(MochiKit.LoggingPane) == 'undefined') {
  23. MochiKit.LoggingPane = {};
  24. }
  25. MochiKit.LoggingPane.NAME = "MochiKit.LoggingPane";
  26. MochiKit.LoggingPane.VERSION = "1.4";
  27. MochiKit.LoggingPane.__repr__ = function () {
  28. return "[" + this.NAME + " " + this.VERSION + "]";
  29. };
  30. MochiKit.LoggingPane.toString = function () {
  31. return this.__repr__();
  32. };
  33. MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */) {
  34. var m = MochiKit.LoggingPane;
  35. inline = !(!inline);
  36. if (m._loggingPane && m._loggingPane.inline != inline) {
  37. m._loggingPane.closePane();
  38. m._loggingPane = null;
  39. }
  40. if (!m._loggingPane || m._loggingPane.closed) {
  41. m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger);
  42. }
  43. return m._loggingPane;
  44. };
  45. MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */) {
  46. /* Use a div if inline, pop up a window if not */
  47. /* Create the elements */
  48. if (typeof(logger) == "undefined" || logger === null) {
  49. logger = MochiKit.Logging.logger;
  50. }
  51. this.logger = logger;
  52. var update = MochiKit.Base.update;
  53. var updatetree = MochiKit.Base.updatetree;
  54. var bind = MochiKit.Base.bind;
  55. var clone = MochiKit.Base.clone;
  56. var win = window;
  57. var uid = "_MochiKit_LoggingPane";
  58. if (typeof(MochiKit.DOM) != "undefined") {
  59. win = MochiKit.DOM.currentWindow();
  60. }
  61. if (!inline) {
  62. // name the popup with the base URL for uniqueness
  63. var url = win.location.href.split("?")[0].replace(/[:\/.><&-]/g, "_");
  64. var name = uid + "_" + url;
  65. var nwin = win.open("", name, "dependent,resizable,height=200");
  66. if (!nwin) {
  67. alert("Not able to open debugging window due to pop-up blocking.");
  68. return undefined;
  69. }
  70. nwin.document.write(
  71. '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
  72. + '"http://www.w3.org/TR/html4/loose.dtd">'
  73. + '<html><head><title>[MochiKit.LoggingPane]</title></head>'
  74. + '<body></body></html>'
  75. );
  76. nwin.document.close();
  77. nwin.document.title += ' ' + win.document.title;
  78. win = nwin;
  79. }
  80. var doc = win.document;
  81. this.doc = doc;
  82. // Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
  83. var debugPane = doc.getElementById(uid);
  84. var existing_pane = !!debugPane;
  85. if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
  86. debugPane.loggingPane.logger = this.logger;
  87. debugPane.loggingPane.buildAndApplyFilter();
  88. return debugPane.loggingPane;
  89. }
  90. if (existing_pane) {
  91. // clear any existing contents
  92. var child;
  93. while ((child = debugPane.firstChild)) {
  94. debugPane.removeChild(child);
  95. }
  96. } else {
  97. debugPane = doc.createElement("div");
  98. debugPane.id = uid;
  99. }
  100. debugPane.loggingPane = this;
  101. var levelFilterField = doc.createElement("input");
  102. var infoFilterField = doc.createElement("input");
  103. var filterButton = doc.createElement("button");
  104. var loadButton = doc.createElement("button");
  105. var clearButton = doc.createElement("button");
  106. var closeButton = doc.createElement("button");
  107. var logPaneArea = doc.createElement("div");
  108. var logPane = doc.createElement("div");
  109. /* Set up the functions */
  110. var listenerId = uid + "_Listener";
  111. this.colorTable = clone(this.colorTable);
  112. var messages = [];
  113. var messageFilter = null;
  114. var messageLevel = function (msg) {
  115. var level = msg.level;
  116. if (typeof(level) == "number") {
  117. level = MochiKit.Logging.LogLevel[level];
  118. }
  119. return level;
  120. };
  121. var messageText = function (msg) {
  122. return msg.info.join(" ");
  123. };
  124. var addMessageText = bind(function (msg) {
  125. var level = messageLevel(msg);
  126. var text = messageText(msg);
  127. var c = this.colorTable[level];
  128. var p = doc.createElement("span");
  129. p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
  130. p.style.cssText = "margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: " + c;
  131. p.appendChild(doc.createTextNode(level + ": " + text));
  132. logPane.appendChild(p);
  133. logPane.appendChild(doc.createElement("br"));
  134. if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
  135. logPaneArea.scrollTop = 0;
  136. } else {
  137. logPaneArea.scrollTop = logPaneArea.scrollHeight;
  138. }
  139. }, this);
  140. var addMessage = function (msg) {
  141. messages[messages.length] = msg;
  142. addMessageText(msg);
  143. };
  144. var buildMessageFilter = function () {
  145. var levelre, infore;
  146. try {
  147. /* Catch any exceptions that might arise due to invalid regexes */
  148. levelre = new RegExp(levelFilterField.value);
  149. infore = new RegExp(infoFilterField.value);
  150. } catch(e) {
  151. /* If there was an error with the regexes, do no filtering */
  152. logDebug("Error in filter regex: " + e.message);
  153. return null;
  154. }
  155. return function (msg) {
  156. return (
  157. levelre.test(messageLevel(msg)) &&
  158. infore.test(messageText(msg))
  159. );
  160. };
  161. };
  162. var clearMessagePane = function () {
  163. while (logPane.firstChild) {
  164. logPane.removeChild(logPane.firstChild);
  165. }
  166. };
  167. var clearMessages = function () {
  168. messages = [];
  169. clearMessagePane();
  170. };
  171. var closePane = bind(function () {
  172. if (this.closed) {
  173. return;
  174. }
  175. this.closed = true;
  176. if (MochiKit.LoggingPane._loggingPane == this) {
  177. MochiKit.LoggingPane._loggingPane = null;
  178. }
  179. this.logger.removeListener(listenerId);
  180. debugPane.loggingPane = null;
  181. if (inline) {
  182. debugPane.parentNode.removeChild(debugPane);
  183. } else {
  184. this.win.close();
  185. }
  186. }, this);
  187. var filterMessages = function () {
  188. clearMessagePane();
  189. for (var i = 0; i < messages.length; i++) {
  190. var msg = messages[i];
  191. if (messageFilter === null || messageFilter(msg)) {
  192. addMessageText(msg);
  193. }
  194. }
  195. };
  196. this.buildAndApplyFilter = function () {
  197. messageFilter = buildMessageFilter();
  198. filterMessages();
  199. this.logger.removeListener(listenerId);
  200. this.logger.addListener(listenerId, messageFilter, addMessage);
  201. };
  202. var loadMessages = bind(function () {
  203. messages = this.logger.getMessages();
  204. filterMessages();
  205. }, this);
  206. var filterOnEnter = bind(function (event) {
  207. event = event || window.event;
  208. key = event.which || event.keyCode;
  209. if (key == 13) {
  210. this.buildAndApplyFilter();
  211. }
  212. }, this);
  213. /* Create the debug pane */
  214. var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
  215. if (inline) {
  216. style += "; height: 10em; border-top: 2px solid black";
  217. } else {
  218. style += "; height: 100%;";
  219. }
  220. debugPane.style.cssText = style;
  221. if (!existing_pane) {
  222. doc.body.appendChild(debugPane);
  223. }
  224. /* Create the filter fields */
  225. style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
  226. updatetree(levelFilterField, {
  227. "value": "FATAL|ERROR|WARNING|INFO|DEBUG",
  228. "onkeypress": filterOnEnter,
  229. "style": style
  230. });
  231. debugPane.appendChild(levelFilterField);
  232. updatetree(infoFilterField, {
  233. "value": ".*",
  234. "onkeypress": filterOnEnter,
  235. "style": style
  236. });
  237. debugPane.appendChild(infoFilterField);
  238. /* Create the buttons */
  239. style = "width: 8%; display:inline; font: " + this.logFont;
  240. filterButton.appendChild(doc.createTextNode("Filter"));
  241. filterButton.onclick = bind("buildAndApplyFilter", this);
  242. filterButton.style.cssText = style;
  243. debugPane.appendChild(filterButton);
  244. loadButton.appendChild(doc.createTextNode("Load"));
  245. loadButton.onclick = loadMessages;
  246. loadButton.style.cssText = style;
  247. debugPane.appendChild(loadButton);
  248. clearButton.appendChild(doc.createTextNode("Clear"));
  249. clearButton.onclick = clearMessages;
  250. clearButton.style.cssText = style;
  251. debugPane.appendChild(clearButton);
  252. closeButton.appendChild(doc.createTextNode("Close"));
  253. closeButton.onclick = closePane;
  254. closeButton.style.cssText = style;
  255. debugPane.appendChild(closeButton);
  256. /* Create the logging pane */
  257. logPaneArea.style.cssText = "overflow: auto; width: 100%";
  258. logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
  259. logPaneArea.appendChild(logPane);
  260. debugPane.appendChild(logPaneArea);
  261. this.buildAndApplyFilter();
  262. loadMessages();
  263. if (inline) {
  264. this.win = undefined;
  265. } else {
  266. this.win = win;
  267. }
  268. this.inline = inline;
  269. this.closePane = closePane;
  270. this.closed = false;
  271. return this;
  272. };
  273. MochiKit.LoggingPane.LoggingPane.prototype = {
  274. "logFont": "8pt Verdana,sans-serif",
  275. "colorTable": {
  276. "ERROR": "red",
  277. "FATAL": "darkred",
  278. "WARNING": "blue",
  279. "INFO": "black",
  280. "DEBUG": "green"
  281. }
  282. };
  283. MochiKit.LoggingPane.EXPORT_OK = [
  284. "LoggingPane"
  285. ];
  286. MochiKit.LoggingPane.EXPORT = [
  287. "createLoggingPane"
  288. ];
  289. MochiKit.LoggingPane.__new__ = function () {
  290. this.EXPORT_TAGS = {
  291. ":common": this.EXPORT,
  292. ":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
  293. };
  294. MochiKit.Base.nameFunctions(this);
  295. MochiKit.LoggingPane._loggingPane = null;
  296. };
  297. MochiKit.LoggingPane.__new__();
  298. MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);