Completed
Push — development ( 57103e...96e27e )
by Stephen
17s
created

script_elk.js ➔ ... ➔ $tabs.each   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 27
rs 8.8571
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 2.0 dev
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
				// @todo this appears to be the start of a confirmation dialog... needs finished.
84
				if (typeof (confirm_text) !== 'undefined')
85
					confirmation_msg_variable = confirm_text.replace(/[\\']/g, '\\$&');
0 ignored issues
show
Unused Code introduced by
The variable confirmation_msg_variable seems to be never used. Consider removing it.
Loading history...
86
			});
87
		}
88
		else
89
		{
90
			// Error returned from the called function, show an alert
91
			if (oElement.getElementsByTagName('text').length !== 0)
92
				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...
93
94
			if (oElement.getElementsByTagName('url').length !== 0)
95
				window.location.href = oElement.getElementsByTagName('url')[0].firstChild.nodeValue;
96
		}
97
98
		if (typeof (onSuccessCallback) !== 'undefined')
99
			onSuccessCallback(btn, request, oElement.getElementsByTagName('error'));
100
	})
101
	.fail(function() {
102
		// ajax failure code
103
	})
104
	.always(function() {
105
		// turn off the indicator
106
		ajax_indicator(false);
107
	});
108
109
	return false;
110
}
111
112
/**
113
 * Helper function: displays and removes the ajax indicator and
114
 * hides some page elements inside "container_id"
115
 * Used by some (one at the moment) ajax buttons
116
 *
117
 * @todo it may be merged into the function if not used anywhere else
118
 *
119
 * @param {HTMLElement|string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
120
 * @param {string} container_id  css ID of the data container
121
 */
122
function toggleHeaderAJAX(btn, container_id)
123
{
124
	// Show ajax is in progress
125
	ajax_indicator(true);
126
	var body_template = '<div class="board_row centertext">{body}</div>';
127
128
	$.ajax({
129
		type: 'GET',
130
		url: btn.href + ';xml;api',
131
		context: document.body,
132
		beforeSend: ajax_indicator(true)
133
		})
134
		.done(function(request) {
135
			if (request === '')
136
				return;
137
138
			var oElement = $(request).find('elk')[0];
139
140
			// No errors
141
			if (oElement.getElementsByTagName('error').length === 0)
142
			{
143
				var text_elem = oElement.getElementsByTagName('text'),
144
					body_elem = oElement.getElementsByTagName('body');
145
146
				$('#' + container_id + ' .pagesection').remove();
147
				$('#' + container_id + ' .topic_listing').remove();
148
				$('#' + container_id + ' .topic_sorting').remove();
149
				if (text_elem.length === 1)
150
					$('#' + container_id + ' #unread_header').html(text_elem[0].firstChild.nodeValue.removeEntities());
151
				if (body_elem.length === 1)
152
					$(body_template.replace('{body}', body_elem[0].firstChild.nodeValue.removeEntities())).insertAfter('#unread_header');
153
			}
154
		})
155
		.fail(function() {
156
			// ajax failure code
157
		})
158
		.always(function() {
159
			// turn off the indicator
160
			ajax_indicator(false);
161
		});
162
}
163
164
/**
165
 * Ajaxify the "notify" button in Display
166
 *
167
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
168
 */
169
function notifyButton(btn)
170
{
171
	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...
172
		return false;
173
174
	return toggleButtonAJAX(btn, 'notification_topic_notice', function(btn, request, errors) {
175
		var toggle = 0;
176
177
		if (errors.length > 0)
178
			return;
179
180
		// This is a "turn notifications on"
181
		if (btn.href.indexOf('sa=on') !== -1)
182
			toggle = 1;
183
		else
184
			toggle = 0;
185
186
		$("input[name='notify']").val(toggle);
187
	});
188
}
189
190
/**
191
 * Ajaxify the "notify" button in MessageIndex
192
 *
193
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
194
 */
195
function notifyboardButton(btn)
196
{
197
	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...
198
		return false;
199
200
	toggleButtonAJAX(btn, 'notification_board_notice');
201
	return false;
202
}
203
204
/**
205
 * Ajaxify the "unwatch" button in Display
206
 *
207
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
208
 */
209
function unwatchButton(btn)
210
{
211
	toggleButtonAJAX(btn);
212
	return false;
213
}
214
215
/**
216
 * Ajaxify the "mark read" button in MessageIndex
217
 *
218
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
219
 */
