includes/clientside/static/acl.js
author Dan Fuhry <dan@enanocms.org>
Thu, 28 Oct 2010 03:05:31 -0400
changeset 1308 f9bee9b125ee
parent 1227 bdac73ed481e
permissions -rw-r--r--
Parser updates. Added the "styled" keyword to wikitables to allow them to be styled using the current theme's standard table skinning, and changes to how the image tag parser decides how to display an image (framed, inline or raw).

// Javascript routines for the ACL editor

var aclManagerID = 'enano_aclmanager_' + Math.floor(Math.random() * 1000000);
var aclPermList = false;
var aclDataCache = false;

function ajaxOpenACLManager(page_id, namespace)
{
	// touch these to make them available to child functions
	void(page_id);
	void(namespace);
	
	// require re-auth
	if ( auth_level <= USER_LEVEL_MEMBER )
	{
		load_component(['login', 'fadefilter', 'flyin', 'jquery', 'jquery-ui', 'crypto', 'messagebox']);
		ajaxDynamicReauth(function(key)
			{
				ajaxOpenACLManager(page_id, namespace);
			}, user_level);
		
		return false;
	}
	
	load_component(['l10n', 'messagebox', 'fadefilter', 'template-compiler', 'jquery', 'jquery-ui', 'autofill']);
	
	if(!page_id || !namespace)
	{
		var data = strToPageID(title);
		var page_id = data[0];
		var namespace = data[1];
	}
	var params = {
			'mode' : 'listgroups',
			'page_id' : page_id,
			'namespace' : namespace
		};
	params = toJSONString(params);
	params = ajaxEscape(params);
	ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				var response = String(ajax.responseText + '');
				if ( !check_json_response(response) )
				{
					handle_invalid_json(ajax.responseText);
					return false;
				}
				try {
					var groups = parseJSON(ajax.responseText);
				} catch(e) {
					handle_invalid_json(ajax.responseText);
				}
				__aclBuildWizardWindow();
				if ( groups.mode == 'error' )
				{
					alert(groups.error);
					killACLManager();
					return false;
				}
				aclDataCache = groups;
				__aclBuildSelector(groups);
			}
		}, true);
	return false;
}

function ajaxOpenDirectACLRule(rule_id)
{
	load_component(['l10n', 'messagebox', 'fadefilter', 'template-compiler', 'autofill']);
	
	var params = {
		target_id: rule_id,
		mode: 'seltarget_id'
	};
	params = ajaxEscape(toJSONString(params));
	ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				var response = String(ajax.responseText + '');
				if ( !check_json_response(response) )
				{
					handle_invalid_json(ajax.responseText);
					return false;
				}
				try
				{
					response = parseJSON(response);
				}
				catch(e)
				{
					handle_invalid_json(response);
				}
				if ( !document.getElementById(aclManagerID) )
				{
					__aclBuildWizardWindow();
					var main = document.getElementById(aclManagerID + '_main');
					main.style.padding = '10px';
				}
				else
				{
					var main = document.getElementById(aclManagerID + '_main');
					main.style.backgroundImage = 'none';
				}
				if ( response.mode == 'error' )
				{
					alert(response.error);
					killACLManager();
					return false;
				}
				aclDataCache = response;
				aclBuildRuleEditor(response, true);
			}
		}, true);
}

function ajaxACLSwitchToSelector()
{
	params = {
			'mode' : 'listgroups'
		};
	if ( aclDataCache.page_id && aclDataCache.namespace )
	{
		params.page_id   = aclDataCache.page_id;
		params.namespace = aclDataCache.namespace;
	}
	params = toJSONString(params);
	params = ajaxEscape(params);
	ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				document.getElementById(aclManagerID+'_main').innerHTML = '';
				document.getElementById(aclManagerID + '_back').style.display = 'none';
				document.getElementById(aclManagerID + '_next').value = $lang.get('etc_wizard_next');
				var groups = parseJSON(ajax.responseText);
				if ( groups.mode == 'error' )
				{
					alert(groups.error);
					killACLManager();
					return false;
				}
				aclDataCache = groups;
				thispage = strToPageID(title);
				groups.page_id = thispage[0];
				groups.namespace = thispage[1];
				__aclBuildSelector(groups);
			}
		}, true);
}

