Created
July 23, 2012 12:05
-
-
Save rich97/3163263 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
var $uploader = $('#uploader') | |
, $feedback = $('#feedback') | |
, $uploadForm = $('#upload-form') | |
, $imagePreviews = $('#image-previews') | |
, $imageErrors = $('#image-errors') | |
, $imageOrder = $('#image-order') | |
, $files = $('#files') | |
, $uid = $('#uid') | |
, $uploaded = $('#uploaded') | |
, $addImagesBtn = $('#add-images-btn') | |
, $progressCancelAll = $('.progress-cancel-all') | |
, $hiddenSet = $('.hidden-set'); | |
var $previewImages = $imagePreviews | |
.children('.preview-image'); | |
var uid = $uid.val() | |
, pid = 0; | |
var $progressMap = {} | |
, $previewMap = {}; | |
var previousMessage = {}; | |
var handleFileChange = function(event) { | |
event.preventDefault(); | |
submitForm(event); | |
}; | |
var handleCancelAll = function(event, id) { | |
event.preventDefault(); | |
updateProgress($progressMap[id], id, { | |
status: 'error', completed: 100 | |
}); | |
$progressMap[id].item.fadeOut('slow', function() { | |
$(this).remove; | |
delete $progressMap[id]; | |
}); | |
if ($previewMap[id] !== undefined) { | |
$.each($previewMap[id], function(key, $file) { | |
$file.removeLink.click(); | |
}); | |
} | |
}; | |
// rebind file change event | |
$files.change(handleFileChange); | |
// cancel all | |
$progressCancelAll.click(handleCancelAll); | |
// rebind trigger event | |
$addImagesBtn.click(function(event) { | |
event.preventDefault(); | |
$files.trigger('click'); | |
}); | |
$previewImages.each(function() { | |
$this = $(this); | |
var group = $this.data('group') | |
, index = $this.data('index'); | |
if ($previewMap[group] === undefined) { | |
$previewMap[group] = {}; | |
} | |
$previewMap[group][index] = { | |
item: $this, | |
content: $this.find('.pi-content'), | |
loadingOverlay: $this.find('.loading'), | |
title: $this.find('.pi-header h4'), | |
removeLink: $this.find('.pi-header a') | |
}; | |
}); | |
$imagePreviews.sortable({ | |
placeholder: 'order-placeholder', | |
update: function(event, ui) { | |
var order = $(this).sortable('toArray').join(); | |
$imageOrder.val(order.replace(/preview-/g, '')); | |
}, | |
activate: function() { $(this).addClass('sorting'); }, | |
deactivate: function() { $(this).removeClass('sorting'); } | |
}); | |
$uploader.addClass('active'); | |
$uploadForm.attr('action', $uploadForm.attr('action') + '?async'); | |
var getData = (function() { | |
function fileAPI(id, event, callback) { | |
if (event === undefined && callback === undefined) { | |
return; | |
} | |
var data; | |
if (event.dataTransfer !== undefined) { | |
data = event.dataTransfer.files; | |
} else if (event.target !== undefined) { | |
data = event.target.files; | |
} | |
var totalSize = 0 | |
, files = []; | |
for (var i = 0, f; f = data[i]; i++) { | |
var reader = new FileReader(); | |
reader.onload = (function(file, index) { | |
return function(e) { | |
var $img = $('<img />') | |
.attr('alt', '') | |
.attr('src', e.target.result) | |
.attr('title', file.name); | |
$img.load(function() { | |
files.push($.extend( | |
file, | |
{content: $(this)} | |
)); | |
totalSize += file.size; | |
if (files.length === data.length) { | |
callback(id, null, { | |
totalSize: totalSize, | |
files: files | |
}); | |
} | |
}); | |
} | |
})(f, i); | |
// Read in the image file as a data URL. | |
reader.readAsDataURL(f); | |
} | |
}; | |
function ajax(id, callback) { | |
var callbacks = {}; | |
callbacks.on = function(data) { | |
if (data.error !== null) { | |
return false; | |
} | |
if (data.response !== null) { | |
var loadScript = $imagePreviews.attr('data-image-load-script'); | |
var totalSize = 0; | |
var files = []; | |
for (i in data.response[id]) { | |
var file = data.response[id][i]; | |
var $img = $('<img />') | |
.attr('alt', '') | |
.attr('src', loadScript + '?file=' + file.response.name) | |
.attr('title', file.response.data.name); | |
totalSize += file.response.data.size; | |
$img.load(function() { | |
files.push({ | |
content: $(this), | |
name: file.response.name, | |
size: file.response.data.size, | |
type: file.response.data.type | |
}); | |
if (files.length === data.response[id].length) { | |
callback(id, data, { | |
totalSize: totalSize, | |
files: files | |
}); | |
} | |
}); | |
} | |
return false; | |
} | |
return true; | |
}; | |
poll($uploadForm.attr('data-status-script'), { uid: id }, callbacks); | |
}; | |
return { | |
'fileAPI': fileAPI, | |
'ajax': ajax | |
}; | |
})(); | |
function submitForm(event) { | |
// generate a new id for each request | |
var id = uid + '_' + pid; | |
while ($previewMap[id] !== undefined) { | |
pid++; | |
id = uid + '_' + pid; | |
} | |
// set form value | |
$uid.val(id); | |
// submit to iframe | |
var $iframe = $('<iframe />') | |
.addClass('upload-frame') | |
.attr('name', 'upload-frame' + id); | |
$uploadForm | |
.attr('target', 'upload-frame' + id) | |
.append($iframe); | |
// trigger submit, we can use forms submit | |
$('#upload').trigger('click'); | |
// reset form value | |
$files.remove(); | |
$files = $('<input />') | |
.attr('type', 'file') | |
.attr('name', 'files[]') | |
.attr('id', 'files') | |
.attr('multiple', 'multiple') | |
.change(handleFileChange); | |
$hiddenSet.append($files); | |
// define handler for data | |
var dataHandler = function(id, data, fileinfo) { | |
// create new progress element | |
$progress = DOM.init('progress', {key: id}); | |
$progress.elements.title.html('Update Progress'); | |
$progress.elements.cancel.click(function(event) { | |
handleCancelAll(event, id) | |
}); | |
// append it to feedback | |
$feedback.append($progress.elements.item); | |
// pass new job to pollProgress | |
var callbacks = {} | |
, dataIsSet = false; | |
callbacks.on = function(data) { | |
if (data.error !== null) { | |
$progress.update({ | |
status: 'error', message: data.error.message, completed: 100 | |
}); | |
} else if (data.response !== null) { | |
if (dataIsSet === false) { | |
// generate previews | |
$.each(fileinfo.files, function(index, file) { | |
var $preview = DOM.init('preview', {key: id, index: index}); | |
var removeProgress = function(event) { | |
event.preventDefault(); | |
$preview.remove({ | |
deleteScript: $imagePreviews.attr('data-delete-script') | |
}); | |
}; | |
$preview.elements.item | |
.addClass('success') | |
.attr('id', 'preview-' + file.name); | |
$preview.elements.title.html(file.name); | |
$preview.elements.content.html(file.content); | |
$preview.elements.removeLink.click(removeProgress).data('file-name', file.name); | |
$preview.update({loaded: true}); | |
$imagePreviews.append($preview.elements.item); | |
}); | |
dataIsSet = true; | |
} | |
if (data.response < 100) { | |
$progress.update({ | |
status: 'uploading', completed: data.response | |
}); | |
} else { | |
$progress.update({ | |
status: 'success', completed: 100 | |
}); | |
$progress.remove(); | |
return false; | |
} | |
} | |
return true; | |
}; | |
if (data === null) { | |
callbacks.end = function(data) { | |
$.get($uploadForm.attr('data-status-script'), {uid: id}, function(data) { | |
setStatus(data); | |
}); | |
}; | |
} else { | |
setStatus(data); | |
} | |
poll($uploadForm.attr('data-progress-script'), { | |
uid: id, | |
post_size: fileinfo.totalSize | |
}, callbacks); | |
} | |
if ( | |
window.File !== undefined && | |
window.FileReader !== undefined && | |
window.FileList !== undefined && | |
window.Blob !== undefined | |
) { | |
getData.fileAPI(id, event, dataHandler); | |
} else { | |
getData.ajax(id, dataHandler); | |
} | |
} | |
function poll(script, data, callbacks, callbackData) { | |
if ( | |
script === undefined || | |
data === undefined || | |
callbacks === undefined | |
) { | |
return false; | |
} | |
if (callbacks.start !== undefined) { | |
callbacks.start(callbackData); | |
delete callbacks.start; | |
} | |
$.get(script, data, function(result) { | |
var repost; | |
if (result === null) { | |
repost = callbacks.on(null, callbackData); | |
} else { | |
repost = callbacks.on(result, callbackData); | |
} | |
if (repost === true) { | |
setTimeout(function() { | |
poll(script, data, callbacks); | |
}, 1000); | |
} else { | |
if (callbacks.end !== undefined) { | |
callbacks.end(result, callbackData); | |
} | |
} | |
}); | |
} | |
function setStatus(data) { | |
if (data.response !== null) { | |
var response = data.response; | |
$.each(response, function(key, files) { | |
if ($previewMap[key] === undefined) { | |
return; | |
} | |
if (files !== null) { | |
$.each(files, function(index, file) { | |
if ($previewMap[key][index] === undefined) { | |
return; | |
} | |
var $preview = $previewMap[key][index]; | |
if (file.response !== null || file.error !== null) { | |
$preview.update({loaded: true}); | |
} | |
if (file.error !== null) { | |
$preview.update({error: file.error.message}); | |
$preview.elements.item.appendTo($imageErrors); | |
delete $previewMap[key][index]; | |
} | |
if (file.response !== null) { | |
var current = $uploaded.val(); | |
var id = $preview.elements.item.attr('id'); | |
if (id.indexOf(file.response.name) < 0) { | |
$preview.elements.item.attr('id', 'preview-' + file.response.name); | |
current = current.replace(id.replace('preview-', ''), file.response.name); | |
$uploaded.val(current); | |
} | |
if (current.indexOf(file.response.name) < 0) { | |
if (current.length > 0) { | |
value = current + ',' + file.response.name; | |
} | |
$uploaded.val(value); | |
} | |
} | |
}); | |
} | |
}); | |
} | |
} | |
var DOM = (function() { | |
function updateProgress(options) { | |
if (typeof options !== 'object') { | |
return; | |
} | |
$this = this.elements; | |
if (typeof options.completed === 'number') { | |
$this.bar.width(options.completed + '%'); | |
} | |
if (typeof options.status === 'string') { | |
$this.item | |
.removeClass() | |
.addClass('progress-bar ' + options.status); | |
} | |
if (typeof options.message === 'string' && options.message !== previousMessage[this.options.key]) { | |
previousMessage[this.options.key] = options.message; | |
$listItem = $('<li />') | |
.addClass('message'); | |
if (typeof options.status === 'string') { | |
$listItem.addClass(options.status); | |
} | |
$this.messages | |
.append( | |
$listItem.html(options.message) | |
); | |
} | |
} | |
function removeProgress() { | |
var key = this.options.key; | |
var $this = this.elements; | |
// remove progress bar | |
setTimeout(function() { | |
$this.item.fadeOut('slow', function() { | |
$this.item.remove; | |
delete $progressMap[key]; | |
}); | |
}, 5000); | |
} | |
function updatePreview(options) { | |
if (typeof options !== 'object') { | |
return; | |
} | |
$this = this.elements; | |
if (typeof options.error === 'string') { | |
$this.content.html(''); | |
var $error = DOM.init('error'); | |
$error.elements.content.html(options.error); | |
$this.removeLink.remove(); | |
$this.item | |
.removeClass('success') | |
.addClass('error'); | |
$this.content | |
.append( | |
$error.elements.image, | |
$error.elements.content | |
); | |
$error.elements.image.load(function() { | |
$this.loadingOverlay.hide(); | |
}); | |
} | |
if (typeof options.loaded === 'boolean') { | |
if (options.loaded === true) { | |
$this.loadingOverlay.fadeOut('slow'); | |
} else { | |
$this.loadingOverlay.fadeIn('slow'); | |
} | |
} | |
} | |
function removeImage(options) { | |
$this = this.elements; | |
var group = $this.item.data('group') | |
, index = $this.item.data('index'); | |
if ($previewMap[group] === undefined) { | |
return; | |
} | |
$.get( | |
options.deleteScript, | |
{key: group, index: index}, | |
function() { | |
if ($previewMap[group][index] !== undefined) { | |
delete $previewMap[group][index]; | |
} | |
$this.item.fadeOut('slow', function() { | |
$this.item.remove(); | |
}); | |
} | |
); | |
} | |
var init = function(name, options) { | |
var elems = { | |
$progress: function(options) { | |
var key = options.key; | |
var $cancel = $('<a />') | |
.addClass('progress-cancel-all') | |
.attr('href', '#') | |
.text('Cancel All ') | |
.append($('<i />').addClass('icon-remove')); | |
var $messages = $('<ul />').addClass('feedback-messages'); | |
var $title = $('<h3 />'); | |
var $bar = $('<div />').addClass('progress-inner'); | |
var $item = $('<div />').addClass('progress-bar') | |
.append( | |
$title, | |
$cancel, | |
$('<div />') | |
.addClass('progress-outer') | |
.html($bar), | |
$messages | |
); | |
var e = function() { | |
this.options = options; | |
this.elements = { | |
item: $item, | |
cancel: $cancel, | |
title: $title, | |
bar: $bar, | |
messages: $messages | |
}; | |
}; | |
e.prototype.update = updateProgress; | |
e.prototype.remove = removeProgress; | |
$progressMap[key] = new e(); | |
return $progressMap[key]; | |
}, | |
$preview: function(options) { | |
var key = options.key; | |
var index = options.index; | |
$title = $('<h4 />'); | |
$content = $('<div />') | |
.addClass('pi-content'); | |
$loadingOverlay = $('<div />') | |
.addClass('loading') | |
.html('<img src="/unew/images/loader.gif" alt="loader" />'); | |
$removeLink = $('<a />') | |
.attr('href', '#') | |
.addClass('icon-remove') | |
.html(' '); | |
$item = $('<li />') | |
.addClass('preview-image') | |
.append( | |
$('<div />').addClass('pi-header').append($title, $removeLink), | |
$('<div />').addClass('pi-content-wrapper').append($loadingOverlay, $content) | |
); | |
$item.data('group', key).data('index', index); | |
var e = function() { | |
this.options = options; | |
this.elements = { | |
item: $item, | |
content: $content, | |
loadingOverlay: $loadingOverlay, | |
title: $title, | |
removeLink: $removeLink | |
}; | |
}; | |
e.prototype.update = updatePreview; | |
e.prototype.remove = removeImage; | |
if ($previewMap[key] === undefined) { | |
$previewMap[key] = {}; | |
} | |
$previewMap[key][index] = new e(); | |
return $previewMap[key][index]; | |
}, | |
$error: function() { | |
$image = $('<img />') | |
.attr('src', '/unew/images/error.png') | |
.attr('alt', 'error'); | |
$content = $('<div />'); | |
var e = function() { | |
this.elements = { | |
image: $image, | |
content: $content | |
}; | |
}; | |
return new e(); | |
} | |
}; | |
if (typeof elems['$' + name] === 'function') { | |
return elems['$' + name](options); | |
} | |
}; | |
return { | |
init: init | |
} | |
})(); | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment