Skip to content
forked from mailru/FileAPI

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

License

Notifications You must be signed in to change notification settings

im-saxo/FileAPI

 
 

Repository files navigation

FileAPI

A set of javascript tools for working with files.

Get started

	<div>
		<!-- "js-fileapi-wrapper" -- required class -->
		<div class="js-fileapi-wrapper upload-btn" id="choose">
			<div class="upload-btn__txt">Choose files</div>
			<input name="files" type="file" multiple />
		</div>
		<div id="images"><!-- previews --></div>
	</div>

	<script>window.FileAPI = { staticPath: '/js/FileAPI/dist/' };</script>
	<script src="/js/FileAPI/dist/FileAPI.min.js"></script>
	<script>
		FileAPI.event.on(choose, 'change', function (evt){
			var files = FileAPI.getFiles(evt); // Retrieve file list

			FileAPI.filterFiles(files, function (file, info/**Object*/){
				if( /^image/.test(file.type) ){
					return	info.width >= 320 && info.height >= 240;
				}
				return	false;
			}, function (files/**Array*/, rejected/**Array*/){
				if( files.length ){
					// Make preview 100x100
					FileAPI.each(files, function (file){
						FileAPI.Image(file).preview(100).get(function (err, img){
							images.appendChild(img);
						});
					});

					// Uploading Files
					FileAPI.upload({
						url: './ctrl.php',
						files: { images: files },
						progress: function (evt){ /* ... */ },
						complete: function (err, xhr){ /* ... */ }
					});
				}
			});
		});
	</script>

Setup options

Edit the file crossdomain.xml and place it to the root of the domain to which files will be uploaded.

	<script>
		window.FileAPI = {
			  debug: false   // debug mode, see Console
			, cors: false    // if used CORS, set `true`
			, media: false   // if used WebCam, set `true`
			, staticPath: '/js/FileAPI/dist/' // path to '*.swf'
			, postNameConcat: function (name, idx){
				// Default: object[foo]=1&object[bar][baz]=2
				// .NET: https://github.com/mailru/FileAPI/issues/121#issuecomment-24590395
				return	name + (idx != null ? '['+ idx +']' : '');
			}
		};
	</script>
	<script src="/js/FileAPI/dist/FileAPI.min.js"></script>

	<!-- OR -->

	<script>
		window.FileAPI = { /* options */ };
		require(['FileAPI'], function (FileAPI){
			// ...
		});
	</script>

getFiles(input:HTMLInputElement|Event|$.Event):Array

Retrieve file list from input element or event object, also support jQuery.

  • input — HTMLInputElement, change and drop event, jQuery collection or jQuery.Event
var el = document.getElement('my-input');
FileAPI.event.on(el, function (evt/**Event*/){
	// Retrieve file list
	var files = FileAPI.getFiles(el);

	// or event
	var files = FileAPI.getFiles(evt);
});

getInfo(file:Object, callback:Function):void

Get info of file (see also: FileAPI.addInfoReader).

// Get info of image file (FileAPI.exif.js included)
FileAPI.getInfo(file, function (err/**String*/, info/**Object*/){
	if( !err ){
		console.log(info); // { width: 800, height: 600, exif: {..} }
	}
});

// Get info of mp3 file (FileAPI.id3.js included)
FileAPI.getInfo(file, function (err/**String*/, info/**Object*/){
	if( !err ){
		console.log(info); // { title: "...", album: "...", artists: "...", ... }
	}
});

filterFiles(files:Array, filter:Function, callback:Function):void

Filtering the list of files, with additional information about files. See also: FileAPI.getInfo and FileAPI.addInfoReader.

  • files — original list of files
  • filter — function, takes two arguments: file — the file itself, info — additional information.
  • callback — function: list — files that match the condition, other — all the rest.
// Get list of file
var files = FileAPI.getFiles(input);

// Filter the List
FileAPI.filterFiles(files, function (file/**Object*/, info/**Object*/){
	if( /^image/.test(file.type) && info ){
		return	info.width > 320 && info.height > 240;
	} else {
		return	file.size < 20 * FileAPI.MB;
	}
}, function (list/**Array*/, other/**Array*/){
	if( list.length ){
		// ..
	}
});

getDropFiles(evt:Event|$.Event, callback:Function):void

