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