function __aclBuildSelector(groups)
{
	thispage = strToPageID(title);
	do_scopesel = ( thispage[0] == groups.page_id && thispage[1] == groups.namespace );
	
	document.getElementById(aclManagerID + '_next').style.display = 'inline';
	
	seed = Math.floor(Math.random() * 1000000);
				
	main = document.getElementById(aclManagerID + '_main');
	main.style.padding = '10px';
	main.style.backgroundImage = 'none';
	
	// the "edit existing" button
	var editbtn_wrapper = document.createElement('div');
	editbtn_wrapper.style.styleFloat = 'right';
	editbtn_wrapper.style.cssFloat = 'right';
	editbtn_wrapper.style.fontSize = 'smaller';
	var editbtn = document.createElement('a');
	editbtn.href = '#';
	editbtn.innerHTML = $lang.get('acl_btn_show_existing');
	editbtn_wrapper.appendChild(editbtn);
	
	// tracer button
	var tracebtn = document.createElement('a');
	tracebtn.href = '#';
	tracebtn.innerHTML = $lang.get('acl_btn_view_effective');
	editbtn_wrapper.appendChild(document.createElement('br'));
	editbtn_wrapper.appendChild(tracebtn);
	
	main.appendChild(editbtn_wrapper);
	
	editbtn.onclick = function()
	{
		aclSetViewListExisting();
		return false;
	}
	
	tracebtn.onclick = function()
	{
		aclSetViewDebugTools();
		return false;
	}
	
	selector = document.createElement('div');
	
	var grpsel = __aclBuildGroupsHTML(groups);
	grpsel.name = 'group_id';
	
	span = document.createElement('div');
	span.id = "enACL_grpbox_"+seed+"";
	
	// Build the selector
	grpb = document.createElement('input');
	grpb.type = 'radio';
	grpb.name  = 'target_type';
	grpb.value = '1'; // ACL_TYPE_GROUP
	grpb.checked = 'checked';
	grpb.className = seed;
	grpb.onclick = function() { seed = this.className; document.getElementById('enACL_grpbox_'+seed).style.display = 'block'; document.getElementById('enACL_usrbox_'+seed).style.display = 'none'; };
	lbl = document.createElement('label');
	lbl.appendChild(grpb);
	lbl.appendChild(document.createTextNode($lang.get('acl_radio_usergroup')));
	lbl.style.display = 'block';
	span.appendChild(grpsel);
	
	anoninfo = document.createElement('div');
	anoninfo.className = 'info-box-mini';
	anoninfo.appendChild(document.createTextNode($lang.get('acl_msg_guest_howto')));
	span.appendChild(document.createElement('br'));
	span.appendChild(anoninfo);
	
	usrb = document.createElement('input');
	usrb.type = 'radio';
	usrb.name  = 'target_type';
	usrb.value = '2'; // ACL_TYPE_USER
	usrb.className = seed;
	usrb.onclick = function() { seed = this.className; document.getElementById('enACL_grpbox_'+seed).style.display = 'none'; document.getElementById('enACL_usrbox_'+seed).style.display = 'block'; };
	lbl2 = document.createElement('label');
	lbl2.appendChild(usrb);
	lbl2.appendChild(document.createTextNode($lang.get('acl_radio_user')));
	lbl2.style.display = 'block';
	
	usrsel = document.createElement('input');
	usrsel.type = 'text';
	usrsel.name = 'username';
	usrsel.className = 'autofill username';
	usrsel.id = 'userfield_' + aclManagerID;
	try {
		usrsel.setAttribute("autocomplete","off");
	} catch(e) {};
	
	span2 = document.createElement('div');
	span2.id = "enACL_usrbox_"+seed+"";
	span2.style.display = 'none';
	span2.appendChild(usrsel);
	
	// Scope selector
	if(do_scopesel)
	{
		scopediv1 = document.createElement('div');
		scopediv2 = document.createElement('div');
		scopediv3 = document.createElement('div');
		scopeRadioPage = document.createElement('input');
			scopeRadioPage.type = 'radio';
			scopeRadioPage.name = 'scope';
			scopeRadioPage.value = 'page';
			scopeRadioPage.checked = 'checked';
			scopeRadioPage.className = '1048576';
			if ( groups.page_groups.length > 0 ) scopeRadioPage.onclick = function() { var id = 'enACL_pgsel_' + this.className; document.getElementById(id).style.display = 'none'; };
		scopeRadioGlobal = document.createElement('input');
			scopeRadioGlobal.type = 'radio';
			scopeRadioGlobal.name = 'scope';
			scopeRadioGlobal.value = 'global';
			scopeRadioGlobal.className = '1048576';
			if ( groups.page_groups.length > 0 ) scopeRadioGlobal.onclick = function() { var id = 'enACL_pgsel_' + this.className; document.getElementById(id).style.display = 'none'; };
		scopeRadioGroup = document.createElement('input');
			scopeRadioGroup.type = 'radio';
			scopeRadioGroup.name = 'scope';
			scopeRadioGroup.value = 'group';
			scopeRadioGroup.className = '1048576';
			if ( groups.page_groups.length > 0 ) scopeRadioGroup.onclick = function() { var id = 'enACL_pgsel_' + this.className; document.getElementById(id).style.display = 'block'; };
		lblPage = document.createElement('label');
			lblPage.style.display = 'block';
			lblPage.appendChild(scopeRadioPage);
			lblPage.appendChild(document.createTextNode($lang.get('acl_radio_scope_thispage')));
		lblGlobal = document.createElement('label');
			lblGlobal.style.display = 'block';
			lblGlobal.appendChild(scopeRadioGlobal);
			lblGlobal.appendChild(document.createTextNode($lang.get('acl_radio_scope_wholesite')));
		lblGroup = document.createElement('label');
			lblGroup.style.display = 'block';
			lblGroup.appendChild(scopeRadioGroup);
			lblGroup.appendChild(document.createTextNode($lang.get('acl_radio_scope_pagegroup')));
		scopediv1.appendChild(lblPage);
		scopediv2.appendChild(lblGroup);
		scopediv3.appendChild(lblGlobal);
		
		scopedesc = document.createElement('p');
		scopedesc.appendChild(document.createTextNode($lang.get('acl_lbl_scope')));
		
		scopePGrp = document.createElement('select');
		scopePGrp.style.marginLeft = '13px';
		scopePGrp.style.display = 'none';
		scopePGrp.id = "enACL_pgsel_1048576";
		
		var opt;
		for ( var i = 0; i < groups.page_groups.length; i++ )
		{
			opt = document.createElement('option');
			opt.value = groups.page_groups[i].id;
			opt.appendChild(document.createTextNode(groups.page_groups[i].name));
			scopePGrp.appendChild(opt);
		}
		
		scopediv2.appendChild(scopePGrp);
		
	}
	
	// Styles
	span.style.marginLeft = '13px';
	span.style.padding = '5px 0';
	span2.style.marginLeft = '13px';
	span2.style.padding = '5px 0';
	
	selector.appendChild(lbl);
	selector.appendChild(span);
	
	selector.appendChild(lbl2);
	selector.appendChild(span2);
	
	container = document.createElement('div');
	container.style.margin = 'auto';
	container.style.width = '360px';
	container.style.paddingTop = '50px';
	
	head = document.createElement('h2');
	head.appendChild(document.createTextNode($lang.get('acl_lbl_welcome_title')));
	
	desc = document.createElement('p');
	desc.appendChild(document.createTextNode($lang.get('acl_lbl_welcome_body')));
	
	container.appendChild(head);
	container.appendChild(desc);
	container.appendChild(selector);
	
	if(do_scopesel)
	{
		container.appendChild(scopedesc);
		container.appendChild(scopediv1);
		if ( groups.page_groups.length > 0 )
		{
			container.appendChild(scopediv2);
		}
		container.appendChild(scopediv3);
	}
	
	main.appendChild(container);
	
	var mode = document.createElement('input');
	mode.name = 'mode';
	mode.type = 'hidden';
	mode.id = aclManagerID + '_mode';
	mode.value = 'seltarget';
	
	var theform = document.getElementById(aclManagerID + '_formobj_id');
	if ( !theform.mode )
	{
		theform.appendChild(mode);
	}
	else
	{
		theform.removeChild(theform.mode);
		theform.appendChild(mode);
	}
	
	autofill_init_element(usrsel, {
			allow_anon: true
		});
}

var aclDebugWin = false;

function aclDebug(text)
{
	if(!aclDebugWin)
		aclDebugWin = pseudoWindowOpen("data:text/html;plain,<html><head><title>debug win</title></head><body><h1>Debug window</h1></body></html>", "aclDebugWin");
		setTimeout(function() {
	aclDebugWin.pre = aclDebugWin.document.createElement('pre');
	aclDebugWin.pre.appendChild(aclDebugWin.document.createTextNode(text));
	aclDebugWin.b = aclDebugWin.document.getElementsByTagName('body')[0];
		aclDebugWin.b.appendChild(aclDebugWin.pre);}, 1000);
}

var pseudoWindows = new Object();

function pseudoWindowOpen(url, id)
{
	if(pseudoWindows[id])
	{
		document.getElementById('pseudowin_ifr_'+id).src = url;
	}
	else
	{
		win = document.createElement('iframe');
		win.style.position='fixed';
		win.style.width = '640px';
		win.style.height = '480px';
		win.style.top = '0px';
		win.style.left = '0px';
		win.style.zIndex = getHighestZ() + 1;
		win.style.backgroundColor = '#FFFFFF';
		win.name = 'pseudo_ifr_'+id;
		win.id = 'pseudowindow_ifr_'+id;
		win.src = url;
		body = document.getElementsByTagName('body')[0];
		body.appendChild(win);
	}
	win_obj = eval("( pseudo_ifr_"+id+" )");
	return win_obj;
}