220
function markboardreadButton(btn)
221
{
222
	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...
223
	{
224
		return false;
225
	}
226
227
	toggleButtonAJAX(btn);
228
229
	// Remove all the "new" icons next to the topics subjects
230
	$('.new_posts').remove();
231
232
	return false;
233
}
234
235
/**
236
 * Ajaxify the "mark all messages as read" button in BoardIndex
237
 *
238
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
239
 */
240
function markallreadButton(btn)
241
{
242
	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...
243
	{
244
		return false;
245
	}
246
247
	toggleButtonAJAX(btn);
248
249
	// Remove all the "new" icons next to the topics subjects
250
	$('.new_posts').remove();
251
252
	// Turn the board icon class to off
253
	$('.board_icon').each(function() {
254
		$(this).removeClass('i-board-new i-board-sub').addClass('i-board-off');
255
	});
256
257
	$('.board_new_posts').removeClass('board_new_posts');
258
259
	return false;
260
}
261
262
/**
263
 * Ajaxify the "mark all messages as read" button in Recent
264
 *
265
 * @param {string} btn string representing this, generally the anchor link tag <a class="" href="" onclick="">
266
 */
267
function markunreadButton(btn)
268
{
269
	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...
270
	{
271
		return false;
272
	}
273
274
	toggleHeaderAJAX(btn, 'main_content_section');
275
276
	return false;
277
}
278
279
/**
280
 * This function changes the relative time around the page real-timeish
281
 */
282
var relative_time_refresh = 0;
283
function updateRelativeTime()
284
{
285
	// In any other case no more than one hour
286
	relative_time_refresh = 3600000;
287
288
	$('time').each(function() {
289
		var oRelativeTime = new relativeTime($(this).data('timestamp') * 1000, oRttime.referenceTime),
290
			time_text = '';
291
292
		if (oRelativeTime.seconds())
293
		{
294
			$(this).text(oRttime.now);
295
			relative_time_refresh = Math.min(relative_time_refresh, 10000);
296
		}
297
		else if (oRelativeTime.minutes())
298
		{
299
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.minutes : oRttime.minute;
300
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
301
			relative_time_refresh = Math.min(relative_time_refresh, 60000);
302
		}
303
		else if (oRelativeTime.hours())
304
		{
305
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.hours : oRttime.hour;
306
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
307
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
308
		}
309
		else if (oRelativeTime.days())
310
		{
311
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.days : oRttime.day;
312
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
313
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
314
		}
315
		else if (oRelativeTime.weeks())
316
		{
317
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.weeks : oRttime.week;
318
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
319
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
320
		}
321
		else if (oRelativeTime.months())
322
		{
323
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.months : oRttime.month;
324
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
325
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
326
		}
327
		else if (oRelativeTime.years())
328
		{
329
			time_text = oRelativeTime.deltaTime > 1 ? oRttime.years : oRttime.year;
330
			$(this).text(time_text.replace('%s', oRelativeTime.deltaTime));
331
			relative_time_refresh = Math.min(relative_time_refresh, 3600000);
332
		}
333
	});
334
	oRttime.referenceTime += relative_time_refresh;
335
336
	setTimeout(function() {updateRelativeTime();}, relative_time_refresh);
337
}
338
339
/**
340
 * Function/object to handle relative times
341
 * sTo is optional, if omitted the relative time is
342
 * calculated from sFrom up to "now"
343
 *
344
 * @param {int} sFrom
345
 * @param {int} sTo
346
 */
