includes/clientside/static/functions.js
changeset 1227 bdac73ed481e
parent 1200 0f94802001ee
child 1252 e34c23a35dc9
equal deleted inserted replaced
1226:de56132c008d 1227:bdac73ed481e
     1 // all utility functions go in here
     1 // all utility functions go in here
     2 
     2 
     3 function makeUrl(page, query, html_friendly)
     3 function makeUrl(page, query, html_friendly)
     4 {
     4 {
     5   url = contentPath+page;
     5 	url = contentPath+page;
     6   if(url.indexOf('?') > 0) sep = '&';
     6 	if(url.indexOf('?') > 0) sep = '&';
     7   else sep = '?';
     7 	else sep = '?';
     8   if(query)
     8 	if(query)
     9   {
     9 	{
    10     url = url + sep + query;
    10 		url = url + sep + query;
    11   }
    11 	}
    12   if(html_friendly)
    12 	if(html_friendly)
    13   {
    13 	{
    14     url = url.replace('&', '&');
    14 		url = url.replace('&', '&');
    15     url = url.replace('<', '&lt;');
    15 		url = url.replace('<', '&lt;');
    16     url = url.replace('>', '&gt;');
    16 		url = url.replace('>', '&gt;');
    17   }
    17 	}
    18   return append_sid(url);
    18 	return append_sid(url);
    19 }
    19 }
    20 
    20 
    21 function makeUrlNS(namespace, page, query, html_friendly)
    21 function makeUrlNS(namespace, page, query, html_friendly)
    22 {
    22 {
    23   var url = contentPath+namespace_list[namespace]+(page.replace(/ /g, '_'));
    23 	var url = contentPath+namespace_list[namespace]+(page.replace(/ /g, '_'));
    24   if(url.indexOf('?') > 0) sep = '&';
    24 	if(url.indexOf('?') > 0) sep = '&';
    25   else sep = '?';
    25 	else sep = '?';
    26   if(query)
    26 	if(query)
    27   {
    27 	{
    28     url = url + sep + query;
    28 		url = url + sep + query;
    29   }
    29 	}
    30   if(html_friendly)
    30 	if(html_friendly)
    31   {
    31 	{
    32     url = url.replace('&', '&amp;');
    32 		url = url.replace('&', '&amp;');
    33     url = url.replace('<', '&lt;');
    33 		url = url.replace('<', '&lt;');
    34     url = url.replace('>', '&gt;');
    34 		url = url.replace('>', '&gt;');
    35   }
    35 	}
    36   return append_sid(url);
    36 	return append_sid(url);
    37 }
    37 }
    38 
    38 
    39 function strToPageID(string)
    39 function strToPageID(string)
    40 {
    40 {
    41   // Convert Special:UploadFile to ['UploadFile', 'Special'], but convert 'Image:Enano.png' to ['Enano.png', 'File']
    41 	// Convert Special:UploadFile to ['UploadFile', 'Special'], but convert 'Image:Enano.png' to ['Enano.png', 'File']
    42   for(var i in namespace_list)
    42 	for(var i in namespace_list)
    43     if(namespace_list[i] != '')
    43 		if(namespace_list[i] != '')
    44       if(namespace_list[i] == string.substr(0, namespace_list[i].length))
    44 			if(namespace_list[i] == string.substr(0, namespace_list[i].length))
    45         return [string.substr(namespace_list[i].length), i];
    45 				return [string.substr(namespace_list[i].length), i];
    46   return [string, 'Article'];
    46 	return [string, 'Article'];
    47 }
    47 }
    48 
    48 
    49 function append_sid(url)
    49 function append_sid(url)
    50 {
    50 {
    51   var match = url.match(/#(.*?)$/);
    51 	var match = url.match(/#(.*?)$/);
    52   url = url.replace(/#(.*?)$/, '');
    52 	url = url.replace(/#(.*?)$/, '');
    53   sep = ( url.indexOf('?') > 0 ) ? '&' : '?';
    53 	sep = ( url.indexOf('?') > 0 ) ? '&' : '?';
    54   if(ENANO_SID.length > 10)
    54 	if(ENANO_SID.length > 10)
    55   {
    55 	{
    56     url = url + sep + 'auth=' + ENANO_SID;
    56 		url = url + sep + 'auth=' + ENANO_SID;
    57     sep = '&';
    57 		sep = '&';
    58   }
    58 	}
    59   if ( pagepass.length > 0 )
    59 	if ( pagepass.length > 0 )
    60   {
    60 	{
    61     url = url + sep + 'pagepass=' + pagepass;
    61 		url = url + sep + 'pagepass=' + pagepass;
    62   }
    62 	}
    63   if ( match )
    63 	if ( match )
    64   {
    64 	{
    65     url = url + match[0];
    65 		url = url + match[0];
    66   }
    66 	}
    67   return url;
    67 	return url;
    68 }
    68 }
    69 
    69 
    70 var stdAjaxPrefix = append_sid(scriptPath+'/ajax.php?title='+title);
    70 var stdAjaxPrefix = append_sid(scriptPath+'/ajax.php?title='+title);
    71 
    71 
    72 /**
    72 /**
    73  * Core AJAX library
    73  * Core AJAX library
    74  */
    74  */
    75 
    75 
    76 function ajaxMakeXHR()
    76 function ajaxMakeXHR()
    77 {
    77 {
    78   var ajax;
    78 	var ajax;
    79   if (window.XMLHttpRequest) {
    79 	if (window.XMLHttpRequest) {
    80     ajax = new XMLHttpRequest();
    80 		ajax = new XMLHttpRequest();
    81   } else {
    81 	} else {
    82     if (window.ActiveXObject) {           
    82 		if (window.ActiveXObject) {           
    83       ajax = new ActiveXObject("Microsoft.XMLHTTP");
    83 			ajax = new ActiveXObject("Microsoft.XMLHTTP");
    84     } else {
    84 		} else {
    85       alert('Enano client-side runtime error: No AJAX support, unable to continue');
    85 			alert('Enano client-side runtime error: No AJAX support, unable to continue');
    86       return;
    86 			return;
    87     }
    87 		}
    88   }
    88 	}
    89   return ajax;
    89 	return ajax;
    90 }
    90 }
    91 
    91 
    92 function ajaxGet(uri, f, call_editor_safe) {
    92 function ajaxGet(uri, f, call_editor_safe) {
    93   // Is the editor open?
    93 	// Is the editor open?
    94   if ( editor_open && !call_editor_safe )
    94 	if ( editor_open && !call_editor_safe )
    95   {
    95 	{
    96     // Make sure the user is willing to close the editor
    96 		// Make sure the user is willing to close the editor
    97     var conf = confirm($lang.get('editor_msg_confirm_ajax'));
    97 		var conf = confirm($lang.get('editor_msg_confirm_ajax'));
    98     if ( !conf )
    98 		if ( !conf )
    99     {
    99 		{
   100       // Kill off any "loading" windows, etc. and cancel the request
   100 			// Kill off any "loading" windows, etc. and cancel the request
   101       unsetAjaxLoading();
   101 			unsetAjaxLoading();
   102       return false;
   102 			return false;
   103     }
   103 		}
   104     // The user allowed the editor to be closed. Reset flags and knock out the on-close confirmation.
   104 		// The user allowed the editor to be closed. Reset flags and knock out the on-close confirmation.
   105     editor_open = false;
   105 		editor_open = false;
   106     enableUnload();
   106 		enableUnload();
   107     // destroy the MCE instance so it can be recreated later
   107 		// destroy the MCE instance so it can be recreated later
   108     $dynano('ajaxEditArea').destroyMCE(false);
   108 		$dynano('ajaxEditArea').destroyMCE(false);
   109   }
   109 	}
   110   var ajax = ajaxMakeXHR();
   110 	var ajax = ajaxMakeXHR();
   111   if ( !ajax )
   111 	if ( !ajax )
   112   {
   112 	{
   113     console.error('ajaxMakeXHR() failed');
   113 		console.error('ajaxMakeXHR() failed');
   114     return false;
   114 		return false;
   115   }
   115 	}
   116   ajax.onreadystatechange = function()
   116 	ajax.onreadystatechange = function()
   117   {
   117 	{
   118     f(ajax);
   118 		f(ajax);
   119   };
   119 	};
   120   ajax.open('GET', uri, true);
   120 	ajax.open('GET', uri, true);
   121   ajax.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
   121 	ajax.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
   122   ajax.send(null);
   122 	ajax.send(null);
   123   window.ajax = ajax;
   123 	window.ajax = ajax;
   124 }
   124 }
   125 
   125 
   126 function ajaxPost(uri, parms, f, call_editor_safe) {
   126 function ajaxPost(uri, parms, f, call_editor_safe) {
   127   // Is the editor open?
   127 	// Is the editor open?
   128   if ( editor_open && !call_editor_safe )
   128 	if ( editor_open && !call_editor_safe )
   129   {
   129 	{
   130     // Make sure the user is willing to close the editor
   130 		// Make sure the user is willing to close the editor
   131     var conf = confirm($lang.get('editor_msg_confirm_ajax'));
   131 		var conf = confirm($lang.get('editor_msg_confirm_ajax'));
   132     if ( !conf )
   132 		if ( !conf )
   133     {
   133 		{
   134       // Kill off any "loading" windows, etc. and cancel the request
   134 			// Kill off any "loading" windows, etc. and cancel the request
   135       unsetAjaxLoading();
   135 			unsetAjaxLoading();
   136       return false;
   136 			return false;
   137     }
   137 		}
   138     // The user allowed the editor to be closed. Reset flags and knock out the on-close confirmation.
   138 		// The user allowed the editor to be closed. Reset flags and knock out the on-close confirmation.
   139     editor_open = false;
   139 		editor_open = false;
   140     enableUnload();
   140 		enableUnload();
   141     // destroy the MCE instance so it can be recreated later
   141 		// destroy the MCE instance so it can be recreated later
   142     $dynano('ajaxEditArea').destroyMCE(false);
   142 		$dynano('ajaxEditArea').destroyMCE(false);
   143   }
   143 	}
   144   var ajax = ajaxMakeXHR();
   144 	var ajax = ajaxMakeXHR();
   145   if ( !ajax )
   145 	if ( !ajax )
   146   {
   146 	{
   147     console.error('ajaxMakeXHR() failed');
   147 		console.error('ajaxMakeXHR() failed');
   148     return false;
   148 		return false;
   149   }
   149 	}
   150   ajax.onreadystatechange = function()
   150 	ajax.onreadystatechange = function()
   151   {
   151 	{
   152     f(ajax);
   152 		f(ajax);
   153   };
   153 	};
   154   ajax.open('POST', uri, true);
   154 	ajax.open('POST', uri, true);
   155   ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   155 	ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   156   // Setting Content-length in Safari triggers a warning
   156 	// Setting Content-length in Safari triggers a warning
   157   if ( !is_Safari )
   157 	if ( !is_Safari )
   158   {
   158 	{
   159     ajax.setRequestHeader("Content-length", parms.length);
   159 		ajax.setRequestHeader("Content-length", parms.length);
   160   }
   160 	}
   161   // fails under chrome 2.0
   161 	// fails under chrome 2.0
   162   // ajax.setRequestHeader("Connection", "close");
   162 	// ajax.setRequestHeader("Connection", "close");
   163   ajax.send(parms);
   163 	ajax.send(parms);
   164   window.ajax = ajax;
   164 	window.ajax = ajax;
   165 }
   165 }
   166 
   166 
   167 /**
   167 /**
   168  * Show a friendly error message depicting an AJAX response that is not valid JSON
   168  * Show a friendly error message depicting an AJAX response that is not valid JSON
   169  * @param string Response text
   169  * @param string Response text
   170  * @param string Custom error message. If omitted, the default will be shown.
   170  * @param string Custom error message. If omitted, the default will be shown.
   171  */
   171  */
   172 
   172 
   173 function handle_invalid_json(response, customerror)
   173 function handle_invalid_json(response, customerror)
   174 {
   174 {
   175   load_component(['messagebox', 'jquery', 'jquery-ui', 'fadefilter', 'flyin', 'l10n']);
   175 	load_component(['messagebox', 'jquery', 'jquery-ui', 'fadefilter', 'flyin', 'l10n']);
   176   
   176 	
   177   darken(aclDisableTransitionFX, 70, 'invalidjsondarkener');
   177 	darken(aclDisableTransitionFX, 70, 'invalidjsondarkener');
   178   
   178 	
   179   var box = document.createElement('div');
   179 	var box = document.createElement('div');
   180   var mainwin = document.createElement('div');
   180 	var mainwin = document.createElement('div');
   181   var panel = document.createElement('div');
   181 	var panel = document.createElement('div');
   182   
   182 	
   183   //
   183 	//
   184   // main window
   184 	// main window
   185   //
   185 	//
   186   
   186 	
   187     mainwin.style.padding = '10px';
   187 		mainwin.style.padding = '10px';
   188     mainwin.style.width = '580px';
   188 		mainwin.style.width = '580px';
   189     mainwin.style.height = '360px';
   189 		mainwin.style.height = '360px';
   190     mainwin.style.clip = 'rect(0px,auto,auto,0px)';
   190 		mainwin.style.clip = 'rect(0px,auto,auto,0px)';
   191     mainwin.style.overflow = 'auto';
   191 		mainwin.style.overflow = 'auto';
   192     mainwin.style.backgroundColor = '#ffffff';
   192 		mainwin.style.backgroundColor = '#ffffff';
   193   
   193 	
   194     // Title
   194 		// Title
   195     var h3 = document.createElement('h3');
   195 		var h3 = document.createElement('h3');
   196     var h3_text = ( $lang.placeholder ) ? 'The site encountered an error while processing your request.' : $lang.get('ajax_badjson_title');
   196 		var h3_text = ( $lang.placeholder ) ? 'The site encountered an error while processing your request.' : $lang.get('ajax_badjson_title');
   197     h3.appendChild(document.createTextNode(h3_text));
   197 		h3.appendChild(document.createTextNode(h3_text));
   198     mainwin.appendChild(h3);
   198 		mainwin.appendChild(h3);
   199     
   199 		
   200     if ( typeof(customerror) == 'string' )
   200 		if ( typeof(customerror) == 'string' )
   201     {
   201 		{
   202       var el = document.createElement('p');
   202 			var el = document.createElement('p');
   203       el.appendChild(document.createTextNode(customerror));
   203 			el.appendChild(document.createTextNode(customerror));
   204       mainwin.appendChild(el);
   204 			mainwin.appendChild(el);
   205     }
   205 		}
   206     else
   206 		else
   207     {
   207 		{
   208       var error = 'We unexpectedly received the following response from the server. The response should have been in the JSON ';
   208 			var error = 'We unexpectedly received the following response from the server. The response should have been in the JSON ';
   209       error += 'serialization format, but the response wasn\'t composed only of the JSON response. There are three possible triggers ';
   209 			error += 'serialization format, but the response wasn\'t composed only of the JSON response. There are three possible triggers ';
   210       error += 'for this problem:';
   210 			error += 'for this problem:';
   211       customerror = ( $lang.placeholder ) ? error : $lang.get('ajax_badjson_body');
   211 			customerror = ( $lang.placeholder ) ? error : $lang.get('ajax_badjson_body');
   212       var el = document.createElement('p');
   212 			var el = document.createElement('p');
   213       el.appendChild(document.createTextNode(customerror));
   213 			el.appendChild(document.createTextNode(customerror));
   214       mainwin.appendChild(el);
   214 			mainwin.appendChild(el);
   215       var ul = document.createElement('ul');
   215 			var ul = document.createElement('ul');
   216       var li1 = document.createElement('li');
   216 			var li1 = document.createElement('li');
   217       var li2 = document.createElement('li');
   217 			var li2 = document.createElement('li');
   218       var li3 = document.createElement('li');
   218 			var li3 = document.createElement('li');
   219       var li1_text = ( $lang.placeholder ) ? 'The server sent back a bad HTTP response code and thus sent an error page instead of running Enano. This indicates a possible problem with your server, and is not likely to be a bug with Enano.' : $lang.get('ajax_badjson_tip1');
   219 			var li1_text = ( $lang.placeholder ) ? 'The server sent back a bad HTTP response code and thus sent an error page instead of running Enano. This indicates a possible problem with your server, and is not likely to be a bug with Enano.' : $lang.get('ajax_badjson_tip1');
   220       var li2_text = ( $lang.placeholder ) ? 'The server sent back the expected JSON response, but also injected some code into the response that should not be there. Typically this consists of advertisement code. In this case, the administrator of this site will have to contact their web host to have advertisements disabled.' : $lang.get('ajax_badjson_tip2');
   220 			var li2_text = ( $lang.placeholder ) ? 'The server sent back the expected JSON response, but also injected some code into the response that should not be there. Typically this consists of advertisement code. In this case, the administrator of this site will have to contact their web host to have advertisements disabled.' : $lang.get('ajax_badjson_tip2');
   221       var li3_text = ( $lang.placeholder ) ? 'It\'s possible that Enano triggered a PHP error or warning. In this case, you may be looking at a bug in Enano.' : $lang.get('ajax_badjson_tip3');
   221 			var li3_text = ( $lang.placeholder ) ? 'It\'s possible that Enano triggered a PHP error or warning. In this case, you may be looking at a bug in Enano.' : $lang.get('ajax_badjson_tip3');
   222       var osc_ex_data = ( $lang.placeholder ) ? 'This is KNOWN to be the case with the OpenSourceCMS.com demo version of Enano.' : $lang.get('ajax_badjson_osc');
   222 			var osc_ex_data = ( $lang.placeholder ) ? 'This is KNOWN to be the case with the OpenSourceCMS.com demo version of Enano.' : $lang.get('ajax_badjson_osc');
   223       li1.appendChild(document.createTextNode(li1_text));
   223 			li1.appendChild(document.createTextNode(li1_text));
   224       var osc_exception = ( window.location.hostname == 'demo.opensourcecms.com' ) ? ' ' + osc_ex_data : '';
   224 			var osc_exception = ( window.location.hostname == 'demo.opensourcecms.com' ) ? ' ' + osc_ex_data : '';
   225       li2.appendChild(document.createTextNode(li2_text + osc_exception));
   225 			li2.appendChild(document.createTextNode(li2_text + osc_exception));
   226       li3.appendChild(document.createTextNode(li3_text));
   226 			li3.appendChild(document.createTextNode(li3_text));
   227         
   227 				
   228       ul.appendChild(li1);
   228 			ul.appendChild(li1);
   229       ul.appendChild(li2);
   229 			ul.appendChild(li2);
   230       ul.appendChild(li3);
   230 			ul.appendChild(li3);
   231       mainwin.appendChild(ul);
   231 			mainwin.appendChild(ul);
   232     }
   232 		}
   233     
   233 		
   234     var p2 = document.createElement('p');
   234 		var p2 = document.createElement('p');
   235     var p2_text = ( $lang.placeholder ) ? 'The response received from the server is as follows:' : $lang.get('ajax_badjson_msg_response');
   235 		var p2_text = ( $lang.placeholder ) ? 'The response received from the server is as follows:' : $lang.get('ajax_badjson_msg_response');
   236     p2.appendChild(document.createTextNode(p2_text));
   236 		p2.appendChild(document.createTextNode(p2_text));
   237     mainwin.appendChild(p2);
   237 		mainwin.appendChild(p2);
   238     
   238 		
   239     var pre = document.createElement('pre');
   239 		var pre = document.createElement('pre');
   240     pre.appendChild(document.createTextNode(response));
   240 		pre.appendChild(document.createTextNode(response));
   241     mainwin.appendChild(pre);
   241 		mainwin.appendChild(pre);
   242     
   242 		
   243     var p3 = document.createElement('p');
   243 		var p3 = document.createElement('p');
   244     var p3_text = $lang.placeholder ? 'You may also choose to view the response as HTML.' : $lang.get('ajax_badjson_msg_viewashtml');
   244 		var p3_text = $lang.placeholder ? 'You may also choose to view the response as HTML.' : $lang.get('ajax_badjson_msg_viewashtml');
   245     p3.appendChild(document.createTextNode(p3_text + ' '));
   245 		p3.appendChild(document.createTextNode(p3_text + ' '));
   246     var a = document.createElement('a');
   246 		var a = document.createElement('a');
   247     var a_text = $lang.placeholder ? 'View as HTML' : $lang.get('ajax_badjson_btn_viewashtml');
   247 		var a_text = $lang.placeholder ? 'View as HTML' : $lang.get('ajax_badjson_btn_viewashtml');
   248     a.appendChild(document.createTextNode(a_text + '...'));
   248 		a.appendChild(document.createTextNode(a_text + '...'));
   249     a._resp = response;
   249 		a._resp = response;
   250     a.onclick = function()
   250 		a.onclick = function()
   251     {
   251 		{
   252       var vah_title = ( $lang.placeholder ) ? 'View the response as HTML?' : $lang.get('ajax_badjson_html_confirm_title');
   252 			var vah_title = ( $lang.placeholder ) ? 'View the response as HTML?' : $lang.get('ajax_badjson_html_confirm_title');
   253       var vah_body = ( $lang.placeholder ) ? 'If the server\'s response was modified by an attacker to include malicious code, viewing the response as HTML might allow that malicious code to run. Only continue if you have inspected the response text and verified that it is safe.' : $lang.get('ajax_badjson_html_confirm_body');
   253 			var vah_body = ( $lang.placeholder ) ? 'If the server\'s response was modified by an attacker to include malicious code, viewing the response as HTML might allow that malicious code to run. Only continue if you have inspected the response text and verified that it is safe.' : $lang.get('ajax_badjson_html_confirm_body');
   254       var btn_confirm = $lang.placeholder ? 'View as HTML' : $lang.get('ajax_badjson_btn_viewashtml');
   254 			var btn_confirm = $lang.placeholder ? 'View as HTML' : $lang.get('ajax_badjson_btn_viewashtml');
   255       var btn_cancel = $lang.placeholder ? 'Cancel' : $lang.get('etc_cancel');
   255 			var btn_cancel = $lang.placeholder ? 'Cancel' : $lang.get('etc_cancel');
   256       var mp = miniPromptMessage({
   256 			var mp = miniPromptMessage({
   257           title: vah_title,
   257 					title: vah_title,
   258           message: vah_body,
   258 					message: vah_body,
   259           buttons: [
   259 					buttons: [
   260             {
   260 						{
   261               text: btn_confirm,
   261 							text: btn_confirm,
   262               color: 'blue',
   262 							color: 'blue',
   263               style: {
   263 							style: {
   264                 fontWeight: 'bold'
   264 								fontWeight: 'bold'
   265               },
   265 							},
   266               onclick: function() {
   266 							onclick: function() {
   267                 var mp = miniPromptGetParent(this);
   267 								var mp = miniPromptGetParent(this);
   268                 var win = window.open('about:blank', 'invalidjson_htmlwin', 'width=550,height=400,status=no,toolbars=no,toolbar=no,address=no,scroll=yes');
   268 								var win = window.open('about:blank', 'invalidjson_htmlwin', 'width=550,height=400,status=no,toolbars=no,toolbar=no,address=no,scroll=yes');
   269                 win.document.write(mp._response);
   269 								win.document.write(mp._response);
   270                 win.document.close();
   270 								win.document.close();
   271                 miniPromptDestroy(this);
   271 								miniPromptDestroy(this);
   272               }
   272 							}
   273             },
   273 						},
   274             {
   274 						{
   275               text: btn_cancel,
   275 							text: btn_cancel,
   276               onclick: function() {
   276 							onclick: function() {
   277                 miniPromptDestroy(this);
   277 								miniPromptDestroy(this);
   278               }
   278 							}
   279             }
   279 						}
   280           ]
   280 					]
   281         });
   281 				});
   282       mp._response = this._resp;
   282 			mp._response = this._resp;
   283       return false;
   283 			return false;
   284     }
   284 		}
   285     a.href = '#';
   285 		a.href = '#';
   286     p3.appendChild(a);
   286 		p3.appendChild(a);
   287     mainwin.appendChild(p3);
   287 		mainwin.appendChild(p3);
   288   
   288 	
   289   //
   289 	//
   290   // panel
   290 	// panel
   291   //
   291 	//
   292   
   292 	
   293     panel.style.backgroundColor = '#D0D0D0';
   293 		panel.style.backgroundColor = '#D0D0D0';
   294     panel.style.textAlign = 'right';
   294 		panel.style.textAlign = 'right';
   295     panel.style.padding = '0 10px';
   295 		panel.style.padding = '0 10px';
   296     panel.style.lineHeight = '40px';
   296 		panel.style.lineHeight = '40px';
   297     panel.style.width = '580px';
   297 		panel.style.width = '580px';
   298     
   298 		
   299     var closer = document.createElement('input');
   299 		var closer = document.createElement('input');
   300     var btn_close = $lang.placeholder ? 'Close' : $lang.get('ajax_badjson_btn_close');
   300 		var btn_close = $lang.placeholder ? 'Close' : $lang.get('ajax_badjson_btn_close');
   301     closer.type = 'button';
   301 		closer.type = 'button';
   302     closer.value = btn_close;
   302 		closer.value = btn_close;
   303     closer.onclick = function()
   303 		closer.onclick = function()
   304     {
   304 		{
   305       var parentdiv = this.parentNode.parentNode;
   305 			var parentdiv = this.parentNode.parentNode;
   306       if ( aclDisableTransitionFX )
   306 			if ( aclDisableTransitionFX )
   307       {
   307 			{
   308         parentdiv.parentNode.removeChild(parentdiv);
   308 				parentdiv.parentNode.removeChild(parentdiv);
   309         enlighten(aclDisableTransitionFX, 'invalidjsondarkener');
   309 				enlighten(aclDisableTransitionFX, 'invalidjsondarkener');
   310       }
   310 			}
   311       else
   311 			else
   312       {
   312 			{
   313         $(parentdiv).hide("blind", {}, 1000, function()
   313 				$(parentdiv).hide("blind", {}, 1000, function()
   314           {
   314 					{
   315             parentdiv.parentNode.removeChild(parentdiv);
   315 						parentdiv.parentNode.removeChild(parentdiv);
   316               enlighten(aclDisableTransitionFX, 'invalidjsondarkener');
   316 							enlighten(aclDisableTransitionFX, 'invalidjsondarkener');
   317           });
   317 					});
   318       }
   318 			}
   319     }
   319 		}
   320     panel.appendChild(closer);
   320 		panel.appendChild(closer);
   321     
   321 		
   322   //
   322 	//
   323   // put it together
   323 	// put it together
   324   //
   324 	//
   325   
   325 	
   326     box.appendChild(mainwin);
   326 		box.appendChild(mainwin);
   327     box.appendChild(panel);
   327 		box.appendChild(panel);
   328     
   328 		
   329     // add it to the body to allow height/width calculation
   329 		// add it to the body to allow height/width calculation
   330     
   330 		
   331     box.style.display = 'block';
   331 		box.style.display = 'block';
   332     box.style.position = 'absolute';
   332 		box.style.position = 'absolute';
   333     box.style.zIndex = getHighestZ() + 1;
   333 		box.style.zIndex = getHighestZ() + 1;
   334     domObjChangeOpac(0, box);
   334 		domObjChangeOpac(0, box);
   335     
   335 		
   336     var body = document.getElementsByTagName('body')[0];
   336 		var body = document.getElementsByTagName('body')[0];
   337     body.appendChild(box);
   337 		body.appendChild(box);
   338     
   338 		
   339     
   339 		
   340     // calculate position of the box
   340 		// calculate position of the box
   341     // box should be exactly 640px high, 480px wide
   341 		// box should be exactly 640px high, 480px wide
   342     var top = ( getHeight() / 2 ) - ( $dynano(box).Height() / 2 ) + getScrollOffset();
   342 		var top = ( getHeight() / 2 ) - ( $dynano(box).Height() / 2 ) + getScrollOffset();
   343     var left = ( getWidth() / 2 ) - ( $dynano(box).Width() / 2 );
   343 		var left = ( getWidth() / 2 ) - ( $dynano(box).Width() / 2 );
   344     console.debug('top = %d, left = %d', top, left);
   344 		console.debug('top = %d, left = %d', top, left);
   345     box.style.top = top + 'px';
   345 		box.style.top = top + 'px';
   346     box.style.left = left + 'px';
   346 		box.style.left = left + 'px';
   347     
   347 		
   348     // we have width and height, set display to none and reset opacity
   348 		// we have width and height, set display to none and reset opacity
   349     if ( aclDisableTransitionFX )
   349 		if ( aclDisableTransitionFX )
   350     {
   350 		{
   351       domObjChangeOpac(100, box);
   351 			domObjChangeOpac(100, box);
   352       box.style.display = 'block';
   352 			box.style.display = 'block';
   353     }
   353 		}
   354     else
   354 		else
   355     {
   355 		{
   356       box.style.display = 'none';
   356 			box.style.display = 'none';
   357       domObjChangeOpac(100, box);
   357 			domObjChangeOpac(100, box);
   358       
   358 			
   359       setTimeout(function()
   359 			setTimeout(function()
   360         {
   360 				{
   361           $(box).show("blind", {}, 1000);
   361 					$(box).show("blind", {}, 1000);
   362         }, 1000);
   362 				}, 1000);
   363     }
   363 		}
   364   return false;
   364 	return false;
   365 }
   365 }
   366 
   366 
   367 /**
   367 /**
   368  * Verify that a string is roughly a valid JSON object. Warning - this is only a very cheap syntax check.
   368  * Verify that a string is roughly a valid JSON object. Warning - this is only a very cheap syntax check.
   369  * @param string
   369  * @param string
   370  * @return bool true if JSON is valid
   370  * @return bool true if JSON is valid
   371  */
   371  */
   372 
   372 
   373 function check_json_response(response)
   373 function check_json_response(response)
   374 {
   374 {
   375   response = trim(response);
   375 	response = trim(response);
   376   if ( response.substr(0, 1) == '{' && response.substr(response.length - 1, 1) == '}' )
   376 	if ( response.substr(0, 1) == '{' && response.substr(response.length - 1, 1) == '}' )
   377   {
   377 	{
   378     return true;
   378 		return true;
   379   }
   379 	}
   380   return false;
   380 	return false;
   381 }
   381 }
   382 
   382 
   383 function ajaxEscape(text)
   383 function ajaxEscape(text)
   384 {
   384 {
   385   /*
   385 	/*
   386   text = escape(text);
   386 	text = escape(text);
   387   text = text.replace(/\+/g, '%2B', text);
   387 	text = text.replace(/\+/g, '%2B', text);
   388   */
   388 	*/
   389   text = window.encodeURIComponent(text);
   389 	text = window.encodeURIComponent(text);
   390   return text;
   390 	return text;
   391 }
   391 }
   392 
   392 
   393 /**
   393 /**
   394  * String functions
   394  * String functions
   395  */
   395  */
   396 
   396 
   397 // Equivalent to PHP trim() function
   397 // Equivalent to PHP trim() function
   398 function trim(text)
   398 function trim(text)
   399 {
   399 {
   400   text = text.replace(/^([\s]+)/, '');
   400 	text = text.replace(/^([\s]+)/, '');
   401   text = text.replace(/([\s]+)$/, '');
   401 	text = text.replace(/([\s]+)$/, '');
   402   return text;
   402 	return text;
   403 }
   403 }
   404 
   404 
   405 // Equivalent to PHP implode() function
   405 // Equivalent to PHP implode() function
   406 function implode(chr, arr)
   406 function implode(chr, arr)
   407 {
   407 {
   408   if ( typeof ( arr.toJSONString ) == 'function' )
   408 	if ( typeof ( arr.toJSONString ) == 'function' )
   409     delete(arr.toJSONString);
   409 		delete(arr.toJSONString);
   410   
   410 	
   411   var ret = '';
   411 	var ret = '';
   412   var c = 0;
   412 	var c = 0;
   413   for ( var i in arr )
   413 	for ( var i in arr )
   414   {
   414 	{
   415     if(i=='toJSONString')continue;
   415 		if(i=='toJSONString')continue;
   416     if ( c > 0 )
   416 		if ( c > 0 )
   417       ret += chr;
   417 			ret += chr;
   418     ret += arr[i];
   418 		ret += arr[i];
   419     c++;
   419 		c++;
   420   }
   420 	}
   421   return ret;
   421 	return ret;
   422 }
   422 }
   423 
   423 
   424 function form_fetch_field(form, name)
   424 function form_fetch_field(form, name)
   425 {
   425 {
   426   var fields = form.getElementsByTagName('input');
   426 	var fields = form.getElementsByTagName('input');
   427   if ( fields.length < 1 )
   427 	if ( fields.length < 1 )
   428     return false;
   428 		return false;
   429   for ( var i = 0; i < fields.length; i++ )
   429 	for ( var i = 0; i < fields.length; i++ )
   430   {
   430 	{
   431     var field = fields[i];
   431 		var field = fields[i];
   432     if ( field.name == name )
   432 		if ( field.name == name )
   433       return field;
   433 			return field;
   434   }
   434 	}
   435   return false;
   435 	return false;
   436 }
   436 }
   437 
   437 
   438 function get_parent_form(o)
   438 function get_parent_form(o)
   439 {
   439 {
   440   if ( !o.parentNode )
   440 	if ( !o.parentNode )
   441     return false;
   441 		return false;
   442   if ( o.tagName == 'FORM' )
   442 	if ( o.tagName == 'FORM' )
   443     return o;
   443 		return o;
   444   var p = o.parentNode;
   444 	var p = o.parentNode;
   445   while(true)
   445 	while(true)
   446   {
   446 	{
   447     if ( p.tagName == 'FORM' )
   447 		if ( p.tagName == 'FORM' )
   448       return p;
   448 			return p;
   449     else if ( !p )
   449 		else if ( !p )
   450       return false;
   450 			return false;
   451     else
   451 		else
   452       p = p.parentNode;
   452 			p = p.parentNode;
   453   }
   453 	}
   454 }
   454 }
   455 
   455 
   456 /**
   456 /**
   457  * Return a DOMElement that uses a sprite image.
   457  * Return a DOMElement that uses a sprite image.
   458  * @param string Path to sprite image
   458  * @param string Path to sprite image
   463  * @return object HTMLImageElement
   463  * @return object HTMLImageElement
   464  */
   464  */
   465 
   465 
   466 function gen_sprite(path, width, height, xpos, ypos)
   466 function gen_sprite(path, width, height, xpos, ypos)
   467 {
   467 {
   468   var image = document.createElement('img');
   468 	var image = document.createElement('img');
   469   image.src = cdnPath + '/images/spacer.gif';
   469 	image.src = cdnPath + '/images/spacer.gif';
   470   image.width = String(width);
   470 	image.width = String(width);
   471   image.height = String(height);
   471 	image.height = String(height);
   472   image.style.backgroundImage = 'url(' + path + ')';
   472 	image.style.backgroundImage = 'url(' + path + ')';
   473   image.style.backgroundRepeat = 'no-repeat';
   473 	image.style.backgroundRepeat = 'no-repeat';
   474   xpos = ( xpos == 0 ) ? '0' : '-' + String(xpos);
   474 	xpos = ( xpos == 0 ) ? '0' : '-' + String(xpos);
   475   ypos = ( ypos == 0 ) ? '0' : '-' + String(ypos);
   475 	ypos = ( ypos == 0 ) ? '0' : '-' + String(ypos);
   476   image.style.backgroundPosition = ypos + 'px ' + xpos + 'px';
   476 	image.style.backgroundPosition = ypos + 'px ' + xpos + 'px';
   477   
   477 	
   478   return image;
   478 	return image;
   479 }
   479 }
   480 
   480 
   481 /**
   481 /**
   482  * The same as gen_sprite but generates HTML instead of a DOMElement.
   482  * The same as gen_sprite but generates HTML instead of a DOMElement.
   483  * @param string Path to sprite image
   483  * @param string Path to sprite image
   488  * @return object HTMLImageElement
   488  * @return object HTMLImageElement
   489  */
   489  */
   490 
   490 
   491 function gen_sprite_html(path, width, height, xpos, ypos)
   491 function gen_sprite_html(path, width, height, xpos, ypos)
   492 {
   492 {
   493   var html = '<img src="' + scriptPath + '/images/spacer.gif" width="' + width + '" height="' + height + '" ';
   493 	var html = '<img src="' + scriptPath + '/images/spacer.gif" width="' + width + '" height="' + height + '" ';
   494   xpos = ( xpos == 0 ) ? '0' : '-' + String(xpos);
   494 	xpos = ( xpos == 0 ) ? '0' : '-' + String(xpos);
   495   ypos = ( ypos == 0 ) ? '0' : '-' + String(ypos);
   495 	ypos = ( ypos == 0 ) ? '0' : '-' + String(ypos);
   496   html += 'style="background-image: url(' + path + '); background-repeat: no-repeat; background-position: ' + ypos + 'px ' + xpos + 'px;"';
   496 	html += 'style="background-image: url(' + path + '); background-repeat: no-repeat; background-position: ' + ypos + 'px ' + xpos + 'px;"';
   497   html += ' />';
   497 	html += ' />';
   498   
   498 	
   499   return html;
   499 	return html;
   500 }
   500 }
   501 
   501 
   502 function findParentForm(o)
   502 function findParentForm(o)
   503 {
   503 {
   504   return get_parent_form(o);
   504 	return get_parent_form(o);
   505 }
   505 }
   506 
   506 
   507 function domObjChangeOpac(opacity, id)
   507 function domObjChangeOpac(opacity, id)
   508 {
   508 {
   509   if ( !id )
   509 	if ( !id )
   510     return false;
   510 		return false;
   511   
   511 	
   512   var object = id.style;
   512 	var object = id.style;
   513   object.opacity = (opacity / 100);
   513 	object.opacity = (opacity / 100);
   514   object.MozOpacity = (opacity / 100);
   514 	object.MozOpacity = (opacity / 100);
   515   object.KhtmlOpacity = (opacity / 100);
   515 	object.KhtmlOpacity = (opacity / 100);
   516   object.filter = "alpha(opacity=" + opacity + ")";
   516 	object.filter = "alpha(opacity=" + opacity + ")";
   517 }
   517 }
   518 
   518 
   519 function getScrollOffset(el)
   519 function getScrollOffset(el)
   520 {
   520 {
   521   var position;
   521 	var position;
   522   var s = el || self;
   522 	var s = el || self;
   523   el = el || document;
   523 	el = el || document;
   524   if ( el.scrollTop )
   524 	if ( el.scrollTop )
   525   {
   525 	{
   526     position = el.scrollTop;
   526 		position = el.scrollTop;
   527   }
   527 	}
   528   else if (s.pageYOffset)
   528 	else if (s.pageYOffset)
   529   {
   529 	{
   530     position = self.pageYOffset;
   530 		position = self.pageYOffset;
   531   }
   531 	}
   532   else if (document.documentElement && document.documentElement.scrollTop)
   532 	else if (document.documentElement && document.documentElement.scrollTop)
   533   {
   533 	{
   534     position = document.documentElement.scrollTop;
   534 		position = document.documentElement.scrollTop;
   535   }
   535 	}
   536   else if (document.body)
   536 	else if (document.body)
   537   {
   537 	{
   538     position = document.body.scrollTop;
   538 		position = document.body.scrollTop;
   539   }
   539 	}
   540   return position;
   540 	return position;
   541 }
   541 }
   542 
   542 
   543 function setScrollOffset(offset)
   543 function setScrollOffset(offset)
   544 {
   544 {
   545   window.scroll(0, offset);
   545 	window.scroll(0, offset);
   546 }
   546 }
   547 
   547 
   548 // Function to fade classes info-box, warning-box, error-box, etc.
   548 // Function to fade classes info-box, warning-box, error-box, etc.
   549 
   549 
   550 function fadeInfoBoxes()
   550 function fadeInfoBoxes()
   551 {
   551 {
   552   var divs = new Array();
   552 	var divs = new Array();
   553   d = document.getElementsByTagName('div');
   553 	d = document.getElementsByTagName('div');
   554   j = 0;
   554 	j = 0;
   555   for(var i in d)
   555 	for(var i in d)
   556   {
   556 	{
   557     if ( !d[i] )
   557 		if ( !d[i] )
   558       continue;
   558 			continue;
   559     if ( !d[i].tagName )
   559 		if ( !d[i].tagName )
   560       continue;
   560 			continue;
   561     if(d[i].className=='info-box' || d[i].className=='error-box' || d[i].className=='warning-box' || d[i].className=='question-box')
   561 		if(d[i].className=='info-box' || d[i].className=='error-box' || d[i].className=='warning-box' || d[i].className=='question-box')
   562     {
   562 		{
   563       divs[j] = d[i];
   563 			divs[j] = d[i];
   564       j++;
   564 			j++;
   565     }
   565 		}
   566   }
   566 	}
   567   if(divs.length < 1) return;
   567 	if(divs.length < 1) return;
   568   load_component('fat');
   568 	load_component('fat');
   569   for(i in divs)
   569 	for(i in divs)
   570   {
   570 	{
   571     if(!divs[i].id) divs[i].id = 'autofade_'+Math.floor(Math.random() * 100000);
   571 		if(!divs[i].id) divs[i].id = 'autofade_'+Math.floor(Math.random() * 100000);
   572     switch(divs[i].className)
   572 		switch(divs[i].className)
   573     {
   573 		{
   574       case 'info-box':
   574 			case 'info-box':
   575       default:
   575 			default:
   576         from = '#3333FF';
   576 				from = '#3333FF';
   577         break;
   577 				break;
   578       case 'error-box':
   578 			case 'error-box':
   579         from = '#FF3333';
   579 				from = '#FF3333';
   580         break;
   580 				break;
   581       case 'warning-box':
   581 			case 'warning-box':
   582         from = '#FFFF33';
   582 				from = '#FFFF33';
   583         break;
   583 				break;
   584       case 'question-box':
   584 			case 'question-box':
   585         from = '#33FF33';
   585 				from = '#33FF33';
   586         break;
   586 				break;
   587     }
   587 		}
   588     Fat.fade_element(divs[i].id,30,2000,from,Fat.get_bgcolor(divs[i].id));
   588 		Fat.fade_element(divs[i].id,30,2000,from,Fat.get_bgcolor(divs[i].id));
   589   }
   589 	}
   590 }
   590 }
   591 
   591 
   592 addOnloadHook(fadeInfoBoxes);
   592 addOnloadHook(fadeInfoBoxes);
   593 
   593 
   594 // Alpha fades
   594 // Alpha fades
   595 
   595 
   596 function opacity(id, opacStart, opacEnd, millisec)
   596 function opacity(id, opacStart, opacEnd, millisec)
   597 {
   597 {
   598     var object = document.getElementById(id);
   598 		var object = document.getElementById(id);
   599     domOpacity(object, opacStart, opacEnd, millisec);
   599 		domOpacity(object, opacStart, opacEnd, millisec);
   600 }
   600 }
   601 
   601 
   602 var opacityDOMCache = {};
   602 var opacityDOMCache = {};
   603 function domOpacity(obj, opacStart, opacEnd, millisec) {
   603 function domOpacity(obj, opacStart, opacEnd, millisec) {
   604     //speed for each frame
   604 		//speed for each frame
   605     var speed = Math.round(millisec / 100);
   605 		var speed = Math.round(millisec / 100);
   606     var timer = 0;
   606 		var timer = 0;
   607     
   607 		
   608     // unique ID for this animation
   608 		// unique ID for this animation
   609     var uniqid = Math.floor(Math.random() * 1000000);
   609 		var uniqid = Math.floor(Math.random() * 1000000);
   610     opacityDOMCache[uniqid] = obj;
   610 		opacityDOMCache[uniqid] = obj;
   611 
   611 
   612     //determine the direction for the blending, if start and end are the same nothing happens
   612 		//determine the direction for the blending, if start and end are the same nothing happens
   613     if(opacStart > opacEnd) {
   613 		if(opacStart > opacEnd) {
   614         for(i = opacStart; i >= opacEnd; i--) {
   614 				for(i = opacStart; i >= opacEnd; i--) {
   615             setTimeout("if ( opacityDOMCache["+uniqid+"] ) { var obj = opacityDOMCache["+uniqid+"]; domObjChangeOpac(" + i + ",obj) }",(timer * speed));
   615 						setTimeout("if ( opacityDOMCache["+uniqid+"] ) { var obj = opacityDOMCache["+uniqid+"]; domObjChangeOpac(" + i + ",obj) }",(timer * speed));
   616             timer++;
   616 						timer++;
   617         }
   617 				}
   618     } else if(opacStart < opacEnd) {
   618 		} else if(opacStart < opacEnd) {
   619         for(i = opacStart; i <= opacEnd; i++)
   619 				for(i = opacStart; i <= opacEnd; i++)
   620             {
   620 						{
   621             setTimeout("if ( opacityDOMCache["+uniqid+"] ) { var obj = opacityDOMCache["+uniqid+"]; domObjChangeOpac(" + i + ",obj); }",(timer * speed));
   621 						setTimeout("if ( opacityDOMCache["+uniqid+"] ) { var obj = opacityDOMCache["+uniqid+"]; domObjChangeOpac(" + i + ",obj); }",(timer * speed));
   622             timer++;
   622 						timer++;
   623         }
   623 				}
   624     }
   624 		}
   625     setTimeout("delete(opacityDOMCache["+uniqid+"]);",(timer * speed));
   625 		setTimeout("delete(opacityDOMCache["+uniqid+"]);",(timer * speed));
   626 }
   626 }
   627 
   627 
   628 function abortFades()
   628 function abortFades()
   629 {
   629 {
   630   opacityDOMCache = {};
   630 	opacityDOMCache = {};
   631 }
   631 }
   632 
   632 
   633 // change the opacity for different browsers
   633 // change the opacity for different browsers
   634 function changeOpac(opacity, id)
   634 function changeOpac(opacity, id)
   635 {
   635 {
   636   var object = document.getElementById(id);
   636 	var object = document.getElementById(id);
   637   return domObjChangeOpac(opacity, object);
   637 	return domObjChangeOpac(opacity, object);
   638 }
   638 }
   639 
   639 
   640 // draw a white ajax-ey "loading" box over an object
   640 // draw a white ajax-ey "loading" box over an object
   641 function whiteOutElement(el)
   641 function whiteOutElement(el)
   642 {
   642 {
   643   var top = $dynano(el).Top();
   643 	var top = $dynano(el).Top();
   644   var left = $dynano(el).Left();
   644 	var left = $dynano(el).Left();
   645   var width = $dynano(el).Width();
   645 	var width = $dynano(el).Width();
   646   var height = $dynano(el).Height();
   646 	var height = $dynano(el).Height();
   647   
   647 	
   648   var blackout = document.createElement('div');
   648 	var blackout = document.createElement('div');
   649   // using fixed here allows modal windows to be blacked out
   649 	// using fixed here allows modal windows to be blacked out
   650   blackout.style.position = ( el.style.position == 'fixed' ) ? 'fixed' : 'absolute';
   650 	blackout.style.position = ( el.style.position == 'fixed' ) ? 'fixed' : 'absolute';
   651   blackout.style.top = top + 'px';
   651 	blackout.style.top = top + 'px';
   652   blackout.style.left = left + 'px';
   652 	blackout.style.left = left + 'px';
   653   blackout.style.width = width + 'px';
   653 	blackout.style.width = width + 'px';
   654   blackout.style.height = height + 'px';
   654 	blackout.style.height = height + 'px';
   655   
   655 	
   656   blackout.style.backgroundColor = '#FFFFFF';
   656 	blackout.style.backgroundColor = '#FFFFFF';
   657   domObjChangeOpac(60, blackout);
   657 	domObjChangeOpac(60, blackout);
   658   var background = ( $dynano(el).Height() < 48 ) ? 'url(' + scriptPath + '/images/loading.gif)' : 'url(' + scriptPath + '/includes/clientside/tinymce/themes/advanced/skins/default/img/progress.gif)';
   658 	var background = ( $dynano(el).Height() < 48 ) ? 'url(' + scriptPath + '/images/loading.gif)' : 'url(' + scriptPath + '/includes/clientside/tinymce/themes/advanced/skins/default/img/progress.gif)';
   659   blackout.style.backgroundImage = background;
   659 	blackout.style.backgroundImage = background;
   660   blackout.style.backgroundPosition = 'center center';
   660 	blackout.style.backgroundPosition = 'center center';
   661   blackout.style.backgroundRepeat = 'no-repeat';
   661 	blackout.style.backgroundRepeat = 'no-repeat';
   662   blackout.style.zIndex = getHighestZ() + 2;
   662 	blackout.style.zIndex = getHighestZ() + 2;
   663   
   663 	
   664   var body = document.getElementsByTagName('body')[0];
   664 	var body = document.getElementsByTagName('body')[0];
   665   body.appendChild(blackout);
   665 	body.appendChild(blackout);
   666   
   666 	
   667   return blackout;
   667 	return blackout;
   668 }
   668 }
   669 
   669 
   670 /**
   670 /**
   671  * Take a div generated by whiteOutElement() and report success using the glossy "check" graphic. Sets the image, then
   671  * Take a div generated by whiteOutElement() and report success using the glossy "check" graphic. Sets the image, then
   672  * briefly fades in, then fades out and destroys the box so as to re-allow control over the underlying element
   672  * briefly fades in, then fades out and destroys the box so as to re-allow control over the underlying element
   673  */
   673  */
   674 
   674 
   675 function whiteOutReportSuccess(whitey, nodestroy_mp)
   675 function whiteOutReportSuccess(whitey, nodestroy_mp)
   676 {
   676 {
   677   whiteOutDestroyWithImage(whitey, cdnPath + '/images/check.png', nodestroy_mp);
   677 	whiteOutDestroyWithImage(whitey, cdnPath + '/images/check.png', nodestroy_mp);
   678 }
   678 }
   679 
   679 
   680 function whiteOutReportFailure(whitey, nodestroy_mp)
   680 function whiteOutReportFailure(whitey, nodestroy_mp)
   681 {
   681 {
   682   if ( typeof(nodestroy_mp) == undefined )
   682 	if ( typeof(nodestroy_mp) == undefined )
   683     nodestroy_mp = true;
   683 		nodestroy_mp = true;
   684     
   684 		
   685   whiteOutDestroyWithImage(whitey, cdnPath + '/images/checkbad.png', nodestroy_mp);
   685 	whiteOutDestroyWithImage(whitey, cdnPath + '/images/checkbad.png', nodestroy_mp);
   686 }
   686 }
   687 
   687 
   688 function whiteOutDestroyWithImage(whitey, image, nodestroy_mp)
   688 function whiteOutDestroyWithImage(whitey, image, nodestroy_mp)
   689 {
   689 {
   690   // fade the status indicator in and then out
   690 	// fade the status indicator in and then out
   691   whitey.style.backgroundImage = 'url(' + image + ')';
   691 	whitey.style.backgroundImage = 'url(' + image + ')';
   692   if ( whitey.isMiniPrompt && !nodestroy_mp )
   692 	if ( whitey.isMiniPrompt && !nodestroy_mp )
   693   {
   693 	{
   694     setTimeout(function()
   694 		setTimeout(function()
   695       {
   695 			{
   696         whiteOutDestroyOnMiniPrompt(whitey);
   696 				whiteOutDestroyOnMiniPrompt(whitey);
   697       }, 500);
   697 			}, 500);
   698     return true;
   698 		return true;
   699   }
   699 	}
   700   if ( aclDisableTransitionFX )
   700 	if ( aclDisableTransitionFX )
   701   {
   701 	{
   702     domObjChangeOpac(80, whitey);
   702 		domObjChangeOpac(80, whitey);
   703   }
   703 	}
   704   else
   704 	else
   705   {
   705 	{
   706     domOpacity(whitey, 60, 80, 500);
   706 		domOpacity(whitey, 60, 80, 500);
   707     setTimeout(function()
   707 		setTimeout(function()
   708       {
   708 			{
   709         domOpacity(whitey, 60, 0, 500);
   709 				domOpacity(whitey, 60, 0, 500);
   710       }, 750);
   710 			}, 750);
   711   }
   711 	}
   712   setTimeout(function()
   712 	setTimeout(function()
   713     {
   713 		{
   714       if ( whitey )
   714 			if ( whitey )
   715         if ( whitey.parentNode )
   715 				if ( whitey.parentNode )
   716           whitey.parentNode.removeChild(whitey);
   716 					whitey.parentNode.removeChild(whitey);
   717     }, 1250);
   717 		}, 1250);
   718 }
   718 }
   719 
   719 
   720 /**
   720 /**
   721  * Whites out a form and disables all buttons under it. Useful for onsubmit functions.
   721  * Whites out a form and disables all buttons under it. Useful for onsubmit functions.
   722  * @example
   722  * @example
   727  * @return object Whiteout div
   727  * @return object Whiteout div
   728  */
   728  */
   729 
   729 
   730 function whiteOutForm(form)
   730 function whiteOutForm(form)
   731 {
   731 {
   732   if ( !form.getElementsByTagName )
   732 	if ( !form.getElementsByTagName )
   733     return false;
   733 		return false;
   734   
   734 	
   735   // disable all buttons
   735 	// disable all buttons
   736   var buttons = form.getElementsByTagName('input');
   736 	var buttons = form.getElementsByTagName('input');
   737   for ( var i = 0; i < buttons.length; i++ )
   737 	for ( var i = 0; i < buttons.length; i++ )
   738   {
   738 	{
   739     if ( buttons[i].type == 'button' || buttons[i].type == 'submit' || buttons[i].type == 'image' )
   739 		if ( buttons[i].type == 'button' || buttons[i].type == 'submit' || buttons[i].type == 'image' )
   740     {
   740 		{
   741       buttons[i].disabled = 'disabled';
   741 			buttons[i].disabled = 'disabled';
   742       // ... but also make a hidden element to preserve any flags
   742 			// ... but also make a hidden element to preserve any flags
   743       var clone = buttons[i].cloneNode(true);
   743 			var clone = buttons[i].cloneNode(true);
   744       clone.type = 'hidden';
   744 			clone.type = 'hidden';
   745       clone.disabled = false;
   745 			clone.disabled = false;
   746       console.debug(clone);
   746 			console.debug(clone);
   747       form.appendChild(clone);
   747 			form.appendChild(clone);
   748     }
   748 		}
   749   }
   749 	}
   750   var buttons = form.getElementsByTagName('button');
   750 	var buttons = form.getElementsByTagName('button');
   751   for ( var i = 0; i < buttons.length; i++ )
   751 	for ( var i = 0; i < buttons.length; i++ )
   752   {
   752 	{
   753     buttons[i].disabled = 'disabled';
   753 		buttons[i].disabled = 'disabled';
   754     // ... but also make a hidden element to preserve any flags
   754 		// ... but also make a hidden element to preserve any flags
   755     if ( buttons[i].name )
   755 		if ( buttons[i].name )
   756     {
   756 		{
   757       var clone = document.createElement('input');
   757 			var clone = document.createElement('input');
   758       clone.type = 'hidden';
   758 			clone.type = 'hidden';
   759       clone.name = buttons[i].name;
   759 			clone.name = buttons[i].name;
   760       clone.value = ( buttons[i].value ) ? buttons[i].value : '';
   760 			clone.value = ( buttons[i].value ) ? buttons[i].value : '';
   761       form.appendChild(clone);
   761 			form.appendChild(clone);
   762     }
   762 		}
   763   }
   763 	}
   764   
   764 	
   765   return whiteOutElement(form);
   765 	return whiteOutElement(form);
   766 }
   766 }
   767 
   767 
   768 // other DHTML functions
   768 // other DHTML functions
   769 
   769 
   770 function fetch_offset(obj)
   770 function fetch_offset(obj)
   771 {
   771 {
   772   var left_offset = obj.offsetLeft;
   772 	var left_offset = obj.offsetLeft;
   773   var top_offset = obj.offsetTop;
   773 	var top_offset = obj.offsetTop;
   774   while ((obj = obj.offsetParent) != null) {
   774 	while ((obj = obj.offsetParent) != null) {
   775     left_offset += obj.offsetLeft;
   775 		left_offset += obj.offsetLeft;
   776     top_offset += obj.offsetTop;
   776 		top_offset += obj.offsetTop;
   777   }
   777 	}
   778   return { 'left' : left_offset, 'top' : top_offset };
   778 	return { 'left' : left_offset, 'top' : top_offset };
   779 }
   779 }
   780 
   780 
   781 function fetch_dimensions(o) {
   781 function fetch_dimensions(o) {
   782   var w = o.offsetWidth;
   782 	var w = o.offsetWidth;
   783   var h = o.offsetHeight;
   783 	var h = o.offsetHeight;
   784   return { 'w' : w, 'h' : h };
   784 	return { 'w' : w, 'h' : h };
   785 }
   785 }
   786 
   786 
   787 function findParentForm(o)
   787 function findParentForm(o)
   788 {
   788 {
   789   if ( o.tagName == 'FORM' )
   789 	if ( o.tagName == 'FORM' )
   790     return o;
   790 		return o;
   791   while(true)
   791 	while(true)
   792   {
   792 	{
   793     o = o.parentNode;
   793 		o = o.parentNode;
   794     if ( !o )
   794 		if ( !o )
   795       return false;
   795 			return false;
   796     if ( o.tagName == 'FORM' )
   796 		if ( o.tagName == 'FORM' )
   797       return o;
   797 			return o;
   798   }
   798 	}
   799   return false;
   799 	return false;
   800 }
   800 }
   801 
   801 
   802 function bannerOn(text)
   802 function bannerOn(text)
   803 {
   803 {
   804   darken(true);
   804 	darken(true);
   805   var thediv = document.createElement('div');
   805 	var thediv = document.createElement('div');
   806   thediv.className = 'mdg-comment';
   806 	thediv.className = 'mdg-comment';
   807   thediv.style.padding = '0';
   807 	thediv.style.padding = '0';
   808   thediv.style.marginLeft = '0';
   808 	thediv.style.marginLeft = '0';
   809   thediv.style.position = 'absolute';
   809 	thediv.style.position = 'absolute';
   810   thediv.style.display = 'none';
   810 	thediv.style.display = 'none';
   811   thediv.style.padding = '4px';
   811 	thediv.style.padding = '4px';
   812   thediv.style.fontSize = '14pt';
   812 	thediv.style.fontSize = '14pt';
   813   thediv.id = 'mdgDynamic_bannerDiv_'+Math.floor(Math.random() * 1000000);
   813 	thediv.id = 'mdgDynamic_bannerDiv_'+Math.floor(Math.random() * 1000000);
   814   thediv.innerHTML = text;
   814 	thediv.innerHTML = text;
   815   
   815 	
   816   var body = document.getElementsByTagName('body');
   816 	var body = document.getElementsByTagName('body');
   817   body = body[0];
   817 	body = body[0];
   818   body.appendChild(thediv);
   818 	body.appendChild(thediv);
   819   body.style.cursor = 'wait';
   819 	body.style.cursor = 'wait';
   820   
   820 	
   821   thediv.style.display = 'block';
   821 	thediv.style.display = 'block';
   822   dim = fetch_dimensions(thediv);
   822 	dim = fetch_dimensions(thediv);
   823   thediv.style.display = 'none';
   823 	thediv.style.display = 'none';
   824   bdim = { 'w' : getWidth(), 'h' : getHeight() };
   824 	bdim = { 'w' : getWidth(), 'h' : getHeight() };
   825   so = getScrollOffset();
   825 	so = getScrollOffset();
   826   
   826 	
   827   var left = (bdim['w'] / 2) - ( dim['w'] / 2 );
   827 	var left = (bdim['w'] / 2) - ( dim['w'] / 2 );
   828   
   828 	
   829   var top  = (bdim['h'] / 2);
   829 	var top  = (bdim['h'] / 2);
   830   top  = top - ( dim['h'] / 2 );
   830 	top  = top - ( dim['h'] / 2 );
   831   
   831 	
   832   top = top + so;
   832 	top = top + so;
   833   
   833 	
   834   thediv.style.top  = top  + 'px';
   834 	thediv.style.top  = top  + 'px';
   835   thediv.style.left = left + 'px';
   835 	thediv.style.left = left + 'px';
   836   
   836 	
   837   thediv.style.display = 'block';
   837 	thediv.style.display = 'block';
   838   
   838 	
   839   return thediv.id;
   839 	return thediv.id;
   840 }
   840 }
   841 
   841 
   842 function bannerOff(id)
   842 function bannerOff(id)
   843 {
   843 {
   844   e = document.getElementById(id);
   844 	e = document.getElementById(id);
   845   if(!e) return;
   845 	if(!e) return;
   846   e.innerHTML = '';
   846 	e.innerHTML = '';
   847   e.style.display = 'none';
   847 	e.style.display = 'none';
   848   var body = document.getElementsByTagName('body');
   848 	var body = document.getElementsByTagName('body');
   849   body = body[0];
   849 	body = body[0];
   850   body.style.cursor = 'default';
   850 	body.style.cursor = 'default';
   851   enlighten(true);
   851 	enlighten(true);
   852 }
   852 }
   853 
   853 
   854 function disableUnload(message)
   854 function disableUnload(message)
   855 {
   855 {
   856   if(typeof message != 'string') message = 'You may want to save your changes first.';
   856 	if(typeof message != 'string') message = 'You may want to save your changes first.';
   857   window._unloadmsg = message;
   857 	window._unloadmsg = message;
   858   window.onbeforeunload = function(e)
   858 	window.onbeforeunload = function(e)
   859   {
   859 	{
   860     if ( !e )
   860 		if ( !e )
   861       e = window.event;
   861 			e = window.event;
   862     e.returnValue = window._unloadmsg;
   862 		e.returnValue = window._unloadmsg;
   863   }
   863 	}
   864 }
   864 }
   865 
   865 
   866 function enableUnload()
   866 function enableUnload()
   867 {
   867 {
   868   window._unloadmsg = null;
   868 	window._unloadmsg = null;
   869   window.onbeforeunload = null;
   869 	window.onbeforeunload = null;
   870 }
   870 }
   871 
   871 
   872 /**
   872 /**
   873  * Gets the highest z-index of all divs in the document
   873  * Gets the highest z-index of all divs in the document
   874  * @return integer
   874  * @return integer
   875  */
   875  */
   876 function getHighestZ()
   876 function getHighestZ()
   877 {
   877 {
   878   z = 0;
   878 	z = 0;
   879   var divs = document.getElementsByTagName('div');
   879 	var divs = document.getElementsByTagName('div');
   880   for(var i = 0; i < divs.length; i++)
   880 	for(var i = 0; i < divs.length; i++)
   881   {
   881 	{
   882     if ( divs[i].style.zIndex > z && divs[i].style.display != 'none' )
   882 		if ( divs[i].style.zIndex > z && divs[i].style.display != 'none' )
   883       z = divs[i].style.zIndex;
   883 			z = divs[i].style.zIndex;
   884   }
   884 	}
   885   return parseInt(z);
   885 	return parseInt(z);
   886 }
   886 }
   887 
   887 
   888 var shift = false;
   888 var shift = false;
   889 function isKeyPressed(event)
   889 function isKeyPressed(event)
   890 {
   890 {
   891   if (event.shiftKey==1)
   891 	if (event.shiftKey==1)
   892   {
   892 	{
   893     shift = true;
   893 		shift = true;
   894   }
   894 	}
   895   else
   895 	else
   896   {
   896 	{
   897     shift = false;
   897 		shift = false;
   898   }
   898 	}
   899 }
   899 }
   900 
   900 
   901 function moveDiv(div, newparent)
   901 function moveDiv(div, newparent)
   902 {
   902 {
   903   var backup = div;
   903 	var backup = div;
   904   var oldparent = div.parentNode;
   904 	var oldparent = div.parentNode;
   905   oldparent.removeChild(div);
   905 	oldparent.removeChild(div);
   906   newparent.appendChild(backup);
   906 	newparent.appendChild(backup);
   907 }
   907 }
   908 
   908 
   909 var busyBannerID;
   909 var busyBannerID;
   910 function goBusy(msg)
   910 function goBusy(msg)
   911 {
   911 {
   912   if(!msg) msg = 'Please wait...';
   912 	if(!msg) msg = 'Please wait...';
   913   body = document.getElementsByTagName('body');
   913 	body = document.getElementsByTagName('body');
   914   body = body[0];
   914 	body = body[0];
   915   body.style.cursor = 'wait';
   915 	body.style.cursor = 'wait';
   916   busyBannerID = bannerOn(msg);
   916 	busyBannerID = bannerOn(msg);
   917 }
   917 }
   918 
   918 
   919 function unBusy()
   919 function unBusy()
   920 {
   920 {
   921   body = document.getElementsByTagName('body');
   921 	body = document.getElementsByTagName('body');
   922   body = body[0];
   922 	body = body[0];
   923   body.style.cursor = 'default';
   923 	body.style.cursor = 'default';
   924   bannerOff(busyBannerID);
   924 	bannerOff(busyBannerID);
   925 }
   925 }
   926 
   926 
   927 function setAjaxLoading()
   927 function setAjaxLoading()
   928 {
   928 {
   929   if ( document.getElementById('ajaxloadicon') )
   929 	if ( document.getElementById('ajaxloadicon') )
   930   {
   930 	{
   931     document.getElementById('ajaxloadicon').src=ajax_load_icon;
   931 		document.getElementById('ajaxloadicon').src=ajax_load_icon;
   932   }
   932 	}
   933 }
   933 }
   934 
   934 
   935 function unsetAjaxLoading()
   935 function unsetAjaxLoading()
   936 {
   936 {
   937   if ( document.getElementById('ajaxloadicon') )
   937 	if ( document.getElementById('ajaxloadicon') )
   938   {
   938 	{
   939     document.getElementById('ajaxloadicon').src=cdnPath + '/images/spacer.gif';
   939 		document.getElementById('ajaxloadicon').src=cdnPath + '/images/spacer.gif';
   940   }
   940 	}
   941 }
   941 }
   942 
   942 
   943 function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
   943 function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
   944 function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
   944 function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
   945 function eraseCookie(name) {createCookie(name,"",-1);}
   945 function eraseCookie(name) {createCookie(name,"",-1);}
   950  */
   950  */
   951 
   951 
   952 // Included only for API-compatibility
   952 // Included only for API-compatibility
   953 function ajaxPromptAdminAuth(call_on_ok, level)
   953 function ajaxPromptAdminAuth(call_on_ok, level)
   954 {
   954 {
   955   ajaxLoginInit(call_on_ok, level);
   955 	ajaxLoginInit(call_on_ok, level);
   956 }
   956 }
   957 
   957 
   958 /**
   958 /**
   959  * Insert a DOM object _after_ the specified child.
   959  * Insert a DOM object _after_ the specified child.
   960  * @param object Parent node
   960  * @param object Parent node
   962  * @param object Node to insert after
   962  * @param object Node to insert after
   963  */
   963  */
   964 
   964 
   965 function insertAfter(parent, baby, bigsister)
   965 function insertAfter(parent, baby, bigsister)
   966 {
   966 {
   967   try
   967 	try
   968   {
   968 	{
   969     if ( parent.childNodes[parent.childNodes.length-1] == bigsister )
   969 		if ( parent.childNodes[parent.childNodes.length-1] == bigsister )
   970       parent.appendChild(baby);
   970 			parent.appendChild(baby);
   971     else
   971 		else
   972       parent.insertBefore(baby, bigsister.nextSibling);
   972 			parent.insertBefore(baby, bigsister.nextSibling);
   973   }
   973 	}
   974   catch(e)
   974 	catch(e)
   975   {
   975 	{
   976     alert(e.toString());
   976 		alert(e.toString());
   977     if ( window.console )
   977 		if ( window.console )
   978     {
   978 		{
   979       // Firebug support
   979 			// Firebug support
   980       window.console.warn(e);
   980 			window.console.warn(e);
   981     }
   981 		}
   982   }
   982 	}
   983 }
   983 }
   984 
   984 
   985 /**
   985 /**
   986  * Validates an e-mail address.
   986  * Validates an e-mail address.
   987  * @param string E-mail address
   987  * @param string E-mail address
   988  * @return bool
   988  * @return bool
   989  */
   989  */
   990 
   990 
   991 function validateEmail(email)
   991 function validateEmail(email)
   992 {
   992 {
   993   return ( email.match(/^(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*>)$/) ) ? true : false;
   993 	return ( email.match(/^(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*)*<[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*>)$/) ) ? true : false;
   994 }
   994 }
   995 
   995 
   996 /**
   996 /**
   997  * Validates a username.
   997  * Validates a username.
   998  * @param string Username to test
   998  * @param string Username to test
   999  * @return bool
   999  * @return bool
  1000  */
  1000  */
  1001 
  1001 
  1002 function validateUsername(username)
  1002 function validateUsername(username)
  1003 {
  1003 {
  1004   var regex = new RegExp('^[^<>&\?\'"%\n\r/]+$', '');
  1004 	var regex = new RegExp('^[^<>&\?\'"%\n\r/]+$', '');
  1005   return ( username.match(regex) ) ? true : false;
  1005 	return ( username.match(regex) ) ? true : false;
  1006 }
  1006 }
  1007 
  1007 
  1008 /*
  1008 /*
  1009  * Utility functions, moved from windows.js
  1009  * Utility functions, moved from windows.js
  1010  */
  1010  */
  1011 
  1011 
  1012 function getHeight() {
  1012 function getHeight() {
  1013   var myHeight = 0;
  1013 	var myHeight = 0;
  1014   if( typeof( window.innerWidth ) == 'number' ) {
  1014 	if( typeof( window.innerWidth ) == 'number' ) {
  1015     myHeight = window.innerHeight;
  1015 		myHeight = window.innerHeight;
  1016   } else if( document.documentElement &&
  1016 	} else if( document.documentElement &&
  1017       ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
  1017 			( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
  1018     myHeight = document.documentElement.clientHeight;
  1018 		myHeight = document.documentElement.clientHeight;
  1019   } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
  1019 	} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
  1020     myHeight = document.body.clientHeight;
  1020 		myHeight = document.body.clientHeight;
  1021   }
  1021 	}
  1022   return myHeight;
  1022 	return myHeight;
  1023 }
  1023 }
  1024 
  1024 
  1025 function getWidth() {
  1025 function getWidth() {
  1026   var myWidth = 0;
  1026 	var myWidth = 0;
  1027   if( typeof( window.innerWidth ) == 'number' ) {
  1027 	if( typeof( window.innerWidth ) == 'number' ) {
  1028     myWidth = window.innerWidth;
  1028 		myWidth = window.innerWidth;
  1029   } else if( document.documentElement &&
  1029 	} else if( document.documentElement &&
  1030       ( document.documentElement.clientWidth || document.documentElement.clientWidth ) ) {
  1030 			( document.documentElement.clientWidth || document.documentElement.clientWidth ) ) {
  1031     myWidth = document.documentElement.clientWidth;
  1031 		myWidth = document.documentElement.clientWidth;
  1032   } else if( document.body && ( document.body.clientWidth || document.body.clientWidth ) ) {
  1032 	} else if( document.body && ( document.body.clientWidth || document.body.clientWidth ) ) {
  1033     myWidth = document.body.clientWidth;
  1033 		myWidth = document.body.clientWidth;
  1034   }
  1034 	}
  1035   return myWidth;
  1035 	return myWidth;
  1036 }
  1036 }
  1037 
  1037 
  1038 /**
  1038 /**
  1039  * Sanitizes a page URL string so that it can safely be stored in the database.
  1039  * Sanitizes a page URL string so that it can safely be stored in the database.
  1040  * @param string Page ID to sanitize
  1040  * @param string Page ID to sanitize
  1041  * @return string Cleaned text
  1041  * @return string Cleaned text
  1042  */
  1042  */
  1043 
  1043 
  1044 function sanitize_page_id(page_id)
  1044 function sanitize_page_id(page_id)
  1045 {
  1045 {
  1046   // Remove character escapes
  1046 	// Remove character escapes
  1047   page_id = dirtify_page_id(page_id);
  1047 	page_id = dirtify_page_id(page_id);
  1048 
  1048 
  1049   var regex = new RegExp('[A-Za-z0-9\\[\\]\./:;\(\)@_-]', 'g');
  1049 	var regex = new RegExp('[A-Za-z0-9\\[\\]\./:;\(\)@_-]', 'g');
  1050   pid_clean = page_id.replace(regex, 'X');
  1050 	pid_clean = page_id.replace(regex, 'X');
  1051   var pid_dirty = [];
  1051 	var pid_dirty = [];
  1052   for ( var i = 0; i < pid_clean.length; i++ )
  1052 	for ( var i = 0; i < pid_clean.length; i++ )
  1053     pid_dirty[i] = pid_clean.substr(i, 1);
  1053 		pid_dirty[i] = pid_clean.substr(i, 1);
  1054 
  1054 
  1055   for ( var i = 0; i < pid_dirty.length; i++ )
  1055 	for ( var i = 0; i < pid_dirty.length; i++ )
  1056   {
  1056 	{
  1057     var chr = pid_dirty[i];
  1057 		var chr = pid_dirty[i];
  1058     if ( chr == 'X' )
  1058 		if ( chr == 'X' )
  1059       continue;
  1059 			continue;
  1060     var cid = chr.charCodeAt(0);
  1060 		var cid = chr.charCodeAt(0);
  1061     cid = cid.toString(16).toUpperCase();
  1061 		cid = cid.toString(16).toUpperCase();
  1062     if ( cid.length < 2 )
  1062 		if ( cid.length < 2 )
  1063     {
  1063 		{
  1064       cid = '0' + cid;
  1064 			cid = '0' + cid;
  1065     }
  1065 		}
  1066     pid_dirty[i] = "." + cid;
  1066 		pid_dirty[i] = "." + cid;
  1067   }
  1067 	}
  1068   
  1068 	
  1069   var pid_chars = [];
  1069 	var pid_chars = [];
  1070   for ( var i = 0; i < page_id.length; i++ )
  1070 	for ( var i = 0; i < page_id.length; i++ )
  1071     pid_chars[i] = page_id.substr(i, 1);
  1071 		pid_chars[i] = page_id.substr(i, 1);
  1072   
  1072 	
  1073   var page_id_cleaned = '';
  1073 	var page_id_cleaned = '';
  1074 
  1074 
  1075   for ( var id in pid_chars )
  1075 	for ( var id in pid_chars )
  1076   {
  1076 	{
  1077     var chr = pid_chars[id];
  1077 		var chr = pid_chars[id];
  1078     if ( pid_dirty[id] == 'X' )
  1078 		if ( pid_dirty[id] == 'X' )
  1079       page_id_cleaned += chr;
  1079 			page_id_cleaned += chr;
  1080     else
  1080 		else
  1081       page_id_cleaned += pid_dirty[id];
  1081 			page_id_cleaned += pid_dirty[id];
  1082   }
  1082 	}
  1083   
  1083 	
  1084   return page_id_cleaned;
  1084 	return page_id_cleaned;
  1085 }
  1085 }
  1086 
  1086 
  1087 /**
  1087 /**
  1088  * Removes character escapes in a page ID string
  1088  * Removes character escapes in a page ID string
  1089  * @param string Page ID string to dirty up
  1089  * @param string Page ID string to dirty up
  1090  * @return string
  1090  * @return string
  1091  */
  1091  */
  1092 
  1092 
  1093 function dirtify_page_id(page_id)
  1093 function dirtify_page_id(page_id)
  1094 {
  1094 {
  1095   // First, replace spaces with underscores
  1095 	// First, replace spaces with underscores
  1096   page_id = page_id.replace(/ /g, '_');
  1096 	page_id = page_id.replace(/ /g, '_');
  1097 
  1097 
  1098   var matches = page_id.match(/\.[A-Fa-f0-9][A-Fa-f0-9]/g);
  1098 	var matches = page_id.match(/\.[A-Fa-f0-9][A-Fa-f0-9]/g);
  1099   
  1099 	
  1100   if ( matches != null )
  1100 	if ( matches != null )
  1101   {
  1101 	{
  1102     for ( var i = 0; i < matches.length; i++ )
  1102 		for ( var i = 0; i < matches.length; i++ )
  1103     {
  1103 		{
  1104       var match = matches[i];
  1104 			var match = matches[i];
  1105       var byt = (match.substr(1)).toUpperCase();
  1105 			var byt = (match.substr(1)).toUpperCase();
  1106       var code = eval("0x" + byt);
  1106 			var code = eval("0x" + byt);
  1107       var regex = new RegExp('\\.' + byt, 'g');
  1107 			var regex = new RegExp('\\.' + byt, 'g');
  1108       page_id = page_id.replace(regex, String.fromCharCode(code));
  1108 			page_id = page_id.replace(regex, String.fromCharCode(code));
  1109     }
  1109 		}
  1110   }
  1110 	}
  1111   
  1111 	
  1112   return page_id;
  1112 	return page_id;
  1113 }
  1113 }
  1114 
  1114 
  1115 /*
  1115 /*
  1116     the getElementsByClassName function I pilfered from this guy.  It's
  1116 		the getElementsByClassName function I pilfered from this guy.  It's
  1117     a useful function that'll return any/all tags with a specific css class.
  1117 		a useful function that'll return any/all tags with a specific css class.
  1118 
  1118 
  1119     Written by Jonathan Snook, http://www.snook.ca/jonathan
  1119 		Written by Jonathan Snook, http://www.snook.ca/jonathan
  1120     Add-ons by Robert Nyman, http://www.robertnyman.com
  1120 		Add-ons by Robert Nyman, http://www.robertnyman.com
  1121     
  1121 		
  1122     Modified to match all elements that match the class name plus an integer after the name
  1122 		Modified to match all elements that match the class name plus an integer after the name
  1123     This is used in Enano to allow sliding sidebar widgets that use their own CSS
  1123 		This is used in Enano to allow sliding sidebar widgets that use their own CSS
  1124 */
  1124 */
  1125 function getElementsByClassName(oElm, strTagName, strClassName)
  1125 function getElementsByClassName(oElm, strTagName, strClassName)
  1126 {
  1126 {
  1127     // first it gets all of the specified tags
  1127 		// first it gets all of the specified tags
  1128     var arrElements = (strTagName == "*" && document.all) ? document.all : oElm.getElementsByTagName(strTagName);
  1128 		var arrElements = (strTagName == "*" && document.all) ? document.all : oElm.getElementsByTagName(strTagName);
  1129     
  1129 		
  1130     // then it sets up an array that'll hold the results
  1130 		// then it sets up an array that'll hold the results
  1131     var arrReturnElements = new Array();
  1131 		var arrReturnElements = new Array();
  1132 
  1132 
  1133     // some regex stuff you don't need to worry about
  1133 		// some regex stuff you don't need to worry about
  1134     strClassName = strClassName.replace(/\-/g, "\\-");
  1134 		strClassName = strClassName.replace(/\-/g, "\\-");
  1135 
  1135 
  1136     var oRegExp = new RegExp("(^|\\s)" + strClassName + "([0-9]*)(\\s|$)");
  1136 		var oRegExp = new RegExp("(^|\\s)" + strClassName + "([0-9]*)(\\s|$)");
  1137     var oElement;
  1137 		var oElement;
  1138     
  1138 		
  1139     // now it iterates through the elements it grabbed above
  1139 		// now it iterates through the elements it grabbed above
  1140     for(var i=0; i<arrElements.length; i++)
  1140 		for(var i=0; i<arrElements.length; i++)
  1141     {
  1141 		{
  1142         oElement = arrElements[i];
  1142 				oElement = arrElements[i];
  1143 
  1143 
  1144         // if the class matches what we're looking for it ads to the results array
  1144 				// if the class matches what we're looking for it ads to the results array
  1145         if(oElement.className.match(oRegExp))
  1145 				if(oElement.className.match(oRegExp))
  1146         {
  1146 				{
  1147             arrReturnElements.push(oElement);
  1147 						arrReturnElements.push(oElement);
  1148         }
  1148 				}
  1149     }
  1149 		}
  1150 
  1150 
  1151     // then it kicks the results back to us
  1151 		// then it kicks the results back to us
  1152     return (arrReturnElements)
  1152 		return (arrReturnElements)
  1153 }
  1153 }
  1154 
  1154 
  1155 /**
  1155 /**
  1156  * Equivalent to PHP's in_array function.
  1156  * Equivalent to PHP's in_array function.
  1157  */
  1157  */
  1158 
  1158 
  1159 function in_array(needle, haystack)
  1159 function in_array(needle, haystack)
  1160 {
  1160 {
  1161   for(var i in haystack)
  1161 	for(var i in haystack)
  1162   {
  1162 	{
  1163     if(haystack[i] == needle) return i;
  1163 		if(haystack[i] == needle) return i;
  1164   }
  1164 	}
  1165   return false;
  1165 	return false;
  1166 }
  1166 }
  1167 
  1167 
  1168 /**
  1168 /**
  1169  * Equivalent of PHP's time()
  1169  * Equivalent of PHP's time()
  1170  * @return int
  1170  * @return int
  1171  */
  1171  */
  1172 
  1172 
  1173 function unix_time()
  1173 function unix_time()
  1174 {
  1174 {
  1175   return parseInt((new Date()).getTime()/1000);
  1175 	return parseInt((new Date()).getTime()/1000);
  1176 }
  1176 }