From be7ff929326131fc6f6b79c2717d2f729f187bae Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:46:50 +0100 Subject: [PATCH 01/18] Bump version to 0.5.1 --- lib/jquery/fileupload/rails/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jquery/fileupload/rails/version.rb b/lib/jquery/fileupload/rails/version.rb index 10fbdc9..af489fd 100644 --- a/lib/jquery/fileupload/rails/version.rb +++ b/lib/jquery/fileupload/rails/version.rb @@ -1,7 +1,7 @@ module JQuery module FileUpload module Rails - VERSION = "0.4.1" + VERSION = '0.5.1' end end end From 52f79b62dcc733e4c93752329fa0352ba99cf1ec Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:47:58 +0100 Subject: [PATCH 02/18] Update jQuery File Upload User Interface Plugin to 9.5.2 --- .../jquery-fileupload/jquery.fileupload-ui.js | 162 ++++++++++++------ 1 file changed, 114 insertions(+), 48 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js index 5d22346..b9dab7d 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js @@ -1,5 +1,5 @@ /* - * jQuery File Upload User Interface Plugin 8.2.1 + * jQuery File Upload User Interface Plugin 9.5.2 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan @@ -9,8 +9,8 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window, URL, webkitURL, FileReader */ +/* jshint nomen:false */ +/* global define, window */ (function (factory) { 'use strict'; @@ -19,7 +19,9 @@ define([ 'jquery', 'tmpl', - './jquery.fileupload-resize', + './jquery.fileupload-image', + './jquery.fileupload-audio', + './jquery.fileupload-video', './jquery.fileupload-validate' ], factory); } else { @@ -29,7 +31,7 @@ window.tmpl ); } -}(function ($, tmpl, loadImage) { +}(function ($, tmpl) { 'use strict'; $.blueimp.fileupload.prototype._specialOptions.push( @@ -64,7 +66,8 @@ // Function returning the current number of files, // used by the maxNumberOfFiles validation: getNumberOfFiles: function () { - return this.filesContainer.children().length; + return this.filesContainer.children() + .not('.processing').length; }, // Callback to retrieve the list of files from the server response: @@ -79,33 +82,53 @@ // widget (via file input selection, drag & drop or add API call). // See the basic file upload widget for more information: add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var $this = $(this), that = $this.data('blueimp-fileupload') || $this.data('fileupload'), - options = that.options, - files = data.files; + 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 = that._renderUpload(files).data('data', data); + data.context.each(function (index) { + $(this).find('.size').text( + that._formatFileSize(data.files[index].size) + ); + }).removeClass('processing'); that._renderPreviews(data); - options.filesContainer[ - options.prependFiles ? 'prepend' : 'append' - ](data.context); - that._forceReflow(data.context); - that._transition(data.context).done( - function () { - if ((that._trigger('added', e, data) !== false) && - (options.autoUpload || data.autoUpload) && - data.autoUpload !== false && !data.files.error) { - data.submit(); + }).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('.error').text(error); } - } - ); + }); + } }); }, // Callback for the start of each file upload request: send: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); if (data.context && data.dataType && @@ -118,7 +141,7 @@ !$.support.transition && 'progress-animated' ) .attr('aria-valuenow', 100) - .find('.bar').css( + .children().first().css( 'width', '100%' ); @@ -127,6 +150,9 @@ }, // Callback for successful uploads: done: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || $(this).data('fileupload'), getFilesFromResponse = data.getFilesFromResponse || @@ -137,8 +163,8 @@ if (data.context) { data.context.each(function (index) { var file = files[index] || - {error: 'Empty file upload result'}, - deferred = that._addFinishedDeferreds(); + {error: 'Empty file upload result'}; + deferred = that._addFinishedDeferreds(); that._transition($(this)).done( function () { var node = $(this); @@ -157,8 +183,9 @@ ); }); } else { - template = that._renderDownload(files) - .appendTo(that.options.filesContainer); + template = that._renderDownload(files)[ + that.options.prependFiles ? 'prependTo' : 'appendTo' + ](that.options.filesContainer); that._forceReflow(template); deferred = that._addFinishedDeferreds(); that._transition(template).done( @@ -173,6 +200,9 @@ }, // Callback for failed (abort or error) uploads: fail: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || $(this).data('fileupload'), template, @@ -213,8 +243,9 @@ } }); } else if (data.errorThrown !== 'abort') { - data.context = that._renderUpload(data.files) - .appendTo(that.options.filesContainer) + data.context = that._renderUpload(data.files)[ + that.options.prependFiles ? 'prependTo' : 'appendTo' + ](that.options.filesContainer) .data('data', data); that._forceReflow(data.context); deferred = that._addFinishedDeferreds(); @@ -234,18 +265,26 @@ }, // Callback for upload progress events: progress: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var progress = Math.floor(data.loaded / data.total * 100); if (data.context) { - var progress = Math.floor(data.loaded / data.total * 100); - data.context.find('.progress') - .attr('aria-valuenow', progress) - .find('.bar').css( - 'width', - progress + '%' - ); + data.context.each(function () { + $(this).find('.progress') + .attr('aria-valuenow', progress) + .children().first().css( + 'width', + progress + '%' + ); + }); } }, // Callback for global upload progress events: progressall: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var $this = $(this), progress = Math.floor(data.loaded / data.total * 100), globalProgressNode = $this.find('.fileupload-progress'), @@ -260,13 +299,16 @@ globalProgressNode .find('.progress') .attr('aria-valuenow', progress) - .find('.bar').css( + .children().first().css( 'width', progress + '%' ); }, // Callback for uploads start, equivalent to the global ajaxStart event: start: function (e) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); that._resetFinishedDeferreds(); @@ -278,6 +320,9 @@ }, // Callback for uploads stop, equivalent to the global ajaxStop event: stop: function (e) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || $(this).data('fileupload'), deferred = that._addFinishedDeferreds(); @@ -289,31 +334,46 @@ function () { $(this).find('.progress') .attr('aria-valuenow', '0') - .find('.bar').css('width', '0%'); + .children().first().css('width', '0%'); $(this).find('.progress-extended').html(' '); deferred.resolve(); } ); }, - processstart: function () { + processstart: function (e) { + if (e.isDefaultPrevented()) { + return false; + } $(this).addClass('fileupload-processing'); }, - processstop: function () { + processstop: function (e) { + if (e.isDefaultPrevented()) { + return false; + } $(this).removeClass('fileupload-processing'); }, // Callback for file deletion: destroy: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var that = $(this).data('blueimp-fileupload') || - $(this).data('fileupload'); - if (data.url) { - $.ajax(data).done(function () { + $(this).data('fileupload'), + removeNode = function () { that._transition(data.context).done( function () { $(this).remove(); that._trigger('destroyed', e, data); } ); + }; + if (data.url) { + data.dataType = data.dataType || that.options.dataType; + $.ajax(data).done(removeNode).fail(function () { + that._trigger('destroyfailed', e, data); }); + } else { + removeNode(); } } }, @@ -446,20 +506,23 @@ var button = $(e.currentTarget), template = button.closest('.template-upload'), data = template.data('data'); - if (data && data.submit && !data.jqXHR && data.submit()) { - button.prop('disabled', true); + button.prop('disabled', true); + if (data && data.submit) { + data.submit(); } }, _cancelHandler: function (e) { e.preventDefault(); - var template = $(e.currentTarget).closest('.template-upload'), + var template = $(e.currentTarget) + .closest('.template-upload,.template-download'), data = template.data('data') || {}; - if (!data.jqXHR) { + data.context = data.context || template; + if (data.abort) { + data.abort(); + } else { data.errorThrown = 'abort'; this._trigger('fail', e, data); - } else { - data.jqXHR.abort(); } }, @@ -606,6 +669,9 @@ _create: function () { this._super(); this._resetFinishedDeferreds(); + if (!$.support.fileInput) { + this._disableFileInputButton(); + } }, enable: function () { From 459b437bce465a958187644a72a6c52fad46ea2b Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:48:19 +0100 Subject: [PATCH 03/18] Update jQuery File Upload Plugin to 5.40.1 --- .../jquery-fileupload/jquery.fileupload.js | 265 +++++++++++++----- 1 file changed, 195 insertions(+), 70 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload.js index 03678f3..0803592 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload.js @@ -1,5 +1,5 @@ /* - * jQuery File Upload Plugin 5.31.1 + * jQuery File Upload Plugin 5.40.1 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan @@ -9,8 +9,8 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window, document, File, Blob, FormData, location */ +/* jshint nomen:false */ +/* global define, window, document, location, Blob, FormData */ (function (factory) { 'use strict'; @@ -27,12 +27,30 @@ }(function ($) { 'use strict'; + // Detect file input support, based on + // http://viljamis.com/blog/2012/file-upload-support-on-mobile/ + $.support.fileInput = !(new RegExp( + // Handle devices which give false positives for the feature detection: + '(Android (1\\.[0156]|2\\.[01]))' + + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + + '|(w(eb)?OSBrowser)|(webOS)' + + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))' + ).test(window.navigator.userAgent) || + // Feature detection for all other devices: + $('').prop('disabled')); + // The FileReader API is not actually used, but works as feature detection, - // as e.g. Safari supports XHR file uploads via the FormData API, - // but not non-multipart XHR file uploads: - $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader); + // as some Safari versions (5?) support XHR file uploads via the FormData API, + // but not non-multipart XHR file uploads. + // window.XMLHttpRequestUpload is not available on IE10, so we check for + // window.ProgressEvent instead to detect XHR2 file upload capability: + $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); $.support.xhrFormDataFileUpload = !!window.FormData; + // Detect support for Blob slicing (required for chunked uploads): + $.support.blobSlice = window.Blob && (Blob.prototype.slice || + Blob.prototype.webkitSlice || Blob.prototype.mozSlice); + // The fileupload widget listens for change events on file input fields defined // via fileInput setting and paste or drop events of the given dropZone. // In addition to the default jQuery Widget methods, the fileupload widget @@ -72,6 +90,14 @@ // To limit the number of files uploaded with one XHR request, // set the following option to an integer greater than 0: limitMultiFileUploads: undefined, + // The following option limits the number of files uploaded with one + // XHR request to keep the request size under or equal to the defined + // limit in bytes: + limitMultiFileUploadSize: undefined, + // Multipart file uploads add a number of bytes to each uploaded file, + // therefore the following option adds an overhead for each file used + // in the limitMultiFileUploadSize configuration: + limitMultiFileUploadSizeOverhead: 512, // Set the following option to true to issue all file upload requests // in a sequential order: sequentialUploads: false, @@ -144,17 +170,23 @@ // The add callback is invoked as soon as files are added to the fileupload // widget (via file input selection, drag & drop, paste or add API call). // If the singleFileUploads option is enabled, this callback will be - // called once for each file in the selection for XHR file uplaods, else + // called once for each file in the selection for XHR file uploads, else // once for each file selection. + // // The upload starts when the submit method is invoked on the data parameter. // The data object contains a files property holding the added files - // and allows to override plugin options as well as define ajax settings. + // and allows you to override plugin options as well as define ajax settings. + // // Listeners for this callback can also be bound the following way: // .bind('fileuploadadd', func); + // // data.submit() returns a Promise object and allows to attach additional // handlers using jQuery's Deferred callbacks: // data.submit().done(func).fail(func).always(func); add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } if (data.autoUpload || (data.autoUpload !== false && $(this).fileupload('option', 'autoUpload'))) { data.process().done(function () { @@ -233,6 +265,11 @@ 'forceIframeTransport' ], + _blobSlice: $.support.blobSlice && function () { + var slice = this.slice || this.webkitSlice || this.mozSlice; + return slice.apply(this, arguments); + }, + _BitrateTimer: function () { this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime()); this.loaded = 0; @@ -256,7 +293,7 @@ _getFormData: function (options) { var formData; - if (typeof options.formData === 'function') { + if ($.type(options.formData) === 'function') { return options.formData(options.form); } if ($.isArray(options.formData)) { @@ -336,10 +373,18 @@ // Trigger a custom progress event with a total data property set // to the file size(s) of the current upload and a loaded data // property calculated accordingly: - this._trigger('progress', e, data); + this._trigger( + 'progress', + $.Event('progress', {delegatedEvent: e}), + data + ); // Trigger a global progress event for all current file uploads, // including ajax calls queued for sequential file uploads: - this._trigger('progressall', e, this._progress); + this._trigger( + 'progressall', + $.Event('progressall', {delegatedEvent: e}), + this._progress + ); } }, @@ -374,15 +419,18 @@ file = options.files[0], // Ignore non-multipart setting if not supported: multipart = options.multipart || !$.support.xhrFileUpload, - paramName = options.paramName[0]; - options.headers = options.headers || {}; + paramName = $.type(options.paramName) === 'array' ? + options.paramName[0] : options.paramName; + options.headers = $.extend({}, options.headers); if (options.contentRange) { options.headers['Content-Range'] = options.contentRange; } - if (!multipart) { + if (!multipart || options.blob || !this._isInstanceOf('File', file)) { options.headers['Content-Disposition'] = 'attachment; filename="' + encodeURI(file.name) + '"'; - options.contentType = file.type; + } + if (!multipart) { + options.contentType = file.type || 'application/octet-stream'; options.data = options.blob || file; } else if ($.support.xhrFormDataFileUpload) { if (options.postMessage) { @@ -399,7 +447,8 @@ } else { $.each(options.files, function (index, file) { formData.push({ - name: options.paramName[index] || paramName, + name: ($.type(options.paramName) === 'array' && + options.paramName[index]) || paramName, value: file }); }); @@ -414,8 +463,6 @@ }); } if (options.blob) { - options.headers['Content-Disposition'] = 'attachment; filename="' + - encodeURI(file.name) + '"'; formData.append(paramName, options.blob, file.name); } else { $.each(options.files, function (index, file) { @@ -424,9 +471,10 @@ if (that._isInstanceOf('File', file) || that._isInstanceOf('Blob', file)) { formData.append( - options.paramName[index] || paramName, + ($.type(options.paramName) === 'array' && + options.paramName[index]) || paramName, file, - file.name + file.uploadName || file.name ); } }); @@ -439,13 +487,13 @@ }, _initIframeSettings: function (options) { + var targetHost = $('').prop('href', options.url).prop('host'); // Setting the dataType to iframe enables the iframe transport: options.dataType = 'iframe ' + (options.dataType || ''); // The iframe transport accepts a serialized array as form data: options.formData = this._getFormData(options); // Add redirect url to form data on cross-domain uploads: - if (options.redirect && $('').prop('href', options.url) - .prop('host') !== location.host) { + if (options.redirect && targetHost && targetHost !== location.host) { options.formData.push({ name: options.redirectParamName || 'redirect', value: options.redirect @@ -510,8 +558,10 @@ options.url = options.form.prop('action') || location.href; } // The HTTP request method must be "POST" or "PUT": - options.type = (options.type || options.form.prop('method') || '') - .toUpperCase(); + options.type = (options.type || + ($.type(options.form.prop('method')) === 'string' && + options.form.prop('method')) || '' + ).toUpperCase(); if (options.type !== 'POST' && options.type !== 'PUT' && options.type !== 'PATCH') { options.type = 'POST'; @@ -570,22 +620,32 @@ // Adds convenience methods to the data callback argument: _addConvenienceMethods: function (e, data) { var that = this, - getPromise = function (data) { - return $.Deferred().resolveWith(that, [data]).promise(); + getPromise = function (args) { + return $.Deferred().resolveWith(that, args).promise(); }; data.process = function (resolveFunc, rejectFunc) { if (resolveFunc || rejectFunc) { data._processQueue = this._processQueue = - (this._processQueue || getPromise(this)) - .pipe(resolveFunc, rejectFunc); + (this._processQueue || getPromise([this])).pipe( + function () { + if (data.errorThrown) { + return $.Deferred() + .rejectWith(that, [data]).promise(); + } + return getPromise(arguments); + } + ).pipe(resolveFunc, rejectFunc); } - return this._processQueue || getPromise(this); + return this._processQueue || getPromise([this]); }; data.submit = function () { if (this.state() !== 'pending') { data.jqXHR = this.jqXHR = - (that._trigger('submit', e, this) !== false) && - that._onSend(e, this); + (that._trigger( + 'submit', + $.Event('submit', {delegatedEvent: e}), + this + ) !== false) && that._onSend(e, this); } return this.jqXHR || that._getXHRPromise(); }; @@ -593,7 +653,9 @@ if (this.jqXHR) { return this.jqXHR.abort(); } - return that._getXHRPromise(); + this.errorThrown = 'abort'; + that._trigger('fail', null, this); + return that._getXHRPromise(false); }; data.state = function () { if (this.jqXHR) { @@ -603,6 +665,10 @@ return that._getDeferredState(this._processQueue); } }; + data.processing = function () { + return !this.jqXHR && this._processQueue && that + ._getDeferredState(this._processQueue) === 'pending'; + }; data.progress = function () { return this._progress; }; @@ -627,12 +693,13 @@ // should be uploaded in chunks, but does not invoke any // upload requests: _chunkedUpload: function (options, testOnly) { + options.uploadedBytes = options.uploadedBytes || 0; var that = this, file = options.files[0], fs = file.size, - ub = options.uploadedBytes = options.uploadedBytes || 0, + ub = options.uploadedBytes, mcs = options.maxChunkSize || fs, - slice = file.slice || file.webkitSlice || file.mozSlice, + slice = this._blobSlice, dfd = $.Deferred(), promise = dfd.promise(), jqXHR, @@ -804,7 +871,11 @@ // Set timer for bitrate progress calculation: options._bitrateTimer = new that._BitrateTimer(); jqXHR = jqXHR || ( - ((aborted || that._trigger('send', e, options) === false) && + ((aborted || that._trigger( + 'send', + $.Event('send', {delegatedEvent: e}), + options + ) === false) && that._getXHRPromise(false, options.context, aborted)) || that._chunkedUpload(options) || $.ajax(options) ).done(function (result, textStatus, jqXHR) { @@ -850,7 +921,8 @@ this._slots.push(slot); pipe = slot.pipe(send); } else { - pipe = (this._sequence = this._sequence.pipe(send, send)); + this._sequence = this._sequence.pipe(send, send); + pipe = this._sequence; } // Return the piped Promise object, enhanced with an abort method, // which is delegated to the jqXHR object of the current upload, @@ -874,39 +946,70 @@ var that = this, result = true, options = $.extend({}, this.options, data), + files = data.files, + filesLength = files.length, limit = options.limitMultiFileUploads, + limitSize = options.limitMultiFileUploadSize, + overhead = options.limitMultiFileUploadSizeOverhead, + batchSize = 0, paramName = this._getParamName(options), paramNameSet, paramNameSlice, fileSet, - i; - if (!(options.singleFileUploads || limit) || + i, + j = 0; + if (limitSize && (!filesLength || files[0].size === undefined)) { + limitSize = undefined; + } + if (!(options.singleFileUploads || limit || limitSize) || !this._isXHRUpload(options)) { - fileSet = [data.files]; + fileSet = [files]; paramNameSet = [paramName]; - } else if (!options.singleFileUploads && limit) { + } else if (!(options.singleFileUploads || limitSize) && limit) { fileSet = []; paramNameSet = []; - for (i = 0; i < data.files.length; i += limit) { - fileSet.push(data.files.slice(i, i + limit)); + for (i = 0; i < filesLength; i += limit) { + fileSet.push(files.slice(i, i + limit)); paramNameSlice = paramName.slice(i, i + limit); if (!paramNameSlice.length) { paramNameSlice = paramName; } paramNameSet.push(paramNameSlice); } + } else if (!options.singleFileUploads && limitSize) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i = i + 1) { + batchSize += files[i].size + overhead; + if (i + 1 === filesLength || + ((batchSize + files[i + 1].size + overhead) > limitSize) || + (limit && i + 1 - j >= limit)) { + fileSet.push(files.slice(j, i + 1)); + paramNameSlice = paramName.slice(j, i + 1); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + j = i + 1; + batchSize = 0; + } + } } else { paramNameSet = paramName; } - data.originalFiles = data.files; - $.each(fileSet || data.files, function (index, element) { + data.originalFiles = files; + $.each(fileSet || files, function (index, element) { var newData = $.extend({}, data); newData.files = fileSet ? element : [element]; newData.paramName = paramNameSet[index]; that._initResponseObject(newData); that._initProgressObject(newData); that._addConvenienceMethods(e, newData); - result = that._trigger('add', e, newData); + result = that._trigger( + 'add', + $.Event('add', {delegatedEvent: e}), + newData + ); return result; }); return result; @@ -1075,7 +1178,11 @@ if (that.options.replaceFileInput) { that._replaceFileInput(data.fileInput); } - if (that._trigger('change', e, data) !== false) { + if (that._trigger( + 'change', + $.Event('change', {delegatedEvent: e}), + data + ) !== false) { that._onAdd(e, data); } }); @@ -1092,23 +1199,30 @@ data.files.push(file); } }); - if (this._trigger('paste', e, data) === false || - this._onAdd(e, data) === false) { - return false; + if (this._trigger( + 'paste', + $.Event('paste', {delegatedEvent: e}), + data + ) !== false) { + this._onAdd(e, data); } } }, _onDrop: function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; var that = this, - dataTransfer = e.dataTransfer = e.originalEvent && - e.originalEvent.dataTransfer, + dataTransfer = e.dataTransfer, data = {}; if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { e.preventDefault(); this._getDroppedFiles(dataTransfer).always(function (files) { data.files = files; - if (that._trigger('drop', e, data) !== false) { + if (that._trigger( + 'drop', + $.Event('drop', {delegatedEvent: e}), + data + ) !== false) { that._onAdd(e, data); } }); @@ -1116,16 +1230,15 @@ }, _onDragOver: function (e) { - var dataTransfer = e.dataTransfer = e.originalEvent && - e.originalEvent.dataTransfer; - if (dataTransfer) { - if (this._trigger('dragover', e) === false) { - return false; - } - if ($.inArray('Files', dataTransfer.types) !== -1) { - dataTransfer.dropEffect = 'copy'; - e.preventDefault(); - } + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var dataTransfer = e.dataTransfer; + if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 && + this._trigger( + 'dragover', + $.Event('dragover', {delegatedEvent: e}) + ) !== false) { + e.preventDefault(); + dataTransfer.dropEffect = 'copy'; } }, @@ -1139,9 +1252,11 @@ paste: this._onPaste }); } - this._on(this.options.fileInput, { - change: this._onChange - }); + if ($.support.fileInput) { + this._on(this.options.fileInput, { + change: this._onChange + }); + } }, _destroyEventHandlers: function () { @@ -1192,15 +1307,21 @@ _initDataAttributes: function () { var that = this, - options = this.options; + options = this.options, + clone = $(this.element[0].cloneNode(false)); // Initialize options set via HTML5 data-attributes: $.each( - $(this.element[0].cloneNode(false)).data(), + clone.data(), function (key, value) { - if (that._isRegExpOption(key, value)) { - value = that._getRegExp(value); + var dataAttributeName = 'data-' + + // Convert camelCase to hyphen-ated key: + key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); + if (clone.attr(dataAttributeName)) { + if (that._isRegExpOption(key, value)) { + value = that._getRegExp(value); + } + options[key] = value; } - options[key] = value; } ); }, @@ -1275,6 +1396,10 @@ if (aborted) { return; } + if (!files.length) { + dfd.reject(); + return; + } data.files = files; jqXHR = that._onSend(null, data).then( function (result, textStatus, jqXHR) { From 3d250be3390b5116af82816402a3f15c6a78482e Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:48:37 +0100 Subject: [PATCH 04/18] Update jQuery File Upload Validation Plugin to 1.1.2 --- .../jquery.fileupload-validate.js | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js index 2599da8..0f66cd6 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js @@ -1,5 +1,5 @@ /* - * jQuery File Upload Validation Plugin 1.0.2 + * jQuery File Upload Validation Plugin 1.1.2 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan @@ -9,8 +9,7 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window */ +/* global define, window */ (function (factory) { 'use strict'; @@ -34,13 +33,13 @@ { action: 'validate', // Always trigger this action, - // even if the previous action was rejected: + // even if the previous action was rejected: always: true, // Options taken from the global options map: - acceptFileTypes: '@acceptFileTypes', - maxFileSize: '@maxFileSize', - minFileSize: '@minFileSize', - maxNumberOfFiles: '@maxNumberOfFiles', + acceptFileTypes: '@', + maxFileSize: '@', + minFileSize: '@', + maxNumberOfFiles: '@', disabled: '@disableValidation' } ); @@ -84,18 +83,22 @@ var dfd = $.Deferred(), settings = this.options, file = data.files[data.index], - numberOfFiles = settings.getNumberOfFiles(); - if (numberOfFiles && $.type(options.maxNumberOfFiles) === 'number' && - numberOfFiles + data.files.length > options.maxNumberOfFiles) { + fileSize; + if (options.minFileSize || options.maxFileSize) { + fileSize = file.size; + } + if ($.type(options.maxNumberOfFiles) === 'number' && + (settings.getNumberOfFiles() || 0) + data.files.length > + options.maxNumberOfFiles) { file.error = settings.i18n('maxNumberOfFiles'); } else if (options.acceptFileTypes && !(options.acceptFileTypes.test(file.type) || options.acceptFileTypes.test(file.name))) { file.error = settings.i18n('acceptFileTypes'); - } else if (options.maxFileSize && file.size > options.maxFileSize) { + } else if (fileSize > options.maxFileSize) { file.error = settings.i18n('maxFileSize'); - } else if ($.type(file.size) === 'number' && - file.size < options.minFileSize) { + } else if ($.type(fileSize) === 'number' && + fileSize < options.minFileSize) { file.error = settings.i18n('minFileSize'); } else { delete file.error; From 44b3b7ace8277f2c8e91fabdf1787cd54d928d77 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:48:53 +0100 Subject: [PATCH 05/18] Update jQuery Iframe Transport Plugin to 1.8.2 --- .../jquery.iframe-transport.js | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js b/vendor/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js index e04e7a0..8d64b59 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js @@ -1,5 +1,5 @@ /* - * jQuery Iframe Transport Plugin 1.6.2 + * jQuery Iframe Transport Plugin 1.8.2 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan @@ -9,8 +9,7 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint unparam: true, nomen: true */ -/*global define, window, document */ +/* global define, window, document */ (function (factory) { 'use strict'; @@ -27,7 +26,7 @@ // Helper variable to create unique names for the transport iframes: var counter = 0; - // The iframe transport accepts three additional options: + // The iframe transport accepts four additional options: // options.fileInput: a jQuery collection of file input fields // options.paramName: the parameter name for the file form data, // overrides the name property of the file input field(s), @@ -35,9 +34,16 @@ // options.formData: an array of objects with name and value properties, // equivalent to the return data of .serializeArray(), e.g.: // [{name: 'a', value: 1}, {name: 'b', value: 2}] + // options.initialIframeSrc: the URL of the initial iframe src, + // by default set to "javascript:false;" $.ajaxTransport('iframe', function (options) { if (options.async) { - var form, + // javascript:false as initial iframe src + // prevents warning popups on HTTPS in IE6: + /*jshint scripturl: true */ + var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', + /*jshint scripturl: false */ + form, iframe, addParamChar; return { @@ -56,15 +62,13 @@ options.url = options.url + addParamChar + '_method=PATCH'; options.type = 'POST'; } - // javascript:false as initial iframe src - // prevents warning popups on HTTPS in IE6. // IE versions below IE8 cannot set the name property of // elements that have already been added to the DOM, // so we set the name along with the iframe HTML markup: counter += 1; iframe = $( - '' + '' ).bind('load', function () { var fileInputClones, paramNames = $.isArray(options.paramName) ? @@ -95,7 +99,7 @@ ); // Fix for IE endless progress bar activity bug // (happens on form submits to iframe targets): - $('') + $('') .appendTo(form); window.setTimeout(function () { // Removing the form in a setTimeout call @@ -138,6 +142,8 @@ .prop('enctype', 'multipart/form-data') // enctype must be set as encoding for IE: .prop('encoding', 'multipart/form-data'); + // Remove the HTML5 form attribute from the input(s): + options.fileInput.removeAttr('form'); } form.submit(); // Insert the file input fields at their original location @@ -145,7 +151,10 @@ if (fileInputClones && fileInputClones.length) { options.fileInput.each(function (index, input) { var clone = $(fileInputClones[index]); - $(input).prop('name', clone.prop('name')); + // Restore the original name and form properties: + $(input) + .prop('name', clone.prop('name')) + .attr('form', clone.attr('form')); clone.replaceWith(input); }); } @@ -159,7 +168,7 @@ // concat is used to avoid the "Script URL" JSLint error: iframe .unbind('load') - .prop('src', 'javascript'.concat(':false;')); + .prop('src', initialIframeSrc); } if (form) { form.remove(); @@ -170,7 +179,15 @@ }); // The iframe transport returns the iframe content document as response. - // The following adds converters from iframe to text, json, html, and script: + // The following adds converters from iframe to text, json, html, xml + // and script. + // Please note that the Content-Type for JSON responses has to be text/plain + // or text/html, if the browser doesn't include application/json in the + // Accept header, else IE will show a download dialog. + // The Content-Type for XML responses on the other hand has to be always + // application/xml or text/xml, so IE properly parses the XML response. + // See also + // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation $.ajaxSetup({ converters: { 'iframe text': function (iframe) { @@ -182,6 +199,12 @@ 'iframe html': function (iframe) { return iframe && $(iframe[0].body).html(); }, + 'iframe xml': function (iframe) { + var xmlDoc = iframe && iframe[0]; + return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : + $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || + $(xmlDoc.body).html()); + }, 'iframe script': function (iframe) { return iframe && $.globalEval($(iframe[0].body).text()); } From ec3e9a38ccf7e80bc68e499d20eb18f9111535f7 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:49:09 +0100 Subject: [PATCH 06/18] Update jQuery UI Widget to 1.10.4+amd --- .../jquery-fileupload/vendor/jquery.ui.widget.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js b/vendor/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js index fd2948f..c430419 100644 --- a/vendor/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js +++ b/vendor/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js @@ -1,8 +1,8 @@ -/* - * jQuery UI Widget 1.10.1+amd +/*! + * jQuery UI Widget 1.10.4+amd * https://github.com/blueimp/jQuery-File-Upload * - * Copyright 2013 jQuery Foundation and other contributors + * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -115,7 +115,7 @@ $.widget = function( name, base, prototype ) { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, @@ -324,12 +324,12 @@ $.Widget.prototype = { curOption = curOption[ parts[ i ] ]; } key = parts.pop(); - if ( value === undefined ) { + if ( arguments.length === 1 ) { return curOption[ key ] === undefined ? null : curOption[ key ]; } curOption[ key ] = value; } else { - if ( value === undefined ) { + if ( arguments.length === 1 ) { return this.options[ key ] === undefined ? null : this.options[ key ]; } options[ key ] = value; From e9a1a96e4d8ae97d076ff5a41b3e5f582c54e7a1 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:49:24 +0100 Subject: [PATCH 07/18] Update JavaScript Load Image to 1.9.0 --- .../jquery-fileupload/vendor/load-image.js | 318 ++++++++++-------- 1 file changed, 183 insertions(+), 135 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js b/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js index 0155d38..c7fd674 100644 --- a/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js +++ b/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js @@ -1,19 +1,16 @@ /* - * JavaScript Load Image 1.3.1 + * JavaScript Load Image 1.9.0 * https://github.com/blueimp/JavaScript-Load-Image * * Copyright 2011, Sebastian Tschan * https://blueimp.net * - * iOS image scaling fixes based on - * https://github.com/stomita/ios-imagefile-megapixel - * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, bitwise: true */ -/*global window, document, URL, webkitURL, Blob, File, FileReader, define */ +/*jslint nomen: true */ +/*global define, window, document, URL, webkitURL, Blob, File, FileReader */ (function ($) { 'use strict'; @@ -30,17 +27,24 @@ if (oUrl && !(options && options.noRevoke)) { loadImage.revokeObjectURL(oUrl); } - callback(loadImage.scale(img, options)); + if (callback) { + callback(loadImage.scale(img, options)); + } }; - if ((window.Blob && file instanceof Blob) || - // Files are also Blob instances, but some browsers - // (Firefox 3.6) support the File API but not Blobs: - (window.File && file instanceof File)) { + if (loadImage.isInstanceOf('Blob', file) || + // Files are also Blob instances, but some browsers + // (Firefox 3.6) support the File API but not Blobs: + loadImage.isInstanceOf('File', file)) { url = oUrl = loadImage.createObjectURL(file); // Store the file type for resize processing: img._type = file.type; - } else { + } else if (typeof file === 'string') { url = file; + if (options && options.crossOrigin) { + img.crossOrigin = options.crossOrigin; + } + } else { + return false; } if (url) { img.src = url; @@ -51,7 +55,9 @@ if (target && target.result) { img.src = target.result; } else { - callback(e); + if (callback) { + callback(e); + } } }); }, @@ -61,139 +67,178 @@ (window.URL && URL.revokeObjectURL && URL) || (window.webkitURL && webkitURL); - // Detects subsampling in JPEG images: - loadImage.detectSubsampling = function (img) { - var iw = img.width, - ih = img.height, - canvas, - ctx; - if (iw * ih > 1024 * 1024) { // only consider mexapixel images - canvas = document.createElement('canvas'); - canvas.width = canvas.height = 1; - ctx = canvas.getContext('2d'); - ctx.drawImage(img, -iw + 1, 0); - // subsampled image becomes half smaller in rendering size. - // check alpha channel value to confirm image is covering edge pixel or not. - // if alpha value is 0 image is not covering, hence subsampled. - return ctx.getImageData(0, 0, 1, 1).data[3] === 0; - } - return false; + loadImage.isInstanceOf = function (type, obj) { + // Cross-frame instanceof check + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; }; - // Detects vertical squash in JPEG images: - loadImage.detectVerticalSquash = function (img, ih) { - var canvas = document.createElement('canvas'), - ctx = canvas.getContext('2d'), - data, - sy, - ey, - py, - alpha; - canvas.width = 1; - canvas.height = ih; - ctx.drawImage(img, 0, 0); - data = ctx.getImageData(0, 0, 1, ih).data; - // search image edge pixel position in case it is squashed vertically: - sy = 0; - ey = ih; - py = ih; - while (py > sy) { - alpha = data[(py - 1) * 4 + 3]; - if (alpha === 0) { - ey = py; - } else { - sy = py; - } - py = (ey + sy) >> 1; - } - return (py / ih) || 1; + // Transform image coordinates, allows to override e.g. + // the canvas orientation based on the orientation option, + // gets canvas, options passed as arguments: + loadImage.transformCoordinates = function () { + return; }; - // Renders image to canvas while working around iOS image scaling bugs: - // https://github.com/blueimp/JavaScript-Load-Image/issues/13 - loadImage.renderImageToCanvas = function (img, canvas, width, height) { - var iw = img.width, - ih = img.height, - ctx = canvas.getContext('2d'), - vertSquashRatio, - d = 1024, // size of tiling canvas - tmpCanvas = document.createElement('canvas'), - tmpCtx, - dw, - dh, - dx, - dy, - sx, - sy; - ctx.save(); - if (loadImage.detectSubsampling(img)) { - iw /= 2; - ih /= 2; - } - vertSquashRatio = loadImage.detectVerticalSquash(img, ih); - tmpCanvas.width = tmpCanvas.height = d; - tmpCtx = tmpCanvas.getContext('2d'); - dw = Math.ceil(d * width / iw); - dh = Math.ceil(d * height / ih / vertSquashRatio); - dy = 0; - sy = 0; - while (sy < ih) { - dx = 0; - sx = 0; - while (sx < iw) { - tmpCtx.clearRect(0, 0, d, d); - tmpCtx.drawImage(img, -sx, -sy); - ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh); - sx += d; - dx += dw; - } - sy += d; - dy += dh; - } - ctx.restore(); - tmpCanvas = tmpCtx = null; + // Returns transformed options, allows to override e.g. + // coordinate and dimension options based on the orientation: + loadImage.getTransformedOptions = function (options) { + return options; + }; + + // Canvas render method, allows to override the + // rendering e.g. to work around issues on iOS: + loadImage.renderImageToCanvas = function ( + canvas, + img, + sourceX, + sourceY, + sourceWidth, + sourceHeight, + destX, + destY, + destWidth, + destHeight + ) { + canvas.getContext('2d').drawImage( + img, + sourceX, + sourceY, + sourceWidth, + sourceHeight, + destX, + destY, + destWidth, + destHeight + ); + return canvas; }; - // Scales the given image (img or canvas HTML element) + // This method is used to determine if the target image + // should be a canvas element: + loadImage.hasCanvasOption = function (options) { + return options.canvas || options.crop; + }; + + // Scales and/or crops the given image (img or canvas HTML element) // using the given options. // Returns a canvas object if the browser supports canvas - // and the canvas option is true or a canvas object is passed - // as image, else the scaled image: + // and the hasCanvasOption method returns true or a canvas + // object is passed as image, else the scaled image: loadImage.scale = function (img, options) { options = options || {}; var canvas = document.createElement('canvas'), - width = img.width, - height = img.height, - scale = Math.max( - (options.minWidth || width) / width, - (options.minHeight || height) / height - ); - if (scale > 1) { - width = Math.ceil(width * scale); - height = Math.ceil(height * scale); - } - scale = Math.min( - (options.maxWidth || width) / width, - (options.maxHeight || height) / height - ); - if (scale < 1) { - width = Math.ceil(width * scale); - height = Math.ceil(height * scale); + useCanvas = img.getContext || + (loadImage.hasCanvasOption(options) && canvas.getContext), + width = img.naturalWidth || img.width, + height = img.naturalHeight || img.height, + destWidth = width, + destHeight = height, + maxWidth, + maxHeight, + minWidth, + minHeight, + sourceWidth, + sourceHeight, + sourceX, + sourceY, + tmp, + scaleUp = function () { + var scale = Math.max( + (minWidth || destWidth) / destWidth, + (minHeight || destHeight) / destHeight + ); + if (scale > 1) { + destWidth = Math.ceil(destWidth * scale); + destHeight = Math.ceil(destHeight * scale); + } + }, + scaleDown = function () { + var scale = Math.min( + (maxWidth || destWidth) / destWidth, + (maxHeight || destHeight) / destHeight + ); + if (scale < 1) { + destWidth = Math.ceil(destWidth * scale); + destHeight = Math.ceil(destHeight * scale); + } + }; + if (useCanvas) { + options = loadImage.getTransformedOptions(options); + sourceX = options.left || 0; + sourceY = options.top || 0; + if (options.sourceWidth) { + sourceWidth = options.sourceWidth; + if (options.right !== undefined && options.left === undefined) { + sourceX = width - sourceWidth - options.right; + } + } else { + sourceWidth = width - sourceX - (options.right || 0); + } + if (options.sourceHeight) { + sourceHeight = options.sourceHeight; + if (options.bottom !== undefined && options.top === undefined) { + sourceY = height - sourceHeight - options.bottom; + } + } else { + sourceHeight = height - sourceY - (options.bottom || 0); + } + destWidth = sourceWidth; + destHeight = sourceHeight; } - if (img.getContext || (options.canvas && canvas.getContext)) { - canvas.width = width; - canvas.height = height; - if (img._type === 'image/jpeg') { - loadImage - .renderImageToCanvas(img, canvas, width, height); + maxWidth = options.maxWidth; + maxHeight = options.maxHeight; + minWidth = options.minWidth; + minHeight = options.minHeight; + if (useCanvas && maxWidth && maxHeight && options.crop) { + destWidth = maxWidth; + destHeight = maxHeight; + tmp = sourceWidth / sourceHeight - maxWidth / maxHeight; + if (tmp < 0) { + sourceHeight = maxHeight * sourceWidth / maxWidth; + if (options.top === undefined && options.bottom === undefined) { + sourceY = (height - sourceHeight) / 2; + } + } else if (tmp > 0) { + sourceWidth = maxWidth * sourceHeight / maxHeight; + if (options.left === undefined && options.right === undefined) { + sourceX = (width - sourceWidth) / 2; + } + } + } else { + if (options.contain || options.cover) { + minWidth = maxWidth = maxWidth || minWidth; + minHeight = maxHeight = maxHeight || minHeight; + } + if (options.cover) { + scaleDown(); + scaleUp(); } else { - canvas.getContext('2d') - .drawImage(img, 0, 0, width, height); + scaleUp(); + scaleDown(); } - return canvas; } - img.width = width; - img.height = height; + if (useCanvas) { + canvas.width = destWidth; + canvas.height = destHeight; + loadImage.transformCoordinates( + canvas, + options + ); + return loadImage.renderImageToCanvas( + canvas, + img, + sourceX, + sourceY, + sourceWidth, + sourceHeight, + 0, + 0, + destWidth, + destHeight + ); + } + img.width = destWidth; + img.height = destHeight; return img; }; @@ -208,12 +253,15 @@ // Loads a given File object via FileReader interface, // invokes the callback with the event object (load or error). // The result can be read via event.target.result: - loadImage.readFile = function (file, callback) { - if (window.FileReader && FileReader.prototype.readAsDataURL) { + loadImage.readFile = function (file, callback, method) { + if (window.FileReader) { var fileReader = new FileReader(); fileReader.onload = fileReader.onerror = callback; - fileReader.readAsDataURL(file); - return fileReader; + method = method || 'readAsDataURL'; + if (fileReader[method]) { + fileReader[method](file); + return fileReader; + } } return false; }; From 08009b67646b6a78fc4be46fe7ab308c582eca1c Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:49:39 +0100 Subject: [PATCH 08/18] Update JavaScript Templates to 2.4.1 --- .../jquery-fileupload/vendor/tmpl.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/vendor/tmpl.js b/vendor/assets/javascripts/jquery-fileupload/vendor/tmpl.js index c8b4b86..9380053 100644 --- a/vendor/assets/javascripts/jquery-fileupload/vendor/tmpl.js +++ b/vendor/assets/javascripts/jquery-fileupload/vendor/tmpl.js @@ -1,5 +1,5 @@ /* - * JavaScript Templates 2.1.0 + * JavaScript Templates 2.4.1 * https://github.com/blueimp/JavaScript-Templates * * Copyright 2011, Sebastian Tschan @@ -12,7 +12,7 @@ * http://ejohn.org/blog/javascript-micro-templating/ */ -/*jslint evil: true, regexp: true */ +/*jslint evil: true, regexp: true, unparam: true */ /*global document, define */ (function ($) { @@ -34,21 +34,21 @@ tmpl.load = function (id) { return document.getElementById(id).innerHTML; }; - tmpl.regexp = /([\s'\\])(?![^%]*%\})|(?:\{%(=|#)([\s\S]+?)%\})|(\{%)|(%\})/g; + tmpl.regexp = /([\s'\\])(?!(?:[^{]|\{(?!%))*%\})|(?:\{%(=|#)([\s\S]+?)%\})|(\{%)|(%\})/g; tmpl.func = function (s, p1, p2, p3, p4, p5) { - if (p1) { // whitespace, quote and backspace in interpolation context + if (p1) { // whitespace, quote and backspace in HTML context return { "\n": "\\n", "\r": "\\r", "\t": "\\t", " " : " " - }[s] || "\\" + s; + }[p1] || "\\" + p1; } if (p2) { // interpolation: {%=prop%}, or unescaped: {%#prop%} if (p2 === "=") { return "'+_e(" + p3 + ")+'"; } - return "'+(" + p3 + "||'')+'"; + return "'+(" + p3 + "==null?'':" + p3 + ")+'"; } if (p4) { // evaluation start tag: {% return "';"; @@ -66,7 +66,8 @@ "'" : "'" }; tmpl.encode = function (s) { - return String(s || "").replace( + /*jshint eqnull:true */ + return (s == null ? "" : "" + s).replace( tmpl.encReg, function (c) { return tmpl.encMap[c] || ""; @@ -74,7 +75,7 @@ ); }; tmpl.arg = "o"; - tmpl.helper = ",print=function(s,e){_s+=e&&(s||'')||_e(s);}" + + tmpl.helper = ",print=function(s,e){_s+=e?(s==null?'':s):_e(s);}" + ",include=function(s,d){_s+=tmpl(s,d);}"; if (typeof define === "function" && define.amd) { define(function () { From 84a69fd134fc4a23fae7c042b38fba0638addbc1 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:49:56 +0100 Subject: [PATCH 09/18] Update jQuery File Upload Processing Plugin to 1.3.0 --- .../jquery.fileupload-process.js | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js index 2f9eeed..8a6b929 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js @@ -1,5 +1,5 @@ /* - * jQuery File Upload Processing Plugin 1.1 + * jQuery File Upload Processing Plugin 1.3.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan @@ -9,8 +9,8 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true */ -/*global define, window */ +/* jshint nomen:false */ +/* global define, window */ (function (factory) { 'use strict'; @@ -64,13 +64,17 @@ */ }, - _processFile: function (data) { + _processFile: function (data, originalData) { var that = this, dfd = $.Deferred().resolveWith(that, [data]), chain = dfd.promise(); this._trigger('process', null, data); $.each(data.processQueue, function (i, settings) { var func = function (data) { + if (originalData.errorThrown) { + return $.Deferred() + .rejectWith(that, [originalData]).promise(); + } return that.processActions[settings.action].call( that, data, @@ -98,14 +102,20 @@ _transformProcessQueue: function (options) { var processQueue = []; $.each(options.processQueue, function () { - var settings = {}; + var settings = {}, + action = this.action, + prefix = this.prefix === true ? action : this.prefix; $.each(this, function (key, value) { if ($.type(value) === 'string' && value.charAt(0) === '@') { - settings[key] = options[value.slice(1)]; + settings[key] = options[ + value.slice(1) || (prefix ? prefix + + key.charAt(0).toUpperCase() + key.slice(1) : key) + ]; } else { settings[key] = value; } + }); processQueue.push(settings); }); @@ -127,10 +137,14 @@ if (this._processing === 0) { this._trigger('processstart'); } - $.each(data.files, function (index, file) { + $.each(data.files, function (index) { var opts = index ? $.extend({}, options) : options, func = function () { - return that._processFile(opts); + if (data.errorThrown) { + return $.Deferred() + .rejectWith(that, [data]).promise(); + } + return that._processFile(opts, data); }; opts.index = index; that._processing += 1; From 0ed3ef5bf8a6d0704cb9bf1dae5e95e8d102d52c Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:50:11 +0100 Subject: [PATCH 10/18] Update jQuery File Upload AngularJS Plugin to 2.2.0 --- .../jquery.fileupload-angular.js | 317 +++++++++++------- 1 file changed, 199 insertions(+), 118 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js index e7ba784..e4ef392 100755 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js @@ -1,5 +1,5 @@ /* - * jQuery File Upload AngularJS Plugin 1.0.1 + * jQuery File Upload AngularJS Plugin 2.2.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2013, Sebastian Tschan @@ -9,28 +9,73 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true */ -/*global angular */ +/* jshint nomen:false */ +/* global define, angular */ -(function () { +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'angular', + './jquery.fileupload-image', + './jquery.fileupload-audio', + './jquery.fileupload-video', + './jquery.fileupload-validate' + ], factory); + } else { + factory(); + } +}(function () { 'use strict'; angular.module('blueimp.fileupload', []) + // The fileUpload service provides configuration options + // for the fileUpload directive and default handlers for + // File Upload events: .provider('fileUpload', function () { - var scopeApply = function () { + var scopeEvalAsync = function (expression) { var scope = angular.element(this) - .fileupload('option', 'scope')(); - if (!scope.$$phase) { - scope.$apply(); - } + .fileupload('option', 'scope'); + // Schedule a new $digest cycle if not already inside of one + // and evaluate the given expression: + scope.$evalAsync(expression); + }, + addFileMethods = function (scope, data) { + var files = data.files, + file = files[0]; + angular.forEach(files, function (file, index) { + file._index = index; + file.$state = function () { + return data.state(); + }; + file.$processing = function () { + return data.processing(); + }; + file.$progress = function () { + return data.progress(); + }; + file.$response = function () { + return data.response(); + }; + }); + file.$submit = function () { + if (!file.error) { + return data.submit(); + } + }; + file.$cancel = function () { + return data.abort(); + }; }, $config; $config = this.defaults = { handleResponse: function (e, data) { var files = data.result && data.result.files; if (files) { - data.scope().replace(data.files, files); + data.scope.replace(data.files, files); } else if (data.errorThrown || data.textStatus === 'error') { data.files[0].error = data.errorThrown || @@ -38,81 +83,72 @@ } }, add: function (e, data) { - var scope = data.scope(); + if (e.isDefaultPrevented()) { + return false; + } + var scope = data.scope, + filesCopy = []; + angular.forEach(data.files, function (file) { + filesCopy.push(file); + }); + scope.$apply(function () { + addFileMethods(scope, data); + var method = scope.option('prependFiles') ? + 'unshift' : 'push'; + Array.prototype[method].apply(scope.queue, data.files); + }); data.process(function () { return scope.process(data); - }).always( - function () { - var file = data.files[0], - submit = function () { - return data.submit(); - }; - file.$cancel = function () { - scope.clear(data.files); - return data.abort(); - }; - file.$state = function () { - return data.state(); - }; - file.$progress = function () { - return data.progress(); - }; - file.$response = function () { - return data.response(); - }; - if (file.$state() === 'rejected') { - file._$submit = submit; - } else { - file.$submit = submit; - } - scope.$apply(function () { - var method = scope.option('prependFiles') ? - 'unshift' : 'push'; - Array.prototype[method].apply( - scope.queue, - data.files - ); - if (file.$submit && - (scope.option('autoUpload') || - data.autoUpload) && - data.autoUpload !== false) { - file.$submit(); - } - }); + }).always(function () { + scope.$apply(function () { + addFileMethods(scope, data); + scope.replace(filesCopy, data.files); + }); + }).then(function () { + if ((scope.option('autoUpload') || + data.autoUpload) && + data.autoUpload !== false) { + data.submit(); } - ); + }); }, progress: function (e, data) { - data.scope().$apply(); + if (e.isDefaultPrevented()) { + return false; + } + data.scope.$apply(); }, done: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } var that = this; - data.scope().$apply(function () { + data.scope.$apply(function () { data.handleResponse.call(that, e, data); }); }, fail: function (e, data) { - var that = this; + if (e.isDefaultPrevented()) { + return false; + } + var that = this, + scope = data.scope; if (data.errorThrown === 'abort') { + scope.clear(data.files); return; } - if (data.dataType.indexOf('json') === data.dataType.length - 4) { - try { - data.result = angular.fromJson(data.jqXHR.responseText); - } catch (err) {} - } - data.scope().$apply(function () { + scope.$apply(function () { data.handleResponse.call(that, e, data); }); }, - stop: scopeApply, - processstart: scopeApply, - processstop: scopeApply, + stop: scopeEvalAsync, + processstart: scopeEvalAsync, + processstop: scopeEvalAsync, getNumberOfFiles: function () { - return this.scope().queue.length; + var scope = this.scope; + return scope.queue.length - scope.processing(); }, dataType: 'json', - prependFiles: true, autoUpload: false }; this.$get = [ @@ -124,8 +160,9 @@ ]; }) + // Format byte numbers to readable presentations: .provider('formatFileSizeFilter', function () { - var $config = this.defaults = { + var $config = { // Byte units following the IEC format // http://en.wikipedia.org/wiki/Kilobyte units: [ @@ -134,28 +171,61 @@ {size: 1000, suffix: ' KB'} ] }; + this.defaults = $config; this.$get = function () { return function (bytes) { if (!angular.isNumber(bytes)) { return ''; } var unit = true, - i = -1; + i = 0, + prefix, + suffix; while (unit) { - unit = $config.units[i += 1]; + unit = $config.units[i]; + prefix = unit.prefix || ''; + suffix = unit.suffix || ''; if (i === $config.units.length - 1 || bytes >= unit.size) { - return (bytes / unit.size).toFixed(2) + unit.suffix; + return prefix + (bytes / unit.size).toFixed(2) + suffix; } + i += 1; } }; }; }) + // The FileUploadController initializes the fileupload widget and + // provides scope methods to control the File Upload functionality: .controller('FileUploadController', [ - '$scope', '$element', '$attrs', 'fileUpload', - function ($scope, $element, $attrs, fileUpload) { - $scope.disabled = angular.element('') - .prop('disabled'); + '$scope', '$element', '$attrs', '$window', 'fileUpload', + function ($scope, $element, $attrs, $window, fileUpload) { + var uploadMethods = { + progress: function () { + return $element.fileupload('progress'); + }, + active: function () { + return $element.fileupload('active'); + }, + option: function (option, data) { + if (arguments.length === 1) { + return $element.fileupload('option', option); + } + $element.fileupload('option', option, data); + }, + add: function (data) { + return $element.fileupload('add', data); + }, + send: function (data) { + return $element.fileupload('send', data); + }, + process: function (data) { + return $element.fileupload('process', data); + }, + processing: function (data) { + return $element.fileupload('processing', data); + } + }; + $scope.disabled = !$window.jQuery.support.fileInput; $scope.queue = $scope.queue || []; $scope.clear = function (files) { var queue = this.queue, @@ -167,7 +237,8 @@ length = files.length; } while (i) { - if (queue[i -= 1] === file) { + i -= 1; + if (queue[i] === file) { return queue.splice(i, length); } } @@ -186,27 +257,6 @@ } } }; - $scope.progress = function () { - return $element.fileupload('progress'); - }; - $scope.active = function () { - return $element.fileupload('active'); - }; - $scope.option = function (option, data) { - return $element.fileupload('option', option, data); - }; - $scope.add = function (data) { - return $element.fileupload('add', data); - }; - $scope.send = function (data) { - return $element.fileupload('send', data); - }; - $scope.process = function (data) { - return $element.fileupload('process', data); - }; - $scope.processing = function (data) { - return $element.fileupload('processing', data); - }; $scope.applyOnQueue = function (method) { var list = this.queue.slice(0), i, @@ -224,16 +274,26 @@ $scope.cancel = function () { this.applyOnQueue('$cancel'); }; + // Add upload methods to the scope: + angular.extend($scope, uploadMethods); // The fileupload widget will initialize with // the options provided via "data-"-parameters, // as well as those given via options object: $element.fileupload(angular.extend( - {scope: function () { - return $scope; - }}, + {scope: $scope}, fileUpload.defaults )).on('fileuploadadd', function (e, data) { - data.scope = $scope.option('scope'); + data.scope = $scope; + }).on('fileuploadfail', function (e, data) { + if (data.errorThrown === 'abort') { + return; + } + if (data.dataType && + data.dataType.indexOf('json') === data.dataType.length - 4) { + try { + data.result = angular.fromJson(data.jqXHR.responseText); + } catch (ignore) {} + } }).on([ 'fileuploadadd', 'fileuploadsubmit', @@ -260,12 +320,23 @@ 'fileuploadprocessalways', 'fileuploadprocessstop' ].join(' '), function (e, data) { - $scope.$emit(e.type, data); + if ($scope.$emit(e.type, data).defaultPrevented) { + e.preventDefault(); + } + }).on('remove', function () { + // Remove upload methods from the scope, + // when the widget is removed: + var method; + for (method in uploadMethods) { + if (uploadMethods.hasOwnProperty(method)) { + delete $scope[method]; + } + } }); // Observe option changes: $scope.$watch( - $attrs.fileupload, - function (newOptions, oldOptions) { + $attrs.fileUpload, + function (newOptions) { if (newOptions) { $element.fileupload('option', newOptions); } @@ -274,10 +345,11 @@ } ]) + // Provide File Upload progress feedback: .controller('FileUploadProgressController', [ '$scope', '$attrs', '$parse', function ($scope, $attrs, $parse) { - var fn = $parse($attrs.progress), + var fn = $parse($attrs.fileUploadProgress), update = function () { var progress = fn($scope); if (!progress || !progress.total) { @@ -289,7 +361,7 @@ }; update(); $scope.$watch( - $attrs.progress + '.loaded', + $attrs.fileUploadProgress + '.loaded', function (newValue, oldValue) { if (newValue !== oldValue) { update(); @@ -299,37 +371,46 @@ } ]) + // Display File Upload previews: .controller('FileUploadPreviewController', [ - '$scope', '$element', '$attrs', '$parse', - function ($scope, $element, $attrs, $parse) { - var fn = $parse($attrs.preview), - file = fn($scope); - if (file.preview) { - $element.append(file.preview); - } + '$scope', '$element', '$attrs', + function ($scope, $element, $attrs) { + $scope.$watch( + $attrs.fileUploadPreview + '.preview', + function (preview) { + $element.empty(); + if (preview) { + $element.append(preview); + } + } + ); } ]) - .directive('fileupload', function () { + .directive('fileUpload', function () { return { - controller: 'FileUploadController' + controller: 'FileUploadController', + scope: true }; }) - .directive('progress', function () { + .directive('fileUploadProgress', function () { return { - controller: 'FileUploadProgressController' + controller: 'FileUploadProgressController', + scope: true }; }) - .directive('preview', function () { + .directive('fileUploadPreview', function () { return { controller: 'FileUploadPreviewController' }; }) + // Enhance the HTML5 download attribute to + // allow drag&drop of files to the desktop: .directive('download', function () { - return function (scope, elm, attrs) { + return function (scope, elm) { elm.on('dragstart', function (e) { try { e.originalEvent.dataTransfer.setData( @@ -340,9 +421,9 @@ elm.prop('href') ].join(':') ); - } catch (err) {} + } catch (ignore) {} }); }; }); -}()); +})); From 1eaf5018432d8124187757b2a239b1613af85124 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:50:35 +0100 Subject: [PATCH 11/18] Update jQuery postMessage Transport Plugin to 1.1.1 --- .../cors/jquery.postmessage-transport.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js b/vendor/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js index 931b635..2b4851e 100755 --- a/vendor/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js +++ b/vendor/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js @@ -1,5 +1,5 @@ /* - * jQuery postMessage Transport Plugin 1.1 + * jQuery postMessage Transport Plugin 1.1.1 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan @@ -9,8 +9,7 @@ * http://www.opensource.org/licenses/MIT */ -/*jslint unparam: true, nomen: true */ -/*global define, window, document */ +/* global define, window, document */ (function (factory) { 'use strict'; @@ -64,8 +63,9 @@ xhrUpload = options.xhr().upload; return { send: function (_, completeCallback) { + counter += 1; var message = { - id: 'postmessage-transport-' + (counter += 1) + id: 'postmessage-transport-' + counter }, eventName = 'message.' + message.id; iframe = $( From 911fab3ca6c541114cbeb7699e38a78d73d9a754 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:51:49 +0100 Subject: [PATCH 12/18] Update cors. --- .../javascripts/jquery-fileupload/cors/jquery.xdr-transport.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js b/vendor/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js index d769f45..0044cc2 100755 --- a/vendor/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js +++ b/vendor/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js @@ -12,8 +12,7 @@ * https://github.com/jaubourg/ajaxHooks/ */ -/*jslint unparam: true */ -/*global define, window, XDomainRequest */ +/* global define, window, XDomainRequest */ (function (factory) { 'use strict'; From f542aa1f8a6e263219262b6aca6d95465337be2d Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:53:35 +0100 Subject: [PATCH 13/18] Add new files for latest release. --- .../jquery.fileupload-audio.js | 106 ++++++ .../jquery.fileupload-image.js | 309 ++++++++++++++++++ .../jquery.fileupload-jquery-ui.js | 152 +++++++++ .../jquery.fileupload-video.js | 106 ++++++ .../jquery.fileupload-noscript.css | 22 ++ .../jquery.fileupload-ui-noscript.css | 17 + .../assets/stylesheets/jquery.fileupload.css | 36 ++ 7 files changed, 748 insertions(+) create mode 100644 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js create mode 100644 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js create mode 100644 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js create mode 100644 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js create mode 100644 vendor/assets/stylesheets/jquery.fileupload-noscript.css create mode 100644 vendor/assets/stylesheets/jquery.fileupload-ui-noscript.css create mode 100644 vendor/assets/stylesheets/jquery.fileupload.css diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js new file mode 100644 index 0000000..575800e --- /dev/null +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js @@ -0,0 +1,106 @@ +/* + * jQuery File Upload Audio Preview Plugin 1.0.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadAudio', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + disabled: '@disableAudioPreview' + }, + { + action: 'setAudio', + name: '@audioPreviewName', + disabled: '@disableAudioPreview' + } + ); + + // The File Upload Audio Preview plugin extends the fileupload widget + // with audio preview functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of audio files to load, + // matched against the file type: + loadAudioFileTypes: /^audio\/.*$/ + }, + + _audioElement: document.createElement('audio'), + + processActions: { + + // Loads the audio file given via data.files and data.index + // as audio element if the browser supports playing it. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadAudio: function (data, options) { + if (options.disabled) { + return data; + } + var file = data.files[data.index], + url, + audio; + if (this._audioElement.canPlayType && + this._audioElement.canPlayType(file.type) && + ($.type(options.maxFileSize) !== 'number' || + file.size <= options.maxFileSize) && + (!options.fileTypes || + options.fileTypes.test(file.type))) { + url = loadImage.createObjectURL(file); + if (url) { + audio = this._audioElement.cloneNode(false); + audio.src = url; + audio.controls = true; + data.audio = audio; + return data; + } + } + return data; + }, + + // Sets the audio element as a property of the file object: + setAudio: function (data, options) { + if (data.audio && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.audio; + } + return data; + } + + } + + }); + +})); diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js new file mode 100644 index 0000000..f3e33c0 --- /dev/null +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js @@ -0,0 +1,309 @@ +/* + * jQuery File Upload Image Preview & Resize Plugin 1.7.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, Blob */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + 'load-image-meta', + 'load-image-exif', + 'load-image-ios', + 'canvas-to-blob', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadImageMetaData', + disableImageHead: '@', + disableExif: '@', + disableExifThumbnail: '@', + disableExifSub: '@', + disableExifGps: '@', + disabled: '@disableImageMetaDataLoad' + }, + { + action: 'loadImage', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + noRevoke: '@', + disabled: '@disableImageLoad' + }, + { + action: 'resizeImage', + // Use "image" as prefix for the "@" options: + prefix: 'image', + maxWidth: '@', + maxHeight: '@', + minWidth: '@', + minHeight: '@', + crop: '@', + orientation: '@', + forceResize: '@', + disabled: '@disableImageResize' + }, + { + action: 'saveImage', + quality: '@imageQuality', + type: '@imageType', + disabled: '@disableImageResize' + }, + { + action: 'saveImageMetaData', + disabled: '@disableImageMetaDataSave' + }, + { + action: 'resizeImage', + // Use "preview" as prefix for the "@" options: + prefix: 'preview', + maxWidth: '@', + maxHeight: '@', + minWidth: '@', + minHeight: '@', + crop: '@', + orientation: '@', + thumbnail: '@', + canvas: '@', + disabled: '@disableImagePreview' + }, + { + action: 'setImage', + name: '@imagePreviewName', + disabled: '@disableImagePreview' + }, + { + action: 'deleteImageReferences', + disabled: '@disableImageReferencesDeletion' + } + ); + + // The File Upload Resize plugin extends the fileupload widget + // with image resize functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of images to load: + // matched against the file type: + loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/, + // The maximum file size of images to load: + loadImageMaxFileSize: 10000000, // 10MB + // The maximum width of resized images: + imageMaxWidth: 1920, + // The maximum height of resized images: + imageMaxHeight: 1080, + // Defines the image orientation (1-8) or takes the orientation + // value from Exif data if set to true: + imageOrientation: false, + // Define if resized images should be cropped or only scaled: + imageCrop: false, + // Disable the resize image functionality by default: + disableImageResize: true, + // The maximum width of the preview images: + previewMaxWidth: 80, + // The maximum height of the preview images: + previewMaxHeight: 80, + // Defines the preview orientation (1-8) or takes the orientation + // value from Exif data if set to true: + previewOrientation: true, + // Create the preview using the Exif data thumbnail: + previewThumbnail: true, + // Define if preview images should be cropped or only scaled: + previewCrop: false, + // Define if preview images should be resized as canvas elements: + previewCanvas: true + }, + + processActions: { + + // Loads the image given via data.files and data.index + // as img element, if the browser supports the File API. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadImage: function (data, options) { + if (options.disabled) { + return data; + } + var that = this, + file = data.files[data.index], + dfd = $.Deferred(); + if (($.type(options.maxFileSize) === 'number' && + file.size > options.maxFileSize) || + (options.fileTypes && + !options.fileTypes.test(file.type)) || + !loadImage( + file, + function (img) { + if (img.src) { + data.img = img; + } + dfd.resolveWith(that, [data]); + }, + options + )) { + return data; + } + return dfd.promise(); + }, + + // Resizes the image given as data.canvas or data.img + // and updates data.canvas or data.img with the resized image. + // Also stores the resized image as preview property. + // Accepts the options maxWidth, maxHeight, minWidth, + // minHeight, canvas and crop: + resizeImage: function (data, options) { + if (options.disabled || !(data.canvas || data.img)) { + return data; + } + options = $.extend({canvas: true}, options); + var that = this, + dfd = $.Deferred(), + img = (options.canvas && data.canvas) || data.img, + resolve = function (newImg) { + if (newImg && (newImg.width !== img.width || + newImg.height !== img.height || + options.forceResize)) { + data[newImg.getContext ? 'canvas' : 'img'] = newImg; + } + data.preview = newImg; + dfd.resolveWith(that, [data]); + }, + thumbnail; + if (data.exif) { + if (options.orientation === true) { + options.orientation = data.exif.get('Orientation'); + } + if (options.thumbnail) { + thumbnail = data.exif.get('Thumbnail'); + if (thumbnail) { + loadImage(thumbnail, resolve, options); + return dfd.promise(); + } + } + } + if (img) { + resolve(loadImage.scale(img, options)); + return dfd.promise(); + } + return data; + }, + + // Saves the processed image given as data.canvas + // inplace at data.index of data.files: + saveImage: function (data, options) { + if (!data.canvas || options.disabled) { + return data; + } + var that = this, + file = data.files[data.index], + dfd = $.Deferred(); + if (data.canvas.toBlob) { + data.canvas.toBlob( + function (blob) { + if (!blob.name) { + if (file.type === blob.type) { + blob.name = file.name; + } else if (file.name) { + blob.name = file.name.replace( + /\..+$/, + '.' + blob.type.substr(6) + ); + } + } + // Don't restore invalid meta data: + if (file.type !== blob.type) { + delete data.imageHead; + } + // Store the created blob at the position + // of the original file in the files list: + data.files[data.index] = blob; + dfd.resolveWith(that, [data]); + }, + options.type || file.type, + options.quality + ); + } else { + return data; + } + return dfd.promise(); + }, + + loadImageMetaData: function (data, options) { + if (options.disabled) { + return data; + } + var that = this, + dfd = $.Deferred(); + loadImage.parseMetaData(data.files[data.index], function (result) { + $.extend(data, result); + dfd.resolveWith(that, [data]); + }, options); + return dfd.promise(); + }, + + saveImageMetaData: function (data, options) { + if (!(data.imageHead && data.canvas && + data.canvas.toBlob && !options.disabled)) { + return data; + } + var file = data.files[data.index], + blob = new Blob([ + data.imageHead, + // Resized images always have a head size of 20 bytes, + // including the JPEG marker and a minimal JFIF header: + this._blobSlice.call(file, 20) + ], {type: file.type}); + blob.name = file.name; + data.files[data.index] = blob; + return data; + }, + + // Sets the resized version of the image as a property of the + // file object, must be called after "saveImage": + setImage: function (data, options) { + if (data.preview && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.preview; + } + return data; + }, + + deleteImageReferences: function (data, options) { + if (!options.disabled) { + delete data.img; + delete data.canvas; + delete data.preview; + delete data.imageHead; + } + return data; + } + + } + + }); + +})); diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js new file mode 100644 index 0000000..af0a00b --- /dev/null +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js @@ -0,0 +1,152 @@ +/* + * jQuery File Upload jQuery UI Plugin 8.7.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery', './jquery.fileupload-ui'], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + processdone: function (e, data) { + data.context.find('.start').button('enable'); + }, + progress: function (e, data) { + if (data.context) { + data.context.find('.progress').progressbar( + 'option', + 'value', + parseInt(data.loaded / data.total * 100, 10) + ); + } + }, + progressall: function (e, data) { + var $this = $(this); + $this.find('.fileupload-progress') + .find('.progress').progressbar( + 'option', + 'value', + parseInt(data.loaded / data.total * 100, 10) + ).end() + .find('.progress-extended').each(function () { + $(this).html( + ($this.data('blueimp-fileupload') || + $this.data('fileupload')) + ._renderExtendedProgress(data) + ); + }); + } + }, + + _renderUpload: function (func, files) { + var node = this._super(func, files), + showIconText = $(window).width() > 480; + node.find('.progress').empty().progressbar(); + node.find('.start').button({ + icons: {primary: 'ui-icon-circle-arrow-e'}, + text: showIconText + }); + node.find('.cancel').button({ + icons: {primary: 'ui-icon-cancel'}, + text: showIconText + }); + if (node.hasClass('fade')) { + node.hide(); + } + return node; + }, + + _renderDownload: function (func, files) { + var node = this._super(func, files), + showIconText = $(window).width() > 480; + node.find('.delete').button({ + icons: {primary: 'ui-icon-trash'}, + text: showIconText + }); + if (node.hasClass('fade')) { + node.hide(); + } + return node; + }, + + _startHandler: function (e) { + $(e.currentTarget).button('disable'); + this._super(e); + }, + + _transition: function (node) { + var deferred = $.Deferred(); + if (node.hasClass('fade')) { + node.fadeToggle( + this.options.transitionDuration, + this.options.transitionEasing, + function () { + deferred.resolveWith(node); + } + ); + } else { + deferred.resolveWith(node); + } + return deferred; + }, + + _create: function () { + this._super(); + this.element + .find('.fileupload-buttonbar') + .find('.fileinput-button').each(function () { + var input = $(this).find('input:file').detach(); + $(this) + .button({icons: {primary: 'ui-icon-plusthick'}}) + .append(input); + }) + .end().find('.start') + .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) + .end().find('.cancel') + .button({icons: {primary: 'ui-icon-cancel'}}) + .end().find('.delete') + .button({icons: {primary: 'ui-icon-trash'}}) + .end().find('.progress').progressbar(); + }, + + _destroy: function () { + this.element + .find('.fileupload-buttonbar') + .find('.fileinput-button').each(function () { + var input = $(this).find('input:file').detach(); + $(this) + .button('destroy') + .append(input); + }) + .end().find('.start') + .button('destroy') + .end().find('.cancel') + .button('destroy') + .end().find('.delete') + .button('destroy') + .end().find('.progress').progressbar('destroy'); + this._super(); + } + + }); + +})); diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js new file mode 100644 index 0000000..3764b27 --- /dev/null +++ b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js @@ -0,0 +1,106 @@ +/* + * jQuery File Upload Video Preview Plugin 1.0.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadVideo', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + disabled: '@disableVideoPreview' + }, + { + action: 'setVideo', + name: '@videoPreviewName', + disabled: '@disableVideoPreview' + } + ); + + // The File Upload Video Preview plugin extends the fileupload widget + // with video preview functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of video files to load, + // matched against the file type: + loadVideoFileTypes: /^video\/.*$/ + }, + + _videoElement: document.createElement('video'), + + processActions: { + + // Loads the video file given via data.files and data.index + // as video element if the browser supports playing it. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadVideo: function (data, options) { + if (options.disabled) { + return data; + } + var file = data.files[data.index], + url, + video; + if (this._videoElement.canPlayType && + this._videoElement.canPlayType(file.type) && + ($.type(options.maxFileSize) !== 'number' || + file.size <= options.maxFileSize) && + (!options.fileTypes || + options.fileTypes.test(file.type))) { + url = loadImage.createObjectURL(file); + if (url) { + video = this._videoElement.cloneNode(false); + video.src = url; + video.controls = true; + data.video = video; + return data; + } + } + return data; + }, + + // Sets the video element as a property of the file object: + setVideo: function (data, options) { + if (data.video && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.video; + } + return data; + } + + } + + }); + +})); diff --git a/vendor/assets/stylesheets/jquery.fileupload-noscript.css b/vendor/assets/stylesheets/jquery.fileupload-noscript.css new file mode 100644 index 0000000..e716fa9 --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fileupload-noscript.css @@ -0,0 +1,22 @@ +@charset "UTF-8"; +/* +* jQuery File Upload Plugin NoScript CSS 1.2.0 +* https://github.com/blueimp/jQuery-File-Upload +* +* Copyright 2013, Sebastian Tschan +* https://blueimp.net +* +* Licensed under the MIT license: +* http://www.opensource.org/licenses/MIT +*/ + +.fileinput-button input { + position: static; + opacity: 1; + filter: none; + font-size: inherit; + direction: inherit; +} +.fileinput-button span { + display: none; +} \ No newline at end of file diff --git a/vendor/assets/stylesheets/jquery.fileupload-ui-noscript.css b/vendor/assets/stylesheets/jquery.fileupload-ui-noscript.css new file mode 100644 index 0000000..87f110c --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fileupload-ui-noscript.css @@ -0,0 +1,17 @@ +@charset "UTF-8"; +/* + * jQuery File Upload UI Plugin NoScript CSS 8.8.5 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2012, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileinput-button i, +.fileupload-buttonbar .delete, +.fileupload-buttonbar .toggle { + display: none; +} diff --git a/vendor/assets/stylesheets/jquery.fileupload.css b/vendor/assets/stylesheets/jquery.fileupload.css new file mode 100644 index 0000000..fb6044d --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fileupload.css @@ -0,0 +1,36 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Plugin CSS 1.3.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileinput-button { + position: relative; + overflow: hidden; +} +.fileinput-button input { + position: absolute; + top: 0; + right: 0; + margin: 0; + opacity: 0; + -ms-filter: 'alpha(opacity=0)'; + font-size: 200px; + direction: ltr; + cursor: pointer; +} + +/* Fixes for IE < 8 */ +@media screen\9 { + .fileinput-button input { + filter: alpha(opacity=0); + font-size: 100%; + height: 100%; + } +} From c4a0bd590b5af0cfdd0e44999a44c69ca132f806 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:53:50 +0100 Subject: [PATCH 14/18] Remove old files. --- .../jquery-fileupload/jquery.fileupload-fp.js | 227 ------------------ .../jquery.fileupload-resize.js | 212 ---------------- 2 files changed, 439 deletions(-) delete mode 100644 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-fp.js delete mode 100755 vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-resize.js diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-fp.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-fp.js deleted file mode 100644 index c782f1e..0000000 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-fp.js +++ /dev/null @@ -1,227 +0,0 @@ -/* - * jQuery File Upload File Processing Plugin 1.2.3 - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2012, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window, document */ - -(function (factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define([ - 'jquery', - 'load-image', - 'canvas-to-blob', - './jquery.fileupload' - ], factory); - } else { - // Browser globals: - factory( - window.jQuery, - window.loadImage - ); - } -}(function ($, loadImage) { - 'use strict'; - - // The File Upload FP version extends the fileupload widget - // with file processing functionality: - $.widget('blueimp.fileupload', $.blueimp.fileupload, { - - options: { - // The list of file processing actions: - process: [ - /* - { - action: 'load', - fileTypes: /^image\/(gif|jpeg|png)$/, - maxFileSize: 20000000 // 20MB - }, - { - action: 'resize', - maxWidth: 1920, - maxHeight: 1200, - minWidth: 800, - minHeight: 600 - }, - { - action: 'save' - } - */ - ], - - // The add callback is invoked as soon as files are added to the - // fileupload widget (via file input selection, drag & drop or add - // API call). See the basic file upload widget for more information: - add: function (e, data) { - if (data.autoUpload || (data.autoUpload !== false && - ($(this).data('blueimp-fileupload') || - $(this).data('fileupload')).options.autoUpload)) { - $(this).fileupload('process', data).done(function () { - data.submit(); - }); - } - } - }, - - processActions: { - // Loads the image given via data.files and data.index - // as img element if the browser supports canvas. - // Accepts the options fileTypes (regular expression) - // and maxFileSize (integer) to limit the files to load: - load: function (data, options) { - var that = this, - file = data.files[data.index], - dfd = $.Deferred(); - if (window.HTMLCanvasElement && - window.HTMLCanvasElement.prototype.toBlob && - ($.type(options.maxFileSize) !== 'number' || - file.size < options.maxFileSize) && - (!options.fileTypes || - options.fileTypes.test(file.type))) { - loadImage( - file, - function (img) { - if (!img.src) { - return dfd.rejectWith(that, [data]); - } - data.img = img; - dfd.resolveWith(that, [data]); - } - ); - } else { - dfd.rejectWith(that, [data]); - } - return dfd.promise(); - }, - // Resizes the image given as data.img and updates - // data.canvas with the resized image as canvas element. - // Accepts the options maxWidth, maxHeight, minWidth and - // minHeight to scale the given image: - resize: function (data, options) { - var img = data.img, - canvas; - options = $.extend({canvas: true}, options); - if (img) { - canvas = loadImage.scale(img, options); - if (canvas.width !== img.width || - canvas.height !== img.height) { - data.canvas = canvas; - } - } - return data; - }, - // Saves the processed image given as data.canvas - // inplace at data.index of data.files: - save: function (data, options) { - // Do nothing if no processing has happened: - if (!data.canvas) { - return data; - } - var that = this, - file = data.files[data.index], - name = file.name, - dfd = $.Deferred(), - callback = function (blob) { - if (!blob.name) { - if (file.type === blob.type) { - blob.name = file.name; - } else if (file.name) { - blob.name = file.name.replace( - /\..+$/, - '.' + blob.type.substr(6) - ); - } - } - // Store the created blob at the position - // of the original file in the files list: - data.files[data.index] = blob; - dfd.resolveWith(that, [data]); - }; - // Use canvas.mozGetAsFile directly, to retain the filename, as - // Gecko doesn't support the filename option for FormData.append: - if (data.canvas.mozGetAsFile) { - callback(data.canvas.mozGetAsFile( - (/^image\/(jpeg|png)$/.test(file.type) && name) || - ((name && name.replace(/\..+$/, '')) || - 'blob') + '.png', - file.type - )); - } else { - data.canvas.toBlob(callback, file.type); - } - return dfd.promise(); - } - }, - - // Resizes the file at the given index and stores the created blob at - // the original position of the files list, returns a Promise object: - _processFile: function (files, index, options) { - var that = this, - dfd = $.Deferred().resolveWith(that, [{ - files: files, - index: index - }]), - chain = dfd.promise(); - that._processing += 1; - $.each(options.process, function (i, settings) { - chain = chain.pipe(function (data) { - return that.processActions[settings.action] - .call(this, data, settings); - }); - }); - chain.always(function () { - that._processing -= 1; - if (that._processing === 0) { - that.element - .removeClass('fileupload-processing'); - } - }); - if (that._processing === 1) { - that.element.addClass('fileupload-processing'); - } - return chain; - }, - - // Processes the files given as files property of the data parameter, - // returns a Promise object that allows to bind a done handler, which - // will be invoked after processing all files (inplace) is done: - process: function (data) { - var that = this, - options = $.extend({}, this.options, data); - if (options.process && options.process.length && - this._isXHRUpload(options)) { - $.each(data.files, function (index, file) { - that._processingQueue = that._processingQueue.pipe( - function () { - var dfd = $.Deferred(); - that._processFile(data.files, index, options) - .always(function () { - dfd.resolveWith(that); - }); - return dfd.promise(); - } - ); - }); - } - return this._processingQueue; - }, - - _create: function () { - this._super(); - this._processing = 0; - this._processingQueue = $.Deferred().resolveWith(this) - .promise(); - } - - }); - -})); diff --git a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-resize.js b/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-resize.js deleted file mode 100755 index ae5c5be..0000000 --- a/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-resize.js +++ /dev/null @@ -1,212 +0,0 @@ -/* - * jQuery File Upload Image Resize Plugin 1.1.2 - * https://github.com/blueimp/jQuery-File-Upload - * - * Copyright 2013, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window */ - -(function (factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define([ - 'jquery', - 'load-image', - 'canvas-to-blob', - './jquery.fileupload-process' - ], factory); - } else { - // Browser globals: - factory( - window.jQuery, - window.loadImage - ); - } -}(function ($, loadImage) { - 'use strict'; - - // Prepend to the default processQueue: - $.blueimp.fileupload.prototype.options.processQueue.unshift( - { - action: 'loadImage', - fileTypes: '@loadImageFileTypes', - maxFileSize: '@loadImageMaxFileSize', - noRevoke: '@loadImageNoRevoke', - disabled: '@disableImageLoad' - }, - { - action: 'resizeImage', - maxWidth: '@imageMaxWidth', - maxHeight: '@imageMaxHeight', - minWidth: '@imageMinWidth', - minHeight: '@imageMinHeight', - crop: '@imageCrop', - disabled: '@disableImageResize' - }, - { - action: 'saveImage', - disabled: '@disableImageResize' - }, - { - action: 'resizeImage', - maxWidth: '@previewMaxWidth', - maxHeight: '@previewMaxHeight', - minWidth: '@previewMinWidth', - minHeight: '@previewMinHeight', - crop: '@previewCrop', - canvas: '@previewAsCanvas', - disabled: '@disableImagePreview' - }, - { - action: 'setImage', - // The name of the property the resized image - // is saved as on the associated file object: - name: 'preview', - disabled: '@disableImagePreview' - } - ); - - // The File Upload Resize plugin extends the fileupload widget - // with image resize functionality: - $.widget('blueimp.fileupload', $.blueimp.fileupload, { - - options: { - // The regular expression for the types of images to load: - // matched against the file type: - loadImageFileTypes: /^image\/(gif|jpeg|png)$/, - // The maximum file size of images to load: - loadImageMaxFileSize: 5000000, // 5MB - // The maximum width of resized images: - imageMaxWidth: 1920, - // The maximum height of resized images: - imageMaxHeight: 1080, - // Define if resized images should be cropped or only scaled: - imageCrop: false, - // Disable the resize image functionality by default: - disableImageResize: true, - // The maximum width of the preview images: - previewMaxWidth: 80, - // The maximum height of the preview images: - previewMaxHeight: 80, - // Define if preview images should be cropped or only scaled: - previewCrop: false, - // Define if preview images should be resized as canvas elements: - previewAsCanvas: true - }, - - processActions: { - - // Loads the image given via data.files and data.index - // as img element if the browser supports canvas. - // Accepts the options fileTypes (regular expression) - // and maxFileSize (integer) to limit the files to load: - loadImage: function (data, options) { - if (options.disabled) { - return data; - } - var that = this, - file = data.files[data.index], - dfd = $.Deferred(); - if (($.type(options.maxFileSize) === 'number' && - file.size > options.maxFileSize) || - (options.fileTypes && - !options.fileTypes.test(file.type)) || - !loadImage( - file, - function (img) { - if (!img.src) { - return dfd.rejectWith(that, [data]); - } - data.img = img; - dfd.resolveWith(that, [data]); - }, - options - )) { - dfd.rejectWith(that, [data]); - } - return dfd.promise(); - }, - - // Resizes the image given as data.canvas or data.img - // and updates data.canvas or data.img with the resized image. - // Accepts the options maxWidth, maxHeight, minWidth, - // minHeight, canvas and crop: - resizeImage: function (data, options) { - options = $.extend({canvas: true}, options); - var img = (options.canvas && data.canvas) || data.img, - canvas; - if (img && !options.disabled) { - canvas = loadImage.scale(img, options); - if (canvas && (canvas.width !== img.width || - canvas.height !== img.height)) { - data[canvas.getContext ? 'canvas' : 'img'] = canvas; - } - } - return data; - }, - - // Saves the processed image given as data.canvas - // inplace at data.index of data.files: - saveImage: function (data, options) { - if (!data.canvas || options.disabled) { - return data; - } - var that = this, - file = data.files[data.index], - name = file.name, - dfd = $.Deferred(), - callback = function (blob) { - if (!blob.name) { - if (file.type === blob.type) { - blob.name = file.name; - } else if (file.name) { - blob.name = file.name.replace( - /\..+$/, - '.' + blob.type.substr(6) - ); - } - } - // Store the created blob at the position - // of the original file in the files list: - data.files[data.index] = blob; - dfd.resolveWith(that, [data]); - }; - // Use canvas.mozGetAsFile directly, to retain the filename, as - // Gecko doesn't support the filename option for FormData.append: - if (data.canvas.mozGetAsFile) { - callback(data.canvas.mozGetAsFile( - (/^image\/(jpeg|png)$/.test(file.type) && name) || - ((name && name.replace(/\..+$/, '')) || - 'blob') + '.png', - file.type - )); - } else if (data.canvas.toBlob) { - data.canvas.toBlob(callback, file.type); - } else { - return data; - } - return dfd.promise(); - }, - - // Sets the resized version of the image as a property of the - // file object, must be called after "saveImage": - setImage: function (data, options) { - var img = data.canvas || data.img; - if (img && !options.disabled) { - data.files[data.index][options.name] = img; - } - return data; - } - - } - - }); - -})); From 11773d20bc012bb1d2523451274482e1444d2eaf Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:55:09 +0100 Subject: [PATCH 15/18] Replace scss with new updated css file. More agnostic to use plain css in vendor path. --- ...pload-ui.scss => jquery.fileupload-ui.css} | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) rename vendor/assets/stylesheets/{jquery.fileupload-ui.scss => jquery.fileupload-ui.css} (56%) diff --git a/vendor/assets/stylesheets/jquery.fileupload-ui.scss b/vendor/assets/stylesheets/jquery.fileupload-ui.css similarity index 56% rename from vendor/assets/stylesheets/jquery.fileupload-ui.scss rename to vendor/assets/stylesheets/jquery.fileupload-ui.css index 72bfcb6..76fb376 100755 --- a/vendor/assets/stylesheets/jquery.fileupload-ui.scss +++ b/vendor/assets/stylesheets/jquery.fileupload-ui.css @@ -1,6 +1,6 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin CSS 8.0 + * jQuery File Upload UI Plugin CSS 9.0.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan @@ -10,40 +10,30 @@ * http://www.opensource.org/licenses/MIT */ -.fileinput-button { - position: relative; - overflow: hidden; -} -.fileinput-button input { - position: absolute; - top: 0; - right: 0; - margin: 0; - opacity: 0; - filter: alpha(opacity=0); - transform: translate(-300px, 0) scale(4); - font-size: 23px; - direction: ltr; - cursor: pointer; -} .fileupload-buttonbar .btn, .fileupload-buttonbar .toggle { margin-bottom: 5px; } +.progress-animated .progress-bar, .progress-animated .bar { - background: url(../img/progressbar.gif) !important; + background: url("../img/progressbar.gif") !important; filter: none; } -.fileupload-loading { +.fileupload-process { float: right; + display: none; +} +.fileupload-processing .fileupload-process, +.files .processing .preview { + display: block; width: 32px; height: 32px; - background: url(../img/loading.gif) center no-repeat; + background: url("../img/loading.gif") center no-repeat; background-size: contain; - display: none; } -.fileupload-processing .fileupload-loading { - display: block; +.files audio, +.files video { + max-width: 300px; } @media (max-width: 767px) { @@ -56,4 +46,12 @@ width: 80px; word-wrap: break-word; } + .files audio, + .files video { + max-width: 80px; + } + .files img, + .files canvas { + max-width: 100%; + } } From cda400e05fea532a034bccbaa1b4c6bd6db45ace Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:55:40 +0100 Subject: [PATCH 16/18] Update index.js --- vendor/assets/javascripts/jquery-fileupload/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/index.js b/vendor/assets/javascripts/jquery-fileupload/index.js index 0cda385..a426b60 100644 --- a/vendor/assets/javascripts/jquery-fileupload/index.js +++ b/vendor/assets/javascripts/jquery-fileupload/index.js @@ -4,6 +4,10 @@ //=require jquery-fileupload/vendor/tmpl //=require jquery-fileupload/jquery.iframe-transport //=require jquery-fileupload/jquery.fileupload -//=require jquery-fileupload/jquery.fileupload-fp +//=require jquery-fileupload/jquery.fileupload-process +//=require jquery-fileupload/jquery.fileupload-image +//=require jquery-fileupload/jquery.fileupload-audio +//=require jquery-fileupload/jquery.fileupload-video +//=require jquery-fileupload/jquery.fileupload-validate //=require jquery-fileupload/jquery.fileupload-ui //=require jquery-fileupload/locale From 5cb7550ff4f49cf3ca3850bf5708f8c34dd83a34 Mon Sep 17 00:00:00 2001 From: Tobias Bohwalli Date: Fri, 28 Feb 2014 19:56:01 +0100 Subject: [PATCH 17/18] Update README. --- .gitignore | 1 + Gemfile | 3 +- README.md | 80 +++++++++++++++++---------- Rakefile | 7 +-- jquery-fileupload-rails.gemspec | 34 ++++++------ lib/jquery/fileupload/rails/upload.rb | 6 +- 6 files changed, 78 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index 4040c6c..466c187 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .bundle Gemfile.lock pkg/* +.rvmrc diff --git a/Gemfile b/Gemfile index 4e391e1..fa75df1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,3 @@ -source "http://rubygems.org" +source 'https://rubygems.org' -# Specify your gem's dependencies in jquery-fileupload-rails.gemspec gemspec diff --git a/README.md b/README.md index 4207f35..7da4ac3 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,29 @@ # jQuery File Upload for Rails -[jQuery-File-Plugin](https://github.com/blueimp/jQuery-File-Upload) is a file upload plugin written by [Sebastian Tschan](https://github.com/blueimp). jQuery File Upload features multiple file selection, drag&drop support, progress bars and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. +[jQuery-File-Plugin][1] is a file upload plugin written by [Sebastian Tschan][2]. jQuery File Upload features multiple file selection, drag&drop support, progress bars and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. -jquery-fileupload-rails is a library that integrates jQuery File Upload for Rails 3.1 Asset Pipeline (Rails 3.2 supported). +`jquery-fileupload-rails` is a library that integrates jQuery File Upload for Rails 3 and 4 Asset Pipeline. ## Plugin versions -* jQuery File Upload User Interface Plugin 6.11 -* jQuery File Upload Plugin 5.19.3 -* jQuery UI Widget 1.9.1+amd +| jQuery Plugin | Version | +|:------------------------------------------|:----------:| +| File Upload User Interface Plugin | 9.5.2 | +| File Upload Plugin | 5.40.1 | +| UI Widget | 1.10.4+amd | +| File Upload AngularJS Plugin | 2.2.0 | +| File Upload Audio Preview Plugin | 1.0.3 | +| File Upload Image Preview & Resize Plugin | 1.7.1 | +| File Upload Processing Plugin | 1.3.0 | +| File Upload Validation Plugin | 1.1.2 | +| File Upload Video Preview Plugin | 1.0.3 | ## Installing Gem +```ruby +gem 'jquery-fileupload-rails', github: 'futhr/jquery-fileupload-rails' +``` - gem "jquery-fileupload-rails" +**NOTE:** _This gem's upstream has not been maintained for long time so its recommended to fork above branch until it been merged._ ## Using the javascripts @@ -22,17 +33,21 @@ Require jquery-fileupload in your app/assets/application.js file. The snippet above will add the following js files to the mainfest file. - //= require jquery-fileupload/vendor/jquery.ui.widget - //= require jquery-fileupload/vendor/load-image - //= require jquery-fileupload/vendor/canvas-to-blob - //= require jquery-fileupload/vendor/tmpl - //= require jquery-fileupload/jquery.iframe-transport - //= require jquery-fileupload/jquery.fileupload - //= require jquery-fileupload/jquery.fileupload-fp - //= require jquery-fileupload/jquery.fileupload-ui - //= require jquery-fileupload/locale - -If you only need the basic files, just add the code below to your application.js file. [Basic setup guide](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin) + //=require jquery-fileupload/vendor/jquery.ui.widget + //=require jquery-fileupload/vendor/load-image + //=require jquery-fileupload/vendor/canvas-to-blob + //=require jquery-fileupload/vendor/tmpl + //=require jquery-fileupload/jquery.iframe-transport + //=require jquery-fileupload/jquery.fileupload + //=require jquery-fileupload/jquery.fileupload-process + //=require jquery-fileupload/jquery.fileupload-image + //=require jquery-fileupload/jquery.fileupload-audio + //=require jquery-fileupload/jquery.fileupload-video + //=require jquery-fileupload/jquery.fileupload-validate + //=require jquery-fileupload/jquery.fileupload-ui + //=require jquery-fileupload/locale + +If you only need the basic files, just add the code below to your application.js file. [Basic setup guide][3] //= require jquery-fileupload/basic @@ -48,25 +63,34 @@ Require the stylesheet file to app/assets/stylesheets/application.css *= require jquery.fileupload-ui -## Using the middleware - -The `jquery.iframe-transport` fallback transport has some special caveats regarding the response data type, http status, and character encodings. `jquery-fileupload-rails` includes a middleware that handles these inconsistencies seamlessly. If you decide to use it, create an initializer that adds the middleware to your application's middleware stack. +Additionally you can add support files: - Rails.application.config.middleware.use JQuery::FileUpload::Rails::Middleware + *= require jquery.fileupload-ui-noscript + *= require jquery.fileupload-noscript + *= require jquery.fileupload -## [Example app](https://github.com/tors/jquery-fileupload-rails-paperclip-example) -This app uses paperclip and twitter-bootstrap-rails +## Using the middleware -You can also check out Ryan Bate's RailsCast [jQuery File Upload episode](http://railscasts.com/episodes/381-jquery-file-upload). You will -need a pro account to watch it though. +The `jquery.iframe-transport` fallback transport has some special caveats regarding the response data type, http status, and character encodings. `jquery-fileupload-rails` includes a middleware that handles these inconsistencies seamlessly. If you decide to use it, create an initializer that adds the middleware to your application's middleware stack. +```ruby +Rails.application.config.middleware.use JQuery::FileUpload::Rails::Middleware +``` +You can also check out Ryan Bate's RailsCast [jQuery File Upload episode][4]. You will need a pro account to watch it though. ## Thanks -Thanks to [Sebastian Tschan](https://github.com/blueimp) for writing an awesome file upload plugin. +Thanks to [Sebastian Tschan][2] for writing an awesome file upload plugin. ## License -Copyright (c) 2012 Tors Dalid +Copyright (c) 2014 [Tors Dalid][6] and [contributors][5] -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +[1]: https://github.com/blueimp/jQuery-File-Upload +[2]: https://github.com/blueimp +[3]: https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin +[4]: http://railscasts.com/episodes/381-jquery-file-upload?view=comments +[5]: https://github.com/tors/jquery-fileupload-rails/graphs/contributors +[6]: https://github.com/tors diff --git a/Rakefile b/Rakefile index 5e69ff9..93d61f7 100644 --- a/Rakefile +++ b/Rakefile @@ -2,14 +2,13 @@ require 'bundler' Bundler::GemHelper.install_tasks -desc "Bundle the gem" +desc 'Bundle the gem' task :bundle do - sh('bundle install') + sh 'bundle install' sh 'gem build *.gemspec' sh 'gem install *.gem' sh 'rm *.gem' end task(:default).clear -task :default => :bundle - +task default: :bundle diff --git a/jquery-fileupload-rails.gemspec b/jquery-fileupload-rails.gemspec index 78b5549..d6015c1 100644 --- a/jquery-fileupload-rails.gemspec +++ b/jquery-fileupload-rails.gemspec @@ -1,24 +1,26 @@ # -*- encoding: utf-8 -*- -$:.push File.expand_path("../lib", __FILE__) -require "jquery/fileupload/rails/version" +$:.push File.expand_path('../lib', __FILE__) +require 'jquery/fileupload/rails/version' Gem::Specification.new do |s| - s.name = "jquery-fileupload-rails" + s.platform = Gem::Platform::RUBY + s.name = 'jquery-fileupload-rails' s.version = JQuery::FileUpload::Rails::VERSION - s.authors = ["Tors Dalid"] - s.email = ["cletedalid@gmail.com"] - s.homepage = "https://github.com/tors/jquery-fileupload-rails" - s.summary = %q{jQuery File Upload for Rails 3.1 Asset Pipeline} - s.description = %q{jQuery File Upload by Sebastian Tschan integrated for Rails 3.1 Asset Pipeline} + s.author = 'Tors Dalid' + s.email = 'cletedalid@gmail.com' + s.homepage = 'https://github.com/tors/jquery-fileupload-rails' + s.summary = %q{jQuery File Upload for Rails 3 and 4 Asset Pipeline} + s.description = %q{jQuery File Upload by Sebastian Tschan integrated for Rails 3 and 4 Asset Pipeline} - s.rubyforge_project = "jquery-fileupload-rails" + s.required_ruby_version = '>= 1.9.3' + s.rubyforge_project = 'jquery-fileupload-rails' - s.files = Dir["lib/**/*"] + Dir["vendor/**/*"] + ["Rakefile", "README.md"] - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } - s.require_paths = ["lib"] + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- spec/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_path = 'lib' - s.add_dependency 'railties', '>= 3.1' - s.add_dependency 'actionpack', '>= 3.1' - s.add_development_dependency 'rails', '>= 3.1' + s.add_runtime_dependency 'railties', '>= 3.1' + s.add_runtime_dependency 'actionpack', '>= 3.1' + s.add_development_dependency 'rails', '>= 3.1' end diff --git a/lib/jquery/fileupload/rails/upload.rb b/lib/jquery/fileupload/rails/upload.rb index f02d383..b849299 100644 --- a/lib/jquery/fileupload/rails/upload.rb +++ b/lib/jquery/fileupload/rails/upload.rb @@ -1,3 +1,3 @@ -require "jquery/fileupload/rails/engine" -require "jquery/fileupload/rails/version" -require "jquery/fileupload/rails/middleware" +require 'jquery/fileupload/rails/engine' +require 'jquery/fileupload/rails/version' +require 'jquery/fileupload/rails/middleware' From d9429f647f8ab5a756cb109e23dd079d3505079c Mon Sep 17 00:00:00 2001 From: Emily Castles Date: Fri, 21 Mar 2014 14:41:16 +0000 Subject: [PATCH 18/18] change load-image.js to minified version to remove parseMetaData error --- .../jquery-fileupload/vendor/load-image.js | 277 +----------------- 1 file changed, 1 insertion(+), 276 deletions(-) diff --git a/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js b/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js index c7fd674..09f3873 100644 --- a/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js +++ b/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js @@ -1,276 +1 @@ -/* - * JavaScript Load Image 1.9.0 - * https://github.com/blueimp/JavaScript-Load-Image - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/*jslint nomen: true */ -/*global define, window, document, URL, webkitURL, Blob, File, FileReader */ - -(function ($) { - 'use strict'; - - // Loads an image for a given File object. - // Invokes the callback with an img or optional canvas - // element (if supported by the browser) as parameter: - var loadImage = function (file, callback, options) { - var img = document.createElement('img'), - url, - oUrl; - img.onerror = callback; - img.onload = function () { - if (oUrl && !(options && options.noRevoke)) { - loadImage.revokeObjectURL(oUrl); - } - if (callback) { - callback(loadImage.scale(img, options)); - } - }; - if (loadImage.isInstanceOf('Blob', file) || - // Files are also Blob instances, but some browsers - // (Firefox 3.6) support the File API but not Blobs: - loadImage.isInstanceOf('File', file)) { - url = oUrl = loadImage.createObjectURL(file); - // Store the file type for resize processing: - img._type = file.type; - } else if (typeof file === 'string') { - url = file; - if (options && options.crossOrigin) { - img.crossOrigin = options.crossOrigin; - } - } else { - return false; - } - if (url) { - img.src = url; - return img; - } - return loadImage.readFile(file, function (e) { - var target = e.target; - if (target && target.result) { - img.src = target.result; - } else { - if (callback) { - callback(e); - } - } - }); - }, - // The check for URL.revokeObjectURL fixes an issue with Opera 12, - // which provides URL.createObjectURL but doesn't properly implement it: - urlAPI = (window.createObjectURL && window) || - (window.URL && URL.revokeObjectURL && URL) || - (window.webkitURL && webkitURL); - - loadImage.isInstanceOf = function (type, obj) { - // Cross-frame instanceof check - return Object.prototype.toString.call(obj) === '[object ' + type + ']'; - }; - - // Transform image coordinates, allows to override e.g. - // the canvas orientation based on the orientation option, - // gets canvas, options passed as arguments: - loadImage.transformCoordinates = function () { - return; - }; - - // Returns transformed options, allows to override e.g. - // coordinate and dimension options based on the orientation: - loadImage.getTransformedOptions = function (options) { - return options; - }; - - // Canvas render method, allows to override the - // rendering e.g. to work around issues on iOS: - loadImage.renderImageToCanvas = function ( - canvas, - img, - sourceX, - sourceY, - sourceWidth, - sourceHeight, - destX, - destY, - destWidth, - destHeight - ) { - canvas.getContext('2d').drawImage( - img, - sourceX, - sourceY, - sourceWidth, - sourceHeight, - destX, - destY, - destWidth, - destHeight - ); - return canvas; - }; - - // This method is used to determine if the target image - // should be a canvas element: - loadImage.hasCanvasOption = function (options) { - return options.canvas || options.crop; - }; - - // Scales and/or crops the given image (img or canvas HTML element) - // using the given options. - // Returns a canvas object if the browser supports canvas - // and the hasCanvasOption method returns true or a canvas - // object is passed as image, else the scaled image: - loadImage.scale = function (img, options) { - options = options || {}; - var canvas = document.createElement('canvas'), - useCanvas = img.getContext || - (loadImage.hasCanvasOption(options) && canvas.getContext), - width = img.naturalWidth || img.width, - height = img.naturalHeight || img.height, - destWidth = width, - destHeight = height, - maxWidth, - maxHeight, - minWidth, - minHeight, - sourceWidth, - sourceHeight, - sourceX, - sourceY, - tmp, - scaleUp = function () { - var scale = Math.max( - (minWidth || destWidth) / destWidth, - (minHeight || destHeight) / destHeight - ); - if (scale > 1) { - destWidth = Math.ceil(destWidth * scale); - destHeight = Math.ceil(destHeight * scale); - } - }, - scaleDown = function () { - var scale = Math.min( - (maxWidth || destWidth) / destWidth, - (maxHeight || destHeight) / destHeight - ); - if (scale < 1) { - destWidth = Math.ceil(destWidth * scale); - destHeight = Math.ceil(destHeight * scale); - } - }; - if (useCanvas) { - options = loadImage.getTransformedOptions(options); - sourceX = options.left || 0; - sourceY = options.top || 0; - if (options.sourceWidth) { - sourceWidth = options.sourceWidth; - if (options.right !== undefined && options.left === undefined) { - sourceX = width - sourceWidth - options.right; - } - } else { - sourceWidth = width - sourceX - (options.right || 0); - } - if (options.sourceHeight) { - sourceHeight = options.sourceHeight; - if (options.bottom !== undefined && options.top === undefined) { - sourceY = height - sourceHeight - options.bottom; - } - } else { - sourceHeight = height - sourceY - (options.bottom || 0); - } - destWidth = sourceWidth; - destHeight = sourceHeight; - } - maxWidth = options.maxWidth; - maxHeight = options.maxHeight; - minWidth = options.minWidth; - minHeight = options.minHeight; - if (useCanvas && maxWidth && maxHeight && options.crop) { - destWidth = maxWidth; - destHeight = maxHeight; - tmp = sourceWidth / sourceHeight - maxWidth / maxHeight; - if (tmp < 0) { - sourceHeight = maxHeight * sourceWidth / maxWidth; - if (options.top === undefined && options.bottom === undefined) { - sourceY = (height - sourceHeight) / 2; - } - } else if (tmp > 0) { - sourceWidth = maxWidth * sourceHeight / maxHeight; - if (options.left === undefined && options.right === undefined) { - sourceX = (width - sourceWidth) / 2; - } - } - } else { - if (options.contain || options.cover) { - minWidth = maxWidth = maxWidth || minWidth; - minHeight = maxHeight = maxHeight || minHeight; - } - if (options.cover) { - scaleDown(); - scaleUp(); - } else { - scaleUp(); - scaleDown(); - } - } - if (useCanvas) { - canvas.width = destWidth; - canvas.height = destHeight; - loadImage.transformCoordinates( - canvas, - options - ); - return loadImage.renderImageToCanvas( - canvas, - img, - sourceX, - sourceY, - sourceWidth, - sourceHeight, - 0, - 0, - destWidth, - destHeight - ); - } - img.width = destWidth; - img.height = destHeight; - return img; - }; - - loadImage.createObjectURL = function (file) { - return urlAPI ? urlAPI.createObjectURL(file) : false; - }; - - loadImage.revokeObjectURL = function (url) { - return urlAPI ? urlAPI.revokeObjectURL(url) : false; - }; - - // Loads a given File object via FileReader interface, - // invokes the callback with the event object (load or error). - // The result can be read via event.target.result: - loadImage.readFile = function (file, callback, method) { - if (window.FileReader) { - var fileReader = new FileReader(); - fileReader.onload = fileReader.onerror = callback; - method = method || 'readAsDataURL'; - if (fileReader[method]) { - fileReader[method](file); - return fileReader; - } - } - return false; - }; - - if (typeof define === 'function' && define.amd) { - define(function () { - return loadImage; - }); - } else { - $.loadImage = loadImage; - } -}(this)); +!function(a){"use strict";var b=function(a,c,d){var e,f,g=document.createElement("img");if(g.onerror=c,g.onload=function(){!f||d&&d.noRevoke||b.revokeObjectURL(f),c&&c(b.scale(g,d))},b.isInstanceOf("Blob",a)||b.isInstanceOf("File",a))e=f=b.createObjectURL(a),g._type=a.type;else{if("string"!=typeof a)return!1;e=a,d&&d.crossOrigin&&(g.crossOrigin=d.crossOrigin)}return e?(g.src=e,g):b.readFile(a,function(a){var b=a.target;b&&b.result?g.src=b.result:c&&c(a)})},c=window.createObjectURL&&window||window.URL&&URL.revokeObjectURL&&URL||window.webkitURL&&webkitURL;b.isInstanceOf=function(a,b){return Object.prototype.toString.call(b)==="[object "+a+"]"},b.transformCoordinates=function(){},b.getTransformedOptions=function(a){return a},b.renderImageToCanvas=function(a,b,c,d,e,f,g,h,i,j){return a.getContext("2d").drawImage(b,c,d,e,f,g,h,i,j),a},b.hasCanvasOption=function(a){return a.canvas||a.crop},b.scale=function(a,c){c=c||{};var d,e,f,g,h,i,j,k,l,m=document.createElement("canvas"),n=a.getContext||b.hasCanvasOption(c)&&m.getContext,o=a.naturalWidth||a.width,p=a.naturalHeight||a.height,q=o,r=p,s=function(){var a=Math.max((f||q)/q,(g||r)/r);a>1&&(q=Math.ceil(q*a),r=Math.ceil(r*a))},t=function(){var a=Math.min((d||q)/q,(e||r)/r);1>a&&(q=Math.ceil(q*a),r=Math.ceil(r*a))};return n&&(c=b.getTransformedOptions(c),j=c.left||0,k=c.top||0,c.sourceWidth?(h=c.sourceWidth,void 0!==c.right&&void 0===c.left&&(j=o-h-c.right)):h=o-j-(c.right||0),c.sourceHeight?(i=c.sourceHeight,void 0!==c.bottom&&void 0===c.top&&(k=p-i-c.bottom)):i=p-k-(c.bottom||0),q=h,r=i),d=c.maxWidth,e=c.maxHeight,f=c.minWidth,g=c.minHeight,n&&d&&e&&c.crop?(q=d,r=e,l=h/i-d/e,0>l?(i=e*h/d,void 0===c.top&&void 0===c.bottom&&(k=(p-i)/2)):l>0&&(h=d*i/e,void 0===c.left&&void 0===c.right&&(j=(o-h)/2))):((c.contain||c.cover)&&(f=d=d||f,g=e=e||g),c.cover?(t(),s()):(s(),t())),n?(m.width=q,m.height=r,b.transformCoordinates(m,c),b.renderImageToCanvas(m,a,j,k,h,i,0,0,q,r)):(a.width=q,a.height=r,a)},b.createObjectURL=function(a){return c?c.createObjectURL(a):!1},b.revokeObjectURL=function(a){return c?c.revokeObjectURL(a):!1},b.readFile=function(a,b,c){if(window.FileReader){var d=new FileReader;if(d.onload=d.onerror=b,c=c||"readAsDataURL",d[c])return d[c](a),d}return!1},"function"==typeof define&&define.amd?define(function(){return b}):a.loadImage=b}(this),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";if(window.navigator&&window.navigator.platform&&/iP(hone|od|ad)/.test(window.navigator.platform)){var b=a.renderImageToCanvas;a.detectSubsampling=function(a){var b,c;return a.width*a.height>1048576?(b=document.createElement("canvas"),b.width=b.height=1,c=b.getContext("2d"),c.drawImage(a,-a.width+1,0),0===c.getImageData(0,0,1,1).data[3]):!1},a.detectVerticalSquash=function(a,b){var c,d,e,f,g,h=a.naturalHeight||a.height,i=document.createElement("canvas"),j=i.getContext("2d");for(b&&(h/=2),i.width=1,i.height=h,j.drawImage(a,0,0),c=j.getImageData(0,0,1,h).data,d=0,e=h,f=h;f>d;)g=c[4*(f-1)+3],0===g?e=f:d=f,f=e+d>>1;return f/h||1},a.renderImageToCanvas=function(c,d,e,f,g,h,i,j,k,l){if("image/jpeg"===d._type){var m,n,o,p,q=c.getContext("2d"),r=document.createElement("canvas"),s=1024,t=r.getContext("2d");if(r.width=s,r.height=s,q.save(),m=a.detectSubsampling(d),m&&(e/=2,f/=2,g/=2,h/=2),n=a.detectVerticalSquash(d,m),m||1!==n){for(f*=n,k=Math.ceil(s*k/g),l=Math.ceil(s*l/h/n),j=0,p=0;h>p;){for(i=0,o=0;g>o;)t.clearRect(0,0,s,s),t.drawImage(d,e,f,g,h,-o,-p,g,h),q.drawImage(r,0,0,s,s,i,j,k,l),o+=s,i+=k;p+=s,j+=l}return q.restore(),c}}return b(c,d,e,f,g,h,i,j,k,l)}}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";var b=a.hasCanvasOption;a.hasCanvasOption=function(a){return b(a)||a.orientation},a.transformCoordinates=function(a,b){var c=a.getContext("2d"),d=a.width,e=a.height,f=b.orientation;if(f)switch(f>4&&(a.width=e,a.height=d),f){case 2:c.translate(d,0),c.scale(-1,1);break;case 3:c.translate(d,e),c.rotate(Math.PI);break;case 4:c.translate(0,e),c.scale(1,-1);break;case 5:c.rotate(.5*Math.PI),c.scale(1,-1);break;case 6:c.rotate(.5*Math.PI),c.translate(0,-e);break;case 7:c.rotate(.5*Math.PI),c.translate(d,-e),c.scale(-1,1);break;case 8:c.rotate(-.5*Math.PI),c.translate(-d,0)}},a.getTransformedOptions=function(a){if(!a.orientation||1===a.orientation)return a;var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=a[b]);switch(a.orientation){case 2:c.left=a.right,c.right=a.left;break;case 3:c.left=a.right,c.top=a.bottom,c.right=a.left,c.bottom=a.top;break;case 4:c.top=a.bottom,c.bottom=a.top;break;case 5:c.left=a.top,c.top=a.left,c.right=a.bottom,c.bottom=a.right;break;case 6:c.left=a.top,c.top=a.right,c.right=a.bottom,c.bottom=a.left;break;case 7:c.left=a.bottom,c.top=a.right,c.right=a.top,c.bottom=a.left;break;case 8:c.left=a.bottom,c.top=a.left,c.right=a.top,c.bottom=a.right}return a.orientation>4&&(c.maxWidth=a.maxHeight,c.maxHeight=a.maxWidth,c.minWidth=a.minHeight,c.minHeight=a.minWidth,c.sourceWidth=a.sourceHeight,c.sourceHeight=a.sourceWidth),c}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";var b=window.Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice);a.blobSlice=b&&function(){var a=this.slice||this.webkitSlice||this.mozSlice;return a.apply(this,arguments)},a.metaDataParsers={jpeg:{65505:[]}},a.parseMetaData=function(b,c,d){d=d||{};var e=this,f=d.maxMetaDataSize||262144,g={},h=!(window.DataView&&b&&b.size>=12&&"image/jpeg"===b.type&&a.blobSlice);(h||!a.readFile(a.blobSlice.call(b,0,f),function(b){if(b.target.error)return console.log(b.target.error),c(g),void 0;var f,h,i,j,k=b.target.result,l=new DataView(k),m=2,n=l.byteLength-4,o=m;if(65496===l.getUint16(0)){for(;n>m&&(f=l.getUint16(m),f>=65504&&65519>=f||65534===f);){if(h=l.getUint16(m+2)+2,m+h>l.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(i=a.metaDataParsers.jpeg[f])for(j=0;j6&&(g.imageHead=k.slice?k.slice(0,o):new Uint8Array(k).subarray(0,o))}else console.log("Invalid JPEG file: Missing JPEG marker.");c(g)},"readAsArrayBuffer"))&&c(g)}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image","load-image-meta"],a):a(window.loadImage)}(function(a){"use strict";a.ExifMap=function(){return this},a.ExifMap.prototype.map={Orientation:274},a.ExifMap.prototype.get=function(a){return this[a]||this[this.map[a]]},a.getExifThumbnail=function(a,b,c){var d,e,f;if(!c||b+c>a.byteLength)return console.log("Invalid Exif data: Invalid thumbnail data."),void 0;for(d=[],e=0;c>e;e+=1)f=a.getUint8(b+e),d.push((16>f?"0":"")+f.toString(16));return"data:image/jpeg,%"+d.join("%")},a.exifTagTypes={1:{getValue:function(a,b){return a.getUint8(b)},size:1},2:{getValue:function(a,b){return String.fromCharCode(a.getUint8(b))},size:1,ascii:!0},3:{getValue:function(a,b,c){return a.getUint16(b,c)},size:2},4:{getValue:function(a,b,c){return a.getUint32(b,c)},size:4},5:{getValue:function(a,b,c){return a.getUint32(b,c)/a.getUint32(b+4,c)},size:8},9:{getValue:function(a,b,c){return a.getInt32(b,c)},size:4},10:{getValue:function(a,b,c){return a.getInt32(b,c)/a.getInt32(b+4,c)},size:8}},a.exifTagTypes[7]=a.exifTagTypes[1],a.getExifValue=function(b,c,d,e,f,g){var h,i,j,k,l,m,n=a.exifTagTypes[e];if(!n)return console.log("Invalid Exif data: Invalid tag type."),void 0;if(h=n.size*f,i=h>4?c+b.getUint32(d+8,g):d+8,i+h>b.byteLength)return console.log("Invalid Exif data: Invalid data offset."),void 0;if(1===f)return n.getValue(b,i,g);for(j=[],k=0;f>k;k+=1)j[k]=n.getValue(b,i+k*n.size,g);if(n.ascii){for(l="",k=0;ka.byteLength)return console.log("Invalid Exif data: Invalid directory offset."),void 0;if(f=a.getUint16(c,d),g=c+2+12*f,g+4>a.byteLength)return console.log("Invalid Exif data: Invalid directory size."),void 0;for(h=0;f>h;h+=1)this.parseExifTag(a,b,c+2+12*h,d,e);return a.getUint32(g,d)},a.parseExifData=function(b,c,d,e,f){if(!f.disableExif){var g,h,i,j=c+10;if(1165519206===b.getUint32(c+4)){if(j+8>b.byteLength)return console.log("Invalid Exif data: Invalid segment size."),void 0;if(0!==b.getUint16(c+8))return console.log("Invalid Exif data: Missing byte alignment offset."),void 0;switch(b.getUint16(j)){case 18761:g=!0;break;case 19789:g=!1;break;default:return console.log("Invalid Exif data: Invalid byte alignment marker."),void 0}if(42!==b.getUint16(j+2,g))return console.log("Invalid Exif data: Missing TIFF marker."),void 0;h=b.getUint32(j+4,g),e.exif=new a.ExifMap,h=a.parseExifTags(b,j,j+h,g,e),h&&!f.disableExifThumbnail&&(i={exif:{}},h=a.parseExifTags(b,j,j+h,g,i),i.exif[513]&&(e.exif.Thumbnail=a.getExifThumbnail(b,j+i.exif[513],i.exif[514]))),e.exif[34665]&&!f.disableExifSub&&a.parseExifTags(b,j,j+e.exif[34665],g,e),e.exif[34853]&&!f.disableExifGps&&a.parseExifTags(b,j,j+e.exif[34853],g,e)}}},a.metaDataParsers.jpeg[65505].push(a.parseExifData)}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image","load-image-exif"],a):a(window.loadImage)}(function(a){"use strict";a.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},a.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},a.ExifMap.prototype.getText=function(a){var b=this.get(a);switch(a){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[a][b];case"ExifVersion":case"FlashpixVersion":return String.fromCharCode(b[0],b[1],b[2],b[3]);case"ComponentsConfiguration":return this.stringValues[a][b[0]]+this.stringValues[a][b[1]]+this.stringValues[a][b[2]]+this.stringValues[a][b[3]];case"GPSVersionID":return b[0]+"."+b[1]+"."+b[2]+"."+b[3]}return String(b)},function(a){var b,c=a.tags,d=a.map;for(b in c)c.hasOwnProperty(b)&&(d[c[b]]=b)}(a.ExifMap.prototype),a.ExifMap.prototype.getAll=function(){var a,b,c={};for(a in this)this.hasOwnProperty(a)&&(b=this.tags[a],b&&(c[b]=this.getText(b)));return c}}); \ No newline at end of file