Major revamps to the template parser. Fixed a few security holes that could allow PHP to be injected in untimely places in TPL code. Improved Ux for XSS attempt in tplWikiFormat. Documented many functions. Backported much cleaner parser from 2.0 branch. Beautified a lot of code in the depths of the template class. Pretty much a small-scale Extreme Makeover.
// Javascript pagination control
/**
* Paginates an array of data.
* @param array List of objects to render
* @param function Function called on each member of the array to render, should take an array member and set this.html to a string
* @param int Optional. Object to start at, defaults to 0.
* @param int Optional. Objects per page, defaults to 10
* @param object Variable that will be passed to the renderer callback
*/
var pagin_objects = new Object();
function paginator(data, callback, offset, perpage, passer)
{
if ( !perpage || typeof(perpage) != 'number' || ( typeof(perpage) == 'number' && perpage < 1 ) )
{
this.perpage = 10;
}
else
{
this.perpage = perpage;
}
if ( typeof(offset) != 'number' )
this.offset = 0;
else
this.offset = offset;
if ( typeof(passer) != 'undefined' )
this.passer = passer;
else
this.passer = false;
this.num_pages = Math.ceil(data.length / perpage );
this.random_id = 'autopagin_' + Math.floor(Math.random() * 1000000);
this._build_control = _build_paginator;
if ( this.num_pages > 1 )
{
var pg_control = '<div class="'+this.random_id+'_control">'+this._build_control(0)+'</div>';
}
else
{
var pg_control = '';
}
this.html = pg_control;
var i = 0;
while ( i < data.length )
{
if ( i % this.perpage == 0 )
{
if ( i > 0 )
this.html += '</div>';
var display = ( ( i * this.perpage ) == this.offset ) ? '' : 'display: none;';
var thispage = Math.floor(i / this.perpage);
this.html += '<div id="' + this.random_id + '_' + thispage + '" style="' + display + '">';
}
this.html += callback(data[i], this.passer);
i++;
}
this.html += '</div>';
this.html += pg_control;
pagin_objects[this.random_id] = this;
}
/**
* Yet another demonstration of the fact that with the right tools, any amount of Javascript can be ported from PHP.
* @access private
*/
function _build_paginator(this_page)
{
var div_styling = ( IE ) ? 'width: 1px; margin: 10px auto 10px 0;' : 'display: table; margin: 10px 0 0 auto;';
var begin = '<div class="tblholder" style="'+div_styling+'"><table border="0" cellspacing="1" cellpadding="4"><tr><th>Page:</th>';
var block = '<td class="row1" style="text-align: center; white-space: nowrap;">{LINK}</td>';
var end = '</tr></table></div>';
var blk = new templateParser(block);
var inner = '';
var cls = 'row2';
if ( this_page > 0 )
{
var url = '#page_'+(this_page);
var link = "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+(this_page-1)+"); return false;\" style='text-decoration: none;'>« Prev</a>";
cls = ( cls == 'row1' ) ? 'row2' : 'row1';
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
}
if ( this.num_pages < 5 )
{
for ( var i = 0; i < this.num_pages; i++ )
{
cls = ( cls == 'row1' ) ? 'row2' : 'row1';
var j = i + 1;
var url = '#page_'+j;
var link = ( i == this_page ) ? "<b>"+j+"</b>" : "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+i+"); return false;\" style='text-decoration: none;'>"+j+"</a>";
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
}
}
else
{
if ( this_page + 5 > this.num_pages )
{
var list = new Array();
var tp = this_page; // The vectors below used to be 3, 2, and 1
if ( this_page + 0 == this.num_pages ) tp = tp - 2;
if ( this_page + 1 == this.num_pages ) tp = tp - 1;
if ( this_page + 2 == this.num_pages ) tp = tp - 0;
for ( var i = tp - 1; i <= tp + 1; i++ )
{
list.push(i);
}
}
else
{
var list = new Array();
var current = this_page;
var lower = ( current < 3 ) ? 1 : current - 1;
for ( var i = 0; i < 3; i++ )
{
list.push(lower + i);
}
}
var url = '#page_1';
var link = ( 0 == this_page ) ? "<b>First</b>" : "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', 0); return false;\" style='text-decoration: none;'>« First</a>";
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
// if ( !in_array(1, $list) )
// {
// $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
// $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
// $inner .= $blk->run();
// }
for ( var k in list )
{
var i = list[k];
if ( i == this.num_pages )
break;
cls = ( cls == 'row1' ) ? 'row2' : 'row1';
var j = i + 1;
var url = '#page_'+j;
var link = ( i == this_page ) ? "<b>"+j+"</b>" : "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+i+"); return false;\" style='text-decoration: none;'>"+j+"</a>";
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
}
if ( this_page < this.num_pages )
{
// $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
// $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
// $inner .= $blk->run();
cls = ( cls == 'row1' ) ? 'row2' : 'row1';
var url = '#page_' + String( this.num_pages-1 );
var link = ( ( this.num_pages - 1 ) == this_page ) ? "<b>Last</b>" : "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+(this.num_pages-1)+"); return false;\" style='text-decoration: none;'>Last »</a>";
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
}
}
if ( this_page < ( this.num_pages - 1 ) )
{
var url = '#page_' + String(this_page + 2);
var link = "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+(this_page+1)+"); return false;\" style='text-decoration: none;'>Next »</a>";
cls = ( cls == 'row1' ) ? 'row2' : 'row1';
blk.assign_vars({
CLASS: cls,
LINK: link
});
inner += blk.run();
}
inner += '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '+this_page+', '+this.num_pages+', '+this.perpage+', {js: true, random_id: \''+this.random_id+'\'});">↓</td>';
var paginator = "\n"+begin+inner+end+"\n";
return paginator;
}
var __paginateLock = false;
function jspaginator_goto(pagin_id, jump_to)
{
if ( __paginateLock )
return false;
var theobj = pagin_objects[pagin_id];
var current_div = false;
var new_div = false;
for ( var i = 0; i < theobj.num_pages; i++ )
{
var thediv = document.getElementById(pagin_id + '_' + i);
if ( !thediv )
{
// if ( window.console )
// window.console.error('jspaginator_goto(): got a bad DOM object in loop');
return false;
}
// window.console.debug("Div "+i+' of '+(theobj.num_pages-1)+': ', thediv);
if ( thediv.style.display != 'none' )
current_div = thediv;
else if ( i == jump_to )
new_div = thediv;
}
if ( !new_div )
{
// if ( window.console )
// window.console.error('jspaginator_goto(): didn\'t get new div');
return false;
}
if ( !current_div )
{
// if ( window.console )
// window.console.error('jspaginator_goto(): didn\'t get current div');
return false;
}
// window.console.debug(current_div);
// window.console.debug(new_div);
// White-out the old div and fade in the new one
if ( IE || is_Safari )
{
current_div.style.display = 'none';
new_div.style.display = 'block';
}
else
{
__paginateLock = true;
var fade_time = 375;
var code = 'var old = \'' + current_div.id + '\';';
code += 'var newer = \'' + new_div.id + '\';';
code += 'document.getElementById(old).style.display = "none";';
code += 'changeOpac(0, newer);';
code += 'document.getElementById(newer).style.display = "block";';
code += 'opacity(newer, 0, 100, '+fade_time+');';
code += '__paginateLock = false;';
// if ( window.console )
// window.console.debug('metacode for fader: ', code);
opacity(current_div.id, 100, 0, fade_time);
setTimeout(code, (fade_time + 50));
}
var pg_control = theobj._build_control(jump_to);
var divs = getElementsByClassName(document, 'div', pagin_id + '_control');
for ( var i = 0; i < divs.length; i++ )
{
divs[i].innerHTML = pg_control;
}
}
function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
{
var height = $(parentobj).Height();
var width = $(parentobj).Width();
var left = $(parentobj).Left();
var top = $(parentobj).Top();
var left_pos = left + width ;
var top_pos = height + top;
var div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = top_pos + 'px';
div.className = 'question-box';
div.style.margin = '1px 0 0 2px';
var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
var regex = new RegExp('\"', 'g');
var submit_target = ( typeof(url_string) == 'object' ) ? ( toJSONString(url_string) ).replace(regex, '\'') : 'unescape(\'' + escape(url_string) + '\')';
var onclick = 'paginator_submit(this, '+num_pages+', '+perpage+', '+submit_target+'); return false;';
div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" /> <a href="#" onclick="'+onclick+'" style="font-size: 14pt; text-decoration: none;">»</a> <a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">×</a>';
var body = document.getElementsByTagName('body')[0];
domObjChangeOpac(0, div);
body.appendChild(div);
document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
document.getElementById(vtmp).focus();
// fade the div
/*
if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
var from = '#33FF33';
Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
*/
fly_in_bottom(div, false, true);
var divh = $(div).Width();
left_pos = left_pos - divh;
div.style.left = left_pos + 'px';
}
function paginator_submit(obj, max, perpage, formatstring)
{
var userinput = obj.previousSibling.previousSibling.value;
userinput = parseInt(userinput);
var offset = ( userinput - 1 ) * perpage;
if ( userinput > max || isNaN(userinput) || userinput < 1 )
{
new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
return false;
}
if ( typeof(formatstring) == 'object' )
{
fly_out_top(obj.parentNode, false, true);
jspaginator_goto(formatstring.random_id, ( offset / perpage ));
}
else
{
var url = sprintf(formatstring, String(offset));
fly_out_top(obj.parentNode, false, true);
window.location = url;
}
}