To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / public / javascripts / attachments.js @ 1586:d0d59d12db94
History | View | Annotate | Download (5.72 KB)
| 1 |
/* Redmine - project management software
|
|---|---|
| 2 |
Copyright (C) 2006-2014 Jean-Philippe Lang */
|
| 3 |
|
| 4 |
function addFile(inputEl, file, eagerUpload) { |
| 5 |
|
| 6 |
if ($('#attachments_fields').children().length < 10) { |
| 7 |
|
| 8 |
var attachmentId = addFile.nextAttachmentId++;
|
| 9 |
|
| 10 |
var fileSpan = $('<span>', { id: 'attachments_' + attachmentId }); |
| 11 |
|
| 12 |
fileSpan.append( |
| 13 |
$('<input>', { type: 'text', 'class': 'filename readonly', name: 'attachments[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name), |
| 14 |
$('<input>', { type: 'text', 'class': 'description', name: 'attachments[' + attachmentId + '][description]', maxlength: 255, placeholder: $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload), |
| 15 |
$('<a> </a>').attr({ href: "#", 'class': 'remove-upload' }).click(removeFile).toggle(!eagerUpload) |
| 16 |
).appendTo('#attachments_fields');
|
| 17 |
|
| 18 |
if(eagerUpload) {
|
| 19 |
ajaxUpload(file, attachmentId, fileSpan, inputEl); |
| 20 |
} |
| 21 |
|
| 22 |
return attachmentId;
|
| 23 |
} |
| 24 |
return null; |
| 25 |
} |
| 26 |
|
| 27 |
addFile.nextAttachmentId = 1;
|
| 28 |
|
| 29 |
function ajaxUpload(file, attachmentId, fileSpan, inputEl) { |
| 30 |
|
| 31 |
function onLoadstart(e) { |
| 32 |
fileSpan.removeClass('ajax-waiting');
|
| 33 |
fileSpan.addClass('ajax-loading');
|
| 34 |
$('input:submit', $(this).parents('form')).attr('disabled', 'disabled'); |
| 35 |
} |
| 36 |
|
| 37 |
function onProgress(e) { |
| 38 |
if(e.lengthComputable) {
|
| 39 |
this.progressbar( 'value', e.loaded * 100 / e.total ); |
| 40 |
} |
| 41 |
} |
| 42 |
|
| 43 |
function actualUpload(file, attachmentId, fileSpan, inputEl) { |
| 44 |
|
| 45 |
ajaxUpload.uploading++; |
| 46 |
|
| 47 |
uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, { |
| 48 |
loadstartEventHandler: onLoadstart.bind(progressSpan),
|
| 49 |
progressEventHandler: onProgress.bind(progressSpan)
|
| 50 |
}) |
| 51 |
.done(function(result) {
|
| 52 |
progressSpan.progressbar( 'value', 100 ).remove(); |
| 53 |
fileSpan.find('input.description, a').css('display', 'inline-block'); |
| 54 |
}) |
| 55 |
.fail(function(result) {
|
| 56 |
progressSpan.text(result.statusText); |
| 57 |
}).always(function() {
|
| 58 |
ajaxUpload.uploading--; |
| 59 |
fileSpan.removeClass('ajax-loading');
|
| 60 |
var form = fileSpan.parents('form'); |
| 61 |
if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) { |
| 62 |
$('input:submit', form).removeAttr('disabled'); |
| 63 |
} |
| 64 |
form.dequeue('upload');
|
| 65 |
}); |
| 66 |
} |
| 67 |
|
| 68 |
var progressSpan = $('<div>').insertAfter(fileSpan.find('input.filename')); |
| 69 |
progressSpan.progressbar(); |
| 70 |
fileSpan.addClass('ajax-waiting');
|
| 71 |
|
| 72 |
var maxSyncUpload = $(inputEl).data('max-concurrent-uploads'); |
| 73 |
|
| 74 |
if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload) |
| 75 |
actualUpload(file, attachmentId, fileSpan, inputEl); |
| 76 |
else
|
| 77 |
$(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl)); |
| 78 |
} |
| 79 |
|
| 80 |
ajaxUpload.uploading = 0;
|
| 81 |
|
| 82 |
function removeFile() { |
| 83 |
$(this).parent('span').remove(); |
| 84 |
return false; |
| 85 |
} |
| 86 |
|
| 87 |
function uploadBlob(blob, uploadUrl, attachmentId, options) { |
| 88 |
|
| 89 |
var actualOptions = $.extend({ |
| 90 |
loadstartEventHandler: $.noop, |
| 91 |
progressEventHandler: $.noop |
| 92 |
}, options); |
| 93 |
|
| 94 |
uploadUrl = uploadUrl + '?attachment_id=' + attachmentId;
|
| 95 |
if (blob instanceof window.File) { |
| 96 |
uploadUrl += '&filename=' + encodeURIComponent(blob.name);
|
| 97 |
} |
| 98 |
|
| 99 |
return $.ajax(uploadUrl, { |
| 100 |
type: 'POST', |
| 101 |
contentType: 'application/octet-stream', |
| 102 |
beforeSend: function(jqXhr, settings) { |
| 103 |
jqXhr.setRequestHeader('Accept', 'application/js'); |
| 104 |
// attach proper File object
|
| 105 |
settings.data = blob; |
| 106 |
}, |
| 107 |
xhr: function() { |
| 108 |
var xhr = $.ajaxSettings.xhr(); |
| 109 |
xhr.upload.onloadstart = actualOptions.loadstartEventHandler; |
| 110 |
xhr.upload.onprogress = actualOptions.progressEventHandler; |
| 111 |
return xhr;
|
| 112 |
}, |
| 113 |
data: blob,
|
| 114 |
cache: false, |
| 115 |
processData: false |
| 116 |
}); |
| 117 |
} |
| 118 |
|
| 119 |
function addInputFiles(inputEl) { |
| 120 |
var clearedFileInput = $(inputEl).clone().val(''); |
| 121 |
|
| 122 |
if (inputEl.files) {
|
| 123 |
// upload files using ajax
|
| 124 |
uploadAndAttachFiles(inputEl.files, inputEl); |
| 125 |
$(inputEl).remove();
|
| 126 |
} else {
|
| 127 |
// browser not supporting the file API, upload on form submission
|
| 128 |
var attachmentId;
|
| 129 |
var aFilename = inputEl.value.split(/\/|\\/); |
| 130 |
attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false);
|
| 131 |
if (attachmentId) {
|
| 132 |
$(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId); |
| 133 |
} |
| 134 |
} |
| 135 |
|
| 136 |
clearedFileInput.insertAfter('#attachments_fields').on('change', function(){addInputFiles(this);}); |
| 137 |
} |
| 138 |
|
| 139 |
function uploadAndAttachFiles(files, inputEl) { |
| 140 |
|
| 141 |
var maxFileSize = $(inputEl).data('max-file-size'); |
| 142 |
var maxFileSizeExceeded = $(inputEl).data('max-file-size-message'); |
| 143 |
|
| 144 |
var sizeExceeded = false; |
| 145 |
$.each(files, function() { |
| 146 |
if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;} |
| 147 |
}); |
| 148 |
if (sizeExceeded) {
|
| 149 |
window.alert(maxFileSizeExceeded); |
| 150 |
} else {
|
| 151 |
$.each(files, function() {addFile(inputEl, this, true);}); |
| 152 |
} |
| 153 |
} |
| 154 |
|
| 155 |
function handleFileDropEvent(e) { |
| 156 |
|
| 157 |
$(this).removeClass('fileover'); |
| 158 |
blockEventPropagation(e); |
| 159 |
|
| 160 |
if ($.inArray('Files', e.dataTransfer.types) > -1) { |
| 161 |
uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector')); |
| 162 |
} |
| 163 |
} |
| 164 |
|
| 165 |
function dragOverHandler(e) { |
| 166 |
$(this).addClass('fileover'); |
| 167 |
blockEventPropagation(e); |
| 168 |
} |
| 169 |
|
| 170 |
function dragOutHandler(e) { |
| 171 |
$(this).removeClass('fileover'); |
| 172 |
blockEventPropagation(e); |
| 173 |
} |
| 174 |
|
| 175 |
function setupFileDrop() { |
| 176 |
if (window.File && window.FileList && window.ProgressEvent && window.FormData) {
|
| 177 |
|
| 178 |
$.event.fixHooks.drop = { props: [ 'dataTransfer' ] }; |
| 179 |
|
| 180 |
$('form div.box').has('input:file').each(function() { |
| 181 |
$(this).on({ |
| 182 |
dragover: dragOverHandler,
|
| 183 |
dragleave: dragOutHandler,
|
| 184 |
drop: handleFileDropEvent
|
| 185 |
}); |
| 186 |
}); |
| 187 |
} |
| 188 |
} |
| 189 |
|
| 190 |
$(document).ready(setupFileDrop);
|