Completed
Pull Request — development (#3082)
by John
14:20
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
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...
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...
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
// @deprecated since 1.0 - innerHTML is supported everywhere.
421
function setInnerHTML(oElement, sToValue)
422
{
423
	if (oElement)
424
		oElement.innerHTML = sToValue;
425
}
426
427
function getInnerHTML(oElement)
428
{
429
	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...
430
		return oElement.innerHTML;
431
}
432
433
/**
434
 * Set the "outer" HTML of an element.
435
 *
436
 * @param {HTMLElement} oElement
437
 * @param {string} sToValue
438
 */
439
function setOuterHTML(oElement, sToValue)
440
{
441
	if ('outerHTML' in oElement)
442
		oElement.outerHTML = sToValue;
443
	else
444
	{
445
		var range = document.createRange();
446
		range.setStartBefore(oElement);
447
		oElement.parentNode.replaceChild(range.createContextualFragment(sToValue), oElement);
448
	}
449
}
450
451
/**
452
 * Checks for variable in theArray, returns true or false
453
 *
454
 * @param {string} variable
455
 * @param {string[]} theArray
456
 */
457
function in_array(variable, theArray)
458
{
459
	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...
460
		if (theArray[i] == variable)
461
			return true;
462
463
	return false;
464
}
465
466
/**
467
 * Checks for variable in theArray and returns the array key
468
 *
469
 * @param {string} variable
470
 * @param {Array.} theArray
471
 */
472
function array_search(variable, theArray)
473
{
474
	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...
475
		if (theArray[i] == variable)
476
			return i;
477
478
	return null;
479
}
480
481
/**
482
 * Find a specific radio button in its group and select it.
483
 *
484
 * @param {HTMLInputElement} oRadioGroup
485
 * @param {type} sName
486
 */
487
function selectRadioByName(oRadioGroup, sName)
488
{
489
	if (!('length' in oRadioGroup))
490
		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...
491
492
	for (var i = 0, n = oRadioGroup.length; i < n; i++)
493
		if (oRadioGroup[i].value === sName)
494
			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...
495
496
	return false;
497
}
498
499
/**
500
 * Selects all the form objects with a single click
501
 *
502
 * @param {object} oInvertCheckbox
503
 * @param {object} oForm
504
 * @param {string} sMask
505
 * @param {string} sValue
506
 */
507
function selectAllRadio(oInvertCheckbox, oForm, sMask, sValue)
508
{
509
	for (var i = 0; i < oForm.length; i++)
510
		if (oForm[i].name !== undefined && oForm[i].name.substr(0, sMask.length) == sMask && oForm[i].value == sValue)
511
			oForm[i].checked = true;
512
}
513
514
/**
515
 * Invert all check boxes at once by clicking a single checkbox.
516
 *
517
 * @param {object} oInvertCheckbox
518
 * @param {HTMLFormElement} oForm
519
 * @param {string} [sMask]
520
 * @param {boolean} [bIgnoreDisabled]
521
 */
522
function invertAll(oInvertCheckbox, oForm, sMask, bIgnoreDisabled)
523
{
524
	for (var i = 0; i < oForm.length; i++)
525
	{
526
		if (!('name' in oForm[i]) || (typeof(sMask) === 'string' && oForm[i].name.substr(0, sMask.length) !== sMask && oForm[i].id.substr(0, sMask.length) !== sMask))
527
			continue;
528
529
		if (!oForm[i].disabled || (typeof(bIgnoreDisabled) === 'boolean' && bIgnoreDisabled))
530
			oForm[i].checked = oInvertCheckbox.checked;
531
	}
532
}
533
534
/**
535
 * Keep the session alive - always!
536
 */
537
function elk_sessionKeepAlive()
538
{
539
	var curTime = new Date().getTime();
540
541
	// Prevent a Firefox bug from hammering the server.
542
	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...
543
	{
544
		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...
545
		tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=keepalive;time=' + curTime;
546
		lastKeepAliveCheck = curTime;
547
	}
548
549
	window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
550
}
551
window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
552
553
/**
554
 * Set a theme option through javascript. / ajax
555
 *
556
 * @param {string} option name being set
557
 * @param {string} value of the option
558
 * @param {string|null} theme its being set or null for all
559
 * @param {string|null} additional_vars to use in the url request that will be sent
560
 */
561
function elk_setThemeOption(option, value, theme, additional_vars)
562
{
563
	if (additional_vars === null || typeof(additional_vars) === 'undefined')
564
		additional_vars = '';
565
566
	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...
567
	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...
568
}
569
570
/**
571
 * Password hashing for user
572
 *
573
 * @param {type} doForm
574
 * @param {type} cur_session_id
575
 * @param {type} token
576
 */
577
function hashLoginPassword(doForm, cur_session_id, token)
578
{
579
	// Don't have our hash lib available?
580
	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...
581
		return;
582
583
	// Are they using an email address?
584
	if (doForm.user.value.indexOf('@') !== -1)
585
		return;
586
587
	doForm.passwrd.autocomplete = 'off';
588
589
	// Fill in the hidden fields with our sha hash
590
	doForm.hash_passwrd.value = hex_sha256(doForm.user.value.php_strtolower() + doForm.passwrd.value);
591
592
	// If the form also contains the old hash input fill it to smooth transitions
593
	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...
594
		doForm.old_hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_strtolower() + doForm.passwrd.value) + cur_session_id + (typeof token === 'undefined' ? '' : token));
