Diff: STRATO-apps/wordpress_03/app/wp-includes/js/plupload/plupload.js
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
/**
2
+
* Plupload - multi-runtime File Uploader
3
+
* v2.1.9
4
+
*
5
+
* Copyright 2013, Moxiecode Systems AB
6
+
* Released under GPL License.
7
+
*
8
+
* License: http://www.plupload.com/license
9
+
* Contributing: http://www.plupload.com/contributing
10
+
*
11
+
* Date: 2016-05-15
12
+
*/
13
+
/**
14
+
* Plupload.js
15
+
*
16
+
* Copyright 2013, Moxiecode Systems AB
17
+
* Released under GPL License.
18
+
*
19
+
* License: http://www.plupload.com/license
20
+
* Contributing: http://www.plupload.com/contributing
21
+
*/
22
+
23
+
/**
24
+
* Modified for WordPress, Silverlight and Flash runtimes support was removed.
25
+
* See https://core.trac.wordpress.org/ticket/41755.
26
+
*/
27
+
28
+
/*global mOxie:true */
29
+
30
+
;(function(window, o, undef) {
31
+
32
+
var delay = window.setTimeout
33
+
, fileFilters = {}
34
+
;
35
+
36
+
// convert plupload features to caps acceptable by mOxie
37
+
function normalizeCaps(settings) {
38
+
var features = settings.required_features, caps = {};
39
+
40
+
function resolve(feature, value, strict) {
41
+
// Feature notation is deprecated, use caps (this thing here is required for backward compatibility)
42
+
var map = {
43
+
chunks: 'slice_blob',
44
+
jpgresize: 'send_binary_string',
45
+
pngresize: 'send_binary_string',
46
+
progress: 'report_upload_progress',
47
+
multi_selection: 'select_multiple',
48
+
dragdrop: 'drag_and_drop',
49
+
drop_element: 'drag_and_drop',
50
+
headers: 'send_custom_headers',
51
+
urlstream_upload: 'send_binary_string',
52
+
canSendBinary: 'send_binary',
53
+
triggerDialog: 'summon_file_dialog'
54
+
};
55
+
56
+
if (map[feature]) {
57
+
caps[map[feature]] = value;
58
+
} else if (!strict) {
59
+
caps[feature] = value;
60
+
}
61
+
}
62
+
63
+
if (typeof(features) === 'string') {
64
+
plupload.each(features.split(/\s*,\s*/), function(feature) {
65
+
resolve(feature, true);
66
+
});
67
+
} else if (typeof(features) === 'object') {
68
+
plupload.each(features, function(value, feature) {
69
+
resolve(feature, value);
70
+
});
71
+
} else if (features === true) {
72
+
// check settings for required features
73
+
if (settings.chunk_size > 0) {
74
+
caps.slice_blob = true;
75
+
}
76
+
77
+
if (settings.resize.enabled || !settings.multipart) {
78
+
caps.send_binary_string = true;
79
+
}
80
+
81
+
plupload.each(settings, function(value, feature) {
82
+
resolve(feature, !!value, true); // strict check
83
+
});
84
+
}
85
+
86
+
// WP: only html runtimes.
87
+
settings.runtimes = 'html5,html4';
88
+
89
+
return caps;
90
+
}
91
+
92
+
/**
93
+
* @module plupload
94
+
* @static
95
+
*/
96
+
var plupload = {
97
+
/**
98
+
* Plupload version will be replaced on build.
99
+
*
100
+
* @property VERSION
101
+
* @for Plupload
102
+
* @static
103
+
* @final
104
+
*/
105
+
VERSION : '2.1.9',
106
+
107
+
/**
108
+
* The state of the queue before it has started and after it has finished
109
+
*
110
+
* @property STOPPED
111
+
* @static
112
+
* @final
113
+
*/
114
+
STOPPED : 1,
115
+
116
+
/**
117
+
* Upload process is running
118
+
*
119
+
* @property STARTED
120
+
* @static
121
+
* @final
122
+
*/
123
+
STARTED : 2,
124
+
125
+
/**
126
+
* File is queued for upload
127
+
*
128
+
* @property QUEUED
129
+
* @static
130
+
* @final
131
+
*/
132
+
QUEUED : 1,
133
+
134
+
/**
135
+
* File is being uploaded
136
+
*
137
+
* @property UPLOADING
138
+
* @static
139
+
* @final
140
+
*/
141
+
UPLOADING : 2,
142
+
143
+
/**
144
+
* File has failed to be uploaded
145
+
*
146
+
* @property FAILED
147
+
* @static
148
+
* @final
149
+
*/
150
+
FAILED : 4,
151
+
152
+
/**
153
+
* File has been uploaded successfully
154
+
*
155
+
* @property DONE
156
+
* @static
157
+
* @final
158
+
*/
159
+
DONE : 5,
160
+
161
+
// Error constants used by the Error event
162
+
163
+
/**
164
+
* Generic error for example if an exception is thrown inside Silverlight.
165
+
*
166
+
* @property GENERIC_ERROR
167
+
* @static
168
+
* @final
169
+
*/
170
+
GENERIC_ERROR : -100,
171
+
172
+
/**
173
+
* HTTP transport error. For example if the server produces a HTTP status other than 200.
174
+
*
175
+
* @property HTTP_ERROR
176
+
* @static
177
+
* @final
178
+
*/
179
+
HTTP_ERROR : -200,
180
+
181
+
/**
182
+
* Generic I/O error. For example if it wasn't possible to open the file stream on local machine.
183
+
*
184
+
* @property IO_ERROR
185
+
* @static
186
+
* @final
187
+
*/
188
+
IO_ERROR : -300,
189
+
190
+
/**
191
+
* @property SECURITY_ERROR
192
+
* @static
193
+
* @final
194
+
*/
195
+
SECURITY_ERROR : -400,
196
+
197
+
/**
198
+
* Initialization error. Will be triggered if no runtime was initialized.
199
+
*
200
+
* @property INIT_ERROR
201
+
* @static
202
+
* @final
203
+
*/
204
+
INIT_ERROR : -500,
205
+
206
+
/**
207
+
* File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered.
208
+
*
209
+
* @property FILE_SIZE_ERROR
210
+
* @static
211
+
* @final
212
+
*/
213
+
FILE_SIZE_ERROR : -600,
214
+
215
+
/**
216
+
* File extension error. If the user selects a file that isn't valid according to the filters setting.
217
+
*
218
+
* @property FILE_EXTENSION_ERROR
219
+
* @static
220
+
* @final
221
+
*/
222
+
FILE_EXTENSION_ERROR : -601,
223
+
224
+
/**
225
+
* Duplicate file error. If prevent_duplicates is set to true and user selects the same file again.
226
+
*
227
+
* @property FILE_DUPLICATE_ERROR
228
+
* @static
229
+
* @final
230
+
*/
231
+
FILE_DUPLICATE_ERROR : -602,
232
+
233
+
/**
234
+
* Runtime will try to detect if image is proper one. Otherwise will throw this error.
235
+
*
236
+
* @property IMAGE_FORMAT_ERROR
237
+
* @static
238
+
* @final
239
+
*/
240
+
IMAGE_FORMAT_ERROR : -700,
241
+
242
+
/**
243
+
* While working on files runtime may run out of memory and will throw this error.
244
+
*
245
+
* @since 2.1.2
246
+
* @property MEMORY_ERROR
247
+
* @static
248
+
* @final
249
+
*/
250
+
MEMORY_ERROR : -701,
251
+
252
+
/**
253
+
* Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.
254
+
*
255
+
* @property IMAGE_DIMENSIONS_ERROR
256
+
* @static
257
+
* @final
258
+
*/
259
+
IMAGE_DIMENSIONS_ERROR : -702,
260
+
261
+
/**
262
+
* Mime type lookup table.
263
+
*
264
+
* @property mimeTypes
265
+
* @type Object
266
+
* @final
267
+
*/
268
+
mimeTypes : o.mimes,
269
+
270
+
/**
271
+
* In some cases sniffing is the only way around :(
272
+
*/
273
+
ua: o.ua,
274
+
275
+
/**
276
+
* Gets the true type of the built-in object (better version of typeof).
277
+
* @credits Angus Croll (http://javascriptweblog.wordpress.com/)
278
+
*
279
+
* @method typeOf
280
+
* @static
281
+
* @param {Object} o Object to check.
282
+
* @return {String} Object [[Class]]
283
+
*/
284
+
typeOf: o.typeOf,
285
+
286
+
/**
287
+
* Extends the specified object with another object.
288
+
*
289
+
* @method extend
290
+
* @static
291
+
* @param {Object} target Object to extend.
292
+
* @param {Object..} obj Multiple objects to extend with.
293
+
* @return {Object} Same as target, the extended object.
294
+
*/
295
+
extend : o.extend,
296
+
297
+
/**
298
+
* Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
299
+
* The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages
300
+
* to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique.
301
+
* It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property
302
+
* to an user unique key.
303
+
*
304
+
* @method guid
305
+
* @static
306
+
* @return {String} Virtually unique id.
307
+
*/
308
+
guid : o.guid,
309
+
310
+
/**
311
+
* Get array of DOM Elements by their ids.
312
+
*
313
+
* @method get
314
+
* @param {String} id Identifier of the DOM Element
315
+
* @return {Array}
316
+
*/
317
+
getAll : function get(ids) {
318
+
var els = [], el;
319
+
320
+
if (plupload.typeOf(ids) !== 'array') {
321
+
ids = [ids];
322
+
}
323
+
324
+
var i = ids.length;
325
+
while (i--) {
326
+
el = plupload.get(ids[i]);
327
+
if (el) {
328
+
els.push(el);
329
+
}
330
+
}
331
+
332
+
return els.length ? els : null;
333
+
},
334
+
335
+
/**
336
+
Get DOM element by id
337
+
338
+
@method get
339
+
@param {String} id Identifier of the DOM Element
340
+
@return {Node}
341
+
*/
342
+
get: o.get,
343
+
344
+
/**
345
+
* Executes the callback function for each item in array/object. If you return false in the
346
+
* callback it will break the loop.
347
+
*
348
+
* @method each
349
+
* @static
350
+
* @param {Object} obj Object to iterate.
351
+
* @param {function} callback Callback function to execute for each item.
352
+
*/
353
+
each : o.each,
354
+
355
+
/**
356
+
* Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
357
+
*
358
+
* @method getPos
359
+
* @static
360
+
* @param {Element} node HTML element or element id to get x, y position from.
361
+
* @param {Element} root Optional root element to stop calculations at.
362
+
* @return {object} Absolute position of the specified element object with x, y fields.
363
+
*/
364
+
getPos : o.getPos,
365
+
366
+
/**
367
+
* Returns the size of the specified node in pixels.
368
+
*
369
+
* @method getSize
370
+
* @static
371
+
* @param {Node} node Node to get the size of.
372
+
* @return {Object} Object with a w and h property.
373
+
*/
374
+
getSize : o.getSize,
375
+
376
+
/**
377
+
* Encodes the specified string.
378
+
*
379
+
* @method xmlEncode
380
+
* @static
381
+
* @param {String} s String to encode.
382
+
* @return {String} Encoded string.
383
+
*/
384
+
xmlEncode : function(str) {
385
+
var xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'}, xmlEncodeRegExp = /[<>&\"\']/g;
386
+
387
+
return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) {
388
+
return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr;
389
+
}) : str;
390
+
},
391
+
392
+
/**
393
+
* Forces anything into an array.
394
+
*
395
+
* @method toArray
396
+
* @static
397
+
* @param {Object} obj Object with length field.
398
+
* @return {Array} Array object containing all items.
399
+
*/
400
+
toArray : o.toArray,
401
+
402
+
/**
403
+
* Find an element in array and return its index if present, otherwise return -1.
404
+
*
405
+
* @method inArray
406
+
* @static
407
+
* @param {mixed} needle Element to find
408
+
* @param {Array} array
409
+
* @return {Int} Index of the element, or -1 if not found
410
+
*/
411
+
inArray : o.inArray,
412
+
413
+
/**
414
+
* Extends the language pack object with new items.
415
+
*
416
+
* @method addI18n
417
+
* @static
418
+
* @param {Object} pack Language pack items to add.
419
+
* @return {Object} Extended language pack object.
420
+
*/
421
+
addI18n : o.addI18n,
422
+
423
+
/**
424
+
* Translates the specified string by checking for the english string in the language pack lookup.
425
+
*
426
+
* @method translate
427
+
* @static
428
+
* @param {String} str String to look for.
429
+
* @return {String} Translated string or the input string if it wasn't found.
430
+
*/
431
+
translate : o.translate,
432
+
433
+
/**
434
+
* Checks if object is empty.
435
+
*
436
+
* @method isEmptyObj
437
+
* @static
438
+
* @param {Object} obj Object to check.
439
+
* @return {Boolean}
440
+
*/
441
+
isEmptyObj : o.isEmptyObj,
442
+
443
+
/**
444
+
* Checks if specified DOM element has specified class.
445
+
*
446
+
* @method hasClass
447
+
* @static
448
+
* @param {Object} obj DOM element like object to add handler to.
449
+
* @param {String} name Class name
450
+
*/
451
+
hasClass : o.hasClass,
452
+
453
+
/**
454
+
* Adds specified className to specified DOM element.
455
+
*
456
+
* @method addClass
457
+
* @static
458
+
* @param {Object} obj DOM element like object to add handler to.
459
+
* @param {String} name Class name
460
+
*/
461
+
addClass : o.addClass,
462
+
463
+
/**
464
+
* Removes specified className from specified DOM element.
465
+
*
466
+
* @method removeClass
467
+
* @static
468
+
* @param {Object} obj DOM element like object to add handler to.
469
+
* @param {String} name Class name
470
+
*/
471
+
removeClass : o.removeClass,
472
+
473
+
/**
474
+
* Returns a given computed style of a DOM element.
475
+
*
476
+
* @method getStyle
477
+
* @static
478
+
* @param {Object} obj DOM element like object.
479
+
* @param {String} name Style you want to get from the DOM element
480
+
*/
481
+
getStyle : o.getStyle,
482
+
483
+
/**
484
+
* Adds an event handler to the specified object and store reference to the handler
485
+
* in objects internal Plupload registry (@see removeEvent).
486
+
*
487
+
* @method addEvent
488
+
* @static
489
+
* @param {Object} obj DOM element like object to add handler to.
490
+
* @param {String} name Name to add event listener to.
491
+
* @param {Function} callback Function to call when event occurs.
492
+
* @param {String} (optional) key that might be used to add specifity to the event record.
493
+
*/
494
+
addEvent : o.addEvent,
495
+
496
+
/**
497
+
* Remove event handler from the specified object. If third argument (callback)
498
+
* is not specified remove all events with the specified name.
499
+
*
500
+
* @method removeEvent
501
+
* @static
502
+
* @param {Object} obj DOM element to remove event listener(s) from.
503
+
* @param {String} name Name of event listener to remove.
504
+
* @param {Function|String} (optional) might be a callback or unique key to match.
505
+
*/
506
+
removeEvent: o.removeEvent,
507
+
508
+
/**
509
+
* Remove all kind of events from the specified object
510
+
*
511
+
* @method removeAllEvents
512
+
* @static
513
+
* @param {Object} obj DOM element to remove event listeners from.
514
+
* @param {String} (optional) unique key to match, when removing events.
515
+
*/
516
+
removeAllEvents: o.removeAllEvents,
517
+
518
+
/**
519
+
* Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _.
520
+
*
521
+
* @method cleanName
522
+
* @static
523
+
* @param {String} s String to clean up.
524
+
* @return {String} Cleaned string.
525
+
*/
526
+
cleanName : function(name) {
527
+
var i, lookup;
528
+
529
+
// Replace diacritics
530
+
lookup = [
531
+
/[\300-\306]/g, 'A', /[\340-\346]/g, 'a',
532
+
/\307/g, 'C', /\347/g, 'c',
533
+
/[\310-\313]/g, 'E', /[\350-\353]/g, 'e',
534
+
/[\314-\317]/g, 'I', /[\354-\357]/g, 'i',
535
+
/\321/g, 'N', /\361/g, 'n',
536
+
/[\322-\330]/g, 'O', /[\362-\370]/g, 'o',
537
+
/[\331-\334]/g, 'U', /[\371-\374]/g, 'u'
538
+
];
539
+
540
+
for (i = 0; i < lookup.length; i += 2) {
541
+
name = name.replace(lookup[i], lookup[i + 1]);
542
+
}
543
+
544
+
// Replace whitespace
545
+
name = name.replace(/\s+/g, '_');
546
+
547
+
// Remove anything else
548
+
name = name.replace(/[^a-z0-9_\-\.]+/gi, '');
549
+
550
+
return name;
551
+
},
552
+
553
+
/**
554
+
* Builds a full url out of a base URL and an object with items to append as query string items.
555
+
*
556
+
* @method buildUrl
557
+
* @static
558
+
* @param {String} url Base URL to append query string items to.
559
+
* @param {Object} items Name/value object to serialize as a querystring.
560
+
* @return {String} String with url + serialized query string items.
561
+
*/
562
+
buildUrl : function(url, items) {
563
+
var query = '';
564
+
565
+
plupload.each(items, function(value, name) {
566
+
query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value);
567
+
});
568
+
569
+
if (query) {
570
+
url += (url.indexOf('?') > 0 ? '&' : '?') + query;
571
+
}
572
+
573
+
return url;
574
+
},
575
+
576
+
/**
577
+
* Formats the specified number as a size string for example 1024 becomes 1 KB.
578
+
*
579
+
* @method formatSize
580
+
* @static
581
+
* @param {Number} size Size to format as string.
582
+
* @return {String} Formatted size string.
583
+
*/
584
+
formatSize : function(size) {
585
+
586
+
if (size === undef || /\D/.test(size)) {
587
+
return plupload.translate('N/A');
588
+
}
589
+
590
+
function round(num, precision) {
591
+
return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
592
+
}
593
+
594
+
var boundary = Math.pow(1024, 4);
595
+
596
+
// TB
597
+
if (size > boundary) {
598
+
return round(size / boundary, 1) + " " + plupload.translate('tb');
599
+
}
600
+
601
+
// GB
602
+
if (size > (boundary/=1024)) {
603
+
return round(size / boundary, 1) + " " + plupload.translate('gb');
604
+
}
605
+
606
+
// MB
607
+
if (size > (boundary/=1024)) {
608
+
return round(size / boundary, 1) + " " + plupload.translate('mb');
609
+
}
610
+
611
+
// KB
612
+
if (size > 1024) {
613
+
return Math.round(size / 1024) + " " + plupload.translate('kb');
614
+
}
615
+
616
+
return size + " " + plupload.translate('b');
617
+
},
618
+
619
+
620
+
/**
621
+
* Parses the specified size string into a byte value. For example 10kb becomes 10240.
622
+
*
623
+
* @method parseSize
624
+
* @static
625
+
* @param {String|Number} size String to parse or number to just pass through.
626
+
* @return {Number} Size in bytes.
627
+
*/
628
+
parseSize : o.parseSizeStr,
629
+
630
+
631
+
/**
632
+
* A way to predict what runtime will be choosen in the current environment with the
633
+
* specified settings.
634
+
*
635
+
* @method predictRuntime
636
+
* @static
637
+
* @param {Object|String} config Plupload settings to check
638
+
* @param {String} [runtimes] Comma-separated list of runtimes to check against
639
+
* @return {String} Type of compatible runtime
640
+
*/
641
+
predictRuntime : function(config, runtimes) {
642
+
var up, runtime;
643
+
644
+
up = new plupload.Uploader(config);
645
+
runtime = o.Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes);
646
+
up.destroy();
647
+
return runtime;
648
+
},
649
+
650
+
/**
651
+
* Registers a filter that will be executed for each file added to the queue.
652
+
* If callback returns false, file will not be added.
653
+
*
654
+
* Callback receives two arguments: a value for the filter as it was specified in settings.filters
655
+
* and a file to be filtered. Callback is executed in the context of uploader instance.
656
+
*
657
+
* @method addFileFilter
658
+
* @static
659
+
* @param {String} name Name of the filter by which it can be referenced in settings.filters
660
+
* @param {String} cb Callback - the actual routine that every added file must pass
661
+
*/
662
+
addFileFilter: function(name, cb) {
663
+
fileFilters[name] = cb;
664
+
}
665
+
};
666
+
667
+
668
+
plupload.addFileFilter('mime_types', function(filters, file, cb) {
669
+
if (filters.length && !filters.regexp.test(file.name)) {
670
+
this.trigger('Error', {
671
+
code : plupload.FILE_EXTENSION_ERROR,
672
+
message : plupload.translate('File extension error.'),
673
+
file : file
674
+
});
675
+
cb(false);
676
+
} else {
677
+
cb(true);
678
+
}
679
+
});
680
+
681
+
682
+
plupload.addFileFilter('max_file_size', function(maxSize, file, cb) {
683
+
var undef;
684
+
685
+
maxSize = plupload.parseSize(maxSize);
686
+
687
+
// Invalid file size
688
+
if (file.size !== undef && maxSize && file.size > maxSize) {
689
+
this.trigger('Error', {
690
+
code : plupload.FILE_SIZE_ERROR,
691
+
message : plupload.translate('File size error.'),
692
+
file : file
693
+
});
694
+
cb(false);
695
+
} else {
696
+
cb(true);
697
+
}
698
+
});
699
+
700
+
701
+
plupload.addFileFilter('prevent_duplicates', function(value, file, cb) {
702
+
if (value) {
703
+
var ii = this.files.length;
704
+
while (ii--) {
705
+
// Compare by name and size (size might be 0 or undefined, but still equivalent for both)
706
+
if (file.name === this.files[ii].name && file.size === this.files[ii].size) {
707
+
this.trigger('Error', {
708
+
code : plupload.FILE_DUPLICATE_ERROR,
709
+
message : plupload.translate('Duplicate file error.'),
710
+
file : file
711
+
});
712
+
cb(false);
713
+
return;
714
+
}
715
+
}
716
+
}
717
+
cb(true);
718
+
});
719
+
720
+
721
+
/**
722
+
@class Uploader
723
+
@constructor
724
+
725
+
@param {Object} settings For detailed information about each option check documentation.
726
+
@param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger.
727
+
@param {String} settings.url URL of the server-side upload handler.
728
+
@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.
729
+
@param {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes.
730
+
@param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element.
731
+
@param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop.
732
+
@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
733
+
@param {Object} [settings.filters={}] Set of file type filters.
734
+
@param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
735
+
@param {String|Number} [settings.filters.max_file_size=0] 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`.
736
+
@param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
737
+
@param {String} [settings.flash_swf_url] URL of the Flash swf. (Not used in WordPress)
738
+
@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
739
+
@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
740
+
@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
741
+
@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
742
+
@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
743
+
@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
744
+
@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}`
745
+
@param {Number} [settings.resize.width] If image is bigger, it will be resized.
746
+
@param {Number} [settings.resize.height] If image is bigger, it will be resized.
747
+
@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
748
+
@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
749
+
@param {String} [settings.runtimes="html5,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
750
+
@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. (Not used in WordPress)
751
+
@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
752
+
@param {Boolean} [settings.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways).
753
+
*/
754
+
plupload.Uploader = function(options) {
755
+
/**
756
+
Fires when the current RunTime has been initialized.
757
+
758
+
@event Init
759
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
760
+
*/
761
+
762
+
/**
763
+
Fires after the init event incase you need to perform actions there.
764
+
765
+
@event PostInit
766
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
767
+
*/
768
+
769
+
/**
770
+
Fires when the option is changed in via uploader.setOption().
771
+
772
+
@event OptionChanged
773
+
@since 2.1
774
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
775
+
@param {String} name Name of the option that was changed
776
+
@param {Mixed} value New value for the specified option
777
+
@param {Mixed} oldValue Previous value of the option
778
+
*/
779
+
780
+
/**
781
+
Fires when the silverlight/flash or other shim needs to move.
782
+
783
+
@event Refresh
784
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
785
+
*/
786
+
787
+
/**
788
+
Fires when the overall state is being changed for the upload queue.
789
+
790
+
@event StateChanged
791
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
792
+
*/
793
+
794
+
/**
795
+
Fires when browse_button is clicked and browse dialog shows.
796
+
797
+
@event Browse
798
+
@since 2.1.2
799
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
800
+
*/
801
+
802
+
/**
803
+
Fires for every filtered file before it is added to the queue.
804
+
805
+
@event FileFiltered
806
+
@since 2.1
807
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
808
+
@param {plupload.File} file Another file that has to be added to the queue.
809
+
*/
810
+
811
+
/**
812
+
Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance.
813
+
814
+
@event QueueChanged
815
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
816
+
*/
817
+
818
+
/**
819
+
Fires after files were filtered and added to the queue.
820
+
821
+
@event FilesAdded
822
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
823
+
@param {Array} files Array of file objects that were added to queue by the user.
824
+
*/
825
+
826
+
/**
827
+
Fires when file is removed from the queue.
828
+
829
+
@event FilesRemoved
830
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
831
+
@param {Array} files Array of files that got removed.
832
+
*/
833
+
834
+
/**
835
+
Fires just before a file is uploaded. Can be used to cancel the upload for the specified file
836
+
by returning false from the handler.
837
+
838
+
@event BeforeUpload
839
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
840
+
@param {plupload.File} file File to be uploaded.
841
+
*/
842
+
843
+
/**
844
+
Fires when a file is to be uploaded by the runtime.
845
+
846
+
@event UploadFile
847
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
848
+
@param {plupload.File} file File to be uploaded.
849
+
*/
850
+
851
+
/**
852
+
Fires while a file is being uploaded. Use this event to update the current file upload progress.
853
+
854
+
@event UploadProgress
855
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
856
+
@param {plupload.File} file File that is currently being uploaded.
857
+
*/
858
+
859
+
/**
860
+
Fires when file chunk is uploaded.
861
+
862
+
@event ChunkUploaded
863
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
864
+
@param {plupload.File} file File that the chunk was uploaded for.
865
+
@param {Object} result Object with response properties.
866
+
@param {Number} result.offset The amount of bytes the server has received so far, including this chunk.
867
+
@param {Number} result.total The size of the file.
868
+
@param {String} result.response The response body sent by the server.
869
+
@param {Number} result.status The HTTP status code sent by the server.
870
+
@param {String} result.responseHeaders All the response headers as a single string.
871
+
*/
872
+
873
+
/**
874
+
Fires when a file is successfully uploaded.
875
+
876
+
@event FileUploaded
877
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
878
+
@param {plupload.File} file File that was uploaded.
879
+
@param {Object} result Object with response properties.
880
+
@param {String} result.response The response body sent by the server.
881
+
@param {Number} result.status The HTTP status code sent by the server.
882
+
@param {String} result.responseHeaders All the response headers as a single string.
883
+
*/
884
+
885
+
/**
886
+
Fires when all files in a queue are uploaded.
887
+
888
+
@event UploadComplete
889
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
890
+
@param {Array} files Array of file objects that was added to queue/selected by the user.
891
+
*/
892
+
893
+
/**
894
+
Fires when a error occurs.
895
+
896
+
@event Error
897
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
898
+
@param {Object} error Contains code, message and sometimes file and other details.
899
+
@param {Number} error.code The plupload error code.
900
+
@param {String} error.message Description of the error (uses i18n).
901
+
*/
902
+
903
+
/**
904
+
Fires when destroy method is called.
905
+
906
+
@event Destroy
907
+
@param {plupload.Uploader} uploader Uploader instance sending the event.
908
+
*/
909
+
var uid = plupload.guid()
910
+
, settings
911
+
, files = []
912
+
, preferred_caps = {}
913
+
, fileInputs = []
914
+
, fileDrops = []
915
+
, startTime
916
+
, total
917
+
, disabled = false
918
+
, xhr
919
+
;
920
+
921
+
922
+
// Private methods
923
+
function uploadNext() {
924
+
var file, count = 0, i;
925
+
926
+
if (this.state == plupload.STARTED) {
927
+
// Find first QUEUED file
928
+
for (i = 0; i < files.length; i++) {
929
+
if (!file && files[i].status == plupload.QUEUED) {
930
+
file = files[i];
931
+
if (this.trigger("BeforeUpload", file)) {
932
+
file.status = plupload.UPLOADING;
933
+
this.trigger("UploadFile", file);
934
+
}
935
+
} else {
936
+
count++;
937
+
}
938
+
}
939
+
940
+
// All files are DONE or FAILED
941
+
if (count == files.length) {
942
+
if (this.state !== plupload.STOPPED) {
943
+
this.state = plupload.STOPPED;
944
+
this.trigger("StateChanged");
945
+
}
946
+
this.trigger("UploadComplete", files);
947
+
}
948
+
}
949
+
}
950
+
951
+
952
+
function calcFile(file) {
953
+
file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;
954
+
calc();
955
+
}
956
+
957
+
958
+
function calc() {
959
+
var i, file;
960
+
961
+
// Reset stats
962
+
total.reset();
963
+
964
+
// Check status, size, loaded etc on all files
965
+
for (i = 0; i < files.length; i++) {
966
+
file = files[i];
967
+
968
+
if (file.size !== undef) {
969
+
// We calculate totals based on original file size
970
+
total.size += file.origSize;
971
+
972
+
// Since we cannot predict file size after resize, we do opposite and
973
+
// interpolate loaded amount to match magnitude of total
974
+
total.loaded += file.loaded * file.origSize / file.size;
975
+
} else {
976
+
total.size = undef;
977
+
}
978
+
979
+
if (file.status == plupload.DONE) {
980
+
total.uploaded++;
981
+
} else if (file.status == plupload.FAILED) {
982
+
total.failed++;
983
+
} else {
984
+
total.queued++;
985
+
}
986
+
}
987
+
988
+
// If we couldn't calculate a total file size then use the number of files to calc percent
989
+
if (total.size === undef) {
990
+
total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;
991
+
} else {
992
+
total.bytesPerSec = Math.ceil(total.loaded / ((+new Date() - startTime || 1) / 1000.0));
993
+
total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;
994
+
}
995
+
}
996
+
997
+
998
+
function getRUID() {
999
+
var ctrl = fileInputs[0] || fileDrops[0];
1000
+
if (ctrl) {
1001
+
return ctrl.getRuntime().uid;
1002
+
}
1003
+
return false;
1004
+
}
1005
+
1006
+
1007
+
function runtimeCan(file, cap) {
1008
+
if (file.ruid) {
1009
+
var info = o.Runtime.getInfo(file.ruid);
1010
+
if (info) {
1011
+
return info.can(cap);
1012
+
}
1013
+
}
1014
+
return false;
1015
+
}
1016
+
1017
+
1018
+
function bindEventListeners() {
1019
+
this.bind('FilesAdded FilesRemoved', function(up) {
1020
+
up.trigger('QueueChanged');
1021
+
up.refresh();
1022
+
});
1023
+
1024
+
this.bind('CancelUpload', onCancelUpload);
1025
+
1026
+
this.bind('BeforeUpload', onBeforeUpload);
1027
+
1028
+
this.bind('UploadFile', onUploadFile);
1029
+
1030
+
this.bind('UploadProgress', onUploadProgress);
1031
+
1032
+
this.bind('StateChanged', onStateChanged);
1033
+
1034
+
this.bind('QueueChanged', calc);
1035
+
1036
+
this.bind('Error', onError);
1037
+
1038
+
this.bind('FileUploaded', onFileUploaded);
1039
+
1040
+
this.bind('Destroy', onDestroy);
1041
+
}
1042
+
1043
+
1044
+
function initControls(settings, cb) {
1045
+
var self = this, inited = 0, queue = [];
1046
+
1047
+
// common settings
1048
+
var options = {
1049
+
runtime_order: settings.runtimes,
1050
+
required_caps: settings.required_features,
1051
+
preferred_caps: preferred_caps
1052
+
};
1053
+
1054
+
// add runtime specific options if any
1055
+
plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) {
1056
+
if (settings[runtime]) {
1057
+
options[runtime] = settings[runtime];
1058
+
}
1059
+
});
1060
+
1061
+
// initialize file pickers - there can be many
1062
+
if (settings.browse_button) {
1063
+
plupload.each(settings.browse_button, function(el) {
1064
+
queue.push(function(cb) {
1065
+
var fileInput = new o.FileInput(plupload.extend({}, options, {
1066
+
accept: settings.filters.mime_types,
1067
+
name: settings.file_data_name,
1068
+
multiple: settings.multi_selection,
1069
+
container: settings.container,
1070
+
browse_button: el
1071
+
}));
1072
+
1073
+
fileInput.onready = function() {
1074
+
var info = o.Runtime.getInfo(this.ruid);
1075
+
1076
+
// for backward compatibility
1077
+
o.extend(self.features, {
1078
+
chunks: info.can('slice_blob'),
1079
+
multipart: info.can('send_multipart'),
1080
+
multi_selection: info.can('select_multiple')
1081
+
});
1082
+
1083
+
inited++;
1084
+
fileInputs.push(this);
1085
+
cb();
1086
+
};
1087
+
1088
+
fileInput.onchange = function() {
1089
+
self.addFile(this.files);
1090
+
};
1091
+
1092
+
fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) {
1093
+
if (!disabled) {
1094
+
if (settings.browse_button_hover) {
1095
+
if ('mouseenter' === e.type) {
1096
+
o.addClass(el, settings.browse_button_hover);
1097
+
} else if ('mouseleave' === e.type) {
1098
+
o.removeClass(el, settings.browse_button_hover);
1099
+
}
1100
+
}
1101
+
1102
+
if (settings.browse_button_active) {
1103
+
if ('mousedown' === e.type) {
1104
+
o.addClass(el, settings.browse_button_active);
1105
+
} else if ('mouseup' === e.type) {
1106
+
o.removeClass(el, settings.browse_button_active);
1107
+
}
1108
+
}
1109
+
}
1110
+
});
1111
+
1112
+
fileInput.bind('mousedown', function() {
1113
+
self.trigger('Browse');
1114
+
});
1115
+
1116
+
fileInput.bind('error runtimeerror', function() {
1117
+
fileInput = null;
1118
+
cb();
1119
+
});
1120
+
1121
+
fileInput.init();
1122
+
});
1123
+
});
1124
+
}
1125
+
1126
+
// initialize drop zones
1127
+
if (settings.drop_element) {
1128
+
plupload.each(settings.drop_element, function(el) {
1129
+
queue.push(function(cb) {
1130
+
var fileDrop = new o.FileDrop(plupload.extend({}, options, {
1131
+
drop_zone: el
1132
+
}));
1133
+
1134
+
fileDrop.onready = function() {
1135
+
var info = o.Runtime.getInfo(this.ruid);
1136
+
1137
+
// for backward compatibility
1138
+
o.extend(self.features, {
1139
+
chunks: info.can('slice_blob'),
1140
+
multipart: info.can('send_multipart'),
1141
+
dragdrop: info.can('drag_and_drop')
1142
+
});
1143
+
1144
+
inited++;
1145
+
fileDrops.push(this);
1146
+
cb();
1147
+
};
1148
+
1149
+
fileDrop.ondrop = function() {
1150
+
self.addFile(this.files);
1151
+
};
1152
+
1153
+
fileDrop.bind('error runtimeerror', function() {
1154
+
fileDrop = null;
1155
+
cb();
1156
+
});
1157
+
1158
+
fileDrop.init();
1159
+
});
1160
+
});
1161
+
}
1162
+
1163
+
1164
+
o.inSeries(queue, function() {
1165
+
if (typeof(cb) === 'function') {
1166
+
cb(inited);
1167
+
}
1168
+
});
1169
+
}
1170
+
1171
+
1172
+
function resizeImage(blob, params, cb) {
1173
+
var img = new o.Image();
1174
+
1175
+
try {
1176
+
img.onload = function() {
1177
+
// no manipulation required if...
1178
+
if (params.width > this.width &&
1179
+
params.height > this.height &&
1180
+
params.quality === undef &&
1181
+
params.preserve_headers &&
1182
+
!params.crop
1183
+
) {
1184
+
this.destroy();
1185
+
return cb(blob);
1186
+
}
1187
+
// otherwise downsize
1188
+
img.downsize(params.width, params.height, params.crop, params.preserve_headers);
1189
+
};
1190
+
1191
+
img.onresize = function() {
1192
+
cb(this.getAsBlob(blob.type, params.quality));
1193
+
this.destroy();
1194
+
};
1195
+
1196
+
img.onerror = function() {
1197
+
cb(blob);
1198
+
};
1199
+
1200
+
img.load(blob);
1201
+
} catch(ex) {
1202
+
cb(blob);
1203
+
}
1204
+
}
1205
+
1206
+
1207
+
function setOption(option, value, init) {
1208
+
var self = this, reinitRequired = false;
1209
+
1210
+
function _setOption(option, value, init) {
1211
+
var oldValue = settings[option];
1212
+
1213
+
switch (option) {
1214
+
case 'max_file_size':
1215
+
if (option === 'max_file_size') {
1216
+
settings.max_file_size = settings.filters.max_file_size = value;
1217
+
}
1218
+
break;
1219
+
1220
+
case 'chunk_size':
1221
+
if (value = plupload.parseSize(value)) {
1222
+
settings[option] = value;
1223
+
settings.send_file_name = true;
1224
+
}
1225
+
break;
1226
+
1227
+
case 'multipart':
1228
+
settings[option] = value;
1229
+
if (!value) {
1230
+
settings.send_file_name = true;
1231
+
}
1232
+
break;
1233
+
1234
+
case 'unique_names':
1235
+
settings[option] = value;
1236
+
if (value) {
1237
+
settings.send_file_name = true;
1238
+
}
1239
+
break;
1240
+
1241
+
case 'filters':
1242
+
// for sake of backward compatibility
1243
+
if (plupload.typeOf(value) === 'array') {
1244
+
value = {
1245
+
mime_types: value
1246
+
};
1247
+
}
1248
+
1249
+
if (init) {
1250
+
plupload.extend(settings.filters, value);
1251
+
} else {
1252
+
settings.filters = value;
1253
+
}
1254
+
1255
+
// if file format filters are being updated, regenerate the matching expressions
1256
+
if (value.mime_types) {
1257
+
settings.filters.mime_types.regexp = (function(filters) {
1258
+
var extensionsRegExp = [];
1259
+
1260
+
plupload.each(filters, function(filter) {
1261
+
plupload.each(filter.extensions.split(/,/), function(ext) {
1262
+
if (/^\s*\*\s*$/.test(ext)) {
1263
+
extensionsRegExp.push('\\.*');
1264
+
} else {
1265
+
extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));
1266
+
}
1267
+
});
1268
+
});
1269
+
1270
+
return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i');
1271
+
}(settings.filters.mime_types));
1272
+
}
1273
+
break;
1274
+
1275
+
case 'resize':
1276
+
if (init) {
1277
+
plupload.extend(settings.resize, value, {
1278
+
enabled: true
1279
+
});
1280
+
} else {
1281
+
settings.resize = value;
1282
+
}
1283
+
break;
1284
+
1285
+
case 'prevent_duplicates':
1286
+
settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value;
1287
+
break;
1288
+
1289
+
// options that require reinitialisation
1290
+
case 'container':
1291
+
case 'browse_button':
1292
+
case 'drop_element':
1293
+
value = 'container' === option
1294
+
? plupload.get(value)
1295
+
: plupload.getAll(value)
1296
+
;
1297
+
1298
+
case 'runtimes':
1299
+
case 'multi_selection':
1300
+
settings[option] = value;
1301
+
if (!init) {
1302
+
reinitRequired = true;
1303
+
}
1304
+
break;
1305
+
1306
+
default:
1307
+
settings[option] = value;
1308
+
}
1309
+
1310
+
if (!init) {
1311
+
self.trigger('OptionChanged', option, value, oldValue);
1312
+
}
1313
+
}
1314
+
1315
+
if (typeof(option) === 'object') {
1316
+
plupload.each(option, function(value, option) {
1317
+
_setOption(option, value, init);
1318
+
});
1319
+
} else {
1320
+
_setOption(option, value, init);
1321
+
}
1322
+
1323
+
if (init) {
1324
+
// Normalize the list of required capabilities
1325
+
settings.required_features = normalizeCaps(plupload.extend({}, settings));
1326
+
1327
+
// Come up with the list of capabilities that can affect default mode in a multi-mode runtimes
1328
+
preferred_caps = normalizeCaps(plupload.extend({}, settings, {
1329
+
required_features: true
1330
+
}));
1331
+
} else if (reinitRequired) {
1332
+
self.trigger('Destroy');
1333
+
1334
+
initControls.call(self, settings, function(inited) {
1335
+
if (inited) {
1336
+
self.runtime = o.Runtime.getInfo(getRUID()).type;
1337
+
self.trigger('Init', { runtime: self.runtime });
1338
+
self.trigger('PostInit');
1339
+
} else {
1340
+
self.trigger('Error', {
1341
+
code : plupload.INIT_ERROR,
1342
+
message : plupload.translate('Init error.')
1343
+
});
1344
+
}
1345
+
});
1346
+
}
1347
+
}
1348
+
1349
+
1350
+
// Internal event handlers
1351
+
function onBeforeUpload(up, file) {
1352
+
// Generate unique target filenames
1353
+
if (up.settings.unique_names) {
1354
+
var matches = file.name.match(/\.([^.]+)$/), ext = "part";
1355
+
if (matches) {
1356
+
ext = matches[1];
1357
+
}
1358
+
file.target_name = file.id + '.' + ext;
1359
+
}
1360
+
}
1361
+
1362
+
1363
+
function onUploadFile(up, file) {
1364
+
var url = up.settings.url
1365
+
, chunkSize = up.settings.chunk_size
1366
+
, retries = up.settings.max_retries
1367
+
, features = up.features
1368
+
, offset = 0
1369
+
, blob
1370
+
;
1371
+
1372
+
// make sure we start at a predictable offset
1373
+
if (file.loaded) {
1374
+
offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0;
1375
+
}
1376
+
1377
+
function handleError() {
1378
+
if (retries-- > 0) {
1379
+
delay(uploadNextChunk, 1000);
1380
+
} else {
1381
+
file.loaded = offset; // reset all progress
1382
+
1383
+
up.trigger('Error', {
1384
+
code : plupload.HTTP_ERROR,
1385
+
message : plupload.translate('HTTP Error.'),
1386
+
file : file,
1387
+
response : xhr.responseText,
1388
+
status : xhr.status,
1389
+
responseHeaders: xhr.getAllResponseHeaders()
1390
+
});
1391
+
}
1392
+
}
1393
+
1394
+
function uploadNextChunk() {
1395
+
var chunkBlob, formData, args = {}, curChunkSize;
1396
+
1397
+
// make sure that file wasn't cancelled and upload is not stopped in general
1398
+
if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) {
1399
+
return;
1400
+
}
1401
+
1402
+
// send additional 'name' parameter only if required
1403
+
if (up.settings.send_file_name) {
1404
+
args.name = file.target_name || file.name;
1405
+
}
1406
+
1407
+
if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory
1408
+
curChunkSize = Math.min(chunkSize, blob.size - offset);
1409
+
chunkBlob = blob.slice(offset, offset + curChunkSize);
1410
+
} else {
1411
+
curChunkSize = blob.size;
1412
+
chunkBlob = blob;
1413
+
}
1414
+
1415
+
// If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller
1416
+
if (chunkSize && features.chunks) {
1417
+
// Setup query string arguments
1418
+
if (up.settings.send_chunk_number) {
1419
+
args.chunk = Math.ceil(offset / chunkSize);
1420
+
args.chunks = Math.ceil(blob.size / chunkSize);
1421
+
} else { // keep support for experimental chunk format, just in case
1422
+
args.offset = offset;
1423
+
args.total = blob.size;
1424
+
}
1425
+
}
1426
+
1427
+
xhr = new o.XMLHttpRequest();
1428
+
1429
+
// Do we have upload progress support
1430
+
if (xhr.upload) {
1431
+
xhr.upload.onprogress = function(e) {
1432
+
file.loaded = Math.min(file.size, offset + e.loaded);
1433
+
up.trigger('UploadProgress', file);
1434
+
};
1435
+
}
1436
+
1437
+
xhr.onload = function() {
1438
+
// check if upload made itself through
1439
+
if (xhr.status >= 400) {
1440
+
handleError();
1441
+
return;
1442
+
}
1443
+
1444
+
retries = up.settings.max_retries; // reset the counter
1445
+
1446
+
// Handle chunk response
1447
+
if (curChunkSize < blob.size) {
1448
+
chunkBlob.destroy();
1449
+
1450
+
offset += curChunkSize;
1451
+
file.loaded = Math.min(offset, blob.size);
1452
+
1453
+
up.trigger('ChunkUploaded', file, {
1454
+
offset : file.loaded,
1455
+
total : blob.size,
1456
+
response : xhr.responseText,
1457
+
status : xhr.status,
1458
+
responseHeaders: xhr.getAllResponseHeaders()
1459
+
});
1460
+
1461
+
// stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them
1462
+
if (o.Env.browser === 'Android Browser') {
1463
+
// doesn't harm in general, but is not required anywhere else
1464
+
up.trigger('UploadProgress', file);
1465
+
}
1466
+
} else {
1467
+
file.loaded = file.size;
1468
+
}
1469
+
1470
+
chunkBlob = formData = null; // Free memory
1471
+
1472
+
// Check if file is uploaded
1473
+
if (!offset || offset >= blob.size) {
1474
+
// If file was modified, destory the copy
1475
+
if (file.size != file.origSize) {
1476
+
blob.destroy();
1477
+
blob = null;
1478
+
}
1479
+
1480
+
up.trigger('UploadProgress', file);
1481
+
1482
+
file.status = plupload.DONE;
1483
+
1484
+
up.trigger('FileUploaded', file, {
1485
+
response : xhr.responseText,
1486
+
status : xhr.status,
1487
+
responseHeaders: xhr.getAllResponseHeaders()
1488
+
});
1489
+
} else {
1490
+
// Still chunks left
1491
+
delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere
1492
+
}
1493
+
};
1494
+
1495
+
xhr.onerror = function() {
1496
+
handleError();
1497
+
};
1498
+
1499
+
xhr.onloadend = function() {
1500
+
this.destroy();
1501
+
xhr = null;
1502
+
};
1503
+
1504
+
// Build multipart request
1505
+
if (up.settings.multipart && features.multipart) {
1506
+
xhr.open("post", url, true);
1507
+
1508
+
// Set custom headers
1509
+
plupload.each(up.settings.headers, function(value, name) {
1510
+
xhr.setRequestHeader(name, value);
1511
+
});
1512
+
1513
+
formData = new o.FormData();
1514
+
1515
+
// Add multipart params
1516
+
plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) {
1517
+
formData.append(name, value);
1518
+
});
1519
+
1520
+
// Add file and send it
1521
+
formData.append(up.settings.file_data_name, chunkBlob);
1522
+
xhr.send(formData, {
1523
+
runtime_order: up.settings.runtimes,
1524
+
required_caps: up.settings.required_features,
1525
+
preferred_caps: preferred_caps
1526
+
});
1527
+
} else {
1528
+
// if no multipart, send as binary stream
1529
+
url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params));
1530
+
1531
+
xhr.open("post", url, true);
1532
+
1533
+
xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header
1534
+
1535
+
// Set custom headers
1536
+
plupload.each(up.settings.headers, function(value, name) {
1537
+
xhr.setRequestHeader(name, value);
1538
+
});
1539
+
1540
+
xhr.send(chunkBlob, {
1541
+
runtime_order: up.settings.runtimes,
1542
+
required_caps: up.settings.required_features,
1543
+
preferred_caps: preferred_caps
1544
+
});
1545
+
}
1546
+
}
1547
+
1548
+
blob = file.getSource();
1549
+
1550
+
// Start uploading chunks
1551
+
if (up.settings.resize.enabled && runtimeCan(blob, 'send_binary_string') && !!~o.inArray(blob.type, ['image/jpeg', 'image/png'])) {
1552
+
// Resize if required
1553
+
resizeImage.call(this, blob, up.settings.resize, function(resizedBlob) {
1554
+
blob = resizedBlob;
1555
+
file.size = resizedBlob.size;
1556
+
uploadNextChunk();
1557
+
});
1558
+
} else {
1559
+
uploadNextChunk();
1560
+
}
1561
+
}
1562
+
1563
+
1564
+
function onUploadProgress(up, file) {
1565
+
calcFile(file);
1566
+
}
1567
+
1568
+
1569
+
function onStateChanged(up) {
1570
+
if (up.state == plupload.STARTED) {
1571
+
// Get start time to calculate bps
1572
+
startTime = (+new Date());
1573
+
} else if (up.state == plupload.STOPPED) {
1574
+
// Reset currently uploading files
1575
+
for (var i = up.files.length - 1; i >= 0; i--) {
1576
+
if (up.files[i].status == plupload.UPLOADING) {
1577
+
up.files[i].status = plupload.QUEUED;
1578
+
calc();
1579
+
}
1580
+
}
1581
+
}
1582
+
}
1583
+
1584
+
1585
+
function onCancelUpload() {
1586
+
if (xhr) {
1587
+
xhr.abort();
1588
+
}
1589
+
}
1590
+
1591
+
1592
+
function onFileUploaded(up) {
1593
+
calc();
1594
+
1595
+
// Upload next file but detach it from the error event
1596
+
// since other custom listeners might want to stop the queue
1597
+
delay(function() {
1598
+
uploadNext.call(up);
1599
+
}, 1);
1600
+
}
1601
+
1602
+
1603
+
function onError(up, err) {
1604
+
if (err.code === plupload.INIT_ERROR) {
1605
+
up.destroy();
1606
+
}
1607
+
// Set failed status if an error occured on a file
1608
+
else if (err.code === plupload.HTTP_ERROR) {
1609
+
err.file.status = plupload.FAILED;
1610
+
calcFile(err.file);
1611
+
1612
+
// Upload next file but detach it from the error event
1613
+
// since other custom listeners might want to stop the queue
1614
+
if (up.state == plupload.STARTED) { // upload in progress
1615
+
up.trigger('CancelUpload');
1616
+
delay(function() {
1617
+
uploadNext.call(up);
1618
+
}, 1);
1619
+
}
1620
+
}
1621
+
}
1622
+
1623
+
1624
+
function onDestroy(up) {
1625
+
up.stop();
1626
+
1627
+
// Purge the queue
1628
+
plupload.each(files, function(file) {
1629
+
file.destroy();
1630
+
});
1631
+
files = [];
1632
+
1633
+
if (fileInputs.length) {
1634
+
plupload.each(fileInputs, function(fileInput) {
1635
+
fileInput.destroy();
1636
+
});
1637
+
fileInputs = [];
1638
+
}
1639
+
1640
+
if (fileDrops.length) {
1641
+
plupload.each(fileDrops, function(fileDrop) {
1642
+
fileDrop.destroy();
1643
+
});
1644
+
fileDrops = [];
1645
+
}
1646
+
1647
+
preferred_caps = {};
1648
+
disabled = false;
1649
+
startTime = xhr = null;
1650
+
total.reset();
1651
+
}
1652
+
1653
+
1654
+
// Default settings
1655
+
settings = {
1656
+
runtimes: o.Runtime.order,
1657
+
max_retries: 0,
1658
+
chunk_size: 0,
1659
+
multipart: true,
1660
+
multi_selection: true,
1661
+
file_data_name: 'file',
1662
+
filters: {
1663
+
mime_types: [],
1664
+
prevent_duplicates: false,
1665
+
max_file_size: 0
1666
+
},
1667
+
resize: {
1668
+
enabled: false,
1669
+
preserve_headers: true,
1670
+
crop: false
1671
+
},
1672
+
send_file_name: true,
1673
+
send_chunk_number: true
1674
+
};
1675
+
1676
+
1677
+
setOption.call(this, options, null, true);
1678
+
1679
+
// Inital total state
1680
+
total = new plupload.QueueProgress();
1681
+
1682
+
// Add public methods
1683
+
plupload.extend(this, {
1684
+
1685
+
/**
1686
+
* Unique id for the Uploader instance.
1687
+
*
1688
+
* @property id
1689
+
* @type String
1690
+
*/
1691
+
id : uid,
1692
+
uid : uid, // mOxie uses this to differentiate between event targets
1693
+
1694
+
/**
1695
+
* Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED.
1696
+
* These states are controlled by the stop/start methods. The default value is STOPPED.
1697
+
*
1698
+
* @property state
1699
+
* @type Number
1700
+
*/
1701
+
state : plupload.STOPPED,
1702
+
1703
+
/**
1704
+
* Map of features that are available for the uploader runtime. Features will be filled
1705
+
* before the init event is called, these features can then be used to alter the UI for the end user.
1706
+
* Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize.
1707
+
*
1708
+
* @property features
1709
+
* @type Object
1710
+
*/
1711
+
features : {},
1712
+
1713
+
/**
1714
+
* Current runtime name.
1715
+
*
1716
+
* @property runtime
1717
+
* @type String
1718
+
*/
1719
+
runtime : null,
1720
+
1721
+
/**
1722
+
* Current upload queue, an array of File instances.
1723
+
*
1724
+
* @property files
1725
+
* @type Array
1726
+
* @see plupload.File
1727
+
*/
1728
+
files : files,
1729
+
1730
+
/**
1731
+
* Object with name/value settings.
1732
+
*
1733
+
* @property settings
1734
+
* @type Object
1735
+
*/
1736
+
settings : settings,
1737
+
1738
+
/**
1739
+
* Total progess information. How many files has been uploaded, total percent etc.
1740
+
*
1741
+
* @property total
1742
+
* @type plupload.QueueProgress
1743
+
*/
1744
+
total : total,
1745
+
1746
+
1747
+
/**
1748
+
* Initializes the Uploader instance and adds internal event listeners.
1749
+
*
1750
+
* @method init
1751
+
*/
1752
+
init : function() {
1753
+
var self = this, opt, preinitOpt, err;
1754
+
1755
+
preinitOpt = self.getOption('preinit');
1756
+
if (typeof(preinitOpt) == "function") {
1757
+
preinitOpt(self);
1758
+
} else {
1759
+
plupload.each(preinitOpt, function(func, name) {
1760
+
self.bind(name, func);
1761
+
});
1762
+
}
1763
+
1764
+
bindEventListeners.call(self);
1765
+
1766
+
// Check for required options
1767
+
plupload.each(['container', 'browse_button', 'drop_element'], function(el) {
1768
+
if (self.getOption(el) === null) {
1769
+
err = {
1770
+
code : plupload.INIT_ERROR,
1771
+
message : plupload.translate("'%' specified, but cannot be found.")
1772
+
}
1773
+
return false;
1774
+
}
1775
+
});
1776
+
1777
+
if (err) {
1778
+
return self.trigger('Error', err);
1779
+
}
1780
+
1781
+
1782
+
if (!settings.browse_button && !settings.drop_element) {
1783
+
return self.trigger('Error', {
1784
+
code : plupload.INIT_ERROR,
1785
+
message : plupload.translate("You must specify either 'browse_button' or 'drop_element'.")
1786
+
});
1787
+
}
1788
+
1789
+
1790
+
initControls.call(self, settings, function(inited) {
1791
+
var initOpt = self.getOption('init');
1792
+
if (typeof(initOpt) == "function") {
1793
+
initOpt(self);
1794
+
} else {
1795
+
plupload.each(initOpt, function(func, name) {
1796
+
self.bind(name, func);
1797
+
});
1798
+
}
1799
+
1800
+
if (inited) {
1801
+
self.runtime = o.Runtime.getInfo(getRUID()).type;
1802
+
self.trigger('Init', { runtime: self.runtime });
1803
+
self.trigger('PostInit');
1804
+
} else {
1805
+
self.trigger('Error', {
1806
+
code : plupload.INIT_ERROR,
1807
+
message : plupload.translate('Init error.')
1808
+
});
1809
+
}
1810
+
});
1811
+
},
1812
+
1813
+
/**
1814
+
* Set the value for the specified option(s).
1815
+
*
1816
+
* @method setOption
1817
+
* @since 2.1
1818
+
* @param {String|Object} option Name of the option to change or the set of key/value pairs
1819
+
* @param {Mixed} [value] Value for the option (is ignored, if first argument is object)
1820
+
*/
1821
+
setOption: function(option, value) {
1822
+
setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize
1823
+
},
1824
+
1825
+
/**
1826
+
* Get the value for the specified option or the whole configuration, if not specified.
1827
+
*
1828
+
* @method getOption
1829
+
* @since 2.1
1830
+
* @param {String} [option] Name of the option to get
1831
+
* @return {Mixed} Value for the option or the whole set
1832
+
*/
1833
+
getOption: function(option) {
1834
+
if (!option) {
1835
+
return settings;
1836
+
}
1837
+
return settings[option];
1838
+
},
1839
+
1840
+
/**
1841
+
* Refreshes the upload instance by dispatching out a refresh event to all runtimes.
1842
+
* This would for example reposition flash/silverlight shims on the page.
1843
+
*
1844
+
* @method refresh
1845
+
*/
1846
+
refresh : function() {
1847
+
if (fileInputs.length) {
1848
+
plupload.each(fileInputs, function(fileInput) {
1849
+
fileInput.trigger('Refresh');
1850
+
});
1851
+
}
1852
+
this.trigger('Refresh');
1853
+
},
1854
+
1855
+
/**
1856
+
* Starts uploading the queued files.
1857
+
*
1858
+
* @method start
1859
+
*/
1860
+
start : function() {
1861
+
if (this.state != plupload.STARTED) {
1862
+
this.state = plupload.STARTED;
1863
+
this.trigger('StateChanged');
1864
+
1865
+
uploadNext.call(this);
1866
+
}
1867
+
},
1868
+
1869
+
/**
1870
+
* Stops the upload of the queued files.
1871
+
*
1872
+
* @method stop
1873
+
*/
1874
+
stop : function() {
1875
+
if (this.state != plupload.STOPPED) {
1876
+
this.state = plupload.STOPPED;
1877
+
this.trigger('StateChanged');
1878
+
this.trigger('CancelUpload');
1879
+
}
1880
+
},
1881
+
1882
+
1883
+
/**
1884
+
* Disables/enables browse button on request.
1885
+
*
1886
+
* @method disableBrowse
1887
+
* @param {Boolean} disable Whether to disable or enable (default: true)
1888
+
*/
1889
+
disableBrowse : function() {
1890
+
disabled = arguments[0] !== undef ? arguments[0] : true;
1891
+
1892
+
if (fileInputs.length) {
1893
+
plupload.each(fileInputs, function(fileInput) {
1894
+
fileInput.disable(disabled);
1895
+
});
1896
+
}
1897
+
1898
+
this.trigger('DisableBrowse', disabled);
1899
+
},
1900
+
1901
+
/**
1902
+
* Returns the specified file object by id.
1903
+
*
1904
+
* @method getFile
1905
+
* @param {String} id File id to look for.
1906
+
* @return {plupload.File} File object or undefined if it wasn't found;
1907
+
*/
1908
+
getFile : function(id) {
1909
+
var i;
1910
+
for (i = files.length - 1; i >= 0; i--) {
1911
+
if (files[i].id === id) {
1912
+
return files[i];
1913
+
}
1914
+
}
1915
+
},
1916
+
1917
+
/**
1918
+
* Adds file to the queue programmatically. Can be native file, instance of Plupload.File,
1919
+
* instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded,
1920
+
* if any files were added to the queue. Otherwise nothing happens.
1921
+
*
1922
+
* @method addFile
1923
+
* @since 2.0
1924
+
* @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue.
1925
+
* @param {String} [fileName] If specified, will be used as a name for the file
1926
+
*/
1927
+
addFile : function(file, fileName) {
1928
+
var self = this
1929
+
, queue = []
1930
+
, filesAdded = []
1931
+
, ruid
1932
+
;
1933
+
1934
+
function filterFile(file, cb) {
1935
+
var queue = [];
1936
+
o.each(self.settings.filters, function(rule, name) {
1937
+
if (fileFilters[name]) {
1938
+
queue.push(function(cb) {
1939
+
fileFilters[name].call(self, rule, file, function(res) {
1940
+
cb(!res);
1941
+
});
1942
+
});
1943
+
}
1944
+
});
1945
+
o.inSeries(queue, cb);
1946
+
}
1947
+
1948
+
/**
1949
+
* @method resolveFile
1950
+
* @private
1951
+
* @param {o.File|o.Blob|plupload.File|File|Blob|input[type="file"]} file
1952
+
*/
1953
+
function resolveFile(file) {
1954
+
var type = o.typeOf(file);
1955
+
1956
+
// o.File
1957
+
if (file instanceof o.File) {
1958
+
if (!file.ruid && !file.isDetached()) {
1959
+
if (!ruid) { // weird case
1960
+
return false;
1961
+
}
1962
+
file.ruid = ruid;
1963
+
file.connectRuntime(ruid);
1964
+
}
1965
+
resolveFile(new plupload.File(file));
1966
+
}
1967
+
// o.Blob
1968
+
else if (file instanceof o.Blob) {
1969
+
resolveFile(file.getSource());
1970
+
file.destroy();
1971
+
}
1972
+
// plupload.File - final step for other branches
1973
+
else if (file instanceof plupload.File) {
1974
+
if (fileName) {
1975
+
file.name = fileName;
1976
+
}
1977
+
1978
+
queue.push(function(cb) {
1979
+
// run through the internal and user-defined filters, if any
1980
+
filterFile(file, function(err) {
1981
+
if (!err) {
1982
+
// make files available for the filters by updating the main queue directly
1983
+
files.push(file);
1984
+
// collect the files that will be passed to FilesAdded event
1985
+
filesAdded.push(file);
1986
+
1987
+
self.trigger("FileFiltered", file);
1988
+
}
1989
+
delay(cb, 1); // do not build up recursions or eventually we might hit the limits
1990
+
});
1991
+
});
1992
+
}
1993
+
// native File or blob
1994
+
else if (o.inArray(type, ['file', 'blob']) !== -1) {
1995
+
resolveFile(new o.File(null, file));
1996
+
}
1997
+
// input[type="file"]
1998
+
else if (type === 'node' && o.typeOf(file.files) === 'filelist') {
1999
+
// if we are dealing with input[type="file"]
2000
+
o.each(file.files, resolveFile);
2001
+
}
2002
+
// mixed array of any supported types (see above)
2003
+
else if (type === 'array') {
2004
+
fileName = null; // should never happen, but unset anyway to avoid funny situations
2005
+
o.each(file, resolveFile);
2006
+
}
2007
+
}
2008
+
2009
+
ruid = getRUID();
2010
+
2011
+
resolveFile(file);
2012
+
2013
+
if (queue.length) {
2014
+
o.inSeries(queue, function() {
2015
+
// if any files left after filtration, trigger FilesAdded
2016
+
if (filesAdded.length) {
2017
+
self.trigger("FilesAdded", filesAdded);
2018
+
}
2019
+
});
2020
+
}
2021
+
},
2022
+
2023
+
/**
2024
+
* Removes a specific file.
2025
+
*
2026
+
* @method removeFile
2027
+
* @param {plupload.File|String} file File to remove from queue.
2028
+
*/
2029
+
removeFile : function(file) {
2030
+
var id = typeof(file) === 'string' ? file : file.id;
2031
+
2032
+
for (var i = files.length - 1; i >= 0; i--) {
2033
+
if (files[i].id === id) {
2034
+
return this.splice(i, 1)[0];
2035
+
}
2036
+
}
2037
+
},
2038
+
2039
+
/**
2040
+
* Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events.
2041
+
*
2042
+
* @method splice
2043
+
* @param {Number} start (Optional) Start index to remove from.
2044
+
* @param {Number} length (Optional) Lengh of items to remove.
2045
+
* @return {Array} Array of files that was removed.
2046
+
*/
2047
+
splice : function(start, length) {
2048
+
// Splice and trigger events
2049
+
var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length);
2050
+
2051
+
// if upload is in progress we need to stop it and restart after files are removed
2052
+
var restartRequired = false;
2053
+
if (this.state == plupload.STARTED) { // upload in progress
2054
+
plupload.each(removed, function(file) {
2055
+
if (file.status === plupload.UPLOADING) {
2056
+
restartRequired = true; // do not restart, unless file that is being removed is uploading
2057
+
return false;
2058
+
}
2059
+
});
2060
+
2061
+
if (restartRequired) {
2062
+
this.stop();
2063
+
}
2064
+
}
2065
+
2066
+
this.trigger("FilesRemoved", removed);
2067
+
2068
+
// Dispose any resources allocated by those files
2069
+
plupload.each(removed, function(file) {
2070
+
file.destroy();
2071
+
});
2072
+
2073
+
if (restartRequired) {
2074
+
this.start();
2075
+
}
2076
+
2077
+
return removed;
2078
+
},
2079
+
2080
+
/**
2081
+
Dispatches the specified event name and its arguments to all listeners.
2082
+
2083
+
@method trigger
2084
+
@param {String} name Event name to fire.
2085
+
@param {Object..} Multiple arguments to pass along to the listener functions.
2086
+
*/
2087
+
2088
+
// override the parent method to match Plupload-like event logic
2089
+
dispatchEvent: function(type) {
2090
+
var list, args, result;
2091
+
2092
+
type = type.toLowerCase();
2093
+
2094
+
list = this.hasEventListener(type);
2095
+
2096
+
if (list) {
2097
+
// sort event list by priority
2098
+
list.sort(function(a, b) { return b.priority - a.priority; });
2099
+
2100
+
// first argument should be current plupload.Uploader instance
2101
+
args = [].slice.call(arguments);
2102
+
args.shift();
2103
+
args.unshift(this);
2104
+
2105
+
for (var i = 0; i < list.length; i++) {
2106
+
// Fire event, break chain if false is returned
2107
+
if (list[i].fn.apply(list[i].scope, args) === false) {
2108
+
return false;
2109
+
}
2110
+
}
2111
+
}
2112
+
return true;
2113
+
},
2114
+
2115
+
/**
2116
+
Check whether uploader has any listeners to the specified event.
2117
+
2118
+
@method hasEventListener
2119
+
@param {String} name Event name to check for.
2120
+
*/
2121
+
2122
+
2123
+
/**
2124
+
Adds an event listener by name.
2125
+
2126
+
@method bind
2127
+
@param {String} name Event name to listen for.
2128
+
@param {function} fn Function to call ones the event gets fired.
2129
+
@param {Object} [scope] Optional scope to execute the specified function in.
2130
+
@param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
2131
+
*/
2132
+
bind: function(name, fn, scope, priority) {
2133
+
// adapt moxie EventTarget style to Plupload-like
2134
+
plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope);
2135
+
},
2136
+
2137
+
/**
2138
+
Removes the specified event listener.
2139
+
2140
+
@method unbind
2141
+
@param {String} name Name of event to remove.
2142
+
@param {function} fn Function to remove from listener.
2143
+
*/
2144
+
2145
+
/**
2146
+
Removes all event listeners.
2147
+
2148
+
@method unbindAll
2149
+
*/
2150
+
2151
+
2152
+
/**
2153
+
* Destroys Plupload instance and cleans after itself.
2154
+
*
2155
+
* @method destroy
2156
+
*/
2157
+
destroy : function() {
2158
+
this.trigger('Destroy');
2159
+
settings = total = null; // purge these exclusively
2160
+
this.unbindAll();
2161
+
}
2162
+
});
2163
+
};
2164
+
2165
+
plupload.Uploader.prototype = o.EventTarget.instance;
2166
+
2167
+
/**
2168
+
* Constructs a new file instance.
2169
+
*
2170
+
* @class File
2171
+
* @constructor
2172
+
*
2173
+
* @param {Object} file Object containing file properties
2174
+
* @param {String} file.name Name of the file.
2175
+
* @param {Number} file.size File size.
2176
+
*/
2177
+
plupload.File = (function() {
2178
+
var filepool = {};
2179
+
2180
+
function PluploadFile(file) {
2181
+
2182
+
plupload.extend(this, {
2183
+
2184
+
/**
2185
+
* File id this is a globally unique id for the specific file.
2186
+
*
2187
+
* @property id
2188
+
* @type String
2189
+
*/
2190
+
id: plupload.guid(),
2191
+
2192
+
/**
2193
+
* File name for example "myfile.gif".
2194
+
*
2195
+
* @property name
2196
+
* @type String
2197
+
*/
2198
+
name: file.name || file.fileName,
2199
+
2200
+
/**
2201
+
* File type, `e.g image/jpeg`
2202
+
*
2203
+
* @property type
2204
+
* @type String
2205
+
*/
2206
+
type: file.type || '',
2207
+
2208
+
/**
2209
+
* File size in bytes (may change after client-side manupilation).
2210
+
*
2211
+
* @property size
2212
+
* @type Number
2213
+
*/
2214
+
size: file.size || file.fileSize,
2215
+
2216
+
/**
2217
+
* Original file size in bytes.
2218
+
*
2219
+
* @property origSize
2220
+
* @type Number
2221
+
*/
2222
+
origSize: file.size || file.fileSize,
2223
+
2224
+
/**
2225
+
* Number of bytes uploaded of the files total size.
2226
+
*
2227
+
* @property loaded
2228
+
* @type Number
2229
+
*/
2230
+
loaded: 0,
2231
+
2232
+
/**
2233
+
* Number of percentage uploaded of the file.
2234
+
*
2235
+
* @property percent
2236
+
* @type Number
2237
+
*/
2238
+
percent: 0,
2239
+
2240
+
/**
2241
+
* Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
2242
+
*
2243
+
* @property status
2244
+
* @type Number
2245
+
* @see plupload
2246
+
*/
2247
+
status: plupload.QUEUED,
2248
+
2249
+
/**
2250
+
* Date of last modification.
2251
+
*
2252
+
* @property lastModifiedDate
2253
+
* @type {String}
2254
+
*/
2255
+
lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
2256
+
2257
+
/**
2258
+
* Returns native window.File object, when it's available.
2259
+
*
2260
+
* @method getNative
2261
+
* @return {window.File} or null, if plupload.File is of different origin
2262
+
*/
2263
+
getNative: function() {
2264
+
var file = this.getSource().getSource();
2265
+
return o.inArray(o.typeOf(file), ['blob', 'file']) !== -1 ? file : null;
2266
+
},
2267
+
2268
+
/**
2269
+
* Returns mOxie.File - unified wrapper object that can be used across runtimes.
2270
+
*
2271
+
* @method getSource
2272
+
* @return {mOxie.File} or null
2273
+
*/
2274
+
getSource: function() {
2275
+
if (!filepool[this.id]) {
2276
+
return null;
2277
+
}
2278
+
return filepool[this.id];
2279
+
},
2280
+
2281
+
/**
2282
+
* Destroys plupload.File object.
2283
+
*
2284
+
* @method destroy
2285
+
*/
2286
+
destroy: function() {
2287
+
var src = this.getSource();
2288
+
if (src) {
2289
+
src.destroy();
2290
+
delete filepool[this.id];
2291
+
}
2292
+
}
2293
+
});
2294
+
2295
+
filepool[this.id] = file;
2296
+
}
2297
+
2298
+
return PluploadFile;
2299
+
}());
2300
+
2301
+
2302
+
/**
2303
+
* Constructs a queue progress.
2304
+
*
2305
+
* @class QueueProgress
2306
+
* @constructor
2307
+
*/
2308
+
plupload.QueueProgress = function() {
2309
+
var self = this; // Setup alias for self to reduce code size when it's compressed
2310
+
2311
+
/**
2312
+
* Total queue file size.
2313
+
*
2314
+
* @property size
2315
+
* @type Number
2316
+
*/
2317
+
self.size = 0;
2318
+
2319
+
/**
2320
+
* Total bytes uploaded.
2321
+
*
2322
+
* @property loaded
2323
+
* @type Number
2324
+
*/
2325
+
self.loaded = 0;
2326
+
2327
+
/**
2328
+
* Number of files uploaded.
2329
+
*
2330
+
* @property uploaded
2331
+
* @type Number
2332
+
*/
2333
+
self.uploaded = 0;
2334
+
2335
+
/**
2336
+
* Number of files failed to upload.
2337
+
*
2338
+
* @property failed
2339
+
* @type Number
2340
+
*/
2341
+
self.failed = 0;
2342
+
2343
+
/**
2344
+
* Number of files yet to be uploaded.
2345
+
*
2346
+
* @property queued
2347
+
* @type Number
2348
+
*/
2349
+
self.queued = 0;
2350
+
2351
+
/**
2352
+
* Total percent of the uploaded bytes.
2353
+
*
2354
+
* @property percent
2355
+
* @type Number
2356
+
*/
2357
+
self.percent = 0;
2358
+
2359
+
/**
2360
+
* Bytes uploaded per second.
2361
+
*
2362
+
* @property bytesPerSec
2363
+
* @type Number
2364
+
*/
2365
+
self.bytesPerSec = 0;
2366
+
2367
+
/**
2368
+
* Resets the progress to its initial values.
2369
+
*
2370
+
* @method reset
2371
+
*/
2372
+
self.reset = function() {
2373
+
self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0;
2374
+
};
2375
+
};
2376
+
2377
+
window.plupload = plupload;
2378
+
2379
+
}(window, mOxie));
2380
+