includes/clientside/static/ajax.js
author Dan Fuhry <dan@enanocms.org>
Mon, 28 Jun 2010 13:31:21 -0400
changeset 1254 221d14331ebe
parent 1252 e34c23a35dc9
child 1284 35380c89b5bf
permissions -rw-r--r--
Added basic support for right-to-left languages. Set meta_direction to "rtl" in core.json.

/*
 * AJAX applets
 */
 
window.ajaxReset = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	var ns_id = strToPageID(physical_title);
	if ( ns_id[1] == 'Special' || ns_id[1] == 'Admin' )
		return false;
	enableUnload();
	setAjaxLoading();
	var redir = ( disable_redirect ) ? '&redirect=no' : '';
	ajaxGet(append_sid(scriptPath + '/ajax.php?title=' + physical_title +'&_mode=getpage&noheaders' + redir), function(ajax) {
		// Allow for 404 here, it's generated by the "page not found" error message
		// (even with noheaders specified, probably should be fixed)
		if ( ajax.readyState == 4 && ( ajax.status == 200 || ajax.status == 404 ) ) {
			unsetAjaxLoading();
			document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
			selectButtonMajor('article');
			unselectAllButtonsMinor();
			// if we're on a userpage, call the onload function to rebuild the tabs
			if ( typeof(userpage_onload) == 'function' )
			{
				window.userpage_blocks = [];
				userpage_onload();
			}
		}
	});
}

// Miscellaneous AJAX applets

window.ajaxProtect = function(existing_level)
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	
	// touch this variable to allow it to be used in child functions
	void(existing_level);
	
	// require re-auth
	if ( auth_level <= USER_LEVEL_MEMBER )
	{
		load_component(['login', 'fadefilter', 'flyin', 'jquery', 'jquery-ui', 'crypto', 'messagebox']);
		ajaxDynamicReauth(function(key)
			{
				ajaxProtect(existing_level);
			}, user_level);
		
		return false;
	}
	
	load_component(['messagebox', 'jquery', 'jquery-ui', 'l10n', 'fadefilter', 'flyin']);
	
	// preload language
	$lang.get('meta_meta');
	
	var mp = miniPrompt(function(parent)
		{
			var icon_full = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 0, 0);
			var icon_semi = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 22, 0);
			var icon_none = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 44, 0);
			
			$(parent).append('<h3>' + $lang.get('onpage_protect_heading') + '</h3>');
			$(parent).append('<p>' + $lang.get('onpage_protect_msg_select_level') + '</p>');
			
			$(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_1" name="protect_level" /> ' + icon_full + ' ' + $lang.get('onpage_protect_btn_full') + '</label></div>');
			$(parent).append('<div class="protectlevel_hint" id="protect_level_1_hint">' + $lang.get('onpage_protect_btn_full_hint') + '</div>');
			$(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_2" name="protect_level" /> ' + icon_semi + ' ' + $lang.get('onpage_protect_btn_semi') + '</label></div>');
			$(parent).append('<div class="protectlevel_hint" id="protect_level_2_hint">' + $lang.get('onpage_protect_btn_semi_hint') + '</div>');
			$(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_0" name="protect_level" /> ' + icon_none + ' ' + $lang.get('onpage_protect_btn_none') + '</label></div>');
			$(parent).append('<div class="protectlevel_hint" id="protect_level_0_hint">' + $lang.get('onpage_protect_btn_none_hint') + '</div>');
			
			$(parent).append('<table class="protectreason"><tr><td valign="top">' + $lang.get('onpage_protect_lbl_reason') + '</td><td><input id="protect_reason" size="30" type="text" /><br /><small>' + $lang.get('onpage_protect_lbl_reason_hint') + '</small></td></tr></table>');
			
			$(parent).append('<p class="buttons"><a class="submitbutton abutton abutton_green" style="font-weight: bold;" href="#" onclick="ajaxProtectSubmit(this); return false;">' + $lang.get('onpage_protect_btn_submit') + '</a> <a class="submitbutton abutton" href="#" onclick="miniPromptDestroy(this); return false;">' + $lang.get('etc_cancel') + '</a></p>');
			
			$('.protectlevel', parent).css('line-height', '22px');
			$('h3', parent).css('text-align', 'center');
			$('.protectlevel_hint', parent)
				.css('font-size', 'smaller')
				.css('margin-left', '52px')
				.hide();
			$('p.buttons', parent).css('margin-top', '15px').css('text-align', 'center');
			
			if ( typeof(existing_level) == 'number' )
			{
				$('#protect_level_' + existing_level, parent).attr('checked', 'checked');
				$('#protect_level_' + existing_level + '_hint', parent).show();
				$('#protect_level_' + existing_level, parent).parent().append(' <small><span style="color: #050; background-color: #eee; padding: 0 4px;">' + $lang.get('onpage_protect_lbl_current') + '</span></small>');
			}
			
			$('input:radio', parent).click(function()
				{
					var mp = miniPromptGetParent(this);
					$('.protectlevel_hint:visible', mp).hide('blind', 150);
					$('#' + this.id + '_hint').show('blind', 150);
					$('#protect_reason').focus();
				});
			$('input:text', parent).keyup(function(e)
				{
					if ( e.keyCode == 13 )
						ajaxProtectSubmit(this);
				});
		});
}

window.ajaxProtectSubmit = function(el)
{
	var mp = miniPromptGetParent(el);
	
	var reason = trim($('#protect_reason', mp).attr('value'));
	if ( reason == '' )
	{
		var oldbg = $('#protect_reason').css('background-color');
		if ( jQuery.fx.off )
		{
			$('#protect_reason').css('background-color', '#a00');
			setTimeout(function()
				{
					$('#protect_reason').css('background-color', oldbg);
				}, 1000);
		}
		else
		{
			$('#protect_reason').css('background-color', '#a00').animate({ backgroundColor: oldbg }, 1000);
		}
		return false;
	}
	
	var level = 0;
	if ( $('#protect_level_1', mp).attr('checked') )
		level = 1;
	if ( $('#protect_level_2', mp).attr('checked') )
		level = 2;
	
	var whitey = whiteOutMiniPrompt(mp);
	$.post(stdAjaxPrefix + '&_mode=protect', { level: level, reason: reason }, function(response, statustext)
		{
			if ( response.success )
			{
				whiteOutReportSuccess(whitey);
				// update protect button
				var btn = $('#tb_ajax_protect_btn').get(0);
				btn.level = level;
				btn.setAttribute('onclick', null);
				btn.onclick = null;
				$(btn).click(function()
					{
						ajaxProtect(this.level);
						return false;
					});
				var status = '';
				switch(level)
				{
					case 1: status = $lang.get('onpage_btn_protect_on'); break;
					case 0: status = $lang.get('onpage_btn_protect_off'); break;
					case 2: status = $lang.get('onpage_btn_protect_semi'); break;
				}
				$('#tb_ajax_protect_status').text(status);
			}
			else
			{
				whiteOutReportFailure(whitey);
				alert($lang.get('page_err_' + response.error));
			}
		}, 'json');
}

window.ajaxRename = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	
	// updated - 1.1.4 to use miniPrompt
	load_component(['l10n', 'messagebox', 'flyin', 'fadefilter']);
	miniPrompt(ajaxRenameConstructDialog);
}

