engine/public/javascripts/admin/plugins/plupload/src/plupload.js

1333 lines
35 KiB
JavaScript
Raw Normal View History

2010-09-15 00:19:34 +00:00
/**
* 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 */
(function() {
var count = 0, runtimes = [], i18n = {}, mimes = {},
xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'},
xmlEncodeRegExp = /[<>&\"\']/g, undef;
// 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,docx pptx xlsx," +
"audio/mpeg,mpga mpega mp2 mp3," +
"audio/x-wav,wav," +
"image/bmp,bmp," +
"image/gif,gif," +
"image/jpeg,jpeg jpg jpe," +
"image/png,png," +
"image/svg+xml,svg svgz," +
"image/tiff,tiff tif," +
"text/html,htm html xhtml," +
"text/rtf,rtf," +
"video/mpeg,mpeg mpg mpe," +
"video/quicktime,qt mov," +
"video/x-flv,flv," +
"video/vnd.rn-realvideo,rv," +
"text/plain,asc txt text diff log," +
"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 = {
/**
* 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 to 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 : -700,
/**
* Mime type lookup table.
*
* @property mimeTypes
* @type Object
* @final
*/
mimeTypes : mimes,
/**
* 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) {
return plupload.translate('N/A');
}
// 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.getBoundingClientRect && (navigator.userAgent.indexOf('MSIE') > 0 && 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.clientWidth || node.offsetWidth,
h : node.clientHeight || node.offsetHeight
};
},
/**
* 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;
},
/**
* 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.
* @reutrn {String} Translated string or the input string if it wasn't found.
*/
translate : function(str) {
return i18n[str] || str;
},
/**
* Adds an event handler to the specified object.
*
* @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.
*/
addEvent : function(obj, name, callback) {
if (obj.attachEvent) {
obj.attachEvent('on' + name, function() {
var evt = window.event;
if (!evt.target) {
evt.target = evt.srcElement;
}
evt.preventDefault = preventDefault;
evt.stopPropagation = stopPropagation;
callback(evt);
});
} else if (obj.addEventListener) {
obj.addEventListener(name, callback, false);
}
}
};
/**
* 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 = [], fileIndex, startTime;
// 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;
if (this.state == plupload.STARTED && fileIndex < files.length) {
file = files[fileIndex++];
if (file.status == plupload.QUEUED) {
this.trigger('BeforeUpload', file);
this.trigger("UploadFile", file);
} else {
uploadNext.call(this);
}
} else {
this.stop();
}
}
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,
/**
* 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;
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) {
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 : '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 : '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) {
self.trigger("QueueChanged");
self.refresh();
}
});
// 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) {
if (file.status == plupload.QUEUED) {
file.status = plupload.UPLOADING;
}
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());
}
});
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
window.setTimeout(function() {
uploadNext.call(self);
});
}
});
self.bind("FileUploaded", function(up, file) {
file.status = plupload.DONE;
file.loaded = file.size;
up.trigger('UploadProgress', file);
uploadNext.call(self);
});
// 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.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 : 'Init error.'
});
}
}
callNextInit();
},
/**
* 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 (this.state != plupload.STARTED) {
fileIndex = 0;
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("StateChanged");
}
},
/**
* 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, 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;
},
/**
* 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, func) {
var list = events[name.toLowerCase()], i;
if (list) {
for (i = list.length - 1; i >= 0; i--) {
if (list[i].func === func) {
list.splice(i, 1);
}
}
}
}
/**
* 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 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.
*/
});
};
/**
* 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;
})();