Completed
Push — development ( 5236fa...488938 )
by Stephen
20s
created

script.js ➔ addLoadEvent   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
/*!
2
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * This file contains code covered by:
7
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
8
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
9
 *
10
 * @version 1.1
11
 */
12
13
/**
14
 * This file contains javascript utility functions
15
 */
16
17
var elk_formSubmitted = false,
18
	lastKeepAliveCheck = new Date().getTime(),
19
	ajax_indicator_ele = null;
20
21
// Some very basic browser detection
22
var ua = navigator.userAgent.toLowerCase(),
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
23
	is_opera = !!window.opera, // Opera 8.0-12, past that it behaves like chrome
24
	is_ff = typeof InstallTrigger !== 'undefined' || ((ua.indexOf('iceweasel') !== -1 || ua.indexOf('icecat') !== -1 || ua.indexOf('shiretoko') !== -1 || ua.indexOf('minefield') !== -1) && !is_opera),
0 ignored issues
show
Bug introduced by
The variable InstallTrigger seems to be never declared. If this is a global, consider adding a /** global: InstallTrigger */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
25
	is_safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0, // Safari 3+
26
	is_chrome = !!window.chrome, // Chrome 1+, Opera 15+
27
	is_ie = !!document.documentMode, // IE8+
28
	is_webkit = ua.indexOf('applewebkit') !== -1;
29
	is_osx = navigator.platform.toUpperCase().indexOf('MAC') >= 0,
0 ignored issues
show
Bug introduced by
The variable is_osx seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_osx.
Loading history...
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
30
	is_mobile = navigator.userAgent.indexOf('Mobi') !== -1, // Common mobile including Mozilla, Safari, IE, Opera, Chrome
0 ignored issues
show
Bug introduced by
The variable is_mobile seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_mobile.
Loading history...
31
	is_touch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
0 ignored issues
show
Bug introduced by
The variable DocumentTouch seems to be never declared. If this is a global, consider adding a /** global: DocumentTouch */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable is_touch seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_touch.
Loading history...
Bug introduced by
Did you forget to assign or call a function?

This error message can for example pop up if you forget to assign the result of a function call to a variable or pass it to another function:

function someFunction(x) {
    (x > 0) ? callFoo() : callBar();
}

// JSHint expects you to assign the result to a variable:
function someFunction(x) {
    var rs = (x > 0) ? callFoo() : callBar();
}

// If you do not use the result, you could also use if statements in the
// case above.
function someFunction(x) {
    if (x > 0) {
        callFoo();
    } else {
        callBar();
    }
}
Loading history...
32
33
// Versions of ie < 9 do not have this built in
34
if (!('getElementsByClassName' in document))
35
{
36
	document.getElementsByClassName = function(className)
37
	{
38
		return $('.' + className);
39
	};
40
}
41
42
/**
43
 * Load an XML document using XMLHttpRequest.
44
 *
45
 * @callback xmlCallback
46
 * @param {string} sUrl
47
 * @param {function} funcCallback
48
 */
49
function getXMLDocument(sUrl, funcCallback)
50
{
51
	var oMyDoc = new XMLHttpRequest(),
0 ignored issues
show
Bug introduced by
The variable XMLHttpRequest seems to be never declared. If this is a global, consider adding a /** global: XMLHttpRequest */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
52
		bAsync = typeof(funcCallback) !== 'undefined',
53
		oCaller = this;
54
55
	if (bAsync)
56
	{
57
		oMyDoc.onreadystatechange = function () {
58
			if (oMyDoc.readyState !== 4)
59
				return;
60
61
			if (oMyDoc.responseXML !== null && oMyDoc.status === 200)
62
				funcCallback.call(oCaller, oMyDoc.responseXML);
63
			else
64
				funcCallback.call(oCaller, false);
65
		};
66
	}
67
68
	oMyDoc.open('GET', sUrl, bAsync);
69
	oMyDoc.send(null);
70
71
	return oMyDoc;
72
}
73
74
/**
75
 * Send a post form to the server using XMLHttpRequest.
76
 *
77
 * @param {string} sUrl
78
 * @param {string} sContent
79
 * @param {string} funcCallback
80
 */
81
function sendXMLDocument(sUrl, sContent, funcCallback)
82
{
83
	var oSendDoc = new window.XMLHttpRequest(),
84
		oCaller = this;
85
86
	if (typeof(funcCallback) !== 'undefined')
87
	{
88
		oSendDoc.onreadystatechange = function () {
89
			if (oSendDoc.readyState !== 4)
90
				return;
91
92
			if (oSendDoc.responseXML !== null && oSendDoc.status === 200)
93
				funcCallback.call(oCaller, oSendDoc.responseXML);
94
			else
95
				funcCallback.call(oCaller, false);
96
		};
97
	}
98
99
	oSendDoc.open('POST', sUrl, true);
100
	if ('setRequestHeader' in oSendDoc)
101
		oSendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
102
	oSendDoc.send(sContent);
103
104
	return true;
105
}
106
107
/**
108
 * All of our specialized string handling functions are defined here
109
 * php_strtr, php_strtolower, php_urlencode, php_htmlspecialchars
110
 * php_unhtmlspecialchars, php_addslashes, removeEntities, easyReplace
111
 */
112
113
/**
114
 * Character-level replacement function.
115
 * @param {string} sFrom
116
 * @param {string} sTo
117
 */
118
String.prototype.php_strtr = function (sFrom, sTo)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
119
{
120
	return this.replace(new RegExp('[' + sFrom + ']', 'g'), function (sMatch) {
121
		return sTo.charAt(sFrom.indexOf(sMatch));
122
	});
123
};
124
125
/**
126
 * Simulate PHP's strtolower (in SOME cases PHP uses ISO-8859-1 case folding).
127
 * @returns {String.prototype@call;php_strtr}
128
 */
129
String.prototype.php_strtolower = function ()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
130
{
131
	return typeof(elk_iso_case_folding) === 'boolean' && elk_iso_case_folding === true ? this.php_strtr(
0 ignored issues
show
Bug introduced by
The variable elk_iso_case_folding seems to be never declared. If this is a global, consider adding a /** global: elk_iso_case_folding */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
132
		'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',
133
		'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'
134
	) : this.php_strtr('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
135
};
136
137
/**
138
 * Simulate php's urlencode function
139
 */
140
String.prototype.php_urlencode = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
141
{
142
	return encodeURIComponent(this).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
143
};
144
145
/**
146
 * Simulate php htmlspecialchars function
147
 */
148
String.prototype.php_htmlspecialchars = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
149
{
150
	return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
151
};
152
153
/**
154
 * Simulate php unhtmlspecialchars function
155
 */
156
String.prototype.php_unhtmlspecialchars = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
157
{
158
	return this.replace(/&quot;/g, '"').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&amp;/g, '&');
159
};
160
161
/**
162
 * Simulate php addslashes function
163
 */
164
String.prototype.php_addslashes = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
165
{
166
	return this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
167
};
168
169
/**
170
 * Callback function for the removeEntities function
171
 */
172
String.prototype._replaceEntities = function(sInput, sDummy, sNum)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
173
{
174
	return String.fromCharCode(parseInt(sNum));
175
};
176
177
/**
178
 * Removes entities from a string and replaces them with a character code
179
 */
180
String.prototype.removeEntities = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
181
{
182
	return this.replace(/&(amp;)?#(\d+);/g, this._replaceEntities);
183
};
184
185
/**
186
 * String replace function, searches a string for x and replaces it with y
187
 *
188
 * @param {object} oReplacements object of search:replace terms
189
 */
190
String.prototype.easyReplace = function (oReplacements)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
191
{
192
	var sResult = this;
193
194
	for (var sSearch in oReplacements) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
195
		sSearch = sSearch.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
196
		sResult = sResult.replace(new RegExp('%' + sSearch + '%', 'g'), oReplacements[sSearch]);
197
	}
198
199
	return sResult;
200
};
201
202
/**
203
 * Simulate php str_repeat function
204
 *
205
 * @param {string} sString
206
 * @param {int} iTime
207
 */