var ajaxRenameConstructDialog = function(div)
{
	// title
	var heading = document.createElement('h3');
	heading.appendChild(document.createTextNode($lang.get('ajax_rename_prompt_short')));
	div.appendChild(heading);
	
	// form
	var form = document.createElement('form');
	form.action = 'javascript:void(0);';
	
	// box
	var box = document.createElement('input');
	box.size = '43';
	box.style.width = '100%';
	form.appendChild(box);
	div.appendChild(form);
	
	// notice
	var notice = document.createElement('small');
	notice.appendChild(document.createTextNode($lang.get('ajax_rename_notice')));
	div.appendChild(notice);
	
	// button area
	var btndiv = document.createElement('div');
	btndiv.className = 'mp-buttons';
	
	// buttons
	var btn_submit = document.createElement('a');
	btn_submit.href = '#';
	btn_submit.appendChild(document.createTextNode($lang.get('etc_go')));
	btn_submit.className = 'abutton abutton_green';
	
	var btn_cancel = document.createElement('a');
	btn_cancel.href = '#';
	btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
	btn_cancel.className = 'abutton';
	
	btndiv.appendChild(btn_submit);
	btndiv.appendChild(document.createTextNode(' | '));
	btndiv.appendChild(btn_cancel);
	div.appendChild(btndiv);
	
	// events
	btn_submit.onclick = function()
	{
		ajaxRenameSubmit(this);
		return false;
	}
	btn_cancel.onclick = function()
	{
		miniPromptDestroy(this);
		return false;
	}
	form.onsubmit = function()
	{
		ajaxRenameSubmit(this);
		return false;
	}
	
	setTimeout(function()
		{
			box.focus();
		}, ( aclDisableTransitionFX ? 200 : 750 ));
}

window.ajaxRenameSubmit = function(obj)
{
	var box = miniPromptGetParent(obj);
	if ( !box )
		return false;
	
	var input = box.getElementsByTagName('input')[0];
	if ( !input )
		return false;
		
	var newname = input.value;
	newname = trim(newname);
	
	if ( newname.length < 1 )
	{
		alert($lang.get('ajax_rename_too_short'));
		return false;
	}
	
	if ( !newname )
	{
		return false;
	}
	
	var innerBox = getElementsByClassName(box, 'div', 'mp-body')[0];
	var whiteout = whiteOutElement(innerBox);
	whiteout.style.width = ( $dynano(whiteout).Width() - 78 ) + 'px';
	whiteout.style.left = ( $dynano(whiteout).Left() + 44 ) + 'px';
	
	ajaxPost(stdAjaxPrefix + '&_mode=rename', 'newtitle=' + ajaxEscape(newname), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				whiteout.parentNode.removeChild(whiteout);
				var response = String(ajax.responseText);
				if ( !check_json_response(response) )
				{
					handle_invalid_json(response);
					return false;
				}
				response = parseJSON(response);
				if ( response.success )
				{
					miniPromptDestroy(box, true);
					ajaxRenameDoClientTransform(newname);
					new MessageBox( MB_OK|MB_ICONINFORMATION, $lang.get('ajax_rename_success_title'), $lang.get('ajax_rename_success_body', { page_name_new: newname }) );
					mb_previously_had_darkener = false;
				}
				else
				{
					var errmsg = $lang.get('page_err_' + response.error);
					alert(errmsg);
				}
			}
		}, true);
}

window.ajaxRenameDoClientTransform = function(newname)
{
	var obj = document.getElementById('h2PageName');
	if ( obj )
	{
		obj.firstChild.nodeValue = newname;
	}
	document.title = newname;
}

window.ajaxDeletePage = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	
	// require re-auth
	if ( auth_level <= USER_LEVEL_MEMBER )
	{
		load_component(['login', 'fadefilter', 'flyin', 'jquery', 'jquery-ui', 'crypto', 'messagebox']);
		ajaxDynamicReauth(function(key)
			{
				ajaxDeletePage();
			}, user_level);
		
		return false;
	}
	
	load_component(['l10n', 'messagebox', 'jquery', 'jquery-ui', 'fadefilter', 'flyin']);
	
	// stage 1: prompt for reason and confirmation
	miniPrompt(function(parent)
		{
			// heading/title
			var h3 = document.createElement('h3');
			h3.appendChild(document.createTextNode($lang.get('ajax_delete_header')));
			parent.appendChild(h3);
			
			// "please enter your reason"
			var p1 = document.createElement('p');
			p1.appendChild(document.createTextNode($lang.get('ajax_delete_prompt_reason')));
			parent.appendChild(p1);
			
			// textbox + label thereof
			var p2 = document.createElement('p');
			var tb = document.createElement('input');
			var dl = document.createElement('label');
			
			tb.type = 'text';
			tb.size = '30';
			tb.onkeyup = function(e)
			{
				if ( e )
				if ( e.keyCode )
				if ( e.keyCode == 13 )
				{
					if ( ajaxDeletePageSubmit(this) )
					{
						miniPromptDestroy(this);
					}
				}
				else if ( e.keyCode == 27 )
				{
					miniPromptDestroy(this);
				}
			}
			
			dl.appendChild(document.createTextNode($lang.get('ajax_delete_lbl_reason') + ' '));
			dl.appendChild(tb);
			p2.appendChild(dl);
			parent.appendChild(p2);
			
			// notice underneath
			var p3 = document.createElement('p');
			p3.style.fontSize = 'smaller';
			p3.appendChild(document.createTextNode($lang.get('ajax_delete_msg_confirm')));
			parent.appendChild(p3);
			
			// confirmation + submit/cancel (structure)
			var divleft  = document.createElement('div');
			var divright = document.createElement('div');
			var divclear = document.createElement('div');
			
			divleft.style.cssFloat = 'left';
			divleft.style.styleFloat = 'left';
			
			divright.style.cssFloat = 'right';
			divright.style.styleFloat = 'right';
			
			divclear.style.clear = 'both';
			
			parent.appendChild(divleft);
			parent.appendChild(divright);
			parent.appendChild(divclear);
			
			// confirmation + submit/cancel (controls)
			var cb = document.createElement('input');
			var cl = document.createElement('label');
			
			cb.type = 'checkbox';
			cb.checked = false;
			
			// a bit of a hack here, doesn't seem to work in fx3
			cb.onblur = function(e)
			{
				var parent = this.parentNode.parentNode.parentNode;
				var submitter = parent.getElementsByTagName('a')[0];
				if ( submitter )
					submitter.focus();
			}
			
			cl.appendChild(cb);
			cl.appendChild(document.createTextNode(' ' + $lang.get('ajax_delete_lbl_confirm')));
			divleft.appendChild(cl);
			
			var btn_submit = document.createElement('a');
			btn_submit.className = 'abutton abutton_red';
			btn_submit.href = '#';
			btn_submit.appendChild(document.createTextNode($lang.get('ajax_delete_btn_delete')));
			btn_submit.onclick = function()
			{
				if ( ajaxDeletePageSubmit(this) )
				{
					miniPromptDestroy(this);
				}
				return false;
			}
			
			var btn_cancel = document.createElement('a');
			btn_cancel.className = 'abutton';
			btn_cancel.href = '#';
			btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
			btn_cancel.onclick = function()
			{
				miniPromptDestroy(this);
				return false;
			}
			
			divright.appendChild(btn_submit);
			divright.appendChild(document.createTextNode(' '));
			divright.appendChild(btn_cancel);
			
			var timeout = ( aclDisableTransitionFX ) ? 10 : 1000;
			setTimeout(function()
				{
					tb.focus();
				}, timeout);
		});
}