function __aclJSONSubmitAjaxHandler(params)
{
	params = toJSONString(params);
	params = ajaxEscape(params);
	ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function(ajax) {
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				var response = String(ajax.responseText + '');
				if ( !check_json_response(response) )
				{
					handle_invalid_json(ajax.responseText);
					return false;
				}
				try
				{
					var data = parseJSON(ajax.responseText);
				}
				catch(e)
				{
					handle_invalid_json(ajax.responseText);
					return false;
				}
				aclDataCache = data;
				switch(data.mode)
				{
					case 'seltarget':
						
						// Build the ACL edit form
						aclBuildRuleEditor(data);
						
						break;
					case 'success':
						var note = document.createElement('div');
						note.className = 'info-box';
						note.style.marginLeft = '0';
						var b = document.createElement('b');
						b.appendChild(document.createTextNode($lang.get('acl_lbl_save_success_title')));
						note.appendChild(b);
						note.appendChild(document.createElement('br'));
						note.appendChild(document.createTextNode($lang.get('acl_lbl_save_success_body', { target_name: data.target_name })));
						note.appendChild(document.createElement('br'));
						
						/*
						var a = document.createElement('a');
						a.href = '#';
						a.id = aclManagerID + '_btn_dismiss';
						a.appendChild(document.createTextNode('[ ' + $lang.get('acl_btn_success_dismiss') + ' :'));
						note.appendChild(a);
						var a2 = document.createElement('a');
						a2.href = '#';
						a.id = aclManagerID + '_btn_close';
						a2.appendChild(document.createTextNode(': ' + $lang.get('acl_btn_success_close') + ' ]'));
						note.appendChild(a2);
						*/
						
						var a_dismiss = document.createElement('a');
						a_dismiss.href = '#';
						a_dismiss.appendChild(document.createTextNode('[ ' + $lang.get('acl_btn_success_dismiss') + ' :'));
						note.appendChild(a_dismiss);
						
						var a_close = document.createElement('a');
						a_close.href = '#';
						a_close.appendChild(document.createTextNode(': ' + $lang.get('acl_btn_success_close') + ' ]'));
						note.appendChild(a_close);
						
						document.getElementById(aclManagerID + '_main').insertBefore(note, document.getElementById(aclManagerID + '_main').firstChild);
						
						a_dismiss.setAttribute('onclick', 'var parent = this.parentNode.parentNode; parent.removeChild(this.parentNode); return false;');
						a_close.setAttribute('onclick', 'killACLManager(); return false;');
						
						if ( !document.getElementById(aclManagerID+'_deletelnk') )
						{
							var p = document.createElement('p');
							p.innerHTML = '<a href="#delete_acl_rule" onclick="if(confirm(\'' + $lang.get('acl_msg_deleterule_confirm') + '\')) __aclDeleteRule(); return false;" style="color: red;">' + $lang.get('acl_lbl_deleterule') + '</a>';
							p.id = aclManagerID + '_deletelnk';
							p.style.textAlign = 'right';
							
							document.getElementById(aclManagerID + '_main').appendChild(p);
						}
						
						document.getElementById(aclManagerID+'_main').scrollTop = 0;
						document.getElementById(aclManagerID+'_main').style.backgroundImage = 'none';
												
						aclDataCache.mode = 'save_edit';
						break;
					case 'delete':
						
						params = {
							'mode' : 'listgroups'
						};
					params = toJSONString(params);
					params = ajaxEscape(params);
					ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function(ajax) {
							if ( ajax.readyState == 4 && ajax.status == 200 )
							{
								document.getElementById(aclManagerID+'_main').innerHTML = '';
								document.getElementById(aclManagerID + '_back').style.display = 'none';
								document.getElementById(aclManagerID + '_next').value = $lang.get('etc_wizard_next');
								ajaxACLSwitchToSelector();
								
								// note
								var note = document.createElement('div');
								note.className = 'info-box-mini';
								note.appendChild(document.createTextNode($lang.get('acl_lbl_delete_success')));
								
								// button: dismiss note
								var a_dismiss = document.createElement('a');
								a_dismiss.href = '#';
								a_dismiss.onclick = function()
								{
									var p = this.parentNode;
									domOpacity(p, 100, 0, 500);
									window.setTimeout(function()
										{
											p.parentNode.removeChild(p);
										}, 600);
									return false;
								}
								a_dismiss.appendChild(document.createTextNode($lang.get('acl_btn_success_dismiss')));
								note.appendChild(a_dismiss);
								// add a space
								note.appendChild(document.createTextNode(' / '));
								
								// button: dismiss note
								var a_close = document.createElement('a');
								a_close.href = '#';
								a_close.onclick = function()
								{
									killACLManager();
									return false;
								}
								a_close.appendChild(document.createTextNode($lang.get('acl_btn_success_close')));
								note.appendChild(a_close);
								
								// style note
								domObjChangeOpac(note, 0);
								note.style.position = 'absolute';
								// icon padding L + icon padding R + icon width + right padding + border width L + border width R
								note.style.width = ($dynano(aclManagerID + '_main').Width() - ( 5 + 5 + 16 + 4 + 1 + 1 )) + 'px';
								
								// make tangible, then calculate height and position right above button panel
								var panel = document.getElementById(aclManagerID + '_panel');
								panel.parentNode.parentNode.appendChild(note);
								note.style.top = '401px';
								note.style.left = '0px';
								
								opacity(note, 0, 100, 500);
							}
						}, true);
						
						break;
					case 'error':
						alert("Server side processing error:\n"+data.error);
						break;
					case 'debug':
						aclDebug(data.text);
						break;
					case 'list_existing':
						aclSetViewListExistingRespond(data);
						break;
					case 'trace':
						aclDrawTraceWrapper(data);
						break;
					default:
						handle_invalid_json(ajax.responseText);
						break;
				}
			}
		}, true);
}

function aclBuildRuleEditor(data, from_direct)
{
	var act_desc = ( data.type == 'new' ) ? $lang.get('acl_lbl_editwin_title_create') : $lang.get('acl_lbl_editwin_title_edit');
	var target_type_t = ( data.target_type == 1 ) ? $lang.get('acl_target_type_group') : $lang.get('acl_target_type_user');
	var target_name_t = data.target_name;
	var scope_type = ( data.page_id == false && data.namespace == false ) ? $lang.get('acl_scope_type_wholesite') : ( data.namespace == '__PageGroup' ) ? $lang.get('acl_scope_type_pagegroup') : $lang.get('acl_scope_type_thispage');
	
	document.getElementById(aclManagerID + '_next').style.display = 'inline';
	
	html = '<h2>'+act_desc+'</h2>';
	html += '<p>' + $lang.get('acl_lbl_editwin_body', { target_type: target_type_t, target: target_name_t, scope_type: scope_type }) + '</p>';
	
	// preset management
	var load_flags = 'href="#" onclick="aclShowPresetLoader(); return false;"';
	var save_flags = 'href="#" onclick="aclShowPresetSave(); return false;"';
	html += '<div style="float: right;">';
	html += $lang.get('acl_btn_edit_presets', { load_flags: load_flags, save_flags: save_flags });
	html += '</div>';
	html += '<div style="clear: both;"></div>';
	
	parser = new templateParser(data.template.acl_field_begin);
	html += parser.run();
	
	cls = 'row2';
	for(var i in data.acl_types)
	{
		if(typeof(data.acl_types[i]) == 'number')
		{
			cls = ( cls == 'row1' ) ? 'row2' : 'row1';
			p = new templateParser(data.template.acl_field_item);
			vars = new Object();
			if ( data.acl_descs[i].match(/^([a-z0-9_]+)$/) )
			{
				vars['FIELD_DESC'] = $lang.get(data.acl_descs[i]);
			}
			else
			{
				vars['FIELD_DESC'] = data.acl_descs[i];
			}
			vars['FIELD_INHERIT_CHECKED'] = '';
			vars['FIELD_DENY_CHECKED'] = '';
			vars['FIELD_DISALLOW_CHECKED'] = '';
			vars['FIELD_WIKIMODE_CHECKED'] = '';
			vars['FIELD_ALLOW_CHECKED'] = '';
			vars['FIELD_NAME'] = i;
			if ( !data.current_perms[i] )
			{
				data.current_perms[i] = 'i';
			}
			switch(data.current_perms[i])
			{
				case 'i':
				default:
					vars['FIELD_INHERIT_CHECKED'] = 'checked="checked"';
					break;
				case 1:
					vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
					break;
				case 2:
					vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
					break;
				case 3:
					vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
					break;
				case 4:
					vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
					break;
			}
			vars['ROW_CLASS'] = cls;
			p.assign_vars(vars);
			html += p.run();
		}
	}
	
	var parser = new templateParser(data.template.acl_field_end);
	html += parser.run();
	
	if(data.type == 'edit')
		html += '<p id="'+aclManagerID+'_deletelnk" style="text-align: right;"><a href="#delete_acl_rule" onclick="if(confirm(\'' + $lang.get('acl_msg_deleterule_confirm') + '\')) __aclDeleteRule(); return false;" style="color: red;">' + $lang.get('acl_lbl_deleterule') + '</a></p>';
	
	var main = document.getElementById(aclManagerID + '_main');
	main.innerHTML = html;
	
	var form = document.getElementById(aclManagerID + '_formobj_id');
	
	if ( from_direct )
	{
		var modeobj = document.getElementById(aclManagerID + '_mode');
		modeobj.value = 'save_edit';
	}
	else
	{
		var modeobj = form_fetch_field(form, 'mode');
		if ( modeobj )
			modeobj.value = 'save_' + data.type;
		else
			alert('modeobj is invalid: '+modeobj);
	}
	
	aclPermList = array_keys(data.acl_types);
	
	document.getElementById(aclManagerID + '_back').style.display = 'inline';
	document.getElementById(aclManagerID + '_next').value = $lang.get('etc_save_changes');
}

