LoggingPane.js 11 KB

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