3 MochiKit.LoggingPane 1.4
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
11 if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.LoggingPane');
13 dojo.require('MochiKit.Logging');
14 dojo.require('MochiKit.Base');
17 if (typeof(JSAN) != 'undefined') {
18 JSAN.use("MochiKit.Logging", []);
19 JSAN.use("MochiKit.Base", []);
23 if (typeof(MochiKit.Base) == 'undefined' || typeof(MochiKit.Logging) == 'undefined') {
27 throw "MochiKit.LoggingPane depends on MochiKit.Base and MochiKit.Logging!";
30 if (typeof(MochiKit.LoggingPane) == 'undefined') {
31 MochiKit.LoggingPane = {};
34 MochiKit.LoggingPane.NAME = "MochiKit.LoggingPane";
35 MochiKit.LoggingPane.VERSION = "1.4";
36 MochiKit.LoggingPane.__repr__ = function () {
37 return "[" + this.NAME + " " + this.VERSION + "]";
40 MochiKit.LoggingPane.toString = function () {
41 return this.__repr__();
44 /** @id MochiKit.LoggingPane.createLoggingPane */
45 MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */, windowHeight) {
46 var m = MochiKit.LoggingPane;
48 if (m._loggingPane && m._loggingPane.inline != inline) {
49 m._loggingPane.closePane();
50 m._loggingPane = null;
52 if (!m._loggingPane || m._loggingPane.closed) {
53 m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger, windowHeight);
55 return m._loggingPane;
58 /** @id MochiKit.LoggingPane.LoggingPane */
59 MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */, windowHeight) {
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;
67 var update = MochiKit.Base.update;
68 var updatetree = MochiKit.Base.updatetree;
69 var bind = MochiKit.Base.bind;
70 var clone = MochiKit.Base.clone;
72 var uid = "_MochiKit_LoggingPane";
73 if (typeof(MochiKit.DOM) != "undefined") {
74 win = MochiKit.DOM.currentWindow();
76 if(!windowHeight) windowHeight = 200;
78 // name the popup with the base URL for uniqueness
79 var url = win.location.href.split("?")[0].replace(/[#:\/.><&-]/g, "_");
80 var name = uid + "_" + url;
81 var nwin = win.open("", name, "dependent,resizable,height=" + windowHeight);
83 alert("Not able to open debugging window due to pop-up blocking.");
87 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" '
88 + '"http://www.w3.org/TR/html4/loose.dtd">'
89 + '<html><head><title>[MochiKit.LoggingPane]</title></head>'
90 + '<body></body></html>'
92 nwin.document.close();
93 nwin.document.title += ' ' + win.document.title;
96 var doc = win.document;
99 // Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
100 var debugPane = doc.getElementById(uid);
101 var existing_pane = !!debugPane;
102 if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
103 debugPane.loggingPane.logger = this.logger;
104 debugPane.loggingPane.buildAndApplyFilter();
105 return debugPane.loggingPane;
109 // clear any existing contents
111 while ((child = debugPane.firstChild)) {
112 debugPane.removeChild(child);
115 debugPane = doc.createElement("div");
118 debugPane.loggingPane = this;
119 var levelFilterField = doc.createElement("input");
120 var infoFilterField = doc.createElement("input");
121 var filterButton = doc.createElement("button");
122 var loadButton = doc.createElement("button");
123 var clearButton = doc.createElement("button");
124 var closeButton = doc.createElement("button");
125 var logPaneArea = doc.createElement("div");
126 var logPane = doc.createElement("div");
128 /* Set up the functions */
129 var listenerId = uid + "_Listener";
130 this.colorTable = clone(this.colorTable);
132 var messageFilter = null;
134 /** @id MochiKit.LoggingPane.messageLevel */
135 var messageLevel = function (msg) {
136 var level = msg.level;
137 if (typeof(level) == "number") {
138 level = MochiKit.Logging.LogLevel[level];
143 /** @id MochiKit.LoggingPane.messageText */
144 var messageText = function (msg) {
145 return msg.info.join(" ");
148 /** @id MochiKit.LoggingPane.addMessageText */
149 var addMessageText = bind(function (msg) {
150 var level = messageLevel(msg);
151 var text = messageText(msg);
152 var c = this.colorTable[level];
153 var p = doc.createElement("span");
154 p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
155 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;
156 p.appendChild(doc.createTextNode(level + ": " + text));
157 logPane.appendChild(p);
158 logPane.appendChild(doc.createElement("br"));
159 if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
160 logPaneArea.scrollTop = 0;
162 logPaneArea.scrollTop = logPaneArea.scrollHeight;
166 /** @id MochiKit.LoggingPane.addMessage */
167 var addMessage = function (msg) {
168 messages[messages.length] = msg;
172 /** @id MochiKit.LoggingPane.buildMessageFilter */
173 var buildMessageFilter = function () {
176 /* Catch any exceptions that might arise due to invalid regexes */
177 levelre = new RegExp(levelFilterField.value);
178 infore = new RegExp(infoFilterField.value);
180 /* If there was an error with the regexes, do no filtering */
181 logDebug("Error in filter regex: " + e.message);
185 return function (msg) {
187 levelre.test(messageLevel(msg)) &&
188 infore.test(messageText(msg))
193 /** @id MochiKit.LoggingPane.clearMessagePane */
194 var clearMessagePane = function () {
195 while (logPane.firstChild) {
196 logPane.removeChild(logPane.firstChild);
200 /** @id MochiKit.LoggingPane.clearMessages */
201 var clearMessages = function () {
206 /** @id MochiKit.LoggingPane.closePane */
207 var closePane = bind(function () {
212 if (MochiKit.LoggingPane._loggingPane == this) {
213 MochiKit.LoggingPane._loggingPane = null;
215 this.logger.removeListener(listenerId);
218 debugPane.loggingPane = null;
219 } catch(e) { logFatal("Bookmarklet was closed incorrectly."); }
221 debugPane.parentNode.removeChild(debugPane);
228 /** @id MochiKit.LoggingPane.filterMessages */
229 var filterMessages = function () {
232 for (var i = 0; i < messages.length; i++) {
233 var msg = messages[i];
234 if (messageFilter === null || messageFilter(msg)) {
240 this.buildAndApplyFilter = function () {
241 messageFilter = buildMessageFilter();
245 this.logger.removeListener(listenerId);
246 this.logger.addListener(listenerId, messageFilter, addMessage);
250 /** @id MochiKit.LoggingPane.loadMessages */
251 var loadMessages = bind(function () {
252 messages = this.logger.getMessages();
256 /** @id MochiKit.LoggingPane.filterOnEnter */
257 var filterOnEnter = bind(function (event) {
258 event = event || window.event;
259 key = event.which || event.keyCode;
261 this.buildAndApplyFilter();
265 /* Create the debug pane */
266 var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
268 style += "; height: 10em; border-top: 2px solid black";
270 style += "; height: 98%; top:0px;"; //100%, top-alignment causes the bottom line to be partially hidden --ccarpita
272 debugPane.style.cssText = style;
274 if (!existing_pane) {
275 doc.body.appendChild(debugPane);
278 /* Create the filter fields */
279 style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
281 updatetree(levelFilterField, {
282 "value": "FATAL|ERROR|WARNING|INFO|DEBUG",
283 "onkeypress": filterOnEnter,
286 debugPane.appendChild(levelFilterField);
288 updatetree(infoFilterField, {
290 "onkeypress": filterOnEnter,
293 debugPane.appendChild(infoFilterField);
295 /* Create the buttons */
296 style = "width: 8%; display:inline; font: " + this.logFont;
298 filterButton.appendChild(doc.createTextNode("Filter"));
299 filterButton.onclick = bind("buildAndApplyFilter", this);
300 filterButton.style.cssText = style;
301 debugPane.appendChild(filterButton);
303 loadButton.appendChild(doc.createTextNode("Load"));
304 loadButton.onclick = loadMessages;
305 loadButton.style.cssText = style;
306 debugPane.appendChild(loadButton);
308 clearButton.appendChild(doc.createTextNode("Clear"));
309 clearButton.onclick = clearMessages;
310 clearButton.style.cssText = style;
311 debugPane.appendChild(clearButton);
313 closeButton.appendChild(doc.createTextNode("Close"));
314 closeButton.onclick = closePane;
315 closeButton.style.cssText = style;
316 debugPane.appendChild(closeButton);
318 /* Create the logging pane */
319 logPaneArea.style.cssText = "overflow: auto; width: 100%";
320 logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
322 logPaneArea.appendChild(logPane);
323 debugPane.appendChild(logPaneArea);
325 this.buildAndApplyFilter();
329 this.win = undefined;
333 this.inline = inline;
334 this.closePane = closePane;
341 MochiKit.LoggingPane.LoggingPane.prototype = {
342 "logFont": "8pt Verdana,sans-serif",
353 MochiKit.LoggingPane.EXPORT_OK = [
357 MochiKit.LoggingPane.EXPORT = [
361 MochiKit.LoggingPane.__new__ = function () {
363 ":common": this.EXPORT,
364 ":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
367 MochiKit.Base.nameFunctions(this);
369 MochiKit.LoggingPane._loggingPane = null;
373 MochiKit.LoggingPane.__new__();
375 MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);