208
function php_str_repeat(sString, iTime)
209
{
210
	if (iTime < 1)
211
		return '';
212
	else
213
		return sString + php_str_repeat(sString, iTime - 1);
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
214
}
215
216
/**
217
 * Opens a new window
218
 *
219
 * @param {string} desktopURL
220
 * @param {int} alternateWidth
221
 * @param {int} alternateHeight
222
 * @param {boolean} noScrollbars
223
 */
224
function reqWin(desktopURL, alternateWidth, alternateHeight, noScrollbars)
225
{
226
	if ((alternateWidth && self.screen.availWidth * 0.8 < alternateWidth) || (alternateHeight && self.screen.availHeight * 0.8 < alternateHeight))
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
227
	{
228
		noScrollbars = false;
229
		alternateWidth = Math.min(alternateWidth, self.screen.availWidth * 0.8);
230
		alternateHeight = Math.min(alternateHeight, self.screen.availHeight * 0.8);
231
	}
232
	else
233
		noScrollbars = typeof(noScrollbars) === 'boolean' && noScrollbars === true;
234
235
	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');
236
237
	// Return false so the click won't follow the link ;).
238
	return false;
239
}
240
241
/**
242
 * Open a overlay div on the screen
243
 *
244
 * @param {string} desktopURL
245
 * @param {string} [sHeader]
246
 * @param {string} [sIcon]
247
 */
248
function reqOverlayDiv(desktopURL, sHeader, sIcon)
249
{
250
	// Set up our div details
251
	var sAjax_indicator = '<div class="centertext"><i class="icon icon-spin icon-big i-spinner"></i></div>';
252
253
	sIcon = typeof(sIcon) === 'string' ? sIcon : 'i-help';
254
	sHeader = typeof(sHeader) === 'string' ? sHeader : help_popup_heading_text;
0 ignored issues
show
Bug introduced by
The variable help_popup_heading_text seems to be never declared. If this is a global, consider adding a /** global: help_popup_heading_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
255
256
	// Create the div that we are going to load
257
	var oContainer = new smc_Popup({heading: sHeader, content: sAjax_indicator, icon: sIcon}),
258
		oPopup_body = $('#' + oContainer.popup_id).find('.popup_content');
259
260
	// Load the help page content (we just want the text to show)
261
	$.ajax({
262
		url: desktopURL,
263
		type: "GET",
264
		dataType: "html"
265
	})
266
	.done(function (data, textStatus, xhr) {
0 ignored issues
show
Unused Code introduced by
The parameter textStatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter xhr is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
267
		var help_content = $('<div id="temp_help">').html(data).find('a[href$="self.close();"]').hide().prev('br').hide().parent().html();
268
269
		oPopup_body.html(help_content);
270
	})
271
	.fail(function (xhr, textStatus, errorThrown) {
0 ignored issues
show
Unused Code introduced by
The parameter errorThrown is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
272
		oPopup_body.html(textStatus);
273
	});
274
275
	return false;
276
}
277
278
/**
279
 * smc_Popup class.
280
 *
281
 * @param {object} oOptions
282
 */
283
function smc_Popup(oOptions)
284
{
285
	this.opt = oOptions;
286
	this.popup_id = this.opt.custom_id ? this.opt.custom_id : 'elk_popup';
287
	this.show();
288
}
289
290
// Show the popup div & prepare the close events
291
smc_Popup.prototype.show = function ()
292
{
293
	var popup_class = 'popup_window ' + (this.opt.custom_class ? this.opt.custom_class : 'content'),
294
		icon = this.opt.icon ? '<i class="icon ' + this.opt.icon + ' icon-top"></i> ' : '';
295
296
	// Todo: opt.icon should be a string referencing the desired icon. Will require changing all callers.
297
298
	// Create the div that will be shown - max-height added here - essential anyway,
299
	// so better here than in the CSS.
300
	// Mind you, I still haven't figured out why it should be essential. Cargo cult coding FTW. :P
301
	// Create the div that will be shown
302
	$('body').append('<div id="' + this.popup_id + '" class="popup_container"><div class="' + popup_class + '" style="max-height: none;"><h3 class="popup_heading"><a href="javascript:void(0);" class="hide_popup icon i-close" title="Close"></a>' + icon + this.opt.heading + '</h3><div class="popup_content">' + this.opt.content + '</div></div></div>');
303
304
	// Show it
305
	this.popup_body = $('#' + this.popup_id).children('.popup_window');
306
	this.popup_body.parent().fadeIn(300);
307
308
	// Let the css know its now available
309
	this.popup_body.addClass("in");
310
311
	// Trigger hide on escape or mouse click
312
	var popup_instance = this;
313
	$(document).mouseup(function (e) {
314
		if ($('#' + popup_instance.popup_id).has(e.target).length === 0)
315
			popup_instance.hide();
316
	})
317
	.keyup(function(e){
318
		if (e.keyCode === 27)
319
			popup_instance.hide();
320
	});
321
322
	$('#' + this.popup_id).find('.hide_popup').on('click', function (){ return popup_instance.hide(); });
323
324
	return false;
325
};
326
327
// Hide the popup
328
smc_Popup.prototype.hide = function ()
329
{
330
	$('#' + this.popup_id).fadeOut(300, function(){ $(this).remove(); });
331
332
	return false;
333
};
334
335
/**
336
 * Replaces the currently selected text with the passed text.
337
 * Used by topic.js when inserting a quote into the plain text quick reply (not the editor QR)
338
 *
339
 * @param {string} text
340
 * @param {object} oTextHandle
341
 */
342
function replaceText(text, oTextHandle)
343
{
344
	// Standards compliant text range replace.
345
	if ('selectionStart' in oTextHandle)
346
	{
347
		var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart),
348
			end = oTextHandle.value.substr(oTextHandle.selectionEnd),
349
			scrollPos = oTextHandle.scrollTop,
350
			goForward = 0;
351
352
		oTextHandle.value = begin + text + end;
353
		if (oTextHandle.setSelectionRange)
354
		{
355
			oTextHandle.focus();
356
357
			if (is_opera && text.match(/\n/g) !== null)
358
				goForward = text.match(/\n/g).length;
359
360
			oTextHandle.setSelectionRange(begin.length + text.length + goForward, begin.length + text.length + goForward);
361
		}
362
		oTextHandle.scrollTop = scrollPos;
363
	}
364
	// Just put it on the end.
365
	else
366
	{
367
		oTextHandle.value += text;
368
		oTextHandle.focus(oTextHandle.value.length - 1);
369
	}
370
}
371
372
/**
373
 * Checks if the passed input's value is nothing.
374
 *
375
 * @param {string|object} theField
376
 */
377
function isEmptyText(theField)
378
{
379
	var theValue;
380
381
	// Copy the value so changes can be made..
382
	if (typeof(theField) === 'string')
383
		theValue = theField;
384
	else
385
		theValue = theField.value;
386
387
	// Strip whitespace off the left side.
388
	while (theValue.length > 0 && (theValue.charAt(0) === ' ' || theValue.charAt(0) === '\t'))
389
		theValue = theValue.substring(1, theValue.length);
390
391
	// Strip whitespace off the right side.
392
	while (theValue.length > 0 && (theValue.charAt(theValue.length - 1) === ' ' || theValue.charAt(theValue.length - 1) === '\t'))
393
		theValue = theValue.substring(0, theValue.length - 1);
394
395
	return theValue === '';
396
}
397
398
// Only allow form submission ONCE.
399
function submitonce(theform)
0 ignored issues
show
Unused Code introduced by
The parameter theform is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
400
{
401
	elk_formSubmitted = true;
402
}
403
404
function submitThisOnce(oControl, bReadOnly)
405
{
406
	// oControl might also be a form.
407
	var oForm = 'form' in oControl ? oControl.form : oControl,
408
		aTextareas = oForm.getElementsByTagName('textarea');
409
410
	bReadOnly = typeof bReadOnly == 'undefined' ? true : bReadOnly;
411
	for (var i = 0, n = aTextareas.length; i < n; i++)
412
		aTextareas[i].readOnly = bReadOnly;
413
414
	// If in a second the form is not gone, there may be a problem somewhere
415
	// (e.g. HTML5 required attribute), so release the textareas
416
	window.setTimeout(function() {submitThisOnce(oControl, false);}, 1000);
417
	return !elk_formSubmitted;
418
}
419
420
function getInnerHTML(oElement)
421
{
422
	if (oElement)
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if oElement is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
423
		return oElement.innerHTML;
424
}
425
426
/**
427
 * Set the "outer" HTML of an element.
428
 *
429
 * @param {HTMLElement} oElement
430
 * @param {string} sToValue
431
 */