595
596
	doForm.passwrd.value = doForm.passwrd.value.replace(/./g, '*');
597
}
598
599
/**
600
 * Password hashing for admin login
601
 *
602
 * @param {type} doForm
603
 * @param {type} username
604
 * @param {type} cur_session_id
605
 * @param {type} token
606
 */
607
function hashAdminPassword(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...
608
{
609
	// Missing sha256.js?
610
	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...
611
		return;
612
613
	doForm.admin_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.admin_pass.value);
614
	doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, '*');
615
}
616
617
/**
618
 * Hashing for the moderation login
619
 *
620
 * @param {type} doForm
621
 * @param {type} username
622
 * @param {type} cur_session_id
623
 * @param {type} token
624
 */
625
function hashModeratePassword(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...
626
{
627
	// Missing sha256.js?
628
	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...
629
		return;
630
631
	doForm.moderate_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.moderate_pass.value);
632
	doForm.moderate_pass.value = doForm.moderate_pass.value.replace(/./g, '*');
633
}
634
635
/**
636
 * Used by elk_Toggle to add an image to the swap/toggle array
637
 *
638
 * @param {string} sSrc
639
 */
640
function smc_preCacheImage(sSrc)
641
{
642
	if (!('smc_aCachedImages' in window))
643
		window.smc_aCachedImages = [];
644
645
	if (!in_array(sSrc, window.smc_aCachedImages))
646
	{
647
		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...
648
		oImage.src = sSrc;
649
	}
650
}
651
652
/**
653
 * smc_Cookie class.
654
 *
655
 * @param {object} oOptions
656
 */
657
function smc_Cookie(oOptions)
658
{
659
	this.opt = oOptions;
660
	this.oCookies = {};
661
	this.init();
662
}
663
664
smc_Cookie.prototype.init = function()
665
{
666
	if ('cookie' in document && document.cookie !== '')
667
	{
668
		var aCookieList = document.cookie.split(';');
669
		for (var i = 0, n = aCookieList.length; i < n; i++)
670
		{
671
			var aNameValuePair = aCookieList[i].split('=');
672
			this.oCookies[aNameValuePair[0].replace(/^\s+|\s+$/g, '')] = decodeURIComponent(aNameValuePair[1]);
673
		}
674
	}
675
};
676
677
smc_Cookie.prototype.get = function(sKey)
678
{
679
	return sKey in this.oCookies ? this.oCookies[sKey] : null;
680
};
681
682
smc_Cookie.prototype.set = function(sKey, sValue)
683
{
684
	document.cookie = sKey + '=' + encodeURIComponent(sValue);
685
};
686
687
/**
688
 * elk_Toggle class.
689
 *
690
 * Collapses a section of the page
691
 * Swaps the collapsed section class or image to indicate the state
692
 * Updates links to indicate state and allow reversal of the action
693
 * Saves state in a cookie and/or in a theme setting option so the last state
694
 * is remembered for the user.
695
 *
696
 * @param {object} oOptions
697
 * @returns {elk_Toggle}
698
 */
699
function elk_Toggle(oOptions)
700
{
701
	this.opt = oOptions;
702
	this.bCollapsed = false;
703
	this.oCookie = null;
704
	this.init();
705
}
706
707
// Initialize the toggle class
708
elk_Toggle.prototype.init = function()
709
{
710
	var i = 0,
711
		n = 0;
712
713
	// The master switch can disable this toggle fully.
714
	if ('bToggleEnabled' in this.opt && !this.opt.bToggleEnabled)
715
		return;
716
717
	// If cookies are enabled and they were set, override the initial state.
718
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
719
	{
720
		// Initialize the cookie handler.
721
		this.oCookie = new smc_Cookie({});
722
723
		// Check if the cookie is set.
724
		var cookieValue = this.oCookie.get(this.opt.oCookieOptions.sCookieName);
725
		if (cookieValue !== null)
726
			this.opt.bCurrentlyCollapsed = cookieValue === '1';
727
	}
728
729
	// If the init state is set to be collapsed, collapse it.
730
	if (this.opt.bCurrentlyCollapsed)
731
		this.changeState(true, true);
732
733
	// Initialize the images to be clickable.
734
	if ('aSwapImages' in this.opt)
735
	{
736
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
737
		{
738
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
739
			if (typeof(oImage) === 'object' && oImage !== null)
740
			{
741
				// Display the image in case it was hidden.
742
				if (getComputedStyle(oImage).getPropertyValue("display") === 'none')
743
					oImage.style.display = 'inline';
744
745
				oImage.instanceRef = this;
746
				oImage.onclick = function () {this.instanceRef.toggle();this.blur();};
747
				oImage.style.cursor = 'pointer';
748
749
				// Pre-load the collapsed image.
750
				smc_preCacheImage(this.opt.aSwapImages[i].srcCollapsed);
751
			}
752
		}
753
	}
754
	// No images to swap, perhaps they want to swap the class?
755
	else if ('aSwapClasses' in this.opt)
756
	{
757
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
758
		{
759
			var oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
760
			if (typeof(oContainer) === 'object' && oContainer !== null)
761
			{
762
				// Display the image in case it was hidden.
763
				if (getComputedStyle(oContainer).getPropertyValue("display") === 'none')
764
					oContainer.style.display = 'block';
765
766
				oContainer.instanceRef = this;
767
768
				oContainer.onclick = function () {
769
					this.instanceRef.toggle();
770
					this.blur();
771
				};
772
				oContainer.style.cursor = 'pointer';
773
			}
774
		}
775
	}
776
777
	// Initialize links.
778
	if ('aSwapLinks' in this.opt)
779
	{
780
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
781
		{
782
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
783
			if (typeof(oLink) === 'object' && oLink !== null)
784
			{
785
				// Display the link in case it was hidden.
786
				if (getComputedStyle(oLink).getPropertyValue("display") === 'none')
787
					oLink.style.display = 'inline-block';
788
789
				oLink.instanceRef = this;
790
				oLink.onclick = function () {
791
					this.instanceRef.toggle();
792
					this.blur();
793
					return false;
794
				};
795
			}
796
		}
797
	}
798
};
799
800
/**
801
 * Collapse or expand the section.
802
 *
803
 * @param {boolean} bCollapse
804
 * @param {boolean} [bInit]
805
 */