Get a list of files, including directories.

  • evt — drop event
  • callback — function, takes one argument, a list of files
FileAPI.event.on(document, 'drop', function (evt/**Event*/){
	evt.preventDefault();

	// Get a list of files
	FileAPI.getDropFiles(evt, function (files/**Array*/){
		// ...
	});
});

upload(opts:Object):XmlHttpRequestPromise

Uploading files to the server (serial: true by default). Returns XHR-like object. It is important to remember to correctly worked flash-transport server response body must not be empty, for example, you can pass, just text "ok".

var el = document.getElementById('my-input');
FileAPI.event.on(el, 'change', function (evt/**Event*/){
	var files = FileAPI.getFiles(evt);
	var xhr = FileAPI.upload({
		url: 'https://rubaxa.org/FileAPI/server/ctrl.php',
		files: { file: files[0] },
		complete: function (err, xhr){
			if( !err ){
				var result = FileAPI.parseJSON(xhr.responseText);
				// ...
			}
		}
	});
});

upload(url:String, files:Mixed[, opts:Object]):XmlHttpRequestPromise

  • url — a string containing the URL to which the request is sent.
  • files — Array, Object or HTMLInput
FileAPI.upload('./ctpl.php', files).done(function (xhr){
	var result = FileAPI.parseJSON(xhr.responseText);
	// ...
});

addInfoReader(mime:RegExp, handler:Function):void

Adds a handler for the collection of information about a file. See also: FileAPI.getInfo and FileAPI.filterFiles.

  • mime — pattern of mime-type
  • handler — takes two arguments: file object and complete function callback
FileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){
	// https://www.nihilogic.dk/labs/exif/exif.js
	// https://www.nihilogic.dk/labs/binaryajax/binaryajax.js
	FileAPI.readAsBinaryString(file, function (evt/**Object*/){
		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' ){
			// ...
		}
	});
});

readAsDataURL(file:Object, callback:Function):void

Reading the contents of the specified File as dataURL.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsDataURL(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var dataURL = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsBinaryString(file:Object, callback:Function):void

Reading the contents of the specified File as BinaryString.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsBinaryString(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var binaryString = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsArrayBuffer(file:Object, callback:Function):void

Reading the contents of the specified File as ArrayBuffer.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsArrayBuffer(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var arrayBuffer = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsText(file:Object, callback:Function):void

Reading the contents of the specified File as text.

  • file — file object
  • callback — function, receives a result
FileAPI.readAsText(file, function (evt/**Object*/){
	if( evt.type == 'load' ){
		// Success
	 	var text = evt.result;
	} else if( evt.type =='progress' ){
		var pr = evt.loaded/evt.total * 100;
	} else {
		// Error
	}
})

readAsText(file:Object, encoding:String, callback:Function):void

Reading the contents of the specified File as text.

  • encoding — a string indicating the encoding to use for the returned data. By default, UTF-8.
FileAPI.readAsText(file, "utf-8", function (evt/**Object*/){
	/*__*/
})

Upload options

url:String

A string containing the URL to which the request is sent.


data:Object

Additional post data to be sent along with the file uploads.

var xhr = FileAPI.upload({
	url: '...',
	data: { 'session-id': 123 },
	files: { ... },
});

headers:Object

Additional request headers, HTML5 or Flash only.

var xhr = FileAPI.upload({
	url: '...',
	headers: { 'x-upload': 'fileapi' },
	files: { .. },
});

files:Object|Array

Key-value object, key — post name, value — File or FileAPI.Image object. Or an array of files.

var xhr = FileAPI.upload({
	url: '...',
	files: {
		audio: files
	}
});

postName:String

The parameter name for the file form data (the request argument name). Default: 'files'.

var xhr = FileAPI.upload({
	url: '...',
	files: myFiles,
	postName: 'images'
});

serial:Boolean

Serially uploading files to the server. Default: 'true'. false — only HTML5, all files are uploading to the server a single request.

var xhr = FileAPI.upload(
	  './ctrl.php'
	, files
	, { serial: false } // false — only HTML5
);

parallel:Number

Number of parallel file uploads. Default: 0. Only HTML5.

var xhr = FileAPI.upload(
	  './ctrl.php'
	, files
	, { parallel: 3 } // только HTML5.
);

chunkSize:Number

Chunk size in bytes, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	files: { images: fileList },
	chunkSize: 0.5 * FileAPI.MB
});

chunkUploadRetry:Number

Number of retries during upload chunks, HTML5 only.

var xhr = FileAPI.upload({
	url: '...',
	files: { images: fileList },
	chunkSize: 0.5 * FileAPI.MB,
	chunkUploadRetry: 3
});

--

imageTransform:Object

Rules of changes the original image on the client.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	// Changes the original image
	imageTransform: {
		// resize by max side
		maxWidth: 800,
		maxHeight: 600,
		// Add watermark
		overlay: [{ x: 10, y: 10, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]
	}
});

