Completed
Pull Request — release-2.1 (#4823)
by
unknown
08:48
created

Themes/default/scripts/smf_fileUpload.js (20 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
function smf_fileUpload(oOptions) {
2
3
	var previewNode = document.querySelector('#au-template');
4
		previewNode.id = '';
5
		previewTemplate = previewNode.parentNode.innerHTML;
0 ignored issues
show
The variable previewTemplate seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.previewTemplate.
Loading history...
6
		previewNode.parentNode.removeChild(previewNode);
7
8
	// Default values in case oOptions isn't defined.
9
	var dOptions = {
10
		url: smf_prepareScriptUrl(smf_scripturl) + 'action=uploadAttach;sa=add;' + smf_session_var + '=' + smf_session_id + (current_board ? ';board=' + current_board : ''),
11
		parallelUploads: 1,
12
		filesizeBase: 1024,
13
		paramName: 'attachment',
14
		uploadMultiple: true,
15
		previewsContainer: '#au-previews',
16
		previewTemplate: previewTemplate,
17
		acceptedFiles: '.doc,.gif,.jpg,.pdf,.png,.txt,.zip',
18
		thumbnailWidth: 100,
19
		thumbnailHeight: null,
20
		autoQueue: false,
21
		clickable: '.fileinput-button',
22
		currentUsedSize: 0,
23
		timeout: null,
24
		smf_insertBBC: function (file, w, h) {
25
26
			var mime_type = typeof file.type !== "undefined" ? file.type : (typeof file.mime_type !== "undefined" ? file.mime_type : ''),
27
				bbcOptionalParams = {
28
					width: mime_type.indexOf('image') == 0 && + w > 0 ? (' width=' + w) : '',
29
					height: mime_type.indexOf('image') == 0 && + h > 0 ? (' height=' + h) : '',
30
					name: typeof file.name !== "undefined" ? (' name=' + file.name) : '',
31
					type: ' type=' + mime_type,
32
				};
33
34
			return '[attach' + bbcOptionalParams.width + bbcOptionalParams.height + decodeURIComponent(bbcOptionalParams.name) + bbcOptionalParams.type + ']' + file.attachID + '[/attach]';
35
		},
36
		createMaxSizeBar: function () {
37
38
			// Update the MaxSize bar to reflect the new size percentage.
39
			var currentSize = Math.round(myDropzone.options.currentUsedSize / 1024),
40
				maxSize = myDropzone.options.maxTotalSize,
41
				usedPercentage = Math.round($.fn.percentToRange($.fn.rangeToPercent(currentSize, 0, maxSize), 0, 100));
42
43
			// 3 basic colors.
44
			if (usedPercentage <= 33)
45
				percentage_class = 'green';
0 ignored issues
show
The variable percentage_class seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.percentage_class.
Loading history...
46
47
			else if (usedPercentage >= 34 && usedPercentage <= 66)
48
				percentage_class = 'yellow';
49
50
			else
51
				percentage_class = 'red';
52
53
			$('#maxFiles_progress').removeClass().addClass('progress_bar progress_' + percentage_class).show();
54
			$('#maxFiles_progress_text').show();
55
			$('#maxFiles_progress .bar').width(usedPercentage + '%');
56
57
			// Show or update the text.
58
			$('#maxFiles_progress_text').text(myDropzone.options.text_max_size_progress.replace('{currentTotal}', maxSize).replace('{currentRemain}', currentSize));
59
60
			if (maxSize == 0) {
61
				$('#maxFiles_progress').hide();
62
				$('#maxFiles_progress_text').hide();
63
			}
64
		},
65
		accept: function (file, done) {
66
67
			var currentlyUsedKB = myDropzone.options.currentUsedSize / 1024,
68
				totalKB = myDropzone.options.maxTotalSize,
69
				fileKB = myDropzone.options.maxFileSize,
70
				uploadedFileKB = file.size / 1024;
71
72
			// Check against the max amount of files setting.
73
			if ((myDropzone.options.maxFileAmount != null) && (myDropzone.getAcceptedFiles().length) >= myDropzone.options.maxFileAmount)
74
				done(this.options.dictMaxFilesExceeded);
75
76
			// Need to check if the added file doesn't surpass the total max size setting.
77
			myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize + file.size;
78
79
			// This file has reached the max total size per post.
80
			if (totalKB > 0 && currentlyUsedKB > totalKB) {
81
				done(myDropzone.options.text_totalMaxSize.replace('{currentTotal}', totalKB).replace('{currentRemain}', currentlyUsedKB));
82
83
				// Remove the file size from the total
84
				myDropzone.options.currentUsedSize - file.size;
85
86
				// File is cancel.
87
				file.status = Dropzone.CANCELED;
88
			}
89
			else if (fileKB > 0 && uploadedFileKB > fileKB) {
90
				done(myDropzone.options.dictFileTooBig);
91
92
				// File is cancel.
93
				file.status = Dropzone.CANCELED;
94
95
				// File wasn't accepted so remove its size.
96
				myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize - file.size;
97
			}
98
			else {
99
100
				myDropzone.options.createMaxSizeBar();
101
102
				// All done!
103
				done();
104
			}
105
		},
106
	};
107
108
	if (oOptions.thumbnailHeight && oOptions.thumbnailWidth) {
109
		if (oOptions.thumbnailHeight > oOptions.thumbnailWidth) {
110
			oOptions.thumbnailWidth = null;
111
		}
112
113
		else {
114
			oOptions.thumbnailHeight = null;
115
		}
116
	}
117
118
	$.extend(true, dOptions, oOptions);
119
120
	var myDropzone = new Dropzone('div#attachUpload', dOptions);
121
122
	myDropzone.on('addedfile', function (file) {
123
124
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
125
126
		// If the attachment is an image and has a thumbnail, show it. Otherwise fallback to the generic thumbfile.
127
		if (!file.type.match(/image.*/)) {
128
			myDropzone.emit('thumbnail', file, smf_images_url + '/generic_attach.png');
129
		}
130
131
		// If the file is too small, it won't have a thumbnail, show the regular file.
132
		else if (typeof file.isMock !== "undefined" && typeof file.attachID !== "undefined") {
133
			myDropzone.emit('thumbnail', file, smf_prepareScriptUrl(smf_scripturl) + 'action=dlattach;attach=' + (file.thumbID > 0 ? file.thumbID : file.attachID) + ';type=preview');
134
		}
135
136
		file.name = file.name.php_to8bit().php_urlencode();
137
138
		// Show the file info.
139
		_thisElement.find('.attach-ui').fadeIn();
140
141
		// Show the progress bar
142
		$('#maxFiles_progress').show();
143
144
		// Create a function to insert the BBC attach tag.
145
		file.insertAttachment = function (_innerElement, response) {
146
			insertButton = $('<a />')
0 ignored issues
show
The variable insertButton seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.insertButton.
Loading history...
147
				.addClass('button')
148
				.prop('disabled', false)
149
				.text(myDropzone.options.text_insertBBC)
150
				.on('click', function (e) {
151
					e.preventDefault();
152
153
					w = _innerElement.find('input[name="attached_BBC_width"]').val();
0 ignored issues
show
The variable w seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.w.
Loading history...
154
					h = _innerElement.find('input[name="attached_BBC_height"]').val();
0 ignored issues
show
The variable h seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.h.
Loading history...
155
156
					// Get the editor stuff.
157
					var e = $('#' + oEditorID).get(0);
158
					var oEditor = sceditor.instance(e);
159
160
					oEditor.insert(myDropzone.options.smf_insertBBC(response, w, h));
161
				})
162
				.appendTo(_innerElement.find('.attach-ui'));
163
		};
164
165
		// Replace the file with a message when the attachment has been deleted.
166
		file.deleteAttachment = function (_innerElement, attachmentId, file) {
167
168
			deleteButton = $('<a />')
0 ignored issues
show
The variable deleteButton seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.deleteButton.
Loading history...
169
				.addClass('button')
170
				.prop('disabled', false)
171
				.text(myDropzone.options.text_deleteAttach)
172
				.one('click', function (e) {
173
174
					$this = $(this);
0 ignored issues
show
The variable $this seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.$this.
Loading history...
175
176
					// Perform the action only after receiving the confirmation.
177
					if (!confirm(smf_you_sure)) {
178
						return;
179
					}
180
181
					// Let the server know you want to delete the file you just recently uploaded...
182
					$.ajax({
183
						url: smf_prepareScriptUrl(smf_scripturl) + 'action=uploadAttach;sa=delete;attach=' + attachmentId + ';' + smf_session_var + '=' + smf_session_id + (current_board ? ';board=' + current_board : ''),
184
						type: 'GET',
185
						dataType: 'json',
186
						beforeSend: function () {
187
							ajax_indicator(true);
188
						},
189
						complete: function (jqXHR, textStatus) {
190
							ajax_indicator(false);
191
192
							// Delete the button.
193
							$this.fadeOutAndRemove('slow');
194
						},
195
						success: function (data, textStatus, xhr) {
196
197
							// For dramatic purposes only!
198
							_innerElement.removeClass('infobox').addClass(data.type + 'box');
199
200
							// Remove the text field and show a nice confirmation message.
201
							_innerElement.find('.attached_BBC').text(data.text);
202
							_thisElement.find('.attach-info a.insertBBC').fadeOut();
203
204
							// Do stuff only if the file was actually accepted and it doesn't have an error status.
205
							if (file.accepted && file.status != Dropzone.ERROR) {
206
207
								// Need to remove the file size to make sure theres plenty of room for another one.
208
								myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize - file.size;
209
210
								// Re-count!
211
								myDropzone.options.createMaxSizeBar();
212
							}
213
						},
214
						error: function (xhr, textStatus, errorThrown) {
215
216
							// Tell the user something horrible happen!
217
							_innerElement.find('span.error').append(textStatus.error.join('<br>')).css({
218
								'text-decoration': 'none'
219
							});
220
221
							// For dramatic purposes only!
222
							_innerElement.removeClass('infobox').addClass('errorbox');
223
						}
224
					});
225
				})
226
				.appendTo(_innerElement.find('.attach-ui'));
227
228
				// Show the current amount of remaining files
229
				$('.attach_remaining').html(myDropzone.getAcceptedFiles().length);
230
		};
231
232
		// Hookup the upload button.
233
		_thisElement.find('.upload').on('click', function () {
234
			myDropzone.enqueueFile(file);
235
		});
236
237
		// Show the main stuff!
238
		_thisElement.addClass('descbox');
239
240
		// Show the upload and cancel all buttons only if there is something to cancel/upload.
241
		if (myDropzone.getFilesWithStatus(Dropzone.ADDED).length == 1) {
242
			$('div#attachUpload').find('#attach-cancelAll, #attach-uploadAll').fadeIn('slow', function() {
243
					$(this).css('display', 'inline-block');
244
			});
245
		}
246
	});
247
248
	// Stuff to do when a file gets cancel.
249
	myDropzone.on('removedfile', function (file) {
250
251
		// Do stuff only if the file was actually accepted and it doesn't have an error status.
252
		if (file.accepted && file.status != Dropzone.ERROR) {
253
			// Need to remove the file size to make sure theres plenty of room for another one.
254
			myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize - file.size;
255
256
			// Re-count!
257
			myDropzone.options.createMaxSizeBar();
258
		}
259
260
		// Hide the cancel and upload all buttons if there is nothing to cancel/upload anymore.
261
		if (myDropzone.getFilesWithStatus(Dropzone.ADDED).length == 0) {
262
			$('div#attachUpload').find('#attach-cancelAll, #attach-uploadAll').fadeOut();
263
			$('#maxFiles_progress').fadeOut();
264
		}
265
	});
266
267
    // Event for when a file has been canceled
268
    myDropzone.on("canceled", function(file) {
269
        // Need to remove the file size to make sure theres plenty of room for another one.
270
        myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize - file.size;
271
272
        // Re-count!
273
        myDropzone.options.createMaxSizeBar();
274
275
        this.removeFile(file);
276
    });
277
278
	// Event for when the total amount of files exceeds the maxFiles option
279
    myDropzone.on("maxfilesexceeded", function(file) {
280
281
        // Need to remove the file size to make sure there is plenty of room for another one.
282
        myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize - file.size;
283
284
        // Re-count!
285
        myDropzone.options.createMaxSizeBar();
286
287
    	this.removeFile(file);
288
    });
289
290
	// Update the total progress bar.
291
	myDropzone.on('totaluploadprogress', function (progress) {
292
		$('#total-progress span').width(progress + '%');
293
	});
294
295
	myDropzone.on('error', function (file, errorMessage, xhr) {
296
297
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
298
299
		// Remove the 'upload' button.
300
		_thisElement.find('.upload').fadeOutAndRemove('slow');
301
302
		// Set a nice css class to make it more obvious there is an error.
303
		_thisElement.addClass('errorbox').removeClass('descbox');
304
	});
305
306
	myDropzone.on('success', function (file, responseText, e) {
307
308
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
309
310
		// Remove the 'upload' button.
311
		_thisElement.find('.upload').fadeOutAndRemove('slow');
312
313
		// Don't do anything if there is no response from server.
314
		if (!responseText) {
315
			return;
316
		}
317
318
		// There is a general error.
319
		if (responseText.generalErrors) {
320
			_thisElement.find('span.error').append(responseText.generalErrors.join('<br>'));
321
			return;
322
		}
323
324
		// Server returns an array.
325
		response = responseText.files[0];
0 ignored issues
show
The variable response seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.response.
Loading history...
326
327
		// Show the input field and insert button.
328
		_thisElement.find('.attach-info div.attached_BBC').fadeIn();
329
		_thisElement.find('.attach-info a.insertBBC').fadeIn();
330
331
		if (typeof response.mime_type == "undefined" || response.mime_type.indexOf('image') != 0) {
332
			_thisElement.find('.attach-info .attached_BBC_width_height').hide();
333
		}
334
335
		// The request was complete but the server returned an error.
336
		if (typeof response.errors !== 'undefined' && response.errors.length > 0) {
337
338
			_thisElement.addClass('errorbox').removeClass('descbox');
339
340
			// Show the server error.
341
			_thisElement.find('span.error').append(response.errors.join('<br>'));
342
			return;
343
		}
344
345
		// If there wasn't any error, change the current cover.
346
		_thisElement.addClass('infobox').removeClass('descbox');
347
348
		// Append the BBC.
349
		w = _thisElement.find('input[name="attached_BBC_width"]').val();
0 ignored issues
show
The variable w seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.w.
Loading history...
350
		h = _thisElement.find('input[name="attached_BBC_height"]').val();
0 ignored issues
show
The variable h seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.h.
Loading history...
351
		_thisElement.find('input[name="attachBBC"]').val(myDropzone.options.smf_insertBBC(response, w, h));
352
353
		file.insertAttachment(_thisElement, response);
354
355
		// You have already loaded this attachment, to prevent abuse, you cannot cancel it and upload a new one.
356
		_thisElement.find('a.cancel').fadeOutAndRemove('slow');
357
358
		// Fire up the delete button.
359
		file.deleteAttachment(_thisElement, response.attachID, file);
360
	});
361
362
	myDropzone.on('uploadprogress', function (file, progress, bytesSent) {
363
364
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
365
366
		// Get the current file box progress bar, set its inner span's width accordingly.
367
		_thisElement.find('.progress_bar .bar').width(progress + '%');
368
	});
369
370
	myDropzone.on('complete', function (file, progress, bytesSent) {
371
372
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
373
374
		// Hide the progress bar.
375
		_thisElement.find('.progress_bar').fadeOut();
376
377
		// Finishing up mocking!
378
		if (typeof file.isMock !== "undefined" && typeof file.attachID !== "undefined") {
379
			// Show the input field.
380
			_thisElement.find('.attach-info div.attached_BBC').fadeIn();
381
			_thisElement.find('.attach-info a.insertBBC').fadeIn();
382
383
			if (typeof file.type == "undefined" || file.type.indexOf('image') != 0) {
384
				_thisElement.find('.attach-info .attached_BBC_width_height').hide();
385
			}
386
387
			// If there wasn't any error, change the current cover.
388
			_thisElement.addClass('infobox').removeClass('descbox');
389
390
			// Remove the 'upload' button.
391
			_thisElement.find('.upload').fadeOutAndRemove('slow');
392
393
			// Append the BBC.
394
			w = _thisElement.find('input[name="attached_BBC_width"]').val();
0 ignored issues
show
The variable w seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.w.
Loading history...
395
			h = _thisElement.find('input[name="attached_BBC_height"]').val();
0 ignored issues
show
The variable h seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.h.
Loading history...
396
			_thisElement.find('input[name="attachBBC"]').val(myDropzone.options.smf_insertBBC(file, w, h));
397
398
			file.insertAttachment(_thisElement, file);
399
400
			// You have already loaded this attachment, to prevent abuse, you cannot cancel it and upload a new one.
401
			_thisElement.find('a.cancel').fadeOutAndRemove('slow');
402
403
			// Fire up the delete button.
404
			file.deleteAttachment(_thisElement, file.attachID, file);
405
406
			// Need to count this towards the max limit.
407
			myDropzone.options.currentUsedSize = myDropzone.options.currentUsedSize + file.size;
408
409
			// Re-count and display the bar.
410
			myDropzone.options.createMaxSizeBar();
411
		}
412
	});
413
414
	// Show each individual's progress bar.
415
	myDropzone.on('sending', function (file, xhr, formData) {
416
417
		_thisElement = $(file.previewElement);
0 ignored issues
show
The variable _thisElement seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window._thisElement.
Loading history...
418
419
		// Show the progress bar when upload starts.
420
		_thisElement.find('.progress_bar').fadeIn();
421
422
		// Show the total progress bar when upload starts.
423
		$("#total-progress").fadeIn();
424
	});
425
426
	// Update the total progress bar.
427
	myDropzone.on("totaluploadprogress", function (progress) {
428
		$("#total-progress span").width(progress + '%');
429
	});
430
431
	// Hide the total progress bar when nothing's uploading anymore.
432
	myDropzone.on("queuecomplete", function (progress) {
433
		$("#total-progress").fadeOut();
434
	});
435
436
	// Add an event for uploading and cancelling all files.
437
	$('a#attach-cancelAll').on('click', function () {
438
439
		if (!confirm(smf_you_sure))
440
			return;
441
442
		myDropzone.removeAllFiles(true);
443
		myDropzone.options.createMaxSizeBar();
444
445
		// Set to zero
446
		myDropzone.options.currentUsedSize = 0;
447
		myDropzone.options.maxTotalSize = 0;
448
449
	});
450
451
	$('a#attach-uploadAll').on('click', function () {
452
453
		if (!confirm(smf_you_sure)) {
454
			return;
455
		}
456
457
		myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
458
		myDropzone.options.createMaxSizeBar();
459
	});
460
461
	// Need to tell the user they cannot post until all files are either uploaded or canceled.
462
	$("input[name ='post']").on('click', function (e) {
463
464
		attachAdded = myDropzone.getFilesWithStatus(Dropzone.ADDED).length;
0 ignored issues
show
The variable attachAdded seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.attachAdded.
Loading history...
465
		attachQueued = myDropzone.getFilesWithStatus(Dropzone.QUEUED).length;
0 ignored issues
show
The variable attachQueued seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.attachQueued.
Loading history...
466
467
		if (attachAdded > 0 || attachQueued > 0) {
468
			alert(myDropzone.options.text_attachLeft);
469
			e.preventDefault();
470
			e.stopPropagation();
471
			return false;
472
		}
473
	});
474
475
	// Hide the default way to show already attached files.
476
	$('#postAttachment').fadeOutAndRemove('slow');
477
478
	// Show any attachments already uploaded.
479
	if (typeof current_attachments !== "undefined") {
480
		$.each(current_attachments, function (key, mock) {
481
482
			// Tell the world this is a mock file!
483
			mock.isMock = true;
484
485
			// Tell everyone this file was accepted.
486
			mock.status = Dropzone.ADDED;
487
			mock.accepted = true;
488
489
			myDropzone.emit("addedfile", mock);
490
491
			// This file is "completed".
492
			myDropzone.emit("complete", mock);
493
		});
494
	}
495
}
496