run:R W Run
20.06 KB
2026-03-11 16:18:51
R W Run
11.75 KB
2026-03-11 16:18:51
R W Run
17.57 KB
2026-03-11 16:18:51
R W Run
248.38 KB
2026-03-11 16:18:51
R W Run
85.35 KB
2026-03-11 16:18:51
R W Run
58.9 KB
2026-03-11 16:18:51
R W Run
15.24 KB
2026-03-11 16:18:51
R W Run
16.31 KB
2026-03-11 16:18:51
R W Run
5.89 KB
2026-03-11 16:18:51
R W Run
error_log
📄plupload.js
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
32var delay = window.setTimeout
33, fileFilters = {}
34;
35
36// convert plupload features to caps acceptable by mOxie
37function 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 */
96var 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
668plupload.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
682plupload.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
701plupload.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*/
754plupload.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
2165plupload.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 */
2177plupload.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
2377window.plupload = plupload;
2378
2379}(window, mOxie));
2380
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1