Files
2025-02-26 14:49:25 +07:00

351 lines
10 KiB
JavaScript

/*
* DEMO HELPERS
*/
/**
* debugData
*
* Pass me a data structure {} and I'll output all the key/value pairs - recursively
*
* @example var HTML = debugData( oElem.style, "Element.style", { keys: "top,left,width,height", recurse: true, sort: true, display: true, returnHTML: true });
*
* @param Object o_Data A JSON-style data structure
* @param String s_Title Title for dialog (optional)
* @param Hash options Pass additional options in a hash
*/
function debugData (o_Data, s_Title, options) {
options = options || {};
var
str=(s_Title||s_Title==='' ? s_Title : 'DATA')
// maintain backward compatibility with OLD 'recurseData' param
, recurse=(typeof options=='boolean' ? options : options.recurse !==false)
, keys=(options.keys?','+options.keys+',':false)
, display=options.display !==false
, html=options.returnHTML !==false
, sort=options.sort !==false
, D=[], i=0 // Array to hold data, i=counter
, hasSubKeys = false
, k, t, skip, x // loop vars
;
if (typeof o_Data != 'object') {
alert( (s_Title ? s_Title +': ' : '')+ o_Data );
return;
}
if (o_Data.jquery) {
str=s_Title+'jQuery Collection ('+ o_Data.length +')\n context="'+ o_Data.context +'"';
}
else if (o_Data.tagName && typeof o_Data.style == 'object') {
str=s_Title+o_Data.tagName;
var id = o_Data.id, cls=o_Data.className, src=o_Data.src, hrf=o_Data.href;
if (id) str+='\n id="'+ id+'"';
if (cls) str+='\n class="'+ cls+'"';
if (src) str+='\n src="'+ src+'"';
if (hrf) str+='\n href="'+ hrf+'"';
}
else {
parse(o_Data,''); // recursive parsing
if (sort && !hasSubKeys) D.sort(); // sort by keyName - but NOT if has subKeys!
if (str) str += '\n***'+ '****************************'.substr(0,str.length) +'\n';
str += D.join('\n'); // add line-breaks
}
if (display) alert(str); // display data
if (html) str=str.replace(/\n/g, ' <br>').replace(/ /g, ' &nbsp;'); // format as HTML
return str;
function parse ( data, prefix ) {
if (typeof prefix=='undefined') prefix='';
try {
$.each( data, function (key, val) {
k = prefix+key+': ';
skip = (keys && keys.indexOf(','+key+',') == -1);
if (typeof val==='function') { // FUNCTION
if (!skip) D[i++] = k +'function()';
}
else if (typeof val==='string') { // STRING
if (!skip) D[i++] = k +'"'+ val +'"';
}
else if (val===null || val===undefined || typeof val !=='object') { // NULL, UNDEFINED, NUMBER or BOOLEAN
if (!skip) D[i++] = k + val;
}
else if (debugIsArray(val)) { // ARRAY
if (!skip) {
if (val.length && typeof val[0] == "object") { // array of objects (hashs or arrays)
D[i++] = k +'{';
parse( val, prefix+' '); // RECURSE
D[i++] = prefix +'}';
}
else
D[i++] = k +'[ '+ val.toString() +' ]'; // output delimited array
}
}
else if (val.jquery) {
if (!skip) D[i++] = k +'jQuery ('+ val.length +') context="'+ val.context +'"';
}
else if (val.tagName && typeof val.style == 'object') {
var id = val.id, cls=val.className, src=val.src, hrf=val.href;
if (skip) D[i++] = k +' '+
id ? 'id="'+ id+'"' :
src ? 'src="'+ src+'"' :
hrf ? 'href="'+ hrf+'"' :
cls ? 'class="'+cls+'"' :
'';
}
else { // Object or JSON
if (!recurse || !hasKeys(val)) { // show an empty hash
if (!skip) D[i++] = k +'{ }';
}
else { // recurse into JSON hash - indent output
D[i++] = k +'{';
parse( val, prefix+' '); // RECURSE
D[i++] = prefix +'}';
}
}
});
} catch (e) {}
function hasKeys(o) {
var c=0;
for (x in o) c++;
if (!hasSubKeys) hasSubKeys = !!c;
return !!c;
}
}
};
function debugIsArray(o) { return (o && typeof o==='object' && !o.propertyIsEnumerable('length') && typeof o.length==='number'); };
function debugStackTrace (s_Title, options) {
var
callstack = []
, isCallstackPopulated = false
;
try {
i.dont.exist += 0; // doesn't exist- that's the point
} catch(e) {
if (e.stack) { // Firefox
var lines = e.stack.split('\n');
for (var i=0, len=lines.length; i<len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
callstack.push(lines[i]);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
else if (window.opera && e.message) { // Opera
var lines = e.message.split('\n');
for (var i=0, len=lines.length; i<len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
var entry = lines[i];
//Append next line also since it has the file info
if (lines[i+1]) {
entry += ' at ' + lines[i+1];
i++;
}
callstack.push(entry);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
}
if (!isCallstackPopulated) { // IE and Safari
var currentFunction = arguments.callee.caller;
while (currentFunction) {
var fn = currentFunction.toString();
var fname = fn.substring(fn.indexOf('function') + 8, fn.indexOf('')) || 'anonymous';
callstack.push(fname);
currentFunction = currentFunction.caller;
}
}
debugData( callstack, s_Title, options );
};
// this end up displaying errors when layout.showErrorMessages = false, so disable it
//if (!window.console) window.console = { log: debugData };
if (window.console) {
if (!window.console.trace)
window.console.trace = function (s_Title) {
window.console.log( debugStackTrace(s_Title, { display: false, returnHTML: false, sort: false }) );
};
// add method to output 'hash data' inside an string
window.console.data = function (o_Data) {
var A = debugIsArray( o_Data ) ? o_Data : [ o_Data ], S='', i=0, c=A.length;
for (; i<c; i++)
S += (S ? '\n' : '') +'{\n'+ debugData( A[i], '', { display: false, returnHTML: false, sort: false }) +'\n}';
return S;
};
};
/**
* timer
*
* Utility for debug timing of events
* Can track multiple timers and returns either a total time or interval from last event
* @param String timerName Name of the timer - defaults to debugTimer
* @param String action Keyword for action or return-value...
* action: 'reset' = reset; 'clear' = delete; 'total' = ms since init; 'step' or '' = ms since last event
*/
/**
* timer
*
* Utility method for timing performance
* Can track multiple timers and returns either a total time or interval from last event
*
* returns time-data: {
* start: Date Object
* , last: Date Object
* , step: 99 // time since 'last'
* , total: 99 // time since 'start'
* }
*
* USAGE SAMPLES
* =============
* timer('name'); // create/init timer
* timer('name', 'reset'); // re-init timer
* timer('name', 'clear'); // clear/remove timer
* var i = timer('name'); // how long since last timer request?
* var i = timer('name', 'total'); // how long since timer started?
*
* @param String timerName Name of the timer - defaults to debugTimer
* @param String action Keyword for action or return-value...
* @param Hash options Options to customize return data
* action: 'reset' = reset; 'clear' = delete; 'total' = ms since init; 'step' or '' = ms since last event
*/
function timer (timerName, action, options) {
var
name = timerName || 'debugTimer'
, Timer = window[ name ]
, defaults = {
returnString: true
, padNumbers: true
, timePrefix: ''
, timeSuffix: ''
}
;
// init the timer first time called
if (!Timer || action == 'reset') { // init timer
Timer = window[ name ] = {
start: new Date()
, last: new Date()
, step: 0 // time since 'last'
, total: 0 // time since 'start'
, options: $.extend({}, defaults, options)
};
}
else if (action == 'clear') { // remove timer
window[ name ] = null;
return null;
}
else { // update existing timer
Timer.step = (new Date()) - Timer.last; // time since 'last'
Timer.total = (new Date()) - Timer.start; // time since 'start'
Timer.last = new Date();
}
var
time = (action == 'total') ? Timer.total : Timer.step
, o = Timer.options // alias
;
if (o.returnString) {
time += ""; // convert integer to string
// pad time to 4 chars with underscores
if (o.padNumbers)
switch (time.length) {
case 1: time = "&ensp;&ensp;&ensp;"+ time; break;
case 2: time = "&ensp;&ensp;"+ time; break;
case 3: time = "&ensp;"+ time; break;
}
// add prefix and suffix
if (o.timePrefix || o.timeSuffix)
time = o.timePrefix + time + o.timeSuffix;
}
return time;
};
/**
* showOptions
*
* Pass a layout-options object, and the pane/key you want to display
*/
function showOptions (Layout, key, debugOpts) {
var data = Layout.options;
$.each(key.split("."), function() {
data = data[this]; // recurse through multiple key-levels
});
debugData( data, 'options.'+key, debugOpts );
};
/**
* showState
*
* Pass a layout-options object, and the pane/key you want to display
*/
function showState (Layout, key, debugOpts) {
var data = Layout.state;
$.each(key.split("."), function() {
data = data[this]; // recurse through multiple key-levels
});
debugData( data, 'state.'+key, debugOpts );
};
/**
* addThemeSwitcher
*
* Remove the cookie set by the UI Themeswitcher to reset a page to default styles
*
* Dependancies: /lib/js/themeswitchertool.js
*/
function addThemeSwitcher ( container, position ) {
var pos = { top: '10px', right: '10px', zIndex: 10 };
$('<div id="themeContainer" style="position: absolute; overflow-x: hidden;"></div>')
.css( $.extend( pos, position ) )
.appendTo( container || 'body')
.themeswitcher()
;
};
/**
* removeUITheme
*
* Remove the cookie set by the UI Themeswitcher to reset a page to default styles
*/
function removeUITheme ( cookieName, removeCookie ) {
$('link.ui-theme').remove();
$('.jquery-ui-themeswitcher-title').text( 'Switch Theme' );
if (removeCookie !== false)
$.cookie( cookieName || 'jquery-ui-theme', null );
};
function debugWindow ( content, options ) {
var defaults = {
css: {
position: 'fixed'
, top: 0
}
};
$.extend( true, (options || {}), defaults );
var $W = $('<div></div>')
.html( content.replace(/\n/g, '<br>').replace(/ /g, ' &nbsp;') ) // format as HTML
.css( options.css )
;
};