/* * xbDebug.js * $Revision: 1.2 $ $Date: 2003/02/07 16:04:19 $ */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Netscape code. * * The Initial Developer of the Original Code is * Netscape Corporation. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): Bob Clary * * ***** END LICENSE BLOCK ***** */ /* ChangeLog: 2002-02-25: bclary - modified xbDebugTraceOject to make sure that original versions of wrapped functions were not rewrapped. This had caused an infinite loop in IE. 2002-02-07: bclary - modified xbDebug.prototype.close to not null the debug window reference. This can cause problems with Internet Explorer if the page is refreshed. These issues will be addressed at a later date. */ function xbDebug() { this.on = false; this.stack = new Array(); this.debugwindow = null; this.execprofile = new Object(); } xbDebug.prototype.push = function () { this.stack[this.stack.length] = this.on; this.on = true; } xbDebug.prototype.pop = function () { this.on = this.stack[this.stack.length - 1]; --this.stack.length; } xbDebug.prototype.open = function () { if (this.debugwindow && !this.debugwindow.closed) this.close(); this.debugwindow = window.open('about:blank', 'DEBUGWINDOW', 'height=400,width=600,resizable=yes,scrollbars=yes'); this.debugwindow.moveTo(0,0); window.focus(); this.debugwindow.document.write('xbDebug Window

Javascript Debug Window

'); } xbDebug.prototype.close = function () { if (!this.debugwindow) return; if (!this.debugwindow.closed) this.debugwindow.close(); // bc 2002-02-07, other windows may still hold a reference to this: this.debugwindow = null; } xbDebug.prototype.dump = function (msg) { if (!this.on) return; if (!this.debugwindow || this.debugwindow.closed) this.open(); this.debugwindow.document.write(msg + '
'); return; } var xbDEBUG = new xbDebug(); window.onunload = function () { xbDEBUG.close(); } function xbDebugGetFunctionName(funcref) { if (!funcref) { return ''; } if (funcref.name) return funcref.name; var name = funcref + ''; name = name.substring(name.indexOf(' ') + 1, name.indexOf('(')); funcref.name = name; if (!name) alert('name not defined'); return name; } // emulate functionref.apply for IE mac and IE win < 5.5 function xbDebugApplyFunction(funcname, funcref, thisref, argumentsref) { var rv; if (!funcref) { alert('xbDebugApplyFunction: funcref is null'); } if (typeof(funcref.apply) != 'undefined') return funcref.apply(thisref, argumentsref); var applyexpr = 'thisref.xbDebug_orig_' + funcname + '('; var i; for (i = 0; i < argumentsref.length; i++) { applyexpr += 'argumentsref[' + i + '],'; } if (argumentsref.length > 0) { applyexpr = applyexpr.substring(0, applyexpr.length - 1); } applyexpr += ')'; return eval(applyexpr); } function xbDebugCreateFunctionWrapper(scopename, funcname, precall, postcall) { var wrappedfunc; var scopeobject = eval(scopename); var funcref = scopeobject[funcname]; scopeobject['xbDebug_orig_' + funcname] = funcref; wrappedfunc = function () { var rv; precall(scopename, funcname, arguments); rv = xbDebugApplyFunction(funcname, funcref, scopeobject, arguments); postcall(scopename, funcname, arguments, rv); return rv; }; if (typeof(funcref.constructor) != 'undefined') wrappedfunc.constructor = funcref.constuctor; if (typeof(funcref.prototype) != 'undefined') wrappedfunc.prototype = funcref.prototype; scopeobject[funcname] = wrappedfunc; } function xbDebugCreateMethodWrapper(contextname, classname, methodname, precall, postcall) { var context = eval(contextname); var methodref = context[classname].prototype[methodname]; context[classname].prototype['xbDebug_orig_' + methodname] = methodref; var wrappedmethod = function () { var rv; // eval 'this' at method run time to pick up reference to the object's instance var thisref = eval('this'); // eval 'arguments' at method run time to pick up method's arguments var argsref = arguments; precall(contextname + '.' + classname, methodname, argsref); rv = xbDebugApplyFunction(methodname, methodref, thisref, argsref); postcall(contextname + '.' + classname, methodname, argsref, rv); return rv; }; return wrappedmethod; } function xbDebugPersistToString(obj) { var s = ''; if (obj == null) return 'null'; switch(typeof(obj)) { case 'number': return obj; case 'string': return '"' + obj + '"'; case 'undefined': return 'undefined'; case 'boolean': return obj + ''; } if (obj.constructor) return '[' + xbDebugGetFunctionName(obj.constructor) + ']'; return null; } function xbDebugTraceBefore(scopename, funcname, funcarguments) { var i; var s = ''; var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; if (!execprofile) execprofile = xbDEBUG.execprofile[scopename + '.' + funcname] = { started: 0, time: 0, count: 0 }; for (i = 0; i < funcarguments.length; i++) { s += xbDebugPersistToString(funcarguments[i]); if (i < funcarguments.length - 1) s += ', '; } xbDEBUG.dump('enter ' + scopename + '.' + funcname + '(' + s + ')'); execprofile.started = (new Date()).getTime(); } function xbDebugTraceAfter(scopename, funcname, funcarguments, rv) { var i; var s = ''; var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; if (!execprofile) xbDEBUG.dump('xbDebugTraceAfter: execprofile not created for ' + scopename + '.' + funcname); else if (execprofile.started == 0) xbDEBUG.dump('xbDebugTraceAfter: execprofile.started == 0 for ' + scopename + '.' + funcname); else { execprofile.time += (new Date()).getTime() - execprofile.started; execprofile.count++; execprofile.started = 0; } for (i = 0; i < funcarguments.length; i++) { s += xbDebugPersistToString(funcarguments[i]); if (i < funcarguments.length - 1) s += ', '; } xbDEBUG.dump('exit ' + scopename + '.' + funcname + '(' + s + ')==' + xbDebugPersistToString(rv)); } function xbDebugTraceFunction(scopename, funcname) { xbDebugCreateFunctionWrapper(scopename, funcname, xbDebugTraceBefore, xbDebugTraceAfter); } function xbDebugTraceObject(contextname, classname) { var classref = eval(contextname + '.' + classname); var p; var sp; if (!classref || !classref.prototype) return; for (p in classref.prototype) { sp = p + ''; if (typeof(classref.prototype[sp]) == 'function' && (sp).indexOf('xbDebug_orig') == -1) { classref.prototype[sp] = xbDebugCreateMethodWrapper(contextname, classname, sp, xbDebugTraceBefore, xbDebugTraceAfter); } } } function xbDebugDumpProfile() { var p; var execprofile; var avg; for (p in xbDEBUG.execprofile) { execprofile = xbDEBUG.execprofile[p]; avg = Math.round ( 100 * execprofile.time/execprofile.count) /100; xbDEBUG.dump('Execution profile ' + p + ' called ' + execprofile.count + ' times. Total time=' + execprofile.time + 'ms. Avg Time=' + avg + 'ms.'); } }