806
elk_Toggle.prototype.changeState = function(bCollapse, bInit)
807
{
808
	var i = 0,
809
		n = 0,
810
		oContainer;
811
812
	// Default bInit to false.
813
	bInit = typeof(bInit) !== 'undefined';
814
815
	// Handle custom function hook before collapse.
816
	if (!bInit && bCollapse && 'funcOnBeforeCollapse' in this.opt)
817
	{
818
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
819
		this.tmpMethod();
820
		delete this.tmpMethod;
821
	}
822
	// Handle custom function hook before expand.
823
	else if (!bInit && !bCollapse && 'funcOnBeforeExpand' in this.opt)
824
	{
825
		this.tmpMethod = this.opt.funcOnBeforeExpand;
826
		this.tmpMethod();
827
		delete this.tmpMethod;
828
	}
829
830
	// Loop through all the items that need to be toggled.
831
	if ('aSwapImages' in this.opt)
832
	{
833
		// Swapping images on a click
834
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
835
		{
836
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
837
			if (typeof(oImage) === 'object' && oImage !== null)
838
			{
839
				// Only (re)load the image if it's changed.
840
				var sTargetSource = bCollapse ? this.opt.aSwapImages[i].srcCollapsed : this.opt.aSwapImages[i].srcExpanded;
841
				if (oImage.src != sTargetSource)
842
					oImage.src = sTargetSource;
843
844
				oImage.alt = oImage.title = bCollapse ? this.opt.aSwapImages[i].altCollapsed : this.opt.aSwapImages[i].altExpanded;
845
			}
846
		}
847
	}
848
	else if ('aSwapClasses' in this.opt)
849
	{
850
		// Or swapping the classes
851
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
852
		{
853
			oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
854
			if (typeof(oContainer) === 'object' && oContainer !== null)
855
			{
856
				// Only swap the class if the state changed
857
				var sTargetClass = bCollapse ? this.opt.aSwapClasses[i].classCollapsed : this.opt.aSwapClasses[i].classExpanded;
858
				if (oContainer.className !== sTargetClass)
859
					oContainer.className = sTargetClass;
860
861
				// And show the new title
862
				oContainer.title = oContainer.title = bCollapse ? this.opt.aSwapClasses[i].titleCollapsed : this.opt.aSwapClasses[i].titleExpanded;
863
			}
864
		}
865
	}
866
867
	// Loop through all the links that need to be toggled.
868
	if ('aSwapLinks' in this.opt)
869
	{
870
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
871
		{
872
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
873
			if (typeof(oLink) === 'object' && oLink !== null)
874
				oLink.innerHTML = bCollapse ? this.opt.aSwapLinks[i].msgCollapsed : this.opt.aSwapLinks[i].msgExpanded;
875
		}
876
	}
877
878
	// Now go through all the sections to be collapsed.
879
	for (i = 0, n = this.opt.aSwappableContainers.length; i < n; i++)
880
	{
881
		if (this.opt.aSwappableContainers[i] === null)
882
			continue;
883
884
		oContainer = document.getElementById(this.opt.aSwappableContainers[i]);
885
		if (typeof(oContainer) === 'object' && oContainer !== null)
886
		{
887
			if (bCollapse)
888
				$(oContainer).slideUp();
889
			else
890
				$(oContainer).slideDown();
891
		}
892
	}
893
894
	// Update the new state.
895
	this.bCollapsed = bCollapse;
896
897
	// Update the cookie, if desired.
898
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
899
		this.oCookie.set(this.opt.oCookieOptions.sCookieName, this.bCollapsed ? '1' : '0');
900
901
	if (!bInit && 'oThemeOptions' in this.opt && this.opt.oThemeOptions.bUseThemeSettings)
902
		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);
903
};
904
905
elk_Toggle.prototype.toggle = function()
906
{
907
	// Change the state by reversing the current state.
908
	this.changeState(!this.bCollapsed);
909
};
910
911
/**
912
 * Creates and shows or hides the sites ajax in progress indicator
913
 *
914
 * @param {boolean} turn_on
915
 * @returns {undefined}
916
 */