432
function setOuterHTML(oElement, sToValue)
433
{
434
	if ('outerHTML' in oElement)
435
		oElement.outerHTML = sToValue;
436
	else
437
	{
438
		var range = document.createRange();
439
		range.setStartBefore(oElement);
440
		oElement.parentNode.replaceChild(range.createContextualFragment(sToValue), oElement);
441
	}
442
}
443
444
/**
445
 * Checks for variable in theArray, returns true or false
446
 *
447
 * @param {string} variable
448
 * @param {string[]} theArray
449
 */
450
function in_array(variable, theArray)
451
{
452
	for (var i in theArray)
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
453
		if (theArray[i] == variable)
454
			return true;
455
456
	return false;
457
}
458
459
/**
460
 * Checks for variable in theArray and returns the array key
461
 *
462
 * @param {string} variable
463
 * @param {Array.} theArray
464
 */
465
function array_search(variable, theArray)
466
{
467
	for (var i in theArray)
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
468
		if (theArray[i] == variable)
469
			return i;
470
471
	return null;
472
}
473
474
/**
475
 * Find a specific radio button in its group and select it.
476
 *
477
 * @param {HTMLInputElement} oRadioGroup
478
 * @param {type} sName
479
 */
480
function selectRadioByName(oRadioGroup, sName)
481
{
482
	if (!('length' in oRadioGroup))
483
		return oRadioGroup.checked = true;
0 ignored issues
show
Bug introduced by
Did you mean to return a conditional instead of an assignment?

This error is thrown if you assign to a variable in your return statement:

function someFunction(x) {
    return x = 1;
}

// Instead you maybe ment

function someFunction(x) {
    return x === 1;
}
Loading history...
484
485
	for (var i = 0, n = oRadioGroup.length; i < n; i++)
486
		if (oRadioGroup[i].value === sName)
487
			return oRadioGroup[i].checked = true;
0 ignored issues
show
Bug introduced by
Did you mean to return a conditional instead of an assignment?

This error is thrown if you assign to a variable in your return statement:

function someFunction(x) {
    return x = 1;
}

// Instead you maybe ment

function someFunction(x) {
    return x === 1;
}
Loading history...
488
489
	return false;
490
}
491
492
/**
493
 * Selects all the form objects with a single click
494
 *
495
 * @param {object} oInvertCheckbox
496
 * @param {object} oForm
497
 * @param {string} sMask
498
 * @param {string} sValue
499
 */
500
function selectAllRadio(oInvertCheckbox, oForm, sMask, sValue)
501
{
502
	for (var i = 0; i < oForm.length; i++)
503
		if (oForm[i].name !== undefined && oForm[i].name.substr(0, sMask.length) == sMask && oForm[i].value == sValue)
504
			oForm[i].checked = true;
505
}
506
507
/**
508
 * Invert all check boxes at once by clicking a single checkbox.
509
 *
510
 * @param {object} oInvertCheckbox
511
 * @param {HTMLFormElement} oForm
512
 * @param {string} [sMask]
513
 * @param {boolean} [bIgnoreDisabled]
514
 */
515
function invertAll(oInvertCheckbox, oForm, sMask, bIgnoreDisabled)
516
{
517
	for (var i = 0; i < oForm.length; i++)
518
	{
519
		if (!('name' in oForm[i]) || (typeof(sMask) === 'string' && oForm[i].name.substr(0, sMask.length) !== sMask && oForm[i].id.substr(0, sMask.length) !== sMask))
520
			continue;
521
522
		if (!oForm[i].disabled || (typeof(bIgnoreDisabled) === 'boolean' && bIgnoreDisabled))
523
			oForm[i].checked = oInvertCheckbox.checked;
524
	}
525
}
526
527
/**
528
 * Keep the session alive - always!
529
 */
530
function elk_sessionKeepAlive()
531
{
532
	var curTime = new Date().getTime();
533
534
	// Prevent a Firefox bug from hammering the server.
535
	if (elk_scripturl && curTime - lastKeepAliveCheck > 900000)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable elk_scripturl is declared in the current environment, consider using typeof elk_scripturl === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
536
	{
537
		var tempImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
538
		tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=keepalive;time=' + curTime;
539
		lastKeepAliveCheck = curTime;
540
	}
541
542
	window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
543
}
544
window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
545
546
/**
547
 * Set a theme option through javascript. / ajax
548
 *
549
 * @param {string} option name being set
550
 * @param {string} value of the option
551
 * @param {string|null} theme its being set or null for all
552
 * @param {string|null} additional_vars to use in the url request that will be sent
553
 */
554
function elk_setThemeOption(option, value, theme, additional_vars)
555
{
556
	if (additional_vars === null || typeof(additional_vars) === 'undefined')
557
		additional_vars = '';
558
559
	var tempImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
560
	tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=jsoption;var=' + option + ';val=' + value + ';' + elk_session_var + '=' + elk_session_id + additional_vars + (theme === null ? '' : '&th=' + theme) + ';time=' + (new Date().getTime());
0 ignored issues
show
Bug introduced by
The variable elk_session_id seems to be never declared. If this is a global, consider adding a /** global: elk_session_id */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_var seems to be never declared. If this is a global, consider adding a /** global: elk_session_var */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
561
}
562
563
/**
564
 * Password hashing for user
565
 *
566
 * @param {type} doForm
567
 * @param {type} cur_session_id
568
 * @param {type} token
569
 */
570
function hashLoginPassword(doForm, cur_session_id, token)
571
{
572
	// Don't have our hash lib available?
573
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
574
		return;
575
576
	// Are they using an email address?
577
	if (doForm.user.value.indexOf('@') !== -1)
578
		return;
579
580
	doForm.passwrd.autocomplete = 'off';
581
582
	// Fill in the hidden fields with our sha hash
583
	doForm.hash_passwrd.value = hex_sha256(doForm.user.value.php_strtolower() + doForm.passwrd.value);
584
585
	// If the form also contains the old hash input fill it to smooth transitions
586
	if ('old_hash_passwrd' in doForm && typeof(hex_sha1) !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha1 seems to be never declared. If this is a global, consider adding a /** global: hex_sha1 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
587
		doForm.old_hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_strtolower() + doForm.passwrd.value) + cur_session_id + (typeof token === 'undefined' ? '' : token));
588
589
	doForm.passwrd.value = doForm.passwrd.value.replace(/./g, '*');
590
}
591
592
/**
593
 * Password hashing for admin login
594
 *
595
 * @param {type} doForm
596
 * @param {type} username
597
 * @param {type} cur_session_id
598
 * @param {type} token
599
 */
600
function hashAdminPassword(doForm, username, cur_session_id, token)
0 ignored issues
show
Unused Code introduced by
The parameter cur_session_id is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter token is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
601
{
602
	// Missing sha256.js?
603
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
604
		return;
605
606
	doForm.admin_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.admin_pass.value);
607
	doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, '*');
608
}
609
610
/**
611
 * Hashing for the moderation login
612
 *
613
 * @param {type} doForm
614
 * @param {type} username
615
 * @param {type} cur_session_id
616
 * @param {type} token
617
 */
618
function hashModeratePassword(doForm, username, cur_session_id, token)
0 ignored issues
show
Unused Code introduced by
The parameter token is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter cur_session_id is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
619
{
620
	// Missing sha256.js?
621
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
622
		return;
623
624
	doForm.moderate_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.moderate_pass.value);
625
	doForm.moderate_pass.value = doForm.moderate_pass.value.replace(/./g, '*');
626
}
627
628
/**
629
 * Used by elk_Toggle to add an image to the swap/toggle array
630
 *
631
 * @param {string} sSrc
632
 */
633
function smc_preCacheImage(sSrc)
634
{
635
	if (!('smc_aCachedImages' in window))
636
		window.smc_aCachedImages = [];
637
638
	if (!in_array(sSrc, window.smc_aCachedImages))
639
	{
640
		var oImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
641
		oImage.src = sSrc;
642
	}
643
}
644
645
/**
646
 * smc_Cookie class.
647
 *
648
 * @param {object} oOptions
649
 */