--

imageTransform:Object

Rules of image transformation on the client, for more images.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	imageTransform: {
		// resize by max side
		'huge': { maxWidth: 800, maxHeight: 600 },
		// crop & resize
		'medium': { width: 320, height: 240, preview: true },
		// crop & resize + watemark
		'small': {
			width: 100, height: 100, preview: true,
			// Add watermark
			overlay: [{ x: 5, y: 5, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]
		}
	}
});

--

imageTransform:Object

Convert all images to jpeg or png.

var xhr = FileAPI.upload({
	url: '...',
	files: { image: imageFiles },
	imageTransform: {
		type: 'image/jpeg',
		quality: 0.86 // jpeg quality
	}
});

imageOriginal:Boolean

Sent to the server the original image or not, if defined imageTransform option.

--

imageAutoOrientation:Boolean

Auto-rotate images on the basis of EXIF.

--

prepare:Function

Prepare options upload for a particular file.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	prepare: function (file/**Object*/, options/**Object*/){
		options.data.secret = utils.getSecretKey(file.name);
	}
});

--

upload:Function

Start uploading.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	upload: function (xhr/**Object*/, options/**Object*/){
		// ...
	}
});

--

fileupload:Function

Start file uploading.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	uploadfile: function (file/**Object*/, xhr/**Object*/, options/**Object*/){
		// ...
	}
});

--

progress:Function

Callback for upload progress events.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	progress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){
		var pr = evt.loaded/evt.total * 100;
	}
});

--

fileprogress:Function

Callback for upload file progress events.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	fileprogress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){
		var pr = evt.loaded/evt.total * 100;
	}
});

--

complete:Function

Callback for end upload requests.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	complete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){
		if( !err ){
			// All files successfully uploaded.
		}
	}
});

--

filecomplete:Function

Callback for end upload requests.

var xhr = FileAPI.upload({
	url: '...',
	files: { .. }
	filecomplete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){
		if( !err ){
			// File successfully uploaded
			var result = xhr.responseText;
		}
	}
});

File object

name:String

The name of the file referenced by the File object.

type:String

The type (MIME type) of the file referenced by the File object.

size:Number

The size (in bytes) of the file referenced by the File object.


XmlHttpRequestPromise

status:Number

The status of the response to the request. This is the HTTP result code (for example, status is 200 for a successful request).


statusText:String

The response string returned by the HTTP server. Unlike status, this includes the entire text of the response message ("200 OK", for example).


responseXML:Document

The response to the request as a DOM Document object, or null if the request was unsuccessful, has not yet been sent, or cannot be parsed as XML or HTML. The response is parsed as if it were a text/xml stream. When the responseType is set to "document" and the request has been made asynchronously, the response is parsed as it were a text/html stream.


responseText:String

The response to the request as text, or null if the request was unsuccessful or has not yet been sent.


abort():void

Aborts the request if it has already been sent.


getAllResponseHeaders():String

Returns all the response headers as a string, or null if no response has been received.


getResponseHeader(name:String):String

Returns the string containing the text of the specified header, or null if either the response has not yet been received or the header doesn't exist in the response.

  • name — header name

success(callback:Function):XmlHttpRequestPromise

A function to be called if the request succeeds.

  • callback — receives two arguments: xhr and options

error(callback:Function):XmlHttpRequestPromise

A function to be called if the request failure.

  • callback — receives three arguments: error, xhr and options

FileAPI.event

on(el:HTMLElement, events:String, handler:Function):void

Attach an event handler function.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — A function to execute when the event is triggered.

off(el:HTMLElement, events:String, handler:Function):void