917
function ajax_indicator(turn_on)
918
{
919
	if (ajax_indicator_ele === null)
920
	{
921
		ajax_indicator_ele = document.getElementById('ajax_in_progress');
922
923
		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...
924
		{
925
			create_ajax_indicator_ele();
926
		}
927
	}
928
929
	if (ajax_indicator_ele !== null)
930
	{
931
		ajax_indicator_ele.style.display = turn_on ? 'block' : 'none';
932
	}
933
}
934
935
/**
936
 * Creates the ajax notification div and adds it to the current screen
937
 */
938
function create_ajax_indicator_ele()
939
{
940
	// Create the div for the indicator.
941
	ajax_indicator_ele = document.createElement('div');
942
943
	// Set the id so it'll load the style properly.
944
	ajax_indicator_ele.id = 'ajax_in_progress';
945
946
	// Add the image in and link to turn it off.
947
	var cancel_link = document.createElement('a');
948
	cancel_link.href = 'javascript:ajax_indicator(false)';
0 ignored issues
show
Coding Style introduced by
Script urls should not be used.
Loading history...
949
950
	var cancel_img = document.createElement('img');
951
	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...
952
953
	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...
954
	{
955
		cancel_img.alt = ajax_notification_cancel_text;
956
		cancel_img.title = ajax_notification_cancel_text;
957
	}
958
959
	// Add the cancel link and image to the indicator.
960
	cancel_link.appendChild(cancel_img);
961
	ajax_indicator_ele.appendChild(cancel_link);
962
963
	// Set the text.  (Note:  You MUST append here and not overwrite.)
964
	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...
965
966
	// Finally attach the element to the body.
967
	document.body.appendChild(ajax_indicator_ele);
968
}
969
970
/**
971
 * Creates and event listener object for a given object
972
 * Object events can then be added with addEventListener
973
 *
974
 * @param {HTMLElement} oTarget
975
 */
976
function createEventListener(oTarget)
977
{
978
	if (!('addEventListener' in oTarget))
979
	{
980
		if (oTarget.attachEvent)
981
		{
982
			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...
983
				oTarget.attachEvent('on' + sEvent, funcHandler);
984
			};
985
986
			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...
987
				oTarget.detachEvent('on' + sEvent, funcHandler);
988
			};
989
		}
990
		else
991
		{
992
			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...
993
				oTarget['on' + sEvent] = funcHandler;
994
			};
995
996
			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...
997
				oTarget['on' + sEvent] = null;
998
			};
999
		}
1000
	}
1001
}
1002
1003
1004
/**
1005
 * This function will retrieve the contents needed for the jump to boxes.
1006
 */
1007
function grabJumpToContent() {
1008
	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...
1009
1010
	return false;
1011
}
1012
1013
/**
1014
 * Callback function for loading the jumpto box
1015
 *
1016
 * @param {object} oXMLDoc
1017
 */
1018
function onJumpReceived(oXMLDoc) {
1019
	var aBoardsAndCategories = [],
1020
		i,
1021
		n,
1022
		items = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('item');
1023
1024
	for (i = 0, n = items.length; i < n; i++)
1025
	{
1026
		aBoardsAndCategories[aBoardsAndCategories.length] = {
1027
			id: parseInt(items[i].getAttribute('id')),
1028
			isCategory: items[i].getAttribute('type') === 'category',
1029
			name: items[i].firstChild.nodeValue.removeEntities(),
1030
			is_current: false,
1031
			childLevel: parseInt(items[i].getAttribute('childlevel'))
1032
		};
1033
	}
1034
1035
	for (i = 0, n = aJumpTo.length; i < n; i++)
1036
		aJumpTo[i].fillSelect(aBoardsAndCategories);
1037
}
1038
1039
/**
1040
 * JumpTo class.
1041
 *
1042
 * Passed object of options can contain:
1043
 * sContainerId: container id to place the list in
1044
 * sClassName: class name to assign items added to the dropdown
1045
 * sJumpToTemplate: html template to wrap the %dropdown_list%
1046
 * iCurBoardId: id of the board current active
1047
 * iCurBoardChildLevel: child level of the currently active board
1048
 * sCurBoardName: name of the currently active board
1049
 * sBoardChildLevelIndicator: text/characters used to indent
1050
 * sBoardPrefix: arrow head
1051
 * sCatPrefix: Prefix to use in from of the categories
1052
 * bNoRedirect: boolean for redirect
1053
 * bDisabled: boolean for disabled
1054
 * sCustomName: custom name to prefix for the select name=""
1055
 * sGoButtonLabel: name for the goto button
1056
 *
1057
 * @param {type} oJumpToOptions
1058
 */