650
function smc_Cookie(oOptions)
651
{
652
	this.opt = oOptions;
653
	this.oCookies = {};
654
	this.init();
655
}
656
657
smc_Cookie.prototype.init = function()
658
{
659
	if ('cookie' in document && document.cookie !== '')
660
	{
661
		var aCookieList = document.cookie.split(';');
662
		for (var i = 0, n = aCookieList.length; i < n; i++)
663
		{
664
			var aNameValuePair = aCookieList[i].split('=');
665
			this.oCookies[aNameValuePair[0].replace(/^\s+|\s+$/g, '')] = decodeURIComponent(aNameValuePair[1]);
666
		}
667
	}
668
};
669
670
smc_Cookie.prototype.get = function(sKey)
671
{
672
	return sKey in this.oCookies ? this.oCookies[sKey] : null;
673
};
674
675
smc_Cookie.prototype.set = function(sKey, sValue)
676
{
677
	document.cookie = sKey + '=' + encodeURIComponent(sValue);
678
};
679
680
/**
681
 * elk_Toggle class.
682
 *
683
 * Collapses a section of the page
684
 * Swaps the collapsed section class or image to indicate the state
685
 * Updates links to indicate state and allow reversal of the action
686
 * Saves state in a cookie and/or in a theme setting option so the last state
687
 * is remembered for the user.
688
 *
689
 * @param {object} oOptions
690
 * @returns {elk_Toggle}
691
 */
692
function elk_Toggle(oOptions)
693
{
694
	this.opt = oOptions;
695
	this.bCollapsed = false;
696
	this.oCookie = null;
697
	this.init();
698
}
699
700
// Initialize the toggle class
701
elk_Toggle.prototype.init = function()
702
{
703
	var i = 0,
704
		n = 0;
705
706
	// The master switch can disable this toggle fully.
707
	if ('bToggleEnabled' in this.opt && !this.opt.bToggleEnabled)
708
		return;
709
710
	// If cookies are enabled and they were set, override the initial state.
711
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
712
	{
713
		// Initialize the cookie handler.
714
		this.oCookie = new smc_Cookie({});
715
716
		// Check if the cookie is set.
717
		var cookieValue = this.oCookie.get(this.opt.oCookieOptions.sCookieName);
718
		if (cookieValue !== null)
719
			this.opt.bCurrentlyCollapsed = cookieValue === '1';
720
	}
721
722
	// If the init state is set to be collapsed, collapse it.
723
	if (this.opt.bCurrentlyCollapsed)
724
		this.changeState(true, true);
725
726
	// Initialize the images to be clickable.
727
	if ('aSwapImages' in this.opt)
728
	{
729
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
730
		{
731
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
732
			if (typeof(oImage) === 'object' && oImage !== null)
733
			{
734
				// Display the image in case it was hidden.
735
				if (getComputedStyle(oImage).getPropertyValue("display") === 'none')
736
					oImage.style.display = 'inline';
737
738
				oImage.instanceRef = this;
739
				oImage.onclick = function () {this.instanceRef.toggle();this.blur();};
740
				oImage.style.cursor = 'pointer';
741
742
				// Pre-load the collapsed image.
743
				smc_preCacheImage(this.opt.aSwapImages[i].srcCollapsed);
744
			}
745
		}
746
	}
747
	// No images to swap, perhaps they want to swap the class?
748
	else if ('aSwapClasses' in this.opt)
749
	{
750
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
751
		{
752
			var oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
753
			if (typeof(oContainer) === 'object' && oContainer !== null)
754
			{
755
				// Display the image in case it was hidden.
756
				if (getComputedStyle(oContainer).getPropertyValue("display") === 'none')
757
					oContainer.style.display = 'block';
758
759
				oContainer.instanceRef = this;
760
761
				oContainer.onclick = function () {
762
					this.instanceRef.toggle();
763
					this.blur();
764
				};
765
				oContainer.style.cursor = 'pointer';
766
			}
767
		}
768
	}
769
770
	// Initialize links.
771
	if ('aSwapLinks' in this.opt)
772
	{
773
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
774
		{
775
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
776
			if (typeof(oLink) === 'object' && oLink !== null)
777
			{
778
				// Display the link in case it was hidden.
779
				if (getComputedStyle(oLink).getPropertyValue("display") === 'none')
780
					oLink.style.display = 'inline-block';
781
782
				oLink.instanceRef = this;
783
				oLink.onclick = function () {
784
					this.instanceRef.toggle();
785
					this.blur();
786
					return false;
787
				};
788
			}
789
		}
790
	}
791
};
792
793
/**
794
 * Collapse or expand the section.
795
 *
796
 * @param {boolean} bCollapse
797
 * @param {boolean} [bInit]
798
 */
799
elk_Toggle.prototype.changeState = function(bCollapse, bInit)
800
{
801
	var i = 0,
802
		n = 0,
803
		oContainer;
804
805
	// Default bInit to false.
806
	bInit = typeof(bInit) !== 'undefined';
807
808
	// Handle custom function hook before collapse.
809
	if (!bInit && bCollapse && 'funcOnBeforeCollapse' in this.opt)
810
	{
811
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
812
		this.tmpMethod();
813
		delete this.tmpMethod;
814
	}
815
	// Handle custom function hook before expand.
816
	else if (!bInit && !bCollapse && 'funcOnBeforeExpand' in this.opt)
817
	{
818
		this.tmpMethod = this.opt.funcOnBeforeExpand;
819
		this.tmpMethod();
820
		delete this.tmpMethod;
821
	}
822
823
	// Loop through all the items that need to be toggled.
824
	if ('aSwapImages' in this.opt)
825
	{
826
		// Swapping images on a click
827
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
828
		{
829
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
830
			if (typeof(oImage) === 'object' && oImage !== null)
831
			{
832
				// Only (re)load the image if it's changed.
833
				var sTargetSource = bCollapse ? this.opt.aSwapImages[i].srcCollapsed : this.opt.aSwapImages[i].srcExpanded;
834
				if (oImage.src != sTargetSource)
835
					oImage.src = sTargetSource;
836
837
				oImage.alt = oImage.title = bCollapse ? this.opt.aSwapImages[i].altCollapsed : this.opt.aSwapImages[i].altExpanded;
838
			}
839
		}
840
	}
841
	else if ('aSwapClasses' in this.opt)
842
	{
843
		// Or swapping the classes
844
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
845
		{
846
			oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
847
			if (typeof(oContainer) === 'object' && oContainer !== null)
848
			{
849
				// Only swap the class if the state changed
850
				var sTargetClass = bCollapse ? this.opt.aSwapClasses[i].classCollapsed : this.opt.aSwapClasses[i].classExpanded;
851
				if (oContainer.className !== sTargetClass)
852
					oContainer.className = sTargetClass;
853
854
				// And show the new title
855
				oContainer.title = oContainer.title = bCollapse ? this.opt.aSwapClasses[i].titleCollapsed : this.opt.aSwapClasses[i].titleExpanded;
856
			}
857
		}
858
	}
859
860
	// Loop through all the links that need to be toggled.
861
	if ('aSwapLinks' in this.opt)
862
	{
863
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
864
		{
865
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
866
			if (typeof(oLink) === 'object' && oLink !== null)
867
				oLink.innerHTML = bCollapse ? this.opt.aSwapLinks[i].msgCollapsed : this.opt.aSwapLinks[i].msgExpanded;
868
		}
869
	}
870
871
	// Now go through all the sections to be collapsed.
872
	for (i = 0, n = this.opt.aSwappableContainers.length; i < n; i++)
873
	{
874
		if (this.opt.aSwappableContainers[i] === null)
875
			continue;
876
877
		oContainer = document.getElementById(this.opt.aSwappableContainers[i]);
878
		if (typeof(oContainer) === 'object' && oContainer !== null)
879
		{
880
			if (bCollapse)
881
				$(oContainer).slideUp();
882
			else
883
				$(oContainer).slideDown();
884
		}
885
	}
886
887
	// Update the new state.
888
	this.bCollapsed = bCollapse;
889
890
	// Update the cookie, if desired.
891
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
892
		this.oCookie.set(this.opt.oCookieOptions.sCookieName, this.bCollapsed ? '1' : '0');
893
894
	if (!bInit && 'oThemeOptions' in this.opt && this.opt.oThemeOptions.bUseThemeSettings)
895
		elk_setThemeOption(this.opt.oThemeOptions.sOptionName, this.bCollapsed ? '1' : '0', 'sThemeId' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sThemeId : null, 'sAdditionalVars' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sAdditionalVars : null);
896
};
897
898
elk_Toggle.prototype.toggle = function()
899
{
900
	// Change the state by reversing the current state.
901
	this.changeState(!this.bCollapsed);
902
};
903
904
/**
905
 * Creates and shows or hides the sites ajax in progress indicator
906
 *
907
 * @param {boolean} turn_on
908
 * @returns {undefined}
909
 */
