diff --git a/app/views/photos/_new_photo.haml b/app/views/photos/_new_photo.haml index b99263a32..30887ff46 100644 --- a/app/views/photos/_new_photo.haml +++ b/app/views/photos/_new_photo.haml @@ -30,14 +30,14 @@ onSubmit: function(id, fileName){ $('#file-upload').addClass("loading"); $('#publisher').find("input[type='submit']").attr('disabled','disabled'); - $("#publisher .options_and_submit").fadeIn(50); + $("div.mention_helper").fadeTo(100, 0, function() { + $("#publisher .options_and_submit, #fileInfo").fadeIn(50); + }); $("#publisher_spinner").fadeIn(100); }, - onComplete: function(id, fileName, responseJSON){ - $('#fileInfo').text(fileName + ' completed').fadeOut(2000); - $("#publisher_spinner").fadeOut(100); - $('#file-upload').removeClass("loading"); + onComplete: function(id, fileName, responseJSON) { + $('#fileInfo').text(fileName + ' completed'); var id = responseJSON.data.photo.id; var url = responseJSON.data.photo.thumb_small; @@ -70,6 +70,15 @@ } }); }); + + }, + + onAllComplete: function(completed_files){ + $('#fileInfo').delay(1800).fadeOut(200, function() { + $("div.mention_helper").fadeTo(100, 100); + }); + $("#publisher_spinner").fadeOut(100); + $('#file-upload').removeClass("loading"); } }); diff --git a/app/views/shared/_publisher.html.haml b/app/views/shared/_publisher.html.haml index a0fdabcc9..5bffab311 100644 --- a/app/views/shared/_publisher.html.haml +++ b/app/views/shared/_publisher.html.haml @@ -37,7 +37,7 @@ = hidden_field_tag 'aspect_ids[]', aspect_id.to_s .options_and_submit - %div + %div.mention_helper %i= t('.mention_helper_text') .right diff --git a/public/javascripts/vendor/fileuploader.js b/public/javascripts/vendor/fileuploader.js index 7da173107..3d859764a 100644 --- a/public/javascripts/vendor/fileuploader.js +++ b/public/javascripts/vendor/fileuploader.js @@ -1,11 +1,11 @@ /** * http://github.com/valums/file-uploader - * - * Multiple file upload component with progress-bar, drag-and-drop. - * © 2010 Andrew Valums ( andrew(at)valums.com ) - * + * + * Multiple file upload component with progress-bar, drag-and-drop. + * © 2010 Andrew Valums ( andrew(at)valums.com ) + * * Licensed under GNU GPL 2 or later, see license.txt. - */ + */ // // Helper functions @@ -15,12 +15,12 @@ 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. @@ -28,20 +28,20 @@ qq.extend = function(first, second){ */ qq.indexOf = function(arr, elt, from){ if (arr.indexOf) return arr.indexOf(elt, from); - - from = from || 0; - var len = arr.length; - - if (from < 0) from += len; - for (; from < len; from++){ - if (from in arr && arr[from] === elt){ + from = from || 0; + var len = arr.length; + + if (from < 0) from += len; + + for (; from < len; from++){ + if (from in arr && arr[from] === elt){ return from; } - } - return -1; -}; - + } + return -1; +}; + qq.getUniqueId = (function(){ var id = 0; return function(){ return id++; }; @@ -86,10 +86,10 @@ qq.remove = function(element){ element.parentNode.removeChild(element); }; -qq.contains = function(parent, descendant){ +qq.contains = function(parent, descendant){ // compareposition returns false in this case if (parent == descendant) return true; - + if (parent.contains){ return parent.contains(descendant); } else { @@ -181,7 +181,7 @@ qq.getByClass = function(element, className){ /** * 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');` @@ -198,21 +198,21 @@ qq.obj2url = function(obj, temp, prefixDone){ var uristrings = [], prefix = '&', add = function(nextObj, i){ - var nextTemp = temp + var nextTemp = temp ? (/\[\]$/.test(temp)) // prevent double-encoding ? temp : temp+'['+i+']' : i; - if ((nextTemp != 'undefined') && (i != 'undefined')) { + if ((nextTemp != 'undefined') && (i != 'undefined')) { uristrings.push( - (typeof nextObj === 'object') + (typeof nextObj === 'object') ? qq.obj2url(nextObj, nextTemp, true) : (Object.prototype.toString.call(nextObj) === '[object Function]') ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj()) - : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) + : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) ); } - }; + }; if (!prefixDone && temp) { prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?'; @@ -234,7 +234,7 @@ qq.obj2url = function(obj, temp, prefixDone){ return uristrings.join(prefix) .replace(/^&/, '') - .replace(/%20/g, '+'); + .replace(/%20/g, '+'); }; // @@ -244,9 +244,9 @@ qq.obj2url = function(obj, temp, prefixDone){ // var qq = qq || {}; - + /** - * Creates upload button, validates upload, but doesn't create file list or dd. + * Creates upload button, validates upload, but doesn't create file list or dd. */ qq.FileUploaderBasic = function(o){ this._options = { @@ -257,81 +257,85 @@ qq.FileUploaderBasic = function(o){ button: null, multiple: true, maxConnections: 3, - // validation - allowedExtensions: [], - sizeLimit: 0, - minSizeLimit: 0, + // 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){}, onCancel: function(id, fileName){}, - // messages + // 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." + onLeave: "The files are being uploaded, if you leave now the upload will be cancelled." }, showMessage: function(message){ alert(message); - } + } }; qq.extend(this._options, o); - + // number of files being uploaded this._filesInProgress = 0; - this._handler = this._createUploadHandler(); - - if (this._options.button){ + this._handler = this._createUploadHandler(); + + if (this._options.button){ this._button = this._createUploadButton(this._options.button); } - - this._preventLeaveInProgress(); + + this._preventLeaveInProgress(); }; - + qq.FileUploaderBasic.prototype = { setParams: function(params){ this._options.params = params; }, getInProgress: function(){ - return this._filesInProgress; + 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'; + 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){ + 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); - }, + 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); @@ -339,69 +343,69 @@ qq.FileUploaderBasic.prototype = { }); 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; - }); - }, - _onSubmit: function(id, fileName){ - this._filesInProgress++; + return self._options.messages.onLeave; + }); }, - _onProgress: function(id, fileName, loaded, total){ + _onSubmit: function(id, fileName){ + this._filesInProgress++; + }, + _onProgress: function(id, fileName, loaded, total){ }, _onComplete: function(id, fileName, result){ - this._filesInProgress--; + this._filesInProgress--; if (result.error){ this._options.showMessage(result.error); - } + } }, _onCancel: function(id, fileName){ - this._filesInProgress--; + this._filesInProgress--; }, _onInputChange: function(input){ - if (this._handler instanceof qq.UploadHandlerXhr){ - this._uploadFileList(input.files); - } else { - if (this._validateFile(input)){ - this._uploadFile(input); - } - } - this._button.reset(); - }, + 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 this._options.sizeLimit){ + + } 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 false; } - - return true; + + return true; }, _error: function(code, fileName){ - var message = this._options.messages[code]; + var message = this._options.messages[code]; function r(name, replacement){ message = message.replace(name, replacement); } - - r('{file}', this._formatFileName(fileName)); + + 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); + + this._options.showMessage(message); }, _formatFileName: function(name){ if (name.length > 33){ - name = name.slice(0, 19) + '...' + name.slice(-13); + 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.length){return true;} + for (var i=0; i 99); - - return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; + + return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; } }; - - + + /** * Class that creates upload widget with drag-and-drop and file list * @inherits qq.FileUploaderBasic @@ -477,17 +481,17 @@ qq.FileUploaderBasic.prototype = { qq.FileUploader = function(o){ // call parent constructor qq.FileUploaderBasic.apply(this, arguments); - - // additional options + + // additional options qq.extend(this._options, { element: null, // if set, will be used instead of qq-upload-list in template listElement: null, - - template: '
' + + + template: '
' + '
Drop files here to upload
' + '
Upload a file
' + - '
    ' + + '
      ' + '
      ', // template for one item in file list @@ -497,15 +501,15 @@ qq.FileUploader = function(o){ '' + 'Cancel' + 'Failed' + - '', - + '', + 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', - + file: 'qq-upload-file', spinner: 'qq-upload-spinner', size: 'qq-upload-size', @@ -517,17 +521,17 @@ qq.FileUploader = function(o){ fail: 'qq-upload-fail' } }); - // overwrite options with user supplied - qq.extend(this._options, o); + // overwrite options with user supplied + qq.extend(this._options, o); this._element = this._options.element; - this._element.innerHTML = this._options.template; + this._element.innerHTML = this._options.template; this._listElement = this._options.listElement || this._find(this._element, 'list'); - + this._classes = this._options.classes; - - this._button = this._createUploadButton(this._find(this._element, 'button')); - + + this._button = this._createUploadButton(this._find(this._element, 'button')); + this._bindCancelEvent(); this._setupDragDrop(); }; @@ -539,17 +543,17 @@ qq.extend(qq.FileUploader.prototype, { /** * Gets one of the elements listed in this._options.classes **/ - _find: function(parent, type){ - var element = qq.getByClass(parent, this._options.classes[type])[0]; + _find: function(parent, type){ + var element = qq.getByClass(parent, this._options.classes[type])[0]; if (!element){ throw new Error('element not found ' + type); } - + return element; }, _setupDragDrop: function(){ var self = this, - dropArea = this._find(this._element, 'drop'); + dropArea = this._find(this._element, 'drop'); var dz = new qq.UploadDropZone({ element: dropArea, @@ -561,35 +565,35 @@ qq.extend(qq.FileUploader.prototype, { e.stopPropagation(); }, onLeaveNotDescendants: function(e){ - qq.removeClass(dropArea, self._classes.dropActive); + qq.removeClass(dropArea, self._classes.dropActive); }, onDrop: function(e){ dropArea.style.display = 'none'; qq.removeClass(dropArea, self._classes.dropActive); - self._uploadFileList(e.dataTransfer.files); + self._uploadFileList(e.dataTransfer.files); } }); - + dropArea.style.display = 'none'; - qq.attach(document, 'dragenter', function(e){ - if (!dz._isValidFileDrag(e)) return; - - dropArea.style.display = 'block'; - }); + qq.attach(document, 'dragenter', function(e){ + if (!dz._isValidFileDrag(e)) return; + + dropArea.style.display = 'block'; + }); qq.attach(document, 'dragleave', function(e){ - if (!dz._isValidFileDrag(e)) return; - + if (!dz._isValidFileDrag(e)) return; + var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // only fire when leaving document out - if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ - dropArea.style.display = 'none'; + if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ + dropArea.style.display = 'none'; } - }); + }); }, _onSubmit: function(id, fileName){ qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments); - this._addToList(id, fileName); + this._addToList(id, fileName); }, _onProgress: function(id, fileName, loaded, total){ qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments); @@ -597,87 +601,87 @@ qq.extend(qq.FileUploader.prototype, { var item = this._getItemByFileId(id); var size = this._find(item, 'size'); size.style.display = 'inline'; - - var text; + + var text; if (loaded != total){ text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total); - } else { + } else { text = this._formatSize(total); - } - - qq.setText(size, text); + } + + qq.setText(size, text); }, _onComplete: function(id, fileName, result){ qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments); // mark completed - var item = this._getItemByFileId(id); + var item = this._getItemByFileId(id); qq.remove(this._find(item, 'cancel')); qq.remove(this._find(item, 'spinner')); - + if (result.success){ - qq.addClass(item, this._classes.success); + qq.addClass(item, this._classes.success); } else { qq.addClass(item, this._classes.fail); - } + } }, _addToList: function(id, fileName){ - var item = qq.toElement(this._options.fileTemplate); + var item = qq.toElement(this._options.fileTemplate); item.qqFileId = id; - var fileElement = this._find(item, 'file'); + var fileElement = this._find(item, 'file'); qq.setText(fileElement, this._formatFileName(fileName)); - this._find(item, 'size').style.display = 'none'; + this._find(item, 'size').style.display = 'none'; this._listElement.appendChild(item); }, _getItemByFileId: function(id){ - var item = this._listElement.firstChild; - + 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; + while (item){ + if (item.qqFileId == id) return item; item = item.nextSibling; - } + } }, /** - * delegate click event for cancel link + * delegate click event for cancel link **/ _bindCancelEvent: function(){ var self = this, - list = this._listElement; - - qq.attach(list, 'click', function(e){ + list = this._listElement; + + qq.attach(list, 'click', function(e){ e = e || window.event; var target = e.target || e.srcElement; - - if (qq.hasClass(target, self._classes.cancel)){ + + if (qq.hasClass(target, self._classes.cancel)){ qq.preventDefault(e); - + var item = target.parentNode; self._handler.cancel(item.qqFileId); qq.remove(item); } }); - } + } }); - + qq.UploadDropZone = function(o){ this._options = { - element: null, + element: null, onEnter: function(e){}, - onLeave: function(e){}, - // is not fired when leaving element by hovering descendants - onLeaveNotDescendants: function(e){}, - onDrop: function(e){} + onLeave: function(e){}, + // is not fired when leaving element by hovering descendants + onLeaveNotDescendants: function(e){}, + onDrop: function(e){} }; - qq.extend(this._options, o); - + qq.extend(this._options, o); + this._element = this._options.element; - + this._disableDropOutside(); - this._attachEvents(); + this._attachEvents(); }; qq.UploadDropZone.prototype = { @@ -688,84 +692,84 @@ qq.UploadDropZone.prototype = { qq.attach(document, 'dragover', function(e){ if (e.dataTransfer){ e.dataTransfer.dropEffect = 'none'; - e.preventDefault(); - } + e.preventDefault(); + } }); - - qq.UploadDropZone.dropOutsideDisabled = true; - } + + qq.UploadDropZone.dropOutsideDisabled = true; + } }, _attachEvents: function(){ - var self = this; - + var self = this; + qq.attach(self._element, 'dragover', function(e){ if (!self._isValidFileDrag(e)) return; - + var effect = e.dataTransfer.effectAllowed; if (effect == 'move' || effect == 'linkMove'){ - e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) - } else { + e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) + } else { e.dataTransfer.dropEffect = 'copy'; // for Chrome } - + e.stopPropagation(); - e.preventDefault(); + e.preventDefault(); }); - + qq.attach(self._element, 'dragenter', function(e){ if (!self._isValidFileDrag(e)) return; - + self._options.onEnter(e); }); - + qq.attach(self._element, 'dragleave', function(e){ if (!self._isValidFileDrag(e)) return; - + self._options.onLeave(e); - - var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); + + var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // do not fire when moving a mouse over a descendant if (qq.contains(this, relatedTarget)) return; - - self._options.onLeaveNotDescendants(e); + + self._options.onLeaveNotDescendants(e); }); - + qq.attach(self._element, 'drop', function(e){ if (!self._isValidFileDrag(e)) return; - + e.preventDefault(); self._options.onDrop(e); - }); + }); }, _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; + // do not check dt.types.contains in webkit, because it crashes safari 4 + isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1; // dt.effectAllowed is none in Safari 5 - // dt.types.contains check is for firefox - return dt && dt.effectAllowed != 'none' && + // dt.types.contains check is for firefox + return dt && dt.effectAllowed != 'none' && (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files'))); - - } -}; + + } +}; qq.UploadButton = function(o){ this._options = { - element: null, - // if set to true adds multiple attribute to file input + element: null, + // if set to true adds multiple attribute to file input multiple: false, // name attribute of file input name: 'file', onChange: function(input){}, hoverClass: 'qq-upload-button-hover', - focusClass: 'qq-upload-button-focus' + focusClass: 'qq-upload-button-focus' }; - + qq.extend(this._options, o); - + this._element = this._options.element; - + // make button suitable container for input qq.css(this._element, { position: 'relative', @@ -773,35 +777,35 @@ qq.UploadButton = function(o){ // Make sure browse button is in the right side // in Internet Explorer direction: 'ltr' - }); - + }); + this._input = this._createInput(); }; qq.UploadButton.prototype = { - /* returns file input element */ + /* returns file input element */ getInput: function(){ return this._input; }, /* cleans/recreates the file input */ reset: function(){ if (this._input.parentNode){ - qq.remove(this._input); - } - + qq.remove(this._input); + } + qq.removeClass(this._element, this._options.focusClass); this._input = this._createInput(); - }, - _createInput: function(){ + }, + _createInput: function(){ var input = document.createElement("input"); - + if (this._options.multiple){ input.setAttribute("multiple", "multiple"); } - + input.setAttribute("type", "file"); input.setAttribute("name", this._options.name); - + qq.css(input, { position: 'absolute', // in Opera only 'browse' button @@ -816,14 +820,14 @@ qq.UploadButton.prototype = { padding: 0, opacity: 0 }); - + this._element.appendChild(input); var self = this; qq.attach(input, 'change', function(){ self._options.onChange(input); }); - + qq.attach(input, 'mouseover', function(){ qq.addClass(self._element, self._options.hoverClass); }); @@ -844,8 +848,8 @@ qq.UploadButton.prototype = { input.setAttribute('tabIndex', "-1"); } - return input; - } + return input; + } }; /** @@ -855,26 +859,28 @@ qq.UploadHandlerAbstract = function(o){ this._options = { debug: false, action: '/upload.php', - // maximum number of concurrent uploads + // maximum number of concurrent uploads maxConnections: 999, onProgress: function(id, fileName, loaded, total){}, onComplete: function(id, fileName, response){}, + onAllComplete: function(completed_files){}, onCancel: function(id, fileName){} }; - qq.extend(this._options, o); - + qq.extend(this._options, o); + this._queue = []; // params for files in queue this._params = []; + this._completed_files = []; }; qq.UploadHandlerAbstract.prototype = { log: function(str){ - if (this._options.debug && window.console) console.log('[uploader] ' + str); + if (this._options.debug && window.console) console.log('[uploader] ' + str); }, /** * 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 @@ -882,12 +888,12 @@ qq.UploadHandlerAbstract.prototype = { upload: function(id, params){ var len = this._queue.push(id); - var copy = {}; + var copy = {}; qq.extend(copy, params); - this._params[id] = copy; - + this._params[id] = copy; + // if too many active uploads, wait... - if (len <= this._options.maxConnections){ + if (len <= this._options.maxConnections){ this._upload(id, this._params[id]); } }, @@ -913,7 +919,7 @@ qq.UploadHandlerAbstract.prototype = { getName: function(id){}, /** * Returns size of the file identified by id - */ + */ getSize: function(id){}, /** * Returns id of files being uploaded or @@ -929,21 +935,28 @@ qq.UploadHandlerAbstract.prototype = { /** * Actual cancel method */ - _cancel: function(id){}, + _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); - + var max = this._options.maxConnections; - + 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); + } }; /** @@ -952,7 +965,7 @@ qq.UploadHandlerAbstract.prototype = { */ qq.UploadHandlerForm = function(o){ qq.UploadHandlerAbstract.apply(this, arguments); - + this._inputs = {}; }; // @inherits qq.UploadHandlerAbstract @@ -961,25 +974,25 @@ qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype); qq.extend(qq.UploadHandlerForm.prototype, { add: function(fileInput){ fileInput.setAttribute('name', 'qqfile'); - var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); - + var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); + this._inputs[id] = fileInput; - + // remove file input from DOM if (fileInput.parentNode){ qq.remove(fileInput); } - + 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]; + + delete this._inputs[id]; var iframe = document.getElementById(id); if (iframe){ @@ -990,29 +1003,29 @@ qq.extend(qq.UploadHandlerForm.prototype, { qq.remove(iframe); } - }, - _upload: function(id, params){ + }, + _upload: function(id, params){ var input = this._inputs[id]; - + if (!input){ throw new Error('file with passed id was not added, or already uploaded or cancelled'); - } + } var fileName = this.getName(id); - + var iframe = this._createIframe(id); var form = this._createForm(iframe, params); form.appendChild(input); var self = this; - this._attachLoadEvent(iframe, function(){ + this._attachLoadEvent(iframe, function(){ self.log('iframe loaded'); - + var response = self._getIframeContentJSON(iframe); self._options.onComplete(id, fileName, response); self._dequeue(id); - + delete self._inputs[id]; // timeout added to fix busy state in FF3.6 setTimeout(function(){ @@ -1020,11 +1033,11 @@ qq.extend(qq.UploadHandlerForm.prototype, { }, 1); }); - form.submit(); - qq.remove(form); - + form.submit(); + qq.remove(form); + return id; - }, + }, _attachLoadEvent: function(iframe, callback){ qq.attach(iframe, 'load', function(){ // when we remove iframe from dom @@ -1055,15 +1068,15 @@ qq.extend(qq.UploadHandlerForm.prototype, { // iframe.contentWindow.document - for IE<7 var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document, response; - + this.log("converting iframe's innerHTML to JSON"); this.log("innerHTML = " + doc.body.innerHTML); - + try { response = eval("(" + doc.body.innerHTML + ")"); } catch(err){ response = {}; - } + } return response; }, @@ -1118,20 +1131,20 @@ qq.UploadHandlerXhr = function(o){ this._files = []; this._xhrs = []; - - // current loaded size in bytes for each file + + // current loaded size in bytes for each file this._loaded = []; }; // static method qq.UploadHandlerXhr.isSupported = function(){ var input = document.createElement('input'); - input.type = 'file'; - + input.type = 'file'; + return ( 'multiple' in input && typeof File != "undefined" && - typeof (new XMLHttpRequest()).upload != "undefined" ); + typeof (new XMLHttpRequest()).upload != "undefined" ); }; // @inherits qq.UploadHandlerAbstract @@ -1141,43 +1154,43 @@ qq.extend(qq.UploadHandlerXhr.prototype, { /** * Adds file to the queue * Returns id to use with upload, cancel - **/ + **/ add: function(file){ if (!(file instanceof File)){ throw new Error('Passed obj in not a File (in qq.UploadHandlerXhr)'); } - - return this._files.push(file) - 1; + + return this._files.push(file) - 1; }, - getName: function(id){ + getName: function(id){ var file = this._files[id]; // fix missing name in Safari 4 - return file.fileName != null ? file.fileName : file.name; + return file.fileName != null ? file.fileName : file.name; }, getSize: function(id){ var file = this._files[id]; return file.fileSize != null ? file.fileSize : file.size; - }, + }, /** - * Returns uploaded bytes for file identified by id - */ + * Returns uploaded bytes for file identified by id + */ getLoaded: function(id){ - return this._loaded[id] || 0; + return this._loaded[id] || 0; }, /** * Sends the file identified by id and additional query params to the server * @param {Object} params name-value string pairs - */ + */ _upload: function(id, params){ var file = this._files[id], name = this.getName(id), size = this.getSize(id); - + this._loaded[id] = 0; - + var xhr = this._xhrs[id] = new XMLHttpRequest(); var self = this; - + xhr.upload.onprogress = function(e){ if (e.lengthComputable){ self._loaded[id] = e.loaded; @@ -1185,9 +1198,9 @@ qq.extend(qq.UploadHandlerXhr.prototype, { } }; - xhr.onreadystatechange = function(){ + xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ - self._onComplete(id, xhr); + self._onComplete(id, xhr); } }; @@ -1205,42 +1218,44 @@ qq.extend(qq.UploadHandlerXhr.prototype, { _onComplete: function(id, xhr){ // the request was aborted/cancelled if (!this._files[id]) return; - + var name = this.getName(id); var size = this.getSize(id); - + this._options.onProgress(id, name, size, size); - + if (xhr.status == 200){ this.log("xhr - server response received"); this.log("responseText = " + xhr.responseText); - + var response; - + try { response = eval("(" + xhr.responseText + ")"); } catch(err){ response = {}; } - + + this._completed_files.push({file: this._files[id], response: response}); this._options.onComplete(id, name, response); - - } else { + + } else { + this._completed_files.push({file: this._files[id], response: {}}); this._options.onComplete(id, name, {}); } - + this._files[id] = null; - this._xhrs[id] = null; - this._dequeue(id); + this._xhrs[id] = null; + this._dequeue(id); }, _cancel: function(id){ this._options.onCancel(id, this.getName(id)); - + this._files[id] = null; - + if (this._xhrs[id]){ this._xhrs[id].abort(); - this._xhrs[id] = null; + this._xhrs[id] = null; } } });