function __aclBuildGroupsHTML(groups)
{
	var groups = groups.groups;
	select = document.createElement('select');
	for(var i in groups)
	{
		if(typeof(groups[i]['name']) == 'string' && i != 'toJSONString')
		{
			o = document.createElement('option');
			o.value = groups[i]['id'];
			t = document.createTextNode(groups[i]['name']);
			o.appendChild(t);
			select.appendChild(o);
		}
	}
	return select;
}

function __aclBuildWizardWindow()
{
	darken(aclDisableTransitionFX, 70, 'acldarkener');
	var box = document.createElement('div');
	box.style.width = '640px'
	box.style.height = IE ? '500px' : '440px';
	box.style.position = 'fixed';
	width = getWidth();
	height = getHeight();
	box.style.left = ( width / 2 - 320 ) + 'px';
	box.style.top = ( height / 2 - 250 ) + 'px';
	box.style.backgroundColor = 'white';
	box.style.zIndex = getHighestZ() + 1;
	box.id = aclManagerID;
	box.style.opacity = '0';
	box.style.filter = 'alpha(opacity=0)';
	box.style.display = 'none';
	
	var mainwin = document.createElement('div');
	mainwin.id = aclManagerID + '_main';
	mainwin.style.clip = 'rect(0px,640px,440px,0px)';
	mainwin.style.overflow = 'auto';
	mainwin.style.width = '620px';
	mainwin.style.height = '420px';
	
	var panel = document.createElement('div');
	panel.style.width = '620px';
	panel.style.padding = '10px';
	panel.style.lineHeight = '40px';
	panel.style.textAlign = 'right';
	panel.style.position = 'fixed';
	if ( IE )
	{
		panel.style.left = '0px';
		panel.style.top = '440px';
	}
	else
	{
		panel.style.left = ( width / 2 - 320 ) + 'px';
		panel.style.top = ( height / 2 + 190 ) + 'px';
	}
	panel.style.backgroundColor = '#D0D0D0';
	panel.style.opacity = '0';
	panel.style.filter = 'alpha(opacity=0)';
	panel.id = aclManagerID + '_panel';
	
	var form = document.createElement('form');
	form.method = 'post';
	form.action = 'javascript:void(0)';
	form.onsubmit = function() { if(this.username && !submitAuthorized) return false; __aclSubmitManager(this); return false; };
	form.name = aclManagerID + '_formobj';
	form.id   = aclManagerID + '_formobj_id';
	
	var back = document.createElement('input');
	back.type = 'button';
	back.value = $lang.get('etc_wizard_back');
	back.style.fontWeight = 'normal';
	back.onclick = function() { ajaxACLSwitchToSelector(); return false; };
	back.style.display = 'none';
	back.id = aclManagerID + '_back';
	
	var saver = document.createElement('input');
	saver.type = 'submit';
	saver.value = $lang.get('etc_wizard_next');
	saver.style.fontWeight = 'bold';
	saver.id = aclManagerID + '_next';
	
	var closer = document.createElement('input');
	closer.type = 'button';
	closer.value = $lang.get('etc_cancel_changes');
	closer.onclick = function()
	{
		miniPromptMessage({
			title: $lang.get('acl_msg_closeacl_confirm_title'),
			message: $lang.get('acl_msg_closeacl_confirm_body'),
			buttons: [
				{
					text: $lang.get('acl_btn_close'),
					color: 'red',
					style: {
						fontWeight: 'bold'
					},
					onclick: function(e)
					{
						killACLManager();
						miniPromptDestroy(this);
					}
				},
				{
					text: $lang.get('etc_cancel'),
					onclick: function(e)
					{
						miniPromptDestroy(this);
					}
				}
			]
		});
		return false;
	}
	
	var spacer1 = document.createTextNode('  ');
	var spacer2 = document.createTextNode('  ');
	
	panel.appendChild(back);
	panel.appendChild(spacer1);
	panel.appendChild(saver);
	panel.appendChild(spacer2);
	panel.appendChild(closer);
	form.appendChild(mainwin);
	form.appendChild(panel);
	box.appendChild(form);
	
	var body = document.getElementsByTagName('body')[0];
	body.appendChild(box);
	if ( aclDisableTransitionFX )
	{
		document.getElementById(aclManagerID).style.display = 'block';
		changeOpac(100, aclManagerID);
		changeOpac(100, aclManagerID + '_panel');
	}
	else
	{
		setTimeout("document.getElementById('"+aclManagerID+"').style.display = 'block'; opacity('"+aclManagerID+"', 0, 100, 250); opacity('"+aclManagerID + '_panel'+"', 0, 100, 250);", 500);
	}
	
	console.debug(panel);
}

function killACLManager()
{
	el = document.getElementById(aclManagerID);
	if(el)
	{
		if ( aclDisableTransitionFX )
		{
			enlighten(true, 'acldarkener');
			el.parentNode.removeChild(el);
		}
		else
		{
			opacity(aclManagerID, 100, 0, 500);
			setTimeout('var el = document.getElementById(aclManagerID); el.parentNode.removeChild(el); enlighten(false, "acldarkener");', 750);
		}
	}
}