910
function ajax_indicator(turn_on)
911
{
912
	if (ajax_indicator_ele === null)
913
	{
914
		ajax_indicator_ele = document.getElementById('ajax_in_progress');
915
916
		if (ajax_indicator_ele === null && typeof(ajax_notification_text) !== null)
0 ignored issues
show
Bug introduced by
The variable ajax_notification_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
917
		{
918
			create_ajax_indicator_ele();
919
		}
920
	}
921
922
	if (ajax_indicator_ele !== null)
923
	{
924
		ajax_indicator_ele.style.display = turn_on ? 'block' : 'none';
925
	}
926
}
927
928
/**
929
 * Creates the ajax notification div and adds it to the current screen
930
 */
931
function create_ajax_indicator_ele()
932
{
933
	// Create the div for the indicator.
934
	ajax_indicator_ele = document.createElement('div');
935
936
	// Set the id so it'll load the style properly.
937
	ajax_indicator_ele.id = 'ajax_in_progress';
938
939
	// Add the image in and link to turn it off.
940
	var cancel_link = document.createElement('a');
941
	cancel_link.href = 'javascript:ajax_indicator(false)';
0 ignored issues
show
Coding Style introduced by
Script urls should not be used.
Loading history...
942
943
	var cancel_img = document.createElement('img');
944
	cancel_img.src = elk_images_url + '/icons/quick_remove.png';
0 ignored issues
show
Bug introduced by
The variable elk_images_url seems to be never declared. If this is a global, consider adding a /** global: elk_images_url */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
945
946
	if (typeof(ajax_notification_cancel_text) !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable ajax_notification_cancel_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_cancel_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
947
	{
948
		cancel_img.alt = ajax_notification_cancel_text;
949
		cancel_img.title = ajax_notification_cancel_text;
950
	}
951
952
	// Add the cancel link and image to the indicator.
953
	cancel_link.appendChild(cancel_img);
954
	ajax_indicator_ele.appendChild(cancel_link);
955
956
	// Set the text.  (Note:  You MUST append here and not overwrite.)
957
	ajax_indicator_ele.innerHTML += ajax_notification_text;
0 ignored issues
show
Bug introduced by
The variable ajax_notification_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
958
959
	// Finally attach the element to the body.
960
	document.body.appendChild(ajax_indicator_ele);
961
}
962
963
/**
964
 * Creates and event listener object for a given object
965
 * Object events can then be added with addEventListener
966
 *
967
 * @param {HTMLElement} oTarget
968
 */
969
function createEventListener(oTarget)
970
{
971
	if (!('addEventListener' in oTarget))
972
	{
973
		if (oTarget.attachEvent)
974
		{
975
			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
976
				oTarget.attachEvent('on' + sEvent, funcHandler);
977
			};
978
979
			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
980
				oTarget.detachEvent('on' + sEvent, funcHandler);
981
			};
982
		}
983
		else
984
		{
985
			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
986
				oTarget['on' + sEvent] = funcHandler;
987
			};
988
989
			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter funcHandler is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
990
				oTarget['on' + sEvent] = null;
991
			};
992
		}
993
	}
994
}
995
996
997
/**
998
 * This function will retrieve the contents needed for the jump to boxes.
999
 */
1000
function grabJumpToContent() {
1001
	getXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=xmlhttp;sa=jumpto;xml', onJumpReceived);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1002
1003
	return false;
1004
}
1005
1006
/**
1007
 * Callback function for loading the jumpto box
1008
 *
1009
 * @param {object} oXMLDoc
1010
 */
1011
function onJumpReceived(oXMLDoc) {
1012
	var aBoardsAndCategories = [],
1013
		i,
1014
		n,
1015
		items = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('item');
1016
1017
	for (i = 0, n = items.length; i < n; i++)
1018
	{
1019
		aBoardsAndCategories[aBoardsAndCategories.length] = {
1020
			id: parseInt(items[i].getAttribute('id')),
1021
			isCategory: items[i].getAttribute('type') === 'category',
1022
			name: items[i].firstChild.nodeValue.removeEntities(),
1023
			is_current: false,
1024
			childLevel: parseInt(items[i].getAttribute('childlevel'))
1025
		};
1026
	}
1027
1028
	for (i = 0, n = aJumpTo.length; i < n; i++)
1029
		aJumpTo[i].fillSelect(aBoardsAndCategories);
1030
}
1031
1032
/**
1033
 * JumpTo class.
1034
 *
1035
 * Passed object of options can contain:
1036
 * sContainerId: container id to place the list in
1037
 * sClassName: class name to assign items added to the dropdown
1038
 * sJumpToTemplate: html template to wrap the %dropdown_list%
1039
 * iCurBoardId: id of the board current active
1040
 * iCurBoardChildLevel: child level of the currently active board
1041
 * sCurBoardName: name of the currently active board
1042
 * sBoardChildLevelIndicator: text/characters used to indent
1043
 * sBoardPrefix: arrow head
1044
 * sCatPrefix: Prefix to use in from of the categories
1045
 * bNoRedirect: boolean for redirect
1046
 * bDisabled: boolean for disabled
1047
 * sCustomName: custom name to prefix for the select name=""
1048
 * sGoButtonLabel: name for the goto button
1049
 *
1050
 * @param {type} oJumpToOptions
1051
 */
