summaryrefslogtreecommitdiffstats
path: root/debian/missing-sources/plupload/javascript/plupload.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:56:53 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:56:53 +0000
commita9c818418b81b93680170e1a84d4e221e578ad2f (patch)
tree5b883aa428f1edb12f5d40f9768438ee16a7ed6b /debian/missing-sources/plupload/javascript/plupload.js
parentAdding upstream version 6.4.3+dfsg1. (diff)
downloadwordpress-a9c818418b81b93680170e1a84d4e221e578ad2f.tar.xz
wordpress-a9c818418b81b93680170e1a84d4e221e578ad2f.zip
Adding debian version 6.4.3+dfsg1-1.debian/6.4.3+dfsg1-1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/missing-sources/plupload/javascript/plupload.js')
-rw-r--r--debian/missing-sources/plupload/javascript/plupload.js1774
1 files changed, 1774 insertions, 0 deletions
diff --git a/debian/missing-sources/plupload/javascript/plupload.js b/debian/missing-sources/plupload/javascript/plupload.js
new file mode 100644
index 0000000..94156df
--- /dev/null
+++ b/debian/missing-sources/plupload/javascript/plupload.js
@@ -0,0 +1,1774 @@
+/**
+ * plupload.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+// JSLint defined globals
+/*global window:false, escape:false */
+
+/*!@@version@@*/
+
+(function() {
+ var count = 0, runtimes = [], i18n = {}, mimes = {},
+ xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'},
+ xmlEncodeRegExp = /[<>&\"\']/g, undef, delay = window.setTimeout,
+ // A place to store references to event handlers
+ eventhash = {},
+ uid;
+
+ // IE W3C like event funcs
+ function preventDefault() {
+ this.returnValue = false;
+ }
+
+ function stopPropagation() {
+ this.cancelBubble = true;
+ }
+
+ // Parses the default mime types string into a mimes lookup map
+ (function(mime_data) {
+ var items = mime_data.split(/,/), i, y, ext;
+
+ for (i = 0; i < items.length; i += 2) {
+ ext = items[i + 1].split(/ /);
+
+ for (y = 0; y < ext.length; y++) {
+ mimes[ext[y]] = items[i];
+ }
+ }
+ })(
+ "application/msword,doc dot," +
+ "application/pdf,pdf," +
+ "application/pgp-signature,pgp," +
+ "application/postscript,ps ai eps," +
+ "application/rtf,rtf," +
+ "application/vnd.ms-excel,xls xlb," +
+ "application/vnd.ms-powerpoint,ppt pps pot," +
+ "application/zip,zip," +
+ "application/x-shockwave-flash,swf swfl," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
+ "application/x-javascript,js," +
+ "application/json,json," +
+ "audio/mpeg,mpga mpega mp2 mp3," +
+ "audio/x-wav,wav," +
+ "audio/mp4,m4a," +
+ "image/bmp,bmp," +
+ "image/gif,gif," +
+ "image/jpeg,jpeg jpg jpe," +
+ "image/photoshop,psd," +
+ "image/png,png," +
+ "image/svg+xml,svg svgz," +
+ "image/tiff,tiff tif," +
+ "text/plain,asc txt text diff log," +
+ "text/html,htm html xhtml," +
+ "text/css,css," +
+ "text/csv,csv," +
+ "text/rtf,rtf," +
+ "video/mpeg,mpeg mpg mpe m2v," +
+ "video/quicktime,qt mov," +
+ "video/mp4,mp4," +
+ "video/x-m4v,m4v," +
+ "video/x-flv,flv," +
+ "video/x-ms-wmv,wmv," +
+ "video/avi,avi," +
+ "video/webm,webm," +
+ "video/3gpp,3gp," +
+ "video/3gpp2,3g2," +
+ "video/vnd.rn-realvideo,rv," +
+ "application/vnd.oasis.opendocument.formula-template,otf," +
+ "application/octet-stream,exe"
+ );
+
+ /**
+ * Plupload class with some global constants and functions.
+ *
+ * @example
+ * // Encode entities
+ * console.log(plupload.xmlEncode("My string &lt;&gt;"));
+ *
+ * // Generate unique id
+ * console.log(plupload.guid());
+ *
+ * @static
+ * @class plupload
+ */
+ var plupload = {
+ /**
+ * Plupload version will be replaced on build.
+ */
+ VERSION : '@@version@@',
+
+ /**
+ * Inital state of the queue and also the state ones it's finished all it's uploads.
+ *
+ * @property STOPPED
+ * @final
+ */
+ STOPPED : 1,
+
+ /**
+ * Upload process is running
+ *
+ * @property STARTED
+ * @final
+ */
+ STARTED : 2,
+
+ /**
+ * File is queued for upload
+ *
+ * @property QUEUED
+ * @final
+ */
+ QUEUED : 1,
+
+ /**
+ * File is being uploaded
+ *
+ * @property UPLOADING
+ * @final
+ */
+ UPLOADING : 2,
+
+ /**
+ * File has failed to be uploaded
+ *
+ * @property FAILED
+ * @final
+ */
+ FAILED : 4,
+
+ /**
+ * File has been uploaded successfully
+ *
+ * @property DONE
+ * @final
+ */
+ DONE : 5,
+
+ // Error constants used by the Error event
+
+ /**
+ * Generic error for example if an exception is thrown inside Silverlight.
+ *
+ * @property GENERIC_ERROR
+ * @final
+ */
+ GENERIC_ERROR : -100,
+
+ /**
+ * HTTP transport error. For example if the server produces a HTTP status other than 200.
+ *
+ * @property HTTP_ERROR
+ * @final
+ */
+ HTTP_ERROR : -200,
+
+ /**
+ * Generic I/O error. For exampe if it wasn't possible to open the file stream on local machine.
+ *
+ * @property IO_ERROR
+ * @final
+ */
+ IO_ERROR : -300,
+
+ /**
+ * Generic I/O error. For exampe if it wasn't possible to open the file stream on local machine.
+ *
+ * @property SECURITY_ERROR
+ * @final
+ */
+ SECURITY_ERROR : -400,
+
+ /**
+ * Initialization error. Will be triggered if no runtime was initialized.
+ *
+ * @property INIT_ERROR
+ * @final
+ */
+ INIT_ERROR : -500,
+
+ /**
+ * 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.
+ *
+ * @property FILE_SIZE_ERROR
+ * @final
+ */
+ FILE_SIZE_ERROR : -600,
+
+ /**
+ * File extension error. If the user selects a file that isn't valid according to the filters setting.
+ *
+ * @property FILE_EXTENSION_ERROR
+ * @final
+ */
+ FILE_EXTENSION_ERROR : -601,
+
+ /**
+ * Runtime will try to detect if image is proper one. Otherwise will throw this error.
+ *
+ * @property IMAGE_FORMAT_ERROR
+ * @final
+ */
+ IMAGE_FORMAT_ERROR : -700,
+
+ /**
+ * While working on the image runtime will try to detect if the operation may potentially run out of memeory and will throw this error.
+ *
+ * @property IMAGE_MEMORY_ERROR
+ * @final
+ */
+ IMAGE_MEMORY_ERROR : -701,
+
+ /**
+ * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.
+ *
+ * @property IMAGE_DIMENSIONS_ERROR
+ * @final
+ */
+ IMAGE_DIMENSIONS_ERROR : -702,
+
+
+ /**
+ * Mime type lookup table.
+ *
+ * @property mimeTypes
+ * @type Object
+ * @final
+ */
+ mimeTypes : mimes,
+
+ /**
+ * In some cases sniffing is the only way around :(
+ */
+ ua: (function() {
+ var nav = navigator, userAgent = nav.userAgent, vendor = nav.vendor, webkit, opera, safari;
+
+ webkit = /WebKit/.test(userAgent);
+ safari = webkit && vendor.indexOf('Apple') !== -1;
+ opera = window.opera && window.opera.buildNumber;
+
+ return {
+ windows: navigator.platform.indexOf('Win') !== -1,
+ android: /Android/.test(userAgent),
+ ie: !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName),
+ webkit: webkit,
+ gecko: !webkit && /Gecko/.test(userAgent),
+ safari: safari,
+ opera: !!opera
+ };
+ }()),
+
+ /**
+ * Gets the true type of the built-in object (better version of typeof).
+ * @credits Angus Croll (http://javascriptweblog.wordpress.com/)
+ *
+ * @param {Object} o Object to check.
+ * @return {String} Object [[Class]]
+ */
+ typeOf: function(o) {
+ return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
+ },
+
+ /**
+ * Extends the specified object with another object.
+ *
+ * @method extend
+ * @param {Object} target Object to extend.
+ * @param {Object..} obj Multiple objects to extend with.
+ * @return {Object} Same as target, the extended object.
+ */
+ extend : function(target) {
+ plupload.each(arguments, function(arg, i) {
+ if (i > 0) {
+ plupload.each(arg, function(value, key) {
+ target[key] = value;
+ });
+ }
+ });
+
+ return target;
+ },
+
+ /**
+ * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _.
+ *
+ * @method cleanName
+ * @param {String} s String to clean up.
+ * @return {String} Cleaned string.
+ */
+ cleanName : function(name) {
+ var i, lookup;
+
+ // Replace diacritics
+ lookup = [
+ /[\300-\306]/g, 'A', /[\340-\346]/g, 'a',
+ /\307/g, 'C', /\347/g, 'c',
+ /[\310-\313]/g, 'E', /[\350-\353]/g, 'e',
+ /[\314-\317]/g, 'I', /[\354-\357]/g, 'i',
+ /\321/g, 'N', /\361/g, 'n',
+ /[\322-\330]/g, 'O', /[\362-\370]/g, 'o',
+ /[\331-\334]/g, 'U', /[\371-\374]/g, 'u'
+ ];
+
+ for (i = 0; i < lookup.length; i += 2) {
+ name = name.replace(lookup[i], lookup[i + 1]);
+ }
+
+ // Replace whitespace
+ name = name.replace(/\s+/g, '_');
+
+ // Remove anything else
+ name = name.replace(/[^a-z0-9_\-\.]+/gi, '');
+
+ return name;
+ },
+
+ /**
+ * Adds a specific upload runtime like for example flash or gears.
+ *
+ * @method addRuntime
+ * @param {String} name Runtime name for example flash.
+ * @param {Object} obj Object containing init/destroy method.
+ */
+ addRuntime : function(name, runtime) {
+ runtime.name = name;
+ runtimes[name] = runtime;
+ runtimes.push(runtime);
+
+ return runtime;
+ },
+
+ /**
+ * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
+ * The only way a user would be able to get the same ID is if the two persons at the same exact milisecond manages
+ * 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.
+ * It's more probable for the earth to be hit with an ansteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property
+ * to an user unique key.
+ *
+ * @method guid
+ * @return {String} Virtually unique id.
+ */
+ guid : function() {
+ var guid = new Date().getTime().toString(32), i;
+
+ for (i = 0; i < 5; i++) {
+ guid += Math.floor(Math.random() * 65535).toString(32);
+ }
+
+ return (plupload.guidPrefix || 'p') + guid + (count++).toString(32);
+ },
+
+ /**
+ * Builds a full url out of a base URL and an object with items to append as query string items.
+ *
+ * @param {String} url Base URL to append query string items to.
+ * @param {Object} items Name/value object to serialize as a querystring.
+ * @return {String} String with url + serialized query string items.
+ */
+ buildUrl : function(url, items) {
+ var query = '';
+
+ plupload.each(items, function(value, name) {
+ query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value);
+ });
+
+ if (query) {
+ url += (url.indexOf('?') > 0 ? '&' : '?') + query;
+ }
+
+ return url;
+ },
+
+ /**
+ * Executes the callback function for each item in array/object. If you return false in the
+ * callback it will break the loop.
+ *
+ * @param {Object} obj Object to iterate.
+ * @param {function} callback Callback function to execute for each item.
+ */
+ each : function(obj, callback) {
+ var length, key, i;
+
+ if (obj) {
+ length = obj.length;
+
+ if (length === undef) {
+ // Loop object items
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (callback(obj[key], key) === false) {
+ return;
+ }
+ }
+ }
+ } else {
+ // Loop array items
+ for (i = 0; i < length; i++) {
+ if (callback(obj[i], i) === false) {
+ return;
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * Formats the specified number as a size string for example 1024 becomes 1 KB.
+ *
+ * @method formatSize
+ * @param {Number} size Size to format as string.
+ * @return {String} Formatted size string.
+ */
+ formatSize : function(size) {
+ if (size === undef || /\D/.test(size)) {
+ return plupload.translate('N/A');
+ }
+
+ // GB
+ if (size > 1073741824) {
+ return Math.round(size / 1073741824, 1) + " GB";
+ }
+
+ // MB
+ if (size > 1048576) {
+ return Math.round(size / 1048576, 1) + " MB";
+ }
+
+ // KB
+ if (size > 1024) {
+ return Math.round(size / 1024, 1) + " KB";
+ }
+
+ return size + " b";
+ },
+
+ /**
+ * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
+ *
+ * @method getPos
+ * @param {Element} node HTML element or element id to get x, y position from.
+ * @param {Element} root Optional root element to stop calculations at.
+ * @return {object} Absolute position of the specified element object with x, y fields.
+ */
+ getPos : function(node, root) {
+ var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
+
+ node = node;
+ root = root || doc.body;
+
+ // Returns the x, y cordinate for an element on IE 6 and IE 7
+ function getIEPos(node) {
+ var bodyElm, rect, x = 0, y = 0;
+
+ if (node) {
+ rect = node.getBoundingClientRect();
+ bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
+ x = rect.left + bodyElm.scrollLeft;
+ y = rect.top + bodyElm.scrollTop;
+ }
+
+ return {
+ x : x,
+ y : y
+ };
+ }
+
+ // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
+ if (node && node.getBoundingClientRect && plupload.ua.ie && (!doc.documentMode || doc.documentMode < 8)) {
+ nodeRect = getIEPos(node);
+ rootRect = getIEPos(root);
+
+ return {
+ x : nodeRect.x - rootRect.x,
+ y : nodeRect.y - rootRect.y
+ };
+ }
+
+ parent = node;
+ while (parent && parent != root && parent.nodeType) {
+ x += parent.offsetLeft || 0;
+ y += parent.offsetTop || 0;
+ parent = parent.offsetParent;
+ }
+
+ parent = node.parentNode;
+ while (parent && parent != root && parent.nodeType) {
+ x -= parent.scrollLeft || 0;
+ y -= parent.scrollTop || 0;
+ parent = parent.parentNode;
+ }
+
+ return {
+ x : x,
+ y : y
+ };
+ },
+
+ /**
+ * Returns the size of the specified node in pixels.
+ *
+ * @param {Node} node Node to get the size of.
+ * @return {Object} Object with a w and h property.
+ */
+ getSize : function(node) {
+ return {
+ w : node.offsetWidth || node.clientWidth,
+ h : node.offsetHeight || node.clientHeight
+ };
+ },
+
+ /**
+ * Parses the specified size string into a byte value. For example 10kb becomes 10240.
+ *
+ * @method parseSize
+ * @param {String/Number} size String to parse or number to just pass through.
+ * @return {Number} Size in bytes.
+ */
+ parseSize : function(size) {
+ var mul;
+
+ if (typeof(size) == 'string') {
+ size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
+ mul = size[2];
+ size = +size[1];
+
+ if (mul == 'g') {
+ size *= 1073741824;
+ }
+
+ if (mul == 'm') {
+ size *= 1048576;
+ }
+
+ if (mul == 'k') {
+ size *= 1024;
+ }
+ }
+
+ return size;
+ },
+
+ /**
+ * Encodes the specified string.
+ *
+ * @method xmlEncode
+ * @param {String} s String to encode.
+ * @return {String} Encoded string.
+ */
+ xmlEncode : function(str) {
+ return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) {
+ return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr;
+ }) : str;
+ },
+
+ /**
+ * Forces anything into an array.
+ *
+ * @method toArray
+ * @param {Object} obj Object with length field.
+ * @return {Array} Array object containing all items.
+ */
+ toArray : function(obj) {
+ var i, arr = [];
+
+ for (i = 0; i < obj.length; i++) {
+ arr[i] = obj[i];
+ }
+
+ return arr;
+ },
+
+ /**
+ * Find an element in array and return it's index if present, otherwise return -1.
+ *
+ * @method inArray
+ * @param {mixed} needle Element to find
+ * @param {Array} array
+ * @return {Int} Index of the element, or -1 if not found
+ */
+ inArray : function(needle, array) {
+ if (array) {
+ if (Array.prototype.indexOf) {
+ return Array.prototype.indexOf.call(array, needle);
+ }
+
+ for (var i = 0, length = array.length; i < length; i++) {
+ if (array[i] === needle) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Extends the language pack object with new items.
+ *
+ * @param {Object} pack Language pack items to add.
+ * @return {Object} Extended language pack object.
+ */
+ addI18n : function(pack) {
+ return plupload.extend(i18n, pack);
+ },
+
+ /**
+ * Translates the specified string by checking for the english string in the language pack lookup.
+ *
+ * @param {String} str String to look for.
+ * @return {String} Translated string or the input string if it wasn't found.
+ */
+ translate : function(str) {
+ return i18n[str] || str;
+ },
+
+ /**
+ * Checks if object is empty.
+ *
+ * @param {Object} obj Object to check.
+ * @return {Boolean}
+ */
+ isEmptyObj : function(obj) {
+ if (obj === undef) return true;
+
+ for (var prop in obj) {
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * Checks if specified DOM element has specified class.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ hasClass : function(obj, name) {
+ var regExp;
+
+ if (obj.className == '') {
+ return false;
+ }
+
+ regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+
+ return regExp.test(obj.className);
+ },
+
+ /**
+ * Adds specified className to specified DOM element.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ addClass : function(obj, name) {
+ if (!plupload.hasClass(obj, name)) {
+ obj.className = obj.className == '' ? name : obj.className.replace(/\s+$/, '')+' '+name;
+ }
+ },
+
+ /**
+ * Removes specified className from specified DOM element.
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Class name
+ */
+ removeClass : function(obj, name) {
+ var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
+
+ obj.className = obj.className.replace(regExp, function($0, $1, $2) {
+ return $1 === ' ' && $2 === ' ' ? ' ' : '';
+ });
+ },
+
+ /**
+ * Returns a given computed style of a DOM element.
+ *
+ * @param {Object} obj DOM element like object.
+ * @param {String} name Style you want to get from the DOM element
+ */
+ getStyle : function(obj, name) {
+ if (obj.currentStyle) {
+ return obj.currentStyle[name];
+ } else if (window.getComputedStyle) {
+ return window.getComputedStyle(obj, null)[name];
+ }
+ },
+
+ /**
+ * Adds an event handler to the specified object and store reference to the handler
+ * in objects internal Plupload registry (@see removeEvent).
+ *
+ * @param {Object} obj DOM element like object to add handler to.
+ * @param {String} name Name to add event listener to.
+ * @param {Function} callback Function to call when event occurs.
+ * @param {String} (optional) key that might be used to add specifity to the event record.
+ */
+ addEvent : function(obj, name, callback) {
+ var func, events, types, key;
+
+ // if passed in, event will be locked with this key - one would need to provide it to removeEvent
+ key = arguments[3];
+
+ name = name.toLowerCase();
+
+ // Initialize unique identifier if needed
+ if (uid === undef) {
+ uid = 'Plupload_' + plupload.guid();
+ }
+
+ // Add event listener
+ if (obj.addEventListener) {
+ func = callback;
+
+ obj.addEventListener(name, func, false);
+ } else if (obj.attachEvent) {
+
+ func = function() {
+ var evt = window.event;
+
+ if (!evt.target) {
+ evt.target = evt.srcElement;
+ }
+
+ evt.preventDefault = preventDefault;
+ evt.stopPropagation = stopPropagation;
+
+ callback(evt);
+ };
+ obj.attachEvent('on' + name, func);
+ }
+
+ // Log event handler to objects internal Plupload registry
+ if (obj[uid] === undef) {
+ obj[uid] = plupload.guid();
+ }
+
+ if (!eventhash.hasOwnProperty(obj[uid])) {
+ eventhash[obj[uid]] = {};
+ }
+
+ events = eventhash[obj[uid]];
+
+ if (!events.hasOwnProperty(name)) {
+ events[name] = [];
+ }
+
+ events[name].push({
+ func: func,
+ orig: callback, // store original callback for IE
+ key: key
+ });
+ },
+
+
+ /**
+ * Remove event handler from the specified object. If third argument (callback)
+ * is not specified remove all events with the specified name.
+ *
+ * @param {Object} obj DOM element to remove event listener(s) from.
+ * @param {String} name Name of event listener to remove.
+ * @param {Function|String} (optional) might be a callback or unique key to match.
+ */
+ removeEvent: function(obj, name) {
+ var type, callback, key;
+
+ // match the handler either by callback or by key
+ if (typeof(arguments[2]) == "function") {
+ callback = arguments[2];
+ } else {
+ key = arguments[2];
+ }
+
+ name = name.toLowerCase();
+
+ if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
+ type = eventhash[obj[uid]][name];
+ } else {
+ return;
+ }
+
+
+ for (var i=type.length-1; i>=0; i--) {
+ // undefined or not, key should match
+ if (type[i].key === key || type[i].orig === callback) {
+
+ if (obj.removeEventListener) {
+ obj.removeEventListener(name, type[i].func, false);
+ } else if (obj.detachEvent) {
+ obj.detachEvent('on'+name, type[i].func);
+ }
+
+ type[i].orig = null;
+ type[i].func = null;
+
+ type.splice(i, 1);
+
+ // If callback was passed we are done here, otherwise proceed
+ if (callback !== undef) {
+ break;
+ }
+ }
+ }
+
+ // If event array got empty, remove it
+ if (!type.length) {
+ delete eventhash[obj[uid]][name];
+ }
+
+ // If Plupload registry has become empty, remove it
+ if (plupload.isEmptyObj(eventhash[obj[uid]])) {
+ delete eventhash[obj[uid]];
+
+ // IE doesn't let you remove DOM object property with - delete
+ try {
+ delete obj[uid];
+ } catch(e) {
+ obj[uid] = undef;
+ }
+ }
+ },
+
+
+ /**
+ * Remove all kind of events from the specified object
+ *
+ * @param {Object} obj DOM element to remove event listeners from.
+ * @param {String} (optional) unique key to match, when removing events.
+ */
+ removeAllEvents: function(obj) {
+ var key = arguments[1];
+
+ if (obj[uid] === undef || !obj[uid]) {
+ return;
+ }
+
+ plupload.each(eventhash[obj[uid]], function(events, name) {
+ plupload.removeEvent(obj, name, key);
+ });
+ }
+ };
+
+
+ /**
+ * Uploader class, an instance of this class will be created for each upload field.
+ *
+ * @example
+ * var uploader = new plupload.Uploader({
+ * runtimes : 'gears,html5,flash',
+ * browse_button : 'button_id'
+ * });
+ *
+ * uploader.bind('Init', function(up) {
+ * alert('Supports drag/drop: ' + (!!up.features.dragdrop));
+ * });
+ *
+ * uploader.bind('FilesAdded', function(up, files) {
+ * alert('Selected files: ' + files.length);
+ * });
+ *
+ * uploader.bind('QueueChanged', function(up) {
+ * alert('Queued files: ' + uploader.files.length);
+ * });
+ *
+ * uploader.init();
+ *
+ * @class plupload.Uploader
+ */
+
+ /**
+ * Constructs a new uploader instance.
+ *
+ * @constructor
+ * @method Uploader
+ * @param {Object} settings Initialization settings, to be used by the uploader instance and runtimes.
+ */
+ plupload.Uploader = function(settings) {
+ var events = {}, total, files = [], startTime, disabled = false;
+
+ // Inital total state
+ total = new plupload.QueueProgress();
+
+ // Default settings
+ settings = plupload.extend({
+ chunk_size : 0,
+ multipart : true,
+ multi_selection : true,
+ file_data_name : 'file',
+ filters : []
+ }, settings);
+
+ // Private methods
+ function uploadNext() {
+ var file, count = 0, i;
+
+ if (this.state == plupload.STARTED) {
+ // Find first QUEUED file
+ for (i = 0; i < files.length; i++) {
+ if (!file && files[i].status == plupload.QUEUED) {
+ file = files[i];
+ file.status = plupload.UPLOADING;
+ if (this.trigger("BeforeUpload", file)) {
+ this.trigger("UploadFile", file);
+ }
+ } else {
+ count++;
+ }
+ }
+
+ // All files are DONE or FAILED
+ if (count == files.length) {
+ this.stop();
+ this.trigger("UploadComplete", files);
+ }
+ }
+ }
+
+ function calc() {
+ var i, file;
+
+ // Reset stats
+ total.reset();
+
+ // Check status, size, loaded etc on all files
+ for (i = 0; i < files.length; i++) {
+ file = files[i];
+
+ if (file.size !== undef) {
+ total.size += file.size;
+ total.loaded += file.loaded;
+ } else {
+ total.size = undef;
+ }
+
+ if (file.status == plupload.DONE) {
+ total.uploaded++;
+ } else if (file.status == plupload.FAILED) {
+ total.failed++;
+ } else {
+ total.queued++;
+ }
+ }
+
+ // If we couldn't calculate a total file size then use the number of files to calc percent
+ if (total.size === undef) {
+ total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;
+ } else {
+ total.bytesPerSec = Math.ceil(total.loaded / ((+new Date() - startTime || 1) / 1000.0));
+ total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;
+ }
+ }
+
+ // Add public methods
+ plupload.extend(this, {
+ /**
+ * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED.
+ * These states are controlled by the stop/start methods. The default value is STOPPED.
+ *
+ * @property state
+ * @type Number
+ */
+ state : plupload.STOPPED,
+
+ /**
+ * Current runtime name.
+ *
+ * @property runtime
+ * @type String
+ */
+ runtime: '',
+
+ /**
+ * Map of features that are available for the uploader runtime. Features will be filled
+ * before the init event is called, these features can then be used to alter the UI for the end user.
+ * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize.
+ *
+ * @property features
+ * @type Object
+ */
+ features : {},
+
+ /**
+ * Current upload queue, an array of File instances.
+ *
+ * @property files
+ * @type Array
+ * @see plupload.File
+ */
+ files : files,
+
+ /**
+ * Object with name/value settings.
+ *
+ * @property settings
+ * @type Object
+ */
+ settings : settings,
+
+ /**
+ * Total progess information. How many files has been uploaded, total percent etc.
+ *
+ * @property total
+ * @type plupload.QueueProgress
+ */
+ total : total,
+
+ /**
+ * Unique id for the Uploader instance.
+ *
+ * @property id
+ * @type String
+ */
+ id : plupload.guid(),
+
+ /**
+ * Initializes the Uploader instance and adds internal event listeners.
+ *
+ * @method init
+ */
+ init : function() {
+ var self = this, i, runtimeList, a, runTimeIndex = 0, items;
+
+ if (typeof(settings.preinit) == "function") {
+ settings.preinit(self);
+ } else {
+ plupload.each(settings.preinit, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+
+ settings.page_url = settings.page_url || document.location.pathname.replace(/\/[^\/]+$/g, '/');
+
+ // If url is relative force it absolute to the current page
+ if (!/^(\w+:\/\/|\/)/.test(settings.url)) {
+ settings.url = settings.page_url + settings.url;
+ }
+
+ // Convert settings
+ settings.chunk_size = plupload.parseSize(settings.chunk_size);
+ settings.max_file_size = plupload.parseSize(settings.max_file_size);
+
+ // Add files to queue
+ self.bind('FilesAdded', function(up, selected_files) {
+ var i, file, count = 0, extensionsRegExp, filters = settings.filters;
+
+ // Convert extensions to regexp
+ if (filters && filters.length) {
+ extensionsRegExp = [];
+
+ plupload.each(filters, function(filter) {
+ plupload.each(filter.extensions.split(/,/), function(ext) {
+ if (/^\s*\*\s*$/.test(ext)) {
+ extensionsRegExp.push('\\.*');
+ } else {
+ extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));
+ }
+ });
+ });
+
+ extensionsRegExp = new RegExp(extensionsRegExp.join('|') + '$', 'i');
+ }
+
+ for (i = 0; i < selected_files.length; i++) {
+ file = selected_files[i];
+ file.loaded = 0;
+ file.percent = 0;
+ file.status = plupload.QUEUED;
+
+ // Invalid file extension
+ if (extensionsRegExp && !extensionsRegExp.test(file.name)) {
+ up.trigger('Error', {
+ code : plupload.FILE_EXTENSION_ERROR,
+ message : plupload.translate('File extension error.'),
+ file : file
+ });
+
+ continue;
+ }
+
+ // Invalid file size
+ if (file.size !== undef && file.size > settings.max_file_size) {
+ up.trigger('Error', {
+ code : plupload.FILE_SIZE_ERROR,
+ message : plupload.translate('File size error.'),
+ file : file
+ });
+
+ continue;
+ }
+
+ // Add valid file to list
+ files.push(file);
+ count++;
+ }
+
+ // Only trigger QueueChanged event if any files where added
+ if (count) {
+ delay(function() {
+ self.trigger("QueueChanged");
+ self.refresh();
+ }, 1);
+ } else {
+ return false; // Stop the FilesAdded event from immediate propagation
+ }
+ });
+
+ // Generate unique target filenames
+ if (settings.unique_names) {
+ self.bind("UploadFile", function(up, file) {
+ var matches = file.name.match(/\.([^.]+)$/), ext = "tmp";
+
+ if (matches) {
+ ext = matches[1];
+ }
+
+ file.target_name = file.id + '.' + ext;
+ });
+ }
+
+ self.bind('UploadProgress', function(up, file) {
+ file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;
+ calc();
+ });
+
+ self.bind('StateChanged', function(up) {
+ if (up.state == plupload.STARTED) {
+ // Get start time to calculate bps
+ startTime = (+new Date());
+
+ } else if (up.state == plupload.STOPPED) {
+ // Reset currently uploading files
+ for (i = up.files.length - 1; i >= 0; i--) {
+ if (up.files[i].status == plupload.UPLOADING) {
+ up.files[i].status = plupload.QUEUED;
+ calc();
+ }
+ }
+ }
+ });
+
+ self.bind('QueueChanged', calc);
+
+ self.bind("Error", function(up, err) {
+ // Set failed status if an error occured on a file
+ if (err.file) {
+ err.file.status = plupload.FAILED;
+ calc();
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ if (up.state == plupload.STARTED) {
+ delay(function() {
+ uploadNext.call(self);
+ }, 1);
+ }
+ }
+ });
+
+ self.bind("FileUploaded", function(up, file) {
+ file.status = plupload.DONE;
+ file.loaded = file.size;
+ up.trigger('UploadProgress', file);
+
+ // Upload next file but detach it from the error event
+ // since other custom listeners might want to stop the queue
+ delay(function() {
+ uploadNext.call(self);
+ }, 1);
+ });
+
+ // Setup runtimeList
+ if (settings.runtimes) {
+ runtimeList = [];
+ items = settings.runtimes.split(/\s?,\s?/);
+
+ for (i = 0; i < items.length; i++) {
+ if (runtimes[items[i]]) {
+ runtimeList.push(runtimes[items[i]]);
+ }
+ }
+ } else {
+ runtimeList = runtimes;
+ }
+
+ // Call init on each runtime in sequence
+ function callNextInit() {
+ var runtime = runtimeList[runTimeIndex++], features, requiredFeatures, i;
+
+ if (runtime) {
+ features = runtime.getFeatures();
+
+ // Check if runtime supports required features
+ requiredFeatures = self.settings.required_features;
+ if (requiredFeatures) {
+ requiredFeatures = requiredFeatures.split(',');
+
+ for (i = 0; i < requiredFeatures.length; i++) {
+ // Specified feature doesn't exist
+ if (!features[requiredFeatures[i]]) {
+ callNextInit();
+ return;
+ }
+ }
+ }
+
+ // Try initializing the runtime
+ runtime.init(self, function(res) {
+ if (res && res.success) {
+ // Successful initialization
+ self.features = features;
+ self.runtime = runtime.name;
+ self.trigger('Init', {runtime : runtime.name});
+ self.trigger('PostInit');
+ self.refresh();
+ } else {
+ callNextInit();
+ }
+ });
+ } else {
+ // Trigger an init error if we run out of runtimes
+ self.trigger('Error', {
+ code : plupload.INIT_ERROR,
+ message : plupload.translate('Init error.')
+ });
+ }
+ }
+
+ callNextInit();
+
+ if (typeof(settings.init) == "function") {
+ settings.init(self);
+ } else {
+ plupload.each(settings.init, function(func, name) {
+ self.bind(name, func);
+ });
+ }
+ },
+
+ /**
+ * Refreshes the upload instance by dispatching out a refresh event to all runtimes.
+ * This would for example reposition flash/silverlight shims on the page.
+ *
+ * @method refresh
+ */
+ refresh : function() {
+ this.trigger("Refresh");
+ },
+
+ /**
+ * Starts uploading the queued files.
+ *
+ * @method start
+ */
+ start : function() {
+ if (files.length && this.state != plupload.STARTED) {
+ this.state = plupload.STARTED;
+ this.trigger("StateChanged");
+
+ uploadNext.call(this);
+ }
+ },
+
+ /**
+ * Stops the upload of the queued files.
+ *
+ * @method stop
+ */
+ stop : function() {
+ if (this.state != plupload.STOPPED) {
+ this.state = plupload.STOPPED;
+ this.trigger("CancelUpload");
+ this.trigger("StateChanged");
+ }
+ },
+
+ /**
+ * Disables/enables browse button on request.
+ *
+ * @method disableBrowse
+ * @param {Boolean} disable Whether to disable or enable (default: true)
+ */
+ disableBrowse : function() {
+ disabled = arguments[0] !== undef ? arguments[0] : true;
+ this.trigger("DisableBrowse", disabled);
+ },
+
+ /**
+ * Returns the specified file object by id.
+ *
+ * @method getFile
+ * @param {String} id File id to look for.
+ * @return {plupload.File} File object or undefined if it wasn't found;
+ */
+ getFile : function(id) {
+ var i;
+
+ for (i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === id) {
+ return files[i];
+ }
+ }
+ },
+
+ /**
+ * Removes a specific file.
+ *
+ * @method removeFile
+ * @param {plupload.File} file File to remove from queue.
+ */
+ removeFile : function(file) {
+ var i;
+
+ for (i = files.length - 1; i >= 0; i--) {
+ if (files[i].id === file.id) {
+ return this.splice(i, 1)[0];
+ }
+ }
+ },
+
+ /**
+ * Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events.
+ *
+ * @method splice
+ * @param {Number} start (Optional) Start index to remove from.
+ * @param {Number} length (Optional) Lengh of items to remove.
+ * @return {Array} Array of files that was removed.
+ */
+ splice : function(start, length) {
+ var removed;
+
+ // Splice and trigger events
+ removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length);
+
+ this.trigger("FilesRemoved", removed);
+ this.trigger("QueueChanged");
+
+ return removed;
+ },
+
+ /**
+ * Dispatches the specified event name and it's arguments to all listeners.
+ *
+ *
+ * @method trigger
+ * @param {String} name Event name to fire.
+ * @param {Object..} Multiple arguments to pass along to the listener functions.
+ */
+ trigger : function(name) {
+ var list = events[name.toLowerCase()], i, args;
+
+ // console.log(name, arguments);
+
+ if (list) {
+ // Replace name with sender in args
+ args = Array.prototype.slice.call(arguments);
+ args[0] = this;
+
+ // Dispatch event to all listeners
+ for (i = 0; i < list.length; i++) {
+ // Fire event, break chain if false is returned
+ if (list[i].func.apply(list[i].scope, args) === false) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ },
+
+ /**
+ * Check whether uploader has any listeners to the specified event.
+ *
+ * @method hasEventListener
+ * @param {String} name Event name to check for.
+ */
+ hasEventListener : function(name) {
+ return !!events[name.toLowerCase()];
+ },
+
+ /**
+ * Adds an event listener by name.
+ *
+ * @method bind
+ * @param {String} name Event name to listen for.
+ * @param {function} func Function to call ones the event gets fired.
+ * @param {Object} scope Optional scope to execute the specified function in.
+ */
+ bind : function(name, func, scope) {
+ var list;
+
+ name = name.toLowerCase();
+ list = events[name] || [];
+ list.push({func : func, scope : scope || this});
+ events[name] = list;
+ },
+
+ /**
+ * Removes the specified event listener.
+ *
+ * @method unbind
+ * @param {String} name Name of event to remove.
+ * @param {function} func Function to remove from listener.
+ */
+ unbind : function(name) {
+ name = name.toLowerCase();
+
+ var list = events[name], i, func = arguments[1];
+
+ if (list) {
+ if (func !== undef) {
+ for (i = list.length - 1; i >= 0; i--) {
+ if (list[i].func === func) {
+ list.splice(i, 1);
+ break;
+ }
+ }
+ } else {
+ list = [];
+ }
+
+ // delete event list if it has become empty
+ if (!list.length) {
+ delete events[name];
+ }
+ }
+ },
+
+ /**
+ * Removes all event listeners.
+ *
+ * @method unbindAll
+ */
+ unbindAll : function() {
+ var self = this;
+
+ plupload.each(events, function(list, name) {
+ self.unbind(name);
+ });
+ },
+
+ /**
+ * Destroys Plupload instance and cleans after itself.
+ *
+ * @method destroy
+ */
+ destroy : function() {
+ this.stop();
+ this.trigger('Destroy');
+
+ // Clean-up after uploader itself
+ this.unbindAll();
+ }
+
+ /**
+ * Fires when the current RunTime has been initialized.
+ *
+ * @event Init
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires after the init event incase you need to perform actions there.
+ *
+ * @event PostInit
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when the silverlight/flash or other shim needs to move.
+ *
+ * @event Refresh
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when the overall state is being changed for the upload queue.
+ *
+ * @event StateChanged
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires when a file is to be uploaded by the runtime.
+ *
+ * @event UploadFile
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ * Fires when just before a file is uploaded. This event enables you to override settings
+ * on the uploader instance before the file is uploaded.
+ *
+ * @event BeforeUpload
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File to be uploaded.
+ */
+
+ /**
+ * Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance.
+ *
+ * @event QueueChanged
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+
+ /**
+ * Fires while a file is being uploaded. Use this event to update the current file upload progress.
+ *
+ * @event UploadProgress
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that is currently being uploaded.
+ */
+
+ /**
+ * Fires while a file was removed from queue.
+ *
+ * @event FilesRemoved
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of files that got removed.
+ */
+
+ /**
+ * Fires while when the user selects files to upload.
+ *
+ * @event FilesAdded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of file objects that was added to queue/selected by the user.
+ */
+
+ /**
+ * Fires when a file is successfully uploaded.
+ *
+ * @event FileUploaded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that was uploaded.
+ * @param {Object} response Object with response properties.
+ */
+
+ /**
+ * Fires when file chunk is uploaded.
+ *
+ * @event ChunkUploaded
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {plupload.File} file File that the chunk was uploaded for.
+ * @param {Object} response Object with response properties.
+ */
+
+ /**
+ * Fires when all files in a queue are uploaded.
+ *
+ * @event UploadComplete
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Array} files Array of file objects that was added to queue/selected by the user.
+ */
+
+ /**
+ * Fires when a error occurs.
+ *
+ * @event Error
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ * @param {Object} error Contains code, message and sometimes file and other details.
+ */
+
+ /**
+ * Fires when destroy method is called.
+ *
+ * @event Destroy
+ * @param {plupload.Uploader} uploader Uploader instance sending the event.
+ */
+ });
+ };
+
+ /**
+ * File instance.
+ *
+ * @class plupload.File
+ * @param {String} name Name of the file.
+ * @param {Number} size File size.
+ */
+
+ /**
+ * Constructs a new file instance.
+ *
+ * @constructor
+ * @method File
+ * @param {String} id Unique file id.
+ * @param {String} name File name.
+ * @param {Number} size File size in bytes.
+ */
+ plupload.File = function(id, name, size) {
+ var self = this; // Setup alias for self to reduce code size when it's compressed
+
+ /**
+ * File id this is a globally unique id for the specific file.
+ *
+ * @property id
+ * @type String
+ */
+ self.id = id;
+
+ /**
+ * File name for example "myfile.gif".
+ *
+ * @property name
+ * @type String
+ */
+ self.name = name;
+
+ /**
+ * File size in bytes.
+ *
+ * @property size
+ * @type Number
+ */
+ self.size = size;
+
+ /**
+ * Number of bytes uploaded of the files total size.
+ *
+ * @property loaded
+ * @type Number
+ */
+ self.loaded = 0;
+
+ /**
+ * Number of percentage uploaded of the file.
+ *
+ * @property percent
+ * @type Number
+ */
+ self.percent = 0;
+
+ /**
+ * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
+ *
+ * @property status
+ * @type Number
+ * @see plupload
+ */
+ self.status = 0;
+ };
+
+ /**
+ * Runtime class gets implemented by each upload runtime.
+ *
+ * @class plupload.Runtime
+ * @static
+ */
+ plupload.Runtime = function() {
+ /**
+ * Returns a list of supported features for the runtime.
+ *
+ * @return {Object} Name/value object with supported features.
+ */
+ this.getFeatures = function() {
+ };
+
+ /**
+ * Initializes the upload runtime. This method should add necessary items to the DOM and register events needed for operation.
+ *
+ * @method init
+ * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized.
+ * @param {function} callback Callback function to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true.
+ */
+ this.init = function(uploader, callback) {
+ };
+ };
+
+ /**
+ * Runtime class gets implemented by each upload runtime.
+ *
+ * @class plupload.QueueProgress
+ */
+
+ /**
+ * Constructs a queue progress.
+ *
+ * @constructor
+ * @method QueueProgress
+ */
+ plupload.QueueProgress = function() {
+ var self = this; // Setup alias for self to reduce code size when it's compressed
+
+ /**
+ * Total queue file size.
+ *
+ * @property size
+ * @type Number
+ */
+ self.size = 0;
+
+ /**
+ * Total bytes uploaded.
+ *
+ * @property loaded
+ * @type Number
+ */
+ self.loaded = 0;
+
+ /**
+ * Number of files uploaded.
+ *
+ * @property uploaded
+ * @type Number
+ */
+ self.uploaded = 0;
+
+ /**
+ * Number of files failed to upload.
+ *
+ * @property failed
+ * @type Number
+ */
+ self.failed = 0;
+
+ /**
+ * Number of files yet to be uploaded.
+ *
+ * @property queued
+ * @type Number
+ */
+ self.queued = 0;
+
+ /**
+ * Total percent of the uploaded bytes.
+ *
+ * @property percent
+ * @type Number
+ */
+ self.percent = 0;
+
+ /**
+ * Bytes uploaded per second.
+ *
+ * @property bytesPerSec
+ * @type Number
+ */
+ self.bytesPerSec = 0;
+
+ /**
+ * Resets the progress to it's initial values.
+ *
+ * @method reset
+ */
+ self.reset = function() {
+ self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0;
+ };
+ };
+
+ // Create runtimes namespace
+ plupload.runtimes = {};
+
+ // Expose plupload namespace
+ window.plupload = plupload;
+})();