PageSourceSearch

https://www.caborian.com/foro/Themes/default/scripts/script.js?fin20

js caborian.com collected 2026-10-01 14:54:56 UTC 48,069 bytes, 1,425 lines download raw bytes

1var smf_formSubmitted = false;
2var lastKeepAliveCheck = new Date().getTime();
3var smf_editorArray = new Array();
4
5// Some very basic browser detection - from Mozilla's sniffer page.
6var ua = navigator.userAgent.toLowerCase();
7
8var is_opera = ua.indexOf('opera') != -1;
9var is_opera5 = ua.indexOf('opera/5') != -1 || ua.indexOf('opera 5') != -1;
10var is_opera6 = ua.indexOf('opera/6') != -1 || ua.indexOf('opera 6') != -1;
11var is_opera7 = ua.indexOf('opera/7') != -1 || ua.indexOf('opera 7') != -1;
12var is_opera8 = ua.indexOf('opera/8') != -1 || ua.indexOf('opera 8') != -1;
13var is_opera9 = ua.indexOf('opera/9') != -1 || ua.indexOf('opera 9') != -1;
14var is_opera95 = ua.indexOf('opera/9.5') != -1 || ua.indexOf('opera 9.5') != -1;
15var is_opera96 = ua.indexOf('opera/9.6') != -1 || ua.indexOf('opera 9.6') != -1;
16var is_opera10 = (ua.indexOf('opera/9.8') != -1 || ua.indexOf('opera 9.8') != -1 || ua.indexOf('opera/10.') != -1 || ua.indexOf('opera 10.') != -1) || ua.indexOf('version/10.') != -1;
17var is_opera95up = is_opera95 || is_opera96 || is_opera10;
18
19var is_ff = (ua.indexOf('firefox') != -1 || ua.indexOf('iceweasel') != -1 || ua.indexOf('icecat') != -1 || ua.indexOf('shiretoko') != -1 || ua.indexOf('minefield') != -1 || ua.indexOf('PaleMoon') != -1) && !is_opera;
20var is_gecko = ua.indexOf('gecko') != -1 && !is_opera;
21
22var is_chrome = ua.indexOf('chrome') != -1;
23var is_safari = ua.indexOf('applewebkit') != -1 && !is_chrome;
24var is_webkit = ua.indexOf('applewebkit') != -1;
25
26var is_ie = ua.indexOf('msie') != -1 && !is_opera;
27var is_ie4 = is_ie && ua.indexOf('msie 4') != -1;
28var is_ie5 = is_ie && ua.indexOf('msie 5') != -1;
29var is_ie50 = is_ie && ua.indexOf('msie 5.0') != -1;
30var is_ie55 = is_ie && ua.indexOf('msie 5.5') != -1;
31var is_ie5up = is_ie && !is_ie4;
32var is_ie6 = is_ie && ua.indexOf('msie 6') != -1;
33var is_ie6up = is_ie5up && !is_ie55 && !is_ie5;
34var is_ie6down = is_ie6 || is_ie5 || is_ie4;
35var is_ie7 = is_ie && ua.indexOf('msie 7') != -1;
36var is_ie7up = is_ie6up && !is_ie6;
37var is_ie7down = is_ie7 || is_ie6 || is_ie5 || is_ie4;
38
39var is_ie8 = is_ie && ua.indexOf('msie 8') != -1;
40var is_ie8up = is_ie8 && !is_ie7down;
41
42var is_iphone = ua.indexOf('iphone') != -1 || ua.indexOf('ipod') != -1;
43var is_android = ua.indexOf('android') != -1;
44
45var ajax_indicator_ele = null;
46
47// Define document.getElementById for Internet Explorer 4.
48if (!('getElementById' in document) && 'all' in document)
49	document.getElementById = function (sId) {
50		return document.all[sId];
51	}
52
53// Define XMLHttpRequest for IE 5 and above. (don't bother for IE 4 :/.... works in Opera 7.6 and Safari 1.2!)
54else if (!('XMLHttpRequest' in window) && 'ActiveXObject' in window)
55	window.XMLHttpRequest = function () {
56		return new ActiveXObject(is_ie5 ? 'Microsoft.XMLHTTP' : 'MSXML2.XMLHTTP');
57	};
58
59// Ensure the getElementsByTagName exists.
60if (!'getElementsByTagName' in document && 'all' in document)
61	document.getElementsByTagName = function (sName) {
62		return document.all.tags[sName];
63	}
64
65// Some older versions of Mozilla don't have this, for some reason.
66if (!('forms' in document))
67	document.forms = document.getElementsByTagName('form');
68
69// Load an XML document using XMLHttpRequest.
70function getXMLDocument(sUrl, funcCallback)
71{
72	if (!window.XMLHttpRequest)
73		return null;
74
75	var oMyDoc = new XMLHttpRequest();
76	var bAsync = typeof(funcCallback) != 'undefined';
77	var oCaller = this;
78	if (bAsync)
79	{
80		oMyDoc.onreadystatechange = function () {
81			if (oMyDoc.readyState != 4)
82				return;
83
84			if (oMyDoc.responseXML != null && oMyDoc.status == 200)
85			{
86				if (funcCallback.call)
87				{
88					funcCallback.call(oCaller, oMyDoc.responseXML);
89				}
90				// A primitive substitute for the call method to support IE 5.0.
91				else
92				{
93					oCaller.tmpMethod = funcCallback;
94					oCaller.tmpMethod(oMyDoc.responseXML);
95					delete oCaller.tmpMethod;
96				}
97			}
98		};
99	}
100	oMyDoc.open('GET', sUrl, bAsync);
101	oMyDoc.send(null);
102
103	return oMyDoc;
104}
105
106// Send a post form to the server using XMLHttpRequest.
107function sendXMLDocument(sUrl, sContent, funcCallback)
108{
109	if (!window.XMLHttpRequest)
110		return false;
111
112	var oSendDoc = new window.XMLHttpRequest();
113	var oCaller = this;
114	if (typeof(funcCallback) != 'undefined')
115	{
116		oSendDoc.onreadystatechange = function () {
117			if (oSendDoc.readyState != 4)
118				return;
119
120			if (oSendDoc.responseXML != null && oSendDoc.status == 200)
121				funcCallback.call(oCaller, oSendDoc.responseXML);
122			else
123				funcCallback.call(oCaller, false);
124		};
125	}
126	oSendDoc.open('POST', sUrl, true);
127	if ('setRequestHeader' in oSendDoc)
128		oSendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
129	oSendDoc.send(sContent);
130
131	return true;
132}
133
134// A property we'll be needing for php_to8bit.
135String.prototype.oCharsetConversion = {
136	from: '',
137	to: ''
138};
139
140// Convert a string to an 8 bit representation (like in PHP).
141String.prototype.php_to8bit = function ()
142{
143	if (smf_charset == 'UTF-8')
144	{
145		var n, sReturn = '';
146
147		// Recode from UTF16 (native .js) to UTF8
148		for (var i = 0, iTextLen = this.length; i < iTextLen; i++)
149		{
150			// Below xFFFF, UTF16 simply = the code points
151			n = this.charCodeAt(i);
152			if (n < 128)
153				sReturn += String.fromCharCode(n);
154			else if (n < 2048)
155				sReturn += String.fromCharCode(192 | n >> 6) + String.fromCharCode(128 | n & 63);
156			// 0xD800 - 0xDBFF
157			else if (n >= 55296 && n <= 56319)
158			{
159				// In this range, this is the beginning of a surrogate pair, where 4-byte utf8 chars are
160				n = 65536 + ((n & 1023) << 10) + (this.charCodeAt(i + 1) & 1023);
161				sReturn += String.fromCharCode(240 | n >> 18) + String.fromCharCode(128 | n >> 12 & 63) + String.fromCharCode(128 | n >> 6 & 63) + String.fromCharCode(128 | n & 63);
162				// Skip next char, already used...
163				i++;
164			}
165			else
166				sReturn += String.fromCharCode(224 | n >> 12) + String.fromCharCode(128 | n >> 6 & 63) + String.fromCharCode(128 | n & 63);
167		}
168
169		return sReturn;
170	}
171
172	else if (this.oCharsetConversion.from.length == 0)
173	{
174		switch (smf_charset)
175		{
176			case 'ISO-8859-1':
177				this.oCharsetConversion = {
178					from: '\xa0-\xff',
179					to: '\xa0-\xff'
180				};
181			break;
182
183			case 'ISO-8859-2':
184				this.oCharsetConversion = {
185					from: '\xa0\u0104\u02d8\u0141\xa4\u013d\u015a\xa7\xa8\u0160\u015e\u0164\u0179\xad\u017d\u017b\xb0\u0105\u02db\u0142\xb4\u013e\u015b\u02c7\xb8\u0161\u015f\u0165\u017a\u02dd\u017e\u017c\u0154\xc1\xc2\u0102\xc4\u0139\u0106\xc7\u010c\xc9\u0118\xcb\u011a\xcd\xce\u010e\u0110\u0143\u0147\xd3\xd4\u0150\xd6\xd7\u0158\u016e\xda\u0170\xdc\xdd\u0162\xdf\u0155\xe1\xe2\u0103\xe4\u013a\u0107\xe7\u010d\xe9\u0119\xeb\u011b\xed\xee\u010f\u0111\u0144\u0148\xf3\xf4\u0151\xf6\xf7\u0159\u016f\xfa\u0171\xfc\xfd\u0163\u02d9',
186					to: '\xa0-\xff'
187				};
188			break;
189
190			case 'ISO-8859-5':
191				this.oCharsetConversion = {
192					from: '\xa0\u0401-\u040c\xad\u040e-\u044f\u2116\u0451-\u045c\xa7\u045e\u045f',
193					to: '\xa0-\xff'
194				};
195			break;
196
197			case 'ISO-8859-9':
198				this.oCharsetConversion = {
199					from: '\xa0-\xcf\u011e\xd1-\xdc\u0130\u015e\xdf-\xef\u011f\xf1-\xfc\u0131\u015f\xff',
200					to: '\xa0-\xff'
201				};
202			break;
203
204			case 'ISO-8859-15':
205				this.oCharsetConversion = {
206					from: '\xa0-\xa3\u20ac\xa5\u0160\xa7\u0161\xa9-\xb3\u017d\xb5-\xb7\u017e\xb9-\xbb\u0152\u0153\u0178\xbf-\xff',
207					to: '\xa0-\xff'
208				};
209			break;
210
211			case 'tis-620':
212				this.oCharsetConversion = {
213					from: '\u20ac\u2026\u2018\u2019\u201c\u201d\u2022\u2013\u2014\xa0\u0e01-\u0e3a\u0e3f-\u0e5b',
214					to: '\x80\x85\x91-\x97\xa0-\xda\xdf-\xfb'
215				};
216			break;
217
218			case 'windows-1251':
219				this.oCharsetConversion = {
220					from: '\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab-\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5-\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410-\u044f',
221					to: '\x80-\x97\x99-\xff'
222				};
223			break;
224
225			case 'windows-1253':
226				this.oCharsetConversion = {
227					from: '\u20ac\u201a\u0192\u201e\u2026\u2020\u2021\u2030\u2039\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u2122\u203a\xa0\u0385\u0386\xa3-\xa9\xab-\xae\u2015\xb0-\xb3\u0384\xb5-\xb7\u0388-\u038a\xbb\u038c\xbd\u038e-\u03a1\u03a3-\u03ce',
228					to: '\x80\x82-\x87\x89\x8b\x91-\x97\x99\x9b\xa0-\xa9\xab-\xd1\xd3-\xfe'
229				};
230			break;
231
232			case 'windows-1255':
233				this.oCharsetConversion = {
234					from: '\u20ac\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u2039\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u203a\xa0-\xa3\u20aa\xa5-\xa9\xd7\xab-\xb9\xf7\xbb-\xbf\u05b0-\u05b9\u05bb-\u05c3\u05f0-\u05f4\u05d0-\u05ea\u200e\u200f',
235					to: '\x80\x82-\x89\x8b\x91-\x99\x9b\xa0-\xc9\xcb-\xd8\xe0-\xfa\xfd\xfe'
236				};
237			break;
238
239			case 'windows-1256':
240				this.oCharsetConversion = {
241					from: '\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\xa0\u060c\xa2-\xa9\u06be\xab-\xb9\u061b\xbb-\xbe\u061f\u06c1\u0621-\u0636\xd7\u0637-\u063a\u0640-\u0643\xe0\u0644\xe2\u0645-\u0648\xe7-\xeb\u0649\u064a\xee\xef\u064b-\u064e\xf4\u064f\u0650\xf7\u0651\xf9\u
2410652\xfb\xfc\u200e\u200f\u06d2',
242					to: '\x80-\xff'
243				};
244			break;
245
246			default:
247				this.oCharsetConversion = {
248					from: '',
249					to: ''
250				};
251			break;
252		}
253		var funcExpandString = function (sSearch) {
254			var sInsert = '';
255			for (var i = sSearch.charCodeAt(0), n = sSearch.charCodeAt(2); i <= n; i++)
256				sInsert += String.fromCharCode(i);
257			return sInsert;
258		};
259		this.oCharsetConversion.from = this.oCharsetConversion.from.replace(/.\-./g, funcExpandString);
260		this.oCharsetConversion.to = this.oCharsetConversion.to.replace(/.\-./g, funcExpandString);
261	}
262
263	var sReturn = '', iOffsetFrom = 0;
264	for (var i = 0, n = this.length; i < n; i++)
265	{
266		iOffsetFrom = this.oCharsetConversion.from.indexOf(this.charAt(i));
267		sReturn += iOffsetFrom > -1 ? this.oCharsetConversion.to.charAt(iOffsetFrom) : (this.charCodeAt(i) > 127 ? '&#' + this.charCodeAt(i) + ';' : this.charAt(i));
268	}
269
270	return sReturn
271}
272
273// Character-level replacement function.
274String.prototype.php_strtr = function (sFrom, sTo)
275{
276	return this.replace(new RegExp('[' + sFrom + ']', 'g'), function (sMatch) {
277		return sTo.charAt(sFrom.indexOf(sMatch));
278	});
279}
280
281// Simulate PHP's strtolower (in SOME cases PHP uses ISO-8859-1 case folding).
282String.prototype.php_strtolower = function ()
283{
284	return typeof(smf_iso_case_folding) == 'boolean' && smf_iso_case_folding == true ? this.php_strtr(
285		'ABCDEFGHIJKLMNOPQRSTUVWXYZ\x8a\x8c\x8e\x9f\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde',
286		'abcdefghijklmnopqrstuvwxyz\x9a\x9c\x9e\xff\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe'
287	) : this.php_strtr('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
288}
289
290String.prototype.php_urlencode = function()
291{
292	return escape(this).replace(/\+/g, '%2b').replace('*', '%2a').replace('/', '%2f').replace('@', '%40');
293}
294
295String.prototype.php_htmlspecialchars = function()
296{
297	return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
298}
299
300String.prototype.php_unhtmlspecialchars = function()
301{
302	return this.replace(/&quot;/g, '"').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&amp;/g, '&');
303}
304
305String.prototype.php_addslashes = function()
306{
307	return this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
308}
309
310String.prototype._replaceEntities = function(sInput, sDummy, sNum)
311{
312	return String.fromCharCode(parseInt(sNum));
313}
314
315String.prototype.removeEntities = function()
316{
317	return this.replace(/&(amp;)?#(\d+);/g, this._replaceEntities);
318}
319
320String.prototype.easyReplace = function (oReplacements)
321{
322	var sResult = this;
323	for (var sSearch in oReplacements)
324		sResult = sResult.replace(new RegExp('%' + sSearch + '%', 'g'), oReplacements[sSearch]);
325
326	return sResult;
327}
328
329
330// Open a new window.
331function reqWin(desktopURL, alternateWidth, alternateHeight, noScrollbars)
332{
333	if ((alternateWidth && self.screen.availWidth * 0.8 < alternateWidth) || (alternateHeight && self.screen.availHeight * 0.8 < alternateHeight))
334	{
335		noScrollbars = false;
336		alternateWidth = Math.min(alternateWidth, self.screen.availWidth * 0.8);
337		alternateHeight = Math.min(alternateHeight, self.screen.availHeight * 0.8);
338	}
339	else
340		noScrollbars = typeof(noScrollbars) == 'boolean' && noScrollbars == true;
341
342	window.open(desktopURL, 'requested_popup', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=' + (noScrollbars ? 'no' : 'yes') + ',width=' + (alternateWidth ? alternateWidth : 480) + ',height=' + (alternateHeight ? alternateHeight : 220) + ',resizable=no');
343
344	// Return false so the click won't follow the link ;).
345	return false;
346}
347
348// Remember the current position.
349function storeCaret(oTextHandle)
350{
351	// Only bother if it will be useful.
352	if ('createTextRange' in oTextHandle)
353		oTextHandle.caretPos = document.selection.createRange().duplicate();
354}
355
356// Replaces the currently selected text with the passed text.
357function replaceText(text, oTextHandle)
358{
359	// Attempt to create a text range (IE).
360	if ('caretPos' in oTextHandle && 'createTextRange' in oTextHandle)
361	{
362		var caretPos = oTextHandle.caretPos;
363
364		caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
365		caretPos.select();
366	}
367	// Mozilla text range replace.
368	else if ('selectionStart' in oTextHandle)
369	{
370		var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart);
371		var end = oTextHandle.value.substr(oTextHandle.selectionEnd);
372		var scrollPos = oTextHandle.scrollTop;
373
374		oTextHandle.value = begin + text + end;
375
376		if (oTextHandle.setSelectionRange)
377		{
378			oTextHandle.focus();
379			var goForward = is_opera ? text.match(/\n/g).length : 0;
380			oTextHandle.setSelectionRange(begin.length + text.length + goF
380orward, begin.length + text.length + goForward);
381		}
382		oTextHandle.scrollTop = scrollPos;
383	}
384	// Just put it on the end.
385	else
386	{
387		oTextHandle.value += text;
388		oTextHandle.focus(oTextHandle.value.length - 1);
389	}
390}
391
392// Surrounds the selected text with text1 and text2.
393function surroundText(text1, text2, oTextHandle)
394{
395	// Can a text range be created?
396	if ('caretPos' in oTextHandle && 'createTextRange' in oTextHandle)
397	{
398		var caretPos = oTextHandle.caretPos, temp_length = caretPos.text.length;
399
400		caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text1 + caretPos.text + text2 + ' ' : text1 + caretPos.text + text2;
401
402		if (temp_length == 0)
403		{
404			caretPos.moveStart('character', -text2.length);
405			caretPos.moveEnd('character', -text2.length);
406			caretPos.select();
407		}
408		else
409			oTextHandle.focus(caretPos);
410	}
411	// Mozilla text range wrap.
412	else if ('selectionStart' in oTextHandle)
413	{
414		var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart);
415		var selection = oTextHandle.value.substr(oTextHandle.selectionStart, oTextHandle.selectionEnd - oTextHandle.selectionStart);
416		var end = oTextHandle.value.substr(oTextHandle.selectionEnd);
417		var newCursorPos = oTextHandle.selectionStart;
418		var scrollPos = oTextHandle.scrollTop;
419
420		oTextHandle.value = begin + text1 + selection + text2 + end;
421
422		if (oTextHandle.setSelectionRange)
423		{
424			var goForward = is_opera ? text1.match(/\n/g).length : 0, goForwardAll = is_opera ? (text1 + text2).match(/\n/g).length : 0;
425			if (selection.length == 0)
426				oTextHandle.setSelectionRange(newCursorPos + text1.length + goForward, newCursorPos + text1.length + goForward);
427			else
428				oTextHandle.setSelectionRange(newCursorPos, newCursorPos + text1.length + selection.length + text2.length + goForwardAll);
429			oTextHandle.focus();
430		}
431		oTextHandle.scrollTop = scrollPos;
432	}
433	// Just put them on the end, then.
434	else
435	{
436		oTextHandle.value += text1 + text2;
437		oTextHandle.focus(oTextHandle.value.length - 1);
438	}
439}
440
441// Checks if the passed input's value is nothing.
442function isEmptyText(theField)
443{
444	// Copy the value so changes can be made..
445	var theValue = theField.value;
446
447	// Strip whitespace off the left side.
448	while (theValue.length > 0 && (theValue.charAt(0) == ' ' || theValue.charAt(0) == '\t'))
449		theValue = theValue.substring(1, theValue.length);
450	// Strip whitespace off the right side.
451	while (theValue.length > 0 && (theValue.charAt(theValue.length - 1) == ' ' || theValue.charAt(theValue.length - 1) == '\t'))
452		theValue = theValue.substring(0, theValue.length - 1);
453
454	if (theValue == '')
455		return true;
456	else
457		return false;
458}
459
460// Only allow form submission ONCE.
461function submitonce(theform)
462{
463	smf_formSubmitted = true;
464
465	// If there are any editors warn them submit is coming!
466	for (var i = 0; i < smf_editorArray.length; i++)
467		smf_editorArray[i].doSubmit();
468}
469function submitThisOnce(oControl)
470{
471	// Hateful, hateful fix for Safari 1.3 beta.
472	if (is_safari)
473		return !smf_formSubmitted;
474
475	// oControl might also be a form.
476	var oForm = 'form' in oControl ? oControl.form : oControl;
477
478	var aTextareas = oForm.getElementsByTagName('textarea');
479	for (var i = 0, n = aTextareas.length; i < n; i++)
480		aTextareas[i].readOnly = true;
481
482	return !smf_formSubmitted;
483}
484
485// Deprecated, as innerHTML is supported everywhere.
486function setInnerHTML(oElement, sToValue)
487{
488	oElement.innerHTML = sToValue;
489}
490
491function getInnerHTML(oElement)
492{
493	return oElement.innerHTML;
494}
495
496// Set the "outer" HTML of an element.
497function setOuterHTML(oElement, sToValue)
498{
499	if ('outerHTML' in oElement)
500		oElement.outerHTML = sToValue;
501	else
502	{
503		var range = document.createRange();
504		range.setStartBefore(oElement);
505		oElement.parentNode.replaceChild(range.createContextualFragment(sToValue), oElement);
506	}
507}
508
509// Checks for variable in theArray.
510function in_array(variable, theArray)
511{
512	for (var i in theArray)
513		if (theArray[i] == variable)
514			return true;
515
516	return false;
517}
518
519// Checks for variable in theArray.
520function array_search(variable, theArray)
521{
522	for (var i in theArray)
523		if (theArray[i] == variable)
524			return i;
525
526	return null;
527}
528
529// Find a specific radio button in its group and select it.
530function selectRadioByName(oRadioGroup, sName)
531{
532	if (!('length' in oRadioGroup))
533		return oRadioGroup.checked = true;
534
535	for (var i = 0, n = oRadioGroup.length; i < n; i++)
536		if (oRadioGroup[i].value == sName)
537			return oRadioGroup[i].checked = true;
538
539	return false;
540}
541
542// Invert all checkboxes at once by clicking a single checkbox.
543function invertAll(oInvertCheckbox, oForm, sMask, bIgnoreDisabled)
544{
545	for (var i = 0; i < oForm.length; i++)
546	{
547		if (!('name' in oForm[i]) || (typeof(sMask) == 'string' && oForm[i].name.substr(0, sMask.length) != sMask && oForm[i].id.substr(0, sMask.length) != sMask))
548			continue;
549
550		if (!oForm[i].disabled || (typeof(bIgnoreDisabled) == 'boolean' && bIgnoreDisabled))
551			oForm[i].checked = oInvertCheckbox.checked;
552	}
553}
554
555// Keep the session alive - always!
556var lastKeepAliveCheck = new Date().getTime();
557function smf_sessionKeepAlive()
558{
559	var curTime = new Date().getTime();
560
561	// Prevent a Firefox bug from hammering the server.
562	if (smf_scripturl && curTime - lastKeepAliveCheck > 900000)
563	{
564		var tempImage = new Image();
565		tempImage.src = smf_prepareScriptUrl(smf_scripturl) + 'action=keepalive;time=' + curTime;
566		lastKeepAliveCheck = curTime;
567	}
568
569	window.setTimeout('smf_sessionKeepAlive();', 1200000);
570}
571window.setTimeout('smf_sessionKeepAlive();', 1200000);
572
573// Set a theme option through javascript.
574function smf_setThemeOption(option, value, theme, cur_session_id, cur_session_var, additional_vars)
575{
576	// Compatibility.
577	if (cur_session_id == null)
578		cur_session_id = smf_session_id;
579	if (typeof(cur_session_var) == 'undefined')
580		cur_session_var = 'sesc';
581
582	if (additional_vars == null)
583		additional_vars = '';
584
585	var tempImage = new Image();
586	tempImage.src = smf_prepareScriptUrl(smf_scripturl) + 'action=jsoption;var=' + option + ';val=' + value + ';' + cur_session_var + '=' + cur_session_id + additional_vars + (theme == null ? '' : '&th=' + theme) + ';time=' + (new Date().getTime());
587}
588
589function smf_avatarResize()
590{
591	var possibleAvatars = document.getElementsByTagName('img');
592
593	for (var i = 0; i < possibleAvatars.length; i++)
594	{
595		var tempAvatars = []; j = 0;
596		if (possibleAvatars[i].className != 'avatar')
597			continue;
598
599		// Image.prototype.avatar = possibleAvatars[i];
600		tempAvatars[j] = new Image();
601		tempAvatars[j].avatar = possibleAvatars[i];
602		
603		tempAvatars[j].onload = function()
604		{
605			this.avatar.width = this.width;
606			this.avatar.height = this.height;
607			if (smf_avatarMaxWidth != 0 && this.width > smf_avatarMaxWidth)
608			{
609				this.avatar.height = (smf_avatarMaxWidth * this.height) / this.width;
610				this.avatar.width = smf_avatarMaxWidth;
611			}
612			if (smf_avatarMaxHeight != 0 && this.avatar.height > smf_avatarMaxHeight)
613			{
614				this.avatar.width = (smf_avatarMaxHeight * this.avatar.width) / this.avatar.height;
615				this.avatar.height = smf_avatarMaxHeight;
616			}
617		}
618		tempAvatars[j].src = possibleAvatars[i].src;
619		j++;
620	}
621
622	if (typeof(window_oldAvatarOnload) != 'undefined' && window_oldAvatarOnload)
623	{
624		window_oldAvatarOnload();
625		window_oldAvatarOnload = null;
626	}
627}
628
629
630function hashLoginPassword(doForm, cur_session_id)
631{
632	// Compatibility.
633	if (cur_session_id == null)
634		cur_session_id = smf_session_id;
635
636	if (typeof(hex_sha1) == 'undefined')
637		return;
638	// Are they using an email address?
639	if (doForm.user.value.indexOf('@') != -1)
640		return;
641
642	// Unless the browser is Opera, the password will not save properly.
643	if (!('opera' in window))
644		doForm.passwrd.autocomplete = 'off';
645
646	doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_to8bit().php_strtolower() + doForm.passwrd.value.php_to8bit()) + cur_session_id);
647
648	// It looks nicer to fill it with asterisks, but Firefox will try to save that.
649	if (is_ff != -1)
650		doForm.passwrd.value = '';
651	else
652		doForm.passwrd.value = doForm.passwrd.value.replace(/./g, '*');
653}
654
655function hashAdminPassword(doForm, username, cur_session_id)
656{
657	// Compatibility.
658	if (cur_session_id == null)
659		cur_session_id = smf_session_id;
660
661	if (typeof(hex_sha1) == 'undefined')
662		return;
663
664	doForm.admin_hash_pass.value = hex_sha1(hex_sha1(username.php_to8bit().php_strtolower() + doForm.admin_pass.value.php_to8bit()) + cur_session_id);
665	doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, '*');
666}
667
668// Shows the page numbers by clicking the dots (in compact view).
669function expandPages(spanNode, baseURL, firstPage, lastPage, perPage)
670{
671	var replacement = '', i, oldLastPage = 0;
672	var perPageLimit = 50;
673
674	// The dots were bold, the page numbers are not (in most cases).
675	spanNode.style.fontWeight = 'normal';
676	spanNode.onclick = '';
677
678	// Prevent too many pages to be loaded at once.
679	if ((lastPage - firstPage) / perPage > perPageLimit)
680	{
681		oldLastPage = lastPage;
682		lastPage = firstPage + perPageLimit * perPage;
683	}
684
685	// Calculate the new pages.
686	for (i = firstPage; i < lastPage; i += perPage)
687		replacement += '<a class="navPages" href="' + baseURL.replace(/%1\$d/, i).replace(/%%/g, '%') + '">' + (1 + i / perPage) + '</a> ';
688
689	if (oldLastPage > 0)
690		replacement += '<span style="font-weight: bold; cursor: ' + (is_ie && !is_ie6up ? 'hand' : 'pointer') + ';" onclick="expandPages(this, \'' + baseURL + '\', ' + lastPage + ', ' + oldLastPage + ', ' + perPage + ');"> ... </span> ';
691
692	// Replace the dots by the new page links.
693	setInnerHTML(spanNode, replacement);
694}
695
696function smc_preCacheImage(sSrc)
697{
698	if (!('smc_aCachedImages' in window))
699		window.smc_aCachedImages = [];
700
701	if (!in_array(sSrc, window.smc_aCachedImages))
702	{
703		var oImage = new Image();
704		oImage.src = sSrc;
705	}
706}
707
708
709// *** smc_Cookie class.
710function smc_Cookie(oOptions)
711{
712	this.opt = oOptions;
713	this.oCookies = {};
714	this.init();
715}
716
717smc_Cookie.prototype.init = function()
718{
719	if ('cookie' in document && document.cookie != '')
720	{
721		var aCookieList = document.cookie.split(';');
722		for (var i = 0, n = aCookieList.length; i < n; i++)
723		{
724			var aNameValuePair = aCookieList[i].split('=');
725			this.oCookies[aNameValuePair[0].replace(/^\s+|\s+$/g, '')] = decodeURIComponent(aNameValuePair[1]);
726		}
727	}
728}
729
730smc_Cookie.prototype.get = function(sKey)
731{
732	return sKey in this.oCookies ? this.oCookies[sKey] : null;
733}
734
735smc_Cookie.prototype.set = function(sKey, sValue)
736{
737	document.cookie = sKey + '=' + encodeURIComponent(sValue);
738}
739
740
741// *** smc_Toggle class.
742function smc_Toggle(oOptions)
743{
744	this.opt = oOptions;
745	this.bCollapsed = false;
746	this.oCookie = null;
747	this.init();
748}
749
750smc_Toggle.prototype.init = function ()
751{
752	// The master switch can disable this toggle fully.
753	if ('bToggleEnabled' in this.opt && !this.opt.bToggleEnabled)
754		return;
755
756	// If cookies are enabled and they were set, override the initial state.
757	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
758	{
759		// Initialize the cookie handler.
760		this.oCookie = new smc_Cookie({});
761
762		// Check if the cookie is set.
763		var cookieValue = this.oCookie.get(this.opt.oCookieOptions.sCookieName)
764		if (cookieValue != null)
765			this.opt.bCurrentlyCollapsed = cookieValue == '1';
766	}
767
768	// If the init state is set to be collapsed, collapse it.
769	if (this.opt.bCurrentlyCollapsed)
770		this.changeState(true, true);
771
772	// Initialize the images to be clickable.
773	if ('aSwapImages' in this.opt)
774	{
775		for (var i = 0, n = this.opt.aSwapImages.length; i < n; i++)
776		{
777			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
778			if (typeof(oImage) == 'object' && oImage != null)
779			{
780				// Display the image in case it was hidden.
781				if (oImage.style.display == 'none')
782					oImage.style.display = '';
783
784				oImage.instanceRef = this;
785				oImage.onclick = function () {
786					this.instanceRef.toggle();
787					this.blur();
788				}
789				oImage.style.cursor = 'pointer';
790
791				// Preload the collapsed image.
792				smc_preCacheImage(this.opt.aSwapImages[i].srcCollapsed);
793			}
794		}
795	}
796
797	// Initialize links.
798	if ('aSwapLinks' in this.opt)
799	{
800		for (var i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
801		{
802			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
803			if (typeof(oLink) == 'object' && oLink != null)
804			{
805				// Display the link in case it was hidden.
806				if (oLink.style.display == 'none')
807					oLink.style.display = '';
808
809				oLink.instanceRef = this;
810				oLink.onclick = function () {
811					this.instanceRef.toggle();
812					this.blur();
813					return false;
814				}
815			}
816		}
817	}
818}
819
820// Collapse or expand the section.
821smc_Toggle.prototype.changeState = function(bCollapse, bInit)
822{
823	// Default bInit to false.
824	bInit = typeof(bInit) == 'undefined' ? false : true;
825
826	// Handle custom function hook before collapse.
827	if (!bInit && bCollapse && 'funcOnBeforeCollapse' in this.opt)
828	{
829		this.tmpMethod = this.opt.funcOnBeforeCollapse;
830		this.tmpMethod();
831		delete this.tmpMethod;
832	}
833
834	// Handle custom function hook before expand.
835	else if (!bInit && !bCollapse && 'funcOnBeforeExpand' in this.opt)
836	{
837		this.tmpMethod = this.opt.funcOnBeforeExpand;
838		this.tmpMethod();
839		delete this.tmpMethod;
840	}
841
842	// Loop through all the images that need to be toggled.
843	if ('aSwapImages' in this.opt)
844	{
845		for (var i = 0, n = this.opt.aSwapImages.length; i < n; i++)
846		{
847			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
848			if (typeof(oImage) == 'object' && oImage != null)
849			{
850				// Only (re)load the image if it's changed.
851				var sTargetSource = bCollapse ? this.opt.aSwapImages[i].srcCollapsed : this.opt.aSwapImages[i].srcExpanded;
852				if (oImage.src != sTargetSource)
853					oImage.src = sTargetSource;
854
855				oImage.alt = oImage.title = bCollapse ? this.opt.aSwapImages[i].altCollapsed : this.opt.aSwapImages[i].altExpanded;
856			}
857		}
858	}
859
860	// Loop through all the links that need to be toggled.
861	if ('aSwapLinks' in this.opt)
862	{
863		for (var i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
864		{
865			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
866			if (typeof(oLink) == 'object' && oLink != null)
867				setInnerHTML(oLink, bCollapse ? this.opt.aSwapLinks[i].msgCollapsed : this.opt.aSwapLinks[i].msgExpanded);
868		}
869	}
870
871	// Now go through all the sections to be collapsed.
872	for (var i = 0, n = this.opt.aSwappableContainers.length; i < n; i++)
873	{
874		if (this.opt.aSwappableContainers[i] == null)
875			continue;
876
877		var oContainer = document.getElementById(this.opt.aSwappableContainers[i]);
878		if (typeof(oContainer) == 'object' && oContainer != null)
879			oContainer.style.display = bCollapse ? 'none' : '';
880	}
881
882	// Update the new state.
883	this.bCollapsed = bCollapse;
884
885	// Update the cookie, if desired.
886	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
887		this.oCookie.set(this.opt.oCookieOptions.sCookieName, this.bCollapsed ? '1' : '0');
888
889	if (!bInit && 'oThemeOptions' in this.opt && this.opt.oThemeOptions.bUseThemeSettings)
890		smf_setThemeOption(this.opt.oThemeOptions.sOptionName, this.bCollapsed ? '1' : '0', 'sThemeId' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sThemeId : null, this.opt.oThemeOptions.sSessionId, this.opt.oThemeOptions.sSessionVar, 'sAdditionalVars' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sAdditionalVars : null);
891}
892
893smc_Toggle.prototype.toggle = function()
894{
895	// Change the state by reversing the current state.
896	this.changeState(!this.bCollapsed);
897}
898
899
900function ajax_indicator(turn_on)
901{
902	if (ajax_indicator_ele == null)
903	{
904		ajax_indicator_ele = document.getElementById('ajax_in_progress');
905
906		if (ajax_indicator_ele == null && typeof(ajax_notification_text) != null)
907		{
908			create_ajax_indicator_ele();
909		}
910	}
911
912	if (ajax_indicator_ele != null)
913	{
914		if (navigator.appName == 'Microsoft Internet Explorer' && !is_ie7up)
915		{
916			ajax_indicator_ele.style.position = 'absolute';
917			ajax_indicator_ele.style.top = document.documentElement.scrollTop;
918		}
919
920		ajax_indicator_ele.style.display = turn_on ? 'block' : 'none';
921	}
922}
923
924function create_ajax_indicator_ele()
925{
926	// Create the div for the indicator.
927	ajax_indicator_ele = document.createElement('div');
928
929	// Set the id so it'll load the style properly.
930	ajax_indicator_ele.id = 'ajax_in_progress';
931
932	// Add the image in and link to turn it off.
933	var cancel_link = document.createElement('a');
934	cancel_link.href = 'javascript:ajax_indicator(false)';
935	var cancel_img = document.createElement('img');
936	cancel_img.src = smf_images_url + '/icons/quick_remove.gif';
937
938	if (typeof(ajax_notification_cancel_text) != 'undefined')
939	{
940		cancel_img.alt = ajax_notification_cancel_text;
941		cancel_img.title = ajax_notification_cancel_text;
942	}
943
944	// Add the cancel link and image to the indicator.
945	cancel_link.appendChild(cancel_img);
946	ajax_indicator_ele.appendChild(cancel_link);
947
948	// Set the text.  (Note:  You MUST append here and not overwrite.)
949	ajax_indicator_ele.innerHTML += ajax_notification_text;
950
951	// Finally attach the element to the body.
952	document.body.appendChild(ajax_indicator_ele);
953}
954
955function createEventListener(oTarget)
956{
957	if (!('addEventListener' in oTarget))
958	{
959		if (oTarget.attachEvent)
960		{
961			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
962				oTarget.attachEvent('on' + sEvent, funcHandler);
963			}
964			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
965				oTarget.detachEvent('on' + sEvent, funcHandler);
966			}
967		}
968		else
969		{
970			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
971				oTarget['on' + sEvent] = funcHandler;
972			}
973			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
974				oTarget['on' + sEvent] = null;
975			}
976		}
977	}
978}
979
980// This function will retrieve the contents needed for the jump to boxes.
981function grabJumpToContent()
982{
983	var oXMLDoc = getXMLDocument(smf_prepareScriptUrl(smf_scripturl) + 'action=xmlhttp;sa=jumpto;xml');
984	var aBoardsAndCategories = new Array();
985
986	ajax_indicator(true);
987
988	if (oXMLDoc.responseXML)
989	{
990		var items = oXMLDoc.responseXML.getElementsByTagName('smf')[0].getElementsByTagName('item');
991		for (var i = 0, n = items.length; i < n; i++)
992		{
993			aBoardsAndCategories[aBoardsAndCategories.length] = {
994				id: parseInt(items[i].getAttribute('id')),
995				isCategory: items[i].getAttribute('type') == 'category',
996				name: items[i].firstChild.nodeValue.removeEntities(),
997				is_current: false,
998				childLevel: parseInt(items[i].getAttribute('childlevel'))
999			}
1000		}
1001	}
1002
1003	ajax_indicator(false);
1004
1005	for (var i = 0, n = aJumpTo.length; i < n; i++)
1006		aJumpTo[i].fillSelect(aBoardsAndCategories);
1007}
1008
1009// This'll contain all JumpTo objects on the page.
1010var aJumpTo = new Array();
1011
1012// *** JumpTo class.
1013function JumpTo(oJumpToOptions)
1014{
1015	this.opt = oJumpToOptions;
1016	this.dropdownList = null;
1017	this.showSelect();
1018}
1019
1020// Show the initial select box (onload). Method of the JumpTo class.
1021JumpTo.prototype.showSelect = function ()
1022{
1023	var sChildLevelPrefix = '';
1024	for (var i = this.opt.iCurBoardChildLevel; i > 0; i--)
1025		sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1026	setInnerHTML(document.getElementById(this.opt.sContainerId), this.opt.sJumpToTemplate.replace(/%select_id%/, this.opt.sContainerId + '_select').replace(/%dropdown_list%/, '<select name="' + this.opt.sContainerId + '_select" id="' + this.opt.sContainerId + '_select" ' + ('implementation' in document ? '' : 'onmouseover="grabJumpToContent();" ') + ('onbeforeactivate' in document ? 'onbeforeactivate' : 'onfocus') + '="grabJumpToContent();"><option value="?board=' + this.opt.iCurBoardId + '.0">' + sChildLevelPrefix + this.opt.sBoardPrefix + this.opt.sCurBoardName.removeEntities() + '</option></select>&nbsp;<input type="button" value="' + this.opt.sGoButtonLabel + '" onclick="window.location.href = \'' + smf_prepareScriptUrl(smf_scripturl) + 'board=' + this.opt.iCurBoardId + '.0\';" />'));
1027	this.dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1028}
1029
1030// Fill the jump to box with entries. Method of the JumpTo class.
1031JumpTo.prototype.fillSelect = function (aBoardsAndCategories)
1032{
1033	var bIE5x = !('implementation' in document);
1034	var iIndexPointer = 0;
1035
1036	// Create an option that'll be above and below the category.
1037	var oDashOption = document.createElement('option');
1038	oDashOption.appendChild(document.createTextNode(this.opt.sCatSeparator));
1039	oDashOption.disabled = 'disabled';
1040	oDashOption.value = '';
1041
1042	// Reset the events and clear the list (IE5.x only).
1043	if (bIE5x)
1044	{
1045		this.dropdownList.onmouseover = null;
1046		this.dropdownList.remove(0);
1047	}
1048	if ('onbeforeactivate' in document)
1049		this.dropdownList.onbeforeactivate = null;
1050	else
1051		this.dropdownList.onfocus = null;
1052
1053	// Create a document fragment that'll allowing inserting big parts at once.
1054	var oListFragment = bIE5x ? this.dropdownList : document.createDocumentFragment();
1055
1056	// Loop through all items to be added.
1057	for (var i = 0, n = aBoardsAndCategories.length; i < n; i++)
1058	{
1059		var j, sChildLevelPrefix, oOption;
1060
1061		// If we've reached the currently selected board add all items so far.
1062		if (!aBoardsAndCategories[i].isCategory && aBoardsAndCategories[i].id == this.opt.iCurBoardId)
1063		{
1064			if (bIE5x)
1065				iIndexPointer = this.dropdownList.options.length;
1066			else
1067			{
1068				this.dropdownList.insertBefore(oListFragment, this.dropdownList.options[0]);
1069				oListFragment = document.createDocumentFragment();
1070				continue;
1071			}
1072		}
1073
1074		if (aBoardsAndCategories[i].isCategory)
1075			oListFragment.appendChild(oDashOption.cloneNode(true));
1076		else
1077			for (j = aBoardsAndCategories[i].childLevel, sChildLevelPrefix = ''; j > 0; j--)
1078				sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1079
1080		oOption = document.createElement('option');
1081		oOption.appendChild(document.createTextNode((aBoardsAndCategories[i].isCategory ? this.opt.sCatPrefix : sChildLevelPrefix + this.opt.sBoardPrefix) + aBoardsAndCategories[i].name));
1082		oOption.value = aBoardsAndCategories[i].isCategory ? '#c' + aBoardsAndCategories[i].id : '?board=' + aBoardsAndCategories[i].id + '.0';
1083		oListFragment.appendChild(oOption);
1084
1085		if (aBoardsAndCategories[i].isCategory)
1086			oListFragment.appendChild(oDashOption.cloneNode(true));
1087	}
1088
1089	// Add the remaining items after the currently selected item.
1090	this.dropdownList.appendChild(oListFragment);
1091
1092	if (bIE5x)
1093		this.dropdownList.options[iIndexPointer].selected = true;
1094
1095	// Internet Explorer needs this to keep the box dropped down.
1096	this.dropdownList.style.width = 'auto';
1097	this.dropdownList.focus();
1098
1099	// Add an onchange action
1100	this.dropdownList.onchange = function() {
1101		if (this.selectedIndex > 0 && this.options[this.selectedIndex].value)
1102			window.location.href = smf_scripturl + this.options[this.selectedIndex].value.substr(smf_scripturl.indexOf('?') == -1 || this.options[this.selectedIndex].value.substr(0, 1) != '?' ? 0 : 1);
1103	}
1104}
1105
1106// A global array containing all IconList objects.
1107var aIconLists = new Array();
1108
1109// *** IconList object.
1110function IconList(oOptions)
1111{
1112	if (!window.XMLHttpRequest)
1113		return;
1114
1115	this.opt = oOptions;
1116	this.bListLoaded = false;
1117	this.oContainerDiv = null;
1118	this.funcMousedownHandler = null;
1119	this.funcParent = this;
1120	this.iCurMessageId = 0;
1121	this.iCurTimeout = 0;
1122
1123	// Add backwards compatibility with old themes.
1124	if (!('sSessionVar' in this.opt))
1125		this.opt.sSessionVar = 'sesc';
1126
1127	this.initIcons();
1128}
1129
1130// Replace all message icons by icons with hoverable and clickable div's.
1131IconList.prototype.initIcons = function ()
1132{
1133	for (var i = document.images.length - 1, iPrefixLength = this.opt.sIconIdPrefix.length; i >= 0; i--)
1134		if (document.images[i].id.substr(0, iPrefixLength) == this.opt.sIconIdPrefix)
1135			setOuterHTML(document.images[i], '<div title="' + this.opt.sLabelIconList + '" onclick="' + this.opt.sBackReference + '.openPopup(this, ' + document.images[i].id.substr(iPrefixLength) + ')" onmouseover="' + this.opt.sBackReference + '.onBoxHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onBoxHover(this, false)" style="background: ' + this.opt.sBoxBackground + '; cursor: ' + (is_ie && !is_ie6up ? 'hand' : 'pointer') + '; padding: 3px; text-align: center;"><img src="' + document.images[i].src + '" alt="' + document.images[i].alt + '" id="' + document.images[i].id + '" style="margin: 0px; padding: ' + (is_ie ? '3px' : '3px 0px 3px 0px') + ';" /></div>');
1136}
1137
1138// Event for the mouse hovering over the original icon.
1139IconList.prototype.onBoxHover = function (oDiv, bMouseOver)
1140{
1141	oDiv.style.border = bMouseOver ? this.opt.iBoxBorderWidthHover + 'px solid ' + this.opt.sBoxBorderColorHover : '';
1142	oDiv.style.background = bMouseOver ? this.opt.sBoxBackgroundHover : this.opt.sBoxBackground;
1143	oDiv.style.padding = bMouseOver ? (3 - this.opt.iBoxBorderWidthHover) + 'px' : '3px'
1144}
1145
1146// Show the list of icons after the user clicked the original icon.
1147IconList.prototype.openPopup = function (oDiv, iMessageId)
1148{
1149	this.iCurMessageId = iMessageId;
1150
1151	if (!this.bListLoaded && this.oContainerDiv == null)
1152	{
1153		// Create a container div.
1154		this.oContainerDiv = document.createElement('div');
1155		this.oContainerDiv.id = 'iconList';
1156		this.oContainerDiv.style.display = 'none';
1157		this.oContainerDiv.style.cursor = is_ie && !is_ie6up ? 'hand' : 'pointer';
1158		this.oContainerDiv.style.position = 'absolute';
1159		this.oContainerDiv.style.width = oDiv.offsetWidth + 'px';
1160		this.oContainerDiv.style.background = this.opt.sContainerBackgroun
1160d;
1161		this.oContainerDiv.style.border = this.opt.sContainerBorder;
1162		this.oContainerDiv.style.padding = '1px';
1163		this.oContainerDiv.style.textAlign = 'center';
1164		document.body.appendChild(this.oContainerDiv);
1165
1166		// Start to fetch its contents.
1167		ajax_indicator(true);
1168		this.tmpMethod = getXMLDocument;
1169		this.tmpMethod(smf_prepareScriptUrl(this.opt.sScriptUrl) + 'action=xmlhttp;sa=messageicons;board=' + this.opt.iBoardId + ';xml', this.onIconsReceived);
1170		delete this.tmpMethod;
1171
1172		createEventListener(document.body);
1173	}
1174
1175	// Set the position of the container.
1176	var aPos = smf_itemPos(oDiv);
1177	if (is_ie50)
1178		aPos[1] += 4;
1179
1180	this.oContainerDiv.style.top = (aPos[1] + oDiv.offsetHeight) + 'px';
1181	this.oContainerDiv.style.left = (aPos[0] - 1) + 'px';
1182	this.oClickedIcon = oDiv;
1183
1184	if (this.bListLoaded)
1185		this.oContainerDiv.style.display = 'block';
1186
1187	document.body.addEventListener('mousedown', this.onWindowMouseDown, false);
1188}
1189
1190// Setup the list of icons once it is received through xmlHTTP.
1191IconList.prototype.onIconsReceived = function (oXMLDoc)
1192{
1193	var icons = oXMLDoc.getElementsByTagName('smf')[0].getElementsByTagName('icon');
1194	var sItems = '';
1195
1196	for (var i = 0, n = icons.length; i < n; i++)
1197		sItems += '<div onmouseover="' + this.opt.sBackReference + '.onItemHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onItemHover(this, false);" onmousedown="' + this.opt.sBackReference + '.onItemMouseDown(this, \'' + icons[i].getAttribute('value') + '\');" style="padding: 3px 0px 3px 0px; margin-left: auto; margin-right: auto; border: ' + this.opt.sItemBorder + ';
1197 background: ' + this.opt.sItemBackground + '"><img src="' + icons[i].getAttribute('url') + '" alt="' + icons[i].getAttribute('name') + '" title="' + icons[i].firstChild.nodeValue + '" /></div>';
1198
1199	setInnerHTML(this.oContainerDiv, sItems);
1200	this.oContainerDiv.style.display = 'block';
1201	this.bListLoaded = true;
1202
1203	if (is_ie)
1204		this.oContainerDiv.style.width = this.oContainerDiv.clientWidth + 'px';
1205
1206	ajax_indicator(false);
1207}
1208
1209// Event handler for hovering over the icons.
1210IconList.prototype.onItemHover = function (oDiv, bMouseOver)
1211{
1212	oDiv.style.background = bMouseOver ? this.opt.sItemBackgroundHover : this.opt.sItemBackground;
1213	oDiv.style.border = bMouseOver ? this.opt.sItemBorderHover : this.opt.sItemBorder;
1214	if (this.iCurTimeout != 0)
1215		window.clearTimeout(this.iCurTimeout);
1216	if (bMouseOver)
1217		this.onBoxHover(this.oClickedIcon, true);
1218	else
1219		this.iCurTimeout = window.setTimeout(this.opt.sBackReference + '.collapseList();', 500);
1220}
1221
1222// Event handler for clicking on one of the icons.
1223IconList.prototype.onItemMouseDown = function (oDiv, sNewIcon)
1224{
1225	if (this.iCurMessageId != 0)
1226	{
1227		ajax_indicator(true);
1228		this.tmpMethod = getXMLDocument;
1229		var oXMLDoc = this.tmpMethod(smf_prepareScriptUrl(this.opt.sScriptUrl) + 'action=jsmodify;topic=' + this.opt.iTopicId + ';msg=' + this.iCurMessageId + ';' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';icon=' + sNewIcon + ';xml');
1230		delete this.tmpMethod;
1231		ajax_indicator(false);
1232
1233		var oMessage = oXMLDoc.responseXML.getElementsByTagName('smf')[0].getElementsByTagName('message')[0];
1234		if (oMessage.getElementsByTagName('error').length == 0)
1235		{
1236			if (this.opt.bShowModify && oMessage.getElementsByTagName('modified').length != 0)
1237				setInnerHTML(document.getElementById('modified_' + this.iCurMessageId), oMessage.getElementsByTagName('modified')[0].childNodes[0].nodeValue);
1238			this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1239		}
1240	}
1241}
1242
1243// Event handler for clicking outside the list (will make the list disappear).
1244IconList.prototype.onWindowMouseDown = function ()
1245{
1246	for (var i = aIconLists.length - 1; i >= 0; i--)
1247	{
1248		aIconLists[i].funcParent.tmpMethod = aIconLists[i].collapseList;
1249		aIconLists[i].funcParent.tmpMethod();
1250		delete aIconLists[i].funcParent.tmpMethod;
1251	}
1252}
1253
1254// Collapse the list of icons.
1255IconList.prototype.collapseList = function()
1256{
1257	this.onBoxHover(this.oClickedIcon, false);
1258	this.oContainerDiv.style.display = 'none';
1259	this.iCurMessageId = 0;
1260	document.body.removeEventListener('mousedown', this.onWindowMouseDown, false);
1261}
1262
1263// Handy shortcuts for getting the mouse position on the screen - only used for IE at the moment.
1264function smf_mousePose(oEvent)
1265{
1266	var x = 0;
1267	var y = 0;
1268
1269	if (oEvent.pageX)
1270	{
1271		y = oEvent.pageY;
1272		x = oEvent.pageX;
1273	}
1274	else if (oEvent.clientX)
1275	{
1276		x = oEvent.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
1277		y = oEvent.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
1278	}
1279
1280	return [x, y];
1281}
1282
1283// Short function for finding the actual position of an item.
1284function smf_itemPos(itemHandle)
1285{
1286	var itemX = 0;
1287	var itemY = 0;
1288
1289	if ('offsetParent' in itemHandle)
1290	{
1291		itemX = itemHandle.offsetLeft;
1292		itemY = itemHandle.offsetTop;
1293		while (itemHandle.offsetParent && typeof(itemHandle.offsetParent) == 'object')
1294		{
1295			itemHandle = itemHandle.offsetParent;
1296			itemX += itemHandle.offsetLeft;
1297			itemY += itemHandle.offsetTop;
1298		}
1299	}
1300	else if ('x' in itemHandle)
1301	{
1302		itemX = itemHandle.x;
1303		itemY = itemHandle.y;
1304	}
1305
1306	return [itemX, itemY];
1307}
1308
1309// This function takes the script URL and prepares it to allow the query string to be appended to it.
1310function smf_prepareScriptUrl(sUrl)
1311{
1312	return sUrl.indexOf('?') == -1 ? sUrl + '?' : sUrl + (sUrl.charAt(sUrl.length - 1) == '?' || sUrl.charAt(sUrl.length - 1) == '&' || sUrl.charAt(sUrl.length - 1) == ';' ? '' : ';');
1313}
1314
1315var aOnloadEvents = new Array();
1316function addLoadEvent(fNewOnload)
1317{
1318	// If there's no event set, just set this one
1319	if (typeof(fNewOnload) == 'function' && (!('onload' in window) || typeof(window.onload) != 'function'))
1320		window.onload = fNewOnload;
1321
1322	// If there's just one event, setup the array.
1323	else if (aOnloadEvents.length == 0)
1324	{
1325		aOnloadEvents[0] = window.onload;
1326		aOnloadEvents[1] = fNewOnload;
1327		window.onload = function() {
1328			for (var i = 0, n = aOnloadEvents.length; i < n; i++)
1329			{
1330				if (typeof(aOnloadEvents[i]) == 'function')
1331					aOnloadEvents[i]();
1332				else if (typeof(aOnloadEvents[i]) == 'string')
1333					eval(aOnloadEvents[i]);
1334			}
1335		}
1336	}
1337
1338	// This isn't the first event function, add it to the list.
1339	else
1340		aOnloadEvents[aOnloadEvents.length] = fNewOnload;
1341}
1342
1343function smfFooterHighlight(element, value)
1344{
1345	element.src = smf_images_url + '/' + (value ? 'h_' : '') + element.i
1345d + '.gif';
1346}
1347
1348// Get the text in a code tag.
1349function smfSelectText(oCurElement, bActOnElement)
1350{
1351	// The place we're looking for is one div up, and next door - if it's auto detect.
1352	if (typeof(bActOnElement) == 'boolean' && bActOnElement)
1353		var oCodeArea = document.getElementById(oCurElement);
1354	else
1355		var oCodeArea = oCurElement.parentNode.nextSibling;
1356
1357	if (typeof(oCodeArea) != 'object' || oCodeArea == null)
1358		return false;
1359
1360	// Start off with my favourite, internet explorer.
1361	if ('createTextRange' in document.body)
1362	{
1363		var oCurRange = document.body.createTextRange();
1364		oCurRange.moveToElementText(oCodeArea);
1365		oCurRange.select();
1366	}
1367	// Firefox at el.
1368	else if (window.getSelection)
1369	{
1370		var oCurSelection = window.getSelection();
1371		// Safari is special!
1372		if (oCurSelection.selectAllChildren)
1373		{
1374			oCurSelection.selectAllChildren(oCodeArea);
1375		}
1376		else if (oCurSelection.setBaseAndExtent)
1377		{
1378			var oLastChild = oCodeArea.lastChild;
1379			oCurSelection.setBaseAndExtent(oCodeArea, 0, oLastChild, 'innerText' in oLastChild ? oLastChild.innerText.length : oLastChild.textContent.length);
1380		}
1381		else
1382		{
1383			var curRange = document.createRange();
1384			curRange.selectNodeContents(oCodeArea);
1385
1386			oCurSelection.removeAllRanges();
1387			oCurSelection.addRange(curRange);
1388		}
1389	}
1390
1391	return false;
1392}
1393
1394// A function needed to discern HTML entities from non-western characters.
1395function smc_saveEntities(sFormName, aElementNames, sMask)
1396{
1397	if (typeof(sMask) == 'string')
1398	{
1399		for (var i = 0, n = document.forms[sFormName].elements.length; i < n; i++)
1400			if (document.forms[sFormName].elements[i].id.substr(0, sMask.length) == sMask)
1401				aElementNames[aElementNames.length] = document.forms[sFormName].elements[i].name;
1402	}
1403
1404	for (var i = 0, n = aElementNames.length; i < n; i++)
1405	{
1406		if (aElementNames[i] in document.forms[sFormName])
1407			document.forms[sFormName][aElementNames[i]].value = document.forms[sFormName][aElementNames[i]].value.replace(/&#/g, '&#38;#');
1408	}
1409}
1410
1411// A function used to clean the attachments on post page
1412function cleanFileInput(idElement)
1413{
1414	// Simpler solutions work in Opera, IE, Safari and Chrome.
1415	if (is_opera || is_ie || is_safari || is_chrome)
1416	{
1417		document.getElementById(idElement).outerHTML = document.getElementById(idElement).outerHTML;
1418	}
1419	// What else can we do? By the way, this doesn't work in Chrome and Mac's Safari.
1420	else
1421	{
1422		document.getElementById(idElement).type = 'input';
1423		document.getElementById(idElement).type = 'file';
1424	}
1425}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.