Completed
Pull Request — master (#3118)
by Emanuele
14:03
created

script_elk.js ➔ ... ➔ $(this).click   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 20
rs 9.4285
c 2
b 0
f 1
1
/*!
2
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * @version 1.1
7
 */
8
9
/**
10
 * This file contains javascript utility functions specific to ElkArte
11
 */
12
13
/**
14
 * We like the globals cuz they is good to us
15
 */
16
17
/** global: notification_topic_notice, notification_board_notice, txt_mark_as_read_confirm, oRttime */
18
/** global: $editor_data, elk_scripturl, elk_smiley_url, elk_session_var, elk_session_id, elk_images_url */
19
/** global: poll_add, poll_remove, poll_add, XMLHttpRequest, ElkInfoBar */
20
21
/**
22
 * Sets code blocks such that resize vertical works as expect.  Done this way to avoid
23
 * page jumps to named anchors missing the target.
24
 */
25
function elk_codefix()
26
{
27
	$('.bbc_code').each(function()
28
	{
29
		var $this = $(this);
30
31
		// If it has a scroll bar, allow the user to resize it vertically
32
		if ($this.get(0).scrollHeight > $this.innerHeight()) {
33
			$this.css('height', $this.height());
34
			$this.css('max-height', 'none');
35
		}
36
		else {
37
			$this.css('resize', 'none');
38
		}
39
	});
40
}
41
42
/**
43
 * Turn a regular url button in to an ajax request
44
 *
45
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
46
 * @param {string} confirmation_msg_variable var name of the text sting to display in the "are you sure" box
47
 * @param {function} onSuccessCallback optional, a callback executed on successfully execute the AJAX call
48
 */
49
function toggleButtonAJAX(btn, confirmation_msg_variable, onSuccessCallback)
50
{
51
	$.ajax({
52
		type: 'GET',
53
		url: btn.href + ';xml;api',
54
		context: document.body,
55
		beforeSend: ajax_indicator(true)
56
	})
57
	.done(function(request) {
58
		if (request === '')
59
			return;
60
61
		var oElement = $(request).find('elk')[0];
62
63
		// No errors
64
		if (oElement.getElementsByTagName('error').length === 0)
65
		{
66
			var text = oElement.getElementsByTagName('text'),
67
				url = oElement.getElementsByTagName('url'),
68
				confirm_elem = oElement.getElementsByTagName('confirm');
69
70
			// Update the page so button/link/confirm/etc reflect the new on or off status
71
			if (confirm_elem.length === 1)
72
				var confirm_text = confirm_elem[0].firstChild.nodeValue.removeEntities();
73
74
			$('.' + btn.className.replace(/(list|link)level\d/g, '').trim()).each(function() {
75
				// @todo: the span should be moved somewhere in themes.js?
76
				if (text.length === 1)
77
					$(this).html('<span>' + text[0].firstChild.nodeValue.removeEntities() + '</span>');
78
79
				if (url.length === 1)
80
					$(this).attr('href', url[0].firstChild.nodeValue.removeEntities());
81
82
				// Replaces the confirmation var text with the new one from the response to allow swapping on/off
83
				if (typeof (confirm_text) !== 'undefined')
84
					eval(confirmation_msg_variable + '= \'' + confirm_text.replace(/[\\']/g, '\\$&') + '\'');
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
Coding Style Security introduced by
The use of eval is generally not recommended.

The use of eval is discouraged because it can potentially make your code vulnerable to various injection attacks.

Besides it will also prevent certain optimizations that runtimes otherwise could make.

Loading history...
85
			});
86
		}
87
		else
88
		{
89
			// Error returned from the called function, show an alert
90
			if (oElement.getElementsByTagName('text').length !== 0)
91
				alert(oElement.getElementsByTagName('text')[0].firstChild.nodeValue.removeEntities());
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
92
93
			if (oElement.getElementsByTagName('url').length !== 0)
94
				window.location.href = oElement.getElementsByTagName('url')[0].firstChild.nodeValue;
95
		}
96
97
		if (typeof (onSuccessCallback) !== 'undefined')
98
			onSuccessCallback(btn, request, oElement.getElementsByTagName('error'));
99
	})
100
	.fail(function() {
101
		// ajax failure code
102
	})
103
	.always(function() {
104
		// turn off the indicator
105
		ajax_indicator(false);
106
	});
107
108
	return false;
109
}
110
111
/**
112
 * Helper function: displays and removes the ajax indicator and
113
 * hides some page elements inside "container_id"
114
 * Used by some (one at the moment) ajax buttons
115
 *
116
 * @todo it may be merged into the function if not used anywhere else
117
 *
118
 * @param {HTMLElement|string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
119
 * @param {string} container_id  css ID of the data container
120
 */
121
function toggleHeaderAJAX(btn, container_id)
122
{
123
	// Show ajax is in progress
124
	ajax_indicator(true);
125
	var body_template = '<div class="board_row centertext">{body}</div>';
126
127
	$.ajax({
128
		type: 'GET',
129
		url: btn.href + ';xml;api',
130
		context: document.body,
131
		beforeSend: ajax_indicator(true)
132
		})
133
		.done(function(request) {
134
			if (request === '')
135
				return;
136
137
			var oElement = $(request).find('elk')[0];
138
139
			// No errors
140
			if (oElement.getElementsByTagName('error').length === 0)
141
			{
142
				var text_elem = oElement.getElementsByTagName('text'),
143
					body_elem = oElement.getElementsByTagName('body');
144
145
				$('#' + container_id + ' .pagesection').remove();
146
				$('#' + container_id + ' .topic_listing').remove();
147
				$('#' + container_id + ' .topic_sorting').remove();
148
				if (text_elem.length === 1)
149
					$('#' + container_id + ' #unread_header').html(text_elem[0].firstChild.nodeValue.removeEntities());
150
				if (body_elem.length === 1)
151
					$(body_template.replace('{body}', body_elem[0].firstChild.nodeValue.removeEntities())).insertAfter('#unread_header');
152
			}
153
		})
154
		.fail(function() {
155
			// ajax failure code
156
		})
157
		.always(function() {
158
			// turn off the indicator
159
			ajax_indicator(false);
160
		});
161
}
162
163
/**
164
 * Ajaxify the "notify" button in Display
165
 *
166
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
167
 */
168
function notifyButton(btn)
169
{
170
	if (typeof (notification_topic_notice) !== 'undefined' && !confirm(notification_topic_notice))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
171
		return false;
172
173
	return toggleButtonAJAX(btn, 'notification_topic_notice', function(btn, request, errors) {
174
		var toggle = 0;
175
176
		if (errors.length > 0)
177
			return;
178
179
		// This is a "turn notifications on"
180
		if (btn.href.indexOf('sa=on') !== -1)
181
			toggle = 1;
182
		else
183
			toggle = 0;
184
185
		$("input[name='notify']").val(toggle);
186
	});
187
}
188
189
/**
190
 * Ajaxify the "notify" button in MessageIndex
191
 *
192
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
193
 */
194
function notifyboardButton(btn)
195
{
196
	if (typeof (notification_board_notice) !== 'undefined' && !confirm(notification_board_notice))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
197
		return false;
198
199
	toggleButtonAJAX(btn, 'notification_board_notice');
200
	return false;
201
}
202
203
/**
204
 * Ajaxify the "unwatch" button in Display
205
 *
206
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
207
 */
208
function unwatchButton(btn)
209
{
210
	toggleButtonAJAX(btn);
211
	return false;
212
}
213
214
/**
215
 * Ajaxify the "mark read" button in MessageIndex
216
 *
217
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
218
 */
219
function markboardreadButton(btn)
220
{
221
	if (!confirm(txt_mark_as_read_confirm))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
222
	{
223
		return false;
224
	}
225
226
	toggleButtonAJAX(btn);
227
228
	// Remove all the "new" icons next to the topics subjects
229
	$('.new_posts').remove();
230
231
	return false;
232
}
233
234
/**
235
 * Ajaxify the "mark all messages as read" button in BoardIndex
236
 *
237
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
238
 */
239
function markallreadButton(btn)
240
{
241
	if (!confirm(txt_mark_as_read_confirm))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
242
	{
243
		return false;
244
	}
245
246
	toggleButtonAJAX(btn);
247
248
	// Remove all the "new" icons next to the topics subjects
249
	$('.new_posts').remove();
250
251
	// Turn the board icon class to off
252
	$('.board_icon').each(function() {
253
		$(this).removeClass('i-board-new i-board-sub').addClass('i-board-off');
254
	});
255
256
	$('.board_new_posts').removeClass('board_new_posts');
257
258
	return false;
259
}
260
261
/**
262
 * Ajaxify the "mark all messages as read" button in Recent
263
 *
264
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
265
 */
266
function markunreadButton(btn)
267
{
268
	if (!confirm(txt_mark_as_read_confirm))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
269
	{
270
		return false;
271
	}
272
273
	toggleHeaderAJAX(btn, 'main_content_section');
274
275
	return false;
276
}
277
278
/**
279
 * This function changes the relative time around the page real-timeish
280
 */
281
var relative_time_refresh = 0;
282
function updateRelativeTime()
283
{
284
	// In any other case no more than one hour
285
	relative_time_refresh = 3600000;
286
287
	$('time').each(function() {
288
		var oRelativeTime = new relativeTime($(this).data('timestamp') * 1000, oRttime.referenceTime),
289
			time_text = '';
290
291
		if (oRelativeTime.seconds())
292
		{
293
			$(this).text(oRttime.now);
294
			relative_time_refresh = Math.min(relative_time_refresh, 10000);
295
		}
296
		else if (oRelativeTime.minutes())
297
		{
298
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.minutes : oRttime.minute;
299
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
300
			relative_time_refresh = Math.min(relative_time_refresh, 60000);
301
		}
302
		else if (oRelativeTime.hours())
303
		{
304
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.hours : oRttime.hour;
305
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
306
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
307
		}
308
		else if (oRelativeTime.days())
309
		{
310
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.days : oRttime.day;
311
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
312
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
313
		}
314
		else if (oRelativeTime.weeks())
315
		{
316
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.weeks : oRttime.week;
317
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
318
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
319
		}
320
		else if (oRelativeTime.months())
321
		{
322
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.months : oRttime.month;
323
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
324
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
325
		}
326
		else if (oRelativeTime.years())
327
		{
328
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.years : oRttime.year;
329
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
330
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
331
		}
332
	});
333
	oRttime.referenceTime += relative_time_refresh;
334
335
	setTimeout(function() {updateRelativeTime();}, relative_time_refresh);
336
}
337
338
/**
339
 * Function/object to handle relative times
340
 * sTo is optional, if omitted the relative time is
341
 * calculated from sFrom up to "now"
342
 *
343
 * @param {int} sFrom
344
 * @param {int} sTo
345
 */
346
function relativeTime(sFrom, sTo)
347
{
348
	if (typeof sTo === 'undefined')
349
	{
350
		this.dateTo = new Date();
351
	}
352
	else if (parseInt(sTo) == 'NaN')
353
	{
354
		var sToSplit = sTo.split(/\D/);
355
		this.dateTo = new Date(sToSplit[0], --sToSplit[1], sToSplit[2], sToSplit[3], sToSplit[4]);
356
	}
357
	else
358
		this.dateTo = new Date(sTo);
359
360
	if (parseInt(sFrom) == 'NaN')
361
	{
362
		var sFromSplit = sFrom.split(/\D/);
363
		this.dateFrom = new Date(sFromSplit[0], --sFromSplit[1], sFromSplit[2], sFromSplit[3], sFromSplit[4]);
364
	}
365
	else
366
		this.dateFrom = new Date(sFrom);
367
368
	this.time_text = '';
369
	this.past_time = (this.dateTo - this.dateFrom) / 1000;
370
	this.deltaTime = 0;
371
}
372
373
relativeTime.prototype.seconds = function()
374
{
375
	// Within the first 60 seconds it is just now.
376
	if (this.past_time < 60)
377
	{
378
		this.deltaTime = this.past_time;
379
		return true;
380
	}
381
382
	return false;
383
};
384
385
relativeTime.prototype.minutes = function()
386
{
387
	// Within the first hour?
388
	if (this.past_time >= 60 && Math.round(this.past_time / 60) < 60)
389
	{
390
		this.deltaTime = Math.round(this.past_time / 60);
391
		return true;
392
	}
393
394
	return false;
395
};
396
397
relativeTime.prototype.hours = function()
398
{
399
	// Some hours but less than a day?
400
	if (Math.round(this.past_time / 60) >= 60 && Math.round(this.past_time / 3600) < 24)
401
	{
402
		this.deltaTime = Math.round(this.past_time / 3600);
403
		return true;
404
	}
405
406
	return false;
407
};
408
409
relativeTime.prototype.days = function()
410
{
411
	// Some days ago but less than a week?
412
	if (Math.round(this.past_time / 3600) >= 24 && Math.round(this.past_time / (24 * 3600)) < 7)
413
	{
414
		this.deltaTime = Math.round(this.past_time / (24 * 3600));
415
		return true;
416
	}
417
418
	return false;
419
};
420
421
relativeTime.prototype.weeks = function()
422
{
423
	// Weeks ago but less than a month?
424
	if (Math.round(this.past_time / (24 * 3600)) >= 7 && Math.round(this.past_time / (24 * 3600)) < 30)
425
	{
426
		this.deltaTime = Math.round(this.past_time / (24 * 3600) / 7);
427
		return true;
428
	}
429
430
	return false;
431
};
432
433
relativeTime.prototype.months = function()
434
{
435
	// Months ago but less than a year?
436
	if (Math.round(this.past_time / (24 * 3600)) >= 30 && Math.round(this.past_time / (30 * 24 * 3600)) < 12)
437
	{
438
		this.deltaTime = Math.round(this.past_time / (30 * 24 * 3600));
439
		return true;
440
	}
441
442
	return false;
443
};
444
445
relativeTime.prototype.years = function()
446
{
447
	// Oha, we've passed at least a year?
448
	if (Math.round(this.past_time / (30 * 24 * 3600)) >= 12)
449
	{
450
		this.deltaTime = this.dateTo.getFullYear() - this.dateFrom.getFullYear();
451
		return true;
452
	}
453
454
	return false;
455
};
456
457
/**
458
 * Used to tag mentioned names when they are entered inline but NOT selected from the dropdown list
459
 * The name must have appeared in the dropdown and be found in that cache list
460
 *
461
 * @param {string} sForm the form that holds the container, only used for plain text QR
462
 * @param {string} sInput the container that atWho is attached
463
 */
464
function revalidateMentions(sForm, sInput)
465
{
466
	var cached_names,
467
		cached_queries,
468
		body,
469
		mentions,
470
		pos = -1,
0 ignored issues
show
Unused Code introduced by
The assignment to variable pos seems to be never used. Consider removing it.
Loading history...
471
		// Some random punctuation marks that may appear next to a name
472
		boundaries_pattern = /[ \.,;!\?'-\\\/="]/i;
473
474
	for (var i = 0, count = all_elk_mentions.length; i < count; i++)
475
	{
476
		// Make sure this mention object is for this selector, safety first
477
		if (all_elk_mentions[i].selector === sInput || all_elk_mentions[i].selector === '#' + sInput)
478
		{
479
			// Was this invoked as the editor plugin?
480
			if (all_elk_mentions[i].oOptions.isPlugin)
481
			{
482
				var $editor = $editor_data[all_elk_mentions[i].selector];
483
484
				cached_names = $editor.opts.mentionOptions.cache.names;
485
				cached_queries = $editor.opts.mentionOptions.cache.queries;
486
487
				// Clean up the newlines and spacing so we can find the @mentions
488
				body = $editor.getText().replace(/[\u00a0\r\n]/g, ' ');
489
				mentions = $($editor.opts.mentionOptions.cache.mentions);
490
			}
491
			// Or just our plain text quick reply box?
492
			else
493
			{
494
				cached_names = all_elk_mentions[i].oMention.cached_names;
495
				cached_queries = all_elk_mentions[i].oMention.cached_queries;
496
497
				// Keep everything separated with spaces, not newlines or no breakable
498
				body = document.forms[sForm][sInput].value.replace(/[\u00a0\r\n]/g, ' ');
499
500
				// The last pulldown box that atWho populated
501
				mentions = $(all_elk_mentions[i].oMention.mentions);
502
			}
503
504
			// Adding a space at the beginning to facilitate catching of mentions at the 1st char
505
			// and one at the end to simplify catching any last thing in the text
506
			body = ' ' + body + ' ';
507
508
			// First check if all those in the list are really mentioned
509
			$(mentions).find('input').each(function (idx, elem) {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
510
				var name = $(elem).data('name'),
511
					next_char,
512
					prev_char,
513
					index = body.indexOf(name);
0 ignored issues
show
Bug introduced by
The variable body is changed as part of the for loop for example by " " + body + " " on line 506. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
514
515
				// It is undefined coming from a preview
516
				if (typeof(name) !== 'undefined')
517
				{
518
					if (index === -1)
519
						$(elem).remove();
520
					else
521
					{
522
						next_char = body.charAt(index + name.length);
523
						prev_char = body.charAt(index - 1);
524
525
						if (next_char !== '' && next_char.search(boundaries_pattern) !== 0)
526
							$(elem).remove();
527
						else if (prev_char !== '' && prev_char.search(boundaries_pattern) !== 0)
528
							$(elem).remove();
529
					}
530
				}
531
			});
532
533
			for (var k = 0, ccount = cached_queries.length; k < ccount; k++)
534
			{
535
				var names = cached_names[cached_queries[k]];
536
537
				for (var l = 0, ncount = names.length; l < ncount; l++)
538
				{
539
					if(checkWordOccurrence(body, names[l].name)) {
540
						pos = body.indexOf(' @' + names[l].name);
541
542
						// If there is something like "{space}@username" AND the following char is a space or a punctuation mark
543
						if (pos !== -1 && body.charAt(pos + 2 + names[l].name.length + 1).search(boundaries_pattern) === 0)
544
							mentions.append($('<input type="hidden" name="uid[]" />').val(names[l].id));
545
					}
546
				}
547
			}
548
		}
549
	}
550
}
551
552
/**
553
 * Check whether the word exists in a given paragraph
554
 *
555
 * @param paragraph to check
556
 * @param word to match
557
 */
558
559
function checkWordOccurrence(paragraph, word){
560
  return new RegExp( '\\b' + word + '\\b', 'i').test(paragraph);
561
}
562
563
/**
564
 * This is called from the editor plugin or display.template to set where to
565
 * find the cache values for use in revalidateMentions
566
 *
567
 * @param {string} selector id of element that atWho is attached to
568
 * @param {object} oOptions only set when called from the plugin, contains those options
569
 */
570
var all_elk_mentions = [];
571
function add_elk_mention(selector, oOptions)
572
{
573
	// Global does not exist, hummm
574
	if (all_elk_mentions.hasOwnProperty(selector))
575
		return;
576
577
	// No options means its attached to the plain text box
578
	if (typeof oOptions === 'undefined')
579
		oOptions = {};
580
	oOptions.selector = selector;
581
582
	// Add it to the stack
583
	all_elk_mentions[all_elk_mentions.length] = {
584
		selector: selector,
585
		oOptions: oOptions
586
	};
587
}
588
589
/**
590
 * Drag and drop to reorder ID's via UI Sortable
591
 *
592
 * @param {object} $
593
 */
594
(function($) {
595
	'use strict';
596
	$.fn.elkSortable = function(oInstanceSettings) {
597
		$.fn.elkSortable.oDefaultsSettings = {
598
			opacity: 0.7,
599
			cursor: 'move',
600
			axis: 'y',
601
			scroll: true,
602
			containment: 'parent',
603
			delay: 150,
604
			handle: '', // Restricts sort start click to the specified element, like category_header
605
			href: '', // If an error occurs redirect here
606
			tolerance: 'intersect', // mode to use for testing whether the item is hovering over another item.
607
			setorder: 'serialize', // how to return the data, really only supports serialize and inorder
608
			placeholder: '', // css class used to style the landing zone
609
			preprocess: '', // This function is called at the start of the update event (when the item is dropped) must in in global space
610
			tag: '#table_grid_sortable', // ID(s) of the container to work with, single or comma separated
611
			connect: '', // Use to group all related containers with a common CSS class
612
			sa: '', // Subaction that the xmlcontroller should know about
613
			title: '', // Title of the error box
614
			error: '', // What to say when we don't know what happened, like connection error
615
			token: '' // Security token if needed
616
		};
617
618
		// Account for any user options
619
		var oSettings = $.extend({}, $.fn.elkSortable.oDefaultsSettings, oInstanceSettings || {});
620
621
		if (typeof oSettings.infobar === 'undefined')
622
		{
623
			oSettings.infobar = new ElkInfoBar('sortable_bar', {error_class: 'errorbox', success_class: 'infobox'});
624
		}
625
626
		// Divs to hold our responses
627
		$("<div id='errorContainer'><div/>").appendTo('body');
628
629
		$('#errorContainer').css({'display': 'none'});
630
631
		// Find all oSettings.tag and attach the UI sortable action
632
		$(oSettings.tag).sortable({
633
			opacity: oSettings.opacity,
634
			cursor: oSettings.cursor,
635
			axis: oSettings.axis,
636
			handle: oSettings.handle,
637
			containment: oSettings.containment,
638
			connectWith: oSettings.connect,
639
			placeholder: oSettings.placeholder,
640
			tolerance: oSettings.tolerance,
641
			delay: oSettings.delay,
642
			scroll: oSettings.scroll,
643
			helper: function(e, ui) {
644
				// Fist create a helper container
645
				var $originals = ui.children(),
646
					$helper = ui.clone(),
647
					$clone;
648
649
				// Replace the helper elements with spans, normally this is a <td> -> <span>
650
				// Done to make this container agnostic.
651
				$helper.children().each(function() {
652
					$(this).replaceWith(function(){
653
						return $("<span />", {html: $(this).html()});
654
					});
655
				});
656
657
				// Set the width of each helper cell span to be the width of the original cells
658
				$helper.children().each(function(index) {
659
					// Set helper cell sizes to match the original sizes
660
					return $(this).width($originals.eq(index).width()).css('display', 'inline-block');
661
				});
662
663
				// Next to overcome an issue where page scrolling does not work, we add the new agnostic helper
664
				// element to the body, and hide it
665
				$('body').append('<div id="clone" class="' + oSettings.placeholder + '">' + $helper.html() + '</div>');
666
				$clone = $('#clone');
667
				$clone.hide();
668
669
				// Append the clone element to the actual container we are working in and show it
670
				setTimeout(function() {
671
					$clone.appendTo(ui.parent());
672
					$clone.show();
673
				}, 1);
674
675
				// The above append process allows page scrolls to work while dragging the clone element
676
				return $clone;
677
			},
678
			update: function(e, ui) {
679
				// Called when an element is dropped in a new location
680
				var postdata = '',
681
					moved = ui.item.attr('id'),
682
					order = [],
683
					receiver = ui.item.parent().attr('id');
684
685
				// Calling a pre processing function?
686
				if (oSettings.preprocess !== '')
687
					window[oSettings.preprocess]();
688
689
				// How to post the sorted data
690
				if (oSettings.setorder === 'inorder')
691
				{
692
					// This will get the order in 1-n as shown on the screen
693
					$(oSettings.tag).find('li').each(function() {
694
						var aid = $(this).attr('id').split('_');
695
						order.push({name: aid[0] + '[]', value: aid[1]});
696
					});
697
					postdata = $.param(order);
698
				}
699
				// Get all id's in all the sortable containers
700
				else
701
				{
702
					$(oSettings.tag).each(function() {
703
						// Serialize will be 1-n of each nesting / connector
704
						if (postdata === "")
705
							postdata += $(this).sortable(oSettings.setorder);
706
						else
707
							postdata += "&" + $(this).sortable(oSettings.setorder);
708
					});
709
				}
710
711
				// Add in our security tags and additional options
712
				postdata += '&' + elk_session_var + '=' + elk_session_id;
713
				postdata += '&order=reorder';
714
				postdata += '&moved=' + moved;
715
				postdata += '&received=' + receiver;
716
717
				if (oSettings.token !== '')
718
					postdata += '&' + oSettings.token.token_var + '=' + oSettings.token.token_id;
719
720
				// And with the post data prepared, lets make the ajax request
721
				$.ajax({
722
					type: "POST",
723
					url: elk_scripturl + "?action=xmlhttp;sa=" + oSettings.sa + ";xml",
724
					dataType: "xml",
725
					data: postdata
726
				})
727
				.fail(function(jqXHR, 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...
728
					oSettings.infobar.isError();
729
					oSettings.infobar.changeText(textStatus).showBar();
730
					// Reset the interface?
731
					if (oSettings.href !== '')
732
						setTimeout(function() {
733
							window.location.href = elk_scripturl + oSettings.href;
734
						}, 1000);
735
				})
736
				.done(function(data, textStatus, jqXHR) {
0 ignored issues
show
Unused Code introduced by
The parameter jqXHR 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...
737
					var $_errorContent = $('#errorContent'),
738
						$_errorContainer = $('#errorContainer');
739
740
					if ($(data).find("error").length !== 0)
741
					{
742
						// Errors get a modal dialog box and redirect on close
743
						$_errorContainer.append('<p id="errorContent"></p>');
744
						$_errorContent.html($(data).find("error").text());
745
						$_errorContent.dialog({
746
							autoOpen: true,
747
							title: oSettings.title,
748
							modal: true,
749
							close: function(event, ui) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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 ui 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...
750
								// Redirecting due to the error, that's a good idea
751
								if (oSettings.href !== '')
752
									window.location.href = elk_scripturl + oSettings.href;
753
							}
754
						});
755
					}
756
					else if ($(data).find("elk").length !== 0)
757
					{
758
						// Valid responses get the unobtrusive slider
759
						oSettings.infobar.isSuccess();
760
						oSettings.infobar.changeText($(data).find('elk > orders > order').text()).showBar();
761
					}
762
					else
763
					{
764
						// Something "other" happened ...
765
						$_errorContainer.append('<p id="errorContent"></p>');
766
						$_errorContent.html(oSettings.error + ' : ' + textStatus);
767
						$_errorContent.dialog({autoOpen: true, title: oSettings.title, modal: true});
768
					}
769
				})
770
				.always(function(data, textStatus, jqXHR) {
0 ignored issues
show
Unused Code introduced by
The parameter jqXHR 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 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...
771
					if ($(data).find("elk > tokens > token").length !== 0)
772
					{
773
						// Reset the token
774
						oSettings.token.token_id = $(data).find("tokens").find('[type="token"]').text();
775
						oSettings.token.token_var = $(data).find("tokens").find('[type="token_var"]').text();
776
					}
777
				});
778
			}
779
		});
780
	};
781
})(jQuery);
782
783
/**
784
 * Helper function used in the preprocess call for drag/drop boards
785
 * Sets the id of all 'li' elements to cat#,board#,childof# for use in the
786
 * $_POST back to the xmlcontroller
787
 */
788
function setBoardIds() {
789
	// For each category of board
790
	$("[id^=category_]").each(function() {
791
		var cat = $(this).attr('id').split('category_'),
792
			uls = $(this).find("ul");
793
794
		// First up add drop zones so we can drag and drop to each level
795
		if (uls.length === 1)
796
		{
797
			// A single empty ul in a category, this can happen when a cat is dragged empty
798
			if ($(uls).find("li").length === 0)
799
				$(uls).append('<li id="cbp_' + cat + ',-1,-1"></li>');
800
			// Otherwise the li's need a child ul so we have a "child-of" drop zone
801
			else
802
				$(uls).find("li:not(:has(ul))").append('<ul class="nolist elk_droppings"></ul>');
803
		}
804
		// All others normally
805
		else
806
			$(uls).find("li:not(:has(ul))").append('<ul class="nolist elk_droppings"></ul>');
807
808
		// Next make find all the ul's in this category that have children, update the
809
		// id's with information that indicates the 1-n and parent/child info
810
		$(this).find('ul:parent').each(function(i, ul) {
0 ignored issues
show
Unused Code introduced by
The parameter ul 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 i 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...
811
812
			// Get the (li) parent of this ul
813
			var parentList = $(this).parent('li').attr('id'),
814
					pli = 0;
815
816
			// No parent, then its a base node 0, else its a child-of this node
817
			if (typeof (parentList) !== "undefined")
818
			{
819
				pli = parentList.split(",");
820
				pli = pli[1];
821
			}
822
823
			// Now for each li in this ul
824
			$(this).find('li').each(function(i, el) {
825
				var currentList = $(el).attr('id');
826
				var myid = currentList.split(",");
827
828
				// Remove the old id, insert the newly computed cat,brd,childof
829
				$(el).removeAttr("id");
830
				myid = "cbp_" + cat[1] + "," + myid[1] + "," + pli;
831
				$(el).attr('id', myid);
832
			});
833
		});
834
	});
835
}
836
837
/**
838
 * Expands the ... of the page indexes
839
 *
840
 * @todo not exactly a plugin and still very bound to the theme structure
841
 *
842
 */
843
;(function($) {
844
	$.fn.expand_pages = function() {
845
		// Used when the user clicks on the ... to expand instead of just a hover expand
846
		function expand_pages($element)
847
		{
848
			var $baseAppend = $($element.closest('.linavPages')),
849
				boxModel = $baseAppend.prev().clone(),
850
				aModel = boxModel.find('a').clone(),
851
				expandModel = $element.clone(),
852
				perPage = $element.data('perpage'),
853
				firstPage = $element.data('firstpage'),
854
				lastPage = $element.data('lastpage'),
855
				rawBaseurl = $element.data('baseurl'),
856
				baseurl = eval($element.data('baseurl')),
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
Coding Style Security introduced by
The use of eval is generally not recommended.

The use of eval is discouraged because it can potentially make your code vulnerable to various injection attacks.

Besides it will also prevent certain optimizations that runtimes otherwise could make.

Loading history...
857
				first;
858
859
			var i = 0,
860
				oldLastPage = 0,
861
				perPageLimit = 10;
862
863
			// Prevent too many pages to be loaded at once.
864
			if ((lastPage - firstPage) / perPage > perPageLimit)
865
			{
866
				oldLastPage = lastPage;
867
				lastPage = firstPage + perPageLimit * perPage;
868
			}
869
870
			// Calculate the new pages.
871
			for (i = lastPage; i > firstPage; i -= perPage)
872
			{
873
				var bElem = aModel.clone(),
874
					boxModelClone = boxModel.clone();
875
876
				bElem.attr('href', baseurl.replace('%1$d', i - perPage)).text(i / perPage);
877
				boxModelClone.find('a').each(function() {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
878
					$(this).replaceWith(bElem[0]);
0 ignored issues
show
Bug introduced by
The variable bElem is changed as part of the for loop for example by aModel.clone() on line 873. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
879
				});
880
				$baseAppend.after(boxModelClone);
881
882
				// This is needed just to remember where to attach the new expand
883
				if (typeof first === 'undefined')
884
					first = boxModelClone;
885
			}
886
			$baseAppend.remove();
887
888
			if (oldLastPage > 0)
889
			{
890
				// This is to remove any hover_expand
891
				expandModel.find('#expanded_pages_container').each(function() {
892
					$(this).remove();
893
				});
894
895
				expandModel.on('click', function(e) {
896
					var $zhis = $(this);
897
					e.preventDefault();
898
899
					expand_pages($zhis);
900
901
					$zhis.off('mouseenter focus');
902
				})
903
				.on('mouseenter focus', function() {
904
					hover_expand($(this));
905
				})
906
				.data('perpage', perPage)
907
				.data('firstpage', lastPage)
908
				.data('lastpage', oldLastPage)
909
				.data('baseurl', rawBaseurl);
910
911
				first.after(expandModel);
912
			}
913
		}
914
915
		this.attr('tabindex', 0).on('click', function(e) {
916
			var $zhis = $(this);
917
			e.preventDefault();
918
919
			expand_pages($zhis);
920
		});
921
	};
922
})(jQuery);
923
924
/**
925
 * SiteTooltip, Basic JQuery function to provide styled tooltips
926
 *
927
 * - will use the hoverintent plugin if available
928
 * - shows the tooltip in a div with the class defined in tooltipClass
929
 * - moves all selector titles to a hidden div and removes the title attribute to
930
 *   prevent any default browser actions
931
 * - attempts to keep the tooltip on screen
932
 *
933
 * @param {type} $
934
 */
935
(function($) {
936
	'use strict';
937
	$.fn.SiteTooltip = function(oInstanceSettings) {
938
		$.fn.SiteTooltip.oDefaultsSettings = {
939
			followMouse: 1,
940
			hoverIntent: {sensitivity: 10, interval: 650, timeout: 50},
941
			positionTop: 12,
942
			positionLeft: 12,
943
			tooltipID: 'site_tooltip', // ID used on the outer div
944
			tooltipTextID: 'site_tooltipText', // as above but on the inner div holding the text
945
			tooltipClass: 'tooltip', // The class applied to the outer div (that displays on hover), use this in your css
946
			tooltipSwapClass: 'site_swaptip', // a class only used internally, change only if you have a conflict
947
			tooltipContent: 'html' // display captured title text as html or text
948
		};
949
950
		// Account for any user options
951
		var oSettings = $.extend({}, $.fn.SiteTooltip.oDefaultsSettings, oInstanceSettings || {});
952
953
		// Move passed selector titles to a hidden span, then remove the selector title to prevent any default browser actions
954
		$(this).each(function()
955
		{
956
			var sTitle = $('<span class="' + oSettings.tooltipSwapClass + '">' + this.title + '</span>').hide();
957
			$(this).append(sTitle).attr('title', '');
958
		});
959
960
		// Determine where we are going to place the tooltip, while trying to keep it on screen
961
		var positionTooltip = function(event)
962
		{
963
			var iPosx = 0,
964
				iPosy = 0,
965
				$_tip = $('#' + oSettings.tooltipID);
966
967
			if (!event)
968
				event = window.event;
969
970
			if (event.pageX || event.pageY)
971
			{
972
				iPosx = event.pageX;
973
				iPosy = event.pageY;
974
			}
975
			else if (event.clientX || event.clientY)
976
			{
977
				iPosx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
978
				iPosy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
979
			}
980
981
			// Position of the tooltip top left corner and its size
982
			var oPosition = {
983
					x: iPosx + oSettings.positionLeft,
984
					y: iPosy + oSettings.positionTop,
985
					w: $_tip.width(),
986
					h: $_tip.height()
987
				};
988
989
			// Display limits and window scroll position
990
			var oLimits = {
991
				x: $(window).scrollLeft(),
992
				y: $(window).scrollTop(),
993
				w: $(window).width() - 24,
994
				h: $(window).height() - 24
995
			};
996
997
			// Don't go off screen with our tooltip
998
			if ((oPosition.y + oPosition.h > oLimits.y + oLimits.h) && (oPosition.x + oPosition.w > oLimits.x + oLimits.w))
999
			{
1000
				oPosition.x = (oPosition.x - oPosition.w) - 45;
1001
				oPosition.y = (oPosition.y - oPosition.h) - 45;
1002
			}
1003
			else if ((oPosition.x + oPosition.w) > (oLimits.x + oLimits.w))
1004
			{
1005
				oPosition.x -= (((oPosition.x + oPosition.w) - (oLimits.x + oLimits.w)) + 24);
1006
			}
1007
			else if (oPosition.y + oPosition.h > oLimits.y + oLimits.h)
1008
			{
1009
				oPosition.y -= (((oPosition.y + oPosition.h) - (oLimits.y + oLimits.h)) + 24);
1010
			}
1011
1012
			// Finally set the position we determined
1013
			$_tip.css({'left': oPosition.x + 'px', 'top': oPosition.y + 'px'});
1014
		};
1015
1016
		// Used to show a tooltip
1017
		var showTooltip = function() {
1018
			$('#' + oSettings.tooltipID + ' #' + oSettings.tooltipTextID).slideDown(150);
1019
		};
1020
1021
		// Used to hide a tooltip
1022
		var hideTooltip = function() {
1023
			var $_tip = $('#' + oSettings.tooltipID);
1024
1025
			$_tip.fadeOut(175, function() {
1026
				$(this).trigger("unload").remove();
1027
			});
1028
		};
1029
1030
		// Used to keep html encoded
1031
		function htmlspecialchars(string)
0 ignored issues
show
introduced by
The function htmlspecialchars does not seem to be used and can be removed.
Loading history...
1032
		{
1033
			return $('<span>').text(string).html();
1034
		}
1035
1036
		// For all of the elements that match the selector on the page, lets set up some actions
1037
		return this.each(function()
1038
		{
1039
			// If we find hoverIntent then use it
1040
			if ($.fn.hoverIntent)
1041
			{
1042
				$(this).hoverIntent({
1043
					sensitivity: oSettings.hoverIntent.sensitivity,
1044
					interval: oSettings.hoverIntent.interval,
1045
					over: site_tooltip_on,
1046
					timeout: oSettings.hoverIntent.timeout,
1047
					out: site_tooltip_off
1048
				});
1049
			}
1050
			else
1051
			{
1052
				// Plain old hover it is
1053
				$(this).hover(site_tooltip_on, site_tooltip_off);
1054
			}
1055
1056
			// Create the on tip action
1057
			function site_tooltip_on(event)
1058
			{
1059
				// If we have text in the hidden span element we created on page load
1060
				if ($(this).children('.' + oSettings.tooltipSwapClass).text())
0 ignored issues
show
Bug introduced by
Possible strict violation.
Loading history...
1061
				{
1062
					// Create a ID'ed div with our style class that holds the tooltip info, hidden for now
1063
					$('body').append('<div id="' + oSettings.tooltipID + '" class="' + oSettings.tooltipClass + '"><div id="' + oSettings.tooltipTextID + '" class="hide"></div></div>');
1064
1065
					// Load information in to our newly created div
1066
					var ttContent = $('#' + oSettings.tooltipTextID);
1067
1068
					if (oSettings.tooltipContent === 'html')
1069
						ttContent.html($(this).children('.' + oSettings.tooltipSwapClass).html());
0 ignored issues
show
Bug introduced by
Possible strict violation.
Loading history...
1070
					else
1071
						ttContent.text($(this).children('.' + oSettings.tooltipSwapClass).text());
0 ignored issues
show
Bug introduced by
Possible strict violation.
Loading history...
1072
1073
					// Show then position or it may position off screen
1074
					showTooltip();
1075
					positionTooltip(event);
1076
				}
1077
1078
				return false;
1079
			}
1080
1081
			// Create the Bye bye tip
1082
			function site_tooltip_off(event)
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
1083
			{
1084
				hideTooltip(this);
0 ignored issues
show
Bug introduced by
The call to hideTooltip seems to have too many arguments starting with this.
Loading history...
Bug introduced by
Possible strict violation.
Loading history...
1085
				return false;
1086
			}
1087
1088
			// Create the tip move with the cursor
1089
			if (oSettings.followMouse)
1090
			{
1091
				$(this).on("mousemove", function(event) {
1092
					positionTooltip(event);
1093
1094
					return false;
1095
				});
1096
			}
1097
1098
			// Clear the tip on a click
1099
			$(this).on("click", function() {
1100
				hideTooltip(this);
0 ignored issues
show
Bug introduced by
The call to hideTooltip seems to have too many arguments starting with this.
Loading history...
1101
				return true;
1102
			});
1103
		});
1104
	};
1105
})(jQuery);
1106
1107
/**
1108
 * Error box handler class
1109
 *
1110
 * @param {type} oOptions
1111
 * @returns {errorbox_handler}
1112
 */
1113
var error_txts = {};
1114
function errorbox_handler(oOptions)
1115
{
1116
	this.opt = oOptions;
1117
	this.oError_box = null;
1118
	this.oErrorHandle = window;
1119
	this.evaluate = false;
1120
	this.init();
1121
}
1122
1123
/**
1124
 * @todo this code works well almost only with the editor I think.
1125
 */
1126
errorbox_handler.prototype.init = function()
1127
{
1128
	if (this.opt.check_id !== undefined)
1129
		this.oChecks_on = $(document.getElementById(this.opt.check_id));
1130
	else if (this.opt.selector !== undefined)
1131
		this.oChecks_on = this.opt.selector;
1132
	else if (this.opt.editor !== undefined)
1133
	{
1134
		this.oChecks_on = eval(this.opt.editor);
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
Coding Style Security introduced by
The use of eval is generally not recommended.

The use of eval is discouraged because it can potentially make your code vulnerable to various injection attacks.

Besides it will also prevent certain optimizations that runtimes otherwise could make.

Loading history...
1135
		this.evaluate = true;
1136
	}
1137
1138
	this.oErrorHandle.instanceRef = this;
1139
1140
	if (this.oError_box === null)
1141
		this.oError_box = $(document.getElementById(this.opt.error_box_id));
1142
1143
	if (this.evaluate === false)
1144
	{
1145
		this.oChecks_on.attr('onblur', this.opt.self + '.checkErrors()');
1146
		this.oChecks_on.attr('onkeyup', this.opt.self + '.checkErrors()');
1147
	}
1148
	else
1149
	{
1150
		var current_error_handler = this.opt.self;
1151
		$(function() {
1152
			var current_error = eval(current_error_handler);
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
Coding Style Security introduced by
The use of eval is generally not recommended.

The use of eval is discouraged because it can potentially make your code vulnerable to various injection attacks.

Besides it will also prevent certain optimizations that runtimes otherwise could make.

Loading history...
1153
			$editor_data[current_error.opt.editor_id].addEvent(current_error.opt.editor_id, 'keyup', function() {
1154
				current_error.checkErrors();
1155
			});
1156
		});
1157
	}
1158
};
1159
1160
errorbox_handler.prototype.boxVal = function()
1161
{
1162
	if (this.evaluate === false)
1163
		return this.oChecks_on.val();
1164
	else
1165
		return this.oChecks_on();
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...
1166
};
1167
1168
/**
1169
 * Runs the field checks as defined by the object instance
1170
 */
1171
errorbox_handler.prototype.checkErrors = function()
1172
{
1173
	var num = this.opt.error_checks.length;
1174
1175
	if (num !== 0)
1176
	{
1177
		// Adds the error checking functions
1178
		for (var i = 0; i < num; i++)
1179
		{
1180
			// Get the element that holds the errors
1181
			var $elem = $(document.getElementById(this.opt.error_box_id + "_" + this.opt.error_checks[i].code));
1182
1183
			// Run the efunction check on this field, then add or remove any errors
1184
			if (this.opt.error_checks[i].efunction(this.boxVal()))
1185
				this.addError($elem, this.opt.error_checks[i].code);
1186
			else
1187
				this.removeError(this.oError_box, $elem);
1188
		}
1189
1190
		this.oError_box.attr("class", "errorbox");
1191
	}
1192
1193
	// Hide show the error box based on if we have any errors
1194
	if (this.oError_box.find("li").length === 0)
1195
		this.oError_box.slideUp();
1196
	else
1197
		this.oError_box.slideDown();
1198
};
1199
1200
/**
1201
 * Add and error to the list
1202
 *
1203
 * @param {type} error_elem
1204
 * @param {type} error_code
1205
 */
1206
errorbox_handler.prototype.addError = function(error_elem, error_code)
1207
{
1208
	if (error_elem.length === 0)
1209
	{
1210
		// First error, then set up the list for insertion
1211
		if ($.trim(this.oError_box.children("#" + this.opt.error_box_id + "_list").html()) === '')
1212
			this.oError_box.append("<ul id='" + this.opt.error_box_id + "_list'></ul>");
1213
1214
		// Add the error it and show it
1215
		$(document.getElementById(this.opt.error_box_id + "_list")).append("<li style=\"display:none;\" id='" + this.opt.error_box_id + "_" + error_code + "' class='error'>" + error_txts[error_code] + "</li>");
1216
		$(document.getElementById(this.opt.error_box_id + "_" + error_code)).slideDown();
1217
	}
1218
};
1219
1220
/**
1221
 * Remove an error from the notice window
1222
 *
1223
 * @param {type} error_box
1224
 * @param {type} error_elem
1225
 */
1226
errorbox_handler.prototype.removeError = function(error_box, error_elem)
1227
{
1228
	if (error_elem.length !== 0)
1229
	{
1230
		error_elem.slideUp(function() {
1231
			error_elem.remove();
1232
1233
			// No errors at all then close the box
1234
			if (error_box.find("li").length === 0)
1235
				error_box.slideUp();
1236
		});
1237
	}
1238
};
1239
1240
/**
1241
 * Add a new dt/dd pair above a parent selector
1242
 * Called most often as a callback option in config options
1243
 * If oData is supplied, will create a select list, populated with that data
1244
 * otherwise a standard input box.
1245
 *
1246
 * @param {string} parent id of the parent "add more button: we will place this before
1247
 * @param {object} oDtName object of dt element options (type, class, size)
1248
 * @param {object} oDdName object of the dd element options (type, class size)
1249
 * @param {object} [oData] optional select box object, 1:{id:value,name:display name}, ...
1250
 */
1251
function addAnotherOption(parent, oDtName, oDdName, oData)
1252
{
1253
	// Some defaults to use if none are passed
1254
	oDtName['type'] = oDtName.type || 'text';
0 ignored issues
show
Coding Style introduced by
['type'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1255
	oDtName['class'] = oDtName['class'] || 'input_text';
1256
	oDtName['size'] = oDtName.size || '20';
0 ignored issues
show
Coding Style introduced by
['size'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1257
1258
	oDdName['type'] = oDdName.type || 'text';
0 ignored issues
show
Coding Style introduced by
['type'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1259
	oDdName['class'] = oDdName['class'] || 'input_text';
1260
	oDdName['size'] = oDdName.size || '20';
0 ignored issues
show
Coding Style introduced by
['size'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1261
	oData = oData || '';
1262
1263
	// Our new <dt> element
1264
	var newDT = document.createElement('dt'),
1265
		newInput = document.createElement('input');
1266
1267
	newInput.name = oDtName.name;
1268
	newInput.type = oDtName.type;
1269
	newInput.setAttribute('class', oDtName['class']);
1270
	newInput.size = oDtName.size;
1271
	newDT.appendChild(newInput);
1272
1273
	// And its matching <dd>
1274
	var newDD = document.createElement('dd');
1275
1276
	// If we have data for this field make it a select
1277
	if (oData === '')
1278
		newInput = document.createElement('input');
1279
	else
1280
		newInput = document.createElement('select');
1281
1282
	newInput.name = oDdName.name;
1283
	newInput.type = oDdName.type;
1284
	newInput.size = oDdName.size;
1285
	newInput.setAttribute('class', oDdName['class']);
1286
	newDD.appendChild(newInput);
1287
1288
	// If its a select box we add in the options
1289
	if (oData !== '')
1290
	{
1291
		// The options are children of the newInput select box
1292
		var opt,
1293
			key,
1294
			obj;
1295
1296
		for (key in oData)
1297
		{
1298
			obj = oData[key];
1299
			opt = document.createElement("option");
1300
			opt.name = "option";
1301
			opt.value = obj.id;
1302
			opt.innerHTML = obj.name;
1303
			newInput.appendChild(opt);
1304
		}
1305
	}
1306
1307
	// Place the new dt/dd pair before our parent
1308
	var placeHolder = document.getElementById(parent);
1309
1310
	placeHolder.parentNode.insertBefore(newDT, placeHolder);
1311
	placeHolder.parentNode.insertBefore(newDD, placeHolder);
1312
}
1313
1314
/**
1315
 * Shows the member search dropdown with the search options
1316
 */
1317
function toggle_mlsearch_opt()
1318
{
1319
	var $_mlsearch = $('#mlsearch_options');
1320
1321
	// If the box is already visible just forget about it
1322
	if ($_mlsearch.is(':visible'))
1323
		return;
1324
1325
	// Time to show the droppy
1326
	$_mlsearch.fadeIn('fast');
1327
1328
	// A click anywhere on the page will close the droppy
1329
	$('body').on('click', mlsearch_opt_hide);
1330
1331
	// Except clicking on the box itself or into the search text input
1332
	$('#mlsearch_options, #mlsearch_input').off('click', mlsearch_opt_hide).on('click', function(ev) {
1333
		ev.stopPropagation();
1334
	});
1335
}
1336
1337
/**
1338
 * Hides the member search dropdown and detach the body click event
1339
 */
1340
function mlsearch_opt_hide()
1341
{
1342
	$('body').off('click', mlsearch_opt_hide);
1343
	$('#mlsearch_options').slideToggle('fast');
1344
}
1345
1346
/**
1347
 * Called when the add/remove poll button is pressed from the post screen
1348
 *
1349
 * Used to add add/remove poll input area above the post new topic screen
1350
 * Updates the message icon to the poll icon
1351
 * Swaps poll button to match the current conditions
1352
 *
1353
 * @param {object} button
1354
 * @param {int} id_board
1355
 * @param {string} form_name
1356
 */
1357
function loadAddNewPoll(button, id_board, form_name)
1358
{
1359
	if (typeof id_board === 'undefined')
1360
		return true;
1361
1362
	// Find the form and add poll to the url
1363
	var $form = $('#post_header').closest("form"),
1364
		$_poll_main_option = $('#poll_main, #poll_options');
1365
1366
	// Change the button label
1367
	if ($(button).val() === poll_add)
1368
	{
1369
		$(button).val(poll_remove);
1370
1371
		// We usually like to have the poll icon associated to polls,
1372
		// but only if the currently selected is the default one
1373
		var $_pollicon = $('#icon');
1374
		if ($_pollicon.val() === 'xx')
1375
			$_pollicon.val('poll').change();
1376
1377
		// Add poll to the form action
1378
		$form.attr('action', $form.attr('action') + ';poll');
1379
1380
		// If the form already exists...just show it back and go out
1381
		if ($('#poll_main').length > 0)
1382
		{
1383
			$_poll_main_option.find('input').each(function() {
1384
				if ($(this).data('required') === 'required')
1385
					$(this).attr('required', 'required');
1386
			});
1387
1388
			$_poll_main_option.toggle();
1389
			return false;
1390
		}
1391
	}
1392
	// Remove the poll section
1393
	else
1394
	{
1395
		var $_icon = $('#icon');
1396
1397
		if ($_icon.val() === 'poll')
1398
			$_icon.val('xx').change();
1399
1400
		// Remove poll to the form action
1401
		$form.attr('action', $form.attr('action').replace(';poll', ''));
1402
1403
		$_poll_main_option.hide().find('input').each(function() {
1404
			if ($(this).attr('required') === 'required')
1405
			{
1406
				$(this).data('required', 'required');
1407
				$(this).removeAttr('required');
1408
			}
1409
		});
1410
1411
		$(button).val(poll_add);
1412
1413
		return false;
1414
	}
1415
1416
	// Retrieve the poll area
1417
	$.ajax({
1418
		url: elk_scripturl + '?action=poll;sa=interface;xml;board=' + id_board,
1419
		type: "GET",
1420
		dataType: "html",
1421
		beforeSend: ajax_indicator(true)
1422
	})
1423
	.done(function (data, textStatus, xhr) {
0 ignored issues
show
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...
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...
1424
		// Find the highest tabindex already present
1425
		var max_tabIndex = 0;
1426
		for (var i = 0, n = document.forms[form_name].elements.length; i < n; i++)
1427
			max_tabIndex = Math.max(max_tabIndex, document.forms[form_name].elements[i].tabIndex);
1428
1429
		// Inject the html
1430
		$('#post_header').after(data);
1431
1432
		$('#poll_main input, #poll_options input').each(function () {
1433
			$(this).attr('tabindex', ++max_tabIndex);
1434
		});
1435
1436
		// Repeated collapse/expand of fieldsets as above
1437
		$('#poll_main legend, #poll_options legend').on('click', function() {
1438
			$(this).siblings().slideToggle("fast");
1439
			$(this).parent().toggleClass("collapsed");
1440
		}).each(function () {
1441
			if ($(this).data('collapsed'))
1442
			{
1443
				$(this).siblings().css({display: "none"});
1444
				$(this).parent().toggleClass("collapsed");
1445
			}
1446
		});
1447
	})
1448
	.always(function() {
1449
		// turn off the indicator
1450
		ajax_indicator(false);
1451
	});
1452
1453
	return false;
1454
}
1455
1456
/**
1457
 * Attempt to prevent browsers from auto completing fields when viewing/editing other members profiles
1458
 * or when register new member
1459
 */
1460
function disableAutoComplete()
1461
{
1462
	window.onload = function() {
1463
		// Turn off autocomplete for these elements
1464
		$("input[type=email], input[type=password], .input_text, .input_clear").attr("autocomplete", "off");
1465
1466
		// Chrome will fill out the form even with autocomplete off, so we need to empty the value as well.
1467
		setTimeout(function() {
1468
			$("input[type=password], .input_clear").val(" ").val("");
1469
		}, 1);
1470
	};
1471
}
1472
1473
/**
1474
 * A system to collect notifications from a single AJAX call and redistribute them
1475
 * among notifiers
1476
 */
1477
(function() {
1478
	var ElkNotifications = (function(opt) {
1479
		'use strict';
1480
1481
		opt = (opt) ? opt : {};
1482
		var _notifiers = [],
1483
			start = true,
0 ignored issues
show
Unused Code introduced by
The variable start seems to be never used. Consider removing it.
Loading history...
1484
			lastTime = 0;
1485
1486
		var init = function(opt) {
1487
			if (typeof opt.delay === 'undefined')
1488
			{
1489
				start = false;
0 ignored issues
show
Unused Code introduced by
The variable start seems to be never used. Consider removing it.
Loading history...
1490
				opt.delay = 15000;
1491
			}
1492
1493
			setTimeout(function() {
1494
				fetch();
1495
			}, opt.delay);
1496
		};
1497
1498
		var add = function(notif) {
1499
			_notifiers.push(notif);
1500
		};
1501
1502
		var send = function(request) {
1503
			for (var i = 0; i < _notifiers.length; i++) {
1504
				_notifiers[i].send(request);
1505
			}
1506
		};
1507
1508
		var fetch = function() {
1509
			if (_notifiers.length === 0)
1510
				return;
1511
1512
			$.ajax({
1513
				url: elk_scripturl + "?action=mentions;sa=fetch;api=json;lastsent=" + lastTime
1514
			})
1515
			.done(function(request) {
1516
				if (request !== "") {
1517
					send(request);
1518
					lastTime = request.timelast;
1519
				}
1520
1521
				setTimeout(function() {
1522
					fetch();
1523
				}, opt.delay);
1524
			});
1525
		};
1526
1527
		init(opt);
1528
		return {
1529
			add: add
1530
		};
1531
	});
1532
1533
	// AMD / RequireJS
1534
	if ( typeof define !== 'undefined' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ 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...
1535
		define([], function() {
1536
			return ElkNotifications;
1537
		});
1538
	}
1539
	// CommonJS
1540
	else if ( typeof module !== 'undefined' && module.exports) {
1541
		module.exports = ElkNotifications;
1542
	}
1543
	// included directly via <script> tag
1544
	else {
1545
		this.ElkNotifications = ElkNotifications;
1546
	}
1547
1548
})();
1549
1550
var ElkNotifier = new ElkNotifications();
0 ignored issues
show
Bug introduced by
The variable ElkNotifications seems to be never declared. If this is a global, consider adding a /** global: ElkNotifications */ 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...
1551
1552
/**
1553
 * Initialize the inline attachments posting interface
1554
 */
1555
(function () {
1556
	var ElkInlineAttachments = (function (selector, editor, opt) {
1557
		'use strict';
1558
1559
		opt = $.extend({
1560
			inlineSelector: '.inline_insert',
1561
			data: 'attachid',
1562
			addAfter: 'label',
1563
			template: ''
1564
		}, opt);
1565
1566
		var listAttachs = [],
1567
			init = function (opt) {},
0 ignored issues
show
Unused Code introduced by
The parameter opt 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...
1568
			addInterface = function ($before, attachId) {
1569
				var $trigger, $container = $('<div class="container" />'), $over;
1570
1571
				if (typeof opt.trigger !== 'undefined')
1572
				{
1573
					$trigger = opt.trigger.clone();
1574
				}
1575
				else
1576
				{
1577
					$trigger = $('<a />');
1578
1579
					if (typeof opt.triggerClass !== 'undefined')
1580
					{
1581
						$trigger.addClass(opt.triggerClass);
1582
					}
1583
				}
1584
1585
				$container.append($trigger);
1586
				$trigger.on('click', function (e) {
1587
					e.preventDefault();
1588
1589
					if ($over != undefined)
0 ignored issues
show
Best Practice introduced by
Comparing $over to undefined using the != operator is not safe. Consider using !== instead.
Loading history...
Coding Style introduced by
It is recommended to use !== to compare with undefined.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
1590
					{
1591
						$(document).trigger('click.ila_insert');
1592
						return;
1593
					}
1594
1595
					$over = $(opt.template).hide();
1596
					var firstLi = false,
1597
					    $tabs = $over.find("ul[data-group='tabs'] li");
1598
					/*
1599
					 * Behaviours (onSomething)
1600
					 */
1601
					$tabs.each(function(k, v) {
0 ignored issues
show
Unused Code introduced by
The parameter k 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 v 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...
1602
						$(this).on('click', function(e) {
1603
							e.preventDefault();
1604
							e.stopPropagation();
1605
1606
							$tabs.each(function(k, v) {
0 ignored issues
show
Unused Code introduced by
The parameter v 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 k 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...
1607
								$(this).removeClass('active');
1608
							});
1609
							var toShow = $(this).data('tab');
1610
							$(this).addClass('active');
1611
							$over.find('.container').each(function(k, v) {
0 ignored issues
show
Unused Code introduced by
The parameter v 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 k 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...
1612
								if ($(this).data('visual') == toShow)
1613
								{
1614
									$(this).show();
1615
								}
1616
								else
1617
								{
1618
									$(this).hide();
1619
								}
1620
							});
1621
						});
1622
						if (firstLi == false)
0 ignored issues
show
Best Practice introduced by
Comparing firstLi to false using the == operator is not safe. Consider using === instead.
Loading history...
Coding Style introduced by
It is recommended to use === to compare with false.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
1623
						{
1624
							$(this).click();
1625
							firstLi = true;
1626
						}
1627
					});
1628
					$over.find("input[data-size='thumb']").on('change', function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
1629
						$over.find('.customsize').slideUp();
1630
					});
1631
					$over.find("input[data-size='full']").on('change', function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
1632
						$over.find('.customsize').slideUp();
1633
					});
1634
					$over.find("input[data-size='cust']").on('change', function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e 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...
1635
						$over.find('.customsize').slideDown();
1636
					});
1637
					$over.find(".range").on('input', function () {
1638
						var val = $(this).val()
0 ignored issues
show
Coding Style introduced by
There should be a semicolon.

Requirement of semicolons purely is a coding style issue since JavaScript has specific rules about semicolons which are followed by all browsers.

Further Readings:

Loading history...
1639
						$over.find(".visualizesize").val(val + 'px');
1640
					}).trigger('input');
1641
1642
					$over.find('.button').on('click', function() {
1643
						var ila_text = '[attach';
1644
						if ($over.find("input[data-size='thumb']").is(':checked'))
1645
						{
1646
							ila_text = ila_text + ' type=thumb';
1647
						}
1648
						if ($over.find("input[data-size='cust']").is(':checked'))
1649
						{
1650
							var w = $over.find('.range').val();
1651
							// Doesn't really matter that much, but just to ensure it's not 1
1652
							if (w > 10)
1653
							{
1654
								ila_text = ila_text + ' width=' + w;
1655
							}
1656
						}
1657
1658
						$over.find(".container[data-visual='align'] input").each(function (k, v) {
0 ignored issues
show
Unused Code introduced by
The parameter k 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 v 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...
1659
							if ($(this).is(':checked'))
1660
							{
1661
								if ($(this).data('align') != 'none')
1662
								{
1663
									ila_text = ila_text + ' align=' + $(this).data('align');
1664
									return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
1665
								}
1666
							}
1667
						});
1668
1669
						ila_text = ila_text + ']' + attachId + '[/attach]';
1670
						$editor_data[editor].insertText(ila_text, false, true);
1671
						$(document).trigger('click.ila_insert');
1672
					});
1673
					// Prevents removing the element to disappear when clicking on
1674
					// anything because of the click.ila_insert event
1675
					$over.find('*').on('click', function(e) {
1676
						e.stopPropagation();
1677
					});
1678
1679
					/*
1680
					 * Initialization
1681
					 */
1682
					$over.find('.container label:first-child input').each(function(k, v) {
0 ignored issues
show
Unused Code introduced by
The parameter k 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 v 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...
1683
						$(this).change().prop('checked', true);
1684
					});
1685
1686
					$container.append($over);
1687
					$over.fadeIn(function() {
1688
						$(document).on('click.ila_insert', function() {
1689
							$over.fadeOut(function() {
1690
								$over.remove();
1691
								$over = undefined;
1692
							});
1693
							$(document).off('click.ila_insert');
1694
						});
1695
					});
1696
				}).attr('id', 'inline_attach_' + attachId)
1697
					.data('attachid', attachId);
1698
1699
				$before.after($container);
1700
				listAttachs.push($trigger);
1701
			},
1702
			removeAttach = function (attachId) {
1703
				var tmpList = [],
1704
					i;
1705
1706
				for (i = 0; i < listAttachs.length; i++) {
1707
					if (listAttachs[i].data('attachid') == attachId)
1708
						break;
1709
1710
					tmpList.push(listAttachs[i]);
1711
				}
1712
1713
				i++;
1714
				for (; i < listAttachs.length; i++) {
1715
					tmpList.push(listAttachs[i]);
1716
				}
1717
1718
				listAttachs = tmpList;
1719
				$('#inline_attach_' + attachId).remove();
1720
			};
1721
1722
		init(opt);
1723
		return {
1724
			addInterface: addInterface,
1725
			removeAttach: removeAttach
1726
		};
1727
	});
1728
1729
	// AMD / RequireJS
1730
	if (typeof define !== 'undefined' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ 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...
1731
		define([], function () {
1732
			return ElkInlineAttachments;
1733
		});
1734
	}
1735
	// CommonJS
1736
	else if (typeof module !== 'undefined' && module.exports) {
1737
		module.exports = ElkInlineAttachments;
1738
	}
1739
	// included directly via <script> tag
1740
	else {
1741
		this.ElkInlineAttachments = ElkInlineAttachments;
1742
	}
1743
})();
1744
1745
/**
1746
 * Initialize the ajax info-bar
1747
 */
1748
(function () {
1749
	var ElkInfoBar = (function (elem_id, opt) {
1750
		'use strict';
1751
1752
		opt = $.extend({
1753
			text: '',
1754
			class: 'ajax_infobar',
1755
			hide_delay: 4000,
1756
			error_class: 'error',
1757
			success_class: 'success'
1758
		}, opt);
1759
1760
		var $elem = $('#' + elem_id),
1761
			time_out = null,
1762
			init = function (elem_id, opt) {
1763
				clearTimeout(time_out);
1764
				if ($elem.length === 0) {
1765
					$elem = $('<div id="' + elem_id + '" class="' + opt.class + ' hide" />');
1766
					$('body').append($elem);
1767
					$elem.attr('id', elem_id);
1768
					$elem.addClass(opt.class);
1769
					$elem.text(opt.text);
1770
				}
1771
			},
1772
			changeText = function (text) {
1773
				clearTimeout(time_out);
1774
				$elem.html(text);
1775
				return this;
1776
			},
1777
			addClass = function (aClass) {
1778
				$elem.addClass(aClass);
1779
				return this;
1780
			},
1781
			removeClass = function (aClass) {
1782
				$elem.removeClass(aClass);
1783
				return this;
1784
			},
1785
			showBar = function() {
1786
				clearTimeout(time_out);
1787
				$elem.fadeIn();
1788
1789
				if (opt.hide_delay !== 0)
1790
				{
1791
					time_out = setTimeout(function() {
1792
						hide();
1793
					}, opt.hide_delay);
1794
				}
1795
				return this;
1796
			},
1797
			isError = function() {
1798
				removeClass(opt.success_class);
1799
				addClass(opt.error_class);
1800
			},
1801
			isSuccess = function() {
1802
				removeClass(opt.error_class);
1803
				addClass(opt.success_class);
1804
			},
1805
			hide = function () {
1806
				clearTimeout(time_out);
1807
				$elem.slideUp();
1808
				return this;
1809
			};
1810
1811
		// Call the init function by default
1812
		init(elem_id, opt);
1813
1814
		return {
1815
			changeText: changeText,
1816
			addClass: addClass,
1817
			removeClass: removeClass,
1818
			showBar: showBar,
1819
			isError: isError,
1820
			isSuccess: isSuccess,
1821
			hide: hide
1822
		};
1823
	});
1824
1825
	// AMD / RequireJS
1826
	if (typeof define !== 'undefined' && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ 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...
1827
		define([], function () {
1828
			return ElkInfoBar;
1829
		});
1830
	}
1831
	// CommonJS
1832
	else if (typeof module !== 'undefined' && module.exports) {
1833
		module.exports = ElkInfoBar;
1834
	}
1835
	// included directly via <script> tag
1836
	else {
1837
		this.ElkInfoBar = ElkInfoBar;
1838
	}
1839
})();
1840