1059
// This'll contain all JumpTo objects on the page.
1060
var aJumpTo = [];
1061
function JumpTo(oJumpToOptions)
1062
{
1063
	this.opt = oJumpToOptions;
1064
	this.dropdownList = null;
1065
	this.showSelect();
1066
1067
	createEventListener(this.dropdownList);
1068
1069
	if (is_mobile && is_touch)
1070
		this.dropdownList.addEventListener('touchstart', grabJumpToContent);
1071
	else
1072
		this.dropdownList.addEventListener('mouseenter', grabJumpToContent);
1073
}
1074
1075
// Remove all the options in the select. Method of the JumpTo class.
1076
JumpTo.prototype.removeAll = function ()
1077
{
1078
//	var dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1079
for (var i = this.dropdownList.options.length; i > 0; i--)
1080
		this.dropdownList.remove(i - 1);
1081
};
1082
1083
// Show the initial select box (onload). Method of the JumpTo class.
1084
JumpTo.prototype.showSelect = function ()
1085
{
1086
	var sChildLevelPrefix = '';
1087
1088
	for (var i = this.opt.iCurBoardChildLevel; i > 0; i--)
1089
		sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1090
1091
	if (sChildLevelPrefix !== '')
1092
		sChildLevelPrefix += this.opt.sBoardPrefix;
1093
1094
	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...
1095
	this.dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1096
};
1097
1098
// Fill the jump to box with entries. Method of the JumpTo class.
1099
JumpTo.prototype.fillSelect = function (aBoardsAndCategories)
1100
{
1101
	this.removeAll();
1102
1103
	if (is_mobile && is_touch)
1104
		this.dropdownList.removeEventListener('touchstart', grabJumpToContent);
1105
	else
1106
		this.dropdownList.removeEventListener('mouseenter', grabJumpToContent);
1107
1108
	// Create a document fragment that'll allowing inserting big parts at once.
1109
	var oListFragment = document.createDocumentFragment(),
1110
		oOptgroupFragment = document.createElement('optgroup');
1111
1112
	// Loop through all items to be added.
1113
	for (var i = 0, n = aBoardsAndCategories.length; i < n; i++)
1114
	{
1115
		var j,
1116
			sChildLevelPrefix = '',
1117
			oOption,
1118
			oText;
1119
1120
		if (aBoardsAndCategories[i].isCategory)
1121
		{
1122
			oOptgroupFragment = document.createElement('optgroup');
1123
			oOptgroupFragment.label = aBoardsAndCategories[i].name;
1124
			oListFragment.appendChild(oOptgroupFragment);
1125
			continue;
1126
		}
1127
		else
1128
		{
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...
1129
			for (j = aBoardsAndCategories[i].childLevel, sChildLevelPrefix = ''; j > 0; j--)
1130
				sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1131
1132
			if (sChildLevelPrefix !== '')
1133
				sChildLevelPrefix += this.opt.sBoardPrefix;
1134
		}
1135
1136
		oOption = document.createElement('option');
1137
		oText = document.createElement('span');
1138
		oText.innerHTML = sChildLevelPrefix + aBoardsAndCategories[i].name;
1139
1140
		if (aBoardsAndCategories[i].id === this.opt.iCurBoardId)
1141
			oOption.selected = 'selected';
1142
1143
		oOption.appendChild(oText);
1144
1145
		if (!this.opt.bNoRedirect)
1146
		{
1147
			oOption.value = '?board=' + aBoardsAndCategories[i].id + '.0';
1148
		}
1149
		else
1150
		{
1151
			oOption.value = aBoardsAndCategories[i].id;
1152
		}
1153
1154
		oOptgroupFragment.appendChild(oOption);
1155
	}
1156
1157
	// Add the remaining items after the currently selected item.
1158
	this.dropdownList.appendChild(oListFragment);
1159
1160
	// Add an onchange action
1161
	if (!this.opt.bNoRedirect)
1162
		this.dropdownList.onchange = function() {
1163
			if (this.selectedIndex > 0 && this.options[this.selectedIndex].value)
1164
				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...
1165
		};
1166
1167
	// Handle custom function hook before showing the new select.
1168
	if ('funcOnBeforeCollapse' in this.opt)
1169
	{
1170
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
1171
		this.tmpMethod(this);
1172
		delete this.tmpMethod;
1173
	}
1174
};
1175
1176
/**
1177
 * IconList object.
1178
 *
1179
 * Allows clicking on a icon to expand out the available options to change
1180
 * Change is done via ajax
1181
 * Used for topic icon and member group icon selections
1182
 *
1183
 * Available options
1184
 *	sBackReference:
1185
 *	sIconIdPrefix:
1186
 *	bShowModify:
1187
 *	iBoardId:
1188
 *	iTopicId:
1189
 *	sAction:
1190
 *	sLabelIconList:
1191
 *
1192
 * The following are style elements that can be passed
1193
 *	sBoxBackground:
1194
 *	sBoxBackgroundHover:
1195
 *	iBoxBorderWidthHover:
1196
 *	sBoxBorderColorHover:
1197
 *	sContainerBackground:
1198
 *	sContainerBorder:
1199
 *	sItemBorder:
1200
 *	sItemBorderHover:
1201
 *	sItemBackground:
1202
 *	sItemBackgroundHover:
1203
 *
1204
 * @param {object} oOptions
1205
 */
