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