window.ajaxDeletePageSubmit = function(prompt_obj)
{
	prompt_obj = miniPromptGetParent(prompt_obj).childNodes[1];
	var inputs = prompt_obj.getElementsByTagName('input');
	var reason = inputs[0];
	var confirm = inputs[1];
	
	if ( trim(reason.value) == '' )
	{
		// flash the background of the reason entry
		$(reason.parentNode).effect("highlight", {}, 1000);
		return false;
	}
	
	if ( !confirm.checked )
	{
		// flash the background of the confirm checkbox
		$(confirm.parentNode).effect("highlight", {}, 1000);
		return false;
	}
	
	prompt_obj.innerHTML = '<img alt="loading" style="display: block; margin: 0 auto;" src="' + cdnPath + '/images/loading-big.gif" />';
	
	// tenemos la confirmación y la razón - borre la página.
	setAjaxLoading();
	ajaxPost(stdAjaxPrefix + '&_mode=deletepage', 'reason=' + ajaxEscape(trim(reason.value)), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				unsetAjaxLoading();
				
				// show the response in the same prompt window
				prompt_obj.style.textAlign = 'center';
				prompt_obj.innerHTML = '';
				
				var p1 = document.createElement('div');
				p1.style.marginBottom = '15px';
				p1.appendChild(document.createTextNode(ajax.responseText));
				prompt_obj.appendChild(p1);
				
				var p2 = document.createElement('p');
				var a = document.createElement('a');
				a.className = 'abutton';
				a.href = '#';
				a.appendChild(document.createTextNode($lang.get('etc_close')));
				a.onclick = function()
				{
					miniPromptDestroy(this);
					window.location.reload();
					return false;
				}
				p2.appendChild(a);
				prompt_obj.appendChild(a);
				
				a.focus();
			}
		});
	
	return true;
}

window.ajaxDelVote = function()
{
	load_component(['l10n', 'messagebox', 'flyin', 'fadefilter']);
	
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	miniPromptMessage({
			title: $lang.get('ajax_delvote_confirm_title'),
			message: $lang.get('ajax_delvote_confirm_body'),
			buttons: [
				{
					text: $lang.get('ajax_delvote_btn_submit'),
					color: 'red',
					style: {
						fontWeight: 'bold'
					},
					onclick: function(e)
					{
						miniPromptDestroy(this);
						setAjaxLoading();
						ajaxGet(stdAjaxPrefix+'&_mode=delvote', function(ajax) {
							if ( ajax.readyState == 4 && ajax.status == 200 ) {
								unsetAjaxLoading();
								alert(ajax.responseText);
							}
						}, true);
					}
				},
				{
					text: $lang.get('etc_cancel'),
					onclick: function(e)
					{
						miniPromptDestroy(this);
					}
				}
			]
		});
}

window.ajaxResetDelVotes = function()
{
	load_component(['l10n', 'messagebox', 'flyin', 'fadefilter']);
	
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	miniPromptMessage({
			title: $lang.get('ajax_delvote_reset_confirm_title'),
			message: $lang.get('ajax_delvote_reset_confirm_body'),
			buttons: [
				{
					text: $lang.get('ajax_delvote_reset_btn_submit'),
					color: 'red',
					style: {
						fontWeight: 'bold'
					},
					onclick: function(e)
					{
						var box = miniPromptGetParent(this);
						var whitey = whiteOutMiniPrompt(box);
						ajaxGet(stdAjaxPrefix+'&_mode=resetdelvotes', function(ajax) {
							if ( ajax.readyState == 4 && ajax.status == 200 ) {
								whiteOutReportSuccess(whitey);
								
								item = document.getElementById('mdgDeleteVoteNoticeBox');
								if(item)
								{
									opacity('mdgDeleteVoteNoticeBox', 100, 0, 1000);
									setTimeout("document.getElementById('mdgDeleteVoteNoticeBox').style.display = 'none';", 1000);
								}
							}
						}, true);
					}
				},
				{
					text: $lang.get('etc_cancel'),
					onclick: function(e)
					{
						miniPromptDestroy(this);
					}
				}
			]
		});
}

// Editing/saving category information
// This was not easy to write, I hope enjoy it, and dang I swear I'm gonna
// find someone to work on just the Javascript part of Enano...

window.ajaxCatEdit = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	setAjaxLoading();
	ajaxGet(stdAjaxPrefix+'&_mode=catedit', function(ajax) {
		if ( ajax.readyState == 4 && ajax.status == 200 ) {
			unsetAjaxLoading();
			edit_open = false;
			eval(ajax.responseText);
		}
	});
}

window.ajaxCatSave = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	var query = 'hello=';
	$('.catCheck input:checkbox:checked').each(function(i, e)
		{
			query += '&categories[]=' + ajaxEscape($(e).val())
		});
	
	ajaxPost(stdAjaxPrefix+'&_mode=catsave', query, function(ajax) {
		if ( ajax.readyState == 4 && ajax.status == 200 ) {
			unsetAjaxLoading();
			edit_open = false;
			if(ajax.responseText != 'GOOD') alert(ajax.responseText);
			ajaxReset();
		}
	});
}

// History stuff

window.ajaxHistory = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	setAjaxLoading();
	ajaxGet(stdAjaxPrefix+'&_mode=histlist', function(ajax) {
		if ( ajax.readyState == 4 && ajax.status == 200 ) {
			unsetAjaxLoading();
			edit_open = false;
			selectButtonMajor('article');
			selectButtonMinor('history');
			document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
			buildDiffList();
		}
	});
}

window.ajaxHistView = function(oldid, ttl) {
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	if(!ttl) ttl=title;
	setAjaxLoading();
	ajaxGet(append_sid(scriptPath+'/ajax.php?title='+ttl+'&_mode=getpage&oldid='+oldid), function(ajax) {
		if ( ajax.readyState == 4 && ajax.status == 200 ) {
			unsetAjaxLoading();
			edit_open = false;
			document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
		}
	});
}

window.ajaxRollback = function(id) {
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	setAjaxLoading();
	ajaxGet(stdAjaxPrefix+'&_mode=rollback&id='+id, function(ajax) {
		if ( ajax.readyState == 4 && ajax.status == 200 ) {
			unsetAjaxLoading();
			
			var response = String(ajax.responseText + '');
			if ( !check_json_response(response) )
			{
				handle_invalid_json(response);
				return false;
			}
			
			response = parseJSON(response);
			if ( response.success )
			{
				alert( $lang.get('page_msg_rb_success_' + response.action, { dateline: response.dateline }) )
			}
			else
			{
				if ( response.action )
				{
					alert( $lang.get('page_err_' + response.error, { action: response.action }) );
				}
				else
				{
					alert( $lang.get('page_err_' + response.error) );
				}
			}
		}
	});
}