function __aclSubmitManager(form)
{
	console.debug(form);
	var thefrm = form;
	// var thefrm = document.forms[form.name];
	var modeobj = form_fetch_field(thefrm, 'mode');
	if ( typeof(modeobj) == 'object' )
	{
		var mode = (thefrm.mode.value) ? thefrm.mode.value : 'cant_get';
	}
	else
	{
		var mode = '';
	}
	switch(mode)
	{
		case 'cant_get':
			alert('BUG: can\'t get the state value from the form field.');
			break;
		case 'seltarget':
			var target_type = parseInt(getRadioState(thefrm, 'target_type', ['1', '2']));
			if(isNaN(target_type))
			{
				alert($lang.get('acl_err_pleaseselect_targettype'));
				return false;
			}
			target_id = ( target_type == 1 ) ? parseInt(thefrm.group_id.value) : thefrm.username.value;
			
			obj = { 'mode' : mode, 'target_type' : target_type, 'target_id' : target_id };
			
			thispage = strToPageID(title);
			do_scopesel = ( thispage[0] == aclDataCache.page_id && thispage[1] == aclDataCache.namespace );
			
			if(do_scopesel)
			{
				scope = getRadioState(thefrm, 'scope', ['page', 'group', 'global']);
				if(scope == 'page')
				{
					pageid = strToPageID(title);
					obj['page_id'] = pageid[0];
					obj['namespace'] = pageid[1];
				}
				else if(scope == 'global')
				{
					obj['page_id'] = false;
					obj['namespace'] = false;
				}
				else if(scope == 'group')
				{
					obj['page_id'] = document.getElementById('enACL_pgsel_1048576').value;
					obj['namespace'] = '__PageGroup';
				}
				else
				{
					alert('Invalid scope');
					return false;
				}
			}
			else
			{
				obj['page_id'] = aclDataCache.page_id;
				obj['namespace'] = aclDataCache.namespace;
			}
			if(target_id == '')
			{
				alert($lang.get('acl_err_pleaseselect_username'));
				return false;
			}
			__aclJSONSubmitAjaxHandler(obj);
			break;
		case 'save_edit':
		case 'save_new':
			var form = document.forms[aclManagerID + '_formobj'];
			selections = new Object();
			var dbg = '';
			var warned_everyone = false;
			for(var i in aclPermList)
			{
				selections[aclPermList[i]] = getRadioState(form, aclPermList[i], ['i', 1, 2, 3, 4]);
				// If we're editing permissions for everyone on the entire site and the
				// admin selected to deny privileges, give a stern warning about it.
				if ( selections[aclPermList[i]] == 1 && aclDataCache.target_type == 1 /* ACL_TYPE_GROUP */ && aclDataCache.target_id == 1 && !warned_everyone )
				{
					warned_everyone = true;
					if ( !confirm($lang.get('acl_msg_deny_everyone_confirm')) )
					{
						return false;
					}
				}
				dbg += aclPermList[i] + ': ' + selections[aclPermList[i]] + "\n";
				if(!selections[aclPermList[i]])
				{
					alert("Invalid return from getRadioState: "+i+": "+selections[i]+" ("+typeof(selections[i])+")");
					return false;
				}
			}
			obj = new Object();
			obj['perms'] = selections;
			obj['mode'] = mode;
			obj['target_type'] = aclDataCache.target_type;
			obj['target_id'] = aclDataCache.target_id;
			obj['target_name'] = aclDataCache.target_name;
			obj['page_id'] = aclDataCache.page_id;
			obj['namespace'] = aclDataCache.namespace;
			__aclJSONSubmitAjaxHandler(obj);
			break;
		case 'trace':
			var params = {
				mode: 'trace',
				user: document.getElementById(aclManagerID + 'trace_user').value,
				page: document.getElementById(aclManagerID + 'trace_page').value
			};
			__aclJSONSubmitAjaxHandler(params);
			break;
		default:
			alert("JSON form submit: invalid mode string "+mode+", stopping execution");
			return false;
			break;
	}
}

function getRadioState(form, name, valArray)
{
	// Konqueror/Safari fix
	if ( form[name] )
	{
		var formitem = form[name];
		if ( String(formitem) == '[object DOMNamedNodesCollection]' || is_Safari )
		{
			var i = 0;
			var radios = new Array();
			var radioids = new Array();
			while(true)
			{
				var elem = formitem[i];
				if ( !elem )
					break;
				radios.push(elem);
				if ( !elem.id )
				{
					elem.id = 'autoRadioBtn_' + Math.floor(Math.random() * 1000000);
				}
				radioids.push(elem.id);
				i++;
			}
			var cr;
			for ( var i = 0; i < radios.length; i++ )
			{
				cr = document.getElementById(radioids[i]);
				if ( cr.value == 'on' || cr.checked == true )
				{
					try {
						return ( typeof ( valArray[i] ) != 'undefined' ) ? valArray[i] : false;
					} catch(e) {
						// alert('Didn\'t get value for index: ' + i);
						return false;
					}
				}
			}
			return false;
		}
	}
	inputs = form.getElementsByTagName('input');
	radios = new Array();
	for(var i in inputs)
	{
		if(inputs[i]) if(inputs[i].type == 'radio')
			radios.push(inputs[i]);
	}
	for(var i in radios)
	{
		if(radios[i].checked && radios[i].name == name)
			return radios[i].value;
	}
	return false;
}

function __aclSetAllRadios(val, valArray)
{
	val = String(val);
	var form = document.forms[aclManagerID + '_formobj'];
	if (!form)
	{
		return false;
	}
	var inputs = form.getElementsByTagName('input');
	var radios = new Array();
	var dbg = '';
	for(var i = 0; i < inputs.length; i++)
	{
		dbg += String(inputs[i]) + "\n";
		if(inputs[i].type == 'radio')
			radios.push(inputs[i]);
	}
	for(var i in radios)
	{
		if(radios[i].value == val)
			radios[i].checked = true;
		else
			radios[i].checked = false;
	}
}

function __aclDeleteRule()
{
	if(!aclDataCache) 
	{
		if ( window.console )
		{
			try{ console.error('ACL editor: can\'t load data cache on delete'); } catch(e) {};
		}
		return false;
	}
	if(aclDataCache.mode != 'seltarget' && aclDataCache.mode != 'save_new' && aclDataCache.mode != 'save_edit')
	{
		if ( window.console )
		{
			try{ console.error('ACL editor: wrong mode on aclDataCache: ' + aclDataCache.mode); } catch(e) {};
		}
		return false;
	}
	parms = {
		'target_type' : aclDataCache.target_type,
		'target_id' : aclDataCache.target_id,
		'target_name' : aclDataCache.target_name,
		'page_id' : aclDataCache.page_id,
		'namespace' : aclDataCache.namespace,
		'mode' : 'delete'
	};
	__aclJSONSubmitAjaxHandler(parms);
}

function aclSetViewListExisting()
{
	if ( !document.getElementById(aclManagerID) )
	{
		return false;
	}
	
	var main = document.getElementById(aclManagerID + '_main');
	main.innerHTML = '';
	main.style.backgroundImage = 'url(' + scriptPath + '/images/loading-big.gif)';
	main.style.backgroundRepeat = 'no-repeat';
	main.style.backgroundPosition = 'center center';
	
	var parms = {
		'mode' : 'list_existing'
	};
	__aclJSONSubmitAjaxHandler(parms);
}

