Implements a class for creating data structure view windows that popup and
are browsable across array/object properties. This is very useful for
debugging values of complex data structures which are messy to read when
printed to the output debugger window. Click on the following link to
popup a data viewer window on it's own object structure:
|
Method Summary
|
public
|
JinnDataBrowser(
)
Default constructor.
|
public
|
backup(
)
As the user drills down into the sub structures of the main data structure
being viewed, a history stack is maintained of the path taken.
|
public array
|
getWindowSpecs(
)
This function returns the default window configuration for the output
debugger window.
|
public
|
jinnit(
)
Default constructor.
|
public
|
postLoadExecute(
mixed data =null , string key =null )
This method is called automatically by JinnDynamicLoader when a new
instance of the service is created.
|
public
|
render(
)
Causes the data browser window to be rendered.
|
public
|
renderProperties(
)
Responsible for looping through each property/index of the object/array
being viewed and rendering the row in the main view table for each.
|
public
|
renderPropertyRow(
string key , mixed value )
Renders the given key/value pair as a table row in the main view table.
|
public
|
setData(
mixed data , string key =null )
Sets the data to be viewed.
|
|
Method Details
|
|
JinnDataBrowser
|
public JinnDataBrowser ( )
Since:
0.9.3
Default constructor.
|
Source Code
|
function JinnDataBrowser() { this.jinnit(); } /*
|
|
|
backup
|
public backup ( )
Since:
0.9.3
As the user drills down into the sub structures of the main data structure
being viewed, a history stack is maintained of the path taken. When this
method is called the browser view is moved one step back in the history.
|
Source Code
|
JinnDataBrowser_proto.backup = function() { if( this.stack.length ) { this.key = this.keyStack.pop(); this.data = this.stack.pop();
this.render(); } } /*
|
|
|
getWindowSpecs
|
public array getWindowSpecs ( )
Returns:
An array of window configuration settings.
Since:
0.9.3
This function returns the default window configuration for the output
debugger window. The values are the same as those defined for the
open() method of the standard DOM Window object.
|
Source Code
|
JinnDataBrowser_proto.getWindowSpecs = function() { var specs = new Array();
specs['width'] = 0.6 * this.getScreenWidth(); specs['height'] = 0.6 * this.getScreenHeight(); specs['directories'] = 'no'; specs['location'] = 'no'; specs['menubar'] = 'no'; specs['status'] = 'no'; specs['titlebar'] = 'yes'; specs['toolbar'] = 'no'; specs['scrollbars'] = 'yes';
return specs; } /*
|
|
|
jinnit
|
public jinnit ( )
Since:
0.9.3
Default constructor. Contains most of the properties that customize the
look and feel of the data browser window. If you want to change the look
and feel, just extend this class register the new class as the dataBrowser
service. make sure to add the original class to the dependency list.
|
Source Code
|
JinnDataBrowser_proto.jinnit = function() { JinnDataBrowser.superjinn.jinnit.call( this );
this.allowMultipleInstances = true;
this.key = null; this.data = null;
this.keyStack = new Array(); this.stack = new Array();
this.window = null; this.timeoutId = null; this.autoUpdate = false;
this.brief = true; this.showFunctions = false;
this.sortBy = 'key'; this.sortAscending = true;
this.denoteDescending = '(descending)'; this.denoteAscending = '(ascending)';
this.htmlTemplate = '<html>' + '<head>' + '<scr' + 'ipt type="text/javascript">' + "\n" + '<' + '!--//--' + '><' + '![' + 'CDATA[//><' + '!--' + "\n" + 'window ? (window.interJinnSkipUserJavaScript = true) : false;' + "\n" + '//--' + '><' + '!]' + ']>' + "\n" + '</' + 'script>' + '<style type="text/css">' + '<!--' + '' // ---------------------------------------------------------------- + 'body, h1, h2, h3, p, font, table, td, th, ul, ol, textarea, input, form, blockquote, select' + '{' + ' font-family: arial, helvetica, sans-serif;' + ' font-size:10px;' + '}' + '' + 'body' + '{' + ' background: #fffff4;' + ' margin-bottom: 2px;' + '}' + '' + 'h1.details' + '{' + ' color: #000000;' + ' font-size: 14px;' + ' margin-bottom: 2px;' + '}' + '' // ---------------------------------------------------------------- + 'table.layout' + '{' + ' width: 100%;' + ' padding: 5px;' + ' background: transparent;' + '}' + '' + 'table.details' + '{' + ' width: 100%;' + ' padding: 2px;' + ' background: transparent;' + '}' + '' + 'table.border' + '{' + ' width: 100%;' + ' padding: 0px;' + ' background: #554400;' + '}' + '' + 'table.data' + '{' + ' width: 100%;' + ' padding: 0px;' + ' background: #dddddd;' + '}' + '' // ---------------------------------------------------------------- + 'th.dataColumn' + '{' + ' width: 33%;' + ' background: #776622;' + ' color: #ffff00; ' + ' font-size:12px;' + ' padding: 4px;' + ' text-align: left;' + '}' + '' + 'td.dataColumn' + '{' + ' background: #ffffff;' + ' color: #000000;' + ' padding: 2px;' + ' text-align: left;' + ' white-space: nowrap;' + '}' + '' + 'td.dataColumnHighlighted' + '{' + ' background: #f0e8d6;' + ' color: #000000;' + ' padding: 2px;' + ' text-align: left;' + ' white-space: nowrap;' + '}' + '' + '.denote' + '{' + ' color: #ffffff;' + ' font-size: 10px;' + ' font-weight: bold;' + ' padding-left: 10px;' + '}' + '' + '.small' + '{' + ' font-size: 8px;' + '}' + '' + '.big' + '{' + ' font-size: 12px;' + '}' + '' + '.success' + '{' + ' color: #009900;' + '}' + '' + '.error' + '{' + ' color: #990000;' + '}' + '' // ---------------------------------------------------------------- + 'a:active' + '{' + ' color: #554400;' + ' font-size: 10px;' + ' text-decoration: none;' + '}' + 'a:focus' + '{' + ' color: #554400;' + ' font-size: 10px;' + ' text-decoration: none;' + '}' + 'a:hover' + '{' + ' color: #554400;' + ' font-size: 10px;' + ' text-decoration: none;' + '}' + 'a:link' + '{' + ' color: #554400;' + ' font-size: 10px;' + ' text-decoration: none;' + '}' + 'a:visited' + '{' + ' color: #554400;' + ' font-size: 10px;' + ' text-decoration: none;' + '}' + '' // ---------------------------------------------------------------- + 'a.action:active' + '{' + ' color: #554400;' + ' font-size: 12px;' + ' text-decoration: none;' + ' margin-bottom: 2px;' + '}' + 'a.action:focus' + '{' + ' color: #554400;' + ' font-size: 12px;' + ' text-decoration: none;' + ' margin-bottom: 2px;' + '}' + 'a.action:hover' + '{' + ' color: #554400;' + ' font-size: 12px;' + ' text-decoration: none;' + ' margin-bottom: 2px;' + '}' + 'a.action:link' + '{' + ' color: #554400;' + ' font-size: 12px;' + ' text-decoration: none;' + ' margin-bottom: 2px;' + '}' + 'a.action:visited' + '{' + ' color: #554400;' + ' font-size: 12px;' + ' text-decoration: none;' + ' margin-bottom: 2px;' + '}' + '' // ---------------------------------------------------------------- + 'a.heading:active' + '{' + ' color: #ffff00; ' + ' font-size:12px;' + ' text-decoration: none;' + '}' + 'a.heading:focus' + '{' + ' color: #ffff00; ' + ' font-size:12px;' + ' text-decoration: none;' + '}' + 'a.heading:hover' + '{' + ' color: #ffff00; ' + ' font-size:12px;' + ' text-decoration: none;' + '}' + 'a.heading:link' + '{' + ' color: #ffff00; ' + ' font-size:12px;' + ' text-decoration: none;' + '}' + 'a.heading:visited' + '{' + ' color: #ffff00; ' + ' font-size:12px;' + ' text-decoration: none;' + '}' + '' // ---------------------------------------------------------------- + 'a.details:active' + '{' + ' color: #007700;' + ' font-weight: bold;' + ' text-decoration: none;' + '}' + 'a.details:focus' + '{' + ' color: #007700;' + ' font-weight: bold;' + ' text-decoration: none;' + '}' + 'a.details:hover' + '{' + ' color: #770000;' + ' font-weight: bold;' + ' text-decoration: none;' + '}' + 'a.details:link' + '{' + ' color: #007700;' + ' font-weight: bold;' + ' text-decoration: none;' + '}' + 'a.details:visited' + '{' + ' color: #007700;' + ' font-weight: bold;' + ' text-decoration: none;' + '}' + '' // ---------------------------------------------------------------- + '-->' + '</style>' + '</head>' + '<body>' + '<div id="interJinnSkipUserJavaScript"></div>' + '<div align="center">' + '<span id="content">' + '</span>' + '</div>' + '</body>' + '</html>'; } /*
|
|
|
postLoadExecute
|
public postLoadExecute
(
|
|
mixed
|
|
data = null ,
|
|
|
string
|
|
key = null
|
)
Parameters:
data
|
- |
An optional data structure to be viewed/browsed.
|
key
|
- |
An optional key/property name that denotes the viewed property or array
index.
|
Since:
0.9.3
This method is called automatically by JinnDynamicLoader when a new
instance of the service is created. If parameters were passed to the
service retrieval function then they will be passed to this method as the
respective parameters described. If data is set then
the data browser window will automatically be opened.
|
Source Code
|
JinnDataBrowser_proto.postLoadExecute = function( data, key ) { if( this.isset( data ) ) { this.setData( data, key ); } } /*
|
|
|
render
|
public render ( )
Since:
0.9.3
Causes the data browser window to be rendered. If the window is already
opened then this causes a refresh. Generally you shouldn't need to call
this since it will be called automatically any time the data being viewed
changes.
|
Source Code
|
JinnDataBrowser_proto.render = function() { var anchorIds = new Array(); var links = new Array();
if( this.autoUpdate ) { if( this.window ) { this.window.clearTimeout( this.timeoutId ); } }
if( this.brief ) { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.brief = false; ' + 'this.jinnViewerWindow.render(); ' + 'return false;"' + '>' + 'Full Details' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; } else { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.brief = true; ' + 'this.jinnViewerWindow.render(); ' + 'return false;"' + '>' + 'Brief Details' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; }
if( this.showFunctions ) { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.showFunctions = false; ' + 'this.jinnViewerWindow.render(); ' + 'return false;"' + '>' + 'Hide Functions' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; } else { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.showFunctions = true; ' + 'this.jinnViewerWindow.render(); ' + 'return false;"' + '>' + 'Show Functions' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; }
if( 1 ) { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.render(); ' + 'return false;"' + '>' + 'Refresh' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; }
if( this.stack.length ) { var anchorId = 'id' + this.getUniqueId();
var link = '<a' + ' id="' + anchorId + '"' + ' class="action"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.backup(); ' + 'return false;"' + '>' + '<< Previous <<' + '</a>';
links[links.length] = link; anchorIds[anchorIds.length] = anchorId; }
datatype = typeof( this.data ); if( this.data === null ) { datatype = 'null'; } else if( datatype == 'object' ) { if( this.data instanceof Array ) { datatype = 'Array'; } else { datatype = this.getClassName( this.data ); } }
var title = '<table class="details" cellspacing="0">' + '<tr>' + '<td align="left">' + '<h1 class="details">' + '<pre style="margin: 0px; padding: 0px;">' + 'Viewing details for ' + (this.key != '' ? ("'" + this.key + "' => ") : '') + "'" + datatype + "'" + '</pre>' + '</h1>' + '</td>' + '</tr>' + '<tr>' + '<td align="left">' + '<pre style="margin: 0px; padding: 0px;">' + links.join( ' | ' ) + ' </pre>' + '</td>' + '</tr>' + '</table>';
var table = '<table class="layout" cellspacing="0">' + '<tr>' + '<td align="left">' + title + '<table class="border" cellspacing="0">' + '<tr>' + '<td>' + '<table id="details" class="data" cellspacing="1">';
if( typeof( this.data ) != 'object' ) { table += '<tr>' + '<th class="dataColumn">Datatype</th>' + '<th class="dataColumn">Value</th>' + '</tr>' + '<tr>' + '<td class="dataColumn">' + typeof( this.data ) + '</th>' + '<td class="dataColumn">' + this.data + '</th>' + '</tr>'; } else { var keyType = 'Property'; if( this.data instanceof Array ) { keyType = 'Index'; }
var keyTitleAppend = ''; if( this.sortBy == 'key' ) { if( this.sortAscending ) { keyTitleAppend = ' <span class="denote">' + this.denoteAscending + '</span>'; } else { keyTitleAppend = ' <span class="denote">' + this.denoteDescending + '</span>'; } }
var datatypeTitleAppend = ''; if( this.sortBy == 'datatype' ) { if( this.sortAscending ) { datatypeTitleAppend = ' <span class="denote">' + this.denoteAscending + '</span>'; } else { datatypeTitleAppend = ' <span class="denote">' + this.denoteDescending + '</span>'; } }
var idSortByKey = 'id' + this.getUniqueId(); anchorIds[anchorIds.length] = idSortByKey; var linkSortByKey = '<a id="' + idSortByKey + '" class="heading" href="#">' + keyType + keyTitleAppend + '</a>';
var idSortByDatatype = 'id' + this.getUniqueId(); anchorIds[anchorIds.length] = idSortByDatatype; var linkSortByDatatype = '<a id="' + idSortByDatatype + '" class="heading" href="#">' + 'Datatype' + datatypeTitleAppend + '</a>';
table += '<tr>'
+ '<th class="dataColumn">' + linkSortByKey + '</th>'
+ '<th class="dataColumn">' + linkSortByDatatype + '</th>'
+ '<th class="dataColumn">' + 'Value' + '</th>'
+ '</tr>'; }
table += '</table>' + '</td>' + '</tr>' + '</table>' + '</td>' + '</tr>' + '</table>';
if( this.window == null || this.window.isClosed() ) { this.window = this.getService( 'window', this.getWindowSpecs() ); this.window.open( this.htmlTemplate );
if( this.window.isOpen() ) { this.window.getWindow().jinnViewerWindow = this; } }
if( this.window.isOpen() ) { this.window.setElementInnerHtml( 'content', table ); }
for( var key in anchorIds ) { var anchor = this.window.getElement( anchorIds[key] );
if( anchor ) { anchor.jinnViewerWindow = this; } }
var anchorSortByKey = this.window.getElement( idSortByKey ); if( anchorSortByKey ) { anchorSortByKey.onclick = function() { if( this.jinnViewerWindow.sortBy == 'key' ) { this.jinnViewerWindow.sortAscending = this.jinnViewerWindow.sortAscending ? false : true; } else { this.jinnViewerWindow.sortBy = 'key'; this.jinnViewerWindow.sortAscending = true; }
this.jinnViewerWindow.render();
return false; } }
var anchorSortyByDatatype = this.window.getElement( idSortByDatatype ); if( anchorSortyByDatatype ) { anchorSortyByDatatype.onclick = function() { if( this.jinnViewerWindow.sortBy == 'datatype' ) { this.jinnViewerWindow.sortAscending = this.jinnViewerWindow.sortAscending ? false : true; } else { this.jinnViewerWindow.sortBy = 'datatype'; this.jinnViewerWindow.sortAscending = true; }
this.jinnViewerWindow.render();
return false; } }
if( typeof( this.data ) == 'object' ) { this.renderProperties(); }
this.window.scrollTo( 0, 0 ); this.window.focus();
if( this.autoUpdate ) { var timeoutFunction = function() { this.jinnViewerWindow.render(); }
this.timeoutId = this.window.setTimeout( timeoutFunction, 500 ); } } /*
|
|
|
renderProperties
|
public renderProperties ( )
Since:
0.9.3
Responsible for looping through each property/index of the object/array
being viewed and rendering the row in the main view table for each.
|
Source Code
|
JinnDataBrowser_proto.renderProperties = function() { if( typeof( this.data ) != 'object' ) { return; }
var entries = new Array(); for( var key in this.data ) { try { value = this.data[key]; } catch( e ) { value = '*** inaccessible ***'; }
var datatype = typeof( value ); if( !this.showFunctions && datatype == 'function' ) { continue; }
var entry = new Array();
entry['key'] = key; entry['datatype'] = datatype; entry['value'] = value; entry['viewer'] = this;
if( value == null ) { entry['datatype'] = 'null'; } else if( datatype == 'object' ) { if( value instanceof Array ) { entry['datatype'] = 'array'; } else { entry['datatype'] = '' + this.getClassName( value ); } }
entries[entries.length] = entry; }
var sortFunction = function( a, b ) { var modifier = a['viewer'].sortAscending ? 1 : -1;
if( a['viewer'].sortBy == 'datatype' ) { if( a['datatype'] < b['datatype'] ) { return 0 - modifier; }
if( a['datatype'] > b['datatype'] ) { return 0 + modifier; }
if( a['key'] < b['key'] ) { return -1; }
if( a['key'] > b['key'] ) { return 1; } } else { if( a['key'] < b['key'] ) { return 0 - modifier; }
if( a['key'] > b['key'] ) { return 0 + modifier; } }
return 0; }
var sorted = entries.sort( sortFunction );
for( var key in sorted ) { this.renderPropertyRow( sorted[key]['key'], sorted[key]['value'] ); } } /*
|
|
|
renderPropertyRow
|
public renderPropertyRow
(
)
Parameters:
key
|
- |
The name of the object property or array index being rendered.
|
value
|
- |
The value of the object property or array index being rendered.
|
Since:
0.9.3
Renders the given key/value pair as a table row in the main view table.
Currently it displays the name of the object property or array index, the
datatype of the value, and the value itself. If the value is an object or
an array then a link will be displayed instead allowing the user to drill
down into the object or array structure.
|
Source Code
|
JinnDataBrowser_proto.renderPropertyRow = function( key, value ) { var datatype = typeof( value );
var showDatatype = datatype; var showValue = '';
var id = 'id' + this.getUniqueId();
if( value == null ) { showDatatype = 'null'; showValue = 'null'; } else if( datatype == 'object' ) { if( value instanceof Array ) { showDatatype = 'array'; } else { showDatatype = this.getClassName( value ); }
showValue = '<a' + ' id="' + id + '"' + ' class="details"' + ' href="#"' + ' onclick="' + 'this.jinnViewerWindow.setData( ' + 'this.jinnViewerObject, this.jinnViewerKey ); ' + 'return false;"' + '>' + 'View Details' + '</a>'; } else { showValue = this.trim( '' + value ); if( showValue == '' ) { showValue = ' '; } else { if( this.brief ) { showValue = showValue.replace( /n/g, ' ' ); showValue = showValue.replace( /s+/g, ' ' );
if( showValue.length > 20 ) { showValue = showValue.substr( 0, 30 ) + '...'; } }
showValue = showValue.replace( /&/g, '&' ); showValue = showValue.replace( /</g, '<' ); showValue = showValue.replace( />/g, '>' ); showValue = '<pre>' + "\n" + showValue + "\n" + '</pre>'; } }
var table = this.window.getElement( 'details' ); if( !table ) { return; }
rowHighlighter = this.getService( 'htmlTableRow' );
var row = table.insertRow( table.rows.length ); row.highlighter = this.getService( 'htmlTableRow', row ); row.onmouseover = function() { row.highlighter.setCellClasses( 'dataColumnHighlighted' ); return true; } row.onmouseout = function() { row.highlighter.revertCellClasses(); return true; }
var cell = null;
cell = row.insertCell( row.cells.length ); cell.className = 'dataColumn'; cell.vAlign = 'top'; cell.innerHTML = key;
cell = row.insertCell( row.cells.length ); cell.className = 'dataColumn'; cell.vAlign = 'top'; cell.innerHTML = showDatatype;
cell = row.insertCell( row.cells.length ); cell.className = 'dataColumn'; cell.vAlign = 'top'; cell.innerHTML = showValue;
if( datatype == 'object' ) { var anchor = this.window.getElement( id ); if( anchor ) { anchor.jinnViewerWindow = this; anchor.jinnViewerKey = key; anchor.jinnViewerObject = value; } } } /*
|
|
|
setData
|
public setData
(
|
|
mixed
|
|
data ,
|
|
|
string
|
|
key = null
|
)
Parameters:
data
|
- |
The data structure to be viewed/browsed.
|
key
|
- |
The name of the currently viewed property or array index. This is set when
the browser drills down into sub data structures. Setting it manually is
optional.
|
Since:
0.9.3
Sets the data to be viewed. If the browser window is not currently opened
then it is opened. The browser window will automatically be updated to
reflect the change of data being viewed.
|
Source Code
|
JinnDataBrowser_proto.setData = function( data, key ) { tKey = '' + this.defaultValue( key, '' );
if( this.data != null ) {
this.keyStack.push( this.key ); this.stack.push( this.data ); }
this.key = tKey; this.data = data;
this.render(); } /*
|
|