window.ajaxClearLogs = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	
	// require re-auth
	if ( auth_level <= USER_LEVEL_MEMBER )
	{
		load_component(['login', 'fadefilter', 'flyin', 'jquery', 'jquery-ui', 'crypto', 'messagebox']);
		ajaxDynamicReauth(function(key)
			{
				ajaxClearLogs();
			}, user_level);
		
		return false;
	}
	
	load_component(['l10n', 'messagebox', 'flyin', 'fadefilter']);
	
	miniPromptMessage({
			title: $lang.get('ajax_clearlogs_confirm_title'),
			message: $lang.get('ajax_clearlogs_confirm_body'),
			buttons: [
				{
					text: $lang.get('ajax_clearlogs_btn_submit'),
					color: 'red',
					style: {
						fontWeight: 'bold'
					},
					onclick: function(e)
					{
						miniPromptDestroy(this);
						setAjaxLoading();
						ajaxGet(stdAjaxPrefix+'&_mode=flushlogs', function(ajax) {
							if ( ajax.readyState == 4 && ajax.status == 200 ) {
								unsetAjaxLoading();
								alert(ajax.responseText);
								window.location.reload();
							}
						});
					}
				},
				{
					text: $lang.get('etc_cancel'),
					onclick: function(e)
					{
						miniPromptDestroy(this);
					}
				}
			]
		});
}

window.buildDiffList = function()
{
	arrDiff1Buttons = getElementsByClassName(document, 'input', 'clsDiff1Radio');
	arrDiff2Buttons = getElementsByClassName(document, 'input', 'clsDiff2Radio');
	var len = arrDiff1Buttons.length;
	if ( len < 1 )
		return false;
	timelist = new Array();
	for ( var i = 0; i < len; i++ )
	{
		timelist.push( arrDiff2Buttons[i].id.substr(6) );
	}
	timelist.push( arrDiff1Buttons[len-1].id.substr(6) );
	delete(timelist.toJSONString);
	for ( var i = 1; i < timelist.length-1; i++ )
	{
		if ( i >= timelist.length ) break;
		arrDiff2Buttons[i].style.display = 'none';
	}
}

window.selectDiff1Button = function(obj)
{
	var this_time = obj.id.substr(6);
	var index = parseInt(in_array(this_time, timelist));
	for ( var i = 0; i < timelist.length - 1; i++ )
	{
		if ( i < timelist.length - 1 )
		{
			var state = ( i < index ) ? 'inline' : 'none';
			var id = 'diff2_' + timelist[i];
			document.getElementById(id).style.display = state;
			
			// alert("Debug:\nIndex: "+index+"\nState: "+state+"\ni: "+i);
		}
	}
}

window.selectDiff2Button = function(obj)
{
	var this_time = obj.id.substr(6);
	var index = parseInt(in_array(this_time, timelist));
	for ( var i = 1; i < timelist.length; i++ )
	{
		if ( i < timelist.length - 1 )
		{
			var state = ( i > index ) ? 'inline' : 'none';
			var id = 'diff1_' + timelist[i];
			document.getElementById(id).style.display = state;
			
			// alert("Debug:\nIndex: "+index+"\nState: "+state+"\ni: "+i);
		}
	}
}

window.ajaxHistDiff = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	var id1=false;
	var id2=false;
	for ( i = 0; i < arrDiff1Buttons.length; i++ )
	{
		k = i + '';
		kpp = i + 1;
		kpp = kpp + '';
		if(arrDiff1Buttons[k].checked) id1 = arrDiff1Buttons[k].id.substr(6);
		if(arrDiff2Buttons[k].checked) id2 = arrDiff2Buttons[k].id.substr(6);
	}
	if(!id1 || !id2) { alert('BUG: Couldn\'t get checked radiobutton state'); return; }
	setAjaxLoading();
	ajaxGet(stdAjaxPrefix+'&_mode=pagediff&diff1='+id1+'&diff2='+id2, function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				unsetAjaxLoading();
				document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
			}
		});
}

// Change the user's preferred style/theme

window.ajaxChangeStyle = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	load_component(['l10n', 'fadefilter', 'jquery', 'jquery-ui']);
	
	// force string fetch
	$lang.get('etc_cancel');
	
	// preload some images
	var i1 = new Image();
	i1.src = cdnPath + '/images/loading-big.gif';
	var i2 = new Image();
	i2.src = cdnPath + '/images/check-large.png';
	
	darken(true, 70, 'theme-selector-shade');
	
	$('body').append('<div id="theme-selector-wrapper"><div id="theme-selector-body"><div id="theme-selector-inner"><div class="theme-selector-spinner"></div></div></div></div>');
	$('#theme-selector-wrapper')
		.css('top', String(getScrollOffset()) + 'px')
		.css('left', 0)
		.css('z-index', String( getHighestZ() + 20 ));
	
	$.get(stdAjaxPrefix + '&_mode=theme_list', {}, function(data, status)
		{
			$('#theme-selector-inner .theme-selector-spinner').fadeOut(650);
			$('#theme-selector-body').animate({ width: 728 }, 600, function()
				{
					// avoiding jQuery's fade functions because they insist on toggling display as well
					if ( !aclDisableTransitionFX )
						changeOpac(0, 'theme-selector-inner');
					$('#theme-selector-inner').html('<h3></h3>');
					$('#theme-selector-inner > h3').text($lang.get('ajax_thmsel_lbl_choosetheme'));
					$('#theme-selector-inner').append('<ul></ul>');
					for ( var i = 0; i < data.length; i++ )
					{
						var bgi = data[i].have_thumb ? cdnPath + '/themes/' + data[i].theme_id + '/preview.png' : cdnPath + '/images/themepreview.png';
						var maxheight = getHeight() - 325;
						$('#theme-selector-inner > ul')
							.css('clip', 'rect(0px, auto, auto, 0px)')
							.css('overflow', 'auto')
							.css('max-height', maxheight)
							.append('<li id="theme_' + i + '"><a href="#"><span></span></a></li>');
						$('#theme-selector-inner li#theme_' + i + ' > a')
							.css('background-image', 'url(' + bgi + ')')
							.attr('enano:theme_id', data[i].theme_id);
						$('#theme-selector-inner li#theme_' + i + ' > a > span')
							.text(data[i].theme_name);
					}
					$('#theme-selector-inner').append('<span class="menuclear"></span>');
					$('#theme-selector-inner').append('<div style="padding-top: 40px;"><a class="abutton abutton_green" style="font-size: larger;" href="#" onclick="ajaxChangeStyleClose(); return false;">' + $lang.get('etc_cancel') + '</a></div>');
					
					$('#theme-selector-body').animate({ height: $('#theme-selector-inner').height() + 30 }, 600, function()
						{
							if ( !aclDisableTransitionFX )
								opacity('theme-selector-inner', 0, 100, 750);
						});
					
					$('#theme-selector-inner li a').click(function()
						{
							var theme_id = $(this).attr('enano:theme_id');
							$('span', this).html('&nbsp;').addClass('loading').fadeTo('fast', 0.6)
							$.get(stdAjaxPrefix + '&_mode=get_styles', { theme_id: theme_id }, function(data, status)
								{
									if ( data.length > 1 )
									{
										$('#theme-selector-inner').css('height', $('#theme-selector-inner').height()).fadeOut(600, function()
										{
											var div = document.createElement('div');
											if ( !aclDisableTransitionFX )
												domObjChangeOpac(0, div);
											
											$(div).attr('id', 'theme-selector-style-list').append('<h3></h3>');
											$('h3', div).text($lang.get('ajax_thmsel_lbl_choosestyle'));
											
											for ( var i = 0; i < data.length; i++ )
											{
												$(div).append('<a class="abutton block stylebtn" id="stylebtn_' + i + '" enano:style_id="' + data[i] + '">' + themeid_to_title(data[i]) + '</a>');
											}
											
											$(div).append('<div style="padding-top: 40px;"><a class="abutton abutton_green" style="font-size: larger;" href="#" onclick="ajaxChangeStyleClose(); return false;">' + $lang.get('etc_cancel') + '</a></div>');
											
											if ( !aclDisableTransitionFX )
												changeOpac(0, 'theme-selector-style-list');
											$(this).html(div).show();
											
											$('#theme-selector-body').animate({width: 300, height: $('#theme-selector-style-list').height() + 30}, 300, function()
												{
													if ( !aclDisableTransitionFX )
														opacity('theme-selector-style-list', 0, 100, 500);
												});
											
											$('.stylebtn').click(function()
												{
													ajaxChangeThemeSetLoading();
													$.post(stdAjaxPrefix + '&_mode=change_theme', { theme_id: theme_id, style_id: $(this).attr('enano:style_id') }, function(data, status)
														{
															if ( data.error )
															{
																alert(data.error);
																ajaxChangeStyleClose();
																return false;
															}
															ajaxChangeThemeShowSuccess();
														}, 2000);
													
													return false;
												});
										});
									}
									else
									{
										if ( !data[0] )
										{
											alert('Didn\'t find any CSS files. :-/');
											ajaxChangeStyleClose();
										}
										
										$.post(stdAjaxPrefix + '&_mode=change_theme', { theme_id: theme_id, style_id: data[0] }, function(data, status)
											{
												if ( data.error )
												{
													alert(data.error);
													ajaxChangeStyleClose();
													return false;
												}
												ajaxChangeThemeShowSuccess();
											}, 'json');
									}
								}, 'json');
							return false;
						}); // click function
				}); // animate
		}, 'json'); // get
}

