PageSourceSearch

https://caliberclub.ru/forum/clientscript/vbulletin_global.js?v=381

js caliberclub.ru collected 2026-10-08 16:15:31 UTC 55,534 bytes, 2,363 lines download raw bytes

1var _____WB$wombat$assign$function_____ = function(name) {return (self._wb_wombat && self._wb_wombat.local_init && self._wb_wombat.local_init(name)) || self[name]; };
2if (!self.__WB_pmw) { self.__WB_pmw = function(obj) { this.__WB_source = obj; return this; } }
3{
4  let window = _____WB$wombat$assign$function_____("window");
5  let self = _____WB$wombat$assign$function_____("self");
6  let document = _____WB$wombat$assign$function_____("document");
7  let location = _____WB$wombat$assign$function_____("location");
8  let top = _____WB$wombat$assign$function_____("top");
9  let parent = _____WB$wombat$assign$function_____("parent");
10  let frames = _____WB$wombat$assign$function_____("frames");
11  let opener = _____WB$wombat$assign$function_____("opener");
12
13/*!======================================================================*\
14|| #################################################################### ||
15|| # vBulletin 3.8.1
16|| # ---------------------------------------------------------------- # ||
17|| # Copyright ©2000-2009 Jelsoft Enterprises Ltd. All Rights Reserved. ||
18|| # This file may not be redistributed in whole or significant part. # ||
19|| # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
20|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
21|| #################################################################### ||
22\*======================================================================*/
23
24/**
25* Handle Firebug calls when Firebug is not available (getfirebug.com)
26*/
27if (!window.console || !console.firebug)
28{
29	window.console = {};
30	var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
31	for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {};
32}
33
34/**
35* Setup Variables
36*
37* @var	string	SESSIONURL - stores the session URL
38* @var	string	SECURITYTOKEN - token that should be passed with POST requests
39* @var	array	vbphrase - stores text phrases
40* @var	array	vB_Editor - array of vB_Text_Editor objects
41* @var	boolean	ignorequotechars - ignore characters inside [quote] tags for message length check
42* @var	integer	pagenavcounter - counts the number of pagenav instances encountered so far
43* @var	boolean	is_regexp - does window.regExp exist? - Catch errors with less capable browsers
44* @var	boolean	AJAX_Compatible - does the current browser support AJAX?
45* @var	string	pointer_cursor - help out old versions of IE that don't understand style.cursor = pointer
46* @var	array	Viewport info array
47* @var	integer	Length of standard AJAX timeout (ms)
48*/
49var SESSIONURL       = (typeof(SESSIONURL) == "undefined" ? "" : SESSIONURL);
50var SECURITYTOKEN    = (typeof(SECURITYTOKEN) == "undefined" ? "" : SECURITYTOKEN);
51var vbphrase         = (typeof(vbphrase) == "undefined" ? new Array() : vbphrase);
52var vB_Editor        = new Array();
53var ignorequotechars = false;
54var pagenavcounter   = 0;
55var is_regexp        = (window.RegExp) ? true : false;
56var AJAX_Compatible  = false;
57var viewport_info    = null;
58var vB_Default_Timeout = 15000;
59
60/**
61* Define the browser loading the page
62*
63* @var	string	userAgent Useragent string
64* @var	boolean	is_opera  Opera
65* @var	boolean	is_saf    Safari
66* @var	boolean	is_webtv  WebTV
67* @var	boolean	is_ie     Internet Explorer
68* @var	boolean	is_ie4    Internet Explorer 4
69* @var	boolean	is_ie7    Internet Explorer 7
70* @var	boolean	is_ps3    Playstation 3
71* @var	boolean	is_moz    Mozilla / Firefox / Camino
72* @var	boolean	is_kon    Konqueror
73* @var	boolean	is_ns     Netscape
74* @var	boolean	is_ns4    Netscape 4
75* @var	boolean	is_mac    Client is running MacOS
76*/
77var userAgent = navigator.userAgent.toLowerCase();
78var is_opera  = ((userAgent.indexOf('opera') != -1) || (typeof(window.opera) != 'undefined'));
79var is_saf    = ((userAgent.indexOf('applewebkit') != -1) || (navigator.vendor == 'Apple Computer, Inc.'));
80var is_webtv  = (userAgent.indexOf('webtv') != -1);
81var is_ie     = ((userAgent.indexOf('msie') != -1) && (!is_opera) && (!is_saf) && (!is_webtv));
82var is_ie4    = ((is_ie) && (userAgent.indexOf('msie 4.') != -1));
83var is_ie7    = ((is_ie) && (userAgent.indexOf('msie 7.') != -1));
84var is_ps3    = (userAgent.indexOf('playstation 3') != -1);
85var is_moz    = ((navigator.product == 'Gecko') && (!is_saf));
86var is_kon    = (userAgent.indexOf('konqueror') != -1);
87var is_ns     = ((userAgent.indexOf('compatible') == -1) && (userAgent.indexOf('mozilla') != -1) && (!is_opera) && (!is_webtv) && (!is_saf));
88var is_ns4    = ((is_ns) && (parseInt(navigator.appVersion) == 4));
89var is_mac    = (userAgent.indexOf('mac') != -1);
90
91/**
92* @var	string	pointer_cursor - help out old versions of IE that don't understand style.cursor = pointer
93*/
94var pointer_cursor   = (is_ie ? 'hand' : 'pointer');
95
96/**
97* Workaround for heinous IE bug - add special vBlength property to all strings
98* This method is applied to ALL string objects automatically
99*
100* @return	integer
101*/
102String.prototype.vBlength = function()
103{
104	return (is_ie && this.indexOf("\n") != -1) ? this.replace(/\r?\n/g, "_").length : this.length;
105}
106
107/**
108* Overrides IE's original String.prototype.substr to accept negative values
109*
110* @param	integer	Substring start position
111* @param	integer	Substring length
112*
113* @return	string
114*/
115if ("1234".substr(-2, 2) == "12") // (which would be incorrect)
116{
117	String.prototype.substr_orig = String.prototype.substr;
118
119	String.prototype.substr = function(start, length)
120	{
121		if (typeof(length) == "undefined")
122		{
123			return this.substr_orig((start < 0 ? this.length + start : start));
124		}
125		else
126		{
127			return this.substr_orig((start < 0 ? this.length + start : start), length);
128		}
129	};
130}
131
132/**
133* Define Array.shift() for browsers that don't have it
134*/
135if (typeof Array.prototype.shift === 'undefined')
136{
137	Array.prototype.shift = function()
138	{
139		for(var i = 0, b = this[0], l = this.length-1; i < l; i++)
140		{
141			this[i] = this[i + 1];
142		}
143		this.length--;
144		return b;
145	};
146}
147
148/**
149* Function to emulate document.getElementById
150*
151* @param	string	Object ID
152*
153* @return	mixed	null if not found, object if found
154*/
155function fetch_object(idname)
156{
157	if (document.getElementById)
158	{
159		return document.getElementById(idname);
160	}
161	else if (document.all)
162	{
163		return document.all[idname];
164	}
165	else if (document.layers)
166	{
167		return document.layers[idname];
168	}
169	else
170	{
171		return null;
172	}
173}
174
175/**
176* Function to emulate document.getElementsByTagName
177*
178* @param	object	Parent object (eg: document)
179* @param	string	Tag type (eg: 'td')
180*
181* @return	array
182*/
183function fetch_tags(parentobj, tag)
184{
185	if (parentobj == null)
186	{
187		return new Array();
188	}
189	else if (typeof parentobj.getElementsByTagName != 'undefined')
190	{
191		return parentobj.getElementsByTagName(tag);
192	}
193	else if (parentobj.all && parentobj.all.tags)
194	{
195		return parentobj.all.tags(tag);
196	}
197	else
198	{
199		return new Array();
200	}
201}
202
203/**
204* Function to count the number of tags in an object
205*
206* @param	object	Parent object (eg: document)
207* @param	string	Tag type (eg: 'td')
208*
209* @return	integer
210*/
211function fetch_tag_count(parentobj, tag)
212{
213	return fetch_tags(parentobj, tag).length;
214}
215
216// #############################################################################
217// Event handlers
218
219/**
220* Handles the different event models of different browsers and prevents event bubbling
221*
222* @param	event	Event object
223*
224* @return	event
225*/
226function do_an_e(eventobj)
227{
228	if (!eventobj || is_ie)
229	{
230		window.event.returnValue = false;
231		window.event.cancelBubble = true;
232		return window.event;
233	}
234	else
235	{
236		eventobj.stopPropagation();
237		eventobj.preventDefault();
238		return eventobj;
239	}
240}
241
242/**
243* Handles the different event models of different browsers and prevents event bubbling in a lesser way than do_an_e()
244*
245* @param	event	Event object
246*
247* @return	event
248*/
249function e_by_gum(eventobj)
250{
251	if (!eventobj || is_ie)
252	{
253		window.event.cancelBubble = true;
254		return window.event;
255	}
256	else
257	{
258		if (eventobj.target.type == 'submit')
259		{
260			// naughty safari
261			eventobj.target.form.submit();
262		}
263		eventobj.stopPropagation();
264		return eventobj;
265	}
266}
267
268// #############################################################################
269// Message manipulation and validation
270
271/**
272* Checks that a message is valid for submission to PHP
273*
274* @param	string	Message text
275* @param	mixed	Either subject text (if you want to make sure it exists) or 0 if you don't care
276* @param	integer	Minimum acceptable character limit for the message
277*
278* @return	boolean
279*/
280function validatemessage(messagetext, subjecttext, minchars)
281{
282	if (is_kon || is_saf || is_webtv)
283	{
284		// ignore less-than-capable browsers
285		return true;
286	}
287	else if (subjecttext.length < 1)
288	{
289		// subject not specified
290		alert(vbphrase['must_enter_subject']);
291		return false;
292	}
293	else
294	{
295		var stripped = PHP.trim(stripcode(messagetext, false, ignorequotechars));
296
297		if (stripped.length < minchars)
298		{
299			// minimum message length not met
300			alert(construct_phrase(vbphrase['message_too_short'], minchars));
301			return false;
302		}
303		else if (typeof(document.forms.vbform) != 'undefined' && typeof(document.forms.vbform.imagestamp) != 'undefined')
304		{
305			// This form has image verification enabled
306			document.forms.vbform.imagestamp.failed = false;
307
308			if (document.forms.vbform.imagestamp.value.length != 6)
309			{
310				alert(vbphrase['complete_image_verification']);
311				document.forms.vbform.imagestamp.failed = true;
312				document.forms.vbform.imagestamp.focus();
313				return false;
314			}
315			else
316			{
317				return true;
318			}
319		}
320		else
321		{
322			// everything seems ok
323			return true;
324		}
325	}
326}
327
328
329/**
330* Strips quotes and bbcode tags from text
331*
332* @param	string	Text to manipulate
333* @param	boolean	If true, strip <x> otherwise strip [x]
334* @param	boolean	If true, strip all [quote]...contents...[/quote]
335*
336* @return	string
337*/
338function stripcode(str, ishtml, stripquotes)
339{
340	if (!is_regexp)
341	{
342		return str;
343	}
344
345	if (stripquotes)
346	{
347		var start_time = new Date().getTime();
348
349		while ((startindex = PHP.stripos(str, '[quote')) !== false)
350		{
351			if (new Date().getTime() - start_time > 2000)
352			{
353				// while loop has been running for over 2 seconds and has probably gone infinite
354				break;
355			}
356
357			if ((stopindex = PHP.stripos(str, '[/quote]')) !== false)
358			{
359				fragment = str.substr(startindex, stopindex - startindex + 8);
360				str = str.replace(fragment, '');
361			}
362			else
363			{
364				break;
365			}
366			str = PHP.trim(str);
367		}
368	}
369
370	if (ishtml)
371	{
372		// exempt image tags -- they need to count as characters in the string
373		// as the do as BB codes
374		str = str.replace(/<img[^>]+src="([^"]+)"[^>]*>/gi, '$1');
375
376		var html1 = new RegExp("<(\\w+)[^>]*>", 'gi');
377		var html2 = new RegExp("<\\/\\w+>", 'gi');
378
379		str = str.replace(html1, '');
380		str = str.replace(html2, '');
381
382		var html3 = new RegExp('(&nbsp;)', 'gi');
383		str = str.replace(html3, ' ');
384	}
385	else
386	{
387		var bbcode1 = new RegExp("\\[(\\w+)(=[^\\]]*)?\\]", 'gi');
388		var bbcode2 = new RegExp("\\[\\/(\\w+)\\]", 'gi');
389
390		str = str.replace(bbcode1, '');
391		str = str.replace(bbcode2, '');
392	}
393
394	return str;
395}
396
397// #############################################################################
398// vB_PHP_Emulator class
399// #############################################################################
400
401/**
402* PHP Function Emulator Class
403*/
404function vB_PHP_Emulator()
405{
406}
407
408// =============================================================================
409// vB_PHP_Emulator Methods
410
411/**
412* Find a string within a string (case insensitive)
413*
414* @param	string	Haystack
415* @param	string	Needle
416* @param	integer	Offset
417*
418* @return	mixed	Not found: false / Found: integer position
419*/
420vB_PHP_Emulator.prototype.stripos = function(haystack, needle, offset)
421{
422	if (typeof offset == 'undefined')
423	{
424		offset = 0;
425	}
426
427	index = haystack.toLowerCase().indexOf(needle.toLowerCase(), offset);
428
429	return (index == -1 ? false : index);
430}
431
432/**
433* Trims leading whitespace
434*
435* @param	string	String to trim
436*
437* @return	string
438*/
439vB_PHP_Emulator.prototype.ltrim = function(str)
440{
441	return str.replace(/^\s+/g, '');
442}
443
444/**
445* Trims trailing whitespace
446*
447* @param	string	String to trim
448*
449* @return	string
450*/
451vB_PHP_Emulator.prototype.rtrim = function(str)
452{
453	return str.replace(/(\s+)$/g, '');
454}
455
456/**
457* Trims leading and trailing whitespace
458*
459* @param	string	String to trim
460*
461* @return	string
462*/
463vB_PHP_Emulator.prototype.trim = function(str)
464{
465	return this.ltrim(this.rtrim(str));
466}
467
468/**
469* Emulation of PHP's preg_quote()
470*
471* @param	string	String to process
472*
473* @return	string
474*/
475vB_PHP_Emulator.prototype.preg_quote = function(str)
476{
477	// replace + { } ( ) [ ] | / ? ^ $ \ . = ! < > : * with backslash+character
478	return str.replace(/(\+|\{|\}|\(|\)|\[|\]|\||\/|\?|\^|\$|\\|\.|\=|\!|\<|\>|\:|\*)/g, "\\$1");
479}
480
481/**
482* Emulates PHP's preg_match_all()... sort of
483*
484* @param	string	Haystack
485* @param	string	Regular expression - to be inserted into RegExp(x)
486*
487* @return	mixed	Array on match, false on no match
488*/
489vB_PHP_Emulator.prototype.match_all = function(string, regex)
490{
491	var gmatch = string.match(RegExp(regex, "gim"));
492	if (gmatch)
493	{
494		var matches = new Array();
495
496		var iregex = new RegExp(regex, "im");
497		for (var i = 0; i < gmatch.length; i++)
498		{
499			matches[matches.length] = gmatch[i].match(iregex);
500		}
501
502		return matches;
503	}
504	else
505	{
506		return false;
507	}
508}
509
510/**
511* Emulates unhtmlspecialchars in vBulletin
512*
513* @param	string	String to process
514*
515* @return	string
516*/
517vB_PHP_Emulator.prototype.unhtmlspecialchars = function(str)
518{
519	var f = new Array(/&lt;/g, /&gt;/g, /&quot;/g, /&amp;/g);
520	var r = new Array('<', '>', '"', '&');
521
522	for (var i in f)
523	{
524		if (YAHOO.lang.hasOwnProperty(f, i))
525		{
526			str = str.replace(f[i], r[i]);
527		}
528	}
529
530	return str;
531}
532
533/**
534* Unescape CDATA from vB_AJAX_XML_Builder PHP class
535*
536* @param	string	Escaped CDATA
537*
538* @return	string
539*/
540vB_PHP_Emulator.prototype.unescape_cdata = function(str)
541{
542	var r1 = /<\=\!\=\[\=C\=D\=A\=T\=A\=\[/g;
543	var r2 = /\]\=\]\=>/g;
544
545	return str.replace(r1, '<![CDATA[').replace(r2, ']]>');
546}
547
548/**
549* Emulates PHP's htmlspecialchars()
550*
551* @param	string	String to process
552*
553* @return	string
554*/
555vB_PHP_Emulator.prototype.htmlspecialchars = function(str)
556{
557	//var f = new Array(/&(?!#[0-9]+;)/g, /</g, />/g, /"/g);
558	var f = new Array(
559		(is_mac && is_ie ? new RegExp('&', 'g') : new RegExp('&(?!#[0-9]+;)', 'g')),
560		new RegExp('<', 'g'),
561		new RegExp('>', 'g'),
562		new RegExp('"', 'g')
563	);
564	var r = new Array(
565		'&amp;',
566		'&lt;',
567		'&gt;',
568		'&quot;'
569	);
570
571	for (var i = 0; i < f.length; i++)
572	{
573		str = str.replace(f[i], r[i]);
574	}
575
576	return str;
577}
578
579/**
580* Searches an array for a value
581*
582* @param	string	Needle
583* @param	array	Haystack
584* @param	boolean	Case insensitive
585*
586* @return	integer	Not found: -1 / Found: integer index
587*/
588vB_PHP_Emulator.prototype.in_array = function(ineedle, haystack, caseinsensitive)
589{
590	var needle = new String(ineedle);
591	var i;
592
593	if (caseinsensitive)
594	{
595		needle = needle.toLowerCase();
596		for (i in haystack)
597		{
598			if (YAHOO.lang.hasOwnProperty(haystack, i))
599			{
600				if (haystack[i].toLowerCase() == needle)
601				{
602					return i;
603				}
604			}
605		}
606	}
607	else
608	{
609		for (i in haystack)
610		{
611			if (YAHOO.lang.hasOwnProperty(haystack, i))
612			{
613				if (haystack[i] == needle)
614				{
615					return i;
616				}
617			}
618		}
619	}
620	return -1;
621}
622
623/**
624* Emulates PHP's strpad()
625*
626* @param	string	Text to pad
627* @param	integer	Length to pad
628* @param	string	String with which to pad
629*
630* @return	string
631*/
632vB_PHP_Emulator.prototype.str_pad = function(text, length, padstring)
633{
634	text = new String(text);
635	padstring = new String(padstring);
636
637	if (text.length < length)
638	{
639		padtext = new String(padstring);
640
641		while (padtext.length < (length - text.length))
642		{
643			padtext += padstring;
644		}
645
646		text = padtext.substr(0, (length - text.length)) + text;
647	}
648
649	return text;
650}
651
652/**
653* A sort of emulation of PHP's urlencode - not 100% the same, but accomplishes the same thing
654*
655* @param	string	String to encode
656*
657* @return	string
658*/
659vB_PHP_Emulator.prototype.urlencode = function(text)
660{
661	text = escape(text.toString()).replace(/\+/g, "%2B");
662
663	// this escapes 128 - 255, as JS uses the unicode code points for them.
664	// This causes problems with submitting text via AJAX with the UTF-8 charset.
665	var matches = text.match(/(%([0-9A-F]{2}))/gi);
666	if (matches)
667	{
668		for (var matchid = 0; matchid < matches.length; matchid++)
669		{
670			var code = matches[matchid].substring(1,3);
671			if (parseInt(code, 16) >= 128)
672			{
673				text = text.replace(matches[matchid], '%u00' + code);
674			}
675		}
676	}
677
678	// %25 gets translated to % by PHP, so if you have %25u1234,
679	// we see it as %u1234 and it gets translated. So make it %u0025u1234,
680	// which will print as %u1234!
681	text = text.replace('%25', '%u0025');
682
683	return text;
684}
685
686/**
687* Works a bit like ucfirst, but with some extra options
688*
689* @param	string	String with which to work
690* @param	string	Cut off string before first occurence of this string
691*
692* @return	string
693*/
694vB_PHP_Emulator.prototype.ucfirst = function(str, cutoff)
695{
696	if (typeof cutoff != 'undefined')
697	{
698		var cutpos = str.indexOf(cutoff);
699		if (cutpos > 0)
700		{
701			str = str.substr(0, cutpos);
702		}
703	}
704
705	str = str.split(' ');
706	for (var i = 0; i < str.length; i++)
707	{
708		str[i] = str[i].substr(0, 1).toUpperCase() + str[i].substr(1);
709	}
710	return str.join(' ');
711}
712
713// #############################################################################
714// vB_AJAX_Handler
715// #############################################################################
716
717/**
718* XML Sender Class - deprecated. Here for BC only. Use YAHOO.util.Connect.asyncRequest instead.
719*
720* @param	boolean	Should connections be asyncronous? (Now redundant)
721*/
722function vB_AJAX_Handler(async) { this.async = async ? true : false; this.conn = null; };
723vB_AJAX_Handler.prototype.init = function() { return AJAX_Compatible; };
724vB_AJAX_Handler.is_compatible = function() { return AJAX_Compatible; };
725vB_AJAX_Handler.prototype.onreadystatechange = function(callback) { this.callback = callback; };
726vB_AJAX_Handler.prototype.fetch_data = function(xml_node) {
727	console.warn("vB_AJAX_Handler.prototype.fetch_data() is deprecated.\nUse responseXML.getElementsByTagName(\"x\")[i].firstChild.nodeValue instead.");
728	if (xml_node && xml_node.firstChild && xml_node.firstChild.nodeValue) { return PHP.unescape_cdata(xml_node.firstChild.nodeValue); } else { return ''; }
729};
730vB_AJAX_Handler.prototype.send = function(desturl, datastream) {
731	this.conn = YAHOO.util.Connect.asyncRequest("POST", desturl, { success: this.callback }, datastream + "&securitytoken=" + SECURITYTOKEN + "&s=" + fetch_sessionhash());
732	this.handler = this.conn.conn;
733};
734
735/**
736* Checks to see if this Javascript-aware browser is also capable of handling AJAX requests
737*
738* @return	boolean
739*/
740function is_ajax_compatible()
741{
742	if (typeof vb_disable_ajax != "undefined" && vb_disable_ajax == 2)
743	{
744		return false;
745	}
746	else if (is_ie && !is_ie4)
747	{
748		return true;
749	}
750	else if (window.XMLHttpRequest)
751	{
752		try
753		{
754			var ajax_test = new XMLHttpRequest();
755			return ajax_test.setRequestHeader ? true : false;
756		}
757		catch(e)
758		{
759			return false;
760		}
761	}
762	else
763	{
764		return false;
765	}
766}
767
768// we can check this variable to see if browser is AJAX compatible
769AJAX_Compatible = is_ajax_compatible();
770console.info("This browser is%s AJAX compatible", AJAX_Compatible ? "" : " NOT");
771
772// #############################################################################
773// YUI AJAX Stuff
774// #############################################################################
775
776/**
777* Handles AJAX request timeouts returned from YUI connection manager
778*
779* @param	object	YUI AJAX
780*/
781function vBulletin_AJAX_Error_Handler(ajax)
782{
783	/**
784	* Available properties of ajax object
785	*
786	* .tId
787	* .status
788	* .statusText
789	* .getResponseHeader[ ]
790	* .getAllResponseHeaders
791	* .responseText
792	* .responseXML
793	* .argument
794	*/
795	console.warn("AJAX Error: Status = %s: %s", ajax.status, ajax.statusText);
796}
797
798// #############################################################################
799// vB_Hidden_Form
800// #############################################################################
801
802/**
803* Form Generator Class
804*
805* Builds a form filled with hidden fields for invisible submit via POST
806*
807* @param	string	Script (my_target_script.php)
808*/
809function vB_Hidden_Form(script)
810{
811	this.action = script;
812	this.variables = new Array();
813}
814
815// =============================================================================
816// vB_Hidden_Form methods
817
818/**
819* Adds a hidden input field to the form object
820*
821* @param	string	Name attribute
822* @param	string	Value attribute
823*/
824vB_Hidden_Form.prototype.add_variable = function(name, value)
825{
826	this.variables[this.variables.length] = new Array(name, value);
827	console.log("vB_Hidden_Form :: add_variable(%s)", name);
828};
829
830/**
831* Fetches all form elements inside an HTML element and performs 'add_input()' on them
832*
833* @param	object	HTML element to search
834*/
835vB_Hidden_Form.prototype.add_variables_from_object = function(obj)
836{
837	if (!obj)
838	{
839		return;
840	}
841	console.info("vB_Hidden_Form :: add_variables_from_object(%s)", obj.id);
842	var inputs = fetch_tags(obj, 'input');
843	var i;
844
845	for (i = 0; i < inputs.length; i++)
846	{
847		switch (inputs[i].type)
848		{
849			case 'checkbox':
850			case 'radio':
851				if (inputs[i].checked)
852				{
853					this.add_variable(inputs[i].name, inputs[i].value);
854				}
855				break;
856			case 'text':
857			case 'hidden':
858			case 'password':
859				this.add_variable(inputs[i].name, inputs[i].value);
860				break;
861			default:
862				continue;
863		}
864	}
865
866	var textareas = fetch_tags(obj, 'textarea');
867	for (i = 0; i < textareas.length; i++)
868	{
869		this.add_variable(textareas[i].name, textareas[i].value);
870	}
871
872	var selects = fetch_tags(obj, 'select');
873	for (i = 0; i < selects.length; i++)
874	{
875		if (selects[i].multiple)
876		{
877			for (var j = 0; j < selects[i].options.length; j++)
878			{
879				if (selects[i].options[j].selected)
880				{
881					this.add_variable(selects[i].name, selects[i].options[j].value);
882				}
883			}
884		}
885		else
886		{
887			this.add_variable(selects[i].name, selects[i].options[selects[i].selectedIndex].value);
888		}
889	}
890};
891
892/**
893* Fetches a variable value
894*
895* @param	string	Variable name
896*
897* @return	mixed	Variable value
898*/
899vB_Hidden_Form.prototype.fetch_variable = function(varname)
900{
901	for (var i = 0; i < this.variables.length; i++)
902	{
903		if (this.variables[i][0] == varname)
904		{
905			return this.variables[i][1];
906		}
907	}
908
909	return null;
910};
911
912/**
913* Submits the hidden form object
914*/
915vB_Hidden_Form.prototype.submit_form = function()
916{
917	this.form = document.createElement('form');
918	this.form.method = 'post';
919	this.form.action = this.action;
920
921	for (var i = 0; i < this.variables.length; i++)
922	{
923		var inputobj = document.createElement('input');
924
925		inputobj.type  = 'hidden';
926		inputobj.name  = this.variables[i][0];
927		inputobj.value = this.variables[i][1];
928
929		this.form.appendChild(inputobj);
930	}
931
932	console.info("vB_Hidden_Form :: submit_form() -> %s", this.action);
933	document.body.appendChild(this.form).submit();
934};
935
936/**
937* Builds a URI query string from the given variables
938*/
939vB_Hidden_Form.prototype.build_query_string = function()
940{
941	var query_string = '';
942
943	for (var i = 0; i < this.variables.length; i++)
944	{
945		query_string += this.variables[i][0] + '=' + PHP.urlencode(this.variables[i][1]) + '&';
946	}
947
948	console.info("vB_Hidden_Form :: Query String = %s", query_string);
949	return query_string;
950}
951
952/**
953* Legacy functions for backward compatability
954*/
955vB_Hidden_Form.prototype.add_input = vB_Hidden_Form.prototype.add_variable;
956vB_Hidden_Form.prototype.add_inputs_from_object = vB_Hidden_Form.prototype.add_variables_from_object;
957
958
959// #############################################################################
960// vB_Select_Overlay_Handler
961// #############################################################################
962
963/**
964* Handler for <select> tags that are overlayed with another element
965* Fixes a problem in IE versions older than IE7.
966*
967* @param	mixed	Object or ID string that is the overlayed object
968*/
969function vB_Select_Overlay_Handler(overlay)
970{
971	this.browser_affected = (is_ie && !is_ie7);
972
973	if (this.browser_affected)
974	{
975		this.overlay = YAHOO.util.Dom.get(overlay);
976		this.hidden_selects = new Array();
977		console.log("Initializing <select> overlay handler for '%s'.", this.overlay.id);
978	}
979}
980
981// =============================================================================
982// vB_Hidden_Form methods
983
984/**
985* Hides any selects that intersect the overlayed object
986*/
987vB_Select_Overlay_Handler.prototype.hide = function()
988{
989	if (this.browser_affected)
990	{
991		var overlay_region = YAHOO.util.Dom.getRegion(this.overlay);
992
993		var selects = document.getElementsByTagName("select");
994		for (var i = 0; i < selects.length; i++)
995		{
996			if (region_intersects(selects[i], overlay_region))
997			{
998				if (YAHOO.util.Dom.isAncestor(this.overlay, selects[i]))
999				{
1000					continue;
1001				}
1002				else
1003				{
1004					YAHOO.util.Dom.setStyle(selects[i], "visibility", "hidden");
1005					this.hidden_selects.push(YAHOO.util.Dom.generateId(selects[i]));
1006				}
1007			}
1008		}
1009	}
1010};
1011
1012/**
1013* Un-hides any hidden selects
1014*/
1015vB_Select_Overlay_Handler.prototype.show = function()
1016{
1017	if (this.browser_affected)
1018	{
1019		var selectid;
1020		while (selectid = this.hidden_selects.pop())
1021		{
1022			YAHOO.util.Dom.setStyle(selectid, "visibility", "visible");
1023		}
1024	}
1025};
1026
1027// #############################################################################
1028// Window openers and instant messenger wrappers
1029
1030/**
1031* Opens a generic browser window
1032*
1033* @param	string	URL
1034* @param	integer	Width
1035* @param	integer	Height
1036* @param	string	Optional Window ID
1037*/
1038function openWindow(url, width, height, windowid)
1039{
1040	return window.open(
1041		url,
1042		(typeof windowid == 'undefined' ? 'vBPopup' : windowid),
1043		'statusbar=no,menubar=no,toolbar=no,scrollbars=yes,resizable=yes'
1044		+ (typeof width != 'undefined' ? (',width=' + width) : '') + (typeof height != 'undefined' ? (',height=' + height) : '')
1045	);
1046}
1047
1048/**
1049* Opens control panel help window
1050*
1051* @param	string	Script name
1052* @param	string	Action type
1053* @param	string	Option value
1054*
1055* @return	window
1056*/
1057function js_open_help(scriptname, actiontype, optionval)
1058{
1059	return openWindow(
1060		'help.php?s=' + SESSIONHASH + '&do=answer&page=' + scriptname + '&pageaction=' + actiontype + '&option=' + optionval,
1061		600, 450, 'helpwindow'
1062	);
1063}
1064
1065/**
1066* Opens a window to show a list of attachments in a thread (misc.php?do=showattachments)
1067*
1068* @param	integer	Thread ID
1069*
1070* @return	window
1071*/
1072function attachments(threadid)
1073{
1074	return openWindow(
1075		'misc.php?' + SESSIONURL + 'do=showattachments&t=' + threadid,
1076		480, 300
1077	);
1078}
1079
1080/**
1081* Opens a window to show a list of posters in a thread (misc.php?do=whoposted)
1082*
1083* @param	integer	Thread ID
1084*
1085* @return	window
1086*/
1087function who(threadid)
1088{
1089	return openWindow(
1090		'misc.php?' + SESSIONURL + 'do=whoposted&t=' + threadid,
1091		230, 300
1092	);
1093}
1094
1095/**
1096* Opens an IM Window
1097*
1098* @param	string	IM type
1099* @param	integer	User ID
1100* @param	integer	Width of window
1101* @param	integer	Height of window
1102*
1103* @return	window
1104*/
1105function imwindow(imtype, userid, width, height)
1106{
1107	return openWindow(
1108		'sendmessage.php?' + SESSIONURL + 'do=im&type=' + imtype + '&u=' + userid,
1109		width, height
1110	);
1111}
1112
1113/**
1114* Sends an MSN message
1115*
1116* @param	string	Target MSN handle
1117*
1118* @return	boolean	false
1119*/
1120function SendMSNMessage(name)
1121{
1122	if (!is_ie)
1123	{
1124		alert(vbphrase['msn_functions_only_work_in_ie']);
1125	}
1126	else
1127	{
1128		try
1129		{
1130			MsgrObj.InstantMessage(name);
1131		}
1132		catch(e)
1133		{
1134			alert(vbphrase['msn_functions_only_work_in_ie']);
1135		}
1136	}
1137
1138	return false;
1139}
1140
1141/**
1142* Adds an MSN Contact (requires MSN)
1143*
1144* @param	string	MSN handle
1145*
1146* @return	boolean	false
1147*/
1148function AddMSNContact(name)
1149{
1150	if (!is_ie)
1151	{
1152		alert(vbphrase['msn_functions_only_work_in_ie']);
1153	}
1154	else
1155	{
1156		try
1157		{
1158			MsgrObj.AddContact(0, name);
1159		}
1160		catch(e)
1161		{
1162			alert(vbphrase['msn_functions_only_work_in_ie']);
1163		}
1164	}
1165
1166	return false;
1167}
1168
1169/**
1170* Detects Caps-Lock when a key is pressed
1171*
1172* @param	event
1173*
1174* @return	boolean	True if Caps-Lock is on
1175*/
1176function detect_caps_lock(e)
1177{
1178	e = (e ? e : window.event);
1179
1180	var keycode = (e.which ? e.which : (e.keyCode ? e.keyCode : (e.charCode ? e.charCode : 0)));
1181	var shifted = (e.shiftKey || (e.modifiers && (e.modifiers & 4)));
1182	var ctrled = (e.ctrlKey || (e.modifiers && (e.modifiers & 2)));
1183
1184	// if characters are uppercase without shift, or lowercase with shift, caps-lock is on.
1185	return (keycode >= 65 && keycode <= 90 && !shifted && !ctrled) || (keycode >= 97 && keycode <= 122 && shifted);
1186}
1187
1188/**
1189* Confirms log-out request
1190*
1191* @param	string	Log-out confirmation message
1192*
1193* @return	boolean
1194*/
1195function log_out(confirmation_message)
1196{
1197	var ht = document.getElementsByTagName("html")[0];
1198	ht.style.filter = "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)";
1199	if (confirm(confirmation_message))
1200	{
1201		return true;
1202	}
1203	else
1204	{
1205		ht.style.filter = "";
1206		return false;
1207	}
1208}
1209
1210// #############################################################################
1211// Cookie handlers
1212
1213/**
1214* Sets a cookie
1215*
1216* @param	string	Cookie name
1217* @param	string	Cookie value
1218* @param	date	Cookie expiry date
1219*/
1220function set_cookie(name, value, expires)
1221{
1222	console.log("Set Cookie :: %s = '%s'", name, value);
1223	document.cookie = name + '=' + escape(value) + '; path=/' + (typeof expires != 'undefined' ? '; expires=' + expires.toGMTString() : '');
1224}
1225
1226/**
1227* Deletes a cookie
1228*
1229* @param	string	Cookie name
1230*/
1231function delete_cookie(name)
1232{
1233	console.log("Delete Cookie :: %s", name);
1234	document.cookie = name + '=' + '; expires=Thu, 01-Jan-70 00:00:01 GMT' +  '; path=/';
1235}
1236
1237/**
1238* Fetches the value of a cookie
1239*
1240* @param	string	Cookie name
1241*
1242* @return	string
1243*/
1244function fetch_cookie(name)
1245{
1246	cookie_name = name + '=';
1247	cookie_length = document.cookie.length;
1248	cookie_begin = 0;
1249	while (cookie_begin < cookie_length)
1250	{
1251		value_begin = cookie_begin + cookie_name.length;
1252		if (document.cookie.substring(cookie_begin, value_begin) == cookie_name)
1253		{
1254			var value_end = document.cookie.indexOf (';', value_begin);
1255			if (value_end == -1)
1256			{
1257				value_end = cookie_length;
1258			}
1259			var cookie_value = unescape(document.cookie.substring(value_begin, value_end));
1260			console.log("Fetch Cookie :: %s = '%s'", name, cookie_value);
1261			return cookie_value;
1262		}
1263		cookie_begin = document.cookie.indexOf(' ', cookie_begin) + 1;
1264		if (cookie_begin == 0)
1265		{
1266			break;
1267		}
1268	}
1269	console.log("Fetch Cookie :: %s (null)", name);
1270	return null;
1271}
1272
1273// #############################################################################
1274// Form element managers (used for 'check all' type systems)
1275
1276/**
1277* Sets all checkboxes, radio buttons or selects in a given form to a given state, with exceptions
1278*
1279* @param	object	Form object
1280* @param	string	Target element type (one of 'radio', 'select-one', 'checkbox')
1281* @param	string	Selected option in case of 'radio'
1282* @param	array	Array of element names to be excluded
1283* @param	mixed	Value to give to found elements
1284*/
1285function js_toggle_all(formobj, formtype, option, exclude, setto)
1286{
1287	for (var i =0; i < formobj.elements.length; i++)
1288	{
1289		var elm = formobj.elements[i];
1290		if (elm.type == formtype && PHP.in_array(elm.name, exclude, false) == -1)
1291		{
1292			switch (formtype)
1293			{
1294				case 'radio':
1295					if (elm.value == option) // option == '' evaluates true when option = 0
1296					{
1297						elm.checked = setto;
1298					}
1299				break;
1300				case 'select-one':
1301					elm.selectedIndex = setto;
1302				break;
1303				default:
1304					elm.checked = setto;
1305				break;
1306			}
1307		}
1308	}
1309}
1310
1311/**
1312* Sets all <select> elements to the selectedIndex specified by the 'selectall' element
1313*
1314* @param	object	Form object
1315*/
1316function js_select_all(formobj)
1317{
1318	exclude = new Array();
1319	exclude[0] = 'selectall';
1320	js_toggle_all(formobj, 'select-one', '', exclude, formobj.selectall.selectedIndex);
1321}
1322
1323/**
1324* Sets all <input type="checkbox" /> elements to have the same checked status as 'allbox'
1325*
1326* @param	object	Form object
1327*/
1328function js_check_all(formobj)
1329{
1330	exclude = new Array();
1331	exclude[0] = 'keepattachments';
1332	exclude[1] = 'allbox';
1333	exclude[2] = 'removeall';
1334	js_toggle_all(formobj, 'checkbox', '', exclude, formobj.allbox.checked);
1335}
1336
1337/**
1338* Sets all <input type="radio" /> groups to have a particular option checked
1339*
1340* @param	object	Form object
1341* @param	mixed	Selected option
1342*/
1343function js_check_all_option(formobj, option)
1344{
1345	exclude = new Array();
1346	exclude[0] = 'useusergroup';
1347	js_toggle_all(formobj, 'radio', option, exclude, true);
1348}
1349
1350/**
1351* Alias to js_check_all
1352*/
1353function checkall(formobj)
1354{
1355	js_check_all(formobj);
1356}
1357
1358/**
1359* Alias to js_check_all_option
1360*/
1361function checkall_option(formobj, option)
1362{
1363	js_check_all_option(formobj, option);
1364}
1365
1366/**
1367* Resize function for CP textareas
1368*
1369* @param	integer	If positive, size up, otherwise size down
1370* @param	string	ID of the textarea
1371*
1372* @return	boolean	false
1373*/
1374function resize_textarea(to, id)
1375{
1376	var textarea = fetch_object(id);
1377
1378	textarea.style.width = parseInt(textarea.offsetWidth) + (to < 0 ? -100 : 100) + "px";
1379	textarea.style.height = parseInt(textarea.offsetHeight) + (to < 0 ? -100 : 100) + "px";
1380
1381	return false;
1382}
1383
1384/**
1385* Determines if two HTML objects intersect
1386*
1387* @param	object	1st HTML object
1388* @param	object	2nd HTML object
1389*
1390* @return	boolean	True if intersection is found
1391*/
1392function region_intersects(obj1, obj2)
1393{
1394	obj1 = typeof(obj1.left) == "undefined" ? YAHOO.util.Dom.getRegion(obj1) : obj1;
1395	obj2 = typeof(obj2.left) == "undefined" ? YAHOO.util.Dom.getRegion(obj2) : obj2;
1396
1397	return (obj1.left > obj2.right || obj1.right < obj2.left || obj1.top > obj2.bottom || obj1.bottom < obj2.top) ? false : true;
1398}
1399
1400/**
1401* Fetch information about the current browser viewport
1402*
1403* @return	array	Contains x, y, w, h elements
1404*/
1405function fetch_viewport_info()
1406{
1407	if (viewport_info == null)
1408	{
1409		viewport_info = {
1410			x : YAHOO.util.Dom.getDocumentScrollLeft(),
1411			y : YAHOO.util.Dom.getDocumentScrollTop(),
1412			w : YAHOO.util.Dom.getViewportWidth(),
1413			h : YAHOO.util.Dom.getViewportHeight()
1414		};
1415
1416		console.info("Viewport Info: Size = %dx%d, Position = %d,%d", viewport_info['w'], viewport_info['h'], viewport_info['x'], viewport_info['y']);
1417	}
1418
1419	return viewport_info;
1420}
1421
1422/**
1423* Clear cached viewport info
1424*/
1425function clear_viewport_info()
1426{
1427	viewport_info = null;
1428}
1429
1430/**
1431* Position an element in the middle of the browser window
1432* Note that this will only work if it is called AFTER an element is part of the DOM tree and has its full size
1433*
1434* @param	object	HTML element to be positioned
1435*/
1436function center_element(el)
1437{
1438	viewport_info = fetch_viewport_info();
1439
1440	YAHOO.util.Dom.setXY(el, [
1441		viewport_info['w'] / 2 + viewport_info['x'] - el.clientWidth / 2,
1442		viewport_info['h'] / 2 + viewport_info['y'] - el.clientHeight / 2
1443	]);
1444}
1445
1446/* Parses a stylesheet to find all rules within, including those fetched with @import
1447*
1448* @param	object	Usually document.styleSheets
1449*
1450* @return	array
1451*/
1452function fetch_all_stylesheets(sheets)
1453{
1454	var all_sheets = new Array(),
1455		i = 0,
1456		current_sheet = null,
1457		current_rule = 0,
1458		current_import = 0;
1459
1460	for (i = 0; i < document.styleSheets.length; i++)
1461	{
1462		current_sheet = document.styleSheets[i];
1463
1464		all_sheets.push(current_sheet);
1465
1466		try
1467		{
1468			if (current_sheet.cssRules) // not IE
1469			{
1470				for (current_rule = 0; current_rule < current_sheet.cssRules.length; current_rule++)
1471				{
1472					if (current_sheet.cssRules[current_rule].styleSheet)
1473					{
1474						all_sheets.push(current_sheet.cssRules[current_rule].styleSheet);
1475					}
1476				}
1477			}
1478			else // IE
1479			{
1480				if (current_sheet.imports)
1481				{
1482					for (current_import = 0; current_import < current_sheet.imports.length; current_import++)
1483					{
1484						all_sheets.push(current_sheet.imports[current_import]);
1485					}
1486				}
1487			}
1488		}
1489		catch(e)
1490		{
1491			// trying to access a stylesheet outside the allowed domain
1492			all_sheets.pop();
1493			continue;
1494		}
1495	}
1496
1497	return all_sheets;
1498}
1499
1500/**
1501* Highlights the login box to make it obvious where to login.
1502*/
1503function highlight_login_box()
1504{
1505	var obj = fetch_object('navbar_username');
1506	var addclass = 'inlinemod';
1507	var i, timeout = 1600, flash_speed = 200;
1508
1509	if (obj)
1510	{
1511		obj.focus();
1512		obj.select();
1513
1514		for (i = 0; i < timeout; i += 2 * flash_speed)
1515		{
1516			window.setTimeout(function() { YAHOO.util.Dom.addClass(obj, addclass) }, i);
1517			window.setTimeout(function() { YAHOO.util.Dom.removeClass(obj, addclass) }, i + flash_speed);
1518		}
1519	}
1520
1521	return false;
1522}
1523
1524// #############################################################################
1525// Collapsible element handlers
1526
1527/**
1528* Toggles the collapse state of an object, and saves state to 'vbulletin_collapse' cookie
1529*
1530* @param	string	Unique ID for the collapse group
1531*
1532* @return	boolean	false
1533*/
1534function toggle_collapse(objid, forcestate)
1535{
1536	if (!is_regexp)
1537	{
1538		return false;
1539	}
1540
1541	var obj = fetch_object('collapseobj_' + objid);
1542	var img = fetch_object('collapseimg_' + objid);
1543	var cel = fetch_object('collapsecel_' + objid);
1544
1545	if (!obj)
1546	{
1547		// nothing to collapse!
1548		if (img)
1549		{
1550			// hide the clicky image if there is one
1551			img.style.display = 'none';
1552		}
1553		return false;
1554	}
1555
1556	if (obj.style.display == 'none' || 'open' == forcestate)
1557	{
1558		obj.style.display = '';
1559
1560		if (!forcestate)
1561		{
1562			save_collapsed(objid, false);
1563		}
1564
1565		if (img)
1566		{
1567			img_re = new RegExp("_collapsed\\.gif$");
1568			img.src = img.src.replace(img_re, '.gif');
1569		}
1570		if (cel)
1571		{
1572			cel_re = new RegExp("^(thead|tcat)(_collapsed)$");
1573			cel.className = cel.className.replace(cel_re, '$1');
1574		}
1575	}
1576	else if (obj.style.display != 'none' || 'closed' == forcestate)
1577	{
1578		obj.style.display = 'none';
1579
1580		if (!forcestate)
1581		{
1582			save_collapsed(objid, true);
1583		}
1584
1585		if (img)
1586		{
1587			img_re = new RegExp("\\.gif$");
1588			img.src = img.src.replace(img_re, '_collapsed.gif');
1589		}
1590		if (cel)
1591		{
1592			cel_re = new RegExp("^(thead|tcat)$");
1593			cel.className = cel.className.replace(cel_re, '$1_collapsed');
1594		}
1595	}
1596	return false;
1597}
1598
1599/**
1600* Updates vbulletin_collapse cookie with collapse preferences
1601*
1602* @param	string	Unique ID for the collapse group
1603* @param	boolean	Add a cookie
1604*/
1605function save_collapsed(objid, addcollapsed)
1606{
1607	var collapsed = fetch_cookie('vbulletin_collapse');
1608	var tmp = new Array();
1609
1610	if (collapsed != null)
1611	{
1612		collapsed = collapsed.split('\n');
1613
1614		for (var i in collapsed)
1615		{
1616			if (YAHOO.lang.hasOwnProperty(collapsed, i) && collapsed[i] != objid && collapsed[i] != '')
1617			{
1618				tmp[tmp.length] = collapsed[i];
1619			}
1620		}
1621	}
1622
1623	if (addcollapsed)
1624	{
1625		tmp[tmp.length] = objid;
1626	}
1627
1628	expires = new Date();
1629	expires.setTime(expires.getTime() + (1000 * 86400 * 365));
1630	set_cookie('vbulletin_collapse', tmp.join('\n'), expires);
1631}
1632
1633// #############################################################################
1634// Event Handlers for PageNav menus
1635
1636/**
1637* Class to handle pagenav events
1638*/
1639function vBpagenav()
1640{
1641}
1642
1643/**
1644* Handles clicks on pagenav menu control objects
1645*/
1646vBpagenav.prototype.controlobj_onclick = function(e)
1647{
1648	this._onclick(e);
1649	var inputs = fetch_tags(this.menu.menuobj, 'input');
1650	for (var i = 0; i < inputs.length; i++)
1651	{
1652		if (inputs[i].type == 'text')
1653		{
1654			inputs[i].focus();
1655			break;
1656		}
1657	}
1658};
1659
1660/**
1661* Submits the pagenav form... sort of
1662*/
1663vBpagenav.prototype.form_gotopage = function(e)
1664{
1665	if ((pagenum = parseInt(fetch_object('pagenav_itxt').value, 10)) > 0)
1666	{
1667		window.location = vBmenu.menus[vBmenu.activemenu].addr + '&page=' + pagenum;
1668	}
1669	return false;
1670};
1671
1672/**
1673* Handles clicks on the 'Go' button in pagenav popups
1674*/
1675vBpagenav.prototype.ibtn_onclick = function(e)
1676{
1677	return this.form.gotopage();
1678};
1679
1680/**
1681* Handles keypresses in the text input of pagenav popups
1682*/
1683vBpagenav.prototype.itxt_onkeypress = function(e)
1684{
1685	return ((e ? e : window.event).keyCode == 13 ? this.form.gotopage() : true);
1686};
1687
1688// #############################################################################
1689// DHTML Popup Menu Handling (complements vbulletin_menu.js)
1690
1691/**
1692* Wrapper for vBmenu.register
1693*
1694* @param	string	Control ID
1695* @param	boolean	No image (true)
1696* @param	boolean	Does nothing any more
1697*/
1698function vbmenu_register(controlid, noimage, datefield)
1699{
1700	if (typeof(vBmenu) == "object")
1701	{
1702		return vBmenu.register(controlid, noimage);
1703	}
1704	else
1705	{
1706		return false;
1707	}
1708}
1709
1710// #############################################################################
1711// Stuff that really doesn't fit anywhere else
1712
1713/**
1714* Converts an HTML string into a DOM node for use elsewhere
1715*
1716* Note: Only works reliably if the string is enclosed in an HTML element.
1717* eg: "<span>Hello, <strong>username</strong></span>" not "Hello, <strong>username</strong>"
1718*
1719* @param	string	HTML String to convert
1720*/
1721function string_to_node(html_string)
1722{
1723	var node_container = document.createElement("div");
1724	node_container.innerHTML = html_string;
1725
1726	var node = node_container.firstChild;
1727	while (node && node.nodeType != 1)
1728	{
1729		node = node.nextSibling;
1730	}
1731
1732	if (!node)
1733	{
1734		return node_container.firstChild.cloneNode(true);
1735	}
1736	else
1737	{
1738		return node.cloneNode(true);
1739	}
1740}
1741
1742/**
1743* Sets an element and all its children to be 'unselectable'
1744*
1745* @param	mixed	Object/Object ID to be made unselectable
1746*/
1747function set_unselectable(obj)
1748{
1749	obj = YAHOO.util.Dom.get(obj);
1750
1751	if (!is_ie4 && typeof obj.tagName != 'undefined')
1752	{
1753		if (obj.hasChildNodes())
1754		{
1755			for (var i = 0; i < obj.childNodes.length; i++)
1756			{
1757				set_unselectable(obj.childNodes[i]);
1758			}
1759		}
1760		obj.unselectable = 'on';
1761	}
1762}
1763
1764/**
1765* Fetches the sessionhash from the SESSIONURL variable
1766*
1767* @return	string
1768*/
1769function fetch_sessionhash()
1770{
1771	return (SESSIONURL == '' ? '' : SESSIONURL.substr(2, 32));
1772}
1773
1774/**
1775* Emulates the PHP version of vBulletin's construct_phrase() sprintf wrapper
1776*
1777* @param	string	String containing %1$s type replacement markers
1778* @param	string	First replacement
1779* @param	string	Nth replacement
1780*
1781* @return	string
1782*/
1783function construct_phrase()
1784{
1785	if (!arguments || arguments.length < 1 || !is_regexp)
1786	{
1787		return false;
1788	}
1789
1790	var args = arguments;
1791	var str = args[0];
1792	var re;
1793
1794	for (var i = 1; i < args.length; i++)
1795	{
1796		re = new RegExp("%" + i + "\\$s", 'gi');
1797		str = str.replace(re, args[i]);
1798	}
1799	return str;
1800}
1801
1802/**
1803* Handles the quick style/language options in the footer
1804*
1805* @param	object	Select object
1806* @param	string	Type (style or language)
1807*/
1808function switch_id(selectobj, type)
1809{
1810	var id = selectobj.options[selectobj.selectedIndex].value;
1811
1812	if (id == '')
1813	{
1814		return;
1815	}
1816
1817	var url = new String(window.location);
1818	var fragment = new String('');
1819
1820	// get rid of fragment
1821	url = url.split('#');
1822
1823	// deal with the fragment first
1824	if (url[1])
1825	{
1826		fragment = '#' + url[1];
1827	}
1828
1829	// deal with the main url
1830	url = url[0];
1831
1832	// remove id=x& from main bit
1833	if (url.indexOf(type + 'id=') != -1 && is_regexp)
1834	{
1835		var re = new RegExp(type + "id=\\d+&?");
1836		url = url.replace(re, '');
1837	}
1838
1839	// add the ? to the url if needed
1840	if (url.indexOf('?') == -1)
1841	{
1842		url += '?';
1843	}
1844	else
1845	{
1846		// make sure that we have a valid character to join our id bit
1847		lastchar = url.substr(url.length - 1);
1848		if (lastchar != '&' && lastchar != '?')
1849		{
1850			url += '&';
1851		}
1852	}
1853
1854	window.location = url + type + 'id=' + id + fragment;
1855}
1856
1857/**
1858* Finds all images within the specified element and sets their alt attribute as title
1859*
1860* @param	object	Containing element
1861*/
1862function child_img_alt_2_title(object)
1863{
1864	var imgs = object.getElementsByTagName("img");
1865	for (var i = 0; i < imgs.length; i++)
1866	{
1867		img_alt_2_title(imgs[i]);
1868	}
1869}
1870
1871/**
1872* Takes the 'alt' attribute for an image and attaches it to the 'title' attribute
1873*
1874* @param	object	Image object
1875*/
1876function img_alt_2_title(img)
1877{
1878	if (!img.title && img.alt != '')
1879	{
1880		img.title = img.alt;
1881	}
1882}
1883
1884
1885function do_securitytoken_replacement(newtoken)
1886{
1887	if (newtoken == '')
1888	{
1889		return;
1890	}
1891
1892	for (var formid = 0; formid < document.forms.length; formid++)
1893	{
1894		if (document.forms[formid].elements['securitytoken'] && document.forms[formid].elements['securitytoken'].value == SECURITYTOKEN)
1895		{
1896			document.forms[formid].elements['securitytoken'].value = newtoken;
1897		}
1898	}
1899	SECURITYTOKEN = newtoken;
1900	console.log("Securitytoken updated");
1901}
1902
1903function handle_securitytoken_response(ajax)
1904{
1905	console.log("Processing securitytoken update");
1906	if (ajax.responseXML && ajax.responseXML.getElementsByTagName("securitytoken").length)
1907	{
1908		var newtoken = ajax.responseXML.getElementsByTagName("securitytoken")[0].firstChild.nodeValue;
1909		do_securitytoken_replacement(newtoken);
1910		securitytoken_errors = 0;
1911	}
1912	else
1913	{
1914		handle_securitytoken_error(ajax);
1915	}
1916}
1917
1918function handle_securitytoken_error(ajax)
1919{
1920	console.log("Securitytoken Error");
1921	if (++securitytoken_errors == 3)
1922	{
1923		do_securitytoken_replacement('guest');
1924	}
1925}
1926
1927// 1 hour = 3,600,000ms
1928var securitytoken_timeout = window.setTimeout('replace_securitytoken()', 3600000);
1929var securitytoken_errors = 0;
1930
1931function replace_securitytoken()
1932{
1933	window.clearTimeout(securitytoken_timeout);
1934	if (AJAX_Compatible && SECURITYTOKEN != '' && SECURITYTOKEN != 'guest')
1935	{
1936		securitytoken_timeout = window.setTimeout('replace_securitytoken()', 3600000);
1937		YAHOO.util.Connect.asyncRequest("POST", "ajax.php", {
1938			success: handle_securitytoken_response,
1939			failure: handle_securitytoken_error,
1940			timeout: vB_Default_Timeout
1941		}, SESSIONURL + "securitytoken=" + SECURITYTOKEN + "&do=securitytoken");
1942	}
1943}
1944
1945// #############################################################################
1946// Initialize a Comment
1947
1948/**
1949* This function runs all the necessary Javascript code on a Comment
1950* after it has been loaded via AJAX. Don't use this method before a
1951* complete page load or you'll have problems.
1952*
1953* @param	object	Object containing postbits
1954*/
1955function Comment_Init(obj)
1956{
1957	if (typeof obj.id == "undefined")
1958	{
1959		return;
1960	}
1961
1962	var objectid = obj.id;
1963	if (isNaN(objectid))
1964	{
1965		var match = null;
1966		if (match = objectid.match(/(\d+)/))
1967		{
1968			objectid = match[0];
1969		}
1970	}
1971
1972	if (typeof inlineMod_comment != "undefined")
1973	{
1974		im_init(obj, inlineMod_comment);
1975	}
1976
1977	if (typeof vB_QuickEditor_Factory != "undefined")
1978	{
1979		if (typeof vB_QuickEditor_Factory.controls[objectid] == "undefined")
1980		{
1981			vB_QuickEditor_Factory.controls[objectid] = new vB_QuickEditor(objectid, vB_QuickEditor_Factory);
1982		}
1983		else
1984		{
1985			vB_QuickEditor_Factory.controls[objectid].init();
1986		}
1987	}
1988
1989	if (typeof vB_QuickLoader_Factory != "undefined")
1990	{
1991		vB_QuickLoader_Factory.controls[objectid] = new vB_QuickLoader(objectid, vB_QuickLoader_Factory);
1992	}
1993
1994	child_img_alt_2_title(obj);
1995}
1996
1997// #############################################################################
1998// Initialize a PostBit
1999
2000/**
2001* This function runs all the necessary Javascript code on a PostBit
2002* after it has been loaded via AJAX. Don't use this method before a
2003* complete page load or you'll have problems.
2004*
2005* @param	object	Object containing postbits
2006*/
2007function PostBit_Init(obj, postid)
2008{
2009	console.log("PostBit Init: %d", postid);
2010
2011	if (typeof vBmenu != 'undefined')
2012	{
2013		// init profile menu(s)
2014		var divs = fetch_tags(obj, 'div');
2015		for (var i = 0; i < divs.length; i++)
2016		{
2017			if (divs[i].id && divs[i].id.substr(0, 9) == 'postmenu_')
2018			{
2019				vBmenu.register(divs[i].id, true);
2020			}
2021		}
2022	}
2023
2024	if (typeof vB_QuickEditor != 'undefined')
2025	{
2026		// init quick edit controls
2027		vB_AJAX_QuickEdit_Init(obj);
2028	}
2029
2030	if (typeof vB_QuickReply != 'undefined')
2031	{
2032		// init quick reply button
2033		qr_init_buttons(obj);
2034	}
2035
2036	if (typeof mq_init != 'undefined')
2037	{
2038		// init quick reply button
2039		mq_init(obj);
2040	}
2041
2042	if (typeof vBrep != 'undefined')
2043	{
2044		if (typeof postid != 'undefined' && typeof postid != 'null')
2045		{
2046			vbrep_register(postid);
2047		}
2048	}
2049
2050	if (typeof inlineMod != 'undefined')
2051	{
2052		im_init(obj);
2053	}
2054
2055	if (typeof vB_Lightbox != 'undefined')
2056	{
2057		init_postbit_lightbox(obj, false, true);
2058	}
2059
2060	child_img_alt_2_title(obj);
2061}
2062
2063// #############################################################################
2064// Main vBulletin Javascript Initialization
2065
2066/**
2067* This function runs (almost) at the end of script loading on most vBulletin pages
2068*
2069* It sets up things like image alt->title tags, turns on the popup menu system etc.
2070*
2071* @return	boolean
2072*/
2073function vBulletin_init()
2074{
2075	// don't bother doing any exciting stuff for WebTV
2076	if (is_webtv)
2077	{
2078		return false;
2079	}
2080
2081	// set 'title' tags for image elements
2082	child_img_alt_2_title(document);
2083
2084	// finalize popup menus
2085	if (typeof vBmenu == 'object')
2086	{
2087		// close all menus on document click or resize
2088		if (typeof(YAHOO) != "undefined")
2089		{
2090			YAHOO.util.Event.on(document, "click", vbmenu_hide);
2091			YAHOO.util.Event.on(window, "resize", vbmenu_hide);
2092		}
2093		else if (window.attachEvent && !is_saf)
2094		{
2095			document.attachEvent('onclick', vbmenu_hide);
2096			window.attachEvent('onresize', vbmenu_hide);
2097		}
2098		else if (document.addEventListener && !is_saf)
2099		{
2100			document.addEventListener('click', vbmenu_hide, false);
2101			window.addEventListener('resize', vbmenu_hide, false);
2102		}
2103		else
2104		{
2105			window.onclick = vbmenu_hide;
2106			window.onresize = vbmenu_hide;
2107		}
2108
2109		// add popups to pagenav elements
2110		var pagenavs = fetch_tags(document, 'td');
2111		for (var n = 0; n < pagenavs.length; n++)
2112		{
2113			if (pagenavs[n].hasChildNodes() && pagenavs[n].firstChild.name && pagenavs[n].firstChild.name.indexOf('PageNav') != -1)
2114			{
2115				var addr = pagenavs[n].title;
2116				pagenavs[n].title = '';
2117				pagenavs[n].innerHTML = '';
2118				pagenavs[n].id = 'pagenav.' + n;
2119				var pn = vBmenu.register(pagenavs[n].id);
2120				pn.addr = addr;
2121
2122				if (is_saf)
2123				{
2124					pn.controlobj._onclick = pn.controlobj.onclick;
2125					pn.controlobj.onclick = vBpagenav.prototype.controlobj_onclick;
2126				}
2127			}
2128		}
2129
2130		// process the pagenavs popup form
2131		if (typeof addr != 'undefined')
2132		{
2133			fetch_object('pagenav_form').gotopage = vBpagenav.prototype.form_gotopage;
2134			fetch_object('pagenav_ibtn').onclick = vBpagenav.prototype.ibtn_onclick;
2135			fetch_object('pagenav_itxt').onkeypress = vBpagenav.prototype.itxt_onkeypress;
2136		}
2137
2138		// activate the menu system
2139		vBmenu.activate(true);
2140	}
2141
2142	// the new init system
2143	vBulletin.init();
2144
2145	return true;
2146}
2147
2148// #############################################################################
2149// vBulletin Javascript Framework
2150
2151/**
2152* General class for handling custom events and custom controls
2153*/
2154function vBulletin_Framework()
2155{
2156	/**
2157	* @var	array	Array of elements to be passed to control init functions
2158	* @var	array	Array of AJAX load/save URLs
2159	* @var	array	Array of YUI custom events
2160	* @var	date	Current time
2161	*/
2162	this.elements = new Array();
2163	this.ajaxurls = new Array();
2164	this.events = new Array();
2165	this.time = new Date();
2166
2167	// custom event to fire during class init
2168	this.add_event("systemInit");
2169}
2170
2171/**
2172* Initializes the object - usually called at end of footer template
2173*/
2174vBulletin_Framework.prototype.init = function()
2175{
2176	console.info("Firing System Init");
2177	this.events.systemInit.fire();
2178}
2179
2180/**
2181* Emulates OOP class extension
2182*
2183* @param	object	Extended class
2184* @param	object	Base class
2185*/
2186vBulletin_Framework.prototype.extend = function(subClass, baseClass)
2187{
2188   function inheritance() {}
2189   inheritance.prototype = baseClass.prototype;
2190
2191   subClass.prototype = new inheritance();
2192   subClass.prototype.constructor = subClass;
2193   subClass.baseConstructor = baseClass;
2194   subClass.superClass = baseClass.prototype;
2195}
2196
2197/**
2198* Registers a custom control for later initialization
2199* Arguments 1-n are stored for later use
2200*
2201* @param	string	Control type (vB_DatePicker etc.)
2202* @param	string	HTML element ID
2203*/
2204vBulletin_Framework.prototype.register_control = function(controltype, element)
2205{
2206	var args = new Array();
2207	for (var i = 1; i < arguments.length; i++)
2208	{
2209		args.push(arguments[i]);
2210	}
2211	if (!this.elements[controltype])
2212	{
2213		console.info("Creating array vBulletin.elements[\"%s\"]", controltype);
2214		this.elements[controltype] = new Array();
2215	}
2216	var x = this.elements[controltype].push(args);
2217	console.log("vBulletin.elements[\"%s\"][%d] = %s", controltype, x-1, args.join(", "));
2218}
2219
2220/**
2221* Registers AJAX load/save urls for a control
2222*
2223* @param	Fetch URL
2224* @param	Save URL
2225* @param	List of elements to which these URLs apply
2226*/
2227vBulletin_Framework.prototype.register_ajax_urls = function(fetch, save, elements)
2228{
2229	fetch = fetch.split("?"); fetch[1] = SESSIONURL + "securitytoken=" + SECURITYTOKEN + "&ajax=1&" + fetch[1].replace(/\{(\d+)(:\w+)?\}/gi, '%$1$s');
2230	save  =  save.split("?");  save[1] = SESSIONURL + "securitytoken=" + SECURITYTOKEN + "&ajax=1&" + save[1].replace(/\{(\d+)(:\w+)?\}/gi, '%$1$s');
2231
2232	console.log("Register AJAX URLs for %s", elements);
2233
2234	for (var i = 0; i < elements.length; i++)
2235	{
2236		this.ajaxurls[elements[i]] = new Array(fetch, save);
2237	}
2238}
2239
2240/**
2241* Register a custom event
2242*
2243* @param	string	Event name
2244*/
2245vBulletin_Framework.prototype.add_event = function(eventname)
2246{
2247	this.events[eventname] = new YAHOO.util.CustomEvent(eventname);
2248}
2249
2250/**
2251* BC: Pass console calls to Firebug if it's available
2252*/
2253//vBulletin_Framework.prototype.console = console.log;
2254vBulletin_Framework.prototype.console = function()
2255{
2256	if (window.console || console.firebug)
2257	{
2258		var args = new Array();
2259		for (var i = 0; i < arguments.length; i++)
2260		{
2261			args[args.length] = arguments[i];
2262		}
2263
2264		try
2265		{
2266			eval("console.log('" + args.join("','") + "');");
2267		}
2268		catch(e) {}
2269	}
2270}
2271
2272// #############################################################################
2273
2274// initialize the PHP function emulator
2275var PHP = new vB_PHP_Emulator();
2276
2277// Create an instance of the vBulletin Framework object
2278var vBulletin = new vBulletin_Framework();
2279
2280vBulletin.events.systemInit.subscribe(function()
2281{
2282	YAHOO.util.Event.on(window, "resize", clear_viewport_info);
2283	YAHOO.util.Event.on(window, "scroll", clear_viewport_info)
2284});
2285
2286// #############################################################################
2287// Functions for dismissing dismissible notices
2288function handle_dismiss_notice_error(ajax)
2289{
2290	if (ajax.argument)
2291	{
2292		var nodeDismissID = YAHOO.util.Dom.get("dismiss_notice_hidden");
2293		nodeDismissID.value = ajax.argument;
2294		var nodeForm = YAHOO.util.Dom.get("notices");
2295		nodeForm.submit();
2296	}
2297}
2298
2299function handle_dismiss_notice_ajax(ajax)
2300{
2301	if (ajax.responseXML && ajax.responseXML.getElementsByTagName("dismissed").length)
2302	{
2303		var dismissed = ajax.responseXML.getElementsByTagName("dismissed")[0].firstChild.nodeValue;
2304		var nodeNotice = YAHOO.util.Dom.get("navbar_notice_" + dismissed);
2305		if (nodeNotice != null)
2306		{
2307			nodeNotice.style.display = "none";
2308			var nodeNotices = YAHOO.util.Dom.getElementsByClassName("navbar_notice", "", YAHOO.util.Dom.get("notices"));
2309			var showing = 0;
2310			for (i = 0; i < nodeNotices.length; i++)
2311			{
2312				if (nodeNotices[i].style.display != "none")
2313				{
2314					showing++;
2315				}
2316			}
2317			if (showing == 0)
2318			{
2319				var nodeNoticeTable = YAHOO.util.Dom.get("notices");
2320				if (nodeNoticeTable != null)
2321				{
2322					// hide the table if no more notices left
2323					nodeNoticeTable.style.display = "none";
2324				}
2325			}
2326		}
2327	}
2328	else
2329	{
2330		handle_dismiss_notice_error(ajax);
2331	}
2332}
2333
2334/**
2335* @param	int	integer value of noticeid
2336*
2337* returns false, to disable link for js compatible browsers, when AJAX enabled or browser support it
2338* returns true, to actually submit the form, when AJAX disabled or browser does not support it
2339*/
2340function dismiss_notice(noticeid)
2341{
2342	if (AJAX_Compatible)
2343	{
2344		var ajax_req = YAHOO.util.Connect.asyncRequest("POST", "ajax.php?do=dismissnotice", {
2345			success: handle_dismiss_notice_ajax,
2346			failure: handle_dismiss_notice_error,
2347			timeout: vB_Default_Timeout,
2348			argument: noticeid
2349		}, SESSIONURL + "securitytoken=" + SECURITYTOKEN + "&do=dismissnotice&noticeid=" + PHP.urlencode(noticeid));
2350		return false;
2351	}
2352	return true;
2353}
2354
2355/*======================================================================*\
2356|| ####################################################################
2357|| # NulleD - FintMax
2358|| # CVS: $RCSfile$ - $Revision: 29350 $
2359|| ####################################################################
2360\*======================================================================*/
2361
2362}
2363

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.