function aclSetViewListExistingRespond(data)
{
	var main = document.getElementById(aclManagerID + '_main');
	main.style.padding = '10px';
	main.innerHTML = '';
	
	var heading = document.createElement('h3');
	heading.appendChild(document.createTextNode($lang.get('acl_msg_scale_intro_title')));
	main.appendChild(heading);
	
	var p = document.createElement('p');
	p.appendChild(document.createTextNode($lang.get('acl_msg_scale_intro_body')));
	main.appendChild(p);
	
	
	main.innerHTML += data.key;
	main.style.backgroundImage = 'none';
	
	document.getElementById(aclManagerID + '_back').style.display = 'inline';
	document.getElementById(aclManagerID + '_next').style.display = 'none';
	
	for ( var i = 0; i < data.rules.length; i++ )
	{
		var rule = data.rules[i];
		// build the rule, this is just more boring DOM crap.
		var div = document.createElement('div');
		div.style.padding = '5px 3px';
		div.style.backgroundColor = '#' + rule.color;
		div.style.cursor = 'pointer';
		div.rule_id = rule.rule_id;
		div.onclick = function()
		{
			var main = document.getElementById(aclManagerID + '_main');
			main.innerHTML = '';
			main.style.backgroundImage = 'url(' + scriptPath + '/images/loading-big.gif)';
			ajaxOpenDirectACLRule(parseInt(this.rule_id));
		}
		div.innerHTML = rule.score_string;
		main.appendChild(div);
	}
}

function aclSetViewDebugTools()
{
	// selection window for viewing effective permissions
	var main = document.getElementById(aclManagerID + '_main');
	main.innerHTML = '';
 
	// set the submission handler to trace
	var thefrm = document.forms[aclManagerID + '_formobj'];
	var modeobj = form_fetch_field(thefrm, 'mode');
	modeobj.value = 'trace';
	
	// show the back button
	document.getElementById(aclManagerID + '_back').style.display = 'inline';
	
	//
	// start building
	//
	
	// selection interface
	var selector = document.createElement('div');
	
		var table = document.createElement('table');
		
		// username
		var tr_user = document.createElement('tr');
		var td_user_l = document.createElement('td');
		var lbl_user = document.createElement('label');
		lbl_user.setAttribute('for', aclManagerID + 'trace_user');
		lbl_user.appendChild(document.createTextNode($lang.get('acl_lbl_trace_user')));
		td_user_l.appendChild(lbl_user);
		tr_user.appendChild(td_user_l);
		
		var td_user_i = document.createElement('td');
		var i_user = document.createElement('input');
		i_user.type = 'text';
		i_user.id = aclManagerID + 'trace_user';
		i_user.onkeyup = function() { new AutofillUsername(this, true); };
		i_user.size = '20';
		td_user_i.appendChild(i_user);
		tr_user.appendChild(td_user_i);
		
		table.appendChild(tr_user);
		
		// page
		var tr_page = document.createElement('tr');
		var td_page_l = document.createElement('td');
		var lbl_page = document.createElement('label');
		lbl_page.setAttribute('for', aclManagerID + 'trace_page');
		lbl_page.appendChild(document.createTextNode($lang.get('acl_lbl_trace_page')));
		td_page_l.appendChild(lbl_page);
		tr_page.appendChild(td_page_l);
		
		var td_page_i = document.createElement('td');
		var i_page = document.createElement('input');
		i_page.type = 'text';
		i_page.id = aclManagerID + 'trace_page';
		i_page.onkeyup = function() { new AutofillPage(this); };
		i_page.size = '20';
		td_page_i.appendChild(i_page);
		tr_page.appendChild(td_page_i);
		
		table.appendChild(tr_page);
		
		selector.appendChild(table);
	
	// wrapper
	
	var container = document.createElement('div');
	
		container.style.margin = 'auto';
		container.style.width = '360px';
		container.style.paddingTop = '90px';
		
		var head = document.createElement('h2');
		head.appendChild(document.createTextNode($lang.get('acl_lbl_trace_title')));
		
		var desc = document.createElement('p');
		desc.innerHTML = $lang.get('acl_lbl_trace_body');
		
		container.appendChild(head);
		container.appendChild(desc);
		container.appendChild(selector);
	
	main.appendChild(container);
}

function aclTraceKey()
{
	var div = document.createElement('div');
	$(div).addClass('tblholder');
	var table = document.createElement('table');
	$(table).attr('cellspacing', '1').attr('cellpadding', '4');
	
	var inherit_list = ['enano_default', 'global_everyone', 'global_group', 'global_user', 'pg_everyone', 'pg_group', 'pg_user', 'local_everyone', 'local_group', 'local_user'];
	for ( var i = 0; i < inherit_list.length; i++ )
	{
		var t = inherit_list[i];
		var tr = document.createElement('tr');
		var td_key = document.createElement('td');
		$(td_key).addClass('acl_' + t).addClass('acl_inherit_key');
		tr.appendChild(td_key);
		var td_explain = document.createElement('td');
		$(td_explain).addClass(i % 2 == 0 ? 'row1' : 'row2');
		td_explain.appendChild(document.createTextNode($lang.get('acl_inherit_key_' + t)));
		tr.appendChild(td_explain);
		table.appendChild(tr);
	}
	div.appendChild(table);
	return div;
}

function aclTraceModalKey()
{
	load_component('messagebox');
	miniPrompt(function(parent)
		{
			// heading
			var h3 = document.createElement('h3');
			h3.appendChild(document.createTextNode($lang.get('acl_msg_trace_key')));
			parent.appendChild(h3);
			
			var key = aclTraceKey();
			parent.appendChild(key);
			
			var p = document.createElement('p');
			$(p).css('text-align', 'center');
			
			var closer = document.createElement('a');
			$(closer).addClass('abutton').addClass('abutton_red').css('font-weight', 'bold');
			closer.appendChild(document.createTextNode($lang.get('etc_close')));
			closer.href = '#';
			$(closer).click(function(e)
				{
					miniPromptDestroy(this);
					return false;
				});
			
			p.appendChild(closer);
			parent.appendChild(p);
		});
}

function aclDrawTraceWrapper(data)
{
	// hide the next button
	document.getElementById(aclManagerID + '_next').style.display = 'none';
	
	var trace_by_perm = aclDrawTraceByPerm(data);
	var trace_by_rule = aclDrawTraceByRule(data);
	
	trace_by_perm.id = 'aclDebugTraceViewPerm';
	trace_by_rule.id = 'aclDebugTraceViewRule';
	
	var start_with_rule = ( readCookie('acl_trace_view') == 'rule' );
	
	if ( start_with_rule )
	{
		trace_by_perm.style.display = 'none';
	}
	else
	{
		trace_by_rule.style.display = 'none';
	}
	
	// selection window for viewing effective permissions
	var main = document.getElementById(aclManagerID + '_main');
	main.innerHTML = '';
	
	var wrapper = document.createElement('div');
	$(wrapper).css('padding-bottom', '20px');
	
	var floatlink = document.createElement('div');
	$(floatlink).css('float', 'right').css('margin-left', '20px').css('margin-bottom', '20px').css('text-align', 'right');
	var a_toggle = document.createElement('a');
	$(a_toggle).attr('id', 'aclDebugTraceViewToggle');
	a_toggle.innerHTML = '&raquo; ';
	a_toggle.innerHTML += start_with_rule ? $lang.get('acl_btn_sort_perm') : $lang.get('acl_btn_sort_rule');
	a_toggle.href = '#';
	floatlink.appendChild(a_toggle);
	floatlink.appendChild(document.createElement('br'));
	var a_key = document.createElement('a');
	$(a_key).css('font-size', 'smaller');
	a_key.innerHTML = '&raquo; ';
	a_key.innerHTML += $lang.get('acl_btn_view_key');
	a_key.href = '#';
	floatlink.appendChild(a_key);
	wrapper.appendChild(floatlink);
	
	var h3 = document.createElement('h3');
	h3.appendChild(document.createTextNode($lang.get('acl_msg_debug_main_title')));
	wrapper.appendChild(h3);
	var p = document.createElement('p');
	p.appendChild(document.createTextNode($lang.get('acl_msg_debug_main_body')));
	wrapper.appendChild(p);
	
	wrapper.appendChild(trace_by_perm);
	wrapper.appendChild(trace_by_rule);
	
	main.appendChild(wrapper);
	
	$(a_toggle).click(function(e)
		{
			aclTraceToggleViews();
			return false;
		});
	
	$(a_key).click(function(e)
		{
			aclTraceModalKey();
			return false;
		});
}