window.ajaxChangeThemeSetLoading = function()
{
	$('#theme-selector-body').animate({width: 130, height: 130});
	$('#theme-selector-inner').empty().html('<div class="theme-selector-spinner"></div>');
}

window.ajaxChangeThemeShowSuccess = function()
{
	if ( aclDisableTransitionFX )
	{
		$('#theme-selector-inner').empty();
	}
	else
	{
		setTimeout(function()
			{
				$('#theme-selector-inner').empty();
			}, 10);
	}
	
	$('#theme-selector-body').animate({width: 400, height: 300 }, 600, function()
			{
				$('#theme-selector-inner').append('<img src="' + cdnPath + '/images/check-large.png" alt=" " style="display: block; margin: 15px auto;" />');
				$('#theme-selector-inner').append('<h3>' + $lang.get('ajax_thmsel_msg_success') + '</h3>');
				$('#theme-selector-inner').append('<div style="padding-top: 20px;"><a class="abutton abutton_green" style="font-size: larger;" href="#" onclick="window.location.reload(); return false;">' + $lang.get('ajax_thmsel_btn_reload') + '</a></div>');
				$('#theme-selector-inner').append('<div style="padding-top: 25px;"><a href="#" style="font-size: smaller;" onclick="ajaxChangeStyleClose(); return false;">' + $lang.get('ajax_thmsel_btn_close') + '</a><br /><small>' + $lang.get('ajax_thmsel_btn_close_hint') + '</small></div>');
				$('#theme-selector-inner').fadeIn();
			});
}

window.ajaxChangeStyleClose = function()
{
	setTimeout(function()
		{
			enlighten(false, 'theme-selector-shade');
			$('#theme-selector-wrapper').fadeOut(500, function()
				{
					$(this).remove();
				});
		}, ( aclDisableTransitionFX ? 0 : 300));
	if ( !aclDisableTransitionFX )
		opacity('theme-selector-inner', 100, 0, 250);
}

function themeid_to_title(id)
{
	if ( typeof(id) != 'string' )
		return false;
	id = id.substr(0, 1).toUpperCase() + id.substr(1);
	id = id.replace(/_/g, ' ');
	id = id.replace(/-/g, ' ');
	return id;
}

window.ajaxSetPassword = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	load_component('crypto');
	pass = hex_sha1(document.getElementById('mdgPassSetField').value);
	setAjaxLoading();
	ajaxPost(stdAjaxPrefix+'&_mode=setpass', 'password='+pass, function(ajax)
		{
			unsetAjaxLoading();
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				alert(ajax.responseText);
			}
		}, true);
}

window.ajaxDisableEmbeddedPHP = function()
{
	// IE <6 pseudo-compatibility
	if ( KILL_SWITCH )
		return true;
	if ( !confirm($lang.get('ajax_killphp_confirm')) )
		return false;
	var $killdiv = $dynano('php_killer');
	if ( !$killdiv.object )
	{
		alert('Can\'t get kill div object');
		return false;
	}
	$killdiv.object.innerHTML = '<img alt="Loading..." src="' + scriptPath + '/images/loading-big.gif" /><br />Making request...';
	var url = makeUrlNS('Admin', 'Home', 'src=ajax');
	ajaxPost(url, 'act=kill_php', function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				if ( ajax.responseText == '1' )
				{
					var $killdiv = $dynano('php_killer');
					//$killdiv.object.innerHTML = '<img alt="Success" src="' + scriptPath + '/images/error.png" /><br />Embedded PHP in pages has been disabled.';
					$killdiv.object.parentNode.removeChild($killdiv.object);
					var newdiv = document.createElement('div');
					// newdiv.style = $killdiv.object.style;
					newdiv.className = $killdiv.object.className;
					newdiv.innerHTML = '<img alt="Success" src="' + scriptPath + '/images/error.png" /><br />' + $lang.get('ajax_killphp_success');
					$killdiv.object.parentNode.appendChild(newdiv);
					$killdiv.object.parentNode.removeChild($killdiv.object);
				}
				else
				{
					var $killdiv = $dynano('php_killer');
					$killdiv.object.innerHTML = ajax.responseText;
				}
			}
		});
}

var catHTMLBuf = false;