1206
// A global array containing all IconList objects.
1207
var aIconLists = [];
1208
function IconList(oOptions)
1209
{
1210
	this.opt = oOptions;
1211
	this.bListLoaded = false;
1212
	this.oContainerDiv = null;
1213
	this.funcMousedownHandler = null;
1214
	this.funcParent = this;
1215
	this.iCurMessageId = 0;
1216
	this.iCurTimeout = 0;
1217
1218
	// Set a default Action
1219
	if (!('sAction' in this.opt) || this.opt.sAction === null)
1220
		this.opt.sAction = 'messageicons;board=' + this.opt.iBoardId;
1221
1222
	this.initIcons();
1223
}
1224
1225
// Replace all message icons by icons with hoverable and clickable div's.
1226
IconList.prototype.initIcons = function ()
1227
{
1228
	for (var i = document.images.length - 1, iPrefixLength = this.opt.sIconIdPrefix.length; i >= 0; i--)
1229
		if (document.images[i].id.substr(0, iPrefixLength) === this.opt.sIconIdPrefix)
1230
			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>');
1231
};
1232
1233
// Event for the mouse hovering over the original icon.
1234
IconList.prototype.onBoxHover = function (oDiv, bMouseOver)
1235
{
1236
	oDiv.style.border = bMouseOver ? this.opt.iBoxBorderWidthHover + 'px solid ' + this.opt.sBoxBorderColorHover : '';
1237
	oDiv.style.background = bMouseOver ? this.opt.sBoxBackgroundHover : this.opt.sBoxBackground;
1238
	oDiv.style.padding = bMouseOver ? (2 - this.opt.iBoxBorderWidthHover) + 'px' : '2px';
1239
};
1240
1241
// Show the list of icons after the user clicked the original icon.
1242
IconList.prototype.openPopup = function (oDiv, iMessageId)
1243
{
1244
	this.iCurMessageId = iMessageId;
1245
1246
	if (!this.bListLoaded && this.oContainerDiv === null)
1247
	{
1248
		// Create a container div.
1249
		this.oContainerDiv = document.createElement('div');
1250
		this.oContainerDiv.id = 'iconList';
1251
		this.oContainerDiv.style.display = 'none';
1252
		this.oContainerDiv.style.cursor = 'pointer';
1253
		this.oContainerDiv.style.position = 'absolute';
1254
		this.oContainerDiv.style.background = this.opt.sContainerBackground;
1255
		this.oContainerDiv.style.border = this.opt.sContainerBorder;
1256
		this.oContainerDiv.style.padding = '6px 0px';
1257
		document.body.appendChild(this.oContainerDiv);
1258
1259
		// Start to fetch its contents.
1260
		ajax_indicator(true);
1261
		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...
1262
1263
		createEventListener(document.body);
1264
	}
1265
1266
	// Set the position of the container.
1267
	var aPos = elk_itemPos(oDiv);
1268
1269
	this.oContainerDiv.style.top = (aPos[1] + oDiv.offsetHeight) + 'px';
1270
	this.oContainerDiv.style.left = (aPos[0] - 1) + 'px';
1271
	this.oClickedIcon = oDiv;
1272
1273
	if (this.bListLoaded)
1274
		this.oContainerDiv.style.display = 'block';
1275
1276
	document.body.addEventListener('mousedown', this.onWindowMouseDown, false);
1277
};
1278
1279
// Setup the list of icons once it is received through xmlHTTP.
1280
IconList.prototype.onIconsReceived = function (oXMLDoc)
1281
{
1282
	var icons = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('icon'),
1283
		sItems = '';
1284
1285
	for (var i = 0, n = icons.length; i < n; i++)
1286
		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>';
1287
1288
	this.oContainerDiv.innerHTML = sItems;
1289
	this.oContainerDiv.style.display = 'block';
1290
	this.bListLoaded = true;
1291
1292
	if (is_ie)
1293
		this.oContainerDiv.style.width = this.oContainerDiv.clientWidth + 'px';
1294
1295
	ajax_indicator(false);
1296
};
1297
1298
// Event handler for hovering over the icons.
1299
IconList.prototype.onItemHover = function (oDiv, bMouseOver)
1300
{
1301
	oDiv.style.background = bMouseOver ? this.opt.sItemBackgroundHover : this.opt.sItemBackground;
1302
	oDiv.style.border = bMouseOver ? this.opt.sItemBorderHover : this.opt.sItemBorder;
1303
1304
	if (this.iCurTimeout !== 0)
1305
		window.clearTimeout(this.iCurTimeout);
1306
1307
	if (bMouseOver)
1308
		this.onBoxHover(this.oClickedIcon, true);
1309
	else
1310
		this.iCurTimeout = window.setTimeout(this.opt.sBackReference + '.collapseList();', 500);
1311
};
1312
1313
// Event handler for clicking on one of the icons.
1314
IconList.prototype.onItemMouseDown = function (oDiv, sNewIcon)
1315
{
1316
	if (this.iCurMessageId !== 0)
1317
	{
1318
		ajax_indicator(true);
1319
		this.tmpMethod = getXMLDocument;
1320
		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_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_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...
1321
		delete this.tmpMethod;
1322
		ajax_indicator(false);
1323
1324
		var oMessage = oXMLDoc.responseXML.getElementsByTagName('elk')[0].getElementsByTagName('message')[0];
1325
		if (oMessage.getElementsByTagName('error').length === 0)
1326
		{
1327
			if ((this.opt.bShowModify && oMessage.getElementsByTagName('modified').length !== 0) && (document.getElementById('modified_' + this.iCurMessageId) !== null))
1328
				document.getElementById('modified_' + this.iCurMessageId).innerHTML = oMessage.getElementsByTagName('modified')[0].childNodes[0].nodeValue;
1329
1330
			this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1331
		}
1332
	}
1333
	else
1334
	{
1335
		this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1336
		if ('sLabelIconBox' in this.opt)
1337
			document.getElementById(this.opt.sLabelIconBox).value = sNewIcon;
1338
	}
1339
};
1340
1341
// Event handler for clicking outside the list (will make the list disappear).
1342
IconList.prototype.onWindowMouseDown = function ()
1343
{
1344
	for (var i = aIconLists.length - 1; i >= 0; i--)
1345
	{
1346
		aIconLists[i].funcParent.tmpMethod = aIconLists[i].collapseList;
1347
		aIconLists[i].funcParent.tmpMethod();
1348
		delete aIconLists[i].funcParent.tmpMethod;
1349
	}
1350
};
1351
1352
// Collapse the list of icons.
1353
IconList.prototype.collapseList = function()
1354
{
1355
	this.onBoxHover(this.oClickedIcon, false);
1356
	this.oContainerDiv.style.display = 'none';
1357
	this.iCurMessageId = 0;
1358
	document.body.removeEventListener('mousedown', this.onWindowMouseDown, false);
1359
};
1360
1361
/**
1362
 * Short function for finding the actual screen position of an item.
1363
 * Used for example to position the suggest member name box
1364
 *
1365
 * @param {object} itemHandle
1366
 */