1052
// This'll contain all JumpTo objects on the page.
1053
var aJumpTo = [];
1054
function JumpTo(oJumpToOptions)
1055
{
1056
	this.opt = oJumpToOptions;
1057
	this.dropdownList = null;
1058
	this.showSelect();
1059
1060
	createEventListener(this.dropdownList);
1061
1062
	if (is_mobile && is_touch)
1063
		this.dropdownList.addEventListener('touchstart', grabJumpToContent);
1064
	else
1065
		this.dropdownList.addEventListener('mouseenter', grabJumpToContent);
1066
}
1067
1068
// Remove all the options in the select. Method of the JumpTo class.
1069
JumpTo.prototype.removeAll = function ()
1070
{
1071
//	var dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1072
for (var i = this.dropdownList.options.length; i > 0; i--)
1073
		this.dropdownList.remove(i - 1);
1074
};
1075
1076
// Show the initial select box (onload). Method of the JumpTo class.
1077
JumpTo.prototype.showSelect = function ()
1078
{
1079
	var sChildLevelPrefix = '';
1080
1081
	for (var i = this.opt.iCurBoardChildLevel; i > 0; i--)
1082
		sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1083
1084
	if (sChildLevelPrefix !== '')
1085
		sChildLevelPrefix += this.opt.sBoardPrefix;
1086
1087
	document.getElementById(this.opt.sContainerId).innerHTML = this.opt.sJumpToTemplate.replace(/%select_id%/, this.opt.sContainerId + '_select').replace(/%dropdown_list%/, '<select ' + (this.opt.bDisabled === true ? 'disabled="disabled" ' : '') + (this.opt.sClassName !== undefined ? 'class="' + this.opt.sClassName + '" ' : '') + 'name="' + (this.opt.sCustomName !== undefined ? this.opt.sCustomName : this.opt.sContainerId + '_select') + '" id="' + this.opt.sContainerId + '_select"><option value="' + (this.opt.bNoRedirect !== undefined && this.opt.bNoRedirect === true ? this.opt.iCurBoardId : '?board=' + this.opt.iCurBoardId + '.0') + '">' + sChildLevelPrefix + this.opt.sCurBoardName.removeEntities() + '</option></select>&nbsp;' + (this.opt.sGoButtonLabel !== undefined ? '<input type="button" class="button_submit" value="' + this.opt.sGoButtonLabel + '" onclick="window.location.href = \'' + elk_prepareScriptUrl(elk_scripturl) + 'board=' + this.opt.iCurBoardId + '.0\';" />' : ''));
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1088
	this.dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1089
};
1090
1091
// Fill the jump to box with entries. Method of the JumpTo class.
1092
JumpTo.prototype.fillSelect = function (aBoardsAndCategories)
1093
{
1094
	this.removeAll();
1095
1096
	if (is_mobile && is_touch)
1097
		this.dropdownList.removeEventListener('touchstart', grabJumpToContent);
1098
	else
1099
		this.dropdownList.removeEventListener('mouseenter', grabJumpToContent);
1100
1101
	// Create a document fragment that'll allowing inserting big parts at once.
1102
	var oListFragment = document.createDocumentFragment(),
1103
		oOptgroupFragment = document.createElement('optgroup');
1104
1105
	// Loop through all items to be added.
1106
	for (var i = 0, n = aBoardsAndCategories.length; i < n; i++)
1107
	{
1108
		var j,
1109
			sChildLevelPrefix = '',
1110
			oOption,
1111
			oText;
1112
1113
		if (aBoardsAndCategories[i].isCategory)
1114
		{
1115
			oOptgroupFragment = document.createElement('optgroup');
1116
			oOptgroupFragment.label = aBoardsAndCategories[i].name;
1117
			oListFragment.appendChild(oOptgroupFragment);
1118
			continue;
1119
		}
1120
		else
1121
		{
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1122
			for (j = aBoardsAndCategories[i].childLevel, sChildLevelPrefix = ''; j > 0; j--)
1123
				sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1124
1125
			if (sChildLevelPrefix !== '')
1126
				sChildLevelPrefix += this.opt.sBoardPrefix;
1127
		}
1128
1129
		oOption = document.createElement('option');
1130
		oText = document.createElement('span');
1131
		oText.innerHTML = sChildLevelPrefix + aBoardsAndCategories[i].name;
1132
1133
		if (aBoardsAndCategories[i].id === this.opt.iCurBoardId)
1134
			oOption.selected = 'selected';
1135
1136
		oOption.appendChild(oText);
1137
1138
		if (!this.opt.bNoRedirect)
1139
		{
1140
			oOption.value = '?board=' + aBoardsAndCategories[i].id + '.0';
1141
		}
1142
		else
1143
		{
1144
			oOption.value = aBoardsAndCategories[i].id;
1145
		}
1146
1147
		oOptgroupFragment.appendChild(oOption);
1148
	}
1149
1150
	// Add the remaining items after the currently selected item.
1151
	this.dropdownList.appendChild(oListFragment);
1152
1153
	// Add an onchange action
1154
	if (!this.opt.bNoRedirect)
1155
		this.dropdownList.onchange = function() {
1156
			if (this.selectedIndex > 0 && this.options[this.selectedIndex].value)
1157
				window.location.href = elk_scripturl + this.options[this.selectedIndex].value.substr(elk_scripturl.indexOf('?') === -1 || this.options[this.selectedIndex].value.substr(0, 1) !== '?' ? 0 : 1);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1158
		};
1159
1160
	// Handle custom function hook before showing the new select.
1161
	if ('funcOnBeforeCollapse' in this.opt)
1162
	{
1163
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
1164
		this.tmpMethod(this);
1165
		delete this.tmpMethod;
1166
	}
1167
};
1168
1169
/**
1170
 * IconList object.
1171
 *
1172
 * Allows clicking on a icon to expand out the available options to change
1173
 * Change is done via ajax
1174
 * Used for topic icon and member group icon selections
1175
 *
1176
 * Available options
1177
 *	sBackReference:
1178
 *	sIconIdPrefix:
1179
 *	bShowModify:
1180
 *	iBoardId:
1181
 *	iTopicId:
1182
 *	sAction:
1183
 *	sLabelIconList:
1184
 *
1185
 * The following are style elements that can be passed
1186
 *	sBoxBackground:
1187
 *	sBoxBackgroundHover:
1188
 *	iBoxBorderWidthHover:
1189
 *	sBoxBorderColorHover:
1190
 *	sContainerBackground:
1191
 *	sContainerBorder:
1192
 *	sItemBorder:
1193
 *	sItemBorderHover:
1194
 *	sItemBackground:
1195
 *	sItemBackgroundHover:
1196
 *
1197
 * @param {object} oOptions
1198
 */
