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