window.ajaxCatToTag = function()
{
	if ( KILL_SWITCH )
		return false;
	setAjaxLoading();
	ajaxGet(stdAjaxPrefix + '&_mode=get_tags', function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				unsetAjaxLoading();
				var resptext = String(ajax.responseText + ' ');
				resptext = resptext.substr(0, resptext.length-1);
				if ( resptext.substr(0, 1) != '{' )
				{
					handle_invalid_json(resptext);
					return false;
				}
				var json = parseJSON(resptext);
				var catbox = document.getElementById('mdgCatBox');
				if ( !catbox )
					return false;
				var linkbox = catbox.parentNode.firstChild.firstChild.nextSibling;
				linkbox.firstChild.nodeValue = $lang.get('catedit_catbox_link_showcategorization');
				linkbox.onclick = function() { ajaxTagToCat(); return false; };
				catHTMLBuf = catbox.innerHTML;
				catbox.innerHTML = '';
				catbox.appendChild(document.createTextNode($lang.get('tags_lbl_page_tags')+' '));
				if ( json.tags.length < 1 )
				{
					catbox.appendChild(document.createTextNode($lang.get('tags_lbl_no_tags')));
				}
				for ( var i = 0; i < json.tags.length; i++ )
				{
					catbox.appendChild(document.createTextNode(json.tags[i].name));
					if ( json.tags[i].can_del )
					{
						catbox.appendChild(document.createTextNode(' '));
						var a = document.createElement('a');
						a.appendChild(document.createTextNode('[X]'));
						a.href = '#';
						a._js_tag_id = json.tags[i].id;
						a.onclick = function() { ajaxDeleteTag(this, this._js_tag_id); return false; }
						catbox.appendChild(a);
					}
					if ( ( i + 1 ) < json.tags.length )
						catbox.appendChild(document.createTextNode(', '));
				}
				if ( json.can_add )
				{
					catbox.appendChild(document.createTextNode(' '));
					var addlink = document.createElement('a');
					addlink.href = '#';
					addlink.onclick = function() { try { ajaxAddTagStage1(); } catch(e) { }; return false; };
					addlink.appendChild(document.createTextNode($lang.get('tags_btn_add_tag')));
					catbox.appendChild(addlink);
				}
			}
		});
}

var addtag_open = false;

window.ajaxAddTagStage1 = function()
{
	if ( addtag_open )
		return false;
	var catbox = document.getElementById('mdgCatBox');
	var adddiv = document.createElement('div');
	var text = document.createElement('input');
	var addlink = document.createElement('a');
	addlink.href = '#';
	addlink.onclick = function() { ajaxAddTagStage2(this.parentNode.firstChild.nextSibling.value, this.parentNode); return false; };
	addlink.appendChild(document.createTextNode($lang.get('tags_btn_add')));
	text.type = 'text';
	text.size = '15';
	text.onkeyup = function(e)
	{
		if ( e.keyCode == 13 )
		{
			ajaxAddTagStage2(this.value, this.parentNode);
		}
	}
	
	adddiv.style.margin = '5px 0 0 0';
	adddiv.appendChild(document.createTextNode($lang.get('tags_lbl_add_tag')+' '));
	adddiv.appendChild(text);
	adddiv.appendChild(document.createTextNode(' '));
	adddiv.appendChild(addlink);
	catbox.appendChild(adddiv);
	addtag_open = true;
}

var addtag_nukeme = false;

window.ajaxAddTagStage2 = function(tag, nukeme)
{
	if ( !addtag_open )
		return false;
	if ( addtag_nukeme )
		return false;
	addtag_nukeme = nukeme;
	tag = ajaxEscape(tag);
	setAjaxLoading();
	ajaxPost(stdAjaxPrefix + '&_mode=addtag', 'tag=' + tag, function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				unsetAjaxLoading();
				var nukeme = addtag_nukeme;
				addtag_nukeme = false;
				var resptext = String(ajax.responseText + ' ');
				resptext = resptext.substr(0, resptext.length-1);
				if ( resptext.substr(0, 1) != '{' )
				{
					handle_invalid_json(resptext);
					return false;
				}
				var json = parseJSON(resptext);
				var parent = nukeme.parentNode;
				parent.removeChild(nukeme);
				addtag_open = false;
				if ( json.success )
				{
					var node = parent.childNodes[1];
					var insertafter = false;
					var nukeafter = false;
					if ( node.nodeValue == $lang.get('tags_lbl_no_tags') )
					{
						nukeafter = true;
					}
					insertafter = parent.childNodes[ parent.childNodes.length - 3 ];
					// these need to be inserted in reverse order
					if ( json.can_del )
					{
						var a = document.createElement('a');
						a.appendChild(document.createTextNode('[X]'));
						a.href = '#';
						a._js_tag_id = json.tag_id;
						a.onclick = function() { ajaxDeleteTag(this, this._js_tag_id); return false; }
						insertAfter(parent, a, insertafter);
						insertAfter(parent, document.createTextNode(' '), insertafter);
					}
					insertAfter(parent, document.createTextNode(json.tag), insertafter);
					if ( !nukeafter )
					{
						insertAfter(parent, document.createTextNode(', '), insertafter);
					}
					if ( nukeafter )
					{
						parent.removeChild(insertafter);
					}
				}
				else
				{
					alert(json.error);
				}
			}
		});
}

window.ajaxDeleteTag = function(parentobj, tag_id)
{
	var arrDelete = [ parentobj, parentobj.previousSibling, parentobj.previousSibling.previousSibling ];
	var parent = parentobj.parentNode;
	var writeNoTags = false;
	if ( parentobj.previousSibling.previousSibling.previousSibling.nodeValue == ', ' )
		arrDelete.push(parentobj.previousSibling.previousSibling.previousSibling);
	else if ( parentobj.previousSibling.previousSibling.previousSibling.nodeValue == $lang.get('tags_lbl_page_tags') + ' ' )
		arrDelete.push(parentobj.nextSibling);
	
	if ( parentobj.previousSibling.previousSibling.previousSibling.nodeValue == $lang.get('tags_lbl_page_tags') + ' ' &&
 			parentobj.nextSibling.nextSibling.firstChild )
		if ( parentobj.nextSibling.nextSibling.firstChild.nodeValue == $lang.get('tags_btn_add_tag'))
			writeNoTags = true;
		
	ajaxPost(stdAjaxPrefix + '&_mode=deltag', 'tag_id=' + String(tag_id), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				if ( ajax.responseText == 'success' )
				{
					for ( var i = 0; i < arrDelete.length; i++ )
					{
						try
						{
							parent.removeChild(arrDelete[i]);
						} catch(e) {}
					}
					if ( writeNoTags )
					{
						var node1 = document.createTextNode($lang.get('tags_lbl_no_tags'));
						var node2 = document.createTextNode(' ');
						insertAfter(parent, node1, parent.firstChild);
						insertAfter(parent, node2, node1);
					}
				}
				else
				{
					alert(ajax.responseText);
				}
			}
		});
}

window.ajaxTagToCat = function()
{
	if ( !catHTMLBuf )
		return false;
	var catbox = document.getElementById('mdgCatBox');
	if ( !catbox )
		return false;
	addtag_open = false;
	var linkbox = catbox.parentNode.firstChild.firstChild.nextSibling;
	linkbox.firstChild.nodeValue = $lang.get('tags_catbox_link');
	linkbox.onclick = function() { ajaxCatToTag(); return false; };
	catbox.innerHTML = catHTMLBuf;
	catHTMLBuf = false;
}

var keepalive_interval = false;

window.ajaxPingServer = function()
{
	ajaxGet(stdAjaxPrefix + '&_mode=ping', function(ajax)
		{
		});
}