1199
// A global array containing all IconList objects.
1200
var aIconLists = [];
1201
function IconList(oOptions)
1202
{
1203
	this.opt = oOptions;
1204
	this.bListLoaded = false;
1205
	this.oContainerDiv = null;
1206
	this.funcMousedownHandler = null;
1207
	this.funcParent = this;
1208
	this.iCurMessageId = 0;
1209
	this.iCurTimeout = 0;
1210
1211
	// Set a default Action
1212
	if (!('sAction' in this.opt) || this.opt.sAction === null)
1213
		this.opt.sAction = 'messageicons;board=' + this.opt.iBoardId;
1214
1215
	this.initIcons();
1216
}
1217
1218
// Replace all message icons by icons with hoverable and clickable div's.
1219
IconList.prototype.initIcons = function ()
1220
{
1221
	for (var i = document.images.length - 1, iPrefixLength = this.opt.sIconIdPrefix.length; i >= 0; i--)
1222
		if (document.images[i].id.substr(0, iPrefixLength) === this.opt.sIconIdPrefix)
1223
			setOuterHTML(document.images[i], '<div title="' + this.opt.sLabelIconList + '" onclick="' + this.opt.sBackReference + '.openPopup(this, ' + document.images[i].id.substr(iPrefixLength) + ')" onmouseover="' + this.opt.sBackReference + '.onBoxHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onBoxHover(this, false)" style="background: ' + this.opt.sBoxBackground + '; cursor: pointer; padding: 2px; margin: 0 auto; vertical-align: top"><img src="' + document.images[i].src + '" alt="' + document.images[i].alt + '" id="' + document.images[i].id + '" style="vertical-align: top; margin: 0 auto; padding: 0 2px;" /></div>');
1224
};
1225
1226
// Event for the mouse hovering over the original icon.
1227
IconList.prototype.onBoxHover = function (oDiv, bMouseOver)
1228
{
1229
	oDiv.style.border = bMouseOver ? this.opt.iBoxBorderWidthHover + 'px solid ' + this.opt.sBoxBorderColorHover : '';
1230
	oDiv.style.background = bMouseOver ? this.opt.sBoxBackgroundHover : this.opt.sBoxBackground;
1231
	oDiv.style.padding = bMouseOver ? (2 - this.opt.iBoxBorderWidthHover) + 'px' : '2px';
1232
};
1233
1234
// Show the list of icons after the user clicked the original icon.
1235
IconList.prototype.openPopup = function (oDiv, iMessageId)
1236
{
1237
	this.iCurMessageId = iMessageId;
1238
1239
	if (!this.bListLoaded && this.oContainerDiv === null)
1240
	{
1241
		// Create a container div.
1242
		this.oContainerDiv = document.createElement('div');
1243
		this.oContainerDiv.id = 'iconList';
1244
		this.oContainerDiv.style.display = 'none';
1245
		this.oContainerDiv.style.cursor = 'pointer';
1246
		this.oContainerDiv.style.position = 'absolute';
1247
		this.oContainerDiv.style.background = this.opt.sContainerBackground;
1248
		this.oContainerDiv.style.border = this.opt.sContainerBorder;
1249
		this.oContainerDiv.style.padding = '6px 0px';
1250
		document.body.appendChild(this.oContainerDiv);
1251
1252
		// Start to fetch its contents.
1253
		ajax_indicator(true);
1254
		sendXMLDocument.call(this, elk_prepareScriptUrl(elk_scripturl) + 'action=xmlhttp;sa=' + this.opt.sAction + ';xml', '', this.onIconsReceived);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1255
1256
		createEventListener(document.body);
1257
	}
1258
1259
	// Set the position of the container.
1260
	var aPos = elk_itemPos(oDiv);
1261
1262
	this.oContainerDiv.style.top = (aPos[1] + oDiv.offsetHeight) + 'px';
1263
	this.oContainerDiv.style.left = (aPos[0] - 1) + 'px';
1264
	this.oClickedIcon = oDiv;
1265
1266
	if (this.bListLoaded)
1267
		this.oContainerDiv.style.display = 'block';
1268
1269
	document.body.addEventListener('mousedown', this.onWindowMouseDown, false);
1270
};
1271
1272
// Setup the list of icons once it is received through xmlHTTP.
1273
IconList.prototype.onIconsReceived = function (oXMLDoc)
1274
{
1275
	var icons = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('icon'),
1276
		sItems = '';
1277
1278
	for (var i = 0, n = icons.length; i < n; i++)
1279
		sItems += '<span onmouseover="' + this.opt.sBackReference + '.onItemHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onItemHover(this, false);" onmousedown="' + this.opt.sBackReference + '.onItemMouseDown(this, \'' + icons[i].getAttribute('value') + '\');" style="padding: 2px 3px; line-height: 20px; border: ' + this.opt.sItemBorder + '; background: ' + this.opt.sItemBackground + '"><img src="' + icons[i].getAttribute('url') + '" alt="' + icons[i].getAttribute('name') + '" title="' + icons[i].firstChild.nodeValue + '" style="vertical-align: middle" /></span>';
1280
1281
	this.oContainerDiv.innerHTML = sItems;
1282
	this.oContainerDiv.style.display = 'block';
1283
	this.bListLoaded = true;
1284
1285
	if (is_ie)
1286
		this.oContainerDiv.style.width = this.oContainerDiv.clientWidth + 'px';
1287
1288
	ajax_indicator(false);
1289
};
1290
1291
// Event handler for hovering over the icons.
1292
IconList.prototype.onItemHover = function (oDiv, bMouseOver)
1293
{
1294
	oDiv.style.background = bMouseOver ? this.opt.sItemBackgroundHover : this.opt.sItemBackground;
1295
	oDiv.style.border = bMouseOver ? this.opt.sItemBorderHover : this.opt.sItemBorder;
1296
1297
	if (this.iCurTimeout !== 0)
1298
		window.clearTimeout(this.iCurTimeout);
1299
1300
	if (bMouseOver)
1301
		this.onBoxHover(this.oClickedIcon, true);
1302
	else
1303
		this.iCurTimeout = window.setTimeout(this.opt.sBackReference + '.collapseList();', 500);
1304
};
1305
1306
// Event handler for clicking on one of the icons.
1307
IconList.prototype.onItemMouseDown = function (oDiv, sNewIcon)
1308
{
1309
	if (this.iCurMessageId !== 0)
1310
	{
1311
		ajax_indicator(true);
1312
		this.tmpMethod = getXMLDocument;
1313
		var oXMLDoc = this.tmpMethod(elk_prepareScriptUrl(elk_scripturl) + 'action=jsmodify;topic=' + this.opt.iTopicId + ';msg=' + this.iCurMessageId + ';' + elk_session_var + '=' + elk_session_id + ';icon=' + sNewIcon + ';xml');
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_var seems to be never declared. If this is a global, consider adding a /** global: elk_session_var */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_id seems to be never declared. If this is a global, consider adding a /** global: elk_session_id */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1314
		delete this.tmpMethod;
1315
		ajax_indicator(false);
1316
1317
		var oMessage = oXMLDoc.responseXML.getElementsByTagName('elk')[0].getElementsByTagName('message')[0];
1318
		if (oMessage.getElementsByTagName('error').length === 0)
1319
		{
1320
			if ((this.opt.bShowModify && oMessage.getElementsByTagName('modified').length !== 0) && (document.getElementById('modified_' + this.iCurMessageId) !== null))
1321
				document.getElementById('modified_' + this.iCurMessageId).innerHTML = oMessage.getElementsByTagName('modified')[0].childNodes[0].nodeValue;
1322
1323
			this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1324
		}
1325
	}
1326
	else
1327
	{
1328
		this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1329
		if ('sLabelIconBox' in this.opt)
1330
			document.getElementById(this.opt.sLabelIconBox).value = sNewIcon;
1331
	}
1332
};
1333
1334
// Event handler for clicking outside the list (will make the list disappear).
1335
IconList.prototype.onWindowMouseDown = function ()
1336
{
1337
	for (var i = aIconLists.length - 1; i >= 0; i--)
1338
	{
1339
		aIconLists[i].funcParent.tmpMethod = aIconLists[i].collapseList;
1340
		aIconLists[i].funcParent.tmpMethod();
1341
		delete aIconLists[i].funcParent.tmpMethod;
1342
	}
1343
};
1344
1345
// Collapse the list of icons.
1346
IconList.prototype.collapseList = function()
1347
{
1348
	this.onBoxHover(this.oClickedIcon, false);
1349
	this.oContainerDiv.style.display = 'none';
1350
	this.iCurMessageId = 0;
1351
	document.body.removeEventListener('mousedown', this.onWindowMouseDown, false);
1352
};
1353
1354
/**
1355
 * Short function for finding the actual screen position of an item.
1356
 * Used for example to position the suggest member name box
1357
 *
1358
 * @param {object} itemHandle
1359
 */
1360
function elk_itemPos(itemHandle)
1361
{
1362
	var itemX = 0,
1363
		itemY = 0;
1364
1365
	if ('offsetParent' in itemHandle)
1366
	{
1367
		itemX = itemHandle.offsetLeft;
1368
		itemY = itemHandle.offsetTop;
1369
1370
		while (itemHandle.offsetParent && typeof(itemHandle.offsetParent) === 'object')
1371
		{
1372
			itemHandle = itemHandle.offsetParent;
1373
			itemX += itemHandle.offsetLeft;
1374
			itemY += itemHandle.offsetTop;
1375
		}
1376
	}
1377
	else if ('x' in itemHandle)
1378
	{
1379
		itemX = itemHandle.x;
1380
		itemY = itemHandle.y;
1381
	}
1382
1383
	return [itemX, itemY];
1384
}
1385
1386
/**
1387
 * This function takes the script URL and prepares it to allow the query string to be appended to it.
1388
 *
1389
 * @param {string} sUrl
1390
 */
1391
function elk_prepareScriptUrl(sUrl)
1392
{
1393
	return sUrl.indexOf('?') === -1 ? sUrl + '?' : sUrl + (sUrl.charAt(sUrl.length - 1) === '?' || sUrl.charAt(sUrl.length - 1) === '&' || sUrl.charAt(sUrl.length - 1) === ';' ? '' : ';');
1394
}
1395
1396
/**
1397
 * Load Event function, adds new events to the window onload control
1398
 *
1399
 * @param {object} fNewOnload function object to call
1400
 *
1401
 * @deprecated aince 2.0; use window.addEventListener("load", fNewOnload)
1402
 */
1403
function addLoadEvent(fNewOnload)
1404
{
1405
	window.addEventListener("load", fNewOnload);
1406
}
1407
1408
/**
1409
 * Get the text in a code tag by selecting the [select] in the code header
1410
 *
1411
 * @param {object} oCurElement
1412
 * @param {boolean} bActOnElement the passed element contains the code
1413
 */
1414
function elkSelectText(oCurElement, bActOnElement)
1415
{
1416
	var oCodeArea = null;
0 ignored issues
show
Unused Code introduced by
The assignment to oCodeArea seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1417
1418
	// The place we're looking for is one div up, and next door - if it's auto detect.
1419
	if (typeof(bActOnElement) === 'boolean' && bActOnElement)
1420
		oCodeArea = document.getElementById(oCurElement);
1421
	else
1422
		oCodeArea = oCurElement.parentNode.nextSibling;
1423
1424
	// Did not find it, bail
1425
	if (typeof(oCodeArea) !== 'object' || oCodeArea === null)
1426
		return false;
1427
1428
	// Start off with internet explorer < 9.
1429
	if ('createTextRange' in document.body)
1430
	{
1431
		var oCurRange = document.body.createTextRange();
1432
		oCurRange.moveToElementText(oCodeArea);
1433
		oCurRange.select();
1434
	}
1435
	// All the rest
1436
	else if (window.getSelection)
1437
	{
1438
		var oCurSelection = window.getSelection(),
1439
			curRange = document.createRange();
1440
1441
			curRange.selectNodeContents(oCodeArea);
1442
			oCurSelection.removeAllRanges();
1443
			oCurSelection.addRange(curRange);
1444
	}
1445
1446
	return false;
1447
}
1448
1449
/**
1450
 * A function needed to discern HTML entities from non-western characters.
1451
 *
1452
 * @param {string} sFormName
1453
 * @param {Array.} aElementNames
1454
 * @param {string} sMask
1455
 */
