Chris@76: var smf_formSubmitted = false; Chris@76: var lastKeepAliveCheck = new Date().getTime(); Chris@76: var smf_editorArray = new Array(); Chris@76: Chris@76: // Some very basic browser detection - from Mozilla's sniffer page. Chris@76: var ua = navigator.userAgent.toLowerCase(); Chris@76: Chris@76: var is_opera = ua.indexOf('opera') != -1; Chris@76: var is_opera5 = ua.indexOf('opera/5') != -1 || ua.indexOf('opera 5') != -1; Chris@76: var is_opera6 = ua.indexOf('opera/6') != -1 || ua.indexOf('opera 6') != -1; Chris@76: var is_opera7 = ua.indexOf('opera/7') != -1 || ua.indexOf('opera 7') != -1; Chris@76: var is_opera8 = ua.indexOf('opera/8') != -1 || ua.indexOf('opera 8') != -1; Chris@76: var is_opera9 = ua.indexOf('opera/9') != -1 || ua.indexOf('opera 9') != -1; Chris@76: var is_opera95 = ua.indexOf('opera/9.5') != -1 || ua.indexOf('opera 9.5') != -1; Chris@76: var is_opera96 = ua.indexOf('opera/9.6') != -1 || ua.indexOf('opera 9.6') != -1; Chris@76: var 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; Chris@76: var is_opera95up = is_opera95 || is_opera96 || is_opera10; Chris@76: Chris@76: 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; Chris@76: var is_gecko = ua.indexOf('gecko') != -1 && !is_opera; Chris@76: Chris@76: var is_chrome = ua.indexOf('chrome') != -1; Chris@76: var is_safari = ua.indexOf('applewebkit') != -1 && !is_chrome; Chris@76: var is_webkit = ua.indexOf('applewebkit') != -1; Chris@76: Chris@76: var is_ie = ua.indexOf('msie') != -1 && !is_opera; Chris@76: var is_ie4 = is_ie && ua.indexOf('msie 4') != -1; Chris@76: var is_ie5 = is_ie && ua.indexOf('msie 5') != -1; Chris@76: var is_ie50 = is_ie && ua.indexOf('msie 5.0') != -1; Chris@76: var is_ie55 = is_ie && ua.indexOf('msie 5.5') != -1; Chris@76: var is_ie5up = is_ie && !is_ie4; Chris@76: var is_ie6 = is_ie && ua.indexOf('msie 6') != -1; Chris@76: var is_ie6up = is_ie5up && !is_ie55 && !is_ie5; Chris@76: var is_ie6down = is_ie6 || is_ie5 || is_ie4; Chris@76: var is_ie7 = is_ie && ua.indexOf('msie 7') != -1; Chris@76: var is_ie7up = is_ie6up && !is_ie6; Chris@76: var is_ie7down = is_ie7 || is_ie6 || is_ie5 || is_ie4; Chris@76: Chris@76: var is_ie8 = is_ie && ua.indexOf('msie 8') != -1; Chris@76: var is_ie8up = is_ie8 && !is_ie7down; Chris@76: Chris@76: var is_iphone = ua.indexOf('iphone') != -1 || ua.indexOf('ipod') != -1; Chris@76: var is_android = ua.indexOf('android') != -1; Chris@76: Chris@76: var ajax_indicator_ele = null; Chris@76: Chris@76: // Define document.getElementById for Internet Explorer 4. Chris@76: if (!('getElementById' in document) && 'all' in document) Chris@76: document.getElementById = function (sId) { Chris@76: return document.all[sId]; Chris@76: } Chris@76: Chris@76: // Define XMLHttpRequest for IE 5 and above. (don't bother for IE 4 :/.... works in Opera 7.6 and Safari 1.2!) Chris@76: else if (!('XMLHttpRequest' in window) && 'ActiveXObject' in window) Chris@76: window.XMLHttpRequest = function () { Chris@76: return new ActiveXObject(is_ie5 ? 'Microsoft.XMLHTTP' : 'MSXML2.XMLHTTP'); Chris@76: }; Chris@76: Chris@76: // Ensure the getElementsByTagName exists. Chris@76: if (!'getElementsByTagName' in document && 'all' in document) Chris@76: document.getElementsByTagName = function (sName) { Chris@76: return document.all.tags[sName]; Chris@76: } Chris@76: Chris@76: // Some older versions of Mozilla don't have this, for some reason. Chris@76: if (!('forms' in document)) Chris@76: document.forms = document.getElementsByTagName('form'); Chris@76: Chris@76: // Load an XML document using XMLHttpRequest. Chris@76: function getXMLDocument(sUrl, funcCallback) Chris@76: { Chris@76: if (!window.XMLHttpRequest) Chris@76: return null; Chris@76: Chris@76: var oMyDoc = new XMLHttpRequest(); Chris@76: var bAsync = typeof(funcCallback) != 'undefined'; Chris@76: var oCaller = this; Chris@76: if (bAsync) Chris@76: { Chris@76: oMyDoc.onreadystatechange = function () { Chris@76: if (oMyDoc.readyState != 4) Chris@76: return; Chris@76: Chris@76: if (oMyDoc.responseXML != null && oMyDoc.status == 200) Chris@76: { Chris@76: if (funcCallback.call) Chris@76: { Chris@76: funcCallback.call(oCaller, oMyDoc.responseXML); Chris@76: } Chris@76: // A primitive substitute for the call method to support IE 5.0. Chris@76: else Chris@76: { Chris@76: oCaller.tmpMethod = funcCallback; Chris@76: oCaller.tmpMethod(oMyDoc.responseXML); Chris@76: delete oCaller.tmpMethod; Chris@76: } Chris@76: } Chris@76: }; Chris@76: } Chris@76: oMyDoc.open('GET', sUrl, bAsync); Chris@76: oMyDoc.send(null); Chris@76: Chris@76: return oMyDoc; Chris@76: } Chris@76: Chris@76: // Send a post form to the server using XMLHttpRequest. Chris@76: function sendXMLDocument(sUrl, sContent, funcCallback) Chris@76: { Chris@76: if (!window.XMLHttpRequest) Chris@76: return false; Chris@76: Chris@76: var oSendDoc = new window.XMLHttpRequest(); Chris@76: var oCaller = this; Chris@76: if (typeof(funcCallback) != 'undefined') Chris@76: { Chris@76: oSendDoc.onreadystatechange = function () { Chris@76: if (oSendDoc.readyState != 4) Chris@76: return; Chris@76: Chris@76: if (oSendDoc.responseXML != null && oSendDoc.status == 200) Chris@76: funcCallback.call(oCaller, oSendDoc.responseXML); Chris@76: else Chris@76: funcCallback.call(oCaller, false); Chris@76: }; Chris@76: } Chris@76: oSendDoc.open('POST', sUrl, true); Chris@76: if ('setRequestHeader' in oSendDoc) Chris@76: oSendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); Chris@76: oSendDoc.send(sContent); Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: // A property we'll be needing for php_to8bit. Chris@76: String.prototype.oCharsetConversion = { Chris@76: from: '', Chris@76: to: '' Chris@76: }; Chris@76: Chris@76: // Convert a string to an 8 bit representation (like in PHP). Chris@76: String.prototype.php_to8bit = function () Chris@76: { Chris@76: if (smf_charset == 'UTF-8') Chris@76: { Chris@76: var n, sReturn = ''; Chris@76: Chris@76: for (var i = 0, iTextLen = this.length; i < iTextLen; i++) Chris@76: { Chris@76: n = this.charCodeAt(i); Chris@76: if (n < 128) Chris@76: sReturn += String.fromCharCode(n) Chris@76: else if (n < 2048) Chris@76: sReturn += String.fromCharCode(192 | n >> 6) + String.fromCharCode(128 | n & 63); Chris@76: else if (n < 65536) Chris@76: sReturn += String.fromCharCode(224 | n >> 12) + String.fromCharCode(128 | n >> 6 & 63) + String.fromCharCode(128 | n & 63); Chris@76: else Chris@76: sReturn += String.fromCharCode(240 | n >> 18) + String.fromCharCode(128 | n >> 12 & 63) + String.fromCharCode(128 | n >> 6 & 63) + String.fromCharCode(128 | n & 63); Chris@76: } Chris@76: Chris@76: return sReturn; Chris@76: } Chris@76: Chris@76: else if (this.oCharsetConversion.from.length == 0) Chris@76: { Chris@76: switch (smf_charset) Chris@76: { Chris@76: case 'ISO-8859-1': Chris@76: this.oCharsetConversion = { Chris@76: from: '\xa0-\xff', Chris@76: to: '\xa0-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'ISO-8859-2': Chris@76: this.oCharsetConversion = { Chris@76: 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', Chris@76: to: '\xa0-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'ISO-8859-5': Chris@76: this.oCharsetConversion = { Chris@76: from: '\xa0\u0401-\u040c\xad\u040e-\u044f\u2116\u0451-\u045c\xa7\u045e\u045f', Chris@76: to: '\xa0-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'ISO-8859-9': Chris@76: this.oCharsetConversion = { Chris@76: from: '\xa0-\xcf\u011e\xd1-\xdc\u0130\u015e\xdf-\xef\u011f\xf1-\xfc\u0131\u015f\xff', Chris@76: to: '\xa0-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'ISO-8859-15': Chris@76: this.oCharsetConversion = { Chris@76: from: '\xa0-\xa3\u20ac\xa5\u0160\xa7\u0161\xa9-\xb3\u017d\xb5-\xb7\u017e\xb9-\xbb\u0152\u0153\u0178\xbf-\xff', Chris@76: to: '\xa0-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'tis-620': Chris@76: this.oCharsetConversion = { Chris@76: from: '\u20ac\u2026\u2018\u2019\u201c\u201d\u2022\u2013\u2014\xa0\u0e01-\u0e3a\u0e3f-\u0e5b', Chris@76: to: '\x80\x85\x91-\x97\xa0-\xda\xdf-\xfb' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'windows-1251': Chris@76: this.oCharsetConversion = { Chris@76: 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', Chris@76: to: '\x80-\x97\x99-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'windows-1253': Chris@76: this.oCharsetConversion = { Chris@76: 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', Chris@76: to: '\x80\x82-\x87\x89\x8b\x91-\x97\x99\x9b\xa0-\xa9\xab-\xd1\xd3-\xfe' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'windows-1255': Chris@76: this.oCharsetConversion = { Chris@76: 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', Chris@76: to: '\x80\x82-\x89\x8b\x91-\x99\x9b\xa0-\xc9\xcb-\xd8\xe0-\xfa\xfd\xfe' Chris@76: }; Chris@76: break; Chris@76: Chris@76: case 'windows-1256': Chris@76: this.oCharsetConversion = { Chris@76: 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', Chris@76: to: '\x80-\xff' Chris@76: }; Chris@76: break; Chris@76: Chris@76: default: Chris@76: this.oCharsetConversion = { Chris@76: from: '', Chris@76: to: '' Chris@76: }; Chris@76: break; Chris@76: } Chris@76: var funcExpandString = function (sSearch) { Chris@76: var sInsert = ''; Chris@76: for (var i = sSearch.charCodeAt(0), n = sSearch.charCodeAt(2); i <= n; i++) Chris@76: sInsert += String.fromCharCode(i); Chris@76: return sInsert; Chris@76: }; Chris@76: this.oCharsetConversion.from = this.oCharsetConversion.from.replace(/.\-./g, funcExpandString); Chris@76: this.oCharsetConversion.to = this.oCharsetConversion.to.replace(/.\-./g, funcExpandString); Chris@76: } Chris@76: Chris@76: var sReturn = '', iOffsetFrom = 0; Chris@76: for (var i = 0, n = this.length; i < n; i++) Chris@76: { Chris@76: iOffsetFrom = this.oCharsetConversion.from.indexOf(this.charAt(i)); Chris@76: sReturn += iOffsetFrom > -1 ? this.oCharsetConversion.to.charAt(iOffsetFrom) : (this.charCodeAt(i) > 127 ? '' + this.charCodeAt(i) + ';' : this.charAt(i)); Chris@76: } Chris@76: Chris@76: return sReturn Chris@76: } Chris@76: Chris@76: // Character-level replacement function. Chris@76: String.prototype.php_strtr = function (sFrom, sTo) Chris@76: { Chris@76: return this.replace(new RegExp('[' + sFrom + ']', 'g'), function (sMatch) { Chris@76: return sTo.charAt(sFrom.indexOf(sMatch)); Chris@76: }); Chris@76: } Chris@76: Chris@76: // Simulate PHP's strtolower (in SOME cases PHP uses ISO-8859-1 case folding). Chris@76: String.prototype.php_strtolower = function () Chris@76: { Chris@76: return typeof(smf_iso_case_folding) == 'boolean' && smf_iso_case_folding == true ? this.php_strtr( Chris@76: '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', Chris@76: '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' Chris@76: ) : this.php_strtr('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); Chris@76: } Chris@76: Chris@76: String.prototype.php_urlencode = function() Chris@76: { Chris@76: return escape(this).replace(/\+/g, '%2b').replace('*', '%2a').replace('/', '%2f').replace('@', '%40'); Chris@76: } Chris@76: Chris@76: String.prototype.php_htmlspecialchars = function() Chris@76: { Chris@76: return this.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); Chris@76: } Chris@76: Chris@76: String.prototype.php_unhtmlspecialchars = function() Chris@76: { Chris@76: return this.replace(/"/g, '"').replace(/>/g, '>').replace(/</g, '<').replace(/&/g, '&'); Chris@76: } Chris@76: Chris@76: String.prototype.php_addslashes = function() Chris@76: { Chris@76: return this.replace(/\\/g, '\\\\').replace(/'/g, '\\\''); Chris@76: } Chris@76: Chris@76: String.prototype._replaceEntities = function(sInput, sDummy, sNum) Chris@76: { Chris@76: return String.fromCharCode(parseInt(sNum)); Chris@76: } Chris@76: Chris@76: String.prototype.removeEntities = function() Chris@76: { Chris@76: return this.replace(/&(amp;)?#(\d+);/g, this._replaceEntities); Chris@76: } Chris@76: Chris@76: String.prototype.easyReplace = function (oReplacements) Chris@76: { Chris@76: var sResult = this; Chris@76: for (var sSearch in oReplacements) Chris@76: sResult = sResult.replace(new RegExp('%' + sSearch + '%', 'g'), oReplacements[sSearch]); Chris@76: Chris@76: return sResult; Chris@76: } Chris@76: Chris@76: Chris@76: // Open a new window. Chris@76: function reqWin(desktopURL, alternateWidth, alternateHeight, noScrollbars) Chris@76: { Chris@76: if ((alternateWidth && self.screen.availWidth * 0.8 < alternateWidth) || (alternateHeight && self.screen.availHeight * 0.8 < alternateHeight)) Chris@76: { Chris@76: noScrollbars = false; Chris@76: alternateWidth = Math.min(alternateWidth, self.screen.availWidth * 0.8); Chris@76: alternateHeight = Math.min(alternateHeight, self.screen.availHeight * 0.8); Chris@76: } Chris@76: else Chris@76: noScrollbars = typeof(noScrollbars) == 'boolean' && noScrollbars == true; Chris@76: Chris@76: 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'); Chris@76: Chris@76: // Return false so the click won't follow the link ;). Chris@76: return false; Chris@76: } Chris@76: Chris@76: // Remember the current position. Chris@76: function storeCaret(oTextHandle) Chris@76: { Chris@76: // Only bother if it will be useful. Chris@76: if ('createTextRange' in oTextHandle) Chris@76: oTextHandle.caretPos = document.selection.createRange().duplicate(); Chris@76: } Chris@76: Chris@76: // Replaces the currently selected text with the passed text. Chris@76: function replaceText(text, oTextHandle) Chris@76: { Chris@76: // Attempt to create a text range (IE). Chris@76: if ('caretPos' in oTextHandle && 'createTextRange' in oTextHandle) Chris@76: { Chris@76: var caretPos = oTextHandle.caretPos; Chris@76: Chris@76: caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text; Chris@76: caretPos.select(); Chris@76: } Chris@76: // Mozilla text range replace. Chris@76: else if ('selectionStart' in oTextHandle) Chris@76: { Chris@76: var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart); Chris@76: var end = oTextHandle.value.substr(oTextHandle.selectionEnd); Chris@76: var scrollPos = oTextHandle.scrollTop; Chris@76: Chris@76: oTextHandle.value = begin + text + end; Chris@76: Chris@76: if (oTextHandle.setSelectionRange) Chris@76: { Chris@76: oTextHandle.focus(); Chris@76: var goForward = is_opera ? text.match(/\n/g).length : 0; Chris@76: oTextHandle.setSelectionRange(begin.length + text.length + goForward, begin.length + text.length + goForward); Chris@76: } Chris@76: oTextHandle.scrollTop = scrollPos; Chris@76: } Chris@76: // Just put it on the end. Chris@76: else Chris@76: { Chris@76: oTextHandle.value += text; Chris@76: oTextHandle.focus(oTextHandle.value.length - 1); Chris@76: } Chris@76: } Chris@76: Chris@76: // Surrounds the selected text with text1 and text2. Chris@76: function surroundText(text1, text2, oTextHandle) Chris@76: { Chris@76: // Can a text range be created? Chris@76: if ('caretPos' in oTextHandle && 'createTextRange' in oTextHandle) Chris@76: { Chris@76: var caretPos = oTextHandle.caretPos, temp_length = caretPos.text.length; Chris@76: Chris@76: caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text1 + caretPos.text + text2 + ' ' : text1 + caretPos.text + text2; Chris@76: Chris@76: if (temp_length == 0) Chris@76: { Chris@76: caretPos.moveStart('character', -text2.length); Chris@76: caretPos.moveEnd('character', -text2.length); Chris@76: caretPos.select(); Chris@76: } Chris@76: else Chris@76: oTextHandle.focus(caretPos); Chris@76: } Chris@76: // Mozilla text range wrap. Chris@76: else if ('selectionStart' in oTextHandle) Chris@76: { Chris@76: var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart); Chris@76: var selection = oTextHandle.value.substr(oTextHandle.selectionStart, oTextHandle.selectionEnd - oTextHandle.selectionStart); Chris@76: var end = oTextHandle.value.substr(oTextHandle.selectionEnd); Chris@76: var newCursorPos = oTextHandle.selectionStart; Chris@76: var scrollPos = oTextHandle.scrollTop; Chris@76: Chris@76: oTextHandle.value = begin + text1 + selection + text2 + end; Chris@76: Chris@76: if (oTextHandle.setSelectionRange) Chris@76: { Chris@76: var goForward = is_opera ? text1.match(/\n/g).length : 0, goForwardAll = is_opera ? (text1 + text2).match(/\n/g).length : 0; Chris@76: if (selection.length == 0) Chris@76: oTextHandle.setSelectionRange(newCursorPos + text1.length + goForward, newCursorPos + text1.length + goForward); Chris@76: else Chris@76: oTextHandle.setSelectionRange(newCursorPos, newCursorPos + text1.length + selection.length + text2.length + goForwardAll); Chris@76: oTextHandle.focus(); Chris@76: } Chris@76: oTextHandle.scrollTop = scrollPos; Chris@76: } Chris@76: // Just put them on the end, then. Chris@76: else Chris@76: { Chris@76: oTextHandle.value += text1 + text2; Chris@76: oTextHandle.focus(oTextHandle.value.length - 1); Chris@76: } Chris@76: } Chris@76: Chris@76: // Checks if the passed input's value is nothing. Chris@76: function isEmptyText(theField) Chris@76: { Chris@76: // Copy the value so changes can be made.. Chris@76: var theValue = theField.value; Chris@76: Chris@76: // Strip whitespace off the left side. Chris@76: while (theValue.length > 0 && (theValue.charAt(0) == ' ' || theValue.charAt(0) == '\t')) Chris@76: theValue = theValue.substring(1, theValue.length); Chris@76: // Strip whitespace off the right side. Chris@76: while (theValue.length > 0 && (theValue.charAt(theValue.length - 1) == ' ' || theValue.charAt(theValue.length - 1) == '\t')) Chris@76: theValue = theValue.substring(0, theValue.length - 1); Chris@76: Chris@76: if (theValue == '') Chris@76: return true; Chris@76: else Chris@76: return false; Chris@76: } Chris@76: Chris@76: // Only allow form submission ONCE. Chris@76: function submitonce(theform) Chris@76: { Chris@76: smf_formSubmitted = true; Chris@76: Chris@76: // If there are any editors warn them submit is coming! Chris@76: for (var i = 0; i < smf_editorArray.length; i++) Chris@76: smf_editorArray[i].doSubmit(); Chris@76: } Chris@76: function submitThisOnce(oControl) Chris@76: { Chris@76: // Hateful, hateful fix for Safari 1.3 beta. Chris@76: if (is_safari) Chris@76: return !smf_formSubmitted; Chris@76: Chris@76: // oControl might also be a form. Chris@76: var oForm = 'form' in oControl ? oControl.form : oControl; Chris@76: Chris@76: var aTextareas = oForm.getElementsByTagName('textarea'); Chris@76: for (var i = 0, n = aTextareas.length; i < n; i++) Chris@76: aTextareas[i].readOnly = true; Chris@76: Chris@76: return !smf_formSubmitted; Chris@76: } Chris@76: Chris@76: // Deprecated, as innerHTML is supported everywhere. Chris@76: function setInnerHTML(oElement, sToValue) Chris@76: { Chris@76: oElement.innerHTML = sToValue; Chris@76: } Chris@76: Chris@76: function getInnerHTML(oElement) Chris@76: { Chris@76: return oElement.innerHTML; Chris@76: } Chris@76: Chris@76: // Set the "outer" HTML of an element. Chris@76: function setOuterHTML(oElement, sToValue) Chris@76: { Chris@76: if ('outerHTML' in oElement) Chris@76: oElement.outerHTML = sToValue; Chris@76: else Chris@76: { Chris@76: var range = document.createRange(); Chris@76: range.setStartBefore(oElement); Chris@76: oElement.parentNode.replaceChild(range.createContextualFragment(sToValue), oElement); Chris@76: } Chris@76: } Chris@76: Chris@76: // Checks for variable in theArray. Chris@76: function in_array(variable, theArray) Chris@76: { Chris@76: for (var i in theArray) Chris@76: if (theArray[i] == variable) Chris@76: return true; Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: // Checks for variable in theArray. Chris@76: function array_search(variable, theArray) Chris@76: { Chris@76: for (var i in theArray) Chris@76: if (theArray[i] == variable) Chris@76: return i; Chris@76: Chris@76: return null; Chris@76: } Chris@76: Chris@76: // Find a specific radio button in its group and select it. Chris@76: function selectRadioByName(oRadioGroup, sName) Chris@76: { Chris@76: if (!('length' in oRadioGroup)) Chris@76: return oRadioGroup.checked = true; Chris@76: Chris@76: for (var i = 0, n = oRadioGroup.length; i < n; i++) Chris@76: if (oRadioGroup[i].value == sName) Chris@76: return oRadioGroup[i].checked = true; Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: // Invert all checkboxes at once by clicking a single checkbox. Chris@76: function invertAll(oInvertCheckbox, oForm, sMask, bIgnoreDisabled) Chris@76: { Chris@76: for (var i = 0; i < oForm.length; i++) Chris@76: { Chris@76: if (!('name' in oForm[i]) || (typeof(sMask) == 'string' && oForm[i].name.substr(0, sMask.length) != sMask && oForm[i].id.substr(0, sMask.length) != sMask)) Chris@76: continue; Chris@76: Chris@76: if (!oForm[i].disabled || (typeof(bIgnoreDisabled) == 'boolean' && bIgnoreDisabled)) Chris@76: oForm[i].checked = oInvertCheckbox.checked; Chris@76: } Chris@76: } Chris@76: Chris@76: // Keep the session alive - always! Chris@76: var lastKeepAliveCheck = new Date().getTime(); Chris@76: function smf_sessionKeepAlive() Chris@76: { Chris@76: var curTime = new Date().getTime(); Chris@76: Chris@76: // Prevent a Firefox bug from hammering the server. Chris@76: if (smf_scripturl && curTime - lastKeepAliveCheck > 900000) Chris@76: { Chris@76: var tempImage = new Image(); Chris@76: tempImage.src = smf_prepareScriptUrl(smf_scripturl) + 'action=keepalive;time=' + curTime; Chris@76: lastKeepAliveCheck = curTime; Chris@76: } Chris@76: Chris@76: window.setTimeout('smf_sessionKeepAlive();', 1200000); Chris@76: } Chris@76: window.setTimeout('smf_sessionKeepAlive();', 1200000); Chris@76: Chris@76: // Set a theme option through javascript. Chris@76: function smf_setThemeOption(option, value, theme, cur_session_id, cur_session_var, additional_vars) Chris@76: { Chris@76: // Compatibility. Chris@76: if (cur_session_id == null) Chris@76: cur_session_id = smf_session_id; Chris@76: if (typeof(cur_session_var) == 'undefined') Chris@76: cur_session_var = 'sesc'; Chris@76: Chris@76: if (additional_vars == null) Chris@76: additional_vars = ''; Chris@76: Chris@76: var tempImage = new Image(); Chris@76: 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()); Chris@76: } Chris@76: Chris@76: function smf_avatarResize() Chris@76: { Chris@76: var possibleAvatars = document.getElementsByTagName('img'); Chris@76: Chris@76: for (var i = 0; i < possibleAvatars.length; i++) Chris@76: { Chris@76: var tempAvatars = []; j = 0; Chris@76: if (possibleAvatars[i].className != 'avatar') Chris@76: continue; Chris@76: Chris@76: // Image.prototype.avatar = possibleAvatars[i]; Chris@76: tempAvatars[j] = new Image(); Chris@76: tempAvatars[j].avatar = possibleAvatars[i]; Chris@76: Chris@76: tempAvatars[j].onload = function() Chris@76: { Chris@76: this.avatar.width = this.width; Chris@76: this.avatar.height = this.height; Chris@76: if (smf_avatarMaxWidth != 0 && this.width > smf_avatarMaxWidth) Chris@76: { Chris@76: this.avatar.height = (smf_avatarMaxWidth * this.height) / this.width; Chris@76: this.avatar.width = smf_avatarMaxWidth; Chris@76: } Chris@76: if (smf_avatarMaxHeight != 0 && this.avatar.height > smf_avatarMaxHeight) Chris@76: { Chris@76: this.avatar.width = (smf_avatarMaxHeight * this.avatar.width) / this.avatar.height; Chris@76: this.avatar.height = smf_avatarMaxHeight; Chris@76: } Chris@76: } Chris@76: tempAvatars[j].src = possibleAvatars[i].src; Chris@76: j++; Chris@76: } Chris@76: Chris@76: if (typeof(window_oldAvatarOnload) != 'undefined' && window_oldAvatarOnload) Chris@76: { Chris@76: window_oldAvatarOnload(); Chris@76: window_oldAvatarOnload = null; Chris@76: } Chris@76: } Chris@76: Chris@76: Chris@76: function hashLoginPassword(doForm, cur_session_id) Chris@76: { Chris@76: // Compatibility. Chris@76: if (cur_session_id == null) Chris@76: cur_session_id = smf_session_id; Chris@76: Chris@76: if (typeof(hex_sha1) == 'undefined') Chris@76: return; Chris@76: // Are they using an email address? Chris@76: if (doForm.user.value.indexOf('@') != -1) Chris@76: return; Chris@76: Chris@76: // Unless the browser is Opera, the password will not save properly. Chris@76: if (!('opera' in window)) Chris@76: doForm.passwrd.autocomplete = 'off'; Chris@76: Chris@76: doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_to8bit().php_strtolower() + doForm.passwrd.value.php_to8bit()) + cur_session_id); Chris@76: Chris@76: // It looks nicer to fill it with asterisks, but Firefox will try to save that. Chris@76: if (is_ff != -1) Chris@76: doForm.passwrd.value = ''; Chris@76: else Chris@76: doForm.passwrd.value = doForm.passwrd.value.replace(/./g, '*'); Chris@76: } Chris@76: Chris@76: function hashAdminPassword(doForm, username, cur_session_id) Chris@76: { Chris@76: // Compatibility. Chris@76: if (cur_session_id == null) Chris@76: cur_session_id = smf_session_id; Chris@76: Chris@76: if (typeof(hex_sha1) == 'undefined') Chris@76: return; Chris@76: Chris@76: doForm.admin_hash_pass.value = hex_sha1(hex_sha1(username.php_to8bit().php_strtolower() + doForm.admin_pass.value.php_to8bit()) + cur_session_id); Chris@76: doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, '*'); Chris@76: } Chris@76: Chris@76: // Shows the page numbers by clicking the dots (in compact view). Chris@76: function expandPages(spanNode, baseURL, firstPage, lastPage, perPage) Chris@76: { Chris@76: var replacement = '', i, oldLastPage = 0; Chris@76: var perPageLimit = 50; Chris@76: Chris@76: // The dots were bold, the page numbers are not (in most cases). Chris@76: spanNode.style.fontWeight = 'normal'; Chris@76: spanNode.onclick = ''; Chris@76: Chris@76: // Prevent too many pages to be loaded at once. Chris@76: if ((lastPage - firstPage) / perPage > perPageLimit) Chris@76: { Chris@76: oldLastPage = lastPage; Chris@76: lastPage = firstPage + perPageLimit * perPage; Chris@76: } Chris@76: Chris@76: // Calculate the new pages. Chris@76: for (i = firstPage; i < lastPage; i += perPage) Chris@76: replacement += '' + (1 + i / perPage) + ' '; Chris@76: Chris@76: if (oldLastPage > 0) Chris@76: replacement += ' ... '; Chris@76: Chris@76: // Replace the dots by the new page links. Chris@76: setInnerHTML(spanNode, replacement); Chris@76: } Chris@76: Chris@76: function smc_preCacheImage(sSrc) Chris@76: { Chris@76: if (!('smc_aCachedImages' in window)) Chris@76: window.smc_aCachedImages = []; Chris@76: Chris@76: if (!in_array(sSrc, window.smc_aCachedImages)) Chris@76: { Chris@76: var oImage = new Image(); Chris@76: oImage.src = sSrc; Chris@76: } Chris@76: } Chris@76: Chris@76: Chris@76: // *** smc_Cookie class. Chris@76: function smc_Cookie(oOptions) Chris@76: { Chris@76: this.opt = oOptions; Chris@76: this.oCookies = {}; Chris@76: this.init(); Chris@76: } Chris@76: Chris@76: smc_Cookie.prototype.init = function() Chris@76: { Chris@76: if ('cookie' in document && document.cookie != '') Chris@76: { Chris@76: var aCookieList = document.cookie.split(';'); Chris@76: for (var i = 0, n = aCookieList.length; i < n; i++) Chris@76: { Chris@76: var aNameValuePair = aCookieList[i].split('='); Chris@76: this.oCookies[aNameValuePair[0].replace(/^\s+|\s+$/g, '')] = decodeURIComponent(aNameValuePair[1]); Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: smc_Cookie.prototype.get = function(sKey) Chris@76: { Chris@76: return sKey in this.oCookies ? this.oCookies[sKey] : null; Chris@76: } Chris@76: Chris@76: smc_Cookie.prototype.set = function(sKey, sValue) Chris@76: { Chris@76: document.cookie = sKey + '=' + encodeURIComponent(sValue); Chris@76: } Chris@76: Chris@76: Chris@76: // *** smc_Toggle class. Chris@76: function smc_Toggle(oOptions) Chris@76: { Chris@76: this.opt = oOptions; Chris@76: this.bCollapsed = false; Chris@76: this.oCookie = null; Chris@76: this.init(); Chris@76: } Chris@76: Chris@76: smc_Toggle.prototype.init = function () Chris@76: { Chris@76: // The master switch can disable this toggle fully. Chris@76: if ('bToggleEnabled' in this.opt && !this.opt.bToggleEnabled) Chris@76: return; Chris@76: Chris@76: // If cookies are enabled and they were set, override the initial state. Chris@76: if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie) Chris@76: { Chris@76: // Initialize the cookie handler. Chris@76: this.oCookie = new smc_Cookie({}); Chris@76: Chris@76: // Check if the cookie is set. Chris@76: var cookieValue = this.oCookie.get(this.opt.oCookieOptions.sCookieName) Chris@76: if (cookieValue != null) Chris@76: this.opt.bCurrentlyCollapsed = cookieValue == '1'; Chris@76: } Chris@76: Chris@76: // If the init state is set to be collapsed, collapse it. Chris@76: if (this.opt.bCurrentlyCollapsed) Chris@76: this.changeState(true, true); Chris@76: Chris@76: // Initialize the images to be clickable. Chris@76: if ('aSwapImages' in this.opt) Chris@76: { Chris@76: for (var i = 0, n = this.opt.aSwapImages.length; i < n; i++) Chris@76: { Chris@76: var oImage = document.getElementById(this.opt.aSwapImages[i].sId); Chris@76: if (typeof(oImage) == 'object' && oImage != null) Chris@76: { Chris@76: // Display the image in case it was hidden. Chris@76: if (oImage.style.display == 'none') Chris@76: oImage.style.display = ''; Chris@76: Chris@76: oImage.instanceRef = this; Chris@76: oImage.onclick = function () { Chris@76: this.instanceRef.toggle(); Chris@76: this.blur(); Chris@76: } Chris@76: oImage.style.cursor = 'pointer'; Chris@76: Chris@76: // Preload the collapsed image. Chris@76: smc_preCacheImage(this.opt.aSwapImages[i].srcCollapsed); Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // Initialize links. Chris@76: if ('aSwapLinks' in this.opt) Chris@76: { Chris@76: for (var i = 0, n = this.opt.aSwapLinks.length; i < n; i++) Chris@76: { Chris@76: var oLink = document.getElementById(this.opt.aSwapLinks[i].sId); Chris@76: if (typeof(oLink) == 'object' && oLink != null) Chris@76: { Chris@76: // Display the link in case it was hidden. Chris@76: if (oLink.style.display == 'none') Chris@76: oLink.style.display = ''; Chris@76: Chris@76: oLink.instanceRef = this; Chris@76: oLink.onclick = function () { Chris@76: this.instanceRef.toggle(); Chris@76: this.blur(); Chris@76: return false; Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // Collapse or expand the section. Chris@76: smc_Toggle.prototype.changeState = function(bCollapse, bInit) Chris@76: { Chris@76: // Default bInit to false. Chris@76: bInit = typeof(bInit) == 'undefined' ? false : true; Chris@76: Chris@76: // Handle custom function hook before collapse. Chris@76: if (!bInit && bCollapse && 'funcOnBeforeCollapse' in this.opt) Chris@76: { Chris@76: this.tmpMethod = this.opt.funcOnBeforeCollapse; Chris@76: this.tmpMethod(); Chris@76: delete this.tmpMethod; Chris@76: } Chris@76: Chris@76: // Handle custom function hook before expand. Chris@76: else if (!bInit && !bCollapse && 'funcOnBeforeExpand' in this.opt) Chris@76: { Chris@76: this.tmpMethod = this.opt.funcOnBeforeExpand; Chris@76: this.tmpMethod(); Chris@76: delete this.tmpMethod; Chris@76: } Chris@76: Chris@76: // Loop through all the images that need to be toggled. Chris@76: if ('aSwapImages' in this.opt) Chris@76: { Chris@76: for (var i = 0, n = this.opt.aSwapImages.length; i < n; i++) Chris@76: { Chris@76: var oImage = document.getElementById(this.opt.aSwapImages[i].sId); Chris@76: if (typeof(oImage) == 'object' && oImage != null) Chris@76: { Chris@76: // Only (re)load the image if it's changed. Chris@76: var sTargetSource = bCollapse ? this.opt.aSwapImages[i].srcCollapsed : this.opt.aSwapImages[i].srcExpanded; Chris@76: if (oImage.src != sTargetSource) Chris@76: oImage.src = sTargetSource; Chris@76: Chris@76: oImage.alt = oImage.title = bCollapse ? this.opt.aSwapImages[i].altCollapsed : this.opt.aSwapImages[i].altExpanded; Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // Loop through all the links that need to be toggled. Chris@76: if ('aSwapLinks' in this.opt) Chris@76: { Chris@76: for (var i = 0, n = this.opt.aSwapLinks.length; i < n; i++) Chris@76: { Chris@76: var oLink = document.getElementById(this.opt.aSwapLinks[i].sId); Chris@76: if (typeof(oLink) == 'object' && oLink != null) Chris@76: setInnerHTML(oLink, bCollapse ? this.opt.aSwapLinks[i].msgCollapsed : this.opt.aSwapLinks[i].msgExpanded); Chris@76: } Chris@76: } Chris@76: Chris@76: // Now go through all the sections to be collapsed. Chris@76: for (var i = 0, n = this.opt.aSwappableContainers.length; i < n; i++) Chris@76: { Chris@76: if (this.opt.aSwappableContainers[i] == null) Chris@76: continue; Chris@76: Chris@76: var oContainer = document.getElementById(this.opt.aSwappableContainers[i]); Chris@76: if (typeof(oContainer) == 'object' && oContainer != null) Chris@76: oContainer.style.display = bCollapse ? 'none' : ''; Chris@76: } Chris@76: Chris@76: // Update the new state. Chris@76: this.bCollapsed = bCollapse; Chris@76: Chris@76: // Update the cookie, if desired. Chris@76: if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie) Chris@76: this.oCookie.set(this.opt.oCookieOptions.sCookieName, this.bCollapsed ? '1' : '0'); Chris@76: Chris@76: if ('oThemeOptions' in this.opt && this.opt.oThemeOptions.bUseThemeSettings) Chris@76: 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); Chris@76: } Chris@76: Chris@76: smc_Toggle.prototype.toggle = function() Chris@76: { Chris@76: // Change the state by reversing the current state. Chris@76: this.changeState(!this.bCollapsed); Chris@76: } Chris@76: Chris@76: Chris@76: function ajax_indicator(turn_on) Chris@76: { Chris@76: if (ajax_indicator_ele == null) Chris@76: { Chris@76: ajax_indicator_ele = document.getElementById('ajax_in_progress'); Chris@76: Chris@76: if (ajax_indicator_ele == null && typeof(ajax_notification_text) != null) Chris@76: { Chris@76: create_ajax_indicator_ele(); Chris@76: } Chris@76: } Chris@76: Chris@76: if (ajax_indicator_ele != null) Chris@76: { Chris@76: if (navigator.appName == 'Microsoft Internet Explorer' && !is_ie7up) Chris@76: { Chris@76: ajax_indicator_ele.style.position = 'absolute'; Chris@76: ajax_indicator_ele.style.top = document.documentElement.scrollTop; Chris@76: } Chris@76: Chris@76: ajax_indicator_ele.style.display = turn_on ? 'block' : 'none'; Chris@76: } Chris@76: } Chris@76: Chris@76: function create_ajax_indicator_ele() Chris@76: { Chris@76: // Create the div for the indicator. Chris@76: ajax_indicator_ele = document.createElement('div'); Chris@76: Chris@76: // Set the id so it'll load the style properly. Chris@76: ajax_indicator_ele.id = 'ajax_in_progress'; Chris@76: Chris@76: // Add the image in and link to turn it off. Chris@76: var cancel_link = document.createElement('a'); Chris@76: cancel_link.href = 'javascript:ajax_indicator(false)'; Chris@76: var cancel_img = document.createElement('img'); Chris@76: cancel_img.src = smf_images_url + '/icons/quick_remove.gif'; Chris@76: Chris@76: if (typeof(ajax_notification_cancel_text) != 'undefined') Chris@76: { Chris@76: cancel_img.alt = ajax_notification_cancel_text; Chris@76: cancel_img.title = ajax_notification_cancel_text; Chris@76: } Chris@76: Chris@76: // Add the cancel link and image to the indicator. Chris@76: cancel_link.appendChild(cancel_img); Chris@76: ajax_indicator_ele.appendChild(cancel_link); Chris@76: Chris@76: // Set the text. (Note: You MUST append here and not overwrite.) Chris@76: ajax_indicator_ele.innerHTML += ajax_notification_text; Chris@76: Chris@76: // Finally attach the element to the body. Chris@76: document.body.appendChild(ajax_indicator_ele); Chris@76: } Chris@76: Chris@76: function createEventListener(oTarget) Chris@76: { Chris@76: if (!('addEventListener' in oTarget)) Chris@76: { Chris@76: if (oTarget.attachEvent) Chris@76: { Chris@76: oTarget.addEventListener = function (sEvent, funcHandler, bCapture) { Chris@76: oTarget.attachEvent('on' + sEvent, funcHandler); Chris@76: } Chris@76: oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) { Chris@76: oTarget.detachEvent('on' + sEvent, funcHandler); Chris@76: } Chris@76: } Chris@76: else Chris@76: { Chris@76: oTarget.addEventListener = function (sEvent, funcHandler, bCapture) { Chris@76: oTarget['on' + sEvent] = funcHandler; Chris@76: } Chris@76: oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) { Chris@76: oTarget['on' + sEvent] = null; Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // This function will retrieve the contents needed for the jump to boxes. Chris@76: function grabJumpToContent() Chris@76: { Chris@76: var oXMLDoc = getXMLDocument(smf_prepareScriptUrl(smf_scripturl) + 'action=xmlhttp;sa=jumpto;xml'); Chris@76: var aBoardsAndCategories = new Array(); Chris@76: Chris@76: ajax_indicator(true); Chris@76: Chris@76: if (oXMLDoc.responseXML) Chris@76: { Chris@76: var items = oXMLDoc.responseXML.getElementsByTagName('smf')[0].getElementsByTagName('item'); Chris@76: for (var i = 0, n = items.length; i < n; i++) Chris@76: { Chris@76: aBoardsAndCategories[aBoardsAndCategories.length] = { Chris@76: id: parseInt(items[i].getAttribute('id')), Chris@76: isCategory: items[i].getAttribute('type') == 'category', Chris@76: name: items[i].firstChild.nodeValue.removeEntities(), Chris@76: is_current: false, Chris@76: childLevel: parseInt(items[i].getAttribute('childlevel')) Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: ajax_indicator(false); Chris@76: Chris@76: for (var i = 0, n = aJumpTo.length; i < n; i++) Chris@76: aJumpTo[i].fillSelect(aBoardsAndCategories); Chris@76: } Chris@76: Chris@76: // This'll contain all JumpTo objects on the page. Chris@76: var aJumpTo = new Array(); Chris@76: Chris@76: // *** JumpTo class. Chris@76: function JumpTo(oJumpToOptions) Chris@76: { Chris@76: this.opt = oJumpToOptions; Chris@76: this.dropdownList = null; Chris@76: this.showSelect(); Chris@76: } Chris@76: Chris@76: // Show the initial select box (onload). Method of the JumpTo class. Chris@76: JumpTo.prototype.showSelect = function () Chris@76: { Chris@76: var sChildLevelPrefix = ''; Chris@76: for (var i = this.opt.iCurBoardChildLevel; i > 0; i--) Chris@76: sChildLevelPrefix += this.opt.sBoardChildLevelIndicator; Chris@76: setInnerHTML(document.getElementById(this.opt.sContainerId), this.opt.sJumpToTemplate.replace(/%select_id%/, this.opt.sContainerId + '_select').replace(/%dropdown_list%/, ' ')); Chris@76: this.dropdownList = document.getElementById(this.opt.sContainerId + '_select'); Chris@76: } Chris@76: Chris@76: // Fill the jump to box with entries. Method of the JumpTo class. Chris@76: JumpTo.prototype.fillSelect = function (aBoardsAndCategories) Chris@76: { Chris@76: var bIE5x = !('implementation' in document); Chris@76: var iIndexPointer = 0; Chris@76: Chris@76: // Create an option that'll be above and below the category. Chris@76: var oDashOption = document.createElement('option'); Chris@76: oDashOption.appendChild(document.createTextNode(this.opt.sCatSeparator)); Chris@76: oDashOption.disabled = 'disabled'; Chris@76: oDashOption.value = ''; Chris@76: Chris@76: // Reset the events and clear the list (IE5.x only). Chris@76: if (bIE5x) Chris@76: { Chris@76: this.dropdownList.onmouseover = null; Chris@76: this.dropdownList.remove(0); Chris@76: } Chris@76: if ('onbeforeactivate' in document) Chris@76: this.dropdownList.onbeforeactivate = null; Chris@76: else Chris@76: this.dropdownList.onfocus = null; Chris@76: Chris@76: // Create a document fragment that'll allowing inserting big parts at once. Chris@76: var oListFragment = bIE5x ? this.dropdownList : document.createDocumentFragment(); Chris@76: Chris@76: // Loop through all items to be added. Chris@76: for (var i = 0, n = aBoardsAndCategories.length; i < n; i++) Chris@76: { Chris@76: var j, sChildLevelPrefix, oOption; Chris@76: Chris@76: // If we've reached the currently selected board add all items so far. Chris@76: if (!aBoardsAndCategories[i].isCategory && aBoardsAndCategories[i].id == this.opt.iCurBoardId) Chris@76: { Chris@76: if (bIE5x) Chris@76: iIndexPointer = this.dropdownList.options.length; Chris@76: else Chris@76: { Chris@76: this.dropdownList.insertBefore(oListFragment, this.dropdownList.options[0]); Chris@76: oListFragment = document.createDocumentFragment(); Chris@76: continue; Chris@76: } Chris@76: } Chris@76: Chris@76: if (aBoardsAndCategories[i].isCategory) Chris@76: oListFragment.appendChild(oDashOption.cloneNode(true)); Chris@76: else Chris@76: for (j = aBoardsAndCategories[i].childLevel, sChildLevelPrefix = ''; j > 0; j--) Chris@76: sChildLevelPrefix += this.opt.sBoardChildLevelIndicator; Chris@76: Chris@76: oOption = document.createElement('option'); Chris@76: oOption.appendChild(document.createTextNode((aBoardsAndCategories[i].isCategory ? this.opt.sCatPrefix : sChildLevelPrefix + this.opt.sBoardPrefix) + aBoardsAndCategories[i].name)); Chris@76: oOption.value = aBoardsAndCategories[i].isCategory ? '#c' + aBoardsAndCategories[i].id : '?board=' + aBoardsAndCategories[i].id + '.0'; Chris@76: oListFragment.appendChild(oOption); Chris@76: Chris@76: if (aBoardsAndCategories[i].isCategory) Chris@76: oListFragment.appendChild(oDashOption.cloneNode(true)); Chris@76: } Chris@76: Chris@76: // Add the remaining items after the currently selected item. Chris@76: this.dropdownList.appendChild(oListFragment); Chris@76: Chris@76: if (bIE5x) Chris@76: this.dropdownList.options[iIndexPointer].selected = true; Chris@76: Chris@76: // Internet Explorer needs this to keep the box dropped down. Chris@76: this.dropdownList.style.width = 'auto'; Chris@76: this.dropdownList.focus(); Chris@76: Chris@76: // Add an onchange action Chris@76: this.dropdownList.onchange = function() { Chris@76: if (this.selectedIndex > 0 && this.options[this.selectedIndex].value) Chris@76: 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); Chris@76: } Chris@76: } Chris@76: Chris@76: // A global array containing all IconList objects. Chris@76: var aIconLists = new Array(); Chris@76: Chris@76: // *** IconList object. Chris@76: function IconList(oOptions) Chris@76: { Chris@76: if (!window.XMLHttpRequest) Chris@76: return; Chris@76: Chris@76: this.opt = oOptions; Chris@76: this.bListLoaded = false; Chris@76: this.oContainerDiv = null; Chris@76: this.funcMousedownHandler = null; Chris@76: this.funcParent = this; Chris@76: this.iCurMessageId = 0; Chris@76: this.iCurTimeout = 0; Chris@76: Chris@76: // Add backwards compatibility with old themes. Chris@76: if (!('sSessionVar' in this.opt)) Chris@76: this.opt.sSessionVar = 'sesc'; Chris@76: Chris@76: this.initIcons(); Chris@76: } Chris@76: Chris@76: // Replace all message icons by icons with hoverable and clickable div's. Chris@76: IconList.prototype.initIcons = function () Chris@76: { Chris@76: for (var i = document.images.length - 1, iPrefixLength = this.opt.sIconIdPrefix.length; i >= 0; i--) Chris@76: if (document.images[i].id.substr(0, iPrefixLength) == this.opt.sIconIdPrefix) Chris@76: setOuterHTML(document.images[i], '