window.ajaxToggleKeepalive = function()
{
	if ( readCookie('admin_keepalive') == '1' )
	{
		createCookie('admin_keepalive', '0', 3650);
		if ( keepalive_interval )
			clearInterval(keepalive_interval);
		var span = document.getElementById('keepalivestat');
		span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_off');
	}
	else
	{
		createCookie('admin_keepalive', '1', 3650);
		if ( !keepalive_interval )
			keepalive_interval = setInterval('ajaxPingServer();', 600000);
		var span = document.getElementById('keepalivestat');
		span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_on');
		ajaxPingServer();
	}
}

var keepalive_onload = function()
{
	if ( readCookie('admin_keepalive') == '1' )
	{
		if ( !keepalive_interval )
			keepalive_interval = setInterval('ajaxPingServer();', 600000);
		var span = document.getElementById('keepalivestat');
		span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_on');
	}
	else
	{
		if ( keepalive_interval )
			clearInterval(keepalive_interval);
		var span = document.getElementById('keepalivestat');
		span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_off');
	}
};

window.aboutKeepAlive = function()
{
	load_component(['messagebox', 'flyin', 'fadefilter']);
	new MessageBox(MB_OK|MB_ICONINFORMATION, $lang.get('user_keepalive_info_title'), $lang.get('user_keepalive_info_body'));
}

window.ajaxUpdateCheck = function(targetelement)
{
	if ( !document.getElementById(targetelement) )
	{
		return false;
	}
	var target = document.getElementById(targetelement);
	target.innerHTML = '';
	var img = document.createElement('img');
	img.src = cdnPath + '/images/loading.gif';
	img.alt = 'Loading...';
	target.appendChild(img);
	ajaxGet(makeUrlNS('Admin', 'Home/updates.xml'), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				var releases = new Array();
				var update_available = false;
				if ( ajax.responseXML == null )
				{
					alert("Error fetching updates list:\n" + ajax.responseText);
					return false;
				}
				if ( ajax.responseXML.firstChild.tagName == 'enano' )
				{
					var enanotag = ajax.responseXML.firstChild;
					for ( var i = 0; i < enanotag.childNodes.length; i++ )
					{
						if ( enanotag.childNodes[i].tagName == 'error' )
						{
							alert(enanotag.childNodes[i].firstChild.nodeValue);
						}
						else if ( enanotag.childNodes[i].tagName == 'latest' )
						{
							// got <latest>
							var latesttag = enanotag.childNodes[i];
							for ( var j = 0; j < latesttag.childNodes.length; j++ )
							{
								var node = latesttag.childNodes[j];
								if ( node.tagName == 'release' )
								{
									var releasedata = new Object();
									for ( var k = 0; k < node.attributes.length; k++ )
									{
										releasedata[node.attributes[k].nodeName] = node.attributes[k].nodeValue;
									}
									releases.push(releasedata);
								}
								else if ( node.tagName == 'haveupdates' )
								{
									update_available = true;
								}
							}
							break;
						}
					}
				}
				else
				{
					return false;
				}
				var thediv = document.getElementById(targetelement);
				thediv.innerHTML = '';
				if ( !thediv )
				{
					return false;
				}
				if ( releases.length > 0 )
				{
					thediv.className = 'tblholder';
					// FIXME: l10n
					if ( update_available )
					{
						var infobox = document.createElement('div');
						infobox.className = 'info-box-mini';
						infobox.appendChild(document.createTextNode('An update for Enano is available. The newest release is highlighted below.'));
						infobox.style.borderWidth = '0';
						infobox.style.margin = '0 0 0 0';
						thediv.appendChild(infobox);
					}
					else
					{
						var infobox = document.createElement('div');
						infobox.className = 'info-box-mini';
						infobox.appendChild(document.createTextNode('No new updates are available. The latest available releases are shown below.'));
						infobox.style.borderWidth = '0';
						infobox.style.margin = '0 0 0 0';
						thediv.appendChild(infobox);
					}
					var table = document.createElement('table');
					table.setAttribute('border', '0');
					table.setAttribute('cellspacing', '1');
					table.setAttribute('cellpadding', '4');
					
					var tr = document.createElement('tr');
					
					var td1 = document.createElement('th');
					var td2 = document.createElement('th');
					var td3 = document.createElement('th');
					var td4 = document.createElement('th');
					
					// FIXME: l10n
					td1.appendChild( document.createTextNode('Release type') );
					td2.appendChild( document.createTextNode('Version') );
					td3.appendChild( document.createTextNode('Code name') );
					td4.appendChild( document.createTextNode('Release notes') );
					
					tr.appendChild(td1);
					tr.appendChild(td2);
					tr.appendChild(td3);
					tr.appendChild(td4);
						
					table.appendChild(tr);
					
					var cls = 'row2';
					
					var j = 0;
					for ( var i in releases )
					{
						j++;
						if ( j > 5 )
							break;
						if ( update_available && j == 1 )
							cls = 'row1_green';
						else
							cls = ( cls == 'row1' ) ? 'row2' : 'row1';
						var release = releases[i];
						var tr = document.createElement('tr');
						
						var td1 = document.createElement('td');
						var td2 = document.createElement('td');
						var td3 = document.createElement('td');
						var td4 = document.createElement('td');
						
						td1.className = cls;
						td2.className = cls;
						td3.className = cls;
						td4.className = cls;
						
						if ( release.tag )
							td1.appendChild( document.createTextNode(release.tag) );
						
						if ( release.version )
							td2.appendChild( document.createTextNode(release.version) );
						
						if ( release.codename )
							td3.appendChild( document.createTextNode(release.codename) );
						
						if ( release.relnotes )
						{
							var a = document.createElement('a');
							a.href = release.relnotes;
							a.appendChild(document.createTextNode('View'));
							td4.appendChild( a );
						}
						
						tr.appendChild(td1);
						tr.appendChild(td2);
						tr.appendChild(td3);
						tr.appendChild(td4);
						
						table.appendChild(tr);
					}
					thediv.appendChild(table);
				}
				else
				{
					thediv.appendChild(document.createTextNode('No releases available.'));
				}
			}
		});
}

