Skip to content

pomeh/FileAPI

 
 

Repository files navigation

FileAPI — a set of tools for working with files.

~~~ DEMO ~~~ user pic ~~~

Support

  • Multiupload: all browsers that support HTML5 or Flash
  • Drag'n'Drop upload: files (HTML5) & directories (Chrome 21+)
  • Chunked file upload (HTML5)
  • Upload one file: all browsers
  • Working with Images: IE6+, FF 3.6+, Chrome 10+, Opera 11.1+, Safari 5.4+
    • crop, resize, preview & rotate (HTML5 or Flash)
    • auto orientation by exif (HTML5, if include FileAPI.exif.js or Flash)

Example

<span class="js-fileapi-wrapper" style="position: relative;"> <input id="user-files" type="file" multiple /> </span> <div id="preview-list"> </div>
var input = document.getElementById('user-files'); var previewNode = document.getElementById('preview-list'); // Drag'n'Drop FileAPI.event.dnd(previewNode, function (over){ $(this).css('background', over ? 'red' : ''); }, function (files){ // .. }); FileAPI.event.on(input, 'change', function (evt){ var files = FileAPI.getFiles(evt.target); // or FileAPI.getFiles(evt) // filtering FileAPI.filterFiles(files, function (file, info){ if( /image/.test(file.type) && info ){ returninfo.width >= 320 && info.height >= 240; } else { returnfile.size > 128; } }, function (fileList, ignor){ if( ignor.length ){ // ... } if( !fileList.length ){ // empty file list return; } // do preview var imageList = FileAPI.filter(fileList, function (file){ return /image/.test(file.type); }); FileAPI.each(imageList, function (imageFile){ FileAPI.Image(imageFile) .preview(100, 120) .get(function (err, image){ if( err ){ // ... } else { previewNode.appendChild(image); } }) ; }); // upload on server var xhr = FileAPI.upload({ url: '...', data: { foo: 'bar' }, // POST-data (iframe, flash, html5) headers: { 'x-header': '...' }, // request headers (html5) files: { files: FileAPI.filter(fileList, function (file){ return !/image/.test(file.type); }), pictures: imageList }, imageTransform: { maxWidth: 1024, maxHeight: 768 }, imageAutoOrientation: true, fileprogress: function (evt){ // (flash, html5) var percent = evt.loaded/evt.total*100; // ... }, progress: function (evt){ // (flash, html5) var percent = evt.loaded/evt.total*100; // ... }, complete: function (err, xhr){ // ... } }); }); });

HTML structure (templates)

API

Events

  • FileAPI.event.on(el:HTMLElement, eventType:String, fn:Function)
  • FileAPI.event.off(el:HTMLElement, eventType:String, fn:Function)
  • FileAPI.event.one(el:HTMLElement, eventType:String, fn:Function)
  • FileAPI.event.dnd(el:HTMLElement, onHover:Function, onDrop:Function)
  • jQuery('#el').dnd(onHover, onDrop)

FileAPI.Image

  • .crop(width[, height])
  • .crop(x, y, width[, height])
  • .resize(width[, height])
  • .resize(width, height, type:Enum(min,max,preview))
  • .preview(width[, height])
  • .rotate(deg)
  • .get(fn:Function)

Utils

  • FileAPI.KB
  • FileAPI.MB
  • FileAPI.GB
  • FileAPI.TB
  • FileAPI.support.html5:Boolean
  • FileAPI.support.cors:Boolean
  • FileAPI.support.dnd:Boolean
  • FileAPI.support.flash:Boolean
  • FileAPI.support.canvas:Boolean
  • FileAPI.support.dataURI:Boolean
  • FileAPI.support.chunked:Boolean
  • FileAPI.each(obj:Object|Array, fn:function, context:Mixed)
  • FileAPI.extend(dst:Object, src:Object):Object
  • FileAPI.filter(list:Array, iterator:Function):Array
  • FileAPI.isFile(file:Mixed):Boolean
  • FileAPI.toBinaryString(str:Base64):String

FileAPI.getFiles

FileAPI.event.on('#my-file-1', 'change', onSelect); // or jQuery $('#my-file-2').on('change', onSelect); function onSelect(evt/**Event*/){ // (1) extract fileList from event var files = FileAPI.getFiles(evt); // (2) or so var files = FileAPI.getFiles(evt.target); }

FileAPI.getDropFiles

