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