347
function relativeTime(sFrom, sTo)
348
{
349
	if (typeof sTo === 'undefined')
350
	{
351
		this.dateTo = new Date();
352
	}
353
	else if (parseInt(sTo) == 'NaN')
354
	{
355
		var sToSplit = sTo.split(/\D/);
356
		this.dateTo = new Date(sToSplit[0], --sToSplit[1], sToSplit[2], sToSplit[3], sToSplit[4]);
357
	}
358
	else
359
		this.dateTo = new Date(sTo);
360
361
	if (parseInt(sFrom) == 'NaN')
362
	{
363
		var sFromSplit = sFrom.split(/\D/);
364
		this.dateFrom = new Date(sFromSplit[0], --sFromSplit[1], sFromSplit[2], sFromSplit[3], sFromSplit[4]);
365
	}
366
	else
367
		this.dateFrom = new Date(sFrom);
368
369
	this.time_text = '';
370
	this.past_time = (this.dateTo - this.dateFrom) / 1000;
371
	this.deltaTime = 0;
372
}
373
374
relativeTime.prototype.seconds = function()
375
{
376
	// Within the first 60 seconds it is just now.
377
	if (this.past_time < 60)
378
	{
379
		this.deltaTime = this.past_time;
380
		return true;
381
	}
382
383
	return false;
384
};
385
386
relativeTime.prototype.minutes = function()
387
{
388
	// Within the first hour?
389
	if (this.past_time >= 60 && Math.round(this.past_time / 60) < 60)
390
	{
391
		this.deltaTime = Math.round(this.past_time / 60);
392
		return true;
393
	}
394
395
	return false;
396
};
397
398
relativeTime.prototype.hours = function()
399
{
400
	// Some hours but less than a day?
401
	if (Math.round(this.past_time / 60) >= 60 && Math.round(this.past_time / 3600) < 24)
402
	{
403
		this.deltaTime = Math.round(this.past_time / 3600);
404
		return true;
405
	}
406
407
	return false;
408
};
409
410
relativeTime.prototype.days = function()
411
{
412
	// Some days ago but less than a week?
413
	if (Math.round(this.past_time / 3600) >= 24 && Math.round(this.past_time / (24 * 3600)) < 7)
414
	{
415
		this.deltaTime = Math.round(this.past_time / (24 * 3600));
416
		return true;
417
	}
418
419
	return false;
420
};
421
422
relativeTime.prototype.weeks = function()
423
{
424
	// Weeks ago but less than a month?
425
	if (Math.round(this.past_time / (24 * 3600)) >= 7 && Math.round(this.past_time / (24 * 3600)) < 30)
426
	{
427
		this.deltaTime = Math.round(this.past_time / (24 * 3600) / 7);
428
		return true;
429
	}
430
431
	return false;
432
};
433
434
relativeTime.prototype.months = function()
435
{
436
	// Months ago but less than a year?
437
	if (Math.round(this.past_time / (24 * 3600)) >= 30 && Math.round(this.past_time / (30 * 24 * 3600)) < 12)
438
	{
439
		this.deltaTime = Math.round(this.past_time / (30 * 24 * 3600));
440
		return true;
441
	}
442
443
	return false;
444
};
445
446
relativeTime.prototype.years = function()
447
{
448
	// Oha, we've passed at least a year?
449
	if (Math.round(this.past_time / (30 * 24 * 3600)) >= 12)
450
	{
451
		this.deltaTime = this.dateTo.getFullYear() - this.dateFrom.getFullYear();
452
		return true;
453
	}
454
455
	return false;
456
};
457
458
/**
459
 * Used to tag mentioned names when they are entered inline but NOT selected from the dropdown list
460
 * The name must have appeared in the dropdown and be found in that cache list
461
 *
462
 * @param {string} sForm the form that holds the container, only used for plain text QR
463
 * @param {string} sInput the container that atWho is attached
464
 */
