I found a solution (requires jquery) somehwere on the Web but it does not work in most browsers.
I changed it and it works in Firefox (Mac, Linux. Android), Chrome (Mac, Linux. Android) and Safari and other Android webkit browsers.
Just write the following code to a file called e.g. debug.js and include it after the inclusion of 'jquery.js' in the <head> section of your webpage and it will work after the page has loaded (document.ready). I still have to find out to allow debugging before everything is loaded (e.g. only the <head>...</head> ).
The webpage has to be called with ?d=1 in the URL and when using Safari ?d=1s as I cannot make a distinction between Safari and another Webkit browser in the user agent and Safari has a different behavior in line number and file name handling than other Webkit browsers.
The function p_r(expression) logs to the window of the id #js_debug and to the console (if opened) with the file name and line number.
var g_d = null;
function sortObj(theObj)
{
var sortable = [];
for (var i in theObj) {
sortable.push(i);
}
sortable.sort();
var copy = new Object;
for (var i in sortable) {
var ind = sortable[i];
copy[ind] = theObj[ind];
}
return copy;
}
function p_r(s, comment, level)
{
if (!g_d) return;
var res = s;
var pre = new Array(""," " , " ", " ", " ");
if (comment) comment += ' : ';
if (arguments.length<2) comment='';
if (arguments.length<3) level = 0;
// if (console) console.log(s);
if (typeof(s) == 'object') {
var copy = sortObj(s);
comment += '\n';
res = '[object]\n';
if (level < 2) {
for (var i in copy) {
if (typeof(copy[i]) != "function")
res += pre[level] + (i) + " : " + p_r(copy[i], '', level+1) + " : " + typeof(copy[i]) + "\n";
}
res += pre[level] + "[/object]\n";
}
}
else if (typeof(s) == 'function')
res = 'function';
else if (typeof(s) != 'string')
res = '' + s;
res = res.replace(/&/g, '&');
res = res.replace(/\x3C/g, '<');
res = res.replace(/>/g, '>');
if (level == 0) {
window.LOG=res;
console.log(window.LOG + comment + res);
g_d.innerHTML += (window.LOG + comment + res + '\n');
}
return res;
}
if (location.href.match(/d\=[1-9]/)) {
$(document).ready(function() {
$("body").prepend("<div id=\"js_debugclick\" onclick=\"$('#js_debug').toggle();\">JS DEBUG</div>\
<pre onclick=\"$('#js_debug').toggle();\" id='js_debug'></pre>\
");
$("head").append("<style type=\"text/css\">\
pre#js_debug {\
border: solid black 1px; background-color: #1CF; color: #000; display:none; position:absolute; top: 20px;\
font-family: Lucida Console, monospace; font-size: 9pt; height: 400px; overflow:scroll; width:100%;\
z-index:100;\
} \
#js_debugclick { \
color:red; font-weight:bold; \
} \
</style>\
");
g_d = document.getElementById('js_debug');
});
var __moredebug = location.href.match(/d\=[2-9]/);
var __issafari = /safari/.test(navigator.userAgent.toLowerCase()) && location.href.match(/d\=[1-9]s/);
var __iswebkit = /webkit/.test(navigator.userAgent.toLowerCase());
var __isopera = /opera/.test(navigator.userAgent.toLowerCase());
if (__moredebug) console.log(__issafari, __iswebkit);
/*@const*/ //for closure-compiler
//DEBUG=2 // 0=off, 1=msg:file:line:column, 2=msg:stack-trace
/*@const @constructor*/
Object.defineProperty(window,'__stack__',{get:function(){
try{i.dont.exist()}catch(e){
if (__moredebug) var x=e.stack.split(":"); for (i in x){console.log(i,x[i]);}
// console.log(e.stack.split(":")[13].match(/(\d+)/)[1]);
return e.stack.split(":")}
}})
/*@const @constructor*/
Object.defineProperty(window,'__file__',{get:function(){
var s=__stack__,l=s.length
var f= __issafari ? s[9] : (__isopera ? s[12] : (__iswebkit ? s[14] : s[9]));
return f.replace(/^.+?\/([^\/]+?)\?.+?$/, "$1");
}})
/*@const @constructor*/
Object.defineProperty(window,'__line__',{get:function(){
var s=__stack__,l=s.length
return __issafari ? s[10].match(/(\d+)/)[1] :(__isopera ? s[13].match(/(\d+)/)[1] : (__iswebkit ? s[15] : s[10].replace(/\n/, " ").replace(/(\d+).+?$/, "$1")));
}})
/*@const @constructor*/
Object.defineProperty(window,'__col__',{get:function(){
var s=__stack__,l=s.length
return (isNaN(s[l-2]))?"NA":s[l-1]
}})
/*@const @constructor*/
Object.defineProperty(window,'LOG',{
get:function(){return out},
set:function(msg){if(0)out=msg+"\t-\t"+__stack__
else out=__file__+" "+__line__+": ";
}
})
}//end if(DEBUG)