diff options
54 files changed, 913 insertions, 1117 deletions
diff --git a/library/blueimp_upload/.gitignore b/library/blueimp_upload/.gitignore deleted file mode 100644 index 29a41a8c4..000000000 --- a/library/blueimp_upload/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -*.pyc -node_modules diff --git a/library/blueimp_upload/.jshintrc b/library/blueimp_upload/.jshintrc deleted file mode 100644 index 4ad82e664..000000000 --- a/library/blueimp_upload/.jshintrc +++ /dev/null @@ -1,81 +0,0 @@ -{ - "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : true, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : true, // true: Require triple equals (===) for comparison - "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() - "immed" : true, // true: Require immediate invocations to be wrapped in parens - // e.g. `(function () { } ());` - "indent" : 4, // {int} Number of spaces to use for indentation - "latedef" : true, // true: Require variables/functions to be defined before being used - "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : true, // true: Prohibit use of empty blocks - "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : "single", // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : true, // true: Require all defined variables be used - "strict" : true, // true: Requires all functions run in ES5 Strict Mode - "trailing" : true, // true: Prohibit trailing whitespaces - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements" - "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : false, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : false, // true: Tolerate functions being defined in loops - "multistr" : false, // true: Tolerate multi-line strings - "proto" : false, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : false, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : false, // Web Browser (window, document, etc) - "couch" : false, // CouchDB - "devel" : false, // Development/debugging (alert, confirm, etc) - "dojo" : false, // Dojo Toolkit - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : false, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : false, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Legacy - "nomen" : true, // true: Prohibit dangling `_` in variables - "onevar" : true, // true: Allow only one `var` statement per function - "passfail" : false, // true: Stop on first error - "white" : true, // true: Check against strict whitespace and indentation rules - - // Custom Globals - "globals" : {} // additional predefined global variables -} diff --git a/library/blueimp_upload/CONTRIBUTING.md b/library/blueimp_upload/CONTRIBUTING.md index b8708f8b6..e182f9b37 100644 --- a/library/blueimp_upload/CONTRIBUTING.md +++ b/library/blueimp_upload/CONTRIBUTING.md @@ -1,42 +1,15 @@ -# Issue Guidelines +Please follow these pull request guidelines: -The issues tracker should only be used for **bugs** or **feature requests**. - -Please post **support requests** and **general discussions** about this project to the [support forum](https://groups.google.com/d/forum/jquery-fileupload). - -## Bugs - -Please follow these guidelines before reporting a bug: - -1. **Update to the latest version** — Check if you can reproduce the issue with the latest version from the `master` branch. - -2. **Use the GitHub issue search** — check if the issue has already been reported. If it has been, please comment on the existing issue. - -3. **Isolate the demonstrable problem** — Try to reproduce the problem with the [Demo](https://blueimp.github.io/jQuery-File-Upload/) or with a reduced test case that includes the least amount of code necessary to reproduce the problem. - -4. **Provide a means to reproduce the problem** — Please provide as much details as possible, e.g. server information, browser and operating system versions, steps to reproduce the problem. If possible, provide a link to your reduced test case, e.g. via [JSFiddle](http://jsfiddle.net/). - - -## Feature requests - -Please follow the bug guidelines above for feature requests, i.e. update to the latest version and search for exising issues before posting a new request. - -Generally, feature requests might be accepted if the implementation would benefit a broader use case or the project could be considered incomplete without that feature. - -If you need help integrating this project into another framework, please post your request to the [support forum](https://groups.google.com/d/forum/jquery-fileupload). - -## Pull requests - -[Pull requests](https://help.github.com/articles/using-pull-requests) are welcome and the preferred way of accepting code contributions. +1. Update your fork to the latest upstream version. -However, if you add a server-side upload handler implementation for another framework, please continue to maintain this version in your own fork without sending a pull request. You are welcome to add a link and possibly documentation about your implementation to the [Wiki](https://github.com/blueimp/jQuery-File-Upload/wiki). +2. Follow the coding conventions of the original source files (indentation, spaces, brackets layout). -Please follow these guidelines before sending a pull request: +3. Code changes must pass JSHint validation with the `.jshintrc` settings of this project. -1. Update your fork to the latest upstream version. +4. Code changes must pass the QUnit tests defined in the `test` folder. -2. Follow the coding conventions of the original repository. Changes to one of the JavaScript source files are required to pass the [JSHint](http://www.jshint.com/) validation tool. +5. New features should be covered by accompanying QUnit tests. -3. Keep your commits as atomar as possible, i.e. create a new commit for every single bug fix or feature added. +6. Keep your commits as atomic as possible, i.e. create a new commit for every single bug fix or feature added. -4. Always add meaningfull commit messages. +7. Always add meaningful commit messages. diff --git a/library/blueimp_upload/Gruntfile.js b/library/blueimp_upload/Gruntfile.js deleted file mode 100644 index dcdb5d57a..000000000 --- a/library/blueimp_upload/Gruntfile.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * jQuery File Upload Gruntfile - * 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 - */ - -/*global module */ - -module.exports = function (grunt) { - 'use strict'; - - grunt.initConfig({ - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'Gruntfile.js', - 'js/cors/*.js', - 'js/*.js', - 'server/node/server.js', - 'test/test.js' - ] - } - }); - - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-bump-build-git'); - grunt.registerTask('test', ['jshint']); - grunt.registerTask('default', ['test']); - -}; diff --git a/library/blueimp_upload/LICENSE b/library/blueimp_upload/LICENSE new file mode 100644 index 000000000..0ecca3e8c --- /dev/null +++ b/library/blueimp_upload/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 jQuery-File-Upload Authors + +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. diff --git a/library/blueimp_upload/README.md b/library/blueimp_upload/README.md index 3aa33de42..56785b847 100644 --- a/library/blueimp_upload/README.md +++ b/library/blueimp_upload/README.md @@ -11,17 +11,6 @@ Supports cross-domain, chunked and resumable file uploads and client-side image * [How to setup the plugin on your website](https://github.com/blueimp/jQuery-File-Upload/wiki/Setup) * [How to use only the basic plugin (minimal setup guide).](https://github.com/blueimp/jQuery-File-Upload/wiki/Basic-plugin) -## Support - -* **[Support Forum](https://groups.google.com/d/forum/jquery-fileupload)** -**Support requests** and **general discussions** about the File Upload plugin can be posted to the official -[Support Forum](https://groups.google.com/d/forum/jquery-fileupload). -If your question is not directly related to the File Upload plugin, you might have a better chance to get a reply by posting to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload). - -* Bugs and Feature requests -**Bugs** and **Feature requests** can be reported using the [issues tracker](https://github.com/blueimp/jQuery-File-Upload/issues). -Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before posting. - ## Features * **Multiple file upload:** Allows to select multiple files at once and upload them simultaneously. @@ -60,28 +49,18 @@ Please read the [issue guidelines](https://github.com/blueimp/jQuery-File-Upload ### Mandatory requirements * [jQuery](https://jquery.com/) v. 1.6+ -* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included) -* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included) - -The jQuery UI widget factory is a requirement for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite. - -The jQuery Iframe Transport is required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). +* [jQuery UI widget factory](https://api.jqueryui.com/jQuery.widget/) v. 1.9+ (included): Required for the basic File Upload plugin, but very lightweight without any other dependencies from the jQuery UI suite. +* [jQuery Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) (included): Required for [browsers without XHR file upload support](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). ### Optional requirements -* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+ -* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+ -* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+ -* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+ -* [Bootstrap CSS framework](http://getbootstrap.com/) v. 3.2.0+ +* [JavaScript Templates engine](https://github.com/blueimp/JavaScript-Templates) v. 2.5.4+: Used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions. +* [JavaScript Load Image library](https://github.com/blueimp/JavaScript-Load-Image) v. 1.13.0+: Required for the image previews and resizing functionality. +* [JavaScript Canvas to Blob polyfill](https://github.com/blueimp/JavaScript-Canvas-to-Blob) v. 2.1.1+:Required for the image previews and resizing functionality. +* [blueimp Gallery](https://github.com/blueimp/Gallery) v. 2.15.1+: Used to display the uploaded images in a lightbox. +* [Bootstrap](http://getbootstrap.com/) v. 3.2.0+ * [Glyphicons](http://glyphicons.com/) -The JavaScript Templates engine is used to render the selected and uploaded files for the Basic Plus UI and jQuery UI versions. - -The JavaScript Load Image library and JavaScript Canvas to Blob polyfill are required for the image previews and resizing functionality. - -The blueimp Gallery is used to display the uploaded images in a lightbox. - -The user interface of all versions except the jQuery UI version is built with Twitter's [Bootstrap](http://getbootstrap.com/) framework and icons from [Glyphicons](http://glyphicons.com/). +The user interface of all versions except the jQuery UI version is built with [Bootstrap](http://getbootstrap.com/) and icons from [Glyphicons](http://glyphicons.com/). ### Cross-domain requirements [Cross-domain File Uploads](https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads) using the [Iframe Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/jquery.iframe-transport.js) require a redirect back to the origin server to retrieve the upload results. The [example implementation](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/main.js) makes use of [result.html](https://github.com/blueimp/jQuery-File-Upload/blob/master/cors/result.html) as a static redirect page for the origin server. @@ -89,6 +68,10 @@ The user interface of all versions except the jQuery UI version is built with Tw The repository also includes the [jQuery XDomainRequest Transport plugin](https://github.com/blueimp/jQuery-File-Upload/blob/master/js/cors/jquery.xdr-transport.js), which enables limited cross-domain AJAX requests in Microsoft Internet Explorer 8 and 9 (IE 10 supports cross-domain XHR requests). The XDomainRequest object allows GET and POST requests only and doesn't support file uploads. It is used on the [Demo](https://blueimp.github.io/jQuery-File-Upload/) to delete uploaded files from the cross-domain demo file upload service. +### Custom Backends + +You can add support for various backends by adhering to the specification [outlined here](https://github.com/blueimp/jQuery-File-Upload/wiki/JSON-Response). + ## Browsers ### Desktop browsers @@ -110,14 +93,15 @@ The File Upload plugin has been tested with and supports the following mobile br * Opera Mobile 12.0+ ### Supported features -For a detailed overview of the features supported by each browser version please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). +For a detailed overview of the features supported by each browser version, please have a look at the [Extended browser support information](https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support). -## License -Released under the [MIT license](http://www.opensource.org/licenses/MIT). +## Contributing +**Bug fixes** and **new features** can be proposed using [pull requests](https://github.com/blueimp/jQuery-File-Upload/pulls). +Please read the [contribution guidelines](https://github.com/blueimp/jQuery-File-Upload/blob/master/CONTRIBUTING.md) before submitting a pull request. -## Donations -jQuery File Upload is free software, but you can donate to support the developer, Sebastian Tschan: - -Flattr: [![Flattr](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/thing/286433/jQuery-File-Upload-Plugin) +## Support +This project is actively maintained, but there is no official support channel. +If you have a question that another developer might help you with, please post to [Stack Overflow](http://stackoverflow.com/questions/tagged/blueimp+jquery+file-upload) and tag your question with `blueimp jquery file upload`. -PayPal: [![PayPal](https://www.paypalobjects.com/WEBSCR-640-20110429-1/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PYWYSYP77KL54) +## License +Released under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/library/blueimp_upload/angularjs.html b/library/blueimp_upload/angularjs.html index 2a3ca2007..4858c8600 100644 --- a/library/blueimp_upload/angularjs.html +++ b/library/blueimp_upload/angularjs.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin AngularJS Demo 2.2.0 + * jQuery File Upload Plugin AngularJS Demo * 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 + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -157,9 +157,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -177,8 +177,8 @@ <a class="play-pause"></a> <ol class="indicator"></ol> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> -<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -207,5 +207,5 @@ <script src="js/jquery.fileupload-angular.js"></script> <!-- The main application script --> <script src="js/app.js"></script> -</body> +</body> </html> diff --git a/library/blueimp_upload/basic-plus.html b/library/blueimp_upload/basic-plus.html index 59b73b60c..9e5c2321f 100644 --- a/library/blueimp_upload/basic-plus.html +++ b/library/blueimp_upload/basic-plus.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Basic Plus Demo 1.4.0 + * jQuery File Upload Plugin Basic Plus Demo * 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 + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -86,9 +86,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -96,7 +96,7 @@ </div> </div> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -150,7 +150,7 @@ $(function () { dataType: 'json', autoUpload: false, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, - maxFileSize: 5000000, // 5 MB + maxFileSize: 999000, // Enable image resizing, except for Android and Opera, // which actually support image resizing, but fail to // send Blob objects via XHR requests: @@ -222,5 +222,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); </script> -</body> +</body> </html> diff --git a/library/blueimp_upload/basic.html b/library/blueimp_upload/basic.html index f248f4d80..c0df639b4 100644 --- a/library/blueimp_upload/basic.html +++ b/library/blueimp_upload/basic.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Basic Demo 1.3.0 + * jQuery File Upload Plugin Basic Demo * 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 + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -86,17 +86,17 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> - <li>Built with Twitter's <a href="http://twitter.github.com/bootstrap/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> + <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> </ul> </div> </div> </div> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Iframe Transport is required for browsers without support for XHR file uploads --> @@ -132,5 +132,5 @@ $(function () { .parent().addClass($.support.fileInput ? undefined : 'disabled'); }); </script> -</body> +</body> </html> diff --git a/library/blueimp_upload/blueimp-file-upload.jquery.json b/library/blueimp_upload/blueimp-file-upload.jquery.json deleted file mode 100644 index d6d8c911c..000000000 --- a/library/blueimp_upload/blueimp-file-upload.jquery.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "blueimp-file-upload", - "version": "9.8.0", - "title": "jQuery File Upload", - "author": { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], - "dependencies": { - "jquery": ">=1.6" - }, - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", - "keywords": [ - "jquery", - "file", - "upload", - "widget", - "multiple", - "selection", - "drag", - "drop", - "progress", - "preview", - "cross-domain", - "cross-site", - "chunk", - "resume", - "gae", - "go", - "python", - "php", - "bootstrap" - ], - "homepage": "https://github.com/blueimp/jQuery-File-Upload", - "docs": "https://github.com/blueimp/jQuery-File-Upload/wiki", - "demo": "https://blueimp.github.io/jQuery-File-Upload/", - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ] -} diff --git a/library/blueimp_upload/bower-version-update.js b/library/blueimp_upload/bower-version-update.js new file mode 100755 index 000000000..09ce3927e --- /dev/null +++ b/library/blueimp_upload/bower-version-update.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +'use strict'; + +var path = require('path'); +var packageJSON = require(path.join(__dirname, 'package.json')); +var bowerFile = path.join(__dirname, 'bower.json'); +var bowerJSON = require('bower-json').parse( + require(bowerFile), + {normalize: true} +); +bowerJSON.version = packageJSON.version; +require('fs').writeFileSync( + bowerFile, + JSON.stringify(bowerJSON, null, 2) + '\n' +); diff --git a/library/blueimp_upload/bower.json b/library/blueimp_upload/bower.json index c0d3d3259..90c74c792 100644 --- a/library/blueimp_upload/bower.json +++ b/library/blueimp_upload/bower.json @@ -1,8 +1,8 @@ { "name": "blueimp-file-upload", - "version": "9.8.0", + "version": "9.18.0", "title": "jQuery File Upload", - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images.", "keywords": [ "jquery", "file", @@ -40,12 +40,7 @@ "url": "git://github.com/blueimp/jQuery-File-Upload.git" }, "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], + "license": "MIT", "dependencies": { "jquery": ">=1.6", "blueimp-tmpl": ">=2.5.4", @@ -53,23 +48,7 @@ "blueimp-canvas-to-blob": ">=2.1.1" }, "main": [ - "css/jquery.fileupload.css", - "css/jquery.fileupload-ui.css", - "css/jquery.fileupload-noscript.css", - "css/jquery.fileupload-ui-noscript.css", - "js/cors/jquery.postmessage-transport.js", - "js/cors/jquery.xdr-transport.js", - "js/vendor/jquery.ui.widget.js", - "js/jquery.fileupload.js", - "js/jquery.fileupload-process.js", - "js/jquery.fileupload-validate.js", - "js/jquery.fileupload-image.js", - "js/jquery.fileupload-audio.js", - "js/jquery.fileupload-video.js", - "js/jquery.fileupload-ui.js", - "js/jquery.fileupload-jquery-ui.js", - "js/jquery.fileupload-angular.js", - "js/jquery.iframe-transport.js" + "js/jquery.fileupload.js" ], "ignore": [ "/*.*", diff --git a/library/blueimp_upload/cors/postmessage.html b/library/blueimp_upload/cors/postmessage.html index 3d1448f08..6db288cf9 100644 --- a/library/blueimp_upload/cors/postmessage.html +++ b/library/blueimp_upload/cors/postmessage.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin postMessage API 1.2.1 + * jQuery File Upload Plugin postMessage API * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -72,4 +72,4 @@ $(window).on('message', function (e) { }); </script> </body> -</html>
\ No newline at end of file +</html> diff --git a/library/blueimp_upload/cors/result.html b/library/blueimp_upload/cors/result.html index 225131495..e3d629814 100644 --- a/library/blueimp_upload/cors/result.html +++ b/library/blueimp_upload/cors/result.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery Iframe Transport Plugin Redirect Page 2.0.1 + * jQuery Iframe Transport Plugin Redirect Page * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> diff --git a/library/blueimp_upload/css/demo-ie8.css b/library/blueimp_upload/css/demo-ie8.css index 262493d08..e0e8ea9b0 100644 --- a/library/blueimp_upload/css/demo-ie8.css +++ b/library/blueimp_upload/css/demo-ie8.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS Fixes for IE<9 1.0.0 + * jQuery File Upload Demo CSS Fixes for IE<9 * 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 + * https://opensource.org/licenses/MIT */ .navigation { diff --git a/library/blueimp_upload/css/demo.css b/library/blueimp_upload/css/demo.css index 2b4d43934..d7d524df5 100644 --- a/library/blueimp_upload/css/demo.css +++ b/library/blueimp_upload/css/demo.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Demo CSS 1.1.0 + * jQuery File Upload Demo CSS * 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 + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/css/jquery.fileupload-noscript.css b/library/blueimp_upload/css/jquery.fileupload-noscript.css index 64d728fc3..2409bfb0a 100644 --- a/library/blueimp_upload/css/jquery.fileupload-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-noscript.css @@ -1,20 +1,20 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin NoScript CSS 1.2.0 + * jQuery File Upload Plugin NoScript CSS * 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 + * https://opensource.org/licenses/MIT */ .fileinput-button input { position: static; opacity: 1; filter: none; - font-size: inherit; + font-size: inherit !important; direction: inherit; } .fileinput-button span { diff --git a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css index 87f110cdb..30651acf0 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui-noscript.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin NoScript CSS 8.8.5 + * jQuery File Upload UI Plugin NoScript CSS * 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 + * https://opensource.org/licenses/MIT */ .fileinput-button i, diff --git a/library/blueimp_upload/css/jquery.fileupload-ui.css b/library/blueimp_upload/css/jquery.fileupload-ui.css index 76fb376de..9e36c42c5 100644 --- a/library/blueimp_upload/css/jquery.fileupload-ui.css +++ b/library/blueimp_upload/css/jquery.fileupload-ui.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload UI Plugin CSS 9.0.0 + * jQuery File Upload UI Plugin CSS * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ .fileupload-buttonbar .btn, diff --git a/library/blueimp_upload/css/jquery.fileupload.css b/library/blueimp_upload/css/jquery.fileupload.css index fb6044d34..8ae3b09d4 100644 --- a/library/blueimp_upload/css/jquery.fileupload.css +++ b/library/blueimp_upload/css/jquery.fileupload.css @@ -1,18 +1,19 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS 1.3.0 + * jQuery File Upload Plugin CSS * 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 + * https://opensource.org/licenses/MIT */ .fileinput-button { position: relative; overflow: hidden; + display: inline-block; } .fileinput-button input { position: absolute; @@ -21,7 +22,7 @@ margin: 0; opacity: 0; -ms-filter: 'alpha(opacity=0)'; - font-size: 200px; + font-size: 200px !important; direction: ltr; cursor: pointer; } diff --git a/library/blueimp_upload/css/style.css b/library/blueimp_upload/css/style.css index b2c60a6f1..3aee25689 100644 --- a/library/blueimp_upload/css/style.css +++ b/library/blueimp_upload/css/style.css @@ -1,13 +1,13 @@ @charset "UTF-8"; /* - * jQuery File Upload Plugin CSS Example 8.8.2 + * jQuery File Upload Plugin CSS Example * 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 + * https://opensource.org/licenses/MIT */ body { diff --git a/library/blueimp_upload/index.html b/library/blueimp_upload/index.html index f92f04aab..2a8dc1521 100644 --- a/library/blueimp_upload/index.html +++ b/library/blueimp_upload/index.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Demo 9.1.0 + * jQuery File Upload Plugin Demo * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -121,9 +121,9 @@ </div> <div class="panel-body"> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework and Icons from <a href="http://glyphicons.com/">Glyphicons</a>.</li> @@ -216,7 +216,7 @@ </tr> {% } %} </script> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included --> <script src="js/vendor/jquery.ui.widget.js"></script> <!-- The Templates plugin is included to render the upload/download listings --> @@ -251,5 +251,5 @@ <!--[if (gte IE 8)&(lt IE 10)]> <script src="js/cors/jquery.xdr-transport.js"></script> <![endif]--> -</body> +</body> </html> diff --git a/library/blueimp_upload/jquery-ui.html b/library/blueimp_upload/jquery-ui.html index d61ee5233..83fe9acd1 100644 --- a/library/blueimp_upload/jquery-ui.html +++ b/library/blueimp_upload/jquery-ui.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin jQuery UI Demo 9.1.0 + * jQuery File Upload Plugin jQuery UI Demo * 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 + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -127,9 +127,9 @@ <br> <h3>Demo Notes</h3> <ul> - <li>The maximum file size for uploads in this demo is <strong>5 MB</strong> (default file size is unlimited).</li> + <li>The maximum file size for uploads in this demo is <strong>999 KB</strong> (default file size is unlimited).</li> <li>Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in this demo (by default there is no file type restriction).</li> - <li>Uploaded files will be deleted automatically after <strong>5 minutes</strong> (demo setting).</li> + <li>Uploaded files will be deleted automatically after <strong>5 minutes or less</strong> (demo files are stored in memory).</li> <li>You can <strong>drag & drop</strong> files from your desktop on this webpage (see <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).</li> <li>Please refer to the <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a> and <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a> for more information.</li> <li>Built with <a href="https://jqueryui.com">jQuery UI</a>.</li> @@ -199,8 +199,8 @@ </tr> {% } %} </script> -<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> -<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> +<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <!-- The Templates plugin is included to render the upload/download listings --> <script src="//blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> @@ -246,5 +246,5 @@ $('#theme-switcher').change(function () { <!--[if (gte IE 8)&(lt IE 10)]> <script src="js/cors/jquery.xdr-transport.js"></script> <![endif]--> -</body> +</body> </html> diff --git a/library/blueimp_upload/js/app.js b/library/blueimp_upload/js/app.js index 47b4f923b..e6b7bce3e 100644 --- a/library/blueimp_upload/js/app.js +++ b/library/blueimp_upload/js/app.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Plugin Angular JS Example 1.2.1 + * jQuery File Upload Plugin Angular JS Example * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ /* global window, angular */ -(function () { +;(function () { 'use strict'; var isOnGitHub = window.location.hostname === 'blueimp.github.io', @@ -37,7 +37,7 @@ // send Blob objects via XHR requests: disableImageResize: /Android(?!.*Chrome)|Opera/ .test(window.navigator.userAgent), - maxFileSize: 5000000, + maxFileSize: 999000, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i }); } diff --git a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js index 2b4851e67..2a0c38cb6 100644 --- a/library/blueimp_upload/js/cors/jquery.postmessage-transport.js +++ b/library/blueimp_upload/js/cors/jquery.postmessage-transport.js @@ -1,21 +1,24 @@ /* - * jQuery postMessage Transport Plugin 1.1.1 + * jQuery postMessage Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); @@ -61,6 +64,12 @@ loc = $('<a>').prop('href', options.postMessage)[0], target = loc.protocol + '//' + loc.host, xhrUpload = options.xhr().upload; + // IE always includes the port for the host property of a link + // element, but not in the location.host or origin property for the + // default http port 80 and https port 443, so we strip it: + if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) { + target = target.replace(/:(80|443)$/, ''); + } return { send: function (_, completeCallback) { counter += 1; diff --git a/library/blueimp_upload/js/cors/jquery.xdr-transport.js b/library/blueimp_upload/js/cors/jquery.xdr-transport.js index 0044cc2d5..a4e2699c6 100644 --- a/library/blueimp_upload/js/cors/jquery.xdr-transport.js +++ b/library/blueimp_upload/js/cors/jquery.xdr-transport.js @@ -1,24 +1,27 @@ /* - * jQuery XDomainRequest Transport Plugin 1.1.3 + * jQuery XDomainRequest Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT * * Based on Julian Aubourg's ajaxHooks xdr.js: * https://github.com/jaubourg/ajaxHooks/ */ -/* global define, window, XDomainRequest */ +/* global define, require, window, XDomainRequest */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); diff --git a/library/blueimp_upload/js/jquery.fileupload-angular.js b/library/blueimp_upload/js/jquery.fileupload-angular.js index e4ef3926b..1c2055276 100644 --- a/library/blueimp_upload/js/jquery.fileupload-angular.js +++ b/library/blueimp_upload/js/jquery.fileupload-angular.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload AngularJS Plugin 2.2.0 + * jQuery File Upload AngularJS Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, angular */ +/* global define, angular, require */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -24,6 +24,16 @@ './jquery.fileupload-video', './jquery.fileupload-validate' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('angular'), + require('./jquery.fileupload-image'), + require('./jquery.fileupload-audio'), + require('./jquery.fileupload-video'), + require('./jquery.fileupload-validate') + ); } else { factory(); } @@ -91,7 +101,7 @@ angular.forEach(data.files, function (file) { filesCopy.push(file); }); - scope.$apply(function () { + scope.$parent.$applyAsync(function () { addFileMethods(scope, data); var method = scope.option('prependFiles') ? 'unshift' : 'push'; @@ -100,7 +110,7 @@ data.process(function () { return scope.process(data); }).always(function () { - scope.$apply(function () { + scope.$parent.$applyAsync(function () { addFileMethods(scope, data); scope.replace(filesCopy, data.files); }); @@ -112,12 +122,6 @@ } }); }, - progress: function (e, data) { - if (e.isDefaultPrevented()) { - return false; - } - data.scope.$apply(); - }, done: function (e, data) { if (e.isDefaultPrevented()) { return false; @@ -197,8 +201,8 @@ // The FileUploadController initializes the fileupload widget and // provides scope methods to control the File Upload functionality: .controller('FileUploadController', [ - '$scope', '$element', '$attrs', '$window', 'fileUpload', - function ($scope, $element, $attrs, $window, fileUpload) { + '$scope', '$element', '$attrs', '$window', 'fileUpload','$q', + function ($scope, $element, $attrs, $window, fileUpload, $q) { var uploadMethods = { progress: function () { return $element.fileupload('progress'); @@ -260,19 +264,21 @@ $scope.applyOnQueue = function (method) { var list = this.queue.slice(0), i, - file; + file, + promises = []; for (i = 0; i < list.length; i += 1) { file = list[i]; if (file[method]) { - file[method](); + promises.push(file[method]()); } } + return $q.all(promises); }; $scope.submit = function () { - this.applyOnQueue('$submit'); + return this.applyOnQueue('$submit'); }; $scope.cancel = function () { - this.applyOnQueue('$cancel'); + return this.applyOnQueue('$cancel'); }; // Add upload methods to the scope: angular.extend($scope, uploadMethods); @@ -320,9 +326,11 @@ 'fileuploadprocessalways', 'fileuploadprocessstop' ].join(' '), function (e, data) { - if ($scope.$emit(e.type, data).defaultPrevented) { - e.preventDefault(); - } + $scope.$parent.$applyAsync(function () { + if ($scope.$emit(e.type, data).defaultPrevented) { + e.preventDefault(); + } + }); }).on('remove', function () { // Remove upload methods from the scope, // when the widget is removed: diff --git a/library/blueimp_upload/js/jquery.fileupload-audio.js b/library/blueimp_upload/js/jquery.fileupload-audio.js index 575800e82..a25377619 100644 --- a/library/blueimp_upload/js/jquery.fileupload-audio.js +++ b/library/blueimp_upload/js/jquery.fileupload-audio.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Audio Preview Plugin 1.0.3 + * jQuery File Upload Audio Preview Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -21,6 +21,13 @@ 'load-image', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( diff --git a/library/blueimp_upload/js/jquery.fileupload-image.js b/library/blueimp_upload/js/jquery.fileupload-image.js index 5bb7026ae..65fc6d7b8 100644 --- a/library/blueimp_upload/js/jquery.fileupload-image.js +++ b/library/blueimp_upload/js/jquery.fileupload-image.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Image Preview & Resize Plugin 1.7.2 + * jQuery File Upload Image Preview & Resize Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, Blob */ +/* global define, require, window, Blob */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -20,11 +20,22 @@ 'jquery', 'load-image', 'load-image-meta', + 'load-image-scale', 'load-image-exif', - 'load-image-ios', 'canvas-to-blob', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('blueimp-load-image/js/load-image-meta'), + require('blueimp-load-image/js/load-image-scale'), + require('blueimp-load-image/js/load-image-exif'), + require('blueimp-canvas-to-blob'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( @@ -236,7 +247,7 @@ blob.name = file.name; } else if (file.name) { blob.name = file.name.replace( - /\..+$/, + /\.\w+$/, '.' + blob.type.substr(6) ); } diff --git a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js index af0a00b1e..7b136b379 100755..100644 --- a/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js +++ b/library/blueimp_upload/js/jquery.fileupload-jquery-ui.js @@ -1,22 +1,31 @@ /* - * jQuery File Upload jQuery UI Plugin 8.7.1 + * jQuery File Upload jQuery UI Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: - define(['jquery', './jquery.fileupload-ui'], factory); + define([ + 'jquery', + './jquery.fileupload-ui' + ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload-ui') + ); } else { // Browser globals: factory(window.jQuery); diff --git a/library/blueimp_upload/js/jquery.fileupload-process.js b/library/blueimp_upload/js/jquery.fileupload-process.js index 8a6b929a6..638f0d26b 100644 --- a/library/blueimp_upload/js/jquery.fileupload-process.js +++ b/library/blueimp_upload/js/jquery.fileupload-process.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Processing Plugin 1.3.0 + * jQuery File Upload Processing Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -20,6 +20,12 @@ 'jquery', './jquery.fileupload' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload') + ); } else { // Browser globals: factory( @@ -81,7 +87,7 @@ settings ); }; - chain = chain.pipe(func, settings.always && func); + chain = chain.then(func, settings.always && func); }); chain .done(function () { @@ -148,7 +154,7 @@ }; opts.index = index; that._processing += 1; - that._processingQueue = that._processingQueue.pipe(func, func) + that._processingQueue = that._processingQueue.then(func, func) .always(function () { that._processing -= 1; if (that._processing === 0) { diff --git a/library/blueimp_upload/js/jquery.fileupload-ui.js b/library/blueimp_upload/js/jquery.fileupload-ui.js index 62cf9aa38..83e7449e6 100644 --- a/library/blueimp_upload/js/jquery.fileupload-ui.js +++ b/library/blueimp_upload/js/jquery.fileupload-ui.js @@ -1,29 +1,38 @@ /* - * jQuery File Upload User Interface Plugin 9.6.0 + * jQuery File Upload User Interface Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', - 'tmpl', + 'blueimp-tmpl', './jquery.fileupload-image', './jquery.fileupload-audio', './jquery.fileupload-video', './jquery.fileupload-validate' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-tmpl'), + require('./jquery.fileupload-image'), + require('./jquery.fileupload-video'), + require('./jquery.fileupload-validate') + ); } else { // Browser globals: factory( @@ -62,10 +71,10 @@ // The expected data type of the upload response, sets the dataType // option of the $.ajax upload requests: dataType: 'json', - + // Error and info messages: messages: { - unknownError: 'Unknown error' + unknownError: 'Unknown error' }, // Function returning the current number of files, diff --git a/library/blueimp_upload/js/jquery.fileupload-validate.js b/library/blueimp_upload/js/jquery.fileupload-validate.js index f93a18fa2..eebeb3733 100644 --- a/library/blueimp_upload/js/jquery.fileupload-validate.js +++ b/library/blueimp_upload/js/jquery.fileupload-validate.js @@ -1,17 +1,17 @@ /* - * jQuery File Upload Validation Plugin 1.1.2 + * jQuery File Upload Validation Plugin * 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 + * https://opensource.org/licenses/MIT */ -/* global define, window */ +/* global define, require, window */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -19,6 +19,12 @@ 'jquery', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( @@ -33,7 +39,7 @@ { 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: '@', diff --git a/library/blueimp_upload/js/jquery.fileupload-video.js b/library/blueimp_upload/js/jquery.fileupload-video.js index 3764b27a2..aedcec2ba 100644 --- a/library/blueimp_upload/js/jquery.fileupload-video.js +++ b/library/blueimp_upload/js/jquery.fileupload-video.js @@ -1,18 +1,18 @@ /* - * jQuery File Upload Video Preview Plugin 1.0.3 + * jQuery File Upload Video Preview Plugin * 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 + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document */ +/* global define, require, window, document */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: @@ -21,6 +21,13 @@ 'load-image', './jquery.fileupload-process' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('blueimp-load-image/js/load-image'), + require('./jquery.fileupload-process') + ); } else { // Browser globals: factory( diff --git a/library/blueimp_upload/js/jquery.fileupload.js b/library/blueimp_upload/js/jquery.fileupload.js index a4cfdc0ac..5ff151b53 100644 --- a/library/blueimp_upload/js/jquery.fileupload.js +++ b/library/blueimp_upload/js/jquery.fileupload.js @@ -1,25 +1,31 @@ /* - * jQuery File Upload Plugin 5.42.0 + * jQuery File Upload Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* jshint nomen:false */ -/* global define, window, document, location, Blob, FormData */ +/* global define, require, window, document, location, Blob, FormData */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', - 'jquery.ui.widget' + 'jquery-ui/ui/widget' ], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory( + require('jquery'), + require('./vendor/jquery.ui.widget') + ); } else { // Browser globals: factory(window.jQuery); @@ -271,7 +277,8 @@ // The following are jQuery ajax settings required for the file uploads: processData: false, contentType: false, - cache: false + cache: false, + timeout: 0 }, // A list of options that require reinitializing event listeners and/or @@ -645,7 +652,7 @@ data.process = function (resolveFunc, rejectFunc) { if (resolveFunc || rejectFunc) { data._processQueue = this._processQueue = - (this._processQueue || getPromise([this])).pipe( + (this._processQueue || getPromise([this])).then( function () { if (data.errorThrown) { return $.Deferred() @@ -653,7 +660,7 @@ } return getPromise(arguments); } - ).pipe(resolveFunc, rejectFunc); + ).then(resolveFunc, rejectFunc); } return this._processQueue || getPromise([this]); }; @@ -938,9 +945,9 @@ if (this.options.limitConcurrentUploads > 1) { slot = $.Deferred(); this._slots.push(slot); - pipe = slot.pipe(send); + pipe = slot.then(send); } else { - this._sequence = this._sequence.pipe(send, send); + this._sequence = this._sequence.then(send, send); pipe = this._sequence; } // Return the piped Promise object, enhanced with an abort method, @@ -977,7 +984,10 @@ fileSet, i, j = 0; - if (limitSize && (!filesLength || files[0].size === undefined)) { + if (!filesLength) { + return false; + } + if (limitSize && files[0].size === undefined) { limitSize = undefined; } if (!(options.singleFileUploads || limit || limitSize) || @@ -1036,13 +1046,19 @@ _replaceFileInput: function (data) { var input = data.fileInput, - inputClone = input.clone(true); + inputClone = input.clone(true), + restoreFocus = input.is(document.activeElement); // Add a reference for the new cloned file input to the data argument: data.fileInputClone = inputClone; $('<form></form>').append(inputClone)[0].reset(); // Detaching allows to insert the fileInput on another form // without loosing the file input value: input.after(inputClone).detach(); + // If the fileInput had focus before it was detached, + // restore focus to the inputClone. + if (restoreFocus) { + inputClone.focus(); + } // Avoid memory leaks with the detached file input: $.cleanData(input.unbind('remove')); // Replace the original file input element in the fileInput @@ -1064,6 +1080,8 @@ _handleFileTreeEntry: function (entry, path) { var that = this, dfd = $.Deferred(), + entries = [], + dirReader, errorHandler = function (e) { if (e && !e.entry) { e.entry = entry; @@ -1091,8 +1109,7 @@ readEntries(); } }, errorHandler); - }, - dirReader, entries = []; + }; path = path || ''; if (entry.isFile) { if (entry._file) { @@ -1123,7 +1140,7 @@ $.map(entries, function (entry) { return that._handleFileTreeEntry(entry, path); }) - ).pipe(function () { + ).then(function () { return Array.prototype.concat.apply( [], arguments @@ -1192,7 +1209,7 @@ return $.when.apply( $, $.map(fileInput, this._getSingleFileInputFiles) - ).pipe(function () { + ).then(function () { return Array.prototype.concat.apply( [], arguments @@ -1295,6 +1312,10 @@ this._off(this.options.fileInput, 'change'); }, + _destroy: function () { + this._destroyEventHandlers(); + }, + _setOption: function (key, value) { var reinit = $.inArray(key, this._specialOptions) !== -1; if (reinit) { @@ -1338,15 +1359,19 @@ _initDataAttributes: function () { var that = this, options = this.options, - clone = $(this.element[0].cloneNode(false)); + data = this.element.data(); // Initialize options set via HTML5 data-attributes: $.each( - clone.data(), - function (key, value) { - var dataAttributeName = 'data-' + - // Convert camelCase to hyphen-ated key: - key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - if (clone.attr(dataAttributeName)) { + this.element[0].attributes, + function (index, attr) { + var key = attr.name.toLowerCase(), + value; + if (/^data-/.test(key)) { + // Convert hyphen-ated key to camelCase: + key = key.slice(5).replace(/-[a-z]/g, function (str) { + return str.charAt(1).toUpperCase(); + }); + value = data[key]; if (that._isRegExpOption(key, value)) { value = that._getRegExp(value); } diff --git a/library/blueimp_upload/js/jquery.iframe-transport.js b/library/blueimp_upload/js/jquery.iframe-transport.js index 8d64b591b..8d25c4641 100644 --- a/library/blueimp_upload/js/jquery.iframe-transport.js +++ b/library/blueimp_upload/js/jquery.iframe-transport.js @@ -1,21 +1,24 @@ /* - * jQuery Iframe Transport Plugin 1.8.2 + * jQuery Iframe Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/* global define, window, document */ +/* global define, require, window, document, JSON */ -(function (factory) { +;(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); } else { // Browser globals: factory(window.jQuery); @@ -24,7 +27,14 @@ 'use strict'; // Helper variable to create unique names for the transport iframes: - var counter = 0; + var counter = 0, + jsonAPI = $, + jsonParse = 'parseJSON'; + + if ('JSON' in window && 'parse' in JSON) { + jsonAPI = JSON; + jsonParse = 'parse'; + } // The iframe transport accepts four additional options: // options.fileInput: a jQuery collection of file input fields @@ -194,7 +204,7 @@ return iframe && $(iframe[0].body).text(); }, 'iframe json': function (iframe) { - return iframe && $.parseJSON($(iframe[0].body).text()); + return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); }, 'iframe html': function (iframe) { return iframe && $(iframe[0].body).html(); diff --git a/library/blueimp_upload/js/main.js b/library/blueimp_upload/js/main.js index 8f57967a3..0403682e7 100644 --- a/library/blueimp_upload/js/main.js +++ b/library/blueimp_upload/js/main.js @@ -1,12 +1,12 @@ /* - * jQuery File Upload Plugin JS Example 8.9.1 + * jQuery File Upload Plugin JS Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* global $, window */ @@ -40,7 +40,7 @@ $(function () { // send Blob objects via XHR requests: disableImageResize: /Android(?!.*Chrome)|Opera/ .test(window.navigator.userAgent), - maxFileSize: 5000000, + maxFileSize: 999000, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i }); // Upload server status check for browsers with CORS support: diff --git a/library/blueimp_upload/js/vendor/jquery.ui.widget.js b/library/blueimp_upload/js/vendor/jquery.ui.widget.js index 7899e6bb3..e08df3fd0 100644 --- a/library/blueimp_upload/js/vendor/jquery.ui.widget.js +++ b/library/blueimp_upload/js/vendor/jquery.ui.widget.js @@ -1,13 +1,19 @@ -/*! jQuery UI - v1.11.1 - 2014-09-17 +/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28 * http://jqueryui.com * Includes: widget.js -* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ (function( factory ) { if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define([ "jquery" ], factory ); + + } else if ( typeof exports === "object" ) { + + // Node/CommonJS + factory( require( "jquery" ) ); + } else { // Browser globals @@ -15,10 +21,10 @@ } }(function( $ ) { /*! - * jQuery UI Widget 1.11.1 + * jQuery UI Widget 1.11.4 * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -42,7 +48,7 @@ $.cleanData = (function( orig ) { } // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} + } catch ( e ) {} } orig( elems ); }; @@ -196,11 +202,6 @@ $.widget.bridge = function( name, object ) { args = widget_slice.call( arguments, 1 ), returnValue = this; - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - if ( isMethodCall ) { this.each(function() { var methodValue, @@ -225,6 +226,12 @@ $.widget.bridge = function( name, object ) { } }); } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat(args) ); + } + this.each(function() { var instance = $.data( this, fullName ); if ( instance ) { @@ -260,10 +267,6 @@ $.Widget.prototype = { this.element = $( element ); this.uuid = widget_uuid++; this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); this.bindings = $(); this.hoverable = $(); @@ -286,6 +289,11 @@ $.Widget.prototype = { this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); } + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + this._create(); this._trigger( "create", null, this._getCreateEventData() ); this._init(); @@ -448,8 +456,14 @@ $.Widget.prototype = { }, _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; element.unbind( eventName ).undelegate( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); }, _delay: function( handler, delay ) { diff --git a/library/blueimp_upload/package.json b/library/blueimp_upload/package.json index 880574aa7..ed4d33681 100644 --- a/library/blueimp_upload/package.json +++ b/library/blueimp_upload/package.json @@ -1,8 +1,8 @@ { "name": "blueimp-file-upload", - "version": "9.8.0", + "version": "9.18.0", "title": "jQuery File Upload", - "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", "keywords": [ "jquery", "file", @@ -29,26 +29,27 @@ "name": "Sebastian Tschan", "url": "https://blueimp.net" }, - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ], "repository": { "type": "git", "url": "git://github.com/blueimp/jQuery-File-Upload.git" }, - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], + "license": "MIT", + "optionalDependencies": { + "blueimp-canvas-to-blob": "3.5.0", + "blueimp-load-image": "2.12.2", + "blueimp-tmpl": "3.6.0" + }, "devDependencies": { - "grunt": "~0.4.5", - "grunt-bump-build-git": "~1.1.1", - "grunt-contrib-jshint": "~0.10.0" - } + "bower-json": "0.8.1", + "jshint": "2.9.3" + }, + "scripts": { + "bower-version-update": "./bower-version-update.js", + "lint": "jshint *.js js/*.js js/cors/*.js", + "test": "npm run lint", + "preversion": "npm test", + "version": "npm run bower-version-update && git add bower.json", + "postversion": "git push --tags origin master && npm publish" + }, + "main": "js/jquery.fileupload.js" } diff --git a/library/blueimp_upload/server/gae-go/app/main.go b/library/blueimp_upload/server/gae-go/app/main.go index 03af0b1d2..a92d128c0 100644 --- a/library/blueimp_upload/server/gae-go/app/main.go +++ b/library/blueimp_upload/server/gae-go/app/main.go @@ -1,59 +1,90 @@ /* - * jQuery File Upload Plugin GAE Go Example 3.2.0 + * jQuery File Upload Plugin GAE Go Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ package app import ( - "appengine" - "appengine/blobstore" - "appengine/image" - "appengine/taskqueue" + "bufio" "bytes" "encoding/json" "fmt" + "github.com/disintegration/gift" + "golang.org/x/net/context" + "google.golang.org/appengine" + "google.golang.org/appengine/memcache" + "hash/crc32" + "image" + "image/gif" + "image/jpeg" + "image/png" "io" "log" "mime/multipart" "net/http" "net/url" + "path/filepath" "regexp" "strings" - "time" ) const ( - WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" - MIN_FILE_SIZE = 1 // bytes - MAX_FILE_SIZE = 5000000 // bytes + WEBSITE = "https://blueimp.github.io/jQuery-File-Upload/" + MIN_FILE_SIZE = 1 // bytes + // Max file size is memcache limit (1MB) minus key size minus overhead: + MAX_FILE_SIZE = 999000 // bytes IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)" ACCEPT_FILE_TYPES = IMAGE_TYPES + THUMB_MAX_WIDTH = 80 + THUMB_MAX_HEIGHT = 80 EXPIRATION_TIME = 300 // seconds - THUMBNAIL_PARAM = "=s80" + // If empty, only allow redirects to the referer protocol+host. + // Set to a regexp string for custom pattern matching: + REDIRECT_ALLOW_TARGET = "" ) var ( imageTypes = regexp.MustCompile(IMAGE_TYPES) acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES) + thumbSuffix = "." + fmt.Sprint(THUMB_MAX_WIDTH) + "x" + + fmt.Sprint(THUMB_MAX_HEIGHT) ) +func escape(s string) string { + return strings.Replace(url.QueryEscape(s), "+", "%20", -1) +} + +func extractKey(r *http.Request) string { + // Use RequestURI instead of r.URL.Path, as we need the encoded form: + path := strings.Split(r.RequestURI, "?")[0] + // Also adjust double encoded slashes: + return strings.Replace(path[1:], "%252F", "%2F", -1) +} + +func check(err error) { + if err != nil { + panic(err) + } +} + type FileInfo struct { - Key appengine.BlobKey `json:"-"` - Url string `json:"url,omitempty"` - ThumbnailUrl string `json:"thumbnailUrl,omitempty"` - Name string `json:"name"` - Type string `json:"type"` - Size int64 `json:"size"` - Error string `json:"error,omitempty"` - DeleteUrl string `json:"deleteUrl,omitempty"` - DeleteType string `json:"deleteType,omitempty"` + Key string `json:"-"` + ThumbnailKey string `json:"-"` + Url string `json:"url,omitempty"` + ThumbnailUrl string `json:"thumbnailUrl,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Size int64 `json:"size"` + Error string `json:"error,omitempty"` + DeleteUrl string `json:"deleteUrl,omitempty"` + DeleteType string `json:"deleteType,omitempty"` } func (fi *FileInfo) ValidateType() (valid bool) { @@ -75,50 +106,58 @@ func (fi *FileInfo) ValidateSize() (valid bool) { return false } -func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) { +func (fi *FileInfo) CreateUrls(r *http.Request, c context.Context) { u := &url.URL{ Scheme: r.URL.Scheme, Host: appengine.DefaultVersionHostname(c), Path: "/", } uString := u.String() - fi.Url = uString + escape(string(fi.Key)) + "/" + - escape(string(fi.Name)) - fi.DeleteUrl = fi.Url + "?delete=true" + fi.Url = uString + fi.Key + fi.DeleteUrl = fi.Url fi.DeleteType = "DELETE" - if imageTypes.MatchString(fi.Type) { - servingUrl, err := image.ServingURL( - c, - fi.Key, - &image.ServingURLOptions{ - Secure: strings.HasSuffix(u.Scheme, "s"), - Size: 0, - Crop: false, - }, - ) - check(err) - fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM + if fi.ThumbnailKey != "" { + fi.ThumbnailUrl = uString + fi.ThumbnailKey } } -func check(err error) { - if err != nil { - panic(err) - } -} - -func escape(s string) string { - return strings.Replace(url.QueryEscape(s), "+", "%20", -1) +func (fi *FileInfo) SetKey(checksum uint32) { + fi.Key = escape(string(fi.Type)) + "/" + + escape(fmt.Sprint(checksum)) + "/" + + escape(string(fi.Name)) } -func delayedDelete(c appengine.Context, fi *FileInfo) { - if key := string(fi.Key); key != "" { - task := &taskqueue.Task{ - Path: "/" + escape(key) + "/-", - Method: "DELETE", - Delay: time.Duration(EXPIRATION_TIME) * time.Second, +func (fi *FileInfo) createThumb(buffer *bytes.Buffer, c context.Context) { + if imageTypes.MatchString(fi.Type) { + src, _, err := image.Decode(bytes.NewReader(buffer.Bytes())) + check(err) + filter := gift.New(gift.ResizeToFit( + THUMB_MAX_WIDTH, + THUMB_MAX_HEIGHT, + gift.LanczosResampling, + )) + dst := image.NewNRGBA(filter.Bounds(src.Bounds())) + filter.Draw(dst, src) + buffer.Reset() + bWriter := bufio.NewWriter(buffer) + switch fi.Type { + case "image/jpeg", "image/pjpeg": + err = jpeg.Encode(bWriter, dst, nil) + case "image/gif": + err = gif.Encode(bWriter, dst, nil) + default: + err = png.Encode(bWriter, dst) + } + check(err) + bWriter.Flush() + thumbnailKey := fi.Key + thumbSuffix + filepath.Ext(fi.Name) + item := &memcache.Item{ + Key: thumbnailKey, + Value: buffer.Bytes(), } - taskqueue.Add(c, task, "") + err = memcache.Set(c, item) + check(err) + fi.ThumbnailKey = thumbnailKey } } @@ -136,24 +175,26 @@ func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) { fi.Error = rec.(error).Error() } }() + var buffer bytes.Buffer + hash := crc32.NewIEEE() + mw := io.MultiWriter(&buffer, hash) lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1} + _, err := io.Copy(mw, lr) + check(err) + fi.Size = MAX_FILE_SIZE + 1 - lr.N + if !fi.ValidateSize() { + return + } + fi.SetKey(hash.Sum32()) + item := &memcache.Item{ + Key: fi.Key, + Value: buffer.Bytes(), + } context := appengine.NewContext(r) - w, err := blobstore.Create(context, fi.Type) - defer func() { - w.Close() - fi.Size = MAX_FILE_SIZE + 1 - lr.N - fi.Key, err = w.Key() - check(err) - if !fi.ValidateSize() { - err := blobstore.Delete(context, fi.Key) - check(err) - return - } - delayedDelete(context, fi) - fi.CreateUrls(r, context) - }() + err = memcache.Set(context, item) check(err) - _, err = io.Copy(w, lr) + fi.createThumb(&buffer, context) + fi.CreateUrls(r, context) return } @@ -183,49 +224,70 @@ func handleUploads(r *http.Request) (fileInfos []*FileInfo) { return } +func validateRedirect(r *http.Request, redirect string) bool { + if redirect != "" { + var redirectAllowTarget *regexp.Regexp + if REDIRECT_ALLOW_TARGET != "" { + redirectAllowTarget = regexp.MustCompile(REDIRECT_ALLOW_TARGET) + } else { + referer := r.Referer() + if referer == "" { + return false + } + refererUrl, err := url.Parse(referer) + if err != nil { + return false + } + redirectAllowTarget = regexp.MustCompile("^" + regexp.QuoteMeta( + refererUrl.Scheme+"://"+refererUrl.Host+"/", + )) + } + return redirectAllowTarget.MatchString(redirect) + } + return false +} + func get(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { http.Redirect(w, r, WEBSITE, http.StatusFound) return } - parts := strings.Split(r.URL.Path, "/") + // Use RequestURI instead of r.URL.Path, as we need the encoded form: + key := extractKey(r) + parts := strings.Split(key, "/") if len(parts) == 3 { - if key := parts[1]; key != "" { - blobKey := appengine.BlobKey(key) - bi, err := blobstore.Stat(appengine.NewContext(r), blobKey) - if err == nil { - w.Header().Add("X-Content-Type-Options", "nosniff") - if !imageTypes.MatchString(bi.ContentType) { - w.Header().Add("Content-Type", "application/octet-stream") - w.Header().Add( - "Content-Disposition", - fmt.Sprintf("attachment; filename=\"%s\"", parts[2]), - ) - } - w.Header().Add( - "Cache-Control", - fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), - ) - blobstore.Send(w, blobKey) - return + context := appengine.NewContext(r) + item, err := memcache.Get(context, key) + if err == nil { + w.Header().Add("X-Content-Type-Options", "nosniff") + contentType, _ := url.QueryUnescape(parts[0]) + if !imageTypes.MatchString(contentType) { + contentType = "application/octet-stream" } + w.Header().Add("Content-Type", contentType) + w.Header().Add( + "Cache-Control", + fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), + ) + w.Write(item.Value) + return } } http.Error(w, "404 Not Found", http.StatusNotFound) } func post(w http.ResponseWriter, r *http.Request) { - result := make(map[string][]*FileInfo, 1) - result["files"] = handleUploads(r) + result := make(map[string][]*FileInfo, 1) + result["files"] = handleUploads(r) b, err := json.Marshal(result) check(err) - if redirect := r.FormValue("redirect"); redirect != "" { - if strings.Contains(redirect, "%s") { - redirect = fmt.Sprintf( - redirect, - escape(string(b)), - ) - } + if redirect := r.FormValue("redirect"); validateRedirect(r, redirect) { + if strings.Contains(redirect, "%s") { + redirect = fmt.Sprintf( + redirect, + escape(string(b)), + ) + } http.Redirect(w, r, redirect, http.StatusFound) return } @@ -238,27 +300,30 @@ func post(w http.ResponseWriter, r *http.Request) { } func delete(w http.ResponseWriter, r *http.Request) { - parts := strings.Split(r.URL.Path, "/") - if len(parts) != 3 { - return - } - result := make(map[string]bool, 1) - if key := parts[1]; key != "" { - c := appengine.NewContext(r) - blobKey := appengine.BlobKey(key) - err := blobstore.Delete(c, blobKey) - check(err) - err = image.DeleteServingURL(c, blobKey) + key := extractKey(r) + parts := strings.Split(key, "/") + if len(parts) == 3 { + result := make(map[string]bool, 1) + context := appengine.NewContext(r) + err := memcache.Delete(context, key) + if err == nil { + result[key] = true + contentType, _ := url.QueryUnescape(parts[0]) + if imageTypes.MatchString(contentType) { + thumbnailKey := key + thumbSuffix + filepath.Ext(parts[2]) + err := memcache.Delete(context, thumbnailKey) + if err == nil { + result[thumbnailKey] = true + } + } + } + w.Header().Set("Content-Type", "application/json") + b, err := json.Marshal(result) check(err) - result[key] = true - } - jsonType := "application/json" - if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { - w.Header().Set("Content-Type", jsonType) + fmt.Fprintln(w, string(b)) + } else { + http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) } - b, err := json.Marshal(result) - check(err) - fmt.Fprintln(w, string(b)) } func handle(w http.ResponseWriter, r *http.Request) { @@ -267,15 +332,15 @@ func handle(w http.ResponseWriter, r *http.Request) { w.Header().Add("Access-Control-Allow-Origin", "*") w.Header().Add( "Access-Control-Allow-Methods", - "OPTIONS, HEAD, GET, POST, PUT, DELETE", + "OPTIONS, HEAD, GET, POST, DELETE", ) w.Header().Add( "Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition", ) switch r.Method { - case "OPTIONS": - case "HEAD": + case "OPTIONS", "HEAD": + return case "GET": get(w, r) case "POST": diff --git a/library/blueimp_upload/server/gae-python/app.yaml b/library/blueimp_upload/server/gae-python/app.yaml index 5fe123f59..764449b74 100644 --- a/library/blueimp_upload/server/gae-python/app.yaml +++ b/library/blueimp_upload/server/gae-python/app.yaml @@ -4,8 +4,9 @@ runtime: python27 api_version: 1 threadsafe: true -builtins: -- deferred: on +libraries: +- name: PIL + version: latest handlers: - url: /(favicon\.ico|robots\.txt) diff --git a/library/blueimp_upload/server/gae-python/main.py b/library/blueimp_upload/server/gae-python/main.py index 6276be6a0..1955ac00a 100644 --- a/library/blueimp_upload/server/gae-python/main.py +++ b/library/blueimp_upload/server/gae-python/main.py @@ -1,49 +1,57 @@ # -*- coding: utf-8 -*- # -# jQuery File Upload Plugin GAE Python Example 2.2.0 +# jQuery File Upload Plugin GAE Python Example # https://github.com/blueimp/jQuery-File-Upload # # Copyright 2011, Sebastian Tschan # https://blueimp.net # # Licensed under the MIT license: -# http://www.opensource.org/licenses/MIT +# https://opensource.org/licenses/MIT # -from __future__ import with_statement -from google.appengine.api import files, images -from google.appengine.ext import blobstore, deferred -from google.appengine.ext.webapp import blobstore_handlers +from google.appengine.api import memcache, images import json +import os import re import urllib import webapp2 +DEBUG=os.environ.get('SERVER_SOFTWARE', '').startswith('Dev') WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/' MIN_FILE_SIZE = 1 # bytes -MAX_FILE_SIZE = 5000000 # bytes +# Max file size is memcache limit (1MB) minus key size minus overhead: +MAX_FILE_SIZE = 999000 # bytes IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') ACCEPT_FILE_TYPES = IMAGE_TYPES -THUMBNAIL_MODIFICATOR = '=s80' # max width / height +THUMB_MAX_WIDTH = 80 +THUMB_MAX_HEIGHT = 80 +THUMB_SUFFIX = '.'+str(THUMB_MAX_WIDTH)+'x'+str(THUMB_MAX_HEIGHT)+'.png' EXPIRATION_TIME = 300 # seconds +# If set to None, only allow redirects to the referer protocol+host. +# Set to a regexp for custom pattern matching against the redirect value: +REDIRECT_ALLOW_TARGET = None + +class CORSHandler(webapp2.RequestHandler): + def cors(self): + headers = self.response.headers + headers['Access-Control-Allow-Origin'] = '*' + headers['Access-Control-Allow-Methods'] =\ + 'OPTIONS, HEAD, GET, POST, DELETE' + headers['Access-Control-Allow-Headers'] =\ + 'Content-Type, Content-Range, Content-Disposition' + def initialize(self, request, response): + super(CORSHandler, self).initialize(request, response) + self.cors() -def cleanup(blob_keys): - blobstore.delete(blob_keys) - - -class UploadHandler(webapp2.RequestHandler): + def json_stringify(self, obj): + return json.dumps(obj, separators=(',', ':')) - def initialize(self, request, response): - super(UploadHandler, self).initialize(request, response) - self.response.headers['Access-Control-Allow-Origin'] = '*' - self.response.headers[ - 'Access-Control-Allow-Methods' - ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE' - self.response.headers[ - 'Access-Control-Allow-Headers' - ] = 'Content-Type, Content-Range, Content-Disposition' + def options(self, *args, **kwargs): + pass +class UploadHandler(CORSHandler): def validate(self, file): if file['size'] < MIN_FILE_SIZE: file['error'] = 'File is too small' @@ -55,6 +63,20 @@ class UploadHandler(webapp2.RequestHandler): return True return False + def validate_redirect(self, redirect): + if redirect: + if REDIRECT_ALLOW_TARGET: + return REDIRECT_ALLOW_TARGET.match(redirect) + referer = self.request.headers['referer'] + if referer: + from urlparse import urlparse + parts = urlparse(referer) + redirect_allow_target = '^' + re.escape( + parts.scheme + '://' + parts.netloc + '/' + ) + return re.match(redirect_allow_target, redirect) + return False + def get_file_size(self, file): file.seek(0, 2) # Seek to the end of the file size = file.tell() # Get the position of EOF @@ -62,64 +84,58 @@ class UploadHandler(webapp2.RequestHandler): return size def write_blob(self, data, info): - blob = files.blobstore.create( - mime_type=info['type'], - _blobinfo_uploaded_filename=info['name'] - ) - with files.open(blob, 'a') as f: - f.write(data) - files.finalize(blob) - return files.blobstore.get_blob_key(blob) + key = urllib.quote(info['type'].encode('utf-8'), '') +\ + '/' + str(hash(data)) +\ + '/' + urllib.quote(info['name'].encode('utf-8'), '') + try: + memcache.set(key, data, time=EXPIRATION_TIME) + except: #Failed to add to memcache + return (None, None) + thumbnail_key = None + if IMAGE_TYPES.match(info['type']): + try: + img = images.Image(image_data=data) + img.resize( + width=THUMB_MAX_WIDTH, + height=THUMB_MAX_HEIGHT + ) + thumbnail_data = img.execute_transforms() + thumbnail_key = key + THUMB_SUFFIX + memcache.set( + thumbnail_key, + thumbnail_data, + time=EXPIRATION_TIME + ) + except: #Failed to resize Image or add to memcache + thumbnail_key = None + return (key, thumbnail_key) def handle_upload(self): results = [] - blob_keys = [] for name, fieldStorage in self.request.POST.items(): if type(fieldStorage) is unicode: continue result = {} - result['name'] = re.sub( - r'^.*\\', - '', - fieldStorage.filename - ) + result['name'] = urllib.unquote(fieldStorage.filename) result['type'] = fieldStorage.type result['size'] = self.get_file_size(fieldStorage.file) if self.validate(result): - blob_key = str( - self.write_blob(fieldStorage.value, result) + key, thumbnail_key = self.write_blob( + fieldStorage.value, + result ) - blob_keys.append(blob_key) - result['deleteType'] = 'DELETE' - result['deleteUrl'] = self.request.host_url +\ - '/?key=' + urllib.quote(blob_key, '') - if (IMAGE_TYPES.match(result['type'])): - try: - result['url'] = images.get_serving_url( - blob_key, - secure_url=self.request.host_url.startswith( - 'https' - ) - ) - result['thumbnailUrl'] = result['url'] +\ - THUMBNAIL_MODIFICATOR - except: # Could not get an image serving url - pass - if not 'url' in result: - result['url'] = self.request.host_url +\ - '/' + blob_key + '/' + urllib.quote( - result['name'].encode('utf-8'), '') + if key is not None: + result['url'] = self.request.host_url + '/' + key + result['deleteUrl'] = result['url'] + result['deleteType'] = 'DELETE' + if thumbnail_key is not None: + result['thumbnailUrl'] = self.request.host_url +\ + '/' + thumbnail_key + else: + result['error'] = 'Failed to store uploaded file.' results.append(result) - deferred.defer( - cleanup, - blob_keys, - _countdown=EXPIRATION_TIME - ) return results - def options(self): - pass - def head(self): pass @@ -130,9 +146,9 @@ class UploadHandler(webapp2.RequestHandler): if (self.request.get('_method') == 'DELETE'): return self.delete() result = {'files': self.handle_upload()} - s = json.dumps(result, separators=(',', ':')) + s = self.json_stringify(result) redirect = self.request.get('redirect') - if redirect: + if self.validate_redirect(redirect): return self.redirect(str( redirect.replace('%s', urllib.quote(s, ''), 1) )) @@ -140,31 +156,49 @@ class UploadHandler(webapp2.RequestHandler): self.response.headers['Content-Type'] = 'application/json' self.response.write(s) - def delete(self): - key = self.request.get('key') or '' - blobstore.delete(key) - s = json.dumps({key: True}, separators=(',', ':')) +class FileHandler(CORSHandler): + def normalize(self, str): + return urllib.quote(urllib.unquote(str), '') + + def get(self, content_type, data_hash, file_name): + content_type = self.normalize(content_type) + file_name = self.normalize(file_name) + key = content_type + '/' + data_hash + '/' + file_name + data = memcache.get(key) + if data is None: + return self.error(404) + # Prevent browsers from MIME-sniffing the content-type: + self.response.headers['X-Content-Type-Options'] = 'nosniff' + content_type = urllib.unquote(content_type) + if not IMAGE_TYPES.match(content_type): + # Force a download dialog for non-image types: + content_type = 'application/octet-stream' + elif file_name.endswith(THUMB_SUFFIX): + content_type = 'image/png' + self.response.headers['Content-Type'] = content_type + # Cache for the expiration time: + self.response.headers['Cache-Control'] = 'public,max-age=%d' \ + % EXPIRATION_TIME + self.response.write(data) + + def delete(self, content_type, data_hash, file_name): + content_type = self.normalize(content_type) + file_name = self.normalize(file_name) + key = content_type + '/' + data_hash + '/' + file_name + result = {key: memcache.delete(key)} + content_type = urllib.unquote(content_type) + if IMAGE_TYPES.match(content_type): + thumbnail_key = key + THUMB_SUFFIX + result[thumbnail_key] = memcache.delete(thumbnail_key) if 'application/json' in self.request.headers.get('Accept'): self.response.headers['Content-Type'] = 'application/json' + s = self.json_stringify(result) self.response.write(s) - -class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler): - def get(self, key, filename): - if not blobstore.get(key): - self.error(404) - else: - # Prevent browsers from MIME-sniffing the content-type: - self.response.headers['X-Content-Type-Options'] = 'nosniff' - # Cache for the expiration time: - self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME - # Send the file forcing a download dialog: - self.send_blob(key, save_as=filename, content_type='application/octet-stream') - app = webapp2.WSGIApplication( [ ('/', UploadHandler), - ('/([^/]+)/([^/]+)', DownloadHandler) + ('/(.+)/([^/]+)/([^/]+)', FileHandler) ], - debug=True + debug=DEBUG ) diff --git a/library/blueimp_upload/server/node/.gitignore b/library/blueimp_upload/server/node/.gitignore deleted file mode 100644 index 9daa8247d..000000000 --- a/library/blueimp_upload/server/node/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -node_modules diff --git a/library/blueimp_upload/server/node/package.json b/library/blueimp_upload/server/node/package.json deleted file mode 100644 index dd38c50ca..000000000 --- a/library/blueimp_upload/server/node/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "blueimp-file-upload-node", - "version": "2.1.0", - "title": "jQuery File Upload Node.js example", - "description": "Node.js implementation example of a file upload handler for jQuery File Upload.", - "keywords": [ - "file", - "upload", - "cross-domain", - "cross-site", - "node" - ], - "homepage": "https://github.com/blueimp/jQuery-File-Upload", - "author": { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - }, - "maintainers": [ - { - "name": "Sebastian Tschan", - "url": "https://blueimp.net" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/blueimp/jQuery-File-Upload.git" - }, - "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ], - "dependencies": { - "formidable": ">=1.0.11", - "node-static": ">=0.6.5", - "imagemagick": ">=0.1.3" - }, - "main": "server.js" -} diff --git a/library/blueimp_upload/server/node/public/files/.gitignore b/library/blueimp_upload/server/node/public/files/.gitignore deleted file mode 100644 index d6b7ef32c..000000000 --- a/library/blueimp_upload/server/node/public/files/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/library/blueimp_upload/server/node/server.js b/library/blueimp_upload/server/node/server.js deleted file mode 100755 index 808d6ffe1..000000000 --- a/library/blueimp_upload/server/node/server.js +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/nodejs -/* - * jQuery File Upload Plugin Node.js Example 2.1.2 - * 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 - */ - -/* jshint nomen:false */ -/* global require, __dirname, unescape, console */ - -(function (port) { - 'use strict'; - var path = require('path'), - fs = require('fs'), - // Since Node 0.8, .existsSync() moved from path to fs: - _existsSync = fs.existsSync || path.existsSync, - formidable = require('formidable'), - nodeStatic = require('node-static'), - imageMagick = require('imagemagick'), - options = { - tmpDir: __dirname + '/tmp', - publicDir: __dirname + '/public', - uploadDir: __dirname + '/public/files', - uploadUrl: '/files/', - maxPostSize: 11000000000, // 11 GB - minFileSize: 1, - maxFileSize: 10000000000, // 10 GB - acceptFileTypes: /.+/i, - // Files not matched by this regular expression force a download dialog, - // to prevent executing any scripts in the context of the service domain: - inlineFileTypes: /\.(gif|jpe?g|png)$/i, - imageTypes: /\.(gif|jpe?g|png)$/i, - imageVersions: { - 'thumbnail': { - width: 80, - height: 80 - } - }, - accessControl: { - allowOrigin: '*', - allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE', - allowHeaders: 'Content-Type, Content-Range, Content-Disposition' - }, - /* Uncomment and edit this section to provide the service via HTTPS: - ssl: { - key: fs.readFileSync('/Applications/XAMPP/etc/ssl.key/server.key'), - cert: fs.readFileSync('/Applications/XAMPP/etc/ssl.crt/server.crt') - }, - */ - nodeStatic: { - cache: 3600 // seconds to cache served files - } - }, - utf8encode = function (str) { - return unescape(encodeURIComponent(str)); - }, - fileServer = new nodeStatic.Server(options.publicDir, options.nodeStatic), - nameCountRegexp = /(?:(?: \(([\d]+)\))?(\.[^.]+))?$/, - nameCountFunc = function (s, index, ext) { - return ' (' + ((parseInt(index, 10) || 0) + 1) + ')' + (ext || ''); - }, - FileInfo = function (file) { - this.name = file.name; - this.size = file.size; - this.type = file.type; - this.deleteType = 'DELETE'; - }, - UploadHandler = function (req, res, callback) { - this.req = req; - this.res = res; - this.callback = callback; - }, - serve = function (req, res) { - res.setHeader( - 'Access-Control-Allow-Origin', - options.accessControl.allowOrigin - ); - res.setHeader( - 'Access-Control-Allow-Methods', - options.accessControl.allowMethods - ); - res.setHeader( - 'Access-Control-Allow-Headers', - options.accessControl.allowHeaders - ); - var handleResult = function (result, redirect) { - if (redirect) { - res.writeHead(302, { - 'Location': redirect.replace( - /%s/, - encodeURIComponent(JSON.stringify(result)) - ) - }); - res.end(); - } else { - res.writeHead(200, { - 'Content-Type': req.headers.accept - .indexOf('application/json') !== -1 ? - 'application/json' : 'text/plain' - }); - res.end(JSON.stringify(result)); - } - }, - setNoCacheHeaders = function () { - res.setHeader('Pragma', 'no-cache'); - res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); - res.setHeader('Content-Disposition', 'inline; filename="files.json"'); - }, - handler = new UploadHandler(req, res, handleResult); - switch (req.method) { - case 'OPTIONS': - res.end(); - break; - case 'HEAD': - case 'GET': - if (req.url === '/') { - setNoCacheHeaders(); - if (req.method === 'GET') { - handler.get(); - } else { - res.end(); - } - } else { - fileServer.serve(req, res); - } - break; - case 'POST': - setNoCacheHeaders(); - handler.post(); - break; - case 'DELETE': - handler.destroy(); - break; - default: - res.statusCode = 405; - res.end(); - } - }; - fileServer.respond = function (pathname, status, _headers, files, stat, req, res, finish) { - // Prevent browsers from MIME-sniffing the content-type: - _headers['X-Content-Type-Options'] = 'nosniff'; - if (!options.inlineFileTypes.test(files[0])) { - // Force a download dialog for unsafe file extensions: - _headers['Content-Type'] = 'application/octet-stream'; - _headers['Content-Disposition'] = 'attachment; filename="' + - utf8encode(path.basename(files[0])) + '"'; - } - nodeStatic.Server.prototype.respond - .call(this, pathname, status, _headers, files, stat, req, res, finish); - }; - FileInfo.prototype.validate = function () { - if (options.minFileSize && options.minFileSize > this.size) { - this.error = 'File is too small'; - } else if (options.maxFileSize && options.maxFileSize < this.size) { - this.error = 'File is too big'; - } else if (!options.acceptFileTypes.test(this.name)) { - this.error = 'Filetype not allowed'; - } - return !this.error; - }; - FileInfo.prototype.safeName = function () { - // Prevent directory traversal and creating hidden system files: - this.name = path.basename(this.name).replace(/^\.+/, ''); - // Prevent overwriting existing files: - while (_existsSync(options.uploadDir + '/' + this.name)) { - this.name = this.name.replace(nameCountRegexp, nameCountFunc); - } - }; - FileInfo.prototype.initUrls = function (req) { - if (!this.error) { - var that = this, - baseUrl = (options.ssl ? 'https:' : 'http:') + - '//' + req.headers.host + options.uploadUrl; - this.url = this.deleteUrl = baseUrl + encodeURIComponent(this.name); - Object.keys(options.imageVersions).forEach(function (version) { - if (_existsSync( - options.uploadDir + '/' + version + '/' + that.name - )) { - that[version + 'Url'] = baseUrl + version + '/' + - encodeURIComponent(that.name); - } - }); - } - }; - UploadHandler.prototype.get = function () { - var handler = this, - files = []; - fs.readdir(options.uploadDir, function (err, list) { - list.forEach(function (name) { - var stats = fs.statSync(options.uploadDir + '/' + name), - fileInfo; - if (stats.isFile() && name[0] !== '.') { - fileInfo = new FileInfo({ - name: name, - size: stats.size - }); - fileInfo.initUrls(handler.req); - files.push(fileInfo); - } - }); - handler.callback({files: files}); - }); - }; - UploadHandler.prototype.post = function () { - var handler = this, - form = new formidable.IncomingForm(), - tmpFiles = [], - files = [], - map = {}, - counter = 1, - redirect, - finish = function () { - counter -= 1; - if (!counter) { - files.forEach(function (fileInfo) { - fileInfo.initUrls(handler.req); - }); - handler.callback({files: files}, redirect); - } - }; - form.uploadDir = options.tmpDir; - form.on('fileBegin', function (name, file) { - tmpFiles.push(file.path); - var fileInfo = new FileInfo(file); - fileInfo.safeName(); - map[path.basename(file.path)] = fileInfo; - files.push(fileInfo); - }).on('field', function (name, value) { - if (name === 'redirect') { - redirect = value; - } - }).on('file', function (name, file) { - var fileInfo = map[path.basename(file.path)]; - fileInfo.size = file.size; - if (!fileInfo.validate()) { - fs.unlink(file.path); - return; - } - fs.renameSync(file.path, options.uploadDir + '/' + fileInfo.name); - if (options.imageTypes.test(fileInfo.name)) { - Object.keys(options.imageVersions).forEach(function (version) { - counter += 1; - var opts = options.imageVersions[version]; - imageMagick.resize({ - width: opts.width, - height: opts.height, - srcPath: options.uploadDir + '/' + fileInfo.name, - dstPath: options.uploadDir + '/' + version + '/' + - fileInfo.name - }, finish); - }); - } - }).on('aborted', function () { - tmpFiles.forEach(function (file) { - fs.unlink(file); - }); - }).on('error', function (e) { - console.log(e); - }).on('progress', function (bytesReceived) { - if (bytesReceived > options.maxPostSize) { - handler.req.connection.destroy(); - } - }).on('end', finish).parse(handler.req); - }; - UploadHandler.prototype.destroy = function () { - var handler = this, - fileName; - if (handler.req.url.slice(0, options.uploadUrl.length) === options.uploadUrl) { - fileName = path.basename(decodeURIComponent(handler.req.url)); - if (fileName[0] !== '.') { - fs.unlink(options.uploadDir + '/' + fileName, function (ex) { - Object.keys(options.imageVersions).forEach(function (version) { - fs.unlink(options.uploadDir + '/' + version + '/' + fileName); - }); - handler.callback({success: !ex}); - }); - return; - } - } - handler.callback({success: false}); - }; - if (options.ssl) { - require('https').createServer(options.ssl, serve).listen(port); - } else { - require('http').createServer(serve).listen(port); - } -}(8888)); diff --git a/library/blueimp_upload/server/node/tmp/.gitignore b/library/blueimp_upload/server/node/tmp/.gitignore deleted file mode 100644 index e69de29bb..000000000 --- a/library/blueimp_upload/server/node/tmp/.gitignore +++ /dev/null diff --git a/library/blueimp_upload/server/php/Dockerfile b/library/blueimp_upload/server/php/Dockerfile new file mode 100644 index 000000000..ca88d3d0d --- /dev/null +++ b/library/blueimp_upload/server/php/Dockerfile @@ -0,0 +1,38 @@ +FROM php:7.0-apache + +# Enable the Apache Headers module: +RUN ln -s /etc/apache2/mods-available/headers.load \ + /etc/apache2/mods-enabled/headers.load + +# Enable the Apache Rewrite module: +RUN ln -s /etc/apache2/mods-available/rewrite.load \ + /etc/apache2/mods-enabled/rewrite.load + +# Install GD, Imagick and ImageMagick as image conversion options: +RUN DEBIAN_FRONTEND=noninteractive \ + apt-get update && apt-get install -y --no-install-recommends \ + libpng-dev \ + libjpeg-dev \ + libmagickwand-dev \ + imagemagick \ + && pecl install \ + imagick \ + && docker-php-ext-enable \ + imagick \ + && docker-php-ext-configure \ + gd --with-jpeg-dir=/usr/include/ \ + && docker-php-ext-install \ + gd \ + # Uninstall obsolete packages: + && apt-get autoremove -y \ + libpng-dev \ + libjpeg-dev \ + libmagickwand-dev \ + # Remove obsolete files: + && apt-get clean \ + && rm -rf \ + /tmp/* \ + /usr/share/doc/* \ + /var/cache/* \ + /var/lib/apt/lists/* \ + /var/tmp/* diff --git a/library/blueimp_upload/server/php/UploadHandler.php b/library/blueimp_upload/server/php/UploadHandler.php index fb77be1d0..1380d4739 100755 --- a/library/blueimp_upload/server/php/UploadHandler.php +++ b/library/blueimp_upload/server/php/UploadHandler.php @@ -1,13 +1,13 @@ <?php /* - * jQuery File Upload Plugin PHP Class 8.1.0 + * jQuery File Upload Plugin PHP Class * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ class UploadHandler @@ -40,11 +40,13 @@ class UploadHandler protected $image_objects = array(); - function __construct($options = null, $initialize = true, $error_messages = null) { + public function __construct($options = null, $initialize = true, $error_messages = null) { + $this->response = array(); $this->options = array( - 'script_url' => $this->get_full_url().'/', + 'script_url' => $this->get_full_url().'/'.$this->basename($this->get_server_var('SCRIPT_NAME')), 'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/', 'upload_url' => $this->get_full_url().'/files/', + 'input_stream' => 'php://input', 'user_dirs' => false, 'mkdir_mode' => 0755, 'param_name' => 'files', @@ -67,6 +69,14 @@ class UploadHandler 'Content-Range', 'Content-Disposition' ), + // By default, allow redirects to the referer protocol+host: + 'redirect_allow_target' => '/^'.preg_quote( + parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_SCHEME) + .'://' + .parse_url($this->get_server_var('HTTP_REFERER'), PHP_URL_HOST) + .'/', // Trailing slash to not match subdomains by mistake + '/' // preg_quote delimiter param + ).'/', // Enable to provide file downloads via GET requests to the PHP script: // 1. Set to 1 to download files via readfile method through PHP // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache @@ -147,7 +157,8 @@ class UploadHandler 'max_width' => 80, 'max_height' => 80 ) - ) + ), + 'print_response' => true ); if ($options) { $this->options = $options + $this->options; @@ -167,15 +178,15 @@ class UploadHandler $this->head(); break; case 'GET': - $this->get(); + $this->get($this->options['print_response']); break; case 'PATCH': case 'PUT': case 'POST': - $this->post(); + $this->post($this->options['print_response']); break; case 'DELETE': - $this->delete(); + $this->delete($this->options['print_response']); break; default: $this->header('HTTP/1.1 405 Method Not Allowed'); @@ -300,7 +311,7 @@ class UploadHandler $this->get_upload_path($file_name) ); $file->url = $this->get_download_url($file->name); - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if (!empty($version)) { if (is_file($this->get_upload_path($file_name, $version))) { $file->{$version.'Url'} = $this->get_download_url( @@ -332,14 +343,15 @@ class UploadHandler } protected function get_error_message($error) { - return array_key_exists($error, $this->error_messages) ? + return isset($this->error_messages[$error]) ? $this->error_messages[$error] : $error; } - function get_config_bytes($val) { + public function get_config_bytes($val) { $val = trim($val); $last = strtolower($val[strlen($val)-1]); - switch($last) { + $val = (int)$val; + switch ($last) { case 'g': $val *= 1024; case 'm': @@ -355,9 +367,9 @@ class UploadHandler $file->error = $this->get_error_message($error); return false; } - $content_length = $this->fix_integer_overflow(intval( - $this->get_server_var('CONTENT_LENGTH') - )); + $content_length = $this->fix_integer_overflow( + (int)$this->get_server_var('CONTENT_LENGTH') + ); $post_max_size = $this->get_config_bytes(ini_get('post_max_size')); if ($post_max_size && ($content_length > $post_max_size)) { $file->error = $this->get_error_message('post_max_size'); @@ -398,6 +410,21 @@ class UploadHandler if (($max_width || $max_height || $min_width || $min_height) && preg_match($this->options['image_file_types'], $file->name)) { list($img_width, $img_height) = $this->get_image_size($uploaded_file); + + // If we are auto rotating the image by default, do the checks on + // the correct orientation + if ( + @$this->options['image_versions']['']['auto_orient'] && + function_exists('exif_read_data') && + ($exif = @exif_read_data($uploaded_file)) && + (((int) @$exif['Orientation']) >= 5) + ) { + $tmp = $img_width; + $img_width = $img_height; + $img_height = $tmp; + unset($tmp); + } + } if (!empty($img_width)) { if ($max_width && $img_width > $max_width) { @@ -421,7 +448,7 @@ class UploadHandler } protected function upcount_name_callback($matches) { - $index = isset($matches[1]) ? intval($matches[1]) + 1 : 1; + $index = isset($matches[1]) ? ((int)$matches[1]) + 1 : 1; $ext = isset($matches[2]) ? $matches[2] : ''; return ' ('.$index.')'.$ext; } @@ -441,8 +468,8 @@ class UploadHandler $name = $this->upcount_name($name); } // Keep an existing filename if this is part of a chunked upload: - $uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1])); - while(is_file($this->get_upload_path($name))) { + $uploaded_bytes = $this->fix_integer_overflow((int)$content_range[1]); + while (is_file($this->get_upload_path($name))) { if ($uploaded_bytes === $this->get_file_size( $this->get_upload_path($name))) { break; @@ -461,7 +488,7 @@ class UploadHandler } if ($this->options['correct_image_extensions'] && function_exists('exif_imagetype')) { - switch(@exif_imagetype($file_path)){ + switch (@exif_imagetype($file_path)){ case IMAGETYPE_JPEG: $extensions = array('jpg', 'jpeg'); break; @@ -491,7 +518,7 @@ class UploadHandler // Remove path information and dots around the filename, to prevent uploading // into different directories or replacing hidden system files. // Also remove control characters and spaces (\x00..\x20) around the filename: - $name = trim(basename(stripslashes($name)), ".\x00..\x20"); + $name = trim($this->basename(stripslashes($name)), ".\x00..\x20"); // Use a timestamp for empty filenames: if (!$name) { $name = str_replace('.', '-', microtime(true)); @@ -515,10 +542,6 @@ class UploadHandler ); } - protected function handle_form_data($file, $index) { - // Handle form data, e.g. $_REQUEST['description'][$index] - } - protected function get_scaled_image_file_paths($file_name, $version) { $file_path = $this->get_upload_path($file_name); if (!empty($version)) { @@ -601,7 +624,7 @@ class UploadHandler if ($exif === false) { return false; } - $orientation = intval(@$exif['Orientation']); + $orientation = (int)@$exif['Orientation']; if ($orientation < 2 || $orientation > 8) { return false; } @@ -825,7 +848,7 @@ class UploadHandler $this->get_scaled_image_file_paths($file_name, $version); $image = $this->imagick_get_image_object( $file_path, - !empty($options['no_cache']) + !empty($options['crop']) || !empty($options['no_cache']) ); if ($image->getImageFormat() === 'GIF') { // Handle animated GIFs: @@ -955,7 +978,7 @@ class UploadHandler return $dimensions; } return false; - } catch (Exception $e) { + } catch (\Exception $e) { error_log($e->getMessage()); } } @@ -965,7 +988,7 @@ class UploadHandler exec($cmd, $output, $error); if (!$error && !empty($output)) { // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000 - $infos = preg_split('/\s+/', $output[0]); + $infos = preg_split('/\s+/', substr($output[0], strlen($file_path))); $dimensions = preg_split('/x/', $infos[2]); return $dimensions; } @@ -1008,7 +1031,7 @@ class UploadHandler protected function handle_image_file($file_path, $file) { $failed_versions = array(); - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if ($this->create_scaled_image($file->name, $version, $options)) { if (!empty($version)) { $file->{$version.'Url'} = $this->get_download_url( @@ -1024,7 +1047,7 @@ class UploadHandler } if (count($failed_versions)) { $file->error = $this->get_error_message('image_resize') - .' ('.implode($failed_versions,', ').')'; + .' ('.implode($failed_versions, ', ').')'; } // Free memory: $this->destroy_image_object($file_path); @@ -1035,7 +1058,7 @@ class UploadHandler $file = new \stdClass(); $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error, $index, $content_range); - $file->size = $this->fix_integer_overflow(intval($size)); + $file->size = $this->fix_integer_overflow((int)$size); $file->type = $type; if ($this->validate($uploaded_file, $file, $error, $index)) { $this->handle_form_data($file, $index); @@ -1061,7 +1084,7 @@ class UploadHandler // Non-multipart uploads (PUT method support) file_put_contents( $file_path, - fopen('php://input', 'r'), + fopen($this->options['input_stream'], 'r'), $append_file ? FILE_APPEND : 0 ); } @@ -1102,41 +1125,33 @@ class UploadHandler protected function body($str) { echo $str; } - + protected function header($str) { header($str); } + protected function get_upload_data($id) { + return @$_FILES[$id]; + } + + protected function get_post_param($id) { + return @$_POST[$id]; + } + + protected function get_query_param($id) { + return @$_GET[$id]; + } + protected function get_server_var($id) { - return isset($_SERVER[$id]) ? $_SERVER[$id] : ''; + return @$_SERVER[$id]; } - protected function generate_response($content, $print_response = true) { - if ($print_response) { - $json = json_encode($content); - $redirect = isset($_REQUEST['redirect']) ? - stripslashes($_REQUEST['redirect']) : null; - if ($redirect) { - $this->header('Location: '.sprintf($redirect, rawurlencode($json))); - return; - } - $this->head(); - if ($this->get_server_var('HTTP_CONTENT_RANGE')) { - $files = isset($content[$this->options['param_name']]) ? - $content[$this->options['param_name']] : null; - if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { - $this->header('Range: 0-'.( - $this->fix_integer_overflow(intval($files[0]->size)) - 1 - )); - } - } - $this->body($json); - } - return $content; + protected function handle_form_data($file, $index) { + // Handle form data, e.g. $_POST['description'][$index] } protected function get_version_param() { - return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null; + return $this->basename(stripslashes($this->get_query_param('version'))); } protected function get_singular_param_name() { @@ -1145,14 +1160,16 @@ class UploadHandler protected function get_file_name_param() { $name = $this->get_singular_param_name(); - return isset($_REQUEST[$name]) ? basename(stripslashes($_REQUEST[$name])) : null; + return $this->basename(stripslashes($this->get_query_param($name))); } protected function get_file_names_params() { - $params = isset($_REQUEST[$this->options['param_name']]) ? - $_REQUEST[$this->options['param_name']] : array(); + $params = $this->get_query_param($this->options['param_name']); + if (!$params) { + return null; + } foreach ($params as $key => $value) { - $params[$key] = basename(stripslashes($value)); + $params[$key] = $this->basename(stripslashes($value)); } return $params; } @@ -1232,6 +1249,34 @@ class UploadHandler .implode(', ', $this->options['access_control_allow_headers'])); } + public function generate_response($content, $print_response = true) { + $this->response = $content; + if ($print_response) { + $json = json_encode($content); + $redirect = stripslashes($this->get_post_param('redirect')); + if ($redirect && preg_match($this->options['redirect_allow_target'], $redirect)) { + $this->header('Location: '.sprintf($redirect, rawurlencode($json))); + return; + } + $this->head(); + if ($this->get_server_var('HTTP_CONTENT_RANGE')) { + $files = isset($content[$this->options['param_name']]) ? + $content[$this->options['param_name']] : null; + if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { + $this->header('Range: 0-'.( + $this->fix_integer_overflow((int)$files[0]->size) - 1 + )); + } + } + $this->body($json); + } + return $content; + } + + public function get_response () { + return $this->response; + } + public function head() { $this->header('Pragma: no-cache'); $this->header('Cache-Control: no-store, no-cache, must-revalidate'); @@ -1245,7 +1290,7 @@ class UploadHandler } public function get($print_response = true) { - if ($print_response && isset($_GET['download'])) { + if ($print_response && $this->get_query_param('download')) { return $this->download(); } $file_name = $this->get_file_name_param(); @@ -1262,58 +1307,59 @@ class UploadHandler } public function post($print_response = true) { - if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') { + if ($this->get_query_param('_method') === 'DELETE') { return $this->delete($print_response); } - $upload = isset($_FILES[$this->options['param_name']]) ? - $_FILES[$this->options['param_name']] : null; + $upload = $this->get_upload_data($this->options['param_name']); // Parse the Content-Disposition header, if available: - $file_name = $this->get_server_var('HTTP_CONTENT_DISPOSITION') ? + $content_disposition_header = $this->get_server_var('HTTP_CONTENT_DISPOSITION'); + $file_name = $content_disposition_header ? rawurldecode(preg_replace( '/(^[^"]+")|("$)/', '', - $this->get_server_var('HTTP_CONTENT_DISPOSITION') + $content_disposition_header )) : null; // Parse the Content-Range header, which has the following form: // Content-Range: bytes 0-524287/2000000 - $content_range = $this->get_server_var('HTTP_CONTENT_RANGE') ? - preg_split('/[^0-9]+/', $this->get_server_var('HTTP_CONTENT_RANGE')) : null; + $content_range_header = $this->get_server_var('HTTP_CONTENT_RANGE'); + $content_range = $content_range_header ? + preg_split('/[^0-9]+/', $content_range_header) : null; $size = $content_range ? $content_range[3] : null; $files = array(); - if ($upload && is_array($upload['tmp_name'])) { - // param_name is an array identifier like "files[]", - // $_FILES is a multi-dimensional array: - foreach ($upload['tmp_name'] as $index => $value) { + if ($upload) { + if (is_array($upload['tmp_name'])) { + // param_name is an array identifier like "files[]", + // $upload is a multi-dimensional array: + foreach ($upload['tmp_name'] as $index => $value) { + $files[] = $this->handle_file_upload( + $upload['tmp_name'][$index], + $file_name ? $file_name : $upload['name'][$index], + $size ? $size : $upload['size'][$index], + $upload['type'][$index], + $upload['error'][$index], + $index, + $content_range + ); + } + } else { + // param_name is a single object identifier like "file", + // $upload is a one-dimensional array: $files[] = $this->handle_file_upload( - $upload['tmp_name'][$index], - $file_name ? $file_name : $upload['name'][$index], - $size ? $size : $upload['size'][$index], - $upload['type'][$index], - $upload['error'][$index], - $index, + isset($upload['tmp_name']) ? $upload['tmp_name'] : null, + $file_name ? $file_name : (isset($upload['name']) ? + $upload['name'] : null), + $size ? $size : (isset($upload['size']) ? + $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), + isset($upload['type']) ? + $upload['type'] : $this->get_server_var('CONTENT_TYPE'), + isset($upload['error']) ? $upload['error'] : null, + null, $content_range ); } - } else { - // param_name is a single object identifier like "file", - // $_FILES is a one-dimensional array: - $files[] = $this->handle_file_upload( - isset($upload['tmp_name']) ? $upload['tmp_name'] : null, - $file_name ? $file_name : (isset($upload['name']) ? - $upload['name'] : null), - $size ? $size : (isset($upload['size']) ? - $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), - isset($upload['type']) ? - $upload['type'] : $this->get_server_var('CONTENT_TYPE'), - isset($upload['error']) ? $upload['error'] : null, - null, - $content_range - ); } - return $this->generate_response( - array($this->options['param_name'] => $files), - $print_response - ); + $response = array($this->options['param_name'] => $files); + return $this->generate_response($response, $print_response); } public function delete($print_response = true) { @@ -1322,11 +1368,11 @@ class UploadHandler $file_names = array($this->get_file_name_param()); } $response = array(); - foreach($file_names as $file_name) { + foreach ($file_names as $file_name) { $file_path = $this->get_upload_path($file_name); $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path); if ($success) { - foreach($this->options['image_versions'] as $version => $options) { + foreach ($this->options['image_versions'] as $version => $options) { if (!empty($version)) { $file = $this->get_upload_path($file_name, $version); if (is_file($file)) { @@ -1340,4 +1386,8 @@ class UploadHandler return $this->generate_response($response, $print_response); } + protected function basename($filepath, $suffix = null) { + $splited = preg_split('/\//', rtrim ($filepath, '/ ')); + return substr(basename('X'.$splited[count($splited)-1], $suffix), 1); + } } diff --git a/library/blueimp_upload/server/php/docker-compose.yml b/library/blueimp_upload/server/php/docker-compose.yml new file mode 100644 index 000000000..691ea9caa --- /dev/null +++ b/library/blueimp_upload/server/php/docker-compose.yml @@ -0,0 +1,6 @@ +apache: + build: ./ + ports: + - "80:80" + volumes: + - "../../:/var/www/html" diff --git a/library/blueimp_upload/server/php/files/.htaccess b/library/blueimp_upload/server/php/files/.htaccess index 56689f0bb..6f454afb9 100644 --- a/library/blueimp_upload/server/php/files/.htaccess +++ b/library/blueimp_upload/server/php/files/.htaccess @@ -1,8 +1,16 @@ -# The following directives force the content-type application/octet-stream -# and force browsers to display a download dialog for non-image files. -# This prevents the execution of script files in the context of the website: +# To enable the Headers module, execute the following command and reload Apache: +# sudo a2enmod headers + +# The following directives prevent the execution of script files +# in the context of the website. +# They also force the content-type application/octet-stream and +# force browsers to display a download dialog for non-image files. +SetHandler default-handler ForceType application/octet-stream Header set Content-Disposition attachment + +# The following unsets the forced type and Content-Disposition headers +# for known image files: <FilesMatch "(?i)\.(gif|jpe?g|png)$"> ForceType none Header unset Content-Disposition diff --git a/library/blueimp_upload/server/php/index.php b/library/blueimp_upload/server/php/index.php index 3ae1295ef..6caabb710 100644 --- a/library/blueimp_upload/server/php/index.php +++ b/library/blueimp_upload/server/php/index.php @@ -1,13 +1,13 @@ <?php /* - * jQuery File Upload Plugin PHP Example 5.14 + * jQuery File Upload Plugin PHP Example * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ error_reporting(E_ALL | E_STRICT); diff --git a/library/blueimp_upload/test/index.html b/library/blueimp_upload/test/index.html index a04e53433..4a9a6f328 100644 --- a/library/blueimp_upload/test/index.html +++ b/library/blueimp_upload/test/index.html @@ -1,14 +1,14 @@ <!DOCTYPE HTML> <!-- /* - * jQuery File Upload Plugin Test 9.1.0 + * jQuery File Upload Plugin Test * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ --> <html lang="en"> @@ -20,7 +20,7 @@ <meta charset="utf-8"> <title>jQuery File Upload Plugin Test</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> -<link rel="stylesheet" href="http://codeorigin.jquery.com/qunit/qunit-1.14.0.css"> +<link rel="stylesheet" href="//codeorigin.jquery.com/qunit/qunit-1.14.0.css"> </head> <body> <h1 id="qunit-header">jQuery File Upload Plugin Test</h1> @@ -36,20 +36,20 @@ <div class="col-lg-7"> <!-- The fileinput-button span is used to style the file input field as button --> <span class="btn btn-success fileinput-button"> - <i class="fa-plus fa fa-inverse"></i> + <i class="icon-plus icon-white"></i> <span>Add files...</span> <input type="file" name="files[]" multiple> </span> <button type="submit" class="btn btn-primary start"> - <i class="fa-arrow-circle-o-up fa fa-inverse"></i> + <i class="icon-upload icon-white"></i> <span>Start upload</span> </button> <button type="reset" class="btn btn-warning cancel"> - <i class="fa-ban fa fa-inverse"></i> + <i class="icon-ban-circle icon-white"></i> <span>Cancel upload</span> </button> <button type="button" class="btn btn-danger delete"> - <i class="fa-trash-o fa fa-inverse"></i> + <i class="icon-trash icon-white"></i> <span>Delete</span> </button> <input type="checkbox" class="toggle"> @@ -168,5 +168,5 @@ window.testUIWidget = $.blueimp.fileupload; </script> <script src="//code.jquery.com/qunit/qunit-1.15.0.js"></script> <script src="test.js"></script> -</body> +</body> </html> diff --git a/library/blueimp_upload/test/test.js b/library/blueimp_upload/test/test.js index 72d08d99e..452127567 100644 --- a/library/blueimp_upload/test/test.js +++ b/library/blueimp_upload/test/test.js @@ -1,12 +1,12 @@ /* - * jQuery File Upload Plugin Test 9.4.0 + * jQuery File Upload Plugin Test * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ /* global $, QUnit, window, document, expect, module, test, asyncTest, start, ok, strictEqual, notStrictEqual */ @@ -83,7 +83,7 @@ $(function () { }); test('Paste zone initialization', function () { - ok($('#fileupload').fileupload() + ok($('#fileupload').fileupload({pasteZone: document}) .fileupload('option', 'pasteZone').length); }); @@ -98,6 +98,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -135,6 +136,7 @@ $(function () { } }, options = { + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -178,6 +180,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; @@ -221,6 +224,7 @@ $(function () { } }, fu = $('#fileupload').fileupload({ + pasteZone: document, dragover: function () { ok(true, 'Triggers dragover callback'); return false; |