function onDrop(evt){ FileAPI.getDropFiles(evt, function (files){ if( files.length ){ // ... } }); } // OR var el = document.getElementById('el'); FileAPI.event.dnd(el, function (over/**Boolean*/, evt/**Event*/){ el.style.background = over ? 'red' : ''; }, function (files/**Array*/, evt/**Event*/){ // ... });

FileAPI.getInfo

FileAPI.getInfo(imageFile/**File*/, function (err/**Boolean*/, info/**Object*/){ if( !err ){ switch( info.exif.Orientation ){ // ... } } }); // ... FileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){ // http://www.nihilogic.dk/labs/exif/exif.js // http://www.nihilogic.dk/labs/binaryajax/binaryajax.js FileAPI.readAsBinaryString(file, function (evt){ if( evt.type == 'load' ){ var binaryString = evt.result; var oFile = new BinaryFile(binaryString, 0, file.size); var exif = EXIF.readFromBinaryFile(oFile); callback(false, { 'exif': exif || {} }); } else if( evt.type == 'error' ){ callback('read_as_binary_string'); } else if( evt.type == 'progress' ){ // ... } }); });

FileAPI.filterFiles

FileAPI.filterFiles(files, function (file, info){ if( /image/.test(file.type) && info ){ returninfo.width > 320 && info.height > 240; } returnfile.size < 10 * FileAPI.MB; }, function (result, ignor){ // ... });

FileAPI.readAsImage, FileAPI.readAsDataURL (FileAPI.readAsBinaryString)

FileAPI.readAsImage(file, function (evt){ if( evt.type == 'load' ){ var images = document.getElementById('images'); images.appendChild(evt.result); } else { // ... } }); FileAPI.readAsDataURL(file, function (evt){ if( evt.type == 'load' ){ // success var result = evt.result; } else if( evt.type == 'progress' ){ var pr = evt.loaded/evt.total * 100; } else { // error } });

FileAPI.upload

var xhr = FileAPI.upload({ url: '...', data: { foo: 'bar' }, headers: { 'x-header': '...' }, files: { images: FileAPI.filter(files, function (file){ return /image/.test(file.type); }), customFile: { file: 'generate.txt', blob: customFileBlob } }, chunkSize: 0, // or chunk size in bytes, eg: FileAPI.MB*.5 (html5) chunkUploadRetry: 0, // number of retries during upload chunks (html5) imageTransform: { maxWidth: 1024, maxHeight: 768 }, imageAutoOrientation: true, prepare: function (file, options){ // prepare options for current file options.data.filename = file.name; }, upload: function (xhr, options){ // start uploading }, fileupload: function (xhr, options){ // start file uploading }, fileprogress: function (evt){ // progress file uploading var filePercent = evt.loaded/evt.total*100; }, filecomplete: function (err, xhr){ if( !err ){ var response = xhr.responseText; } }, progress: function (evt){ // total progress uploading var totalPercent = evt.loaded/evt.total*100; }, complete: function (err, xhr){ if( !err ){ // Congratulations, the uploading was successful! } } });

imageTransform

  • width:Number
  • height:Number
  • preview:Boolean
  • maxWidth:Number
  • maxHeight:Number
  • rotate:Number
FileAPI.upload({ // .. imageOriginal: false, // don't send original on server imageTransform: { // (1) Resize to 120x200 resize: { width: 120, height: 200 } // (2) create preview 320x240 thumb: { width: 320, height: 240, preview: true } // (3) Resize by max side max: { maxWidth: 800, maxHeight: 600 } // (4) Custom resize custom: function (info, transform){ return transform .crop(100, 100, 300, 200) .resize(100, 50) ; } } });

imageAutoOrientation

// (1) all images FileAPI.upload({ // .. imageAutoOrientation: true }); // (2) or so FileAPI.upload({ // .. imageAutoOrientation: true, imageTransform: { width: .., height: .. } }); // (3) or so FileAPI.upload({ // .. imageTransform: { rotate: 'auto' } }); // (4) only "800x600", original not modified FileAPI.upload({ // .. imageTransform: { "800x600": { width: 800, height: 600, rotate: 'auto' } } });

Flash settings

<script> var FileAPI = { // @required staticPath: '/js/' // @default: "./" // @optional , flashUrl: '/js/FileAPI.flash.swf' // @default: FileAPI.staticPath + "FileAPI.flash.swf" , flashImageUrl: '/js/FileAPI.flash.image.swf' // @default: FileAPI.staticPath + "FileAPI.flash.image.swf" }; </script> <script src="/js/FileAPI.min.js"></script>

Flash-request (FileReference)

The following sample HTTP POST request is sent from Flash Player to a server-side script if no parameters are specified:

 POST /handler.cfm HTTP/1.1 Accept: text/* Content-Type: multipart/form-data; boundary=----------Ij5ae0ae0KM7GI3KM7 User-Agent: Shockwave Flash Host: www.example.com Content-Length: 421 Connection: Keep-Alive Cache-Control: no-cache ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7 Content-Disposition: form-data; name="Filename" MyFile.jpg ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7 Content-Disposition: form-data; name="Filedata"; filename="MyFile.jpg" Content-Type: application/octet-stream FileDataHere ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7 Content-Disposition: form-data; name="Upload" Submit Query ------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7-- 

Chunked file upload (html5)

FileAPI.upload({ url: '...' , files: fileList , chunkSize: .5 * FileAPI.MB // 512KB , chunkUploadRetry: 1 , complete: function (err, xhr){} });

All relations between client and server is operated on level of HTTP's titles. Client sets up titles for transferring separate chunk.

Other titles are not used. Tracking name's uniqueness of delegating file is not executed. It is left on developer's consideration.

In response to delegating chunk server can reply following codes:

  • 200, 201 — chunk is successfully saved
  • 416, 500 — repairable error, you can continue upload.

All the other codes — fatal error, user's involvement is recommend.


{ name: 'fileName', type: 'mime-type', size: 'fileSize' }

XMLHttpRequest

{ status: Number, statusText: Number, readyState: Number, response: Blob, responseXML: XML, responseText: String, responseBody: String, getResponseHeader: function (name/**String*/)/**String*/{}, getAllResponseHeaders: function ()/**Object*/{}, abort: function (){} }

Cross-Domain upload-controller headers

<? header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Headers: Origin, X-Requested-With'); // and other custom headers header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); // a comma-separated list of domains if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){ exit;	} if( $_SERVER['REQUEST_METHOD'] == 'POST' ){ // ...	} ?>

iframe

POST-query

/controller.php	?foo=bar	&images=...	&callback=... 

POST-response

<script type="text/javascript"> (function (ctx, jsonp){ if( ctx && ctx[jsonp] ){	ctx[jsonp](<?=$statusCode/*200 — OK*/?>, "<?=addslashes($statusText)?>", "<?=addslashes($response)?>");	} })(this.parent, "<?=htmlspecialchars($_POST['callback'])?>"); </script>

HTML structure (templates)

Default

<span class="js-fileapi-wrapper" style="position: relative; display: inline-block;"> <input name="files" type="file" multiple /> </span>

Button

<style> .upload-btn { width: 130px; height: 25px; overflow: hidden; position: relative; border: 3px solid #06c; border-radius: 5px; background: #0cf; }	.upload-btn:hover { background: #09f;	}	.upload-btn__txt { z-index: 1; position: relative; color: #fff; font-size: 18px; font-family: "Helvetica Neue"; line-height: 24px; text-align: center; text-shadow: 0 1px 1px #000;	}	.upload-btn__inp { top: -10px; right: -40px; z-index: 2; position: absolute; cursor: pointer; opacity: 0; filter: alpha(opacity=0); font-size: 50px;	} </style> <div class="upload-btn js-fileapi-wrapper"> <div class="upload-btn__txt">Upload files</div> <input class="upload-btn__inp" name="files" type="file" multiple /> </div>

Link

<style> .upload-link { color: #36c; display: inline-block; *zoom: 1; *display: inline; overflow: hidden; position: relative; padding-bottom: 2px; text-decoration: none; }	.upload-link__txt { z-index: 1; position: relative; border-bottom: 1px dotted #36c;	}	.upload-link:hover .upload-link__txt { color: #f00; border-bottom-color: #f00;	}	.upload-link__inp { top: -10px; right: -40px; z-index: 2; position: absolute; cursor: pointer; opacity: 0; filter: alpha(opacity=0); font-size: 50px;	} </style> <a class="upload-link js-fileapi-wrapper"> <span class="upload-link__txt">Upload photo</span> <input class="upload-link__inp" name="photo" type="file" accept=".jpg,.jpeg,.gif" /> </a>

Changelog

1.2.0

  • #57: Chunked file upload

1.1.0

  • #54: added FileAPI.flashUrl and FileAPI.flashImageUrl

1.0.1

  • #51: remove circular references from file-objects (Flash transport)
  • added changelog

1.0.0

  • first release

About

FileAPI — a set of javascript tools for working with files.

Resources

License

Stars

Watchers

Forks

Packages

No packages published