Remove an event handler.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — a handler function previously attached for the event(s).

one(el:HTMLElement, events:String, handler:Function):void

Attach an event handler function. The handler is executed at most once.

  • el — DOM element
  • events — one or more space-separated event types.
  • handler — a function to execute when the event is triggered.

dnd(el:HTMLElement, hover:Function, handler:Function):void

Attach an drag and drop event handler function.

  • el — drop zone
  • hover — dragenter and dragleave listener
  • handler — drop event handler.
var el = document.getElementById('dropzone');
FileAPI.event.dnd(el, function (over){
	el.style.backgroundColor = over ? '#f60': '';
}, function (files){
	if( files.length ){
		// Upload their.
	}
});

// or jQuery
$('#dropzone').dnd(hoverFn, dropFn);

dnd.off(el:HTMLElement, hover:Function, handler:Function):void

Remove an drag and drop event handler function.

  • el — drop zone
  • hover — dragenter and dragleave listener
  • handler — drop event handler.
// Native
FileAPI.event.dnd.off(el, hoverFn, dropFn);

// jQuery
$('#dropzone').dndoff(hoverFn, dropFn);

--

FileAPI.Image

Class for working with images

constructor(file:Object):void

The constructor takes a single argument, the File object.

  • file — the File object
FileAPI.Image(imageFile).get(function (err/**String*/, img/**HTMLElement*/){
	if( !err ){
		document.body.appendChild( img );
	}
});

crop(width:Number, height:Number):FileAPI.Image

Crop image by width and height.

  • width — new image width
  • height — new image height
FileAPI.Image(imageFile)
	.crop(640, 480)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

crop(x:Number, y:Number, width:Number, height:Number):FileAPI.Image

Crop image by x, y, width and height.

  • x — offset from the left corner
  • y — offset from the top corner
FileAPI.Image(imageFile)
	.crop(100, 50, 320, 240)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

resize(width:Number, height:Number[, strategy:String]):FileAPI.Image

Resize image.

  • width — new image width
  • height — new image height
  • strategy — enum: min, max, preview. By default undefined.
FileAPI.Image(imageFile)
	.resize(320, 240)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

// Resize image on by max side.
FileAPI.Image(imageFile)
	.resize(320, 240, 'max')
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

preview(width:Number[, height:Number]):FileAPI.Image

Crop and resize image.

  • width — new image width
  • height — new image height
FileAPI.Image(imageFile)
	.preview(100, 100)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

rotate(deg:Number):FileAPI.Image

Rotate image.

  • deg — rotation angle in degrees
FileAPI.Image(imageFile)
	.rotate(90)
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

rotate(type:String):FileAPI.Image

Auto rotate image by exif.

  • type — "auto"
FileAPI.Image(imageFile)
	.rotate("auto")
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

filter(callback:Function):FileAPI.Image

Apply filter function. Only HTML5.

  • callback — takes two arguments, canvas element and done method.
FileAPI.Image(imageFile)
	.filter(function (canvas/**HTMLCanvasElement*/, doneFn/**Function*/){
		// bla-bla-lba
		doneFn();
	})
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

filter(name:String):FileAPI.Image

Uses CamanJS, include it before FileAPI library.

  • name — CamanJS filter name (custom or preset)
Caman.Filter.register("my-funky-filter", function () {
	// https://camanjs.com/guides/#Extending
});

FileAPI.Image(imageFile)
	.filter("my-funky-filter") // or .filter("vintage")
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

overlay(images:Array):FileAPI.Image

Add overlay images, eg: watermark.

  • images — array of overlays
FileAPI.Image(imageFile)
	.overlay([
		// Left corner.
		{ x: 10, y: 10, w: 100, h: 10, src: '/i/watermark.png' },

		// Right bottom corner.
		{ x: 10, y: 10, src: '/i/watermark.png', rel: FileAPI.Image.RIGHT_BOTTOM }
	])
	.get(function (err/**String*/, img/**HTMLElement*/){

	})
;

get(fn:Function):FileAPI.Image

Get the final image.

  • fn — complete callback

FileAPI.Camera

To work with a webcam, be sure to set FileAPI.media: true.

publish(el:HTMLElement, options:Object, callback:Function):void

