diff --git a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload-ui.js b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload-ui.js index 635fa3a9a5..527f1b1919 100644 --- a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload-ui.js +++ b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload-ui.js @@ -54,7 +54,8 @@ $.blueimp.fileupload.prototype._specialOptions.push( 'filesContainer', 'uploadTemplateId', - 'downloadTemplateId' + 'downloadTemplateId', + 'errorTemplateId' ); // The UI version extends the file upload widget @@ -70,6 +71,8 @@ uploadTemplateId: 'template-upload', // The ID of the download template: downloadTemplateId: 'template-download', + // The ID of the template for rendering an error + errorTemplateId: 'template-error', // The container for the list of files. If undefined, it is set to // an element with class "files" inside of the widget element: filesContainer: undefined, @@ -87,6 +90,11 @@ .not('.processing').length; }, + getNumberOfUploadedFiles: function () { + return this.filesContainer.children('.template-download') + .not('.processing').length; + }, + // Callback to retrieve the list of files from the server response: getFilesFromResponse: function (data) { if (data.result && $.isArray(data.result.files)) { @@ -106,40 +114,36 @@ that = $this.data('blueimp-fileupload') || $this.data('fileupload'), options = that.options; - data.context = that._renderUpload(data.files) - .data('data', data) - .addClass('processing'); - options.filesContainer[ - options.prependFiles ? 'prepend' : 'append' - ](data.context); - that._forceReflow(data.context); - that._transition(data.context); + data.process(function () { return $this.fileupload('process', data); }).always(function () { - data.context.each(function (index) { - $(this).find('.size').text( - that._formatFileSize(data.files[index].size) - ); - }).removeClass('processing'); - that._renderPreviews(data); - }).done(function () { - data.context.find('.start').prop('disabled', false); - if ((that._trigger('added', e, data) !== false) && - (options.autoUpload || data.autoUpload) && - data.autoUpload !== false) { - data.submit(); - } - }).fail(function () { - if (data.files.error) { - data.context.each(function (index) { - var error = data.files[index].error; - if (error) { - $(this).find('.fileupload-error').text(error) - .removeClass('is-invisible'); + var successFiles = []; + $.each(data.files, function (index, file) { + var error = file.error; + if (error) { + // TODO proper i18n for these strings + if (error === 'File type not allowed') { + data.files[index].error = '"' + file.name + '" is not a supported file type.' } - }); - } + that._renderError(file).appendTo(options.errorList); + } else { + successFiles.push(file); + } + }); + + data.files = successFiles; + + // render successful files + data.context = that._renderUpload(data.files) + .data('data', data); + data.context.find('.start').prop('disabled', false); + options.filesContainer[ + options.prependFiles ? 'prepend' : 'append' + ](data.context); + + that._forceReflow(data.context); + that._transition(data.context); }); }, // Callback for the start of each file upload request: @@ -519,6 +523,10 @@ ).find('a[download]').each(this._enableDragToDesktop).end(); }, + _renderError: function (error) { + return $(this.options.errorTemplate(error)); + }, + _startHandler: function (e) { e.preventDefault(); var button = $(e.currentTarget), @@ -581,10 +589,16 @@ _initButtonBarEventHandlers: function () { var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), - filesList = this.options.filesContainer; + filesList = this.options.filesContainer, + dropZone = this.element.find('.drag-drop'); this._on(fileUploadButtonBar.find('.start'), { click: function (e) { e.preventDefault(); + $(e.target).prop('disabled', true) + .text('Uploading...'); + dropZone.addClass('is-hidden'); + // TODO change upload progress message + this.options.updateUploadCountIndicator(this.options); filesList.find('.start').click(); } }); @@ -666,6 +680,9 @@ if (options.downloadTemplateId) { options.downloadTemplate = tmpl(options.downloadTemplateId); } + if (options.errorTemplateId) { + options.errorTemplate = tmpl(options.errorTemplateId); + } } }, diff --git a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload.js b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload.js index 0803592d65..396e18a323 100644 --- a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload.js +++ b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/jquery.fileupload.js @@ -958,6 +958,13 @@ fileSet, i, j = 0; + if (options.beforeAdd) { + if (typeof options.beforeAdd === "function") { + options.beforeAdd(e, $.extend({}, this.options, data)); + } else { + console.log('options.beforeAdd should be type "function", but is type "' + typeof options.beforeAdd + '"'); + } + } if (limitSize && (!filesLength || files[0].size === undefined)) { limitSize = undefined; } @@ -1012,6 +1019,13 @@ ); return result; }); + if (options.afterAdd) { + if (typeof options.afterAdd === "function") { + options.afterAdd(e, $.extend({}, this.options, data)); + } else { + console.log('options.afterAdd should be type "function", but is type "' + typeof options.beforeAdd + '"'); + } + } return result; }, diff --git a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/main.js b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/main.js index 8256e68ce2..553d8c3c6a 100644 --- a/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/main.js +++ b/zanata-war/src/main/webapp/resources/jQuery-File-Upload/9_5_6/js/main.js @@ -15,17 +15,108 @@ $(function () { 'use strict'; $('.fileupload').each(function() { - var uploadForm = $(this), + var $doc = $(document), + uploadForm = $(this), dropZone = uploadForm.find('.drag-drop'), - container = uploadForm.closest('.modal'); + filesList = uploadForm.find('.files'), + errorList = uploadForm.find('.js-errors'), + startButton = uploadForm.find('.fileupload-main-start'), + doneButton = uploadForm.find('.fileupload-done'), + cancelButton = uploadForm.find('.fileupload-cancel'), + closeButton = uploadForm.find('.fileupload-close'), + closeButtons = doneButton.add(cancelButton).add(closeButton), + container = uploadForm.closest('.modal'), + revealButtonId = container.attr('id') + '-toggle-button', + revealButton = $('#' + revealButtonId), + countIndicator = uploadForm.find('.js-file-count'), + resetUploadForm = (function resetUploadForm () { + errorList.empty(); + // individual items should clean up any resources they use + filesList.find('.cancel').click(); + // remove items that don't have a cancel button + filesList.empty(); + startButton.removeClass('is-hidden') + .attr('disabled', true) + .text('Upload Documents'); + doneButton.addClass('is-hidden').prop('disabled', true); + cancelButton.removeClass('is-hidden').prop('disabled', false); + dropZone.removeClass('is-hidden'); + }), + updateCountIndicator = (function updateCountIndicator (options) { + var numberOfFiles = options.getNumberOfFiles(), + noFiles = numberOfFiles === 0; + // FIXME i18n on this string + countIndicator.text((noFiles ? 'No' : numberOfFiles) + ' document' + (numberOfFiles === 1 ? '' : 's') + ' queued'); + // start button should only be enabled if there are files to upload + startButton.attr('disabled', noFiles); + }), + updateUploadCountIndicator = (function updateUploadCountIndicator (options) { + var totalFiles = options.getNumberOfFiles(), + uploadedFiles = options.getNumberOfUploadedFiles(); + countIndicator.text('Uploaded ' + uploadedFiles + ' of ' + totalFiles + ' files'); + if (uploadedFiles === totalFiles) { + startButton.addClass('is-hidden').prop('disabled', true); + doneButton.removeClass('is-hidden').prop('disabled', false); + cancelButton.addClass('is-hidden').prop('disabled', true); + } + }); // move the container to the end of the body so it is on top of everything container.appendTo('body'); + revealButton.bind('click', resetUploadForm); + + closeButtons.bind('click', function (e) { + zanata.modal.hide('#' + container.attr('id')); + }); + + // prevent default file drop behaviour on the page + $doc.bind('drop dragover', function (e) { + e.preventDefault(); + }); + + + dropZone.bind('drop dragleave dragend', function (e) { + e.preventDefault(); + dropZone.removeClass('is-active'); + }); + dropZone.bind('dragover', function (e) { + e.preventDefault(); + dropZone.addClass('is-active'); + }); + uploadForm.fileupload({ sequentialUploads: true, dropZone: dropZone, - acceptFileTypes: /(\.|\/)(pot|dtd|txt|idml|html?|od[tpsg])$/i + beforeAdd: (function beforeAdd (e, data) { + errorList.empty(); + startButton.attr('disabled', true); + }), + afterAdd: (function afterAdd (e, data) { + updateCountIndicator(data); + }), + errorList: errorList, + // TODO this might need to be passed in as a composite interface attribute and stored in a data- attribute + acceptFileTypes: /(\.|\/)(pot|dtd|txt|idml|html?|od[tpsg])$/i, + failed: (function updateCount (e, data) { + // update count when removing files + var $this = $(this), + that = $this.data('blueimp-fileupload') || + $this.data('fileupload'), + options = that.options; + // FIXME may want to make sure this doesn't trigger update while + // uploading. Alternative: make this function aware of + // current uploading state. + updateCountIndicator(options); + }), + completed: (function completed (e, data) { + var $this = $(this), + that = $this.data('blueimp-fileupload') || + $this.data('fileupload'), + options = that.options; + updateUploadCountIndicator(options); + }), + updateUploadCountIndicator: updateUploadCountIndicator }); // FIXME may be unnecessary. If necessary, it could just go in the above options