comparison .svn/pristine/c9/c9a4606fd56695d0574a554ddcfcebb976dd9120.svn-base @ 1516:b450a9d58aed redmine-2.4

Update to Redmine SVN revision 13356 on 2.4-stable branch
author Chris Cannam
date Tue, 09 Sep 2014 09:28:31 +0100
parents
children
comparison
equal deleted inserted replaced
1494:e248c7af89ec 1516:b450a9d58aed
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>&nbsp</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);