function aclTraceToggleViews()
{
	var trace_by_perm = document.getElementById('aclDebugTraceViewPerm');
	var trace_by_rule = document.getElementById('aclDebugTraceViewRule');
	
	var toggler = document.getElementById('aclDebugTraceViewToggle');
	var newtext;
	
	if ( trace_by_perm.style.display == 'none' )
	{
		newtext = $lang.get('acl_btn_sort_rule');
		$(trace_by_rule).hide('blind', {}, 750, function()
			{
				$(trace_by_perm).show('blind', {}, 750);
			});
		createCookie('acl_trace_view', 'perm');
	}
	else
	{
		newtext = $lang.get('acl_btn_sort_perm');
		$(trace_by_perm).hide('blind', {}, 750, function()
			{
				$(trace_by_rule).show('blind', {}, 750);
			});
		createCookie('acl_trace_view', 'rule');
	}
	$(toggler).fadeOut(500, function()
		{
			this.innerHTML = '&raquo; ' + newtext;
			$(this).fadeIn(500);
		});
}

function aclDrawTraceByPerm(data)
{
	var wrapper = document.createElement('div');
	// wrapper.style.display = 'none';
	
	// temporarily append wrapper to body to allow onclick to work
	// var body = document.getElementsByTagName('body')[0];
	// body.appendChild(wrapper);  
	
	for ( var i in data.perms )
	{
		var perm = data.perms[i];
		var item = document.createElement('div');
		item.className = perm.divclass;
		
		// first row - permission name + current setting
		// use innerHTML here to allow for HTML in localized permission types
		item.innerHTML += '<b>' + perm.perm_name + ' - ' + perm.perm_value + '</b>';
		item.appendChild(document.createElement('br'));
		
		// second row - permission localized name + rule ID
		var sm = document.createElement('small');
		sm.innerHTML = perm.perm_src;
		
		item.appendChild(sm);
		
		wrapper.appendChild(item);
		
		// whole row is now in the document
		if ( perm.rule_id != -1 )
		{
			sm.innerHTML += ' [';
			// rule is editable
			var editlink = document.createElement('a');
			editlink.href = 'javascript:ajaxOpenDirectACLRule(' + perm.rule_id + ');';
			editlink.appendChild(document.createTextNode($lang.get('acl_btn_edit_rule')));
			sm.appendChild(editlink);
			sm.innerHTML += ']';
		}
		
		if ( perm.bad_deps.length > 0 )
		{
			var bd = document.createElement('span');
			$(bd).addClass('acl_failed_deps');
			var failed_deps = '';
			for ( var i = 0; i < perm.bad_deps.length; i++ )
			{
				if ( i > 0 )
					failed_deps += ', ';
				failed_deps += data.perms[perm.bad_deps[i]].perm_name;
			}
			var title = document.createElement('span');
			$(title).addClass('title');
			title.appendChild(document.createTextNode($lang.get('acl_msg_failed_deps')));
			bd.appendChild(title);
			bd.appendChild(document.createTextNode(failed_deps));
			
			item.appendChild(document.createElement('br'));
			item.appendChild(bd);
		}
	}
	
	// var ret = wrapper.cloneNode(true);
	// body.removeChild(wrapper);
	// wrapper = false;
	// ret.style.display = 'block';
	// console.debug(ret);
	// return ret;
	return wrapper;
}

function aclDrawTraceByRule(data)
{
	var wrapper = document.createElement('div');
	var groupdata = {};
	
	for ( var i in data.perms )
	{
		var perm = data.perms[i];
		if ( !groupdata[perm['rule_id']] )
		{
			groupdata[perm['rule_id']] = {
				meta: {
					divclass: perm.divclass,
					perm_src: perm.perm_src,
					rule_id: perm.rule_id
				},
				rules: {}
			};
		}
		groupdata[perm['rule_id']]['rules'][i] = perm;
	}
	
	for ( var i in groupdata )
	{
		var group = groupdata[i];
		var grp = document.createElement('div');
		var head = document.createElement('div');
		head.className = group.meta.divclass;
		var span = document.createElement('span');
		span.style.fontSize = 'larger';
		span.appendChild(document.createTextNode(group.meta.perm_src));
		head.appendChild(span);
		if ( group.meta.rule_id != -1 )
		{
			head.innerHTML += ' [';
			// rule is editable
			var editlink = document.createElement('a');
			editlink.href = 'javascript:ajaxOpenDirectACLRule(' + group.meta.rule_id + ');';
			editlink.appendChild(document.createTextNode($lang.get('acl_btn_edit_rule')));
			head.appendChild(editlink);
			head.innerHTML += ']';
		}
		grp.appendChild(head);
		for ( var i in group.rules )
		{
			var rule = group.rules[i];
			var rulediv = document.createElement('div');
			rulediv.style.padding = '3px 12px';
			rulediv.innerHTML += rule.perm_name + ': ';
			var b = document.createElement('strong');
			b.appendChild(document.createTextNode(rule.perm_value));
			rulediv.appendChild(b);
			grp.appendChild(rulediv);
			
			if ( rule.bad_deps.length > 0 )
			{
				var bd = document.createElement('span');
				$(bd).addClass('acl_failed_deps');
				var failed_deps = '';
				for ( var i = 0; i < rule.bad_deps.length; i++ )
				{
					if ( i > 0 )
						failed_deps += ', ';
					failed_deps += data.perms[rule.bad_deps[i]].perm_name;
				}
				var title = document.createElement('span');
				$(title).addClass('title');
				title.appendChild(document.createTextNode($lang.get('acl_msg_failed_deps')));
				bd.appendChild(title);
				bd.appendChild(document.createTextNode(failed_deps));
				
				rulediv.appendChild(document.createElement('br'));
				rulediv.appendChild(bd);
			}
		}
		wrapper.appendChild(grp);
	}
	
	return wrapper;
}