465
function revalidateMentions(sForm, sInput)
466
{
467
	var cached_names,
468
		cached_queries,
469
		body,
470
		mentions,
471
		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...
472
		// Some random punctuation marks that may appear next to a name
473
		boundaries_pattern = /[ \.,;!\?'-\\\/="]/i;
474
475
	for (var i = 0, count = all_elk_mentions.length; i < count; i++)
476
	{
477
		// Make sure this mention object is for this selector, safety first
478
		if (all_elk_mentions[i].selector === sInput || all_elk_mentions[i].selector === '#' + sInput)
479
		{
480
			// Was this invoked as the editor plugin?
481
			if (all_elk_mentions[i].oOptions.isPlugin)
482
			{
483
				var $editor = $editor_data[all_elk_mentions[i].selector];
484
485
				cached_names = $editor.opts.mentionOptions.cache.names;
486
				cached_queries = $editor.opts.mentionOptions.cache.queries;
487
488
				// Clean up the newlines and spacing so we can find the @mentions
489
				body = $editor.getText().replace(/[\u00a0\r\n]/g, ' ');
490
				mentions = $($editor.opts.mentionOptions.cache.mentions);
491
			}
492
			// Or just our plain text quick reply box?
493
			else
494
			{
495
				cached_names = all_elk_mentions[i].oMention.cached_names;
496
				cached_queries = all_elk_mentions[i].oMention.cached_queries;
497
498
				// Keep everything separated with spaces, not newlines or no breakable
499
				body = document.forms[sForm][sInput].value.replace(/[\u00a0\r\n]/g, ' ');
500
501
				// The last pulldown box that atWho populated
502
				mentions = $(all_elk_mentions[i].oMention.mentions);
503
			}
504
505
			// Adding a space at the beginning to facilitate catching of mentions at the 1st char
506
			// and one at the end to simplify catching any last thing in the text
507
			body = ' ' + body + ' ';
508
509
			// First check if all those in the list are really mentioned
510
			$(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...
511
				var name = $(elem).data('name'),
512
					next_char,
513
					prev_char,
514
					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 507. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
515
516
				// It is undefined coming from a preview
517
				if (typeof(name) !== 'undefined')
518
				{
519
					if (index === -1)
520
						$(elem).remove();
521
					else
522
					{
523
						next_char = body.charAt(index + name.length);
524
						prev_char = body.charAt(index - 1);
525
526
						if (next_char !== '' && next_char.search(boundaries_pattern) !== 0)
527
							$(elem).remove();
528
						else if (prev_char !== '' && prev_char.search(boundaries_pattern) !== 0)
529
							$(elem).remove();
530
					}
531
				}
532
			});
533
534
			for (var k = 0, ccount = cached_queries.length; k < ccount; k++)
535
			{
536
				var names = cached_names[cached_queries[k]];
537
538
				for (var l = 0, ncount = names.length; l < ncount; l++)
539
				{
540
					if(checkWordOccurrence(body, names[l].name)) {
541
						pos = body.indexOf(' @' + names[l].name);
542
543
						// If there is something like "{space}@username" AND the following char is a space or a punctuation mark
544
						if (pos !== -1 && body.charAt(pos + 2 + names[l].name.length + 1).search(boundaries_pattern) === 0)
545
							mentions.append($('<input type="hidden" name="uid[]" />').val(names[l].id));
546
					}
547
				}
548
			}
549
		}
550
	}
551
}
552
553
/**
554
 * Check whether the word exists in a given paragraph
555
 *
556
 * @param paragraph to check
557
 * @param word to match
558
 */
559
560
function checkWordOccurrence(paragraph, word){
561
  return new RegExp( '\\b' + word + '\\b', 'i').test(paragraph);
562
}
563
564
/**
565
 * This is called from the editor plugin or display.template to set where to
566
 * find the cache values for use in revalidateMentions
567
 *
568
 * @param {string} selector id of element that atWho is attached to
569
 * @param {object} oOptions only set when called from the plugin, contains those options
570
 */
571
var all_elk_mentions = [];
572
function add_elk_mention(selector, oOptions)
573
{
574
	// Global does not exist, hummm
575
	if (all_elk_mentions.hasOwnProperty(selector))
576
		return;
577
578
	// No options means its attached to the plain text box
579
	if (typeof oOptions === 'undefined')
580
		oOptions = {};
581
	oOptions.selector = selector;
582
583
	// Add it to the stack
584
	all_elk_mentions[all_elk_mentions.length] = {
585
		selector: selector,
586
		oOptions: oOptions
587
	};
588
}
589
590
/**
591
 * Drag and drop to reorder ID's via UI Sortable
592
 *
593
 * @param {object} $
594
 */