Publication of the camera.

  • el — target
  • options — { width: 100%, height: 100%, start: true }
  • callback — the first parameter is a possible error, the second instance of FileAPI.Camera
var el = document.getElementById('cam');
FileAPI.Camera.publish(el, { width: 320, height: 240 }, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		// The webcam is ready, you can use it.
	}
});

start(callback:Function):void

Turn on the camera.

  • callback — will be called when the camera ready
var el = document.getElementById('cam');
FileAPI.Camera.publish(el, { start: false }, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		// Turn on
		cam.start(function (err){
			if( !err ){
				// The camera is ready for use.
			}
		});
	}
});

stop():void

Turn off the camera.


shot():FileAPI.Image

Take a picture with the camera.

var el = document.getElementById('cam');
FileAPI.Camera.publish(el, function (err, cam/**FileAPI.Camera*/){
	if( !err ){
		var shot = cam.shot(); // take a picture

		// create thumbnail 100x100
		shot.preview(100).get(function (err, img){
			previews.appendChild(img);
		});

		// and/or
		FileAPI.upload({
			url: '...',
			files: { cam: shot
		});
	}
});

Сonstants

FileAPI.KB:Number

1024 bytes

FileAPI.MB:Number

1048576 bytes

FileAPI.GB:Number

1073741824 bytes

FileAPI.TB:Number

1.0995116e+12 bytes


Utils

FileAPI.each(obj:Object|Array, callback:Function[, thisObject:Mixed]):void

Iterate over a object or array, executing a function for each matched element.

  • obj — array or object
  • callback — a function to execute for each element.
  • thisObject — object to use as this when executing callback.

--

FileAPI.extend(dst:Object, src:Object):Object

Merge the contents of two objects together into the first object.

  • dst — an object that will receive the new properties
  • src — an object containing additional properties to merge in.

--

FileAPI.filter(array:Array, callback:Function[, thisObject:Mixed):Object

Creates a new array with all elements that pass the test implemented by the provided function.

  • array — original Array
  • callback — Function to test each element of the array.
  • thisObject — object to use as this when executing callback.

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)

FileAPI.support.html5:Boolean

HTML5 borwser support

FileAPI.support.cors:Boolean

This cross-origin resource sharing is used to enable cross-site HTTP requests.

FileAPI.support.dnd:Boolean

Drag'n'drop events support.

FileAPI.support.flash:Boolean

Availability Flash plugin.

FileAPI.support.canvas:Boolean

Canvas support.

FileAPI.support.dataURI:Boolean

Support dataURI as src for image.

FileAPI.support.chunked:Boolean

Support chuncked upload.


Flash

Flash is very "buggy" thing :] The server response can not be empty. Therefore, in the event of a successful uploading http status should be only 200 OK.

Settings

Flash settings. It is advisable to place flash on the same server where the files will be uploaded.

<script>
	var FileAPI = {
	 	// @default: "./dist/"
		staticPath: '/js/',

		 // @default: FileAPI.staticPath + "FileAPI.flash.swf"
		flashUrl: '/statics/FileAPI.flash.swf',

		// @default: FileAPI.staticPath + "FileAPI.flash.image.swf"
		flashImageUrl: '/statics/FileAPI.flash.image.swf'
	};
</script>
<script src="/js/FileAPI.min.js"></script>

crossdomain.xml

Necessarily make this file on the server. Do not forget to replace youdomain.com on the name of your domain.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "https://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="all"/>
	<allow-access-from domain="youdomain.com" secure="false"/>
	<allow-access-from domain="*.youdomain.com" secure="false"/>
	<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>

request

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

POST /server/ctrl.php HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7
User-Agent: Shockwave Flash
Host: www.youdomain.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

[[..FILE_DATA_HERE..]]
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"

Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--

Server settings

IFrame/JSONP

