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