script.js 55 KB

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