1456
function smc_saveEntities(sFormName, aElementNames, sMask) {
1457
	var i = 0,
1458
		n = 0;
1459
1460
	if (typeof(sMask) === 'string') {
1461
		for (i = 0, n = document.forms[sFormName].elements.length; i < n; i++) {
1462
			if (document.forms[sFormName].elements[i].id.substr(0, sMask.length) === sMask) {
1463
				aElementNames[aElementNames.length] = document.forms[sFormName].elements[i].name;
1464
			}
1465
		}
1466
	}
1467
1468
	for (i = 0, n = aElementNames.length; i < n; i++) {
1469
		if (aElementNames[i] in document.forms[sFormName]) {
1470
			// Handle the editor.
1471
			if (typeof post_box_name !== 'undefined' && aElementNames[i] === post_box_name && $editor_data[post_box_name] !== undefined) {
0 ignored issues
show
Bug introduced by
The variable post_box_name seems to be never declared. If this is a global, consider adding a /** global: post_box_name */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1472
				document.forms[sFormName][aElementNames[i]].value = $editor_data[post_box_name].val().replace(/&#/g, '&#38;#');
1473
				$editor_data[post_box_name].val(document.forms[sFormName][aElementNames[i]].value);
1474
			}
1475
			else {
1476
				document.forms[sFormName][aElementNames[i]].value = document.forms[sFormName][aElementNames[i]].value.replace(/&#/g, '&#38;#');
1477
			}
1478
		}
1479
	}
1480
}
1481
1482
/**
1483
 * Enable / Disable the "Only show the results after the poll has expired."
1484
 * based on if they have entered a time limit or not
1485
 *
1486
 * @returns {undefined}
1487
 */
1488
function pollOptions()
1489
{
1490
	var expire_time = document.getElementById('poll_expire');
1491
1492
	if (isEmptyText(expire_time) || expire_time.value === 0)
1493
	{
1494
		document.forms[form_name].poll_hide[2].disabled = true;
0 ignored issues
show
Bug introduced by
The variable form_name seems to be never declared. If this is a global, consider adding a /** global: form_name */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1495
		if (document.forms[form_name].poll_hide[2].checked)
1496
			document.forms[form_name].poll_hide[1].checked = true;
1497
	}
1498
	else
1499
		document.forms[form_name].poll_hide[2].disabled = false;
1500
}
1501
1502
/**
1503
 * Generate the number of days in a given month for a given year
1504
 * Used to populate the day pulldown in the calendar
1505
 *
1506
 * @param {int} [offset] optional
1507
 */
1508
function generateDays(offset)
1509
{
1510
	// Work around JavaScript's lack of support for default values...
1511
	offset = typeof(offset) !== 'undefined' ? offset : '';
1512
1513
	var days = 0,
1514
		selected = 0,
1515
		dayElement = document.getElementById("day" + offset),
1516
		yearElement = document.getElementById("year" + offset),
1517
		monthElement = document.getElementById("month" + offset),
1518
		monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1519
1520
	monthLength[1] = 28;
1521
	if (yearElement.options[yearElement.selectedIndex].value % 4 === 0)
1522
		monthLength[1] = 29;
1523
1524
	selected = dayElement.selectedIndex;
1525
	while (dayElement.options.length)
1526
		dayElement.options[0] = null;
1527
1528
	days = monthLength[monthElement.value - 1];
1529
1530
	for (var i = 1; i <= days; i++)
1531
		dayElement.options[dayElement.length] = new Option(i, i);
0 ignored issues
show
Bug introduced by
The variable Option seems to be never declared. If this is a global, consider adding a /** global: Option */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1532
1533
	if (selected < days)
1534
		dayElement.selectedIndex = selected;
1535
}
1536
1537
/**
1538
 * Enable/disable the board selection list when a calendar event is linked, or not, to a post
1539
 *
1540
 * @param {string} form
1541
 */
1542
function toggleLinked(form)
1543
{
1544
	form.board.disabled = !form.link_to_board.checked;
1545
}
1546
1547
/**
1548
 * load event for search for and PM search, un escapes any existing search
1549
 * value for back button or change search etc.
1550
 */
1551
function initSearch()
1552
{
1553
	if (document.forms.searchform.search.value.indexOf("%u") !== -1)
1554
		document.forms.searchform.search.value = decodeURI(document.forms.searchform.search.value);
1555
}
1556
1557
/**
1558
 * Checks or unchecks the list of available boards
1559
 *
1560
 * @param {type} ids
1561
 * @param {string} aFormName
1562
 * @param {string} sInputName
1563
 */
1564
function selectBoards(ids, aFormName, sInputName)
1565
{
1566
	var toggle = true,
1567
		i = 0;
1568
1569
	for (var f = 0, max = document.forms.length; f < max; f++)
1570
	{
1571
		if (document.forms[f].name == aFormName)
1572
		{
1573
			aForm = document.forms[f];
0 ignored issues
show
Bug introduced by
The variable aForm seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.aForm.
Loading history...
1574
			break;
1575
		}
1576
	}
1577
	if (typeof aForm == 'undefined')
1578
		return;
1579
1580
	for (i = 0; i < ids.length; i++)
1581
		toggle = toggle && aForm[sInputName + '[' + ids[i] + ']'].checked;
1582
1583
	for (i = 0; i < ids.length; i++)
1584
		aForm[sInputName + '[' + ids[i] + ']'].checked = !toggle;
1585
}
1586
1587
/**
1588
 * Expands or collapses a container
1589
 *
1590
 * @param {string} id
1591
 * @param {string} icon
1592
 * @param {int} speed
1593
 */
1594
function expandCollapse(id, icon, speed)
1595
{
1596
	var	oId = $('#' + id);
1597
1598
	icon = icon || false;
1599
	speed = speed || 300;
1600
1601
	// Change the icon on the box as well?
1602
	if (icon)
1603
		$('#' + icon).attr("src", elk_images_url + (oId.is(":hidden") !== true ? "/selected.png" : "/selected_open.png"));
0 ignored issues
show
Bug introduced by
The variable elk_images_url seems to be never declared. If this is a global, consider adding a /** global: elk_images_url */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1604
1605
	// Open or collapse the content id
1606
	oId.slideToggle(speed);
1607
}
1608
1609
/**
1610
 * Highlight a selection box by adding the highlight2 class
1611
 *
1612
 * @param {string} container_id
1613
 */
1614
function initHighlightSelection(container_id)
1615
{
1616
	$('#' + container_id + ' [name="def_language"]').on('click', function (ev) {
0 ignored issues
show
Unused Code introduced by
The parameter ev is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1617
		$('#' + container_id + ' .standard_row').removeClass('highlight2');
1618
		$(this).parent().parent().addClass('highlight2');
1619
	});
1620
}
1621
1622
/**
1623
 * Auto submits a paused form, such as a maintenance task
1624
 *
1625
 * @param {int} countdown
1626
 * @param {string} txt_message
1627
 * @param {string} [formName=autoSubmit]
0 ignored issues
show
Documentation Bug introduced by
The parameter formName=autoSubmit does not exist. Did you maybe mean formName instead?
Loading history...
1628
 */
1629
function doAutoSubmit(countdown, txt_message, formName)
1630
{
1631
	var formID = typeof(formName) !== 'undefined' ? formName : "autoSubmit";
1632
1633
	if (countdown === 0)
1634
		document.forms[formID].submit();
1635
	else if (countdown === -1)
1636
		return;
1637
1638
	document.forms[formID].cont.value = txt_message + ' (' + countdown + ')';
1639
	countdown--;
1640
1641
	setTimeout(function() {doAutoSubmit(countdown, txt_message, formID);}, 1000);
1642
}
1643