├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── demo ├── client.js ├── index.html ├── layout.css └── spinner.gif ├── jquery.iframe-transport.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .grunt 3 | .sizecache.json 4 | build 5 | docs 6 | node_modules 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "browser": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "eqnull": true, 7 | "es3": true, 8 | "expr": true, 9 | "evil": true, 10 | "indent": 2, 11 | "newcap": true, 12 | "noarg": true, 13 | "scripturl": true, 14 | "undef": true, 15 | "globals": { 16 | "jQuery": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*jshint node: true, camelcase: false */ 2 | 3 | 'use strict'; 4 | 5 | module.exports = function (grunt) { 6 | 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | jshint: { 10 | files: [ 11 | 'Gruntfile.js', 12 | 'jquery.iframe-transport.js' 13 | ], 14 | options: { 15 | jshintrc: '.jshintrc' 16 | } 17 | }, 18 | uglify: { 19 | options: { 20 | banner: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.license %> */\n' 21 | }, 22 | build: { 23 | files: { 24 | 'build/jquery.iframe-transport-<%= pkg.version %>.min.js': 'jquery.iframe-transport.js' 25 | } 26 | } 27 | }, 28 | docco: { 29 | debug: { 30 | src: ['jquery.iframe-transport.js'], 31 | options: { 32 | output: 'docs/' 33 | } 34 | } 35 | }, 36 | copy: { 37 | doc: { 38 | src: 'docs/jquery.iframe-transport.html', 39 | dest: 'docs/index.html', 40 | nonull: true 41 | } 42 | }, 43 | 'gh-pages': { 44 | options: { 45 | base: 'docs' 46 | }, 47 | src: ['**'] 48 | }, 49 | connect: { 50 | server: { 51 | options: { 52 | port: 3000, 53 | base: 'demo', 54 | keepalive: true, 55 | middleware: function(connect, options, middlewares) { 56 | var multiparty = require('multiparty'), 57 | util = require('util'); 58 | middlewares.unshift(function(req, res, next) { 59 | if (req.url === '/jquery.iframe-transport.js') { 60 | return connect.static(__dirname)(req, res, next); 61 | } 62 | if (req.url !== '/upload' || req.method.toUpperCase() !== 'POST') { 63 | return next(); 64 | } 65 | 66 | var form = new multiparty.Form(); 67 | form.parse(req, function(error, fields, files) { 68 | res.writeHead(200, {'Content-Type': 'application/json'}); 69 | setTimeout(function() { 70 | res.end(JSON.stringify({ 71 | files: files['file'], 72 | comment: fields['comment'] 73 | })); 74 | }, 500); 75 | }); 76 | }); 77 | return middlewares; 78 | } 79 | } 80 | } 81 | } 82 | }); 83 | 84 | // Loading dependencies 85 | for (var key in grunt.file.readJSON('package.json').devDependencies) { 86 | if (key !== 'grunt' && key.indexOf('grunt') === 0) { 87 | grunt.loadNpmTasks(key); 88 | } 89 | } 90 | 91 | grunt.registerTask('default', ['jshint', 'uglify']); 92 | grunt.registerTask('demo', ['connect']); 93 | grunt.registerTask('doc', ['docco', 'copy:doc', 'gh-pages']); 94 | }; 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 Christopher Lenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Iframe Transport 2 | 3 | jQuery Ajax transport plugin for iframe-based file uploads. For documentation, see: 4 | 5 | [https://cmlenz.github.io/jquery-iframe-transport/](https://cmlenz.github.io/jquery-iframe-transport/) 6 | 7 | # Demo 8 | 9 | To run the included simple demo application, you'll need [node.js](http://nodejs.org/). 10 | 11 | In the `jquery-iframe-transport` source directory, run: 12 | 13 | $ npm install 14 | 15 | That should download and install all dependencies required for the build, including running the demo app. Then simply run: 16 | 17 | $ grunt connect 18 | 19 | Point your browser to http://localhost:3000/ and you should be able to play with the demo. 20 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery.iframe-transport", 3 | "version": "1.0.0", 4 | "homepage": "https://cmlenz.github.io/jquery-iframe-transport/", 5 | "authors": [ 6 | "Christopher Lenz " 7 | ], 8 | "description": "jQuery plugin that implements an iframe transport so that ajax calls support the uploading of files using standard HTML file input fields", 9 | "main": "jquery.iframe-transport.js", 10 | "dependencies": { 11 | "jquery": ">=1.6" 12 | }, 13 | "keywords": [ 14 | "jquery", 15 | "iframe", 16 | "upload", 17 | "file", 18 | "form", 19 | "ajax" 20 | ], 21 | "license": "MIT", 22 | "ignore": [ 23 | "**/.*", 24 | "node_modules", 25 | "bower_components", 26 | "Gruntfile.js" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /demo/client.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | $('form').on('click', 'button[type=submit]', function(evt) { 5 | var form = $(this.form).addClass('loading'); 6 | evt.preventDefault(); 7 | $.ajax(form.prop('action'), { 8 | data: form.find('textarea').serializeArray(), 9 | dataType: 'json', 10 | files: form.find(':file'), 11 | iframe: true, 12 | processData: false 13 | }).always(function() { 14 | form.removeClass('loading'); 15 | }).done(function(data) { 16 | console.log(data); 17 | $.each(data.files, function(idx, file) { 18 | $('
  • ' + 19 | '

    ' + 20 | '

    ,

    ' + 21 | '
  • ') 22 | .find('h4').text(file.originalFilename).end() 23 | .find('.size').text(formatSize(file.size)).end() 24 | .find('.mime').text(file.headers['content-type']).end() 25 | .find('.comment').text(data.comment || '').end() 26 | .appendTo('#filelist'); 27 | }); 28 | form.find(':file').val(''); 29 | }); 30 | }); 31 | 32 | function formatSize(size) { 33 | var units = ['B', 'KB', 'MB', 'GB'], 34 | idx = 0; 35 | if (!size) { 36 | return '0 bytes'; 37 | } 38 | while (size >= 1024) { 39 | size /= 1024; 40 | idx++; 41 | } 42 | return size.toFixed(0) + ' ' + units[idx]; 43 | } 44 | 45 | })(jQuery); 46 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery Iframe Transport Demo 5 | 6 | 9 | 10 | 11 |
    12 | 15 |

    16 | This is a simple example showing a file upload field that gets 17 | transmitted asynchronously using the iframe transport. Just choose one or 18 | more files, and they will be uploaded to the server (but not stored). After 19 | one upload has completed, you can upload more files. 20 |

    21 |

    22 | Please note that this example needs to run via 23 | grunt connect, as uploads require a server-side 24 | component to work properly. 25 |

    26 |
    27 |
    28 |
    29 |
    30 | 31 | 32 |
    33 |
    34 | 35 | 37 |
    38 |
    39 | 40 |
    41 |
    42 |
    43 |
    44 | 45 |
    46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /demo/layout.css: -------------------------------------------------------------------------------- 1 | form.loading { background: url(spinner.gif) 100% 0 no-repeat; } 2 | -------------------------------------------------------------------------------- /demo/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmlenz/jquery-iframe-transport/f9a5446f5f8a9d7bc4659ea9c49349b1f585316b/demo/spinner.gif -------------------------------------------------------------------------------- /jquery.iframe-transport.js: -------------------------------------------------------------------------------- 1 | // This [jQuery](https://jquery.com/) plugin implements an `"); 195 | 196 | // The first load event gets fired after the iframe has been injected 197 | // into the DOM, and is used to prepare the actual submission. 198 | iframe.one("load", function() { 199 | 200 | // The second load event gets fired when the response to the form 201 | // submission is received. The implementation detects whether the 202 | // actual payload is embedded in a `