<script>
(function (ctx, jsonp){
	'use strict';
	var status = {{httpStatus}}, statusText = "{{httpStatusText}}", response = "{{responseBody}}";
	try {
		ctx[jsonp](status, statusText, response);
	} catch (e){
		var data = "{\"id\":\""+jsonp+"\",\"status\":"+status+",\"statusText\":\""+statusText+"\",\"response\":\""+response.replace(/\"/g, '\\\\\"')+"\"}";
		try {
			ctx.postMessage(data, document.referrer);
		} catch (e){}
	}
})(window.parent, '{{request_param_callback}}');
</script>

<!-- or -->

<?php
	include './FileAPI.class.php';

	if( strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' ){
		// Retrieve File List
		$files	= FileAPI::getFiles();

		// ... your logic

		// JSONP callback name
		$jsonp	= isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : null;

		// Server response: "HTTP/1.1 200 OK"
		FileAPI::makeResponse(array(
			  'status' => FileAPI::OK
			, 'statusText' => 'OK'
			, 'body' => array('count' => sizeof($files)
		), $jsonp);
		exit;
	}
?>

CORS

Enable CORS.

<?php
	// Permitted types of request
    header('Access-Control-Allow-Methods: POST, OPTIONS');

    // Describe custom headers
    header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type');

    // A comma-separated list of domains
    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);

	// Allow cookie
	header('Access-Control-Allow-Credentials: true');

    if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){
        exit;
    }

    if( $_SERVER['REQUEST_METHOD'] == 'POST' ){
        // ...
    }
?>

Chunked file upload

Client and server communicate to each other using the following HTTP headers and status codes.
Client explicitly sets the following headers:

  • Content-Range: bytes <start-offset>-<end-offset>/<total>
  • Content-Disposition: attachment; filename=<file-name>
Any other headers are set by a target browser and are not used by client. Library does not provide any facilities to track a file uniqueness across requests, it's left on developer's consideration.
Response codes:
  • 200 - last chunk is uploaded
  • 201 - chunk is successfully saved
  • 416 - range is not acceptable error, recoverable
  • 500 - server error, recoverable
For recoverable errors server tries to resend chunk `chunkUploadRetry` times then fails.
  • X-Last-Known-Byte: int, library tries to resend chunk from the given offset. Applicable to response codes 200 and 416
  • All the other codes - fatal error, user's involvement is recommend.

    Buttons examples

    Base

    Simple input[type="file"]

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

    Button

    Stylized 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 input {
            top: -10px;
            right: -40px;
            z-index: 2;
            position: absolute;
            cursor: pointer;
            opacity: 0;
            filter: alpha(opacity=0);
            font-size: 50px;
        }
    </style>
    <div class="js-fileapi-wrapper upload-btn">
        <div class="upload-btn__txt">Upload files</div>
        <input name="files" type="file" multiple />
    </div>

    Link

    Button like 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 input {
            top: -10px;
            right: -40px;
            z-index: 2;
            position: absolute;
            cursor: pointer;
            opacity: 0;
            filter: alpha(opacity=0);
            font-size: 50px;
        }
    </style>
    <a class="js-fileapi-wrapper upload-link">
        <span class="upload-link__txt">Upload photo</span>
        <input name="photo" type="file" accept="image/*" />
    </a>

    Installation, testing, assembling

    npm install fileapi
    cd fileapi
    npm install
    grunt


    Changelog

    • + QUnit-tests for iframe-transport
    • + `postMessage` for iframe-transport
    • + `jsonp: "callback"` option
    • * resize: `imageTransform.type` rename to `imageTransform.strategy` (!!!)

    2.0.2

    • + test: upload headers
    • + test: upload + camanjs
    • + test: upload + autoOrientation
    • FileAPI.class.php: + HTTP header Content-Type: application/json
    • #143: + `FileAPI.flashWebcamUrl` option
    • * merge v1.2.7
    • + `FileAPI.formData: true` option

    2.0.1

    • + support 'filter' prop in imageTransform

    2.1.0

    • + Flash-fallback for `readAsDataURL`, `readAsBinaryString` and `readAsText`
    • + `FileAPI.upload(url, files[, opts])`
    • #134: + `FileAPI.getMimeType(file)`
    • + `serial: true` upload option
    • + `postName: 'files'` uplaod option

    2.0.0

    1.2.6

    1.2.5

    1.2.4

    1.2.3

    1.2.2

    1.2.1

    1.2.0

    1.1.0

    1.0.1

    1.0.0

    • first release

    About

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

    Resources

    License

    Stars

    Watchers

    Forks

    Releases

    No releases published

    Packages

    No packages published

    Languages

    • JavaScript 72.3%
    • ActionScript 25.5%
    • CSS 1.7%
    • PHP 0.5%