View file upload/js/xenforo/full/attachment_editor_new.js

File size: 16.2Kb
/** @param {jQuery} $ jQuery Object */
!function($, window, document, _undefined)
{
	// *********************************************************************

	var insertSpeed = XenForo.speed.normal,
		removeSpeed = XenForo.speed.fast;

	XenForo.AttachmentUploader = function($container)
	{
		var ERRORS = {
			TOO_LARGE: 110,
			EMPTY: 120,
			INVALID_EXTENSION: 130
		};

		var $trigger = $($container.data('trigger')),
			$form = $container.closest('form'),
			postParams = {},
			attachmentErrorAlert = function(file, errorCode, message)
			{
				var messageText = $container.data('err-' + errorCode) || message;

				if (!messageText)
				{
					messageText = $container.data('err-unknown');
				}

				if (file)
				{
					XenForo.alert(messageText + '<br /><br />' + XenForo.htmlspecialchars(file.name));
				}
				else
				{
					XenForo.alert(messageText);
				}
			},
			maxFileSize = $container.data('maxfilesize'),
			maxUploads = $container.data('maxuploads'),
			extensions = $container.data('extensions'),
			uniqueKey = $container.data('uniquekey');

		extensions = extensions.replace(/[;*.]/g, '')
			.replace(/,{2,}/g, ',')
			.replace(/^,+/, '').replace(/,+$/, '');

		// --------------------------------------

		// un-hide the upload button
		$container.show();

		var flow,
			useFlow = window.Flow ? true : false;

		var ua = navigator.userAgent;
		if (ua.match(/Android [1-4]/))
		{
			var chrome = ua.match(/Chrome\/([0-9]+)/);
			if (!chrome || parseInt(chrome[1], 10) < 33)
			{
				console.log('Old Android WebView detected. Must fallback to basic uploader.');
				useFlow = false;
			}
		}

		if (useFlow)
		{
			var useFusty = false;

			var flowOptions = {
				target: $container.data('action'),
				allowDuplicateUploads: true,
				fileParameterName: $container.data('postname'),
				query: function()
				{
					var params = $.extend({
						_xfToken: XenForo._csrfToken,
						_xfNoRedirect: 1,
						_xfResponseType: useFusty ? 'json-text' : 'json'
					}, postParams);

					$container.find('.HiddenInput').each(function(i, element)
					{
						var $element = $(element);
						params[$element.data('name')] = $element.data('value');
					});

					return params;
				},
				simultaneousUploads: 1,
				testChunks: false,
				chunkSize: 4 * 1024 * 1024 * 1024, // always one chunk
				readFileFn: function (fileObj, startByte, endByte, fileType, chunk)
				{
					var function_name = 'slice';

					if (fileObj.file.slice) function_name =  'slice';
					else if (fileObj.file.mozSlice) function_name = 'mozSlice';
					else if (fileObj.file.webkitSlice) function_name = 'webkitSlice';

					if (!fileType)
					{
						fileType = '';
					}

					chunk.readFinished(fileObj.file[function_name](startByte, endByte, fileType));
				}
			};

			flow = new Flow(flowOptions);
			if (!flow.support)
			{
				flow = new FustyFlow(flowOptions);
				useFusty = true;
			}

			var $flowTarget = $('<span />').insertAfter($trigger).append($trigger);

			flow.assignBrowse($flowTarget[0], false, false, {
				accept: '.' + extensions.toLowerCase().replace(/,/g, ',.')
			});

			if (useFusty)
			{
				var outerWidth = $trigger.outerWidth();
				if (outerWidth > 30)
				{
					$flowTarget.css('width', outerWidth);
				}
			}
			else
			{
				var $file = $flowTarget.find('input[type=file]');
				$file.css('overflow', 'hidden');
				$file.css(XenForo.isRTL() ? 'right' : 'left', -1000);
			}

			$trigger.on('click BeforeOverlayTrigger', function(e)
			{
				e.preventDefault();
			});

			flow.on('fileAdded', function(file)
			{
				var isImage = false;

				// for improved swfupload compat
				file.id = file.uniqueIdentifier;

				switch (file.name.substr(file.name.lastIndexOf('.')).toLowerCase())
				{
					case '.jpg':
					case '.jpeg':
					case '.jpe':
					case '.png':
					case '.gif':
						isImage = true;
				}

				var event = $.Event('AttachmentQueueValidation');
				event.file = file;
				event.flow = flow;
				event.isImage = isImage;
				$container.trigger(event);

				if (event.isDefaultPrevented())
				{
					return false;
				}

				if (file.size > maxFileSize && !isImage) // allow web images to bypass the file size check, as they (may) be resized on the server
				{
					attachmentErrorAlert(file, ERRORS.TOO_LARGE);
					return false;
				}

				event = $.Event('AttachmentQueued');
				event.file = file;
				event.flow = flow;
				event.isImage = isImage;
				$container.trigger(event);
			});
			flow.on('filesSubmitted', function() { flow.upload(); });
			flow.on('fileProgress', function(file)
			{
				// for improved swfupload compat
				file.id = file.uniqueIdentifier;

				$container.trigger(
				{
					type: 'AttachmentUploadProgress',
					file: file,
					bytes: Math.round(file.progress() * file.size),
					flow: flow
				});
			});
			flow.on('fileSuccess', function(file, message)
			{
				try
				{
					if (useFusty && message.substr(0, 1) == '<')
					{
						message = $($.parseHTML(message)).text();
					}

					var ajaxData = $.parseJSON(message);
				}
				catch (e)
				{
					console.warn(e);
					return;
				}

				// for improved swfupload compat
				file.id = file.uniqueIdentifier;

				if (ajaxData.error)
				{
					$container.trigger({
						type: 'AttachmentUploadError',
						file: file,
						ajaxData: ajaxData,
						flow: flow
					});
				}
				else
				{
					$container.trigger({
						type: 'AttachmentUploaded',
						file: file,
						ajaxData: ajaxData,
						flow: flow
					});
				}
			});
			flow.on('fileError', function(file, message)
			{
				var errorCode = 0;

				// for improved swfupload compat
				file.id = file.uniqueIdentifier;

				$container.trigger({
					type: 'AttachmentUploadError',
					file: file,
					errorCode: errorCode,
					message: message,
					ajaxData: { error: [ $container.data('err-unknown') ] },
					flow: flow
				});
			});
		}
		else
		{
			console.error('flow.js must be loaded');
		}

		/**
		 * Bind to the AutoInlineUploadEvent of the document, just in case SWFUpload failed
		 */
		$(document).bind('AutoInlineUploadComplete', function(e)
		{
			if (uniqueKey && e.ajaxData && uniqueKey !== e.ajaxData.key)
			{
				return false;
			}

			var $target = $(e.target);

			if ($target.is('form.AttachmentUploadForm'))
			{
				if ($trigger.overlay())
				{
					$trigger.overlay().close();
				}

				$container.trigger({
					type: 'AttachmentUploaded',
					ajaxData: e.ajaxData
				});

				return false;
			}
		});

		return {
			getSwfUploader: function()
			{
				return null;
			},
			getFlowUploader: function()
			{
				return flow;
			},
			swfAlert: attachmentErrorAlert,
			attachmentErrorAlert: attachmentErrorAlert
		};
	};

	// *********************************************************************

	XenForo.AttachmentEditor = function($editor)
	{
		this.setVisibility = function(instant)
		{
			var $hideElement = $editor.closest('.ctrlUnit'),
				$insertAll = $editor.find('.AttachmentInsertAllBlock'),
				$files = $editor.find('.AttachedFile:not(#AttachedFileTemplate)'),
				$images = $files.filter('.AttachedImage');

			console.log('Attachments changed, total files: %d, images: %d', $files.length, $images.length);

			if ($hideElement.length == 0)
			{
				$hideElement = $editor;
			}

			if (instant === true)
			{
				if ($files.length)
				{
					if ($images.length > 1)
					{
						$insertAll.show();
					}
					else
					{
						$insertAll.hide();
					}

					$hideElement.show();
				}
				else
				{
					$hideElement.hide();
				}
			}
			else
			{
				if ($files.length)
				{
					if ($images.length > 1)
					{
						if ($hideElement.is(':hidden'))
						{
							$insertAll.show();
						}
						else
						{
							$insertAll.xfFadeDown(XenForo.speed.fast);
						}
					}
					else
					{
						if ($hideElement.is(':hidden'))
						{
							$insertAll.hide();
						}
						else
						{
							$insertAll.xfFadeUp(XenForo.speed.fast, false, XenForo.speed.fast, 'swing');
						}
					}

					$hideElement.xfFadeDown(XenForo.speed.normal);
				}
				else
				{
					$insertAll.slideUp(XenForo.speed.fast);

					$hideElement.xfFadeUp(XenForo.speed.normal, false, false, 'swing');
				}
			}
		};

		this.setVisibility(true);

		$('#AttachmentUploader').bind(
		{
			/**
			 * Fires when the upload button is clicked
			 */
			click: function()
			{
				$('textarea.BbCodeWysiwygEditor').each(function() {
					var ed = $(this).data('XenForo.BbCodeWysiwygEditor');
					if (ed)
					{
						ed.blurEditor();
					}
				});
			},

			/**
			 * Fires when a file is added to the upload queue
			 *
			 * @param event Including e.file
			 */
			AttachmentQueued: function(e)
			{
				var file = e.file,
					id = file.uniqueIdentifier || file.id;

				console.info('Queued file %s (%d bytes).', file.name, file.size);

				var $template = $('#AttachedFileTemplate').clone().attr('id', id);

				$template.find('.Filename').text(file.name);
				$template.find('.ProgressCounter').text('0%');
				$template.find('.ProgressGraphic span').css('width', '0%');

				if (e.isImage)
				{
					$template.addClass('AttachedImage');
				}

				$template.xfInsert('appendTo', '.AttachmentList.New', null, insertSpeed);

				$template.find('.AttachmentCanceller').css('display', 'block').click(function()
				{
					if (e.swfUpload)
					{
						e.swfUpload.cancelUpload(e.file.id);
					}
					else if (file.flowObj)
					{
						file.cancel();
					}

					$template.xfRemove(null, function() {
						$editor.trigger('AttachmentsChanged');
					}, removeSpeed, 'swing');
				});

				$editor.trigger('AttachmentsChanged');
			},

			/**
			 * Fires when an upload progress update is received
			 *
			 * @param event Including e.file and e.bytes
			 */
			AttachmentUploadProgress: function(e)
			{
				var file = e.file,
					bytes = e.bytes,
					id = file.uniqueIdentifier || file.id;

				console.log('Uploaded %d/%d bytes.', bytes, file.size);

				var percentNum = Math.min(100, Math.ceil(bytes * 100 / file.size)),
					percentage = percentNum + '%',
					$placeholder = $('#' + id),
					$counter = $placeholder.find('.ProgressCounter'),
					$graphic = $placeholder.find('.ProgressGraphic');

				$counter.text(percentage);
				$graphic.css('width', percentage);

				if (percentNum >= 100)
				{
					$placeholder.find('.AttachmentCanceller').prop('disabled', true).addClass('disabled');
				}

				if ($graphic.width() > $counter.outerWidth())
				{
					$counter.appendTo($graphic);
				}
			},

			/**
			 * Fires if an error occurs during the upload
			 *
			 * @param event
			 */
			AttachmentUploadError: function(e)
			{
				var error = '',
					file = e.file,
					id = file.uniqueIdentifier || file.id;

				$.each(e.ajaxData.error, function(i, errorText) { error += errorText + "\n"; });

				XenForo.alert(error + '<br /><br />' + XenForo.htmlspecialchars(file.name));

				var $attachment = $('#' + id),
					$editor = $attachment.closest('.AttachmentEditor');

				$attachment.xfRemove(null, function() {
					$editor.trigger('AttachmentsChanged');
				}, removeSpeed, 'swing');

				console.warn('AttachmentUploadError: %o', e);
			},

			/**
			 * Fires when a file has been successfully uploaded
			 *
			 * @param event
			 */
			AttachmentUploaded: function(e)
			{
				if (e.file) // SWFupload/flow.js method
				{
					var file = e.file,
						id = file.uniqueIdentifier || file.id,
						$attachment = $('#' + id),
						$attachmentText = $attachment.find('.AttachmentText'),
						$templateHtml = $(e.ajaxData.templateHtml),
						$thumbnail;

					$attachmentText.fadeOut(XenForo.speed.fast, function()
					{
						$templateHtml.find('.AttachmentText').xfInsert('insertBefore', $attachmentText, 'fadeIn', XenForo.speed.fast);

						$thumbnail = $attachment.find('.Thumbnail');
						$thumbnail.html($templateHtml.find('.Thumbnail').html());
						//XenForo.activate($thumbnail);

						$attachmentText.xfRemove();

						$attachment.attr('id', 'attachment' + e.ajaxData.attachment_id);
					});
				}
				else // regular javascript method
				{
					var $attachment = $('#attachment' + e.ajaxData.attachment_id);

					if (!$attachment.length)
					{
						$attachment = $(e.ajaxData.templateHtml).xfInsert('appendTo', $editor.find('.AttachmentList.New'), null, insertSpeed);
					}
				}

				$editor.trigger('AttachmentsChanged');
			}
		});

		var thisVis = $.context(this, 'setVisibility');

		$('#QuickReply').bind('QuickReplyComplete', function(e)
		{
			$editor.find('.AttachmentList.New li:not(#AttachedFileTemplate)').xfRemove().promise().always(thisVis);
		});

		$editor.bind('AttachmentsChanged', thisVis);
	};

	// *********************************************************************

	XenForo.AttachmentInserter = function($trigger)
	{
		$trigger.click(function(e)
		{
			var $attachment = $trigger.closest('.AttachedFile').find('.Thumbnail a'),
				attachmentId = $attachment.data('attachmentid'),
			 	editor,
				bbcode,
				html,
				thumb = $attachment.find('img').attr('src'),
				img = $attachment.attr('href');

			e.preventDefault();

			if ($trigger.attr('name') == 'thumb')
			{
				bbcode = '[ATTACH]' + attachmentId + '[/ATTACH] ';
				html = '<img src="' + thumb + '" class="attachThumb bbCodeImage" alt="attachThumb' + attachmentId + '" /> ';
			}
			else
			{
				bbcode = '[ATTACH=full]' + attachmentId + '[/ATTACH] ';
				html = '<img src="' + img + '" class="attachFull bbCodeImage" alt="attachFull' + attachmentId + '" /> ';
			}

			var editor = XenForo.getEditorInForm($trigger.closest('form'), ':not(.NoAttachment)');
			if (editor)
			{
				if (editor.$editor)
				{
					editor.insertHtml(html);
					var update = editor.$editor.data('xenForoElastic');
					if (update)
					{
						setTimeout(function() { update(); }, 250);
						setTimeout(function() { update(); }, 1000);
					}
				}
				else
				{
					editor.val(editor.val() + bbcode);
				}
			}
		});
	};

	// *********************************************************************

	XenForo.AttachmentDeleter = function($trigger)
	{
		$trigger.css('display', 'block').click(function(e)
		{
			var $trigger = $(e.target),
				href = $trigger.attr('href') || $trigger.data('href'),
				$attachment = $trigger.closest('.AttachedFile'),
				$thumb = $trigger.closest('.AttachedFile').find('.Thumbnail a'),
				attachmentId = $thumb.data('attachmentid');

			if (href)
			{
				$attachment.xfFadeUp(XenForo.speed.normal, null, removeSpeed, 'swing');

				XenForo.ajax(href, '', function(ajaxData, textStatus)
				{
					if (XenForo.hasResponseError(ajaxData))
					{
						$attachment.xfFadeDown(XenForo.speed.normal);
						return false;
					}

					var $editor = $attachment.closest('.AttachmentEditor');

					$attachment.xfRemove(null, function() {
						$editor.trigger('AttachmentsChanged');
					}, removeSpeed, 'swing');
				});

				if (attachmentId)
				{
					var editor = XenForo.getEditorInForm($trigger.closest('form'), ':not(.NoAttachment)');
					if (editor && editor.$editor)
					{
						editor.$editor.find('img[alt=attachFull' + attachmentId + '], img[alt=attachThumb' + attachmentId + ']').remove();
						var update = editor.$editor.data('xenForoElastic');
						if (update)
						{
							update();
						}
					}
				}

				return false;
			}

			console.warn('Unable to locate href for attachment deletion from %o', $trigger);
		});
	};

	// *********************************************************************

	XenForo.AttachmentInsertAll = function($trigger)
	{
		$trigger.click(function()
		{
			$('.AttachmentInserter[name=' + $trigger.attr('name') + ']').each(function(i, input)
			{
				$(input).trigger('click');
			});
		});
	};

	// *********************************************************************

	XenForo.AttachmentDeleteAll = function($trigger)
	{
		$trigger.click(function()
		{
			// TODO: This is a fairly horrible way of doing this, but it's going to be used very infrequently.
			$('.AttachmentDeleter').each(function(i, input)
			{
				$(input).trigger('click');
			});
		});
	};

	// *********************************************************************

	XenForo.register('.AttachmentUploader', 'XenForo.AttachmentUploader');

	XenForo.register('.AttachmentEditor', 'XenForo.AttachmentEditor');

	XenForo.register('.AttachmentInserter', 'XenForo.AttachmentInserter');

	XenForo.register('.AttachmentDeleter', 'XenForo.AttachmentDeleter');

	XenForo.register('.AttachmentInsertAll', 'XenForo.AttachmentInsertAll');

	XenForo.register('.AttachmentDeleteAll', 'XenForo.AttachmentDeleteAll');
}
(jQuery, this, document);