window.ajaxPluginAction = function(action, plugin_filename, btnobj, send_confirm)
{
	// if installing, uninstalling, or re-importing, confirm
	if ( action == 'install' || action == 'uninstall' || action == 'reimport' )
	{
		var prompt = miniPrompt(function(div)
			{
				var txtholder = document.createElement('div');
				txtholder.style.textAlign = 'center';
				txtholder.appendChild(document.createTextNode($lang.get('acppl_msg_confirm_' + action)));
				txtholder.appendChild(document.createElement('br'));
				txtholder.appendChild(document.createElement('br'));
				
				// create buttons
				var btn_go = document.createElement('a');
				btn_go.className = 'abutton abutton_red';
				btn_go.href = '#';
				btn_go._action = action;
				btn_go._filename = plugin_filename;
				btn_go._button = btnobj;
				btn_go.appendChild(document.createTextNode($lang.get('acppl_btn_' + action)));
				btn_go.style.fontWeight = 'bold';
				txtholder.appendChild(btn_go);
				
				// space
				txtholder.appendChild(document.createTextNode(' '));
				
				// cancel
				var btn_cancel = document.createElement('a');
				btn_cancel.className = 'abutton abutton_blue';
				btn_cancel.href = '#';
				btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
				
				txtholder.appendChild(btn_cancel);
				div.appendChild(txtholder);
				
				btn_go.onclick = function()
				{
					ajaxPluginAction(this._action + '_confirm', this._filename, this._button);
					miniPromptDestroy(this);
					return false;
				};
				btn_cancel.onclick = function()
				{
					miniPromptDestroy(this);
					return false;
				};
			});
		return true;
	}
	action = action.replace(/_confirm$/, '');
	// white-out the plugin info box
	if ( btnobj )
	{
		var td = btnobj.parentNode.parentNode.parentNode.parentNode;
		var blackbox = whiteOutElement(td);
	}
	var request = {
			mode: action,
			plugin: plugin_filename
		};
	if ( send_confirm )
	{
		request.install_confirmed = true;
	}
	request = toJSONString(request);
	ajaxPost(makeUrlNS('Admin', 'PluginManager/action.json'), 'r=' + ajaxEscape(request), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				var response = String(ajax.responseText + '');
				if ( !check_json_response(response) )
				{
					handle_invalid_json(response);
					return false;
				}
				response = parseJSON(response);
				if ( blackbox )
				{
					blackbox.parentNode.removeChild(blackbox);
				}
				if ( response.success )
				{
					ajaxPage( namespace_list['Admin'] + 'PluginManager' );
					return true;
				}
				if ( response.need_confirm )
				{
					miniPromptMessage({
							title: $lang.get(response.confirm_title),
							message: $lang.get(response.confirm_body),
							buttons: [
								{
									text: $lang.get('acppl_btn_install'),
									color: 'red',
									style: {
										fontWeight: 'bold'
									},
									onclick: function() {
										ajaxPluginAction(action + '_confirm', plugin_filename, btnobj, true);
										miniPromptDestroy(this);
									}
								},
								{
									text: $lang.get('etc_cancel'),
									color: 'blue',
									onclick: function() {
										miniPromptDestroy(this);
									}
								}
							]
						});
					return true;
				}
				// wait for fade effect to finish its run
				setTimeout(function()
					{
						miniPrompt(function(div)
							{
								if ( blackbox )
								{
									blackbox.parentNode.removeChild(blackbox);
								}
								var txtholder = document.createElement('div');
								txtholder.style.textAlign = 'center';
								txtholder.appendChild(document.createTextNode(response.error));
								txtholder.appendChild(document.createElement('br'));
								txtholder.appendChild(document.createElement('br'));
								
								// close button
								var btn_cancel = document.createElement('a');
								btn_cancel.className = 'abutton abutton_red';
								btn_cancel.href = '#';
								btn_cancel.appendChild(document.createTextNode($lang.get('etc_ok')));
								
								txtholder.appendChild(btn_cancel);
								div.appendChild(txtholder);
								
								btn_cancel.onclick = function()
								{
									miniPromptDestroy(this);
									return false;
								}
							});
					}, 750);
			}
		});
}

window.ajaxReverseDNS = function(o, text)
{
	if(text) var ipaddr = text;
	else var ipaddr = o.innerHTML;
	rDnsObj = o;
	rDnsBannerObj = bannerOn('Retrieving reverse DNS info...');
	ajaxGet(stdAjaxPrefix+'&_mode=rdns&ip='+ipaddr, function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				off = fetch_offset(rDnsObj);
				dim = fetch_dimensions(rDnsObj);
				right = off['left'] + dim['w'];
				top = off['top'] + dim['h'];
				var thediv = document.createElement('div');
				thediv.className = 'info-box';
				thediv.style.margin = '0';
				thediv.style.position = 'absolute';
				thediv.style.top  = top  + 'px';
				thediv.style.display = 'none';
				thediv.style.zIndex = getHighestZ() + 2;
				thediv.id = 'mdgDynamic_rDnsInfoDiv_'+Math.floor(Math.random() * 1000000);
				// FIXME: l10n
				thediv.innerHTML = '<b>Reverse DNS:</b><br />'+ajax.responseText+' <a href="#" onclick="elem = document.getElementById(\''+thediv.id+'\'); elem.innerHTML = \'\'; elem.style.display = \'none\';return false;">Close</a>';
				var body = document.getElementsByTagName('body');
				body = body[0];
				bannerOff(rDnsBannerObj);
				body.appendChild(thediv);
				thediv.style.display = 'block';
				left = fetch_dimensions(thediv);
				thediv.style.display = 'none';
				left = right - left['w'];
				thediv.style.left = left + 'px';
				thediv.style.display = 'block';
				fadeInfoBoxes();
			}
		});
}

window.ajaxGzipCheck = function()
{
	var resultdiv = document.getElementById('gzip_check_result');
	if ( !resultdiv )
		return false;
	
	resultdiv.innerHTML = '<img alt="Loading..." src="' + cdnPath + '/images/loading.gif" />';
	ajaxPost(makeUrlNS('Admin', 'GeneralConfig'), 'act=gzip_check', function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				resultdiv.innerHTML = '';
				var response = String(ajax.responseText + '');
				if ( !check_json_response(response) )
				{
					handle_invalid_json(response);
					return false;
				}
				response = parseJSON(response);
				if ( response.error )
				{
					resultdiv.innerHTML = '<div class="error-box-mini">' + response.error + '</div>';
				}
				else
				{
					// probably success.
					resultdiv.innerHTML += response.server_does_it ?
						'<div class="error-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_server_does_it') + '</div>' :
						'<div class="info-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_server_good') + '</div>';
					resultdiv.innerHTML += response.php_supports_gzip ?
						'<div class="info-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_php_good') + '</div>' :
						'<div class="error-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_php_bad') + '</div>';
						
					if ( response.php_supports_gzip && !response.server_does_it )
					{
						resultdiv.innerHTML += '<div class="success-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_success') + '</div>';
					}
					else
					{
						resultdiv.innerHTML += '<div class="error-box-mini">' + $lang.get('acpgc_field_gzip_check_msg_failure') + '</div>';
					}
				}
			}
		});
}

window.ajaxVerifyFilePath = function(input)
{
	input._lastkeyup = new Date();
	// 500ms between keyup and trigger
	setTimeout(function()
		{
			var now = new Date();
			if ( input._lastkeyup.getTime() + 499 < now.getTime() )
			{
				// do the ajaxverify
				ajaxVerifyFilePathReal(input);
			}
		}, 500);
}

window.ajaxVerifyFilePathReal = function(input)
{
	if ( input.nextSibling && input.nextSibling.tagName == 'IMG' )
		input.parentNode.removeChild(input.nextSibling);
	var img = document.createElement('img');
	img.src = cdnPath + '/images/loading.gif';
	img.hspace = '7';
	ajaxPost(makeUrlNS('Admin', 'UploadConfig', 'act=verify_path'), 'path=' + ajaxEscape(input.value), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				img.src = ( ajax.responseText == 'true' ) ? cdnPath + '/images/mini-success.png' : cdnPath + '/images/mini-error.png';
			}
		});
	insertAfter(input.parentNode, img, input);
}