/*
** InkWeb Debugger - help the development with InkWeb.
**
** Copyright (C) 2009 Aurelio A. Heckert, aurium (a) gmail dot com
**
** ********* Bugs and New Fetures *************************************
** If you found any bug on this script or if you want to propose a
** new feature, please report it in the inkscape bug tracker
** https://bugs.launchpad.net/inkscape/+filebug
** and assign that to Aurium.
** ********************************************************************
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published
** by the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program. If not, see .
**
** ********************************************************************
**
** This script extends InkWeb with methods like log() and viewProperties().
** So, you must to call this script after the inkweb.js load.
*/
InkWeb.debugVersion = 0.1;
// Prepare InkWeb Debug:
(function (bli, xyz) {
// Add logging calls to all InkWeb methods:
for ( var att in InkWeb ) {
if ( typeof(InkWeb[att]) == "function" ) {
var code = InkWeb[att].toString()
beforeCode = 'this.log(this.__callMethodInfo("'+att+'", arguments));\ntry {';
afterCode = '} catch(e) { this.log( e, "Ups... There is a problem in InkWeb.'+att+'()" ) }';
code = code
.replace( /^(function [^{]+[{])/, "$1\n"+ beforeCode +"\n" )
.replace( /[}]$/, ";\n"+ afterCode +"\n}" );
eval( "InkWeb."+att+" = "+ code );
//alert( InkWeb[att] )
}
}
})(123,456);
InkWeb.__callMethodInfo = function (funcName, arg) {
var func = arg.callee;
var str = 'Called InkWeb.'+funcName+'() with:'
if ( ! func.argList ) {
func.argList = func.toString()
.replace( /^function [^(]*\(([^)]*)\)(.|\s)*$/, "$1" )
.split( /,\s*/ );
}
for ( var a,i=0; a=func.argList[i]; i++ ) {
str += "\n"+ a +" = "+ this.serialize( arg[i], {recursionLimit:2} );
}
return str;
}
InkWeb.copySerializeConf = function (conf) {
return {
recursionStep: conf.recursionStep,
recursionLimit: conf.recursionLimit,
showTagElements: conf.showTagElements
}
}
InkWeb.serialize = function (v, conf) {
try {
if ( ! conf ) { conf = {} }
if ( ! conf.showTagElements ) { conf.showTagElements = false }
if ( ! conf.recursionLimit ) { conf.recursionLimit = 10 }
if ( ! conf.recursionStep ) { conf.recursionStep = 0 }
if ( conf.recursionLimit == 0 ) {
return '"<>"';
}
conf.recursionLimit--;
conf.recursionStep++;
switch ( typeof(v) ) {
case "undefined":
v = "undefined";
break;
case "string":
v = '"'+ v
.replace( /\n/g, "\\n" )
.replace( /\r/g, "\\r" )
.replace( /\t/g, "\\t" )
.replace( /"/g, '"' ) +
'"';
break;
case "boolean":
case "number":
case "function":
v = v.toString();
break;
case "object":
if ( v == null ) {
v = "null";
} else {
if ( v.constructor == Array ) {
try {
v = this.__serializeArray(v, conf);
} catch(e) {
this.log( e, "InkWeb.serialize(): Forced recursion limit in" +
" recursionLimit="+ conf.recursionLimit +
" and recursionStep="+ conf.recursionStep
);
v += '"<>"'
}
} else {
// A Hash Object
if ( v.tagName && ! conf.showTagElements ) {
// Tags are not allowed.
v = '"<'+ v.tagName +' id=\\"'+ v.id +'\\">"';
} else {
// Ok, serialize this object:
try {
v = this.__serializeObject(v, conf);
} catch(e) {
this.log( e, "InkWeb.serialize(): Forced recursion limit in" +
" recursionLimit="+ conf.recursionLimit +
" and recursionStep="+ conf.recursionStep
);
v += '"<>"'
}
}
}
}
break;
default:
v = '"<>"';
}
return v;
} catch(e) {
this.log( e, "Ups... There is a problem in InkWeb.serialize()." );
}
}
InkWeb.__serializeArray = function (v, conf) {
try {
var vStr = "[ ";
var size = v.length;
for ( var i=0; i0 ) { vStr += ", " }
vStr += this.serialize(v[i], this.copySerializeConf(conf));
}
return vStr +" ]";
} catch(e) {
this.log( e, "Ups... There is a problem in InkWeb.__serializeArray()." );
}
}
InkWeb.__serializeObject = function (obj, conf) {
try {
var vStr = "{ ";
var first = true;
for ( var att in obj ) {
if ( !first ) { vStr += ", " }
vStr += this.serialize(att) +':'+
this.serialize( obj[att], this.copySerializeConf(conf) );
first = false;
}
return vStr +" }";
} catch(e) {
this.log( e, "Ups... There is a problem in InkWeb.__serializeObject()." );
}
}
// Allow log configuration:
InkWeb.mustLog = {
error: true,
warning: true,
sequence: true
};
// This will keep the log information:
InkWeb.__log__ = [];
InkWeb.log = function (type, msg) {
/* This method register what was happen with InkWeb
** ( if mustLog allows that )
**
** --- Usage ---
** this.log( <"sequence"|"warning"|"warn"|errorObject>, <"logMessage"> );
** this.log( <"logMessage"> ); // only for sequences
**
** --- Examples ---
** Sequence log:
** function foo (bar) {
** InkWeb.log( 'Call function foo with argument bar="'+bar+'"' );
**
** Warning log:
** if ( foo == bar ) {
** foo = other;
** InkWeb.log( "warn", "foo must not be bar." );
**
** Error log:
** try { ... some hard thing ... }
** catch (e) { InkWeb.log( e, "Trying to do some hard thing." ) }
*/
if ( this.mustLog ) {
if( type.constructor == ReferenceError ) {
// in a error logging the type argument is the error object.
var error = type;
type = "error";
this.addViewLogBt();
}
if( type == "warn" ) {
// that allows a little simplify in the log call.
type = "warning";
}
if( msg == undefined ) {
// that allows to log a sequence without tos say the type.
msg = type;
type = "sequence";
}
var logSize = this.__log__.length
if ( logSize > 0 &&
this.__log__[logSize-1].type == type &&
this.__log__[logSize-1].msg == msg ) {
this.__log__[logSize-1].happens++
} else {
if ( type == "error" && this.mustLog.error ) {
this.__log__[logSize] = this.__logError( error, msg )
}
if ( type == "warning" && this.mustLog.warning ) {
this.__log__[logSize] = this.__logWarning( msg )
}
if ( type == "sequence" && this.mustLog.sequence ) {
this.__log__[logSize] = this.__logSequence( msg )
}
}
}
}
InkWeb.__logError = function ( error, msg ) {
return { type:"error", date:new Date(), msg:msg, error:error, happens:1 };
}
InkWeb.__logWarning = function ( msg ) {
return { type:"warning", date:new Date(), msg:msg, happens:1 };
}
InkWeb.__logSequence = function ( msg ) {
return { type:"sequence", date:new Date(), msg:msg, happens:1 };
}
InkWeb.logToString = function (conf) {
/* Show the log in a formatted string.
** conf attributes:
** format: a string to format the log items.
** formatError: to format the error log items.
** sep: the log items separator string.
** format variables:
** $F: the item date in the format YYYY-MM-DD
** $T: the item time in the format HH:MM:SS
** $type: the log type
** $logmsg: the text argument in the log call
** $times: how much times this item happens in sequence
** $error: the error text (if this is a error item)
** $index: the position of the item in the log list
** $oddeven: return odd or even based in the index.
*/
if (!conf) { conf = {} }
if (!conf.sep) { conf.sep = "\n\n" }
if (!conf.format) { conf.format = "$F $T - $type - $logmsg - Happens $times." }
if (!conf.formatError) { conf.formatError = "$F $T - ERROR - $logmsg - Happens $times.\n$error" }
/* * * Helper * * */
function _2d(num) {
return ( ( num < 10 )? "0"+num : ""+num )
}
function _2dMonth(date) {
var m = date.getMonth() + 1;
return _2d( m )
}
var str = "";
var logSize = this.__log__.length;
if ( logSize == 0 ) {
str = "There are no errors.";
}
// View all items to mount the log string:
for ( var item,pos=0; item=this.__log__[pos]; pos++ ) {
var d = item.date;
// Add log line, converting variables:
var line = ( (item.type=="error")? conf.formatError : conf.format );
str += line
.replace( /\$index/g, pos )
.replace( /\$oddeven/g, (pos%2 == 1)? "odd" : "even" )
.replace( /\$type/g, item.type )
.replace( /\$logmsg/g, item.msg )
.replace( /\$error/g, (item.error)? item.error.message : "" )
.replace( /\$times/g, (item.happens>1)? item.happens+" times" : "one time" )
.replace( /\$F/g, d.getFullYear() +"-"+ _2dMonth(d) +"-"+ _2d(d.getDate()) )
.replace( /\$T/g, _2d(d.getHours()) +":"+ _2d(d.getMinutes()) +":"+ _2d(d.getSeconds()) )
// Add separator:
if ( pos < (logSize-1) ) { str += conf.sep }
}
return str;
}
InkWeb.addViewLogBt = function () {
var svg = document.getElementsByTagName("svg")[0];
if ( this.__viewLogBt ) {
svg.appendChild( this.__viewLogBt );
} else {
var g = this.el( "g", { onclick: "InkWeb.openLogWindow()", parent: svg } );
var rect = this.el( "rect", { x: 10, y: 10, width: 60, height: 17, ry: 5,
style: "fill:#C00; stroke:#800; stroke-width:2",
parent: g } );
var text = this.el( "text", { x: 40, y: 22, text: "View Log",
style: "fill:#FFF; font-size:10px;" +
"font-family:sans-serif;" +
"text-anchor:middle; text-align:center",
parent: g } );
this.__viewLogBt = g;
}
}
InkWeb.__openFormatedWindow = function (bodyHTML) {
var win = window.open("","_blank","width=500,height=500,scrollbars=yes");
var html =
'InkWeb' +
''+ bodyHTML +'';
win.document.write(html);
win.document.close();
return win;
}
InkWeb.openLogWindow = function () {
var html = 'InkWeb Log
\n' +
'\n' +
'
Time | Message | Happens |
---|
\n' +
this.logToString({
format: '
' +
'$T | $logmsg | $times |
',
formatError: '' +
'$T | $logmsg | $times |
\n'+
'$error |
',
sep: '\n\n'
}) +
'\n
'
var win = this.__openFormatedWindow( html );
win.document.title = "InkWeb Log"
}
InkWeb.viewProperties = function () {
// Display object properties.
this.__openFormatedWindow( "coming soon..." );
}