function aclShowPresetLoader()
{
	var prompt = miniPrompt(function(parent)
		{
			parent.innerHTML = '<img style="display: block; margin: 0 auto;" src="' + cdnPath + '/images/loading-big.gif" />';
		});
	var request = toJSONString({
			mode: 'list_presets'
		});
	ajaxPost(stdAjaxPrefix + '&_mode=acljson', 'acl_params=' + ajaxEscape(request), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				if ( !check_json_response(ajax.responseText) )
				{
					miniPromptDestroy(prompt);
					return handle_invalid_json(ajax.responseText);
				}
				var response = parseJSON(ajax.responseText);
				if ( response.mode == 'error' )
				{
					alert(response.error);
					miniPromptDestroy(prompt);
					return false;
				}
				prompt = prompt.firstChild.nextSibling;
				prompt.style.textAlign = 'center';
				prompt.innerHTML = '<h3>' + $lang.get('acl_lbl_preset_load_title') + '</h3>';
				
				if ( response.presets.length > 0 )
				{
					// selection box
					var para = document.createElement('p');
					var select = document.createElement('select');
					
					var option = document.createElement('option');
					option.value = '0';
					option.appendChild(document.createTextNode($lang.get('acl_lbl_preset_load')));
					select.appendChild(option);
					
					for ( var i = 0; i < response.presets.length; i++ )
					{
						var preset = response.presets[i];
						var option = document.createElement('option');
						option.value = preset.rule_id;
						option.preset_data = preset;
						option.appendChild(document.createTextNode($lang.get(preset.preset_name)));
						select.appendChild(option);
					}
					
					para.appendChild(select);
					prompt.appendChild(para);
					
					// buttons
					var buttons = document.createElement('p');
					
					// load button
					var btn_load = document.createElement('a');
					btn_load.className = 'abutton abutton_green';
					btn_load.style.fontWeight = 'bold';
					btn_load.appendChild(document.createTextNode($lang.get('acl_btn_load_preset')));
					btn_load.selectobj = select;
					btn_load.onclick = function()
					{
						if ( this.selectobj.value == '0' )
						{
							alert($lang.get('acl_err_select_preset'));
							return false;
						}
						// retrieve preset data
						for ( var i = 0; i < this.selectobj.childNodes.length; i++ )
						{
							if ( this.selectobj.childNodes[i].tagName == 'OPTION' )
							{
								var node = this.selectobj.childNodes[i];
								if ( node.value == this.selectobj.value )
								{
									aclSetRulesAbsolute(node.preset_data.rules);
									break;
								}
							}
						}
						miniPromptDestroy(this);
						return false;
					}
					btn_load.href = '#';
					buttons.appendChild(btn_load);
					
					buttons.appendChild(document.createTextNode(' '));
					
					// cancel button
					var btn_cancel = document.createElement('a');
					btn_cancel.className = 'abutton';
					btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
					btn_cancel.onclick = function()
					{
						miniPromptDestroy(this);
						return false;
					}
					btn_cancel.href = '#';
					buttons.appendChild(btn_cancel);
					
					prompt.appendChild(buttons);
				}
				else
				{
					// "no presets"
					prompt.innerHTML += '<p>' + $lang.get('acl_msg_no_presets', { close_flags: 'href="#" onclick="miniPromptDestroy(this); return false;"' }) + '</p>';
				}
			}
		});
}

function aclSetRulesAbsolute(rules)
{
	__aclSetAllRadios('i');
	
	var form = document.forms[aclManagerID + '_formobj'];
	if (!form)
	{
		return false;
	}
	var inputs = form.getElementsByTagName('input');
	var radios = new Array();
	var dbg = '';
	for(var i = 0; i < inputs.length; i++)
	{
		if(inputs[i].type == 'radio')
			radios.push(inputs[i]);
	}
	for(var i in radios)
	{
		if ( typeof(rules[ radios[i]['name'] ]) == 'number' )
		{
			radios[i].checked = ( rules[radios[i]['name']] == radios[i].value );
		}
	}
}

function aclShowPresetSave()
{
	miniPrompt(function(parent)
		{
			parent.style.textAlign = 'center';
			
			parent.innerHTML = '<h3>' + $lang.get('acl_lbl_preset_save_title') + '</h3>';
			var input = document.createElement('input');
			input.id = aclManagerID + '_preset_save';
			input.type = 'text';
			input.size = '30';
			input.onkeypress = function(e)
			{
				// javascript sucks. IE and several others throw myriad errors unless it's done this way.
				if ( e )
				if ( e.keyCode )
				if ( e.keyCode == 13 )
				{
					if ( aclSavePreset() )
					{
						if ( window.opera )
						{
							// damn weird opera bug.
							var input = this;
							setTimeout(function()
								{
									miniPromptDestroy(input);
								}, 10);
						}
						else
						{
							miniPromptDestroy(this);
						}
					}
				}
				else if ( e.keyCode == 27 )
				{
					miniPromptDestroy(this);
				}
			}
			var para = document.createElement('p');
			para.appendChild(input);
			
			parent.appendChild(para);
			
			// buttons
			var buttons = document.createElement('p');
			
			// save button
			var btn_save = document.createElement('a');
			btn_save.className = 'abutton abutton_green';
			btn_save.style.fontWeight = 'bold';
			btn_save.appendChild(document.createTextNode($lang.get('acl_btn_save_preset')));
			btn_save.selectobj = select;
			btn_save.onclick = function()
			{
				if ( aclSavePreset() )
				{
					miniPromptDestroy(this);
				}
				return false;
			}
			btn_save.href = '#';
			buttons.appendChild(btn_save);
			
			buttons.appendChild(document.createTextNode(' '));
			
			// cancel button
			var btn_cancel = document.createElement('a');
			btn_cancel.className = 'abutton';
			btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
			btn_cancel.onclick = function()
			{
				miniPromptDestroy(this);
				return false;
			}
			btn_cancel.href = '#';
			buttons.appendChild(btn_cancel);
			
			parent.appendChild(buttons);
			
			var timeout = ( aclDisableTransitionFX ) ? 10 : 1000;
			setTimeout(function()
				{
					input.focus();
				}, timeout);
		});
}

function aclSavePreset()
{
	var input = document.getElementById(aclManagerID + '_preset_save');
	if ( trim(input.value) == '' )
	{
		alert($lang.get('acl_err_preset_name_empty'));
		return false;
	}
	var form = document.forms[aclManagerID + '_formobj'], selections = {};
	var dbg = '';
	var warned_everyone = false;
	for(var i in aclPermList)
	{
		selections[aclPermList[i]] = getRadioState(form, aclPermList[i], ['i', 1, 2, 3, 4]);
		// If we're editing permissions for everyone on the entire site and the
		// admin selected to deny privileges, give a stern warning about it.
		if ( selections[aclPermList[i]] == 1 && aclDataCache.target_type == 1 /* ACL_TYPE_GROUP */ && aclDataCache.target_id == 1 && !warned_everyone )
		{
			warned_everyone = true;
			if ( !confirm($lang.get('acl_msg_deny_everyone_confirm')) )
			{
				return false;
			}
		}
		dbg += aclPermList[i] + ': ' + selections[aclPermList[i]] + "\n";
		if(!selections[aclPermList[i]])
		{
			alert("Invalid return from getRadioState: "+i+": "+selections[i]+" ("+typeof(selections[i])+")");
			return false;
		}
	}
	
	var packet = toJSONString({
			mode: 'save_preset',
			preset_name: input.value,
			perms: selections
		});
	
	var whitey = whiteOutElement(document.getElementById(aclManagerID));
	
	ajaxPost(stdAjaxPrefix + '&_mode=acljson', 'acl_params=' + ajaxEscape(packet), function(ajax)
		{
			if ( ajax.readyState == 4 && ajax.status == 200 )
			{
				if ( !check_json_response(ajax.responseText) )
				{
					whitey.parentNode.removeChild(whitey);
					return handle_invalid_json(ajax.responseText);
				}
				var response = parseJSON(ajax.responseText);
				if ( response.mode == 'error' )
				{
					whitey.parentNode.removeChild(whitey);
					alert(response.error);
					return false;
				}
				whiteOutReportSuccess(whitey);
			}
		});
	
	return true;
}

function array_keys(obj)
{
	keys = new Array();
	for(var i in obj)
		keys.push(i);
	return keys;
}