595
(function($) {
596
	'use strict';
597
	$.fn.elkSortable = function(oInstanceSettings) {
598
		$.fn.elkSortable.oDefaultsSettings = {
599
			opacity: 0.7,
600
			cursor: 'move',
601
			axis: 'y',
602
			scroll: true,
603
			containment: 'parent',
604
			delay: 150,
605
			handle: '', // Restricts sort start click to the specified element, like category_header
606
			href: '', // If an error occurs redirect here
607
			tolerance: 'intersect', // mode to use for testing whether the item is hovering over another item.
608
			setorder: 'serialize', // how to return the data, really only supports serialize and inorder
609
			placeholder: '', // css class used to style the landing zone
610
			preprocess: '', // This function is called at the start of the update event (when the item is dropped) must in in global space
611
			tag: '#table_grid_sortable', // ID(s) of the container to work with, single or comma separated
612
			connect: '', // Use to group all related containers with a common CSS class
613
			sa: '', // Subaction that the xmlcontroller should know about
614
			title: '', // Title of the error box
615
			error: '', // What to say when we don't know what happened, like connection error
616
			token: '' // Security token if needed
617
		};
618
619
		// Account for any user options
620
		var oSettings = $.extend({}, $.fn.elkSortable.oDefaultsSettings, oInstanceSettings || {});
621
622
		if (typeof oSettings.infobar === 'undefined')
623
		{
624
			oSettings.infobar = new ElkInfoBar('sortable_bar', {error_class: 'errorbox', success_class: 'infobox'});
625
		}
626
627
		// Divs to hold our responses
628
		$("<div id='errorContainer'><div/>").appendTo('body');
629
630
		$('#errorContainer').css({'display': 'none'});
631
632
		// Find all oSettings.tag and attach the UI sortable action
633
		$(oSettings.tag).sortable({
634
			opacity: oSettings.opacity,
635
			cursor: oSettings.cursor,
636
			axis: oSettings.axis,
637
			handle: oSettings.handle,
638
			containment: oSettings.containment,
639
			connectWith: oSettings.connect,
640
			placeholder: oSettings.placeholder,
641
			tolerance: oSettings.tolerance,
642
			delay: oSettings.delay,
643
			scroll: oSettings.scroll,
644
			helper: function(e, ui) {
645
				// Fist create a helper container
646
				var $originals = ui.children(),
647
					$helper = ui.clone(),
648
					$clone;
649
650
				// Replace the helper elements with spans, normally this is a <td> -> <span>
651
				// Done to make this container agnostic.
652
				$helper.children().each(function() {
653
					$(this).replaceWith(function(){
654
						return $("<span />", {html: $(this).html()});
655
					});
656
				});
657
658
				// Set the width of each helper cell span to be the width of the original cells
659
				$helper.children().each(function(index) {
660
					// Set helper cell sizes to match the original sizes
661
					return $(this).width($originals.eq(index).width()).css('display', 'inline-block');
662
				});
663
664
				// Next to overcome an issue where page scrolling does not work, we add the new agnostic helper
665
				// element to the body, and hide it
666
				$('body').append('<div id="clone" class="' + oSettings.placeholder + '">' + $helper.html() + '</div>');
667
				$clone = $('#clone');
668
				$clone.hide();
669
670
				// Append the clone element to the actual container we are working in and show it
671
				setTimeout(function() {
672
					$clone.appendTo(ui.parent());
673
					$clone.show();
674
				}, 1);
675
676
				// The above append process allows page scrolls to work while dragging the clone element
677
				return $clone;
678
			},
679
			update: function(e, ui) {
680
				// Called when an element is dropped in a new location
681
				var postdata = '',
682
					moved = ui.item.attr('id'),
683
					order = [],
684
					receiver = ui.item.parent().attr('id');
685
686
				// Calling a pre processing function?
687
				if (oSettings.preprocess !== '')
688
					window[oSettings.preprocess]();
689
690
				// How to post the sorted data
691
				if (oSettings.setorder === 'inorder')
692
				{
693
					// This will get the order in 1-n as shown on the screen
694
					$(oSettings.tag).find('li').each(function() {
695
						var aid = $(this).attr('id').split('_');
696
						order.push({name: aid[0] + '[]', value: aid[1]});
697
					});
698
					postdata = $.param(order);
699
				}
700
				// Get all id's in all the sortable containers
701
				else
702
				{
703
					$(oSettings.tag).each(function() {
704
						// Serialize will be 1-n of each nesting / connector
705
						if (postdata === "")
706
							postdata += $(this).sortable(oSettings.setorder);
707
						else
708
							postdata += "&" + $(this).sortable(oSettings.setorder);
709
					});
710
				}
711
712
				// Add in our security tags and additional options
713
				postdata += '&' + elk_session_var + '=' + elk_session_id;
714
				postdata += '&order=reorder';
715
				postdata += '&moved=' + moved;
716
				postdata += '&received=' + receiver;
717
718
				if (oSettings.token !== '')
719
					postdata += '&' + oSettings.token.token_var + '=' + oSettings.token.token_id;
720
721
				// And with the post data prepared, lets make the ajax request
722
				$.ajax({
723
					type: "POST",
724
					url: elk_scripturl + "?action=xmlhttp;sa=" + oSettings.sa + ";xml",
725
					dataType: "xml",
726
					data: postdata
727
				})
728
				.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...
729
					oSettings.infobar.isError();
730
					oSettings.infobar.changeText(textStatus).showBar();
731
					// Reset the interface?
732
					if (oSettings.href !== '')
733
						setTimeout(function() {
734
							window.location.href = elk_scripturl + oSettings.href;
735
						}, 1000);
736
				})
737
				.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...
738
					var $_errorContent = $('#errorContent'),
739
						$_errorContainer = $('#errorContainer');
740
741
					if ($(data).find("error").length !== 0)
742
					{
743
						// Errors get a modal dialog box and redirect on close
744
						$_errorContainer.append('<p id="errorContent"></p>');
745
						$_errorContent.html($(data).find("error").text());
746
						$_errorContent.dialog({
747
							autoOpen: true,
748
							title: oSettings.title,
749
							modal: true,
750
							close: function(event, ui) {
0 ignored issues
show
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...
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...
751
								// Redirecting due to the error, that's a good idea
752
								if (oSettings.href !== '')
753
									window.location.href = elk_scripturl + oSettings.href;
754
							}
755
						});
756
					}
757
					else if ($(data).find("elk").length !== 0)
758
					{
759
						// Valid responses get the unobtrusive slider
760
						oSettings.infobar.isSuccess();
761
						oSettings.infobar.changeText($(data).find('elk > orders > order').text()).showBar();
762
					}
763
					else
764
					{
765
						// Something "other" happened ...
766
						$_errorContainer.append('<p id="errorContent"></p>');
767
						$_errorContent.html(oSettings.error + ' : ' + textStatus);
768
						$_errorContent.dialog({autoOpen: true, title: oSettings.title, modal: true});
769
					}
770
				})
771
				.always(function(data, textStatus, jqXHR) {
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 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...
772
					if ($(data).find("elk > tokens > token").length !== 0)
773
					{
774
						// Reset the token
775
						oSettings.token.token_id = $(data).find("tokens").find('[type="token"]').text();
776
						oSettings.token.token_var = $(data).find("tokens").find('[type="token_var"]').text();
777
					}
778
				});
779
			}
780
		});