1367
function elk_itemPos(itemHandle)
1368
{
1369
	var itemX = 0,
1370
		itemY = 0;
1371
1372
	if ('offsetParent' in itemHandle)
1373
	{
1374
		itemX = itemHandle.offsetLeft;
1375
		itemY = itemHandle.offsetTop;
1376
1377
		while (itemHandle.offsetParent && typeof(itemHandle.offsetParent) === 'object')
1378
		{
1379
			itemHandle = itemHandle.offsetParent;
1380
			itemX += itemHandle.offsetLeft;
1381
			itemY += itemHandle.offsetTop;
1382
		}
1383
	}
1384
	else if ('x' in itemHandle)
1385
	{
1386
		itemX = itemHandle.x;
1387
		itemY = itemHandle.y;
1388
	}
1389
1390
	return [itemX, itemY];
1391
}
1392
1393
/**
1394
 * This function takes the script URL and prepares it to allow the query string to be appended to it.
1395
 *
1396
 * @param {string} sUrl
1397
 */
1398
function elk_prepareScriptUrl(sUrl)
1399
{
1400
	return sUrl.indexOf('?') === -1 ? sUrl + '?' : sUrl + (sUrl.charAt(sUrl.length - 1) === '?' || sUrl.charAt(sUrl.length - 1) === '&' || sUrl.charAt(sUrl.length - 1) === ';' ? '' : ';');
1401
}
1402
1403
/**
1404
 * Load Event function, adds new events to the window onload control
1405
 *
1406
 * @param {object} fNewOnload function object to call
1407
 *
1408
 * @deprecated aince 2.0; use window.addEventListener("load", fNewOnload)
1409
 */
1410
function addLoadEvent(fNewOnload)
1411
{
1412
	window.addEventListener("load", fNewOnload);
1413
}
1414
1415
/**
1416
 * Get the text in a code tag by selecting the [select] in the code header
1417
 *
1418
 * @param {object} oCurElement
1419
 * @param {boolean} bActOnElement the passed element contains the code
1420
 */
1421
function elkSelectText(oCurElement, bActOnElement)
1422
{
1423
	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...
1424
1425
	// The place we're looking for is one div up, and next door - if it's auto detect.
1426
	if (typeof(bActOnElement) === 'boolean' && bActOnElement)
1427
		oCodeArea = document.getElementById(oCurElement);
1428
	else
1429
		oCodeArea = oCurElement.parentNode.nextSibling;
1430
1431
	// Did not find it, bail
1432
	if (typeof(oCodeArea) !== 'object' || oCodeArea === null)
1433
		return false;
1434
1435
	// Start off with internet explorer < 9.
1436
	if ('createTextRange' in document.body)
1437
	{
1438
		var oCurRange = document.body.createTextRange();
1439
		oCurRange.moveToElementText(oCodeArea);
1440
		oCurRange.select();
1441
	}
1442
	// All the rest
1443
	else if (window.getSelection)
1444
	{
1445
		var oCurSelection = window.getSelection(),
1446
			curRange = document.createRange();
1447
1448
			curRange.selectNodeContents(oCodeArea);
1449
			oCurSelection.removeAllRanges();
1450
			oCurSelection.addRange(curRange);
1451
	}
1452
1453
	return false;
1454
}
1455
1456
/**
1457
 * A function needed to discern HTML entities from non-western characters.
1458
 *
1459
 * @param {string} sFormName
1460
 * @param {Array.} aElementNames
1461
 * @param {string} sMask
1462
 */
