jsTracer.js
Summary
No overview generated for 'jsTracer.js'
Class Summary
|
jsTracer |
jsTracer serves as a simple but powerful JavaScript logging, tracing and debugging tool. |
Method Summary
|
static void
|
trace(message, messageType, css)
A simple trace function added for ease of use.
|
if (typeof(CSSStyleSheet) != "undefined")
{
window.isMoz = true;
CSSStyleSheet.prototype.__defineGetter__("rules", function()
{
return this.cssRules;
});
CSSStyleSheet.prototype.addRule = function(selector, style, index)
{
this.insertRule(selector + " { " + style + " }", index);
}
}
function jsTracer()
{
if (!jsTracer.prototype.defined)
{
jsTracer.prototype.MessageType =
{
INFO: 1,
WARNING: 2,
ERROR: 3
}
jsTracer.prototype.addEventListener = function(obj, eventName, listener)
{
if (obj.addEventListener)
obj.addEventListener(eventName, listener, false);
else if (obj.attachEvent)
obj.attachEvent("on" + eventName, listener);
}
jsTracer.prototype.removeEventListener = function(obj, eventName, listener)
{
if (obj.removeEventListener)
obj.removeEventListener(eventName, listener, false);
else if (obj.detachEvent)
obj.detachEvent("on" + eventName, listener);
}
jsTracer.prototype.changeView = function(messageType)
{
var css = _master.getTracerStyleSheet();
var rules = css.cssRules || css.rules;
var info, warning, error;
for (index in rules)
{
var rule = rules[index];
if (info && warning && error) break;
switch (rule.selectorText)
{
case ".info":
info = rule;
break;
case ".warning":
warning = rule;
break;
case ".error":
error = rule;
break;
}
}
switch(messageType)
{
case MessageType.INFO:
info.style.display = "block";
error.style.display = "none";
warning.style.display = "none";
break;
case MessageType.ERROR:
info.style.display = "none";
error.style.display = "block";
warning.style.display = "none";
break;
case MessageType.WARNING:
info.style.display = "none";
error.style.display = "none";
warning.style.display = "block";
break;
default:
info.style.display = "block";
error.style.display = "block";
warning.style.display = "block";
break;
}
}
jsTracer.prototype.highlightMessage = function(message, color)
{
if (message && color)
{
message.id = "messageHighlighted";
message.style.border = "solid 3px " + color;
message.highlightColor = color;
message.highlighted = true;
}
}
jsTracer.prototype.removeHighlight = function(message)
{
message.style.border = "none";
message.style.borderBottom = "solid 1px #D0D0D2";
message.id = "message";
message.highlighted = false;
}
jsTracer.prototype.messageClicked = function(event)
{
event = event || window.event;
var element = event.target || event.srcElement;
if (element.highlighted)
{
jstracer.removeHighlight(element);
}
else
{
var color = element.highlightColor || "blue";
jstracer.highlightMessage(element, color);
}
}
jsTracer.prototype.showContextMenu = function(event)
{
var doc = _master.jsTracerFrame.contentWindow.document;
event = event || window.event;
var element = event.target || event.srcElement;
if (event.preventDefault) event.preventDefault();
if (_master.hideContextMenuTimer)
{
_master.getWindow().clearTimeout(_master.hideContextMenuTimer);
_master.hideContextMenuTimer = null;
return false;
}
if (!_master.contextMenu || !_master.contextMenu.visible)
{
_master.contextElement = element;
if (!_master.contextMenu)
{
var contextMenu = doc.createElement("div");
contextMenu.id = "contextMenu";
_master.addEventListener(contextMenu, "mouseover", jstracer.showContextMenu);
_master.addEventListener(contextMenu, "mouseout", jstracer.hideContextMenu);
var colors = ["Red", "Blue", "Yellow"];
for (var i = 0; i < colors.length; i++)
{
var color = colors[i];
var item = doc.createElement("a");
item.setAttribute("color", color);
item.innerHTML = "Highlight <span style='color:" + color + "' color='" + color + "'>" + color + "</span>";
_master.addEventListener(item, "click", jstracer.hideContextMenuImmediate);
_master.addEventListener(item, "click", jstracer.highlightMessageClicked);
_master.addEventListener(item, "mouseover", jstracer.showContextMenu);
contextMenu.appendChild(item);
}
contextMenu.appendChild(doc.createElement("hr"));
var item = doc.createElement("a");
item.innerHTML = "Remove Highlight";
_master.addEventListener(item, "click", jstracer.hideContextMenuImmediate);
_master.addEventListener(item, "click", jstracer.removeHighlightClicked);
_master.addEventListener(item, "mouseover", jstracer.showContextMenu);
contextMenu.appendChild(item);
if (element.stack && element.stack != "null" && element.stack != "undefined")
{
contextMenu.appendChild(doc.createElement("hr"));
item = doc.createElement("a");
item.innerHTML = "View Stack Trace";
_master.addEventListener(item, "click", jstracer.hideContextMenuImmediate);
_master.addEventListener(item, "click", jstracer.showStackTrace);
_master.addEventListener(item, "mouseover", jstracer.showContextMenu);
contextMenu.appendChild(item);
}
doc.body.appendChild(contextMenu);
_master.contextMenu = contextMenu;
}
_master.contextMenu.style.visibility = "hidden";
_master.contextMenu.style.display = "block";
_master.contextMenu.visible = true;
var screenTop = event.screenY - event.clientY;
var screenLeft = event.screenX - event.clientX;
var height = _master.contextMenu.offsetHeight;
var width = _master.contextMenu.offsetWidth;
var top = (event.screenY - screenTop) - 5;
var left = (event.screenX - screenLeft) - 5;
var topDiff = (top + height) - doc.body.clientHeight;
var leftDiff = (left + width) - doc.body.clientWidth;
if (top < 5) top = 5;
else if (topDiff >= 0) top = top - (topDiff + 5);
if (left < 5) left = 5;
else if (leftDiff >= 0) left = left - (leftDiff + 5);
_master.contextMenu.style.top = top + doc.body.scrollTop;
_master.contextMenu.style.left = left + doc.body.scrollLeft;
jstracer.setViewerOpacity(4);
_master.contextMenu.style.visibility = "visible";
}
return false;
}
jsTracer.prototype.setViewerOpacity = function(opacity)
{
var doc = _master.jsTracerFrame.contentWindow.document;
var header = jstracer.getHeader();
var messages = jstracer.getMessageContainer()
if (opacity != 10)
{
if (window.isMoz)
{
header.style.opacity = "." + opacity;
messages.style.opacity = "." + opacity;
}
else
{
header.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + opacity + "0)";
messages.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + opacity + "0)";
}
}
else
{
header.style.opacity = "";
messages.style.opacity = "";
messages.style.filter = "";
messages.style.filter = "";
}
}
jsTracer.prototype.removeContextMenu = function()
{
var doc = _master.jsTracerFrame.contentWindow.document;
var menu = doc.getElementById("contextMenu");
if (menu) doc.body.removeChild(menu);
_master.contextMenu = null;
}
jsTracer.prototype.hideContextMenuImmediate = function(event)
{
var doc = _master.jsTracerFrame.contentWindow.document;
_master.removeContextMenu();
_master.hideContextMenuTimer = null;
jstracer.setViewerOpacity(10);
}
jsTracer.prototype.hideContextMenu = function(event)
{
_master.hideContextMenuTimer = _master.getWindow().setTimeout("jstracer.hideContextMenuImmediate();", 300);
}
jsTracer.prototype.highlightMessageClicked = function(event)
{
event = event || window.event;
var element = event.target || event.srcElement;
_master.highlightMessage(_master.contextElement, element.getAttribute("color"));
}
jsTracer.prototype.removeHighlightClicked = function(event)
{
event = event || window.event;
var element = event.target || event.srcElement;
_master.removeHighlight(_master.contextElement);
}
jsTracer.prototype.getWindow = function()
{
return window;
}
jsTracer.prototype.showStackTrace = function(event)
{
event = event || window.event;
var element = event.target || event.srcElement;
if (_master.contextElement && _master.contextElement.stack)
{
var stack = unescape(_master.contextElement.stack).split("##jsTracer##");
var stackWindow = window.open("about:blank", "", "height=500,width=700,scrollbars=1,resizable=1,status=0");
var doc = stackWindow.document;
doc.open();
doc.write("<html><head><title>" + _master.contextElement.innerHTML + "</title>" +
"<style type='text/css'>" +
"body { margin:0px; }" +
"#source { font-family:verdana,sans-serif; font-size:12px; padding:15px; background-color:#ECECEC; border-bottom:solid 1px #9D9DA1; }" +
"#stackViewer * { font-size:11px; }" +
"#stackViewer .codeBlock { margin-top:10px; margin-left:10px; font-family:courier; white-space:nowrap; }" +
"#stackViewer .codeBlock .func { margin-left:10px; margin-top:10px; }" +
"#stackViewer .codeBlock .line { height:1px; font-size:1px; line-height:1px; color:#E6E6E6; background-color:#E6E6E6; margin:0px; }" +
"</style>" +
"</head><body>" +
"<div id='source'>" + _master.contextElement.innerHTML + "</div>" +
"</body></html>");
doc.close();
var stackViewer = doc.createElement("div");
stackViewer.id = "stackViewer";
stackViewer.innerHTML = "";
var funcContainer = stackViewer;
var stackCounter = stack.length;
var len = stack.length;
for (var i = 0; i < len; i++)
{
var func = _master._getFunctionHTML(stack[i]);
var codeBlock = doc.createElement("div");
codeBlock.className = "codeBlock";
var color = jstracer._getRandomRGB();
codeBlock.style.borderTop = "solid 1px " + color;
codeBlock.style.borderLeft = "solid 1px " + color;
if (i == 0) codeBlock.style.border = "none";
codeBlock.innerHTML += "<div style='background-color:" + color + ";padding-left:5px;'>" + stackCounter + ":</div><div class='func'>" + func + "</div>";
funcContainer.appendChild(codeBlock);
funcContainer = codeBlock;
stackCounter--;
}
doc.body.appendChild(stackViewer);
}
}
jsTracer.prototype._getRandomRGB = function()
{
var min = 100;
var r = Math.floor(Math.random() * (256 - min)) + min;
var g = Math.floor(Math.random() * (256 - min)) + min;
var b = Math.floor(Math.random() * (256 - min)) + min;
return "rgb(" + r + "," + g + "," + b + ")";
}
jsTracer.prototype._getFunctionHTML = function(func)
{
var funcString = escape(func);
var funcHTML = funcString.replace(/%20/g, " ");
funcHTML = funcHTML.replace(/%0A/g, "<div class='line'> </div>");
funcHTML = funcHTML.replace(/%09/g, " ");
funcHTML = unescape(funcHTML);
var keywords = ["function", "var", "this"];
for (var i in keywords)
{
funcHTML = funcHTML.replace(keywords[i], "<span style='color:blue;font-weight:bold'>" + keywords[i] + "</span>");
}
return funcHTML;
}
jsTracer.prototype.write = function(message, messageType, css)
{
var stack = null;
if (_master._stackTraceEnabled)
{
stack = [];
var func = this.write.caller;
while(func)
{
stack.push(func);
func = func.caller;
}
stack = escape(stack.join("##jsTracer##"));
}
messageType = messageType || MessageType.INFO;
css = css == null ? "" : css;
message = escape(message);
if (_master.initialized)
setTimeout("jstracer._write('" + message + "'," + messageType + ",'" + css + "','" + stack + "');", 10);
else
_master._queue.push([message, messageType, css, stack]);
}
jsTracer.prototype._write = function(message, messageType, css, stack)
{
if (_master.enabled)
{
if (_master._queue)
{
var n = null;
while (_master._queue.length)
{
var item = _master._queue.shift();
_master._writeReal(item[0], item[1], item[2], item[3]);
}
_master._queue = null;
}
_master._writeReal(message, messageType, css, stack);
}
}
jsTracer.prototype._writeReal = function(message, messageType, css, stack)
{
message = unescape(message) + "";
_master.count++;
message = _master.count + ": " + _master.prepMessage(message);
var el = _master.jsTracerFrame.contentWindow.document.createElement("div");
el.innerHTML = message;
el.stack = stack;
_master.addEventListener(el, "click", this.messageClicked);
_master.addEventListener(el, "contextmenu", this.showContextMenu);
switch(messageType)
{
case MessageType.WARNING:
el.className = "warning";
break;
case MessageType.ERROR:
el.className = "error";
break;
default:
el.className = "info";
break;
}
if (css)
{
var rules = css.split(";");
var len = rules.length;
for (var i = 0; i < len; i++)
{
try
{
var rule = rules[i].split(":");
var selector = rule[0];
var value = rule[1];
if (rule && rule.length == 2)
{
if (el.style.setProperty)
el.style.setProperty(selector, value, "");
else
{
var fix = selector.split("-");
var scriptSelector = fix[0];
if (fix.length > 1)
{
for (var x = 1; x < fix.length; fix++)
scriptSelector = scriptSelector + fix[x].substring(0, 1).toUpperCase() + fix[x].substring(1);
}
el.style[scriptSelector] = value;
}
}
}
catch(ex)
{
_master.write("jsTracer: " + ex.message, MessageType.ERROR);
}
}
}
var messageContainer = this.getMessageContainer();
messageContainer.insertBefore(el, messageContainer.firstChild);
}
jsTracer.prototype.clear = function()
{
_master.count = 0;
if (_master.length > 0)
_master.splice(_master[0], _master.length);
var messageContainer = this.getMessageContainer();
messageContainer.innerHTML = "";
messageContainer.appendChild(messageContainer.ownerDocument.createTextNode(""));
}
jsTracer.prototype.close = function(event)
{
_master.enabled = false;
_master.frameset.removeChild(_master.jsTracerFrame);
_master.frameset.cols = "*";
}
jsTracer.prototype.filterChanged = function(event)
{
event = event || window.event;
var target = event.target || event.srcElement;
var messageType = Number(target.options[target.selectedIndex].value);
_master.changeView(messageType);
}
jsTracer.prototype.toggleEnable = function(event)
{
vent = event || window.event;
var target = event.target || event.srcElement;
if (_master.enabled)
{
target.value = "Enable";
_master.enabled = false;
}
else
{
target.value = "Disable";
_master.enabled = true;
}
}
jsTracer.prototype.prepMessage = function(message)
{
message = message.replace(/</g, "<");
message = message.replace(/>/g, ">");
return message;
}
jsTracer.prototype.getTopTracer = function()
{
var tracer = this;
if (window != parent)
tracer = parent.jstracer.getTopTracer();
return tracer;
}
jsTracer.prototype.getTracerStyleSheet = function()
{
var sheet = _master.jsTracerFrame.contentWindow.document.styleSheets[0];
return sheet;
}
jsTracer.prototype.getHeader = function()
{
var messageContainer = _master.jsTracerFrame.contentWindow.document.getElementById("header");
return messageContainer;
}
jsTracer.prototype.getMessageContainer = function()
{
var messageContainer = _master.jsTracerFrame.contentWindow.document.getElementById("messageContainer");
return messageContainer;
}
jsTracer.prototype.init = function()
{
if (!this.initialized)
{
if (window == parent)
{
var checked = this._stackTraceEnabled ? " checked" : "";
this.frameset = document.createElement("frameset");
this.frameset.cols = "300,*";
this.jsTracerFrame = document.createElement("frame");
this.jsTracerFrame.name = "jsTracerFrame";
this.jsTracerFrame.id = "jsTracerFrame";
this.jsTracerFrame.scrolling = "yes";
this.frameset.appendChild(this.jsTracerFrame);
this.contentFrame = document.createElement("frame");
this.contentFrame.name = "contentFrame";
this.contentFrame.id = "contentFrame";
this.frameset.appendChild(this.contentFrame);
document.documentElement.replaceChild(this.frameset, document.body);
this.contentFrame.contentWindow.location = location;
var tracerHtml = "<html>" +
"<head>" +
"<style type='text/css'>" +
"* { font-family:verdana,sans-serif; font-size:11px; }" +
"body { margin:0px; }" +
"select { margin-right:2px; }" +
"#controls, #controls * { font-size:10px; }" +
"a { text-decoration:none; }" +
".subcopy { font-size:60%; font-weight:normal; }" +
".error { color:red; padding:5px; border-bottom:solid 1px #D0D0D2; cursor:pointer; }" +
".warning { color:#D16900; padding:5px; border-bottom:solid 1px #D0D0D2; cursor:pointer; }" +
".info { color:black; padding:5px; border-bottom:solid 1px #D0D0D2; cursor:pointer; }" +
"#header { white-space:nowrap; border-bottom:solid 1px #9D9DA1; background-color:#ECECEC; padding:5px; padding-top:2px; }" +
".logo { margin:0px 0px 2px 5px; }" +
".logo a, .logo a * { font-family:impact, tahoma, sans-serif; font-style:italic; font-size:160%; font-weight:bold; color:#0070E0; }" +
".logo a .js { color:black; font-size:110%; }" +
".logo .tagline { font-size:9px; font-style:italic; color:#A6A6A6; margin-left:5px; }" +
".g { float:right; margin:0px; padding:0px; margin-top:5px; margin-bottom:5px; }" +
"#controls { clear:both; padding:3px; background-color:#E0DFE3; border:solid 1px #99A0A3; text-align:center; }" +
"#controls table { margin-left:auto; margin-right:auto; }" +
"#controls a { color:#000; }" +
"#controls #buttons { padding:3px; margin-bottom:4px; background-color:#D1D1D7; border:solid 1px #99A0A3; }" +
"#contextMenu { padding:10px; padding-top:5px; width:190px; padding-bottom:5px; border:solid 1px #666666; position:absolute; background-color:white; z-index:999; }" +
"#contextMenu * { font-size:11px; }" +
"#contextMenu a { display:block; cursor:pointer; color:black; margin-bottom:5px; }" +
"#contextMenu a:hover { text-decoration:underline; }" +
"#contextMenu hr { height:1px; display:block; border:none; border-top:solid 1px #9D9DA1; margin-top:5px; margin-bottom:5px; width:100%; color:#9D9DA1; }" +
"</style>" +
"</head>" +
"<body>" +
"<div id='header'>" +
"<div class='logo'><a href='http://jstracer.sourceforge.net/' target='_top'><span class='js'>js</span>Tracer</a> <span class='tagline'>by Nathan Hopkins</span></div>" +
"<div id='controls'>" +
"<div id='buttons'>" +
"<input type='button' value='Disable' accesskey='e' onclick='parent.jstracer.toggleEnable(event);' />" +
"<input type='button' value='Clear' accesskey='c' onclick='parent.jstracer.clear(event);' />" +
"<input type='button' value='Close' accesskey='x' onclick='parent.jstracer.close(event);' />" +
"</div>" +
"<table border='0' cellpadding='0' cellspacing='0'><tr><td>Filter: <select id='filter' onchange='top.jstracer.filterChanged(event);'>" +
"<option value='-1'>All</option>" +
"<option value='1'>Info</option>" +
"<option value='2'>Warnings</option>" +
"<option value='3'>Errors</option>" +
"</select></td><td>" +
"<table border='0' cellpadding='0' cellspacing='0'><tr><td><input id='stack' onclick='parent.jstracer.toggleStackTrace(this);' type='checkbox' " + checked + " /></td><td><a href='javascript:document.getElementById(\"stack\").click();'>Stack Trace</a></td></tr></table></td></tr></table>" +
"</div>" +
"</div>" +
"<div id='messageContainer'><b></b></div>" +
"</body>" +
"</html>";
var doc = this.jsTracerFrame.contentWindow.document;
doc.open();
doc.write(tracerHtml);
doc.close();
}
this.initialized = true;
}
}
jsTracer.prototype.defined = true;
}
jsTracer.prototype._updateStackTraceOption = function(checked)
{
if (_master && _master.jsTracerFrame && _master.jsTracerFrame.contentWindow)
{
var doc = _master.jsTracerFrame.contentWindow.document;
var el = doc.getElementById("stack");
el.checked = checked;
}
}
jsTracer.prototype.enableStackTrace = function()
{
this._stackTraceEnabled = true;
if (this != _master)
_master.enableStackTrace();
this._updateStackTraceOption(true);
}
jsTracer.prototype.disableStackTrace = function()
{
this._stackTraceEnabled = false;
if (this != _master)
_master.disableStackTrace();
this._updateStackTraceOption(false);
}
jsTracer.prototype.toggleStackTrace = function(el)
{
if (el)
{
if (el.checked)
this.enableStackTrace();
else
this.disableStackTrace();
}
this.removeContextMenu();
}
this.count = 0;
this.maxSize = 100;
this.enabled = true;
var _master = this.getTopTracer();
this._stackTraceEnabled = false;
this._queue = [];
}
var jstracer = new jsTracer();
jstracer.addEventListener(window, "load", function(){window.jstracer.init();});
window.jstracer = jstracer;
var MessageType = jstracer.MessageType;
Documentation generated by
JSDoc on Fri Jun 23 00:24:30 2006