781
	};
782
})(jQuery);
783
784
/**
785
 * Helper function used in the preprocess call for drag/drop boards
786
 * Sets the id of all 'li' elements to cat#,board#,childof# for use in the
787
 * $_POST back to the xmlcontroller
788
 */
789
function setBoardIds() {
790
	// For each category of board
791
	$("[id^=category_]").each(function() {
792
		var cat = $(this).attr('id').split('category_'),
793
			uls = $(this).find("ul");
794
795
		// First up add drop zones so we can drag and drop to each level
796
		if (uls.length === 1)
797
		{
798
			// A single empty ul in a category, this can happen when a cat is dragged empty
799
			if ($(uls).find("li").length === 0)
800
				$(uls).append('<li id="cbp_' + cat + ',-1,-1"></li>');
801
			// Otherwise the li's need a child ul so we have a "child-of" drop zone
802
			else
803
				$(uls).find("li:not(:has(ul))").append('<ul class="nolist elk_droppings"></ul>');
804
		}
805
		// All others normally
806
		else
807
			$(uls).find("li:not(:has(ul))").append('<ul class="nolist elk_droppings"></ul>');
808
809
		// Next make find all the ul's in this category that have children, update the
810
		// id's with information that indicates the 1-n and parent/child info
811
		$(this).find('ul:parent').each(function(i, ul) {
0 ignored issues
show
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...
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...
812
813
			// Get the (li) parent of this ul
814
			var parentList = $(this).parent('li').attr('id'),
815
					pli = 0;
816
817
			// No parent, then its a base node 0, else its a child-of this node
818
			if (typeof (parentList) !== "undefined")
819
			{
820
				pli = parentList.split(",");
821
				pli = pli[1];
822
			}
823
824
			// Now for each li in this ul
825
			$(this).find('li').each(function(i, el) {
826
				var currentList = $(el).attr('id');
827
				var myid = currentList.split(",");
828
829
				// Remove the old id, insert the newly computed cat,brd,childof
830
				$(el).removeAttr("id");
831
				myid = "cbp_" + cat[1] + "," + myid[1] + "," + pli;
832
				$(el).attr('id', myid);
833
			});
834
		});
835
	});
836
}
837
838
/**
839
 * Expands the ... of the page indexes
840
 *
841
 * @todo not exactly a plugin and still very bound to the theme structure
842
 *
843
 */
844
;(function($) {
845
	$.fn.expand_pages = function() {
846
		// Used when the user clicks on the ... to expand instead of just a hover expand
847
		function expand_pages($element)
848
		{
849
			var $baseAppend = $($element.closest('.linavPages')),
850
				boxModel = $baseAppend.prev().clone(),
851
				aModel = boxModel.find('a').clone(),
852
				expandModel = $element.clone(),
853
				perPage = $element.data('perpage'),
854
				firstPage = $element.data('firstpage'),
855
				lastPage = $element.data('lastpage'),
856
				rawBaseurl = $element.data('baseurl'),
857
				baseurl = elk_scripturl + $element.data('baseurl'),
858
				first,
859
				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