694 |
steven |
1 |
/**
|
|
|
2 |
* jquery.plupload.queue.js
|
|
|
3 |
*
|
|
|
4 |
* Copyright 2009, Moxiecode Systems AB
|
|
|
5 |
* Released under GPL License.
|
|
|
6 |
*
|
|
|
7 |
* License: http://www.plupload.com/license
|
|
|
8 |
* Contributing: http://www.plupload.com/contributing
|
|
|
9 |
*/
|
|
|
10 |
|
|
|
11 |
/* global jQuery:true, alert:true */
|
|
|
12 |
|
|
|
13 |
/**
|
|
|
14 |
jQuery based implementation of the Plupload API - multi-runtime file uploading API.
|
|
|
15 |
|
|
|
16 |
To use the widget you must include _jQuery_. It is not meant to be extended in any way and is provided to be
|
|
|
17 |
used as it is.
|
|
|
18 |
|
|
|
19 |
@example
|
|
|
20 |
<!-- Instantiating: -->
|
|
|
21 |
<div id="uploader">
|
|
|
22 |
<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
|
|
|
23 |
</div>
|
|
|
24 |
|
|
|
25 |
<script>
|
|
|
26 |
$('#uploader').pluploadQueue({
|
|
|
27 |
url : '../upload.php',
|
|
|
28 |
filters : [
|
|
|
29 |
{title : "Image files", extensions : "jpg,gif,png"}
|
|
|
30 |
],
|
|
|
31 |
rename: true,
|
|
|
32 |
flash_swf_url : '../../js/Moxie.swf',
|
|
|
33 |
silverlight_xap_url : '../../js/Moxie.xap',
|
|
|
34 |
});
|
|
|
35 |
</script>
|
|
|
36 |
|
|
|
37 |
@example
|
|
|
38 |
// Retrieving a reference to plupload.Uploader object
|
|
|
39 |
var uploader = $('#uploader').pluploadQueue();
|
|
|
40 |
|
|
|
41 |
uploader.bind('FilesAdded', function() {
|
|
|
42 |
|
|
|
43 |
// Autostart
|
|
|
44 |
setTimeout(uploader.start, 1); // "detach" from the main thread
|
|
|
45 |
});
|
|
|
46 |
|
|
|
47 |
@class pluploadQueue
|
|
|
48 |
@constructor
|
|
|
49 |
@param {Object} settings For detailed information about each option check documentation.
|
|
|
50 |
@param {String} settings.url URL of the server-side upload handler.
|
|
|
51 |
@param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
|
|
|
52 |
@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
|
|
|
53 |
@param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
|
|
|
54 |
@param {String} [settings.flash_swf_url] URL of the Flash swf.
|
|
|
55 |
@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
|
|
|
56 |
@param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
|
|
|
57 |
@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
|
|
|
58 |
@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
|
|
|
59 |
@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
|
|
|
60 |
@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
|
|
|
61 |
@param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
|
|
|
62 |
@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
|
|
|
63 |
@param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
|
|
|
64 |
@param {Number} [settings.resize.width] If image is bigger, it will be resized.
|
|
|
65 |
@param {Number} [settings.resize.height] If image is bigger, it will be resized.
|
|
|
66 |
@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
|
|
|
67 |
@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
|
|
|
68 |
@param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
|
|
|
69 |
@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
|
|
|
70 |
@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
|
|
|
71 |
|
|
|
72 |
@param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
|
|
|
73 |
@param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
|
|
|
74 |
@param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
|
|
|
75 |
*/
|
|
|
76 |
;(function($, plupload) {
|
|
|
77 |
var uploaders = {};
|
|
|
78 |
|
|
|
79 |
function _(str) {
|
|
|
80 |
return plupload.translate(str) || str;
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
function renderUI(id, target) {
|
|
|
84 |
// Remove all existing non plupload items
|
|
|
85 |
target.contents().each(function(i, node) {
|
|
|
86 |
node = $(node);
|
|
|
87 |
|
|
|
88 |
if (!node.is('.plupload')) {
|
|
|
89 |
node.remove();
|
|
|
90 |
}
|
|
|
91 |
});
|
|
|
92 |
|
|
|
93 |
target.prepend(
|
|
|
94 |
'<div class="plupload_wrapper plupload_scroll">' +
|
|
|
95 |
'<div id="' + id + '_container" class="plupload_container">' +
|
|
|
96 |
'<div class="plupload">' +
|
|
|
97 |
'<div class="plupload_header">' +
|
|
|
98 |
'<div class="plupload_header_content">' +
|
|
|
99 |
'<div class="plupload_header_title">' + _('Select files') + '</div>' +
|
|
|
100 |
'<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +
|
|
|
101 |
'</div>' +
|
|
|
102 |
'</div>' +
|
|
|
103 |
|
|
|
104 |
'<div class="plupload_content">' +
|
|
|
105 |
'<div class="plupload_filelist_header">' +
|
|
|
106 |
'<div class="plupload_file_name">' + _('Filename') + '</div>' +
|
|
|
107 |
'<div class="plupload_file_action"> </div>' +
|
|
|
108 |
'<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' +
|
|
|
109 |
'<div class="plupload_file_size">' + _('Size') + '</div>' +
|
|
|
110 |
'<div class="plupload_clearer"> </div>' +
|
|
|
111 |
'</div>' +
|
|
|
112 |
|
|
|
113 |
'<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' +
|
|
|
114 |
|
|
|
115 |
'<div class="plupload_filelist_footer">' +
|
|
|
116 |
'<div class="plupload_file_name">' +
|
|
|
117 |
'<div class="plupload_buttons">' +
|
|
|
118 |
'<a href="#" class="plupload_button plupload_add" id="' + id + '_browse">' + _('Add Files') + '</a>' +
|
|
|
119 |
'<a href="#" class="plupload_button plupload_start">' + _('Start Upload') + '</a>' +
|
|
|
120 |
'</div>' +
|
|
|
121 |
'<span class="plupload_upload_status"></span>' +
|
|
|
122 |
'</div>' +
|
|
|
123 |
'<div class="plupload_file_action"></div>' +
|
|
|
124 |
'<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' +
|
|
|
125 |
'<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' +
|
|
|
126 |
'<div class="plupload_progress">' +
|
|
|
127 |
'<div class="plupload_progress_container">' +
|
|
|
128 |
'<div class="plupload_progress_bar"></div>' +
|
|
|
129 |
'</div>' +
|
|
|
130 |
'</div>' +
|
|
|
131 |
'<div class="plupload_clearer"> </div>' +
|
|
|
132 |
'</div>' +
|
|
|
133 |
'</div>' +
|
|
|
134 |
'</div>' +
|
|
|
135 |
'</div>' +
|
|
|
136 |
'<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="0" />' +
|
|
|
137 |
'</div>'
|
|
|
138 |
);
|
|
|
139 |
}
|
|
|
140 |
|
|
|
141 |
$.fn.pluploadQueue = function(settings) {
|
|
|
142 |
if (settings) {
|
|
|
143 |
this.each(function() {
|
|
|
144 |
var uploader, target, id, contents_bak;
|
|
|
145 |
|
|
|
146 |
target = $(this);
|
|
|
147 |
id = target.attr('id');
|
|
|
148 |
|
|
|
149 |
if (!id) {
|
|
|
150 |
id = plupload.guid();
|
|
|
151 |
target.attr('id', id);
|
|
|
152 |
}
|
|
|
153 |
|
|
|
154 |
contents_bak = target.html();
|
|
|
155 |
renderUI(id, target);
|
|
|
156 |
|
|
|
157 |
settings = $.extend({
|
|
|
158 |
dragdrop : true,
|
|
|
159 |
browse_button : id + '_browse',
|
|
|
160 |
container : id
|
|
|
161 |
}, settings);
|
|
|
162 |
|
|
|
163 |
// Enable drag/drop (see PostInit handler as well)
|
|
|
164 |
if (settings.dragdrop) {
|
|
|
165 |
settings.drop_element = id + '_filelist';
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
uploader = new plupload.Uploader(settings);
|
|
|
169 |
|
|
|
170 |
uploaders[id] = uploader;
|
|
|
171 |
|
|
|
172 |
function handleStatus(file) {
|
|
|
173 |
var actionClass;
|
|
|
174 |
|
|
|
175 |
if (file.status == plupload.DONE) {
|
|
|
176 |
actionClass = 'plupload_done';
|
|
|
177 |
}
|
|
|
178 |
|
|
|
179 |
if (file.status == plupload.FAILED) {
|
|
|
180 |
actionClass = 'plupload_failed';
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
if (file.status == plupload.QUEUED) {
|
|
|
184 |
actionClass = 'plupload_delete';
|
|
|
185 |
}
|
|
|
186 |
|
|
|
187 |
if (file.status == plupload.UPLOADING) {
|
|
|
188 |
actionClass = 'plupload_uploading';
|
|
|
189 |
}
|
|
|
190 |
|
|
|
191 |
var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block');
|
|
|
192 |
if (file.hint) {
|
|
|
193 |
icon.attr('title', file.hint);
|
|
|
194 |
}
|
|
|
195 |
}
|
|
|
196 |
|
|
|
197 |
function updateTotalProgress() {
|
|
|
198 |
$('span.plupload_total_status', target).html(uploader.total.percent + '%');
|
|
|
199 |
$('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%');
|
|
|
200 |
$('span.plupload_upload_status', target).html(
|
|
|
201 |
plupload.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length)
|
|
|
202 |
);
|
|
|
203 |
}
|
|
|
204 |
|
|
|
205 |
function updateList() {
|
|
|
206 |
var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML;
|
|
|
207 |
|
|
|
208 |
$.each(uploader.files, function(i, file) {
|
|
|
209 |
inputHTML = '';
|
|
|
210 |
|
|
|
211 |
if (file.status == plupload.DONE) {
|
|
|
212 |
if (file.target_name) {
|
|
|
213 |
inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />';
|
|
|
214 |
}
|
|
|
215 |
|
|
|
216 |
inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />';
|
|
|
217 |
inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />';
|
|
|
218 |
|
|
|
219 |
inputCount++;
|
|
|
220 |
|
|
|
221 |
$('#' + id + '_count').val(inputCount);
|
|
|
222 |
}
|
|
|
223 |
|
|
|
224 |
fileList.append(
|
|
|
225 |
'<li id="' + file.id + '">' +
|
|
|
226 |
'<div class="plupload_file_name"><span>' + file.name + '</span></div>' +
|
|
|
227 |
'<div class="plupload_file_action"><a href="#"></a></div>' +
|
|
|
228 |
'<div class="plupload_file_status">' + file.percent + '%</div>' +
|
|
|
229 |
'<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' +
|
|
|
230 |
'<div class="plupload_clearer"> </div>' +
|
|
|
231 |
inputHTML +
|
|
|
232 |
'</li>'
|
|
|
233 |
);
|
|
|
234 |
|
|
|
235 |
handleStatus(file);
|
|
|
236 |
|
|
|
237 |
$('#' + file.id + '.plupload_delete a').click(function(e) {
|
|
|
238 |
$('#' + file.id).remove();
|
|
|
239 |
uploader.removeFile(file);
|
|
|
240 |
|
|
|
241 |
e.preventDefault();
|
|
|
242 |
});
|
|
|
243 |
});
|
|
|
244 |
|
|
|
245 |
$('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size));
|
|
|
246 |
|
|
|
247 |
if (uploader.total.queued === 0) {
|
|
|
248 |
$('span.plupload_add_text', target).html(_('Add Files'));
|
|
|
249 |
} else {
|
|
|
250 |
$('span.plupload_add_text', target).html(plupload.sprintf(_('%d files queued'), uploader.total.queued));
|
|
|
251 |
}
|
|
|
252 |
|
|
|
253 |
$('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed));
|
|
|
254 |
|
|
|
255 |
// Scroll to end of file list
|
|
|
256 |
fileList[0].scrollTop = fileList[0].scrollHeight;
|
|
|
257 |
|
|
|
258 |
updateTotalProgress();
|
|
|
259 |
|
|
|
260 |
// Re-add drag message if there is no files
|
|
|
261 |
if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) {
|
|
|
262 |
$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
|
|
|
263 |
}
|
|
|
264 |
}
|
|
|
265 |
|
|
|
266 |
function destroy() {
|
|
|
267 |
delete uploaders[id];
|
|
|
268 |
uploader.destroy();
|
|
|
269 |
target.html(contents_bak);
|
|
|
270 |
uploader = target = contents_bak = null;
|
|
|
271 |
}
|
|
|
272 |
|
|
|
273 |
uploader.bind("UploadFile", function(up, file) {
|
|
|
274 |
$('#' + file.id).addClass('plupload_current_file');
|
|
|
275 |
});
|
|
|
276 |
|
|
|
277 |
uploader.bind('Init', function(up, res) {
|
|
|
278 |
// Enable rename support
|
|
|
279 |
if (!settings.unique_names && settings.rename) {
|
|
|
280 |
target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) {
|
|
|
281 |
var targetSpan = $(e.target), file, parts, name, ext = "";
|
|
|
282 |
|
|
|
283 |
// Get file name and split out name and extension
|
|
|
284 |
file = up.getFile(targetSpan.parents('li')[0].id);
|
|
|
285 |
name = file.name;
|
|
|
286 |
parts = /^(.+)(\.[^.]+)$/.exec(name);
|
|
|
287 |
if (parts) {
|
|
|
288 |
name = parts[1];
|
|
|
289 |
ext = parts[2];
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
// Display input element
|
|
|
293 |
targetSpan.hide().after('<input type="text" />');
|
|
|
294 |
targetSpan.next().val(name).focus().blur(function() {
|
|
|
295 |
targetSpan.show().next().remove();
|
|
|
296 |
}).keydown(function(e) {
|
|
|
297 |
var targetInput = $(this);
|
|
|
298 |
|
|
|
299 |
if (e.keyCode == 13) {
|
|
|
300 |
e.preventDefault();
|
|
|
301 |
|
|
|
302 |
// Rename file and glue extension back on
|
|
|
303 |
file.name = targetInput.val() + ext;
|
|
|
304 |
targetSpan.html(file.name);
|
|
|
305 |
targetInput.blur();
|
|
|
306 |
}
|
|
|
307 |
});
|
|
|
308 |
});
|
|
|
309 |
}
|
|
|
310 |
|
|
|
311 |
$('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime);
|
|
|
312 |
|
|
|
313 |
$('a.plupload_start', target).click(function(e) {
|
|
|
314 |
if (!$(this).hasClass('plupload_disabled')) {
|
|
|
315 |
uploader.start();
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
e.preventDefault();
|
|
|
319 |
});
|
|
|
320 |
|
|
|
321 |
$('a.plupload_stop', target).click(function(e) {
|
|
|
322 |
e.preventDefault();
|
|
|
323 |
uploader.stop();
|
|
|
324 |
});
|
|
|
325 |
|
|
|
326 |
$('a.plupload_start', target).addClass('plupload_disabled');
|
|
|
327 |
});
|
|
|
328 |
|
|
|
329 |
uploader.bind("Error", function(up, err) {
|
|
|
330 |
var file = err.file, message;
|
|
|
331 |
|
|
|
332 |
if (file) {
|
|
|
333 |
message = err.message;
|
|
|
334 |
|
|
|
335 |
if (err.details) {
|
|
|
336 |
message += " (" + err.details + ")";
|
|
|
337 |
}
|
|
|
338 |
|
|
|
339 |
if (err.code == plupload.FILE_SIZE_ERROR) {
|
|
|
340 |
alert(_("Error: File too large:") + " " + file.name);
|
|
|
341 |
}
|
|
|
342 |
|
|
|
343 |
if (err.code == plupload.FILE_EXTENSION_ERROR) {
|
|
|
344 |
alert(_("Error: Invalid file extension:") + " " + file.name);
|
|
|
345 |
}
|
|
|
346 |
|
|
|
347 |
file.hint = message;
|
|
|
348 |
$('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message);
|
|
|
349 |
}
|
|
|
350 |
|
|
|
351 |
if (err.code === plupload.INIT_ERROR) {
|
|
|
352 |
setTimeout(function() {
|
|
|
353 |
destroy();
|
|
|
354 |
}, 1);
|
|
|
355 |
}
|
|
|
356 |
});
|
|
|
357 |
|
|
|
358 |
uploader.bind("PostInit", function(up) {
|
|
|
359 |
// features are populated only after input components are fully instantiated
|
|
|
360 |
if (up.settings.dragdrop && up.features.dragdrop) {
|
|
|
361 |
$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
|
|
|
362 |
}
|
|
|
363 |
});
|
|
|
364 |
|
|
|
365 |
uploader.init();
|
|
|
366 |
|
|
|
367 |
uploader.bind('StateChanged', function() {
|
|
|
368 |
if (uploader.state === plupload.STARTED) {
|
|
|
369 |
$('li.plupload_delete a,div.plupload_buttons', target).hide();
|
|
|
370 |
uploader.disableBrowse(true);
|
|
|
371 |
|
|
|
372 |
$('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block');
|
|
|
373 |
$('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files');
|
|
|
374 |
|
|
|
375 |
if (settings.multiple_queues) {
|
|
|
376 |
$('span.plupload_total_status,span.plupload_total_file_size', target).show();
|
|
|
377 |
}
|
|
|
378 |
} else {
|
|
|
379 |
updateList();
|
|
|
380 |
$('a.plupload_stop,div.plupload_progress', target).hide();
|
|
|
381 |
$('a.plupload_delete', target).css('display', 'block');
|
|
|
382 |
|
|
|
383 |
if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) {
|
|
|
384 |
$(".plupload_buttons,.plupload_upload_status", target).css("display", "inline");
|
|
|
385 |
uploader.disableBrowse(false);
|
|
|
386 |
|
|
|
387 |
$(".plupload_start", target).addClass("plupload_disabled");
|
|
|
388 |
$('span.plupload_total_status,span.plupload_total_file_size', target).hide();
|
|
|
389 |
}
|
|
|
390 |
}
|
|
|
391 |
});
|
|
|
392 |
|
|
|
393 |
uploader.bind('FilesAdded', updateList);
|
|
|
394 |
|
|
|
395 |
uploader.bind('FilesRemoved', function() {
|
|
|
396 |
// since the whole file list is redrawn for every change in the queue
|
|
|
397 |
// we need to scroll back to the file removal point to avoid annoying
|
|
|
398 |
// scrolling to the bottom bug (see #926)
|
|
|
399 |
var scrollTop = $('#' + id + '_filelist').scrollTop();
|
|
|
400 |
updateList();
|
|
|
401 |
$('#' + id + '_filelist').scrollTop(scrollTop);
|
|
|
402 |
});
|
|
|
403 |
|
|
|
404 |
uploader.bind('FileUploaded', function(up, file) {
|
|
|
405 |
handleStatus(file);
|
|
|
406 |
});
|
|
|
407 |
|
|
|
408 |
uploader.bind("UploadProgress", function(up, file) {
|
|
|
409 |
// Set file specific progress
|
|
|
410 |
$('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%');
|
|
|
411 |
|
|
|
412 |
handleStatus(file);
|
|
|
413 |
updateTotalProgress();
|
|
|
414 |
});
|
|
|
415 |
|
|
|
416 |
// Call setup function
|
|
|
417 |
if (settings.setup) {
|
|
|
418 |
settings.setup(uploader);
|
|
|
419 |
}
|
|
|
420 |
});
|
|
|
421 |
|
|
|
422 |
return this;
|
|
|
423 |
} else {
|
|
|
424 |
// Get uploader instance for specified element
|
|
|
425 |
return uploaders[$(this[0]).attr('id')];
|
|
|
426 |
}
|
|
|
427 |
};
|
|
|
428 |
})(jQuery, plupload);
|