$ cnpm install fileapi

A set of JavaScript tools for working with files.
Download the files from the dist directory, and then:
<div>
<!-- "js-fileapi-wrapper" -- required class -->
<div class="js-fileapi-wrapper upload-btn">
<div class="upload-btn__txt">Choose files</div>
<input id="choose" 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>
var choose = document.getElementById('choose');
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>
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>
:HTMLInputElement|Event|$.Event):ArrayRetrieve file list from input element or event object, also support jQuery.
HTMLInputElement, change and drop event, jQuery collection or jQuery.Eventvar el = document.getElement('my-input');
FileAPI.event.on(el, 'change', function (evt/**Event*/){
// Retrieve file list
var files = FileAPI.getFiles(el);
// or event
var files = FileAPI.getFiles(evt);
});
:Object, callback:Function):voidGet 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: "...", ... }
}
});
:Array, filter:Function, callback:Function):voidFiltering the list of files, with additional information about files. See also: FileAPI.getInfo and FileAPI.addInfoReader.
file — the file itself, info — additional information.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 ){
// ..
}
});
:Event|$.Event, callback:Function):voidGet a list of files, including directories.
drop eventFileAPI.event.on(document, 'drop', function (evt/**Event*/){
evt.preventDefault();
// Get a list of files
FileAPI.getDropFiles(evt, function (files/**Array*/){
// ...
});
});
:Object):XmlHttpRequestUploading files to the server (successively). 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: 'http://rubaxa.org/FileAPI/server/ctrl.php',
files: { file: files[0] },
complete: function (err, xhr){
if( !err ){
var result = xhr.responseText;
// ...
}
}
});
});
:RegExp, handler:Function):voidAdds a handler for the collection of information about a file. See also: FileAPI.getInfo and FileAPI.filterFiles.
file object and complete function callbackFileAPI.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/**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' ){
// ...
}
});
});
:Object, callback:Function):voidReading the contents of the specified File as dataURL.
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
}
})
:Object, callback:Function):voidReading the contents of the specified File as BinaryString.
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
}
})
:Object, callback:Function):voidReading the contents of the specified File as ArrayBuffer.
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
}
})
:Object, callback:Function):voidReading the contents of the specified File as text.
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
}
})
:Object, encoding:String, callback:Function):voidReading the contents of the specified File as text.
FileAPI.readAsText(file, "utf-8", 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
}
})
:StringA string containing the URL to which the request is sent.
:ObjectAdditional post data to be sent along with the file uploads.
var xhr = FileAPI.upload({
url: '...',
data: { 'session-id': 123 },
files: { ... },
});
:StringRequest method, HTML5 only.
var xhr = FileAPI.upload({
url: '...',
uploadMethod: 'PUT',
files: { .. },
});
:BooleanPass credentials to upload request, HTML5 only.
var xhr = FileAPI.upload({
url: '...',
uploadCredentials: false,
files: { .. },
});
:ObjectAdditional request headers, HTML5 only.
var xhr = FileAPI.upload({
url: '...',
headers: { 'x-upload': 'fileapi' },
files: { .. },
});
:BooleanSetting to true removes the default timestamp URL parameter.
:ObjectKey-value object, key — post name, value — File or FileAPI.Image object.
var xhr = FileAPI.upload({
url: '...',
files: {
audio: files
}
});
:NumberChunk size in bytes, HTML5 only.
var xhr = FileAPI.upload({
url: '...',
files: { images: fileList },
chunkSize: 0.5 * FileAPI.MB
});
:NumberNumber of retries during upload chunks, HTML5 only.
var xhr = FileAPI.upload({
url: '...',
files: { images: fileList },
chunkSize: 0.5 * FileAPI.MB,
chunkUploadRetry: 3
});
--
:ObjectRules 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 }]
}
});
--
:ObjectRules 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,
// Add watermark
overlay: [{ x: 5, y: 5, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]
}
}
});
--
:ObjectConvert all images to jpeg or png.
var xhr = FileAPI.upload({
url: '...',
files: { image: imageFiles },
imageTransform: {
type: 'image/jpeg',
quality: 0.86 // jpeg quality
}
});
:BooleanSent to the server the original image or not, if defined imageTransform option.
--
:BooleanAuto-rotate images on the basis of EXIF.
--
:FunctionPrepare 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);
}
});
--
:FunctionStart uploading.
var xhr = FileAPI.upload({
url: '...',
files: { .. }
upload: function (xhr/**Object*/, options/**Object*/){
// ...
}
});
--
:FunctionStart file uploading.
var xhr = FileAPI.upload({
url: '...',
files: { .. }
fileupload: function (file/**Object*/, xhr/**Object*/, options/**Object*/){
// ...
}
});
--
:FunctionCallback 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;
}
});
--
:FunctionCallback 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;
}
});
--
:FunctionCallback 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.
}
}
});
--
:FunctionCallback 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;
}
}
});
The name of the file referenced by the File object.
The type (MIME type) of the file referenced by the File object.
The size (in bytes) of the file referenced by the File object.
:HTMLElement, events:String, handler:Function):voidAttach an event handler function.
:HTMLElement, events:String, handler:Function):voidRemove an event handler.
:HTMLElement, events:String, handler:Function):voidAttach an event handler function. The handler is executed at most once.
:HTMLElement, hover:Function, handler:Function):voidAttach an drag and drop event handler function.
dragenter and dragleave listenerdrop 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);
:HTMLElement, hover:Function, handler:Function):voidRemove an drag and drop event handler function.
dragenter and dragleave listenerdrop event handler.// Native
FileAPI.event.dnd.off(el, hoverFn, dropFn);
// jQuery
$('#dropzone').dndoff(hoverFn, dropFn);
--
Class for working with images
:Object):voidThe constructor takes a single argument, the File object.
File objectFileAPI.Image(imageFile).get(function (err/**String*/, img/**HTMLElement*/){
if( !err ){
document.body.appendChild( img );
}
});
:Number, height:Number):FileAPI.ImageCrop image by width and height.
FileAPI.Image(imageFile)
.crop(640, 480)
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Number, y:Number, width:Number, height:Number):FileAPI.ImageCrop image by x, y, width and height.
FileAPI.Image(imageFile)
.crop(100, 50, 320, 240)
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Number, height:Number[, strategy:String]):FileAPI.ImageResize image.
min, max, preview, width, height. 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*/){
})
;
// Resize image on by fixed height.
FileAPI.Image(imageFile)
.resize(240, 'height')
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Number[, height:Number]):FileAPI.ImageCrop and resize image.
FileAPI.Image(imageFile)
.preview(100, 100)
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Number):FileAPI.ImageRotate image.
FileAPI.Image(imageFile)
.rotate(90)
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Function):FileAPI.ImageApply filter function. Only HTML5.
canvas element and done method.FileAPI.Image(imageFile)
.filter(function (canvas/**HTMLCanvasElement*/, doneFn/**Function*/){
// bla-bla-lba
doneFn();
})
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:String):FileAPI.ImageUses CamanJS, include it before FileAPI library.
Caman.Filter.register("my-funky-filter", function () {
// http://camanjs.com/guides/#Extending
});
FileAPI.Image(imageFile)
.filter("my-funky-filter") // or .filter("vintage")
.get(function (err/**String*/, img/**HTMLElement*/){
})
;
:Array):FileAPI.ImageAdd overlay images, eg: watermark.
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*/){
})
;
:Function):FileAPI.ImageGet the final image.
To work with a webcam, be sure to set FileAPI.media: true.
:HTMLElement, options:Object, callback:Function):voidPublication of the camera.
width: 100%, height: 100%, start: true }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.
}
});
:Function):voidTurn on the camera.
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.
}
});
}
});
:voidTurn off the camera.
:FileAPI.ImageTake 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
});
}
});
:Number1024 bytes
:Number1048576 bytes
:Number1073741824 bytes
:Number1.0995116e+12 bytes
:Object|Array, callback:Function[, thisObject:Mixed]):voidIterate over an object or array, executing a function for each matched element.
this when executing callback.--
:Object, src:Object):ObjectMerge the contents of two objects together into the first object.
--
:Array, callback:Function[, thisObject:Mixed):ObjectCreates a new array with all elements that pass the test implemented by the provided function.
this when executing callback.:BooleanHTML5 browser support
:BooleanThis cross-origin resource sharing is used to enable cross-site HTTP requests.
:BooleanDrag'n'drop events support.
:BooleanAvailability Flash plugin.
:BooleanCanvas support.
:BooleanSupport dataURI as src for image.
:BooleanSupport chunked upload.
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.
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>
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 "http://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>
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--
By default FileAPI.flash.swf allows access from any domain via Security.allowDomain("*").
This can lead to same origin bypass vulnerability if swf is loaded from the same domain as your critical data.
To prevent this, allow only your domains here and rebuild flash.
<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;
}
?>
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' ){
// ...
}
?>
Client and server communicate to each other using the following HTTP headers and status codes.
Client explicitly sets the following headers:
Simple input[type="file"]
<span class="js-fileapi-wrapper" style="position: relative; display: inline-block;">
<input name="files" type="file" multiple/>
</span>
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>
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>
npm install fileapi
cd fileapi
npm install
grunt
Copyright 2013 - present © cnpmjs.org