1463
function smc_saveEntities(sFormName, aElementNames, sMask) {
1464
	var i = 0,
1465
		n = 0;
1466
1467
	if (typeof(sMask) === 'string') {
1468
		for (i = 0, n = document.forms[sFormName].elements.length; i < n; i++) {
1469
			if (document.forms[sFormName].elements[i].id.substr(0, sMask.length) === sMask) {
1470
				aElementNames[aElementNames.length] = document.forms[sFormName].elements[i].name;
1471
			}
1472
		}
1473
	}
1474
1475
	for (i = 0, n = aElementNames.length; i < n; i++) {
1476
		if (aElementNames[i] in document.forms[sFormName]) {
1477
			// Handle the editor.
1478
			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 $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...
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...
1479
				document.forms[sFormName][aElementNames[i]].value = $editor_data[post_box_name].val().replace(/&#/g, '&#38;#');
1480
				$editor_data[post_box_name].val(document.forms[sFormName][aElementNames[i]].value);
1481
			}
1482
			else {
1483
				document.forms[sFormName][aElementNames[i]].value = document.forms[sFormName][aElementNames[i]].value.replace(/&#/g, '&#38;#');
1484
			}
1485
		}
1486
	}
1487
}
1488
1489
/**
1490
 * Enable / Disable the "Only show the results after the poll has expired."
1491
 * based on if they have entered a time limit or not
1492
 *
1493
 * @returns {undefined}
1494
 */
1495
function pollOptions()
1496
{
1497
	var expire_time = document.getElementById('poll_expire');
1498
1499
	if (isEmptyText(expire_time) || expire_time.value === 0)
1500
	{
1501
		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...
1502
		if (document.forms[form_name].poll_hide[2].checked)
1503
			document.forms[form_name].poll_hide[1].checked = true;
1504
	}
1505
	else
1506
		document.forms[form_name].poll_hide[2].disabled = false;
1507
}
1508
1509
/**
1510
 * Generate the number of days in a given month for a given year
1511
 * Used to populate the day pulldown in the calendar
1512
 *
1513
 * @param {int} [offset] optional
1514
 */
1515
function generateDays(offset)
1516
{
1517
	// Work around JavaScript's lack of support for default values...
1518
	offset = typeof(offset) !== 'undefined' ? offset : '';
1519
1520
	var days = 0,
1521
		selected = 0,
1522
		dayElement = document.getElementById("day" + offset),
1523
		yearElement = document.getElementById("year" + offset),
1524
		monthElement = document.getElementById("month" + offset),
1525
		monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1526
1527
	monthLength[1] = 28;
1528
	if (yearElement.options[yearElement.selectedIndex].value % 4 === 0)
1529
		monthLength[1] = 29;
1530
1531
	selected = dayElement.selectedIndex;
1532
	while (dayElement.options.length)
1533
		dayElement.options[0] = null;
1534
1535
	days = monthLength[monthElement.value - 1];
1536
1537
	for (var i = 1; i <= days; i++)
1538
		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...
1539
1540
	if (selected < days)
1541
		dayElement.selectedIndex = selected;
1542
}
1543
1544
/**
1545
 * Enable/disable the board selection list when a calendar event is linked, or not, to a post
1546
 *
1547
 * @param {string} form
1548
 */
1549
function toggleLinked(form)
1550
{
1551
	form.board.disabled = !form.link_to_board.checked;
1552
}
1553
1554
/**
1555
 * load event for search for and PM search, un escapes any existing search
1556
 * value for back button or change search etc.
1557
 */
1558
function initSearch()
1559
{
1560
	if (document.forms.searchform.search.value.indexOf("%u") !== -1)
1561
		document.forms.searchform.search.value = decodeURI(document.forms.searchform.search.value);
1562
}
1563
1564
/**
1565
 * Checks or unchecks the list of available boards
1566
 *
1567
 * @param {type} ids
1568
 * @param {string} aFormName
1569
 * @param {string} sInputName
1570
 */
1571
function selectBoards(ids, aFormName, sInputName)
1572
{
1573
	var toggle = true,
1574
		i = 0;
1575
1576
	for (var f = 0, max = document.forms.length; f < max; f++)
1577
	{
1578
		if (document.forms[f].name == aFormName)
1579
		{
1580
			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...
1581
			break;
1582
		}
1583
	}
1584
	if (typeof aForm == 'undefined')
1585
		return;
1586
1587
	for (i = 0; i < ids.length; i++)
1588
		toggle = toggle && aForm[sInputName + '[' + ids[i] + ']'].checked;
1589
1590
	for (i = 0; i < ids.length; i++)
1591
		aForm[sInputName + '[' + ids[i] + ']'].checked = !toggle;
1592
}
1593
1594
/**
1595
 * Expands or collapses a container
1596
 *
1597
 * @param {string} id
1598
 * @param {string} icon
1599
 * @param {int} speed
1600
 */
1601
function expandCollapse(id, icon, speed)
1602
{
1603
	var	oId = $('#' + id);
1604
1605
	icon = icon || false;
1606
	speed = speed || 300;
1607
1608
	// Change the icon on the box as well?
1609
	if (icon)
1610
		$('#' + 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...
1611
1612
	// Open or collapse the content id
1613
	oId.slideToggle(speed);
1614
}
1615
1616
/**
1617
 * Highlight a selection box by adding the highlight2 class
1618
 *
1619
 * @param {string} container_id
1620
 */
1621
function initHighlightSelection(container_id)
1622
{
1623
	$('#' + 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...
1624
		$('#' + container_id + ' .standard_row').removeClass('highlight2');
1625
		$(this).parent().parent().addClass('highlight2');
1626
	});
1627
}
1628
1629
/**
1630
 * Auto submits a paused form, such as a maintenance task
1631
 *
1632
 * @param {int} countdown
1633
 * @param {string} txt_message
1634
 * @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...
1635
 */
1636
function doAutoSubmit(countdown, txt_message, formName)
1637
{
1638
	var formID = typeof(formName) !== 'undefined' ? formName : "autoSubmit";
1639
1640
	if (countdown === 0)
1641
		document.forms[formID].submit();
1642
	else if (countdown === -1)
1643
		return;
1644
1645
	document.forms[formID].cont.value = txt_message + ' (' + countdown + ')';
1646
	countdown--;
1647
1648
	setTimeout(function() {doAutoSubmit(countdown, txt_message, formID);}, 1000);
1649
}
1650