Newer
Older
Daniel Vincent Grippi
a validé
/**
* http://github.com/valums/file-uploader
*
* Multiple file upload component with progress-bar, drag-and-drop.
* © 2010 Andrew Valums ( andrew(at)valums.com )
*
Daniel Vincent Grippi
a validé
* Licensed under GNU GPL 2 or later, see license.txt.
*/
//
// Helper functions
//
var qq = qq || {};
/**
* Adds all missing properties from second obj to first obj
*/
qq.extend = function(first, second){
for (var prop in second){
first[prop] = second[prop];
}
};
/**
* Searches for a given element in the array, returns -1 if it is not present.
* @param {Number} [from] The index at which to begin the search
*/
qq.indexOf = function(arr, elt, from){
var len = arr.length;
for (; from < len; from++){
if (from in arr && arr[from] === elt){
}
return -1;
};
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
qq.getUniqueId = (function(){
var id = 0;
return function(){ return id++; };
})();
//
// Events
qq.attach = function(element, type, fn){
if (element.addEventListener){
element.addEventListener(type, fn, false);
} else if (element.attachEvent){
element.attachEvent('on' + type, fn);
}
};
qq.detach = function(element, type, fn){
if (element.removeEventListener){
element.removeEventListener(type, fn, false);
} else if (element.attachEvent){
element.detachEvent('on' + type, fn);
}
};
qq.preventDefault = function(e){
if (e.preventDefault){
e.preventDefault();
} else{
e.returnValue = false;
}
};
//
// Node manipulations
/**
* Insert node a before node b.
*/
qq.insertBefore = function(a, b){
b.parentNode.insertBefore(a, b);
};
qq.remove = function(element){
element.parentNode.removeChild(element);
};
qq.contains = function(parent, descendant){
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
if (parent.contains){
return parent.contains(descendant);
} else {
return !!(descendant.compareDocumentPosition(parent) & 8);
}
};
/**
* Creates and returns element from html string
* Uses innerHTML to create an element
*/
qq.toElement = (function(){
var div = document.createElement('div');
return function(html){
div.innerHTML = html;
var element = div.firstChild;
div.removeChild(element);
return element;
};
})();
//
// Node properties and attributes
/**
* Sets styles for an element.
* Fixes opacity in IE6-8.
*/
qq.css = function(element, styles){
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){
styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')';
}
}
qq.extend(element.style, styles);
};
qq.hasClass = function(element, name){
var re = new RegExp('(^| )' + name + '( |$)');
return re.test(element.className);
};
qq.addClass = function(element, name){
if (!qq.hasClass(element, name)){
element.className += ' ' + name;
}
};
qq.removeClass = function(element, name){
var re = new RegExp('(^| )' + name + '( |$)');
element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, "");
};
qq.setText = function(element, text){
element.innerText = text;
element.textContent = text;
};
//
// Selecting elements
qq.children = function(element){
var children = [],
child = element.firstChild;
while (child){
if (child.nodeType == 1){
children.push(child);
}
child = child.nextSibling;
}
return children;
};
qq.getByClass = function(element, className){
if (element.querySelectorAll){
return element.querySelectorAll('.' + className);
}
var result = [];
var candidates = element.getElementsByTagName("*");
var len = candidates.length;
for (var i = 0; i < len; i++){
if (qq.hasClass(candidates[i], className)){
result.push(candidates[i]);
}
}
return result;
};
/**
* obj2url() takes a json-object as argument and generates
* a querystring. pretty much like jQuery.param()
*
* how to use:
*
* `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`
*
* will result in:
*
* `http://any.url/upload?otherParam=value&a=b&c=d`
*
* @param Object JSON-Object
* @param String current querystring-part
* @return String encoded querystring
*/
qq.obj2url = function(obj, temp, prefixDone){
var uristrings = [],
prefix = '&',
add = function(nextObj, i){
var nextTemp = temp
? (/\[\]$/.test(temp)) // prevent double-encoding
? temp
: temp+'['+i+']'
: i;
if ((nextTemp != 'undefined') && (i != 'undefined')) {
(typeof nextObj === 'object')
? qq.obj2url(nextObj, nextTemp, true)
: (Object.prototype.toString.call(nextObj) === '[object Function]')
? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj())
: encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj)
};
if (!prefixDone && temp) {
prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?';
uristrings.push(temp);
uristrings.push(qq.obj2url(obj));
} else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) {
// we wont use a for-in-loop on an array (performance)
for (var i = 0, len = obj.length; i < len; ++i){
add(obj[i], i);
}
} else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){
// for anything else but a scalar, we will use for-in-loop
for (var i in obj){
add(obj[i], i);
}
} else {
uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj));
}
return uristrings.join(prefix)
.replace(/^&/, '')
.replace(/%20/g, '+');
};
//
//
// Uploader Classes
//
//
var qq = qq || {};
* Creates upload button, validates upload, but doesn't create file list or dd.
*/
qq.FileUploaderBasic = function(o){
this._options = {
// set to true to see the server response
debug: false,
action: '/server/upload',
params: {},
button: null,
multiple: true,
maxConnections: 3,
// validation
allowedExtensions: [],
sizeLimit: 0,
minSizeLimit: 0,
// events
// return false to cancel submit
onSubmit: function(id, fileName){},
onProgress: function(id, fileName, loaded, total){},
onComplete: function(id, fileName, responseJSON){},
onAllComplete: function(completed_files){},
// messages
messages: {
typeError: "{file} has invalid extension. Only {extensions} are allowed.",
sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
emptyError: "{file} is empty, please select files again without it.",
onLeave: "The files are being uploaded, if you leave now the upload will be cancelled."
},
showMessage: function(message){
alert(message);
}
// number of files being uploaded
this._filesInProgress = 0;
this._handler = this._createUploadHandler();
if (this._options.button){
this._button = this._createUploadButton(this._options.button);
}
this._preventLeaveInProgress();
qq.FileUploaderBasic.prototype = {
setParams: function(params){
this._options.params = params;
},
getInProgress: function(){
return this._filesInProgress;
},
_createUploadButton: function(element){
var self = this;
return new qq.UploadButton({
element: element,
multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),
onChange: function(input){
self._onInputChange(input);
}
});
},
_createUploadHandler: function(){
var self = this,
handlerClass;
if(qq.UploadHandlerXhr.isSupported()){
handlerClass = 'UploadHandlerXhr';
} else {
handlerClass = 'UploadHandlerForm';
}
var handler = new qq[handlerClass]({
debug: this._options.debug,
action: this._options.action,
maxConnections: this._options.maxConnections,
onProgress: function(id, fileName, loaded, total){
self._onProgress(id, fileName, loaded, total);
self._options.onProgress(id, fileName, loaded, total);
},
onComplete: function(id, fileName, result){
self._onComplete(id, fileName, result);
self._options.onComplete(id, fileName, result);
},
onAllComplete: function(completed_files){
self._options.onAllComplete(completed_files);
},
onCancel: function(id, fileName){
self._onCancel(id, fileName);
self._options.onCancel(id, fileName);
}
});
return handler;
},
_preventLeaveInProgress: function(){
var self = this;
qq.attach(window, 'beforeunload', function(e){
if (!self._filesInProgress){return;}
var e = e || window.event;
// for ie, ff
e.returnValue = self._options.messages.onLeave;
// for webkit
return self._options.messages.onLeave;
});
},
this._filesInProgress++;
_onProgress: function(id, fileName, loaded, total){
},
_onComplete: function(id, fileName, result){
this._filesInProgress--;
if (result.error){
this._options.showMessage(result.error);
}
this._filesInProgress--;
if (this._handler instanceof qq.UploadHandlerXhr){
this._uploadFileList(input.files);
} else {
if (this._validateFile(input)){
this._uploadFile(input);
}
}
this._button.reset();
},
_uploadFileList: function(files){
for (var i=0; i<files.length; i++){
if ( !this._validateFile(files[i])){
return;
}
this._uploadFile(files[i]);
}
},
_uploadFile: function(fileContainer){
var id = this._handler.add(fileContainer);
var fileName = this._handler.getName(id);
if (this._options.onSubmit(id, fileName) !== false){
this._onSubmit(id, fileName);
this._handler.upload(id, this._options.params);
}
},
_validateFile: function(file){
var name, size;
// it is a file input
// get input value and remove path to normalize
name = file.value.replace(/.*(\/|\\)/, "");
} else {
// fix missing properties in Safari
name = file.fileName != null ? file.fileName : file.name;
size = file.fileSize != null ? file.fileSize : file.size;
}
if (! this._isAllowedExtension(name)){
this._error('typeError', name);
return false;
} else if (size === 0){
this._error('emptyError', name);
return false;
} else if (size && this._options.sizeLimit && size > this._options.sizeLimit){
this._error('sizeError', name);
return false;
} else if (size && size < this._options.minSizeLimit){
this._error('minSizeError', name);
return false;
return true;
var message = this._options.messages[code];
function r(name, replacement){ message = message.replace(name, replacement); }
r('{file}', this._formatFileName(fileName));
r('{extensions}', this._options.allowedExtensions.join(', '));
r('{sizeLimit}', this._formatSize(this._options.sizeLimit));
r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit));
this._options.showMessage(message);
},
_formatFileName: function(name){
if (name.length > 33){
name = name.slice(0, 19) + '...' + name.slice(-13);
}
return name;
},
_isAllowedExtension: function(fileName){
var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : '';
var allowed = this._options.allowedExtensions;
if (!allowed.length){return true;}
if (allowed[i].toLowerCase() == ext){ return true;}
},
var i = -1;
i++;
return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];
Daniel Vincent Grippi
a validé
/**
* Class that creates upload widget with drag-and-drop and file list
* @inherits qq.FileUploaderBasic
Daniel Vincent Grippi
a validé
*/
qq.FileUploader = function(o){
// call parent constructor
qq.FileUploaderBasic.apply(this, arguments);
// additional options
Daniel Vincent Grippi
a validé
element: null,
// if set, will be used instead of qq-upload-list in template
listElement: null,
template: '<div class="qq-uploader">' +
'<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
'<div class="qq-upload-button">Upload a file</div>' +
'<ul class="qq-upload-list"></ul>' +
Daniel Vincent Grippi
a validé
'</div>',
// template for one item in file list
fileTemplate: '<li>' +
'<span class="qq-upload-file"></span>' +
'<span class="qq-upload-spinner"></span>' +
'<span class="qq-upload-size"></span>' +
'<a class="qq-upload-cancel" href="#">Cancel</a>' +
'<span class="qq-upload-failed-text">Failed</span>' +
'</li>',
Daniel Vincent Grippi
a validé
classes: {
// used to get elements from templates
button: 'qq-upload-button',
drop: 'qq-upload-drop-area',
dropActive: 'qq-upload-drop-area-active',
list: 'qq-upload-list',
Daniel Vincent Grippi
a validé
file: 'qq-upload-file',
spinner: 'qq-upload-spinner',
size: 'qq-upload-size',
cancel: 'qq-upload-cancel',
// added to list item when upload completes
// used in css to hide progress spinner
success: 'qq-upload-success',
fail: 'qq-upload-fail'
}
// overwrite options with user supplied
qq.extend(this._options, o);
Daniel Vincent Grippi
a validé
this._element.innerHTML = this._options.template;
this._listElement = this._options.listElement || this._find(this._element, 'list');
Daniel Vincent Grippi
a validé
this._classes = this._options.classes;
this._button = this._createUploadButton(this._find(this._element, 'button'));
Daniel Vincent Grippi
a validé
this._bindCancelEvent();
this._setupDragDrop();
};
// inherit from Basic Uploader
qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype);
qq.extend(qq.FileUploader.prototype, {
Daniel Vincent Grippi
a validé
/**
* Gets one of the elements listed in this._options.classes
**/
_find: function(parent, type){
var element = qq.getByClass(parent, this._options.classes[type])[0];
Daniel Vincent Grippi
a validé
if (!element){
throw new Error('element not found ' + type);
}
Daniel Vincent Grippi
a validé
return element;
},
_setupDragDrop: function(){
var self = this,
dropArea = this._find(this._element, 'drop');
Daniel Vincent Grippi
a validé
var dz = new qq.UploadDropZone({
element: dropArea,
onEnter: function(e){
qq.addClass(dropArea, self._classes.dropActive);
e.stopPropagation();
},
onLeave: function(e){
e.stopPropagation();
},
onLeaveNotDescendants: function(e){
qq.removeClass(dropArea, self._classes.dropActive);
Daniel Vincent Grippi
a validé
},
onDrop: function(e){
dropArea.style.display = 'none';
qq.removeClass(dropArea, self._classes.dropActive);
self._uploadFileList(e.dataTransfer.files);
Daniel Vincent Grippi
a validé
}
});
Daniel Vincent Grippi
a validé
dropArea.style.display = 'none';
qq.attach(document, 'dragenter', function(e){
if (!dz._isValidFileDrag(e)) return;
dropArea.style.display = 'block';
});
Daniel Vincent Grippi
a validé
qq.attach(document, 'dragleave', function(e){
if (!dz._isValidFileDrag(e)) return;
Daniel Vincent Grippi
a validé
var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
// only fire when leaving document out
if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){
dropArea.style.display = 'none';
Daniel Vincent Grippi
a validé
}
});
Daniel Vincent Grippi
a validé
},
_onSubmit: function(id, fileName){
qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments);
this._addToList(id, fileName);
Daniel Vincent Grippi
a validé
},
_onProgress: function(id, fileName, loaded, total){
qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments);
Daniel Vincent Grippi
a validé
var item = this._getItemByFileId(id);
Daniel Vincent Grippi
a validé
size.style.display = 'inline';
var text;
Daniel Vincent Grippi
a validé
if (loaded != total){
text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total);
} else {
Daniel Vincent Grippi
a validé
text = this._formatSize(total);
}
qq.setText(size, text);
Daniel Vincent Grippi
a validé
},
_onComplete: function(id, fileName, result){
qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments);
// mark completed
var item = this._getItemByFileId(id);
qq.remove(this._find(item, 'cancel'));
qq.remove(this._find(item, 'spinner'));
qq.addClass(item, this._classes.success);
} else {
qq.addClass(item, this._classes.fail);
}
var item = qq.toElement(this._options.fileTemplate);
var fileElement = this._find(item, 'file');
qq.setText(fileElement, this._formatFileName(fileName));
this._find(item, 'size').style.display = 'none';
Daniel Vincent Grippi
a validé
},
_getItemByFileId: function(id){
var item = this._listElement.firstChild;
// there can't be txt nodes in dynamically created list
// and we can use nextSibling
while (item){
if (item.qqFileId == id) return item;
Daniel Vincent Grippi
a validé
item = item.nextSibling;
}
Daniel Vincent Grippi
a validé
},
/**
* delegate click event for cancel link
Daniel Vincent Grippi
a validé
**/
_bindCancelEvent: function(){
var self = this,
list = this._listElement;
qq.attach(list, 'click', function(e){
Daniel Vincent Grippi
a validé
e = e || window.event;
var target = e.target || e.srcElement;
if (qq.hasClass(target, self._classes.cancel)){
Daniel Vincent Grippi
a validé
qq.preventDefault(e);
Daniel Vincent Grippi
a validé
var item = target.parentNode;
self._handler.cancel(item.qqFileId);
qq.remove(item);
}
});
}
Daniel Vincent Grippi
a validé
qq.UploadDropZone = function(o){
this._options = {
element: null,
Daniel Vincent Grippi
a validé
onEnter: function(e){},
onLeave: function(e){},
// is not fired when leaving element by hovering descendants
onLeaveNotDescendants: function(e){},
onDrop: function(e){}
Daniel Vincent Grippi
a validé
};
qq.extend(this._options, o);
Daniel Vincent Grippi
a validé
this._element = this._options.element;
Daniel Vincent Grippi
a validé
this._disableDropOutside();
this._attachEvents();
Daniel Vincent Grippi
a validé
};
qq.UploadDropZone.prototype = {
_disableDropOutside: function(e){
// run only once for all instances
if (!qq.UploadDropZone.dropOutsideDisabled ){
qq.attach(document, 'dragover', function(e){
if (e.dataTransfer){
e.dataTransfer.dropEffect = 'none';
e.preventDefault();
}
Daniel Vincent Grippi
a validé
});
qq.UploadDropZone.dropOutsideDisabled = true;
}
Daniel Vincent Grippi
a validé
},
_attachEvents: function(){
var self = this;
Daniel Vincent Grippi
a validé
qq.attach(self._element, 'dragover', function(e){
if (!self._isValidFileDrag(e)) return;
Daniel Vincent Grippi
a validé
var effect = e.dataTransfer.effectAllowed;
if (effect == 'move' || effect == 'linkMove'){
e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed)
} else {
Daniel Vincent Grippi
a validé
e.dataTransfer.dropEffect = 'copy'; // for Chrome
}
Daniel Vincent Grippi
a validé
e.stopPropagation();
e.preventDefault();
Daniel Vincent Grippi
a validé
});
Daniel Vincent Grippi
a validé
qq.attach(self._element, 'dragenter', function(e){
if (!self._isValidFileDrag(e)) return;
Daniel Vincent Grippi
a validé
self._options.onEnter(e);
});
Daniel Vincent Grippi
a validé
qq.attach(self._element, 'dragleave', function(e){
if (!self._isValidFileDrag(e)) return;
Daniel Vincent Grippi
a validé
self._options.onLeave(e);
var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);
Daniel Vincent Grippi
a validé
// do not fire when moving a mouse over a descendant
if (qq.contains(this, relatedTarget)) return;
self._options.onLeaveNotDescendants(e);
Daniel Vincent Grippi
a validé
});
Daniel Vincent Grippi
a validé
qq.attach(self._element, 'drop', function(e){
if (!self._isValidFileDrag(e)) return;
Daniel Vincent Grippi
a validé
e.preventDefault();
self._options.onDrop(e);
});
Daniel Vincent Grippi
a validé
},
_isValidFileDrag: function(e){
var dt = e.dataTransfer,
// do not check dt.types.contains in webkit, because it crashes safari 4
isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1;
Daniel Vincent Grippi
a validé
// dt.effectAllowed is none in Safari 5
// dt.types.contains check is for firefox
return dt && dt.effectAllowed != 'none' &&
Daniel Vincent Grippi
a validé
(dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files')));
}
};
Daniel Vincent Grippi
a validé
qq.UploadButton = function(o){
this._options = {
element: null,
// if set to true adds multiple attribute to file input
Daniel Vincent Grippi
a validé
multiple: false,
// name attribute of file input
name: 'file',
onChange: function(input){},
hoverClass: 'qq-upload-button-hover',
focusClass: 'qq-upload-button-focus'
Daniel Vincent Grippi
a validé
};
Daniel Vincent Grippi
a validé
qq.extend(this._options, o);
Daniel Vincent Grippi
a validé
this._element = this._options.element;
Daniel Vincent Grippi
a validé
// make button suitable container for input
qq.css(this._element, {
position: 'relative',
overflow: 'hidden',
// Make sure browse button is in the right side
// in Internet Explorer
direction: 'ltr'
});
Daniel Vincent Grippi
a validé
this._input = this._createInput();
};
qq.UploadButton.prototype = {
/* returns file input element */
Daniel Vincent Grippi
a validé
getInput: function(){
return this._input;
},
/* cleans/recreates the file input */
reset: function(){
if (this._input.parentNode){
qq.remove(this._input);
}
Daniel Vincent Grippi
a validé
qq.removeClass(this._element, this._options.focusClass);
this._input = this._createInput();
},
_createInput: function(){
Daniel Vincent Grippi
a validé
var input = document.createElement("input");
Daniel Vincent Grippi
a validé
if (this._options.multiple){
input.setAttribute("multiple", "multiple");
}
Daniel Vincent Grippi
a validé
input.setAttribute("type", "file");
input.setAttribute("name", this._options.name);
Daniel Vincent Grippi
a validé
qq.css(input, {
position: 'absolute',
// in Opera only 'browse' button
// is clickable and it is located at
// the right side of the input
right: 0,
top: 0,
//fontFamily: 'Arial',
Daniel Vincent Grippi
a validé
// 4 persons reported this, the max values that worked for them were 243, 236, 236, 118
//fontSize: '118px',
Daniel Vincent Grippi
a validé
margin: 0,
padding: 0,
opacity: 0
});
Daniel Vincent Grippi
a validé
this._element.appendChild(input);
var self = this;
qq.attach(input, 'change', function(){
self._options.onChange(input);
});
Daniel Vincent Grippi
a validé
qq.attach(input, 'mouseover', function(){
qq.addClass(self._element, self._options.hoverClass);
});
qq.attach(input, 'mouseout', function(){
qq.removeClass(self._element, self._options.hoverClass);
});
qq.attach(input, 'focus', function(){
qq.addClass(self._element, self._options.focusClass);
});
qq.attach(input, 'blur', function(){
qq.removeClass(self._element, self._options.focusClass);
});
// IE and Opera, unfortunately have 2 tab stops on file input
// which is unacceptable in our case, disable keyboard access
if (window.attachEvent){
// it is IE or Opera
input.setAttribute('tabIndex', "-1");
}
return input;
}
Daniel Vincent Grippi
a validé
};
/**
* Class for uploading files, uploading itself is handled by child classes
Daniel Vincent Grippi
a validé
*/
Daniel Vincent Grippi
a validé
this._options = {
// maximum number of concurrent uploads
maxConnections: 999,
onProgress: function(id, fileName, loaded, total){},
onComplete: function(id, fileName, response){},
onAllComplete: function(completed_files){},
Daniel Vincent Grippi
a validé
};
qq.extend(this._options, o);
this._queue = [];
// params for files in queue
this._params = [];
this._completed_files = [];
Daniel Vincent Grippi
a validé
};
qq.UploadHandlerAbstract.prototype = {
log: function(str){
if (this._options.debug && window.console) console.log('[uploader] ' + str);
Daniel Vincent Grippi
a validé
/**
* Adds file or file input to the queue
* @returns id
**/
add: function(file){},
/**
* Sends the file identified by id and additional query params to the server
*/
upload: function(id, params){
var len = this._queue.push(id);
var copy = {};
this._params[id] = copy;
if (len <= this._options.maxConnections){
this._upload(id, this._params[id]);
}
},
/**
* Cancels file upload by id
*/
cancel: function(id){
this._cancel(id);
this._dequeue(id);
},
/**
* Cancells all uploads
*/
cancelAll: function(){
for (var i=0; i<this._queue.length; i++){
this._cancel(this._queue[i]);
}
this._queue = [];
},
/**
* Returns name of the file identified by id
*/
getName: function(id){},
/**
* Returns size of the file identified by id
*/
getSize: function(id){},
/**
* Returns id of files being uploaded or
* waiting for their turn
*/
getQueue: function(){
return this._queue;
},
/**
* Actual upload method
*/
_upload: function(id){},
/**
* Actual cancel method
*/
_cancel: function(id){},
/**
* Removes element from queue, starts upload of next
*/
_dequeue: function(id){
var i = qq.indexOf(this._queue, id);
this._queue.splice(i, 1);
if (this._queue.length >= max){
var nextId = this._queue[max-1];
this._upload(nextId, this._params[nextId]);
}
if (this._queue.length == 0){
this._onAllComplete();
}
},
_onAllComplete: function(){
this._options.onAllComplete(this._completed_files);
}
};
/**
* Class for uploading files using form and iframe
* @inherits qq.UploadHandlerAbstract
*/
qq.UploadHandlerForm = function(o){
qq.UploadHandlerAbstract.apply(this, arguments);
this._inputs = {};
};
// @inherits qq.UploadHandlerAbstract
qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype);
qq.extend(qq.UploadHandlerForm.prototype, {
Daniel Vincent Grippi
a validé
add: function(fileInput){
fileInput.setAttribute('name', 'qqfile');
var id = 'qq-upload-handler-iframe' + qq.getUniqueId();
Daniel Vincent Grippi
a validé
this._inputs[id] = fileInput;
Daniel Vincent Grippi
a validé
// remove file input from DOM
if (fileInput.parentNode){
qq.remove(fileInput);
}
Daniel Vincent Grippi
a validé
return id;
},
getName: function(id){
// get input value and remove path to normalize
return this._inputs[id].value.replace(/.*(\/|\\)/, "");
},
_cancel: function(id){
this._options.onCancel(id, this.getName(id));
delete this._inputs[id];