/* ** 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' + '\n' + this.logToString({ format: '' + '', formatError: '' + '\n'+ '', sep: '\n\n' }) + '\n
TimeMessageHappens
$T$logmsg$times
$T$logmsg$times
$error
' var win = this.__openFormatedWindow( html ); win.document.title = "InkWeb Log" } InkWeb.viewProperties = function () { // Display object properties. this.__openFormatedWindow( "coming soon..." ); }