/*
* LICENSE AND COPYRIGHT
*
* Copyright (C) 2014 Eric Wolf ( coyocanid@gmail.com )
* This module is free software; it can be used under the terms of the artistic license
*
* Version 0.105
*/
if( ! $.yote ) {
$.yote = {
fetch_default_app: function() { return undefined; },
fetch_account: function() { return undefined; },
reinit:function() {},
_no_yote: true,
};
}
(function() {
var _after_render_functions = [];
var _compiled_templates = {};
var _ids = 0;
var _next_id = function() {
return '__ytidx_'+_ids++;
}
var _pag_list_cache = {};
var _pag_hash_cache = {};
var scratch = {}; // all context objects have a reference to this called scratch, so ctx.scratch
var _wrap_list = function( array, key ) {
return _data_wrapper( array, key );
};
var _wrap_hash = function( hash, key ) {
return _data_wrapper( hash, key, true );
};
if( $.yote._no_yote ) { // if this is a stand alone block
_wrap_hash = function() { throw new Exception( 'yote system not present: cannot wrap yote hash' ); };
_wrap_list = function() { throw new Exception( 'yote system not present: cannot wrap yote list' ); };
}
var _data_wrapper = function( struct, key, is_hash ) {
var arry = struct;
var hash = struct;
var node = is_hash ? _pag_hash_cache[ key ] : _pag_list_cache[ key ];
if( ! key || (! node && ( ! arry && ! hash ) ) ) {
if( is_hash )
throw new Exception( 'wrap hash called without ' + ( key ? 'hash' : 'key' ) );
else
throw new Exception( 'wrap list called without ' + ( key ? 'list' : 'key' ) );
}
if( ! node ) {
var start = 0;
node = {
id : _next_id(),
_start : start,
_page_size : 0,
_filter_function : undefined,
_sort_function : undefined,
_transform_function : undefined,
set_filter : function( filter_fun ) {
this._filter_function = filter_fun;
},
set_sort : function( sort_fun ) {
this._sort_function = sort_fun;
},
set_transform : function( trans_fun ) {
this._transform_function = trans_fun;
},
can_rewind:function(){
return this._start > 0;
},
can_fast_forward:function(){
return (this._start + this._page_size) < this._data_size;
},
back:function(){
this._start -= this._page_size;
if( this._start < 0 ) {
this._start = 0;
}
},
forwards:function(){
this._start += this._page_size;
if( this._start >= this._data_size ) {
this._start = this._data_size - 1;
}
},
first:function(){
this._start = 0;
},
last:function(){
this._start = this._data_size - this._page_size;
if( this._start < 0 ) {
this._start = 0;
}
},
set_size : function( newsize ) {
this._page_size = Number(newsize);
},
to_list : function() {
var ret
if( typeof this._filter_function !== 'undefined' ) {
ret = [];
for( var i=0, len = this._arry.length; i<len; i++ ) {
if( this._filter_function( i, this._arry[ i ], this._arry ) ) {
ret.push( this._arry[ i ] );
}
}
} else {
ret = this._arry.slice( 0 );
}
if( typeof this._sort_function !== 'undefined' ) {
ret = ret.sort( this._sort_function );
}
if( typeof this._start !== 'undefined' || typeof this._page_size !== 'undefined' ) {
if( typeof this._page_size !== 'undefined' )
ret = ret.slice( this._start, this._start + this._page_size );
else
ret = ret.slice( this._start );
}
return ret;
},
keys : function() {
var ret = Object.keys( this._hash );
if( typeof this._filter_function !== 'undefined' ) {
var new_ret = [];
for( var i=0, len = ret.length; i<len; i++ ) {
var k = ret[ i ];
if( this._filter_function( k, this._hash[ k ], this._hash ) )
new_ret.push( k );
}
ret = new_ret;
}
ret = ret.sort( this._sort_function );
if( typeof this._start !== 'undefined' || typeof this._page_size !== 'undefined' ) {
if( typeof this._page_size !== 'undefined' )
ret = ret.slice( this._start, this._start + this._page_size );
else
ret = ret.slice( this._start );
}
return ret;
},
to_hash : function() {
var h = this._hash;
var r = {};
var k = this.keys();
for( var i=0, len=k.length; i<len; i++ ) {
r[ k[i] ] = h[ k[i] ];
}
return r;
}
};
if( is_hash )
_pag_hash_cache[ key ] = node;
else
_pag_list_cache[ key ] = node;
} //if needs a node
if( arry ) {
node._arry = arry;
node._data_size = arry.length;
}
if( hash ) {
node._hash = hash;
node._data_size = Object.keys( hash ).length;
}
return node;
}; //_data_wrapper
var _compile_template = function( key, value ) {
key = key.trim();
// fun list = a list of ( priority, function ) couples
var fun_list = _parse_template( value, key );
// sort the indexes of the fun list with the indexes of the highest priority functions coming first
var idxs = [];
for( var i=0, len=fun_list.length; i < len; i++ ) {
idxs.push( i );
}
idxs.sort( function( a, b ) {
// lower numbers go first
return fun_list[ a ][ 0 ] - fun_list[ b ][ 0 ];
} );
//build tuples in a list [ [ positi onal idx, function, is_text, is_after_render ], ... ]
var compiled = [];
for( var i=0, len=idxs.length; i<len; i++ ) {
var idx = idxs[ i ];
var priority = fun_list[ idx ][ 0 ];
var fun_pair = fun_list[ idx ][ 1 ];
((function( item ) {
if( priority == 8 ) { //after render priority
compiled.push( [ idx, function( ctx ) { return function() { item( ctx ); } }, false, true ] );
} else if( priority == 7 ) { //raw text
compiled.push( [ idx, item, true, false ] );
} else if( priority == 3 || priority == 0 ) { //building functions, so process results again
compiled.push( [ idx, function( ctx ) {
var ret = _fill_template_direct( item( ctx ), ctx, key );
return ret;
}, false, false ] );
} else { // build with a function that returns
compiled.push( [ idx, function( ctx ) { return item( ctx ) }, false, false ] );
}
} )( fun_list[ idx ][ 1 ] ))
}
_compiled_templates[ key ] = compiled;
}; // _compile_template
var _parse_args = function( arg_txt ) {
var sing_pos = arg_txt.indexOf( "'" );
var double_pos = arg_txt.indexOf( '"' );
if( sing_pos >= 0 || double_pos >= 0 ) {
if( ( sing_pos > double_pos && double_pos >= 0 ) || sing_pos == -1 ) {
var parts = arg_txt.match( /^([^"]*)"([^"\\]*(\\.[^"\\]*)*)"([\s\S]*)/ );
} else {
parts = arg_txt.match( /^([^']*)'([^'\\]*(\\.[^'\\]*)*)'([\s\S]*)/ );
}
if( parts.length == 5 ) {
var ret;
if( parts[1].trim().length > 0 ) {
ret = parts[ 1 ].trim().split( /\s+/ );
ret.push( parts[ 2 ] );
} else {
ret = [ parts[ 2 ] ];
}
if( parts[ 4 ].trim().length > 0 ) {
var newparts = _parse_args( parts[ 4 ] );
ret.push.apply( ret, newparts );
}
return ret;
}
throw new Error( "improperly escaped string in args '" + arg_txt + "'" );
}
return arg_txt.trim().split( /\s+/ );
}; // _parse_args
var _to_function = function( str ) {
var funparts = str.match( /^\s*function\s*\(([^\),]+)[^)]*\)\s*\{([\s\S]*)\}\s*$/ );
if( funparts && funparts.length == 3 )
return new Function( 'var ' + funparts[ 1 ] + ' = arguments[0];' + funparts[ 2 ] );
// assumed to be the function without 'function( ctx )'
return new Function( 'var ctx = arguments[0];' + str );
}; //_to_function
// 0 : ???, 1 : $$$, 2 : ??, 4: $$, 5 : $, 6 : raw text, 7 : ?
var _parse_template = function( template_txt, template_name, recurse ) {
// clear out comments
//if( $.yote.templates.debug ) return;
if( ! recurse ) {
while( template_txt.indexOf( '<#' ) > -1 ) {
var parts = _template_parts( template_txt, '#', template_name );
template_txt = parts[ 0 ] + parts [ 2 ];
}
recurse = 0;
}
// function to add to template text before other tag types are processed
if( recurse < 2 && template_txt.indexOf( '<???' ) > -1 ) {
var parts = _template_parts( template_txt, '???', template_name );
var A = _parse_template( parts[ 0 ], template_name, 2 );
var B = _parse_template( parts[ 2 ], template_name, 1 );
try {
var f = _to_function( parts[1] );
A.push( [ 0, f ] );
A.push.apply( A, B );
return A;
}
catch( err ) {
console.log( "Error in compiling '" + template_name + "' in function <??? " + parts[1] + " ???> : " + err);
A.push.apply( A, B );
}
} // ???
// register controls
if( recurse < 3 && template_txt.indexOf( '<$$$' ) > -1 ) {
var parts = _template_parts( template_txt, '$$$', template_name );
var A = _parse_template( parts[ 0 ], template_name, 3 );
var B = _parse_template( parts[ 2 ], template_name, 2 );
A.push( [ 1, function( ctx ) { return _register( parts[ 1 ], ctx ) } ] );
A.push.apply( A, B );
return A;
} // $$$
// function to add to template text after controls have been registered
if( recurse < 4 && template_txt.indexOf( '<??' ) > -1 ) {
var parts = _template_parts( template_txt, '??', template_name );
var A = _parse_template( parts[ 0 ], template_name, 4 );
var B = _parse_template( parts[ 2 ], template_name, 3 );
try {
var f = _to_function( parts[1] );
A.push( [ 3, f ] );
A.push.apply( A, B );
return A;
}
catch( err ) {
console.log( "Error in compiling '" + template_name + "' in function <?? " + parts[1] + " ??> : " + err);
A.push.apply( A, B );
}
} // ??
// fill template
if( recurse < 7 && template_txt.indexOf( '<$$' ) > -1 ) {
var parts = _template_parts( template_txt, '$$', template_name );
var args = _parse_args( parts[1] );
var tmpl = args.shift();
var A = _parse_template( parts[ 0 ], template_name, 7 );
var B = _parse_template( parts[ 2 ], template_name, 6 );
A.push( [ 5, function( ctx ) { return _fill_template( tmpl, ctx, args ) } ] );
A.push.apply( A, B );
return A;
} // $$
// place variable
if( recurse < 8 && template_txt.indexOf( '<$' ) > -1 ) {
var parts = _template_parts( template_txt, '$', template_name );
var args = _parse_args( parts[1] );
var vari = args.shift();
var A = _parse_template( parts[ 0 ], template_name, 8 );
var B = _parse_template( parts[ 2 ], template_name, 7 );
A.push( [ 6, function( ctx ) { return _fill_template_variable( vari, ctx, args ) } ] );
A.push.apply( A, B );
return A;
}
// functions to be run after rendering is done
if( recurse < 9 && template_txt.indexOf( '<?' ) > -1 ) {
var parts = _template_parts( template_txt, '?', template_name );
var A = _parse_template( parts[ 0 ], template_name, 8 );
A.push.apply( A, _parse_template( parts[ 2 ], template_name, 7 ) );
try {
var fun = _to_function( parts[1] );
A.push( [ 8, fun ] ); //can be put on the end as this doesn't change the html rendered
}
catch( err ) {
console.log( "Error compiling after render function in template '" + template_name + "' : '" + err + "' for funtion '" + parts[ 1 ] + "'" );
}
return A;
} // <?
if( typeof template_txt === 'string' )
return [ [ 7, template_txt ] ];
return [ ];
}; //_parse_template
// fill
var _template_parts = function( txt, sigil, template_name ) {
var rev_sigil = sigil.split('').reverse().join('');
var start = txt.indexOf( '<' + sigil );
var end = txt.indexOf( rev_sigil + '>' );
if( end == -1 ) throw new Error( "Error, mismatched template start and end sigils (" + sigil + ") for template '" + template_name + "' : " + txt );
var len = sigil.length + 1;
// recalculate the start if need be...this chunk should not have two
// starts in a row..actally just reverse the string and find the
// first rev_sigel...so
// '<$$ <$$ foo bar $$>' ---> <$$ rab oof $$> $$>
// end ^ ^ lenstring - indexof rev is start
// however, the while loop will work as well
while( txt.substring( start + len, end ).indexOf( '<' + sigil ) >= 0 ) {
if( txt.substring( start + len, end ).indexOf( '<' + sigil ) < start ) {
console.log( "Template error for '"+template_name+"' : unable to find close of <" + sigil + ' : ' + txt );
return;
}
start = txt.substring( start + len, end ).indexOf( '<' + sigil );
}
if( end < start ) {
console.log( "Template error for '"+template_name+"' : unable to find close of <" + sigil + ' : ' + txt);
return;
}
return [ txt.substring( 0, start ),
txt.substring( start + len, end ).trim(),
txt.substring( end+len ) ];
}; //_template_parts
// pass in a value/variable (calling this vavar) name string, a context and a boolean.
// if the boolean is false, then if the vavar name is not defined in the context, it is returned literally
// so _parse_val( "FOO", { context object with foo defined as "bar" }, true ) --> "bar"
// so _parse_val( "FOO", { context object with NOT foo defined }, true ) --> "FOO"
// in addition, the vavar contains period characters, those are treated as separators.
// _parse_val( "foo.bar.baz", { context object with foo object that has a bar object that has a baz field with the value of "yup" } ) --> "yup"
var _parse_val = function( value, context, no_literal ) {
/*
Check to see if this has been designated as a list or hash or wrapped list or hash.
*/
var is_list = false, is_hash = false, is_wrapped_list = false, is_wrapped_hash = false;
var orig_val = value;
if( value[ value.length - 1 ] == '@' ) {
if( value[ value.length - 2 ] == '@' ) {
is_wrapped_list = true;
value = value.substring( 0, value.length - 2 );
} else {
is_list = true;
value = value.substring( 0, value.length - 1 );
}
}
else if( value[ value.length - 1 ] == '%' ) {
if( value[ value.length - 2 ] == '%' ) {
is_wrapped_hash = true;
value = value.substring( 0, value.length - 2 );
} else {
is_hash = true;
value = value.substring( 0, value.length - 1 );
}
}
var subj = context;
var start = 0;
var vari;
var prev_is_get = true; // the context is the first subj
var last_dot = value.lastIndexOf( '.' );
var last_pipe = value.lastIndexOf( '|' );
var last_sep = last_dot > last_pipe ? last_dot : last_pipe;
if( last_sep > 0 ) {
for( var i=0, len = value.length; i<len; i++ ) {
if( value[ i ] == '.' || value[ i ] == '|' ) {
vari = value.substring( start, i );
if( last_sep >= i ) {
//not yet at last seperator
subj = prev_is_get ? subj.get( vari ) : subj[ vari ];
prev_is_get = value[ i ] == '|';
start = i + 1;
}
}
}
}
vari = last_sep == 0 ? value.substring( 1 ) : value.substring( start );
if( prev_is_get && last_sep > 0 ) {
if( is_list ) {
subj = subj.get( vari ).to_list();
} else if( is_hash ) {
subj = subj.get( vari ).to_hash();
} else if( is_wrapped_list ) {
subj = subj.class == 'ARRAY' ?
subj = _wrap_list( subj.get( vari ).to_list(), context.template_path + '#' + orig_val ) :
subj = $.yote._wrap_list( subj, vari, context.template_path + '#' + orig_val );
} else if( is_wrapped_hash ) {
subj = subj.class == 'HASH' ?
_wrap_hash( subj.get( vari ).to_hash(), context.template_path + '#' + orig_val ) :
$.yote._wrap_hash( subj, vari, context.template_path + '#' + orig_val );
} else {
subj = subj.get( vari );
}
} else if( last_pipe == 0 && ( is_list || is_hash )) {
if( is_list ) {
subj = subj.get( vari ).to_list();
} else if( is_hash ) {
subj = subj.get( vari ).to_hash();
}
} else {
subj = last_sep >= 0 ? subj[ vari ] : subj.get( vari );
if( is_wrapped_list ) {
subj = _wrap_list( subj, context.template_path + '#' + orig_val );
} else if( is_wrapped_hash ) {
subj = _wrap_hash( subj, context.template_path + '#' + orig_val );
}
}
if( typeof subj === 'undefined' ) return no_literal ? undefined : orig_val;
return subj;
}; //_parse_val
var _register = function( args_string, context ) {
/*
registers an html control with a unique id and assigns
the control-name in the controls context to it.
<$$$ control-name <..html control..> $$$>
*/
var parts = args_string.match( /^\s*(\S+)(\s+\S[\s\S]*)?/ );
var varname = parts ? parts[ 1 ] : undefined;
var rest = parts ? parts[ 2 ] : undefined;
// check to see if the control already has an id or not.
// assign an id if it does not.
var ctrl_parts = /\*\<[\s\S]* id\s*=\s*['"]?(\S+)['"]? /.exec( rest );
var ctrl_id;
if( ctrl_parts ) {
ctrl_id = ctrl_parts[ 1 ];
}
else {
ctrl_id = _next_id();
if( rest )
rest = rest.replace( /^\s*(<\s*[^\s\>]+)([ \>])/, '$1 id="' + ctrl_id + '" $2' );
}
context.control[ varname ] = $( '#' + ctrl_id );
context.controls[ varname ] = '#' + ctrl_id;
context.control_ids[ varname ] = ctrl_id;
return rest;
}; //_register
var _new_context = function() {
return {
vars : {},
functions : {},
controls : {},
control_ids : {},
control : {},
args : [], // args passed in to the template as it was built
parent : undefined,
scratch : scratch, // reference to common scratch area.
_app_ : $.yote.fetch_default_app(),
_acct_ : $.yote.fetch_account(),
get: function( key ) { return typeof this.vars[ key ] === 'undefined' ?
( key == '_app_' ? $.yote.fetch_default_app() : key == '_acct_' ?
$.yote.fetch_account() :
undefined )
: this.vars[ key ]; },
id:_next_id(),
refresh : $.yote.templates.refresh,
parse : function( vari ) {
return _parse_val( vari, this, true )
},
clone : function() {
var clone = {
vars : Object.clone( this.vars ),
functions : Object.clone( this.functions ),
id : _next_id(),
controls : Object.clone( this.controls ),
control : Object.clone( this.control ),
control_ids : Object.clone( this.control_ids ),
args : Object.clone( this.args ),
refresh : this.refresh,
}; //TODO : add hash key and index
clone.clone = this.clone;
clone._app_ = this._app_;
clone._acct_ = this._acct_;
clone.parent = this;
clone.parse = this.parse;
clone.get = this.get;
clone.scratch = scratch;
return clone;
} //clone
};
}; //_new_context
var _fill_template = function( template_name, old_context, args ) {
var compilation = _compiled_templates[ template_name ];
if( ! compilation ) {
console.log( "Error : Template '" + template_name + '" not found.' );
return '';
}
var context = old_context ? old_context.clone() : _new_context();
context.template_id = _next_id();
if( old_context ) {
context.template_path = old_context.template_path + '/' + template_name;
} else {
context.template_path = '/' + template_name;
}
context.args = args;
var res = [];
for( var i=0, len=compilation.length; i < len; i++ ) {
var tuple = compilation[ i ];
var idx = tuple[ 0 ];
if( tuple[ 2 ] ) { // is text
res[ idx ] = tuple[ 1 ];
} else if( tuple[ 3 ] ) { // is after render
try {
_after_render_functions.push( tuple[ 1 ]( context ) ); // builds function with context baked in
res[ idx ] = '';
} catch( err ) {
console.log( "Runtime Error filling template '" + template_name + ":" + err + ' in function : ' + tuple[1] );
}
} else { //function
try {
res[ idx ] = tuple[ 1 ]( context );
} catch( err ) {
console.log( "Runtime Error filling template '" + template_name + " : " + err + ' in function : ' + tuple[1]);
}
}
}
return res.join('');
}; //_fill_template
var _fill_template_direct = function( template, context, template_name ) {
if( ! template ) return '';
template += '';
while( template.indexOf( '<#' ) > -1 ) {
var parts = _template_parts( template, '#', template_name );
template = parts[ 0 ] + parts [ 2 ];
}
// function buliding template ( highest precidence )
while( template.indexOf( '<???' ) > -1 ) {
var parts = _template_parts( template, '???', template_name );
try {
var f = _to_function( parts[1] );
var txt = f( context );
template = parts[ 0 ] + ( typeof txt === 'undefined' ? '' : txt ) + parts[ 2 ];
}
catch( err ) {
console.log( "Error in '" + context.template_path + "' in function '" + parts[1] + "' : " + err);
template = parts[ 0 ] + parts[ 2 ];
}
} // ???
// variable and control definitions for template
while( template.indexOf( '<$$$' ) > -1 ) {
var parts = _template_parts( template, '$$$', template_name );
template = parts[ 0 ] +
_register( parts[ 1 ], context )
+ parts[ 2 ];
} // $$$
// function buliding template
while( template.indexOf( '<??' ) > -1 ) {
var parts = _template_parts( template, '??', template_name );
try {
var f = _to_function( parts[1] );
var txt = f( context );
template = parts[ 0 ] + ( typeof txt === 'undefined' ? '' : txt ) + parts[ 2 ];
}
catch( err ) {
console.log( "Error in '" + context.template_path + "' in function '" + parts[1] + "' : " + err);
template = parts[ 0 ] + parts[ 2 ];
}
} // ??
// fill template
while( template.indexOf( '<$$' ) > -1 ) {
var parts = _template_parts( template, '$$', template_name );
var args = _parse_args( parts[1] );
var template_name = args.shift();
template = parts[ 0 ] +
_fill_template( template_name, context, args ) +
parts[ 2 ];
} // $$
// place variable
while( template.indexOf( '<$' ) > -1 ) {
var parts = _template_parts( template, '$', template_name );
var args = _parse_args( parts[1] );
var vari = args.shift();
template = parts[ 0 ] +
_fill_template_variable( vari, context, args ) +
parts[ 2 ];
}
while( template.indexOf( '<?' ) > -1 ) {
// functions to be run after rendering is done
var parts = _template_parts( template, '?', template_name );
try {
var fun = _to_function( parts[1] );
_after_render_functions.push(
(function( f, ctx ) { return function() {
try {
alert( 'need context bottled up...need to have a template registry path --> template' );
f( ctx );
} catch( Err ) {
console.log( "Error in after render function '" + ctx.template_path + "' in function '" + f + "' : " + Err);
}
} } )( fun, context ) );
}
catch( err ) {
console.log( "Error in '" + context.template_path + "' in function '" + parts[1] + "' : " + err);
}
template = parts[ 0 ] + parts[ 2 ];
} // <?
return template;
}; //fill_template_direct
var _fill_template_variable = function( vari, context, args ) {
var res = _parse_val( vari, context, true );
return typeof res === 'undefined' ? args[ 0 ] ? args[ 0 ] : '' : res;
}; //_fill_template_variable
$.yote.templates = {
// called seldom/debugging
fill_template:function( template_name, old_context, args ) {
return _fill_template( template_name, old_context, args );
},
// imports templates from a url and places them into the document.
import_templates:function( url ) {
$.ajax( {
async:false,
cache: false,
contentType: "text/html",
dataFilter:function(a,b) {
return a;
},
error:function(a,b,c) { console.log(a); },
success:function( data ) {
$( 'html' ).append( data );
},
type:'GET',
url: url
} );
}, //import_templates
register_template:function( key, value ) {
_compile_template( key, value );
}, //register template
is_registered:function( key ) {
return typeof _compiled_templates[ key.trim() ] !== 'undefined';
}, //is_registered
unregister_template:function( key ) {
delete _compiled_templates[ key.trim() ];
}, //unregister_template
// register templates defined in html
init:function() {
$( '.yote_template_definition' ).each( function() {
$.yote.templates.register_template( $( this ).attr( 'template_name' ), $( this ).text() );
} );
var html = $( 'body' ).html();
function dissemble( txt ) {
var matches = txt.match( /([\s\S]*?)<\$\$([\s\S]*?)\$\$>([\s\S]*)/m );
if( matches ) {
return matches[1] + '<$$' + matches[2] + '$$>' + dissemble( matches[3] );
}
return txt;
}
$.yote.templates.register_template( '__BODY__', dissemble( $( 'body' ).html() ) );
}, //init
// rebuild the UI, refreshing all templates
refresh:function() {
var $el = $( 'body' );
var templ_name = '__BODY__';
if( ! _compiled_templates[ templ_name ] ) {
console.log( "Error : template '" + templ_name + "' not found" );
return;
}
var initial = $el.html();
try {
var filled = _fill_template( templ_name, undefined, [] );
$el.empty().append( filled );
} catch( Err ) {
$el.empty().append( initial );
console.log( "Error filling template '" + templ_name + '" : ' + Err );
}
// now that all templates have been rendered, run their after render functions
for( var i=0, len=_after_render_functions.length; i < len; i++ ) {
_after_render_functions[ i ]();
}
// reset so next refresh is clean
_after_render_functions = [];
}, //refresh
}//$.yote.templates
} )();
if( ! Object.size ) {
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
}
if( ! Object.keys ) {
Object.keys = function( t ) {
var k = []
for( var key in t ) {
k.push( key );
}
return k;
}
}
if( ! Object.clone ) {
// shallow clone
Object.clone = function( h ) {
var clone = {};
for( var key in h ) {
clone[ key ] = h[ key ];
}
return clone;
}
}