{"id":13447211,"url":"https://github.com/mailru/FileAPI","last_synced_at":"2025-03-21T17:31:12.711Z","repository":{"id":2242911,"uuid":"3197382","full_name":"mailru/FileAPI","owner":"mailru","description":"FileAPI — a set of  javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF.","archived":false,"fork":false,"pushed_at":"2020-09-24T08:35:44.000Z","size":75288,"stargazers_count":3567,"open_issues_count":50,"forks_count":457,"subscribers_count":173,"default_branch":"master","last_synced_at":"2025-03-16T21:41:07.831Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://mailru.github.io/FileAPI/","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mailru.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-01-17T06:47:39.000Z","updated_at":"2025-02-26T09:49:15.000Z","dependencies_parsed_at":"2022-08-18T08:21:10.624Z","dependency_job_id":null,"html_url":"https://github.com/mailru/FileAPI","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2FFileAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2FFileAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2FFileAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2FFileAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mailru","download_url":"https://codeload.github.com/mailru/FileAPI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244838123,"owners_count":20518792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T05:01:11.030Z","updated_at":"2025-03-21T17:31:07.698Z","avatar_url":"https://github.com/mailru.png","language":"JavaScript","readme":"﻿\u003ca name=\"FileAPI\"\u003e\u003c/a\u003e\n## FileAPI \u003cimg src=\"https://api.travis-ci.org/mailru/FileAPI.png?branch=master\"/\u003e\nA set of JavaScript tools for working with files.\n\n\u003ca name=\"started\"\u003e\u003c/a\u003e\n### Get started\n\nDownload the files from the [dist](https://github.com/mailru/FileAPI/tree/master/dist) directory, and then:\n\n```html\n\t\u003cdiv\u003e\n\t\t\u003c!-- \"js-fileapi-wrapper\" -- required class --\u003e\n\t\t\u003cdiv class=\"js-fileapi-wrapper upload-btn\"\u003e\n\t\t\t\u003cdiv class=\"upload-btn__txt\"\u003eChoose files\u003c/div\u003e\n\t\t\t\u003cinput id=\"choose\" name=\"files\" type=\"file\" multiple /\u003e\n\t\t\u003c/div\u003e\n\t\t\u003cdiv id=\"images\"\u003e\u003c!-- previews --\u003e\u003c/div\u003e\n\t\u003c/div\u003e\n\n\t\u003cscript\u003ewindow.FileAPI = { staticPath: '/js/FileAPI/dist/' };\u003c/script\u003e\n\t\u003cscript src=\"/js/FileAPI/dist/FileAPI.min.js\"\u003e\u003c/script\u003e\n\t\u003cscript\u003e\n\t\tvar choose = document.getElementById('choose');\n\t\tFileAPI.event.on(choose, 'change', function (evt){\n\t\t\tvar files = FileAPI.getFiles(evt); // Retrieve file list\n\n\t\t\tFileAPI.filterFiles(files, function (file, info/**Object*/){\n\t\t\t\tif( /^image/.test(file.type) ){\n\t\t\t\t\treturn\tinfo.width \u003e= 320 \u0026\u0026 info.height \u003e= 240;\n\t\t\t\t}\n\t\t\t\treturn\tfalse;\n\t\t\t}, function (files/**Array*/, rejected/**Array*/){\n\t\t\t\tif( files.length ){\n\t\t\t\t\t// Make preview 100x100\n\t\t\t\t\tFileAPI.each(files, function (file){\n\t\t\t\t\t\tFileAPI.Image(file).preview(100).get(function (err, img){\n\t\t\t\t\t\t\timages.appendChild(img);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\n\t\t\t\t\t// Uploading Files\n\t\t\t\t\tFileAPI.upload({\n\t\t\t\t\t\turl: './ctrl.php',\n\t\t\t\t\t\tfiles: { images: files },\n\t\t\t\t\t\tprogress: function (evt){ /* ... */ },\n\t\t\t\t\t\tcomplete: function (err, xhr){ /* ... */ }\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\u003c/script\u003e\n```\n\n---\n\n\u003ca name=\"FileAPI.setup\"\u003e\u003c/a\u003e\n### Setup options\nEdit the file `crossdomain.xml` and place it to the root of the domain to which files will be uploaded.\n\n```html\n\t\u003cscript\u003e\n\t\twindow.FileAPI = {\n\t\t\t  debug: false   // debug mode, see Console\n\t\t\t, cors: false    // if used CORS, set `true`\n\t\t\t, media: false   // if used WebCam, set `true`\n\t\t\t, staticPath: '/js/FileAPI/dist/' // path to '*.swf'\n\t\t\t, postNameConcat: function (name, idx){\n\t\t\t\t// Default: object[foo]=1\u0026object[bar][baz]=2\n\t\t\t\t// .NET: https://github.com/mailru/FileAPI/issues/121#issuecomment-24590395\n\t\t\t\treturn\tname + (idx != null ? '['+ idx +']' : '');\n\t\t\t}\n\t\t};\n\t\u003c/script\u003e\n\t\u003cscript src=\"/js/FileAPI/dist/FileAPI.min.js\"\u003e\u003c/script\u003e\n\n\t\u003c!-- OR --\u003e\n\n\t\u003cscript\u003e\n\t\twindow.FileAPI = { /* options */ };\n\t\trequire(['FileAPI'], function (FileAPI){\n\t\t\t// ...\n\t\t});\n\t\u003c/script\u003e\n```\n\n---\n\n\n\u003ca name=\"FileAPI.getFiles\"\u003e\u003c/a\u003e\n### getFiles(input`:HTMLInputElement|Event|$.Event`)`:Array`\nRetrieve file list from `input` element or `event` object, also support `jQuery`.\n\n* input — `HTMLInputElement`, `change` and `drop` event, `jQuery` collection or `jQuery.Event`\n\n```js\nvar el = document.getElement('my-input');\nFileAPI.event.on(el, 'change', function (evt/**Event*/){\n\t// Retrieve file list\n\tvar files = FileAPI.getFiles(el);\n\n\t// or event\n\tvar files = FileAPI.getFiles(evt);\n});\n```\n\n---\n\n\n\u003ca name=\"FileAPI.getInfo\"\u003e\u003c/a\u003e\n### getInfo(file`:Object`, callback`:Function`)`:void`\nGet info of file (see also: FileAPI.addInfoReader).\n\n* file — file object (https://developer.mozilla.org/en-US/docs/DOM/File)\n* callback — function, called after collected info of file\n\n```js\n// Get info of image file (FileAPI.exif.js included)\nFileAPI.getInfo(file, function (err/**String*/, info/**Object*/){\n\tif( !err ){\n\t\tconsole.log(info); // { width: 800, height: 600, exif: {..} }\n\t}\n});\n\n// Get info of mp3 file (FileAPI.id3.js included)\nFileAPI.getInfo(file, function (err/**String*/, info/**Object*/){\n\tif( !err ){\n\t\tconsole.log(info); // { title: \"...\", album: \"...\", artists: \"...\", ... }\n\t}\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.filterFiles\"\u003e\u003c/a\u003e\n### filterFiles(files`:Array`, filter`:Function`, callback`:Function`)`:void`\nFiltering the list of files, with additional information about files.\nSee also: FileAPI.getInfo and FileAPI.addInfoReader.\n\n* files — original list of files\n* filter — function, takes two arguments: `file` — the file itself, `info` — additional information.\n* callback — function: `list` — files that match the condition, `other` — all the rest.\n\n```js\n// Get list of file\nvar files = FileAPI.getFiles(input);\n\n// Filter the List\nFileAPI.filterFiles(files, function (file/**Object*/, info/**Object*/){\n\tif( /^image/.test(file.type) \u0026\u0026 info ){\n\t\treturn\tinfo.width \u003e 320 \u0026\u0026 info.height \u003e 240;\n\t} else {\n\t\treturn\tfile.size \u003c 20 * FileAPI.MB;\n\t}\n}, function (list/**Array*/, other/**Array*/){\n\tif( list.length ){\n\t\t// ..\n\t}\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.getDropFiles\"\u003e\u003c/a\u003e\n### getDropFiles(evt`:Event|$.Event`, callback`:Function`)`:void`\nGet a list of files, including directories.\n\n* evt — `drop` event\n* callback — function, takes one argument, a list of files\n\n```js\nFileAPI.event.on(document, 'drop', function (evt/**Event*/){\n\tevt.preventDefault();\n\n\t// Get a list of files\n\tFileAPI.getDropFiles(evt, function (files/**Array*/){\n\t\t// ...\n\t});\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.upload\"\u003e\u003c/a\u003e\n### upload(opts`:Object`)`:XmlHttpRequest`\nUploading files to the server (successively). Returns XHR-like object.\nIt is important to remember to correctly worked flash-transport server response body must not be empty,\nfor example, you can pass, just text \"ok\".\n\n* opts — options object, see [Upload options](#options)\n\n```js\nvar el = document.getElementById('my-input');\nFileAPI.event.on(el, 'change', function (evt/**Event*/){\n\tvar files = FileAPI.getFiles(evt);\n\tvar xhr = FileAPI.upload({\n\t\turl: 'http://rubaxa.org/FileAPI/server/ctrl.php',\n\t\tfiles: { file: files[0] },\n\t\tcomplete: function (err, xhr){\n\t\t\tif( !err ){\n\t\t\t\tvar result = xhr.responseText;\n\t\t\t\t// ...\n\t\t\t}\n\t\t}\n\t});\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.addInfoReader\"\u003e\u003c/a\u003e\n### addInfoReader(mime`:RegExp`, handler`:Function`)`:void`\nAdds a handler for the collection of information about a file.\nSee also: FileAPI.getInfo and FileAPI.filterFiles.\n\n* mime — pattern of mime-type\n* handler — takes two arguments: `file` object and `complete` function callback\n\n```js\nFileAPI.addInfoReader(/^image/, function (file/**File*/, callback/**Function*/){\n\t// http://www.nihilogic.dk/labs/exif/exif.js\n\t// http://www.nihilogic.dk/labs/binaryajax/binaryajax.js\n\tFileAPI.readAsBinaryString(file, function (evt/**Object*/){\n\t\tif( evt.type == 'load' ){\n\t\t\tvar binaryString = evt.result;\n\t\t\tvar oFile = new BinaryFile(binaryString, 0, file.size);\n\t\t\tvar exif  = EXIF.readFromBinaryFile(oFile);\n\t\t\tcallback(false, { 'exif': exif || {} });\n\t\t}\n\t\telse if( evt.type == 'error' ){\n\t\t\tcallback('read_as_binary_string');\n\t\t}\n\t\telse if( evt.type == 'progress' ){\n\t\t\t// ...\n\t\t}\n\t});\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.readAsDataURL\"\u003e\u003c/a\u003e\n### readAsDataURL(file`:Object`, callback`:Function`)`:void`\nReading the contents of the specified `File` as `dataURL`.\n\n* file — file object\n* callback — function, receives a result\n\n```js\nFileAPI.readAsDataURL(file, function (evt/**Object*/){\n\tif( evt.type == 'load' ){\n\t\t// Success\n\t \tvar dataURL = evt.result;\n\t} else if( evt.type =='progress' ){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t} else {\n\t\t// Error\n\t}\n})\n```\n\n---\n\n\u003ca name=\"FileAPI.readAsBinaryString\"\u003e\u003c/a\u003e\n### readAsBinaryString(file`:Object`, callback`:Function`)`:void`\nReading the contents of the specified `File` as `BinaryString`.\n\n* file — file object\n* callback — function, receives a result\n\n```js\nFileAPI.readAsBinaryString(file, function (evt/**Object*/){\n\tif( evt.type == 'load' ){\n\t\t// Success\n\t \tvar binaryString = evt.result;\n\t} else if( evt.type =='progress' ){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t} else {\n\t\t// Error\n\t}\n})\n```\n\n---\n\n\u003ca name=\"FileAPI.readAsArrayBuffer\"\u003e\u003c/a\u003e\n### readAsArrayBuffer(file`:Object`, callback`:Function`)`:void`\nReading the contents of the specified `File` as `ArrayBuffer`.\n\n* file — file object\n* callback — function, receives a result\n\n```js\nFileAPI.readAsArrayBuffer(file, function (evt/**Object*/){\n\tif( evt.type == 'load' ){\n\t\t// Success\n\t \tvar arrayBuffer = evt.result;\n\t} else if( evt.type =='progress' ){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t} else {\n\t\t// Error\n\t}\n})\n```\n\n---\n\n\u003ca name=\"FileAPI.readAsText\"\u003e\u003c/a\u003e\n### readAsText(file`:Object`, callback`:Function`)`:void`\nReading the contents of the specified `File` as `text`.\n\n* file — file object\n* callback — function, receives a result\n\n```js\nFileAPI.readAsText(file, function (evt/**Object*/){\n\tif( evt.type == 'load' ){\n\t\t// Success\n\t \tvar text = evt.result;\n\t} else if( evt.type =='progress' ){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t} else {\n\t\t// Error\n\t}\n})\n```\n\n---\n\n\u003ca name=\"FileAPI.readAsText-encoding\"\u003e\u003c/a\u003e\n### readAsText(file`:Object`, encoding`:String`, callback`:Function`)`:void`\nReading the contents of the specified `File` as `text`.\n\n* encoding — a string indicating the encoding to use for the returned data. By default, UTF-8.\n\n```js\nFileAPI.readAsText(file, \"utf-8\", function (evt/**Object*/){\n\tif( evt.type == 'load' ){\n\t\t// Success\n\t \tvar text = evt.result;\n\t} else if( evt.type =='progress' ){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t} else {\n\t\t// Error\n\t}\n})\n```\n\n---\n\n\n\u003ca name=\"options\" data-name=\"Upload options\"\u003e\u003c/a\u003e\n## Upload options\n\n\u003ca name=\"options.url\"\u003e\u003c/a\u003e\n### url`:String`\nA string containing the URL to which the request is sent.\n\n---\n\n\u003ca name=\"options.data\"\u003e\u003c/a\u003e\n### data`:Object`\nAdditional post data to be sent along with the file uploads.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tdata: { 'session-id': 123 },\n\tfiles: { ... },\n});\n```\n\n---\n\n\u003ca name=\"options.uploadMethod\"\u003e\u003c/a\u003e\n### uploadMethod`:String`\nRequest method, HTML5 only.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tuploadMethod: 'PUT',\n\tfiles: { .. },\n});\n```\n\n---\n\n\u003ca name=\"options.uploadCredentials\"\u003e\u003c/a\u003e\n### uploadCredentials`:Boolean`\nPass credentials to upload request, HTML5 only.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tuploadCredentials: false,\n\tfiles: { .. },\n});\n```\n\n---\n\n\u003ca name=\"options.headers\"\u003e\u003c/a\u003e\n### headers`:Object`\nAdditional request headers, HTML5 only.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\theaders: { 'x-upload': 'fileapi' },\n\tfiles: { .. },\n});\n```\n\n---\n\n\u003ca name=\"options.cache\"\u003e\u003c/a\u003e\n### cache`:Boolean`\nSetting to true removes the default timestamp URL parameter.\n\n---\n\n\u003ca name=\"options.files\"\u003e\u003c/a\u003e\n### files`:Object`\nKey-value object, `key` — post name, `value` — File or FileAPI.Image object.\n\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: {\n\t\taudio: files\n\t}\n});\n```\n\n---\n\n\u003ca name=\"options.chunkSize\"\u003e\u003c/a\u003e\n### chunkSize`:Number`\nChunk size in bytes, HTML5 only.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { images: fileList },\n\tchunkSize: 0.5 * FileAPI.MB\n});\n```\n\n---\n\n\u003ca name=\"options.chunkUploadRetry\"\u003e\u003c/a\u003e\n### chunkUploadRetry`:Number`\nNumber of retries during upload chunks, HTML5 only.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { images: fileList },\n\tchunkSize: 0.5 * FileAPI.MB,\n\tchunkUploadRetry: 3\n});\n```\n\n--\n\n\u003ca name=\"options.imageTransform\"\u003e\u003c/a\u003e\n### imageTransform`:Object`\nRules of changes the original image on the client.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { image: imageFiles },\n\t// Changes the original image\n\timageTransform: {\n\t\t// resize by max side\n\t\tmaxWidth: 800,\n\t\tmaxHeight: 600,\n\t\t// Add watermark\n\t\toverlay: [{ x: 10, y: 10, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.imageTransform-multi\"\u003e\u003c/a\u003e\n### imageTransform`:Object`\nRules of image transformation on the client, for more images.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { image: imageFiles },\n\timageTransform: {\n\t\t// resize by max side\n\t\t'huge': { maxWidth: 800, maxHeight: 600 },\n\t\t// crop \u0026 resize\n\t\t'medium': { width: 320, height: 240, preview: true },\n\t\t// crop \u0026 resize + watemark\n\t\t'small': {\n\t\t\twidth: 100, height: 100,\n\t\t\t// Add watermark\n\t\t\toverlay: [{ x: 5, y: 5, src: '/i/watemark.png', rel: FileAPI.Image.RIGHT_BOTTOM }]\n\t\t}\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.imageTransform-jpeg\"\u003e\u003c/a\u003e\n### imageTransform`:Object`\nConvert all images to jpeg or png.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { image: imageFiles },\n\timageTransform: {\n\t\ttype: 'image/jpeg',\n\t\tquality: 0.86 // jpeg quality\n\t}\n});\n```\n\n\n\u003ca name=\"options.imageOriginal\"\u003e\u003c/a\u003e\n### imageOriginal`:Boolean`\nSent to the server the original image or not, if defined imageTransform option.\n\n--\n\n\u003ca name=\"options.imageAutoOrientation\"\u003e\u003c/a\u003e\n### imageAutoOrientation`:Boolean`\nAuto-rotate images on the basis of EXIF.\n\n--\n\n\u003ca name=\"options.prepare\"\u003e\u003c/a\u003e\n### prepare`:Function`\nPrepare options upload for a particular file.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tprepare: function (file/**Object*/, options/**Object*/){\n\t\toptions.data.secret = utils.getSecretKey(file.name);\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.upload\"\u003e\u003c/a\u003e\n### upload`:Function`\nStart uploading.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tupload: function (xhr/**Object*/, options/**Object*/){\n\t\t// ...\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.fileupload\"\u003e\u003c/a\u003e\n### fileupload`:Function`\nStart file uploading.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tfileupload: function (file/**Object*/, xhr/**Object*/, options/**Object*/){\n\t\t// ...\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.progress\"\u003e\u003c/a\u003e\n### progress`:Function`\nCallback for upload progress events.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tprogress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.fileprogress\"\u003e\u003c/a\u003e\n### fileprogress`:Function`\nCallback for upload file progress events.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tfileprogress: function (evt/**Object*/, file/**Object*/, xhr/**Object*/, options/**Object*/){\n\t\tvar pr = evt.loaded/evt.total * 100;\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.complete\"\u003e\u003c/a\u003e\n### complete`:Function`\nCallback for end upload requests.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tcomplete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){\n\t\tif( !err ){\n\t\t\t// All files successfully uploaded.\n\t\t}\n\t}\n});\n```\n\n--\n\n\u003ca name=\"options.filecomplete\"\u003e\u003c/a\u003e\n### filecomplete`:Function`\nCallback for end upload requests.\n\n```js\nvar xhr = FileAPI.upload({\n\turl: '...',\n\tfiles: { .. }\n\tfilecomplete: function (err/**String*/, xhr/**Object*/, file/**Object/, options/**Object*/){\n\t\tif( !err ){\n\t\t\t// File successfully uploaded\n\t\t\tvar result = xhr.responseText;\n\t\t}\n\t}\n});\n```\n\n---\n\n\u003ca name=\"File\"\u003e\u003c/a\u003e\n## File object\n\n\u003ca name=\"File.name\"\u003e\u003c/a\u003e\n### name\nThe name of the file referenced by the File object.\n\n\u003ca name=\"File.type\"\u003e\u003c/a\u003e\n### type\nThe type (MIME type) of the file referenced by the File object.\n\n\u003ca name=\"File.size\"\u003e\u003c/a\u003e\n### size\nThe size (in bytes) of the file referenced by the File object.\n\n\n---\n\n\n\u003ca name=\"FileAPI.event\"\u003e\u003c/a\u003e\n## FileAPI.event\n\n\u003ca name=\"FileAPI.event.on\"\u003e\u003c/a\u003e\n### on(el`:HTMLElement`, events`:String`, handler`:Function`)`:void`\nAttach an event handler function.\n\n* el — DOM element\n* events — one or more space-separated event types.\n* handler — A function to execute when the event is triggered.\n\n---\n\n\u003ca name=\"FileAPI.event.off\"\u003e\u003c/a\u003e\n### off(el`:HTMLElement`, events`:String`, handler`:Function`)`:void`\nRemove an event handler.\n\n* el — DOM element\n* events — one or more space-separated event types.\n* handler — a handler function previously attached for the event(s).\n\n---\n\n\u003ca name=\"FileAPI.event.one\"\u003e\u003c/a\u003e\n### one(el`:HTMLElement`, events`:String`, handler`:Function`)`:void`\nAttach an event handler function. The handler is executed at most once.\n\n* el — DOM element\n* events — one or more space-separated event types.\n* handler — a function to execute when the event is triggered.\n\n---\n\n\u003ca name=\"FileAPI.event.dnd\"\u003e\u003c/a\u003e\n### dnd(el`:HTMLElement`, hover`:Function`, handler`:Function`)`:void`\nAttach an drag and drop event handler function.\n\n* el — drop zone\n* hover — `dragenter` and `dragleave` listener\n* handler — `drop` event handler.\n\n```js\nvar el = document.getElementById('dropzone');\nFileAPI.event.dnd(el, function (over){\n\tel.style.backgroundColor = over ? '#f60': '';\n}, function (files){\n\tif( files.length ){\n\t\t// Upload their.\n\t}\n});\n\n// or jQuery\n$('#dropzone').dnd(hoverFn, dropFn);\n```\n\n---\n\n\u003ca name=\"FileAPI.event.dnd.off\"\u003e\u003c/a\u003e\n### dnd.off(el`:HTMLElement`, hover`:Function`, handler`:Function`)`:void`\nRemove an drag and drop event handler function.\n\n* el — drop zone\n* hover — `dragenter` and `dragleave` listener\n* handler — `drop` event handler.\n\n```js\n// Native\nFileAPI.event.dnd.off(el, hoverFn, dropFn);\n\n// jQuery\n$('#dropzone').dndoff(hoverFn, dropFn);\n```\n\n--\n\n\u003ca name=\"FileAPI.Image\"\u003e\u003c/a\u003e\n## FileAPI.Image\nClass for working with images\n\n### constructor(file`:Object`)`:void`\nThe constructor takes a single argument, the `File` object.\n\n* file — the `File` object\n\n```js\nFileAPI.Image(imageFile).get(function (err/**String*/, img/**HTMLElement*/){\n\tif( !err ){\n\t\tdocument.body.appendChild( img );\n\t}\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.crop\"\u003e\u003c/a\u003e\n### crop(width`:Number`, height`:Number`)`:FileAPI.Image`\nCrop image by width and height.\n\n* width — new image width\n* height — new image height\n\n```js\nFileAPI.Image(imageFile)\n\t.crop(640, 480)\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n### crop(x`:Number`, y`:Number`, width`:Number`, height`:Number`)`:FileAPI.Image`\nCrop image by x, y, width and height.\n\n* x — offset from the top corner\n* y — offset from the left corner\n\n```js\nFileAPI.Image(imageFile)\n\t.crop(100, 50, 320, 240)\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.resize\"\u003e\u003c/a\u003e\n### resize(width`:Number`, height`:Number`[, strategy`:String`])`:FileAPI.Image`\nResize image.\n\n* width — new image width\n* height — new image height\n* strategy — enum: `min`, `max`, `preview`, `width`, `height`. By default `undefined`.\n\n```js\nFileAPI.Image(imageFile)\n\t.resize(320, 240)\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n\n// Resize image on by max side.\nFileAPI.Image(imageFile)\n\t.resize(320, 240, 'max')\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n\n// Resize image on by fixed height.\nFileAPI.Image(imageFile)\n\t.resize(240, 'height')\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.preview\"\u003e\u003c/a\u003e\n### preview(width`:Number`[, height`:Number`])`:FileAPI.Image`\nCrop and resize image.\n\n* width — new image width\n* height — new image height\n\n```js\nFileAPI.Image(imageFile)\n\t.preview(100, 100)\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.rotate\"\u003e\u003c/a\u003e\n### rotate(deg`:Number`)`:FileAPI.Image`\nRotate image.\n\n* deg — rotation angle in degrees\n\n```js\nFileAPI.Image(imageFile)\n\t.rotate(90)\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.filter\"\u003e\u003c/a\u003e\n### filter(callback`:Function`)`:FileAPI.Image`\nApply filter function. Only `HTML5`.\n\n* callback — takes two arguments, `canvas` element and `done` method.\n\n```js\nFileAPI.Image(imageFile)\n\t.filter(function (canvas/**HTMLCanvasElement*/, doneFn/**Function*/){\n\t\t// bla-bla-lba\n\t\tdoneFn();\n\t})\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n\n---\n\n### filter(name`:String`)`:FileAPI.Image`\nUses [CamanJS](http://camanjs.com/), include it before FileAPI library.\n\n* name — CamanJS filter name (custom or preset)\n\n```js\nCaman.Filter.register(\"my-funky-filter\", function () {\n\t// http://camanjs.com/guides/#Extending\n});\n\nFileAPI.Image(imageFile)\n\t.filter(\"my-funky-filter\") // or .filter(\"vintage\")\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.overlay\"\u003e\u003c/a\u003e\n### overlay(images`:Array`)`:FileAPI.Image`\nAdd overlay images, eg: watermark.\n\n* images — array of overlays\n\n```js\nFileAPI.Image(imageFile)\n\t.overlay([\n\t\t// Left corner.\n\t\t{ x: 10, y: 10, w: 100, h: 10, src: '/i/watermark.png' },\n\n\t\t// Right bottom corner.\n\t\t{ x: 10, y: 10, src: '/i/watermark.png', rel: FileAPI.Image.RIGHT_BOTTOM }\n\t])\n\t.get(function (err/**String*/, img/**HTMLElement*/){\n\n\t})\n;\n```\n\n---\n\n\u003ca name=\"FileAPI.Image.get\"\u003e\u003c/a\u003e\n### get(fn`:Function`)`:FileAPI.Image`\nGet the final image.\n\n* fn — complete callback\n\n---\n\n\u003ca name=\"FileAPI.Camera\"\u003e\u003c/a\u003e\n## FileAPI.Camera\nTo work with a webcam, be sure to set `FileAPI.media: true`.\n\n\n\u003ca name=\"FileAPI.Camera.publish\"\u003e\u003c/a\u003e\n### publish(el`:HTMLElement`, options`:Object`, callback`:Function`)`:void`\nPublication of the camera.\n\n* el — target\n* options — { `width: 100%`, `height: 100%`, `start: true` }\n* callback — the first parameter is a possible error, the second instance of FileAPI.Camera\n\n```js\nvar el = document.getElementById('cam');\nFileAPI.Camera.publish(el, { width: 320, height: 240 }, function (err, cam/**FileAPI.Camera*/){\n\tif( !err ){\n\t\t// The webcam is ready, you can use it.\n\t}\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.Camera.start\"\u003e\u003c/a\u003e\n### start(callback`:Function`)`:void`\nTurn on the camera.\n\n* callback — will be called when the camera ready\n\n```js\nvar el = document.getElementById('cam');\nFileAPI.Camera.publish(el, { start: false }, function (err, cam/**FileAPI.Camera*/){\n\tif( !err ){\n\t\t// Turn on\n\t\tcam.start(function (err){\n\t\t\tif( !err ){\n\t\t\t\t// The camera is ready for use.\n\t\t\t}\n\t\t});\n\t}\n});\n```\n\n---\n\n\u003ca name=\"FileAPI.Camera.stop\"\u003e\u003c/a\u003e\n### stop()`:void`\nTurn off the camera.\n\n---\n\n\u003ca name=\"FileAPI.Camera.shot\"\u003e\u003c/a\u003e\n### shot()`:FileAPI.Image`\nTake a picture with the camera.\n\n```js\nvar el = document.getElementById('cam');\nFileAPI.Camera.publish(el, function (err, cam/**FileAPI.Camera*/){\n\tif( !err ){\n\t\tvar shot = cam.shot(); // take a picture\n\n\t\t// create thumbnail 100x100\n\t\tshot.preview(100).get(function (err, img){\n\t\t\tpreviews.appendChild(img);\n\t\t});\n\n\t\t// and/or\n\t\tFileAPI.upload({\n\t\t\turl: '...',\n\t\t\tfiles: { cam: shot\n\t\t});\n\t}\n});\n```\n\n---\n\n\u003ca name=\"const\" data-name=\"Const\"\u003e\u003c/a\u003e\n## Constants\n\n\u003ca name=\"FileAPI.KB\"\u003e\u003c/a\u003e\n### FileAPI.KB`:Number`\n1024 bytes\n\n\u003ca name=\"FileAPI.MB\"\u003e\u003c/a\u003e\n### FileAPI.MB`:Number`\n1048576 bytes\n\n\u003ca name=\"FileAPI.GB\"\u003e\u003c/a\u003e\n### FileAPI.GB`:Number`\n1073741824 bytes\n\n\u003ca name=\"FileAPI.TB\"\u003e\u003c/a\u003e\n### FileAPI.TB`:Number`\n1.0995116e+12 bytes\n\n---\n\n\u003ca name=\"FileAPI.utils\"\u003e\u003c/a\u003e\n## Utils\n\n\u003ca name=\"FileAPI.each\"\u003e\u003c/a\u003e\n### FileAPI.each(obj`:Object|Array`, callback`:Function`[, thisObject`:Mixed`])`:void`\nIterate over an object or array, executing a function for each matched element.\n\n* obj — array or object\n* callback — a function to execute for each element.\n* thisObject — object to use as `this` when executing `callback`.\n\n--\n\n\u003ca name=\"FileAPI.extend\"\u003e\u003c/a\u003e\n### FileAPI.extend(dst`:Object`, src`:Object`)`:Object`\nMerge the contents of two objects together into the first object.\n\n* dst — an object that will receive the new properties\n* src — an object containing additional properties to merge in.\n\n--\n\n\u003ca name=\"FileAPI.filter\"\u003e\u003c/a\u003e\n### FileAPI.filter(array`:Array`, callback`:Function`[, thisObject`:Mixed`)`:Object`\nCreates a new array with all elements that pass the test implemented by the provided function.\n\n* array — original Array\n* callback — Function to test each element of the array.\n* thisObject — object to use as `this` when executing `callback`.\n\n---\n\n\u003ca name=\"support\"\u003e\u003ca/\u003e\n## Support\n\u003cul\u003e\n\t\u003cli\u003eMultiupload: all browsers that support HTML5 or Flash\u003c/li\u003e\n\t\u003cli\u003eDrag'n'Drop upload: files (HTML5) \u0026 directories (Chrome 21+)\u003c/li\u003e\n\t\u003cli\u003eChunked file upload (HTML5)\u003c/li\u003e\n\t\u003cli\u003eUpload one file: all browsers\u003c/li\u003e\n\t\u003cli\u003e\n\t\tWorking with Images: IE6+, FF 3.6+, Chrome 10+, Opera 11.1+, Safari 6+\n\t\t\u003cul\u003e\n\t\t\t\u003cli\u003ecrop, resize, preview \u0026 rotate (HTML5 or Flash)\u003c/li\u003e\n\t\t\t\u003cli\u003eauto orientation by exif (HTML5, if include FileAPI.exif.js or Flash)\u003c/li\u003e\n\t\t\u003c/ul\u003e\n\t\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ca name=\"FileAPI.support.html5\"\u003e\u003c/a\u003e\n### FileAPI.support.html5`:Boolean`\nHTML5 browser support\n\n\u003ca name=\"FileAPI.support.cors\"\u003e\u003c/a\u003e\n### FileAPI.support.cors`:Boolean`\nThis cross-origin resource sharing is used to enable cross-site HTTP requests.\n\n\u003ca name=\"FileAPI.support.dnd\"\u003e\u003c/a\u003e\n### FileAPI.support.dnd`:Boolean`\nDrag'n'drop events support.\n\n\u003ca name=\"FileAPI.support.flash\"\u003e\u003c/a\u003e\n### FileAPI.support.flash`:Boolean`\nAvailability Flash plugin.\n\n\u003ca name=\"FileAPI.support.canvas\"\u003e\u003c/a\u003e\n### FileAPI.support.canvas`:Boolean`\nCanvas support.\n\n\u003ca name=\"FileAPI.support.dataURI\"\u003e\u003c/a\u003e\n### FileAPI.support.dataURI`:Boolean`\nSupport dataURI as src for image.\n\n\u003ca name=\"FileAPI.support.chunked\"\u003e\u003c/a\u003e\n### FileAPI.support.chunked`:Boolean`\nSupport chunked upload.\n\n---\n\n\u003ca name=\"flash\"\u003e\u003c/a\u003e\n## Flash\nFlash is very \"buggy\" thing :]\nThe server response can not be empty.\nTherefore, in the event of a successful uploading `http status` should be only `200 OK`.\n\n\u003ca name=\"flash.settings\"\u003e\u003c/a\u003e\n### Settings\nFlash settings.\nIt is advisable to place flash on the same server where the files will be uploaded.\n\n```html\n\u003cscript\u003e\n\tvar FileAPI = {\n\t \t// @default: \"./dist/\"\n\t\tstaticPath: '/js/',\n\n\t\t // @default: FileAPI.staticPath + \"FileAPI.flash.swf\"\n\t\tflashUrl: '/statics/FileAPI.flash.swf',\n\n\t\t// @default: FileAPI.staticPath + \"FileAPI.flash.image.swf\"\n\t\tflashImageUrl: '/statics/FileAPI.flash.image.swf'\n\t};\n\u003c/script\u003e\n\u003cscript src=\"/js/FileAPI.min.js\"\u003e\u003c/script\u003e\n```\n\n---\n\n\u003ca name=\"crossdomain.xml\"\u003e\u003c/a\u003e\n### crossdomain.xml\nNecessarily make this file on the server.\nDo not forget to replace `youdomain.com` on the name of your domain.\n\n```xml\n\u003c?xml version=\"1.0\"?\u003e\n\u003c!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"\u003e\n\u003ccross-domain-policy\u003e\n\t\u003csite-control permitted-cross-domain-policies=\"all\"/\u003e\n\t\u003callow-access-from domain=\"youdomain.com\" secure=\"false\"/\u003e\n\t\u003callow-access-from domain=\"*.youdomain.com\" secure=\"false\"/\u003e\n\t\u003callow-http-request-headers-from domain=\"*\" headers=\"*\" secure=\"false\"/\u003e\n\u003c/cross-domain-policy\u003e\n```\n\n---\n\n\u003ca name=\"flash.request\"\u003e\u003c/a\u003e\n### request\nThe following sample HTTP POST request is sent from Flash Player to a server-side script if no parameters are specified:\n\n```xml\nPOST /server/ctrl.php HTTP/1.1\nAccept: text/*\nContent-Type: multipart/form-data;\nboundary=----------Ij5ae0ae0KM7GI3KM7\nUser-Agent: Shockwave Flash\nHost: www.youdomain.com\nContent-Length: 421\nConnection: Keep-Alive\nCache-Control: no-cache\n\n------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7\nContent-Disposition: form-data; name=\"Filename\"\n\nMyFile.jpg\n------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"MyFile.jpg\"\nContent-Type: application/octet-stream\n\n[[..FILE_DATA_HERE..]]\n------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7\nContent-Disposition: form-data; name=\"Upload\"\n\nSubmit Query\n------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--\n```\n\n---\n\n\u003ca name=\"flash.security\"\u003e\u003c/a\u003e\n### Security\nBy default `FileAPI.flash.swf` allows access from any domain via `Security.allowDomain(\"*\")`.\nThis can lead to same origin bypass vulnerability if swf is loaded from the same domain as your critical data.\nTo prevent this, allow only your domains [here](https://github.com/mailru/FileAPI/blob/master/flash/core/src/ru/mail/communication/JSCallbackPresenter.as#L25) and rebuild flash.\n\n---\n\n\u003ca name=\"server\"\u003e\u003c/a\u003e\n## Server settings\n\n\u003ca name=\"server.iframe\"\u003e\u003c/a\u003e\n### IFrame/JSONP\n\n```php\n\u003cscript\u003e\n(function (ctx, jsonp){\n\t'use strict';\n\tvar status = {{httpStatus}}, statusText = \"{{httpStatusText}}\", response = \"{{responseBody}}\";\n\ttry {\n\t\tctx[jsonp](status, statusText, response);\n\t} catch (e){\n\t\tvar data = \"{\\\"id\\\":\\\"\"+jsonp+\"\\\",\\\"status\\\":\"+status+\",\\\"statusText\\\":\\\"\"+statusText+\"\\\",\\\"response\\\":\\\"\"+response.replace(/\\\"/g, '\\\\\\\\\\\"')+\"\\\"}\";\n\t\ttry {\n\t\t\tctx.postMessage(data, document.referrer);\n\t\t} catch (e){}\n\t}\n})(window.parent, '{{request_param_callback}}');\n\u003c/script\u003e\n\n\u003c!-- or --\u003e\n\n\u003c?php\n\tinclude './FileAPI.class.php';\n\n\tif( strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' ){\n\t\t// Retrieve File List\n\t\t$files\t= FileAPI::getFiles();\n\n\t\t// ... your logic\n\n\t\t// JSONP callback name\n\t\t$jsonp\t= isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : null;\n\n\t\t// Server response: \"HTTP/1.1 200 OK\"\n\t\tFileAPI::makeResponse(array(\n\t\t\t  'status' =\u003e FileAPI::OK\n\t\t\t, 'statusText' =\u003e 'OK'\n\t\t\t, 'body' =\u003e array('count' =\u003e sizeof($files))\n\t\t), $jsonp);\n\t\texit;\n\t}\n?\u003e\n```\n\n---\n\n\u003ca name=\"server.CORS\"\u003e\u003c/a\u003e\n### CORS\nEnable CORS.\n\n```php\n\u003c?php\n\t// Permitted types of request\n    header('Access-Control-Allow-Methods: POST, OPTIONS');\n\n    // Describe custom headers\n    header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Range, Content-Disposition, Content-Type');\n\n    // A comma-separated list of domains\n    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);\n\n\t// Allow cookie\n\theader('Access-Control-Allow-Credentials: true');\n\n    if( $_SERVER['REQUEST_METHOD'] == 'OPTIONS' ){\n        exit;\n    }\n\n    if( $_SERVER['REQUEST_METHOD'] == 'POST' ){\n        // ...\n    }\n?\u003e\n```\n\n---\n\n\u003ca name=\"server.chunked\"\u003e\u003c/a\u003e\n### Chunked file upload\nClient and server communicate to each other using the following HTTP headers and status codes.\u003cbr/\u003e\nClient explicitly sets the following headers:\u003cbr/\u003e\n\u003cul\u003e\n\t\u003cli\u003eContent-Range: bytes \u0026lt;start-offset\u0026gt;-\u0026lt;end-offset\u0026gt;/\u0026lt;total\u0026gt;\u003c/li\u003e\n\t\u003cli\u003eContent-Disposition: attachment; filename=\u0026lt;file-name\u0026gt;\u003c/li\u003e\n\u003c/ul\u003e\nAny 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.\u003cbr/\u003e\nResponse codes:\n\u003cul\u003e\n\t\u003cli\u003e200 - last chunk is uploaded\u003c/li\u003e\n\t\u003cli\u003e201 - chunk is successfully saved\u003c/li\u003e\n\t\u003cli\u003e416 - range is not acceptable error, recoverable\u003c/li\u003e\n\t\u003cli\u003e500 - server error, recoverable\u003c/li\u003e\n\u003c/ul\u003e\nFor recoverable errors server tries to resend chunk `chunkUploadRetry` times then fails.\u003cbr/\nResponse headers:\n\u003cul\u003e\n\t\u003cli\u003eX-Last-Known-Byte: int, library tries to resend chunk from the given offset. Applicable to response codes 200 and 416\u003c/li\u003e\n\u003c/ul\u003e\nAll the other codes - fatal error, user's involvement is recommended.\n\n---\n\n\n\u003ca name=\"buttons.examples\"\u003e\u003c/a\u003e\n## Buttons examples\n\n\u003ca name=\"buttons.examples.base\"\u003e\u003c/a\u003e\n### Base\nSimple input[type=\"file\"]\n\n```html\n\u003cspan class=\"js-fileapi-wrapper\" style=\"position: relative; display: inline-block;\"\u003e\n    \u003cinput name=\"files\" type=\"file\" multiple/\u003e\n\u003c/span\u003e\n```\n\n---\n\n\u003ca name=\"buttons.examples.button\"\u003e\u003c/a\u003e\n### Button\nStylized button.\n\n```html\n\u003cstyle\u003e\n.upload-btn {\n    width: 130px;\n    height: 25px;\n    overflow: hidden;\n    position: relative;\n    border: 3px solid #06c;\n    border-radius: 5px;\n    background: #0cf;\n\n}\n    .upload-btn:hover {\n        background: #09f;\n    }\n    .upload-btn__txt {\n        z-index: 1;\n        position: relative;\n        color: #fff;\n        font-size: 18px;\n        font-family: \"Helvetica Neue\";\n        line-height: 24px;\n        text-align: center;\n        text-shadow: 0 1px 1px #000;\n    }\n    .upload-btn input {\n        top: -10px;\n        right: -40px;\n        z-index: 2;\n        position: absolute;\n        cursor: pointer;\n        opacity: 0;\n        filter: alpha(opacity=0);\n        font-size: 50px;\n    }\n\u003c/style\u003e\n\u003cdiv class=\"js-fileapi-wrapper upload-btn\"\u003e\n    \u003cdiv class=\"upload-btn__txt\"\u003eUpload files\u003c/div\u003e\n    \u003cinput name=\"files\" type=\"file\" multiple /\u003e\n\u003c/div\u003e\n```\n\n\n---\n\n\n\u003ca name=\"buttons.examples.link\"\u003e\u003c/a\u003e\n### Link\nButton like link.\n\n```html\n\u003cstyle\u003e\n.upload-link {\n    color: #36c;\n    display: inline-block;\n    *zoom: 1;\n    *display: inline;\n    overflow: hidden;\n    position: relative;\n    padding-bottom: 2px;\n    text-decoration: none;\n}\n    .upload-link__txt {\n        z-index: 1;\n        position: relative;\n        border-bottom: 1px dotted #36c;\n    }\n        .upload-link:hover .upload-link__txt {\n            color: #f00;\n            border-bottom-color: #f00;\n        }\n\n    .upload-link input {\n        top: -10px;\n        right: -40px;\n        z-index: 2;\n        position: absolute;\n        cursor: pointer;\n        opacity: 0;\n        filter: alpha(opacity=0);\n        font-size: 50px;\n    }\n\u003c/style\u003e\n\u003ca class=\"js-fileapi-wrapper upload-link\"\u003e\n    \u003cspan class=\"upload-link__txt\"\u003eUpload photo\u003c/span\u003e\n    \u003cinput name=\"photo\" type=\"file\" accept=\"image/*\" /\u003e\n\u003c/a\u003e\n```\n\n---\n\n\u003ca name=\"install\" data-name=\"Installation\"\u003e\u003c/a\u003e\n## Installation, testing, assembling\n`npm install fileapi`\u003cbr/\u003e\n`cd fileapi`\u003cbr/\u003e\n`npm install`\u003cbr/\u003e\n`grunt`\n\n\n---\n\n\n\u003ca name=\"Changelog\"\u003e\u003c/a\u003e\n## Changelog\n\n### 2.0.20\n\u003cul\u003e\n\t\u003cli\u003e#369: * IEMobile\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.19\n\u003cul\u003e\n\t\u003cli\u003e#367: * [flash] allow gif and bmp to resize\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.18\n\u003cul\u003e\n\t\u003cli\u003e#364: * Camera#stop\u003c/li\u003e\n\t\u003cli\u003e#363: * support `Blob` in `FileAPI.getInfo`\u003c/li\u003e\n\t\u003cli\u003e#361: + upload zero-files\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.16-2.0.17\n\u003cul\u003e\n\t\u003cli\u003e#353: debug mode vs. IE\u003c/li\u003e\n\t\u003cli\u003e#352: correct filename via flash-uploading\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.12-2.0.15 (!)\n\u003cul\u003e\n\t\u003cli\u003e#346, #342, #344: fixes for XSS into Flash-transport\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.11\n\u003cul\u003e\n\t\u003cli\u003e#322, #308: dnd \u0026 safari + $.fn.dnd (store all dropped items)\u003c/li\u003e\n\t\u003cli\u003e#319: NodeJS tesing\u003c/li\u003e\n\t\u003cli\u003e#317, #313: fixed \"malformed entry.name (OSX Unicode NFD)\"\u003c/li\u003e\n\t\u003cli\u003e#311: fixed \"Arithmetic result exceeded 32 bits\"\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.10\n\u003cul\u003e\n\t\u003cli\u003e#289: * WebCam \u0026 html5 == false\u003c/li\u003e\n\t\u003cli\u003e#199, #265: flash fix 2015 error with BitmapData\u003c/li\u003e\n\t\u003cli\u003e#177: IE9, IE11 flash.camera remembered settigns\u003c/li\u003e\n\t\u003cli\u003e#254: check 'onLoadFnName' before call\u003c/li\u003e\n\t\u003cli\u003e#272: fixed `entry.createReader().readEntries`\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.9\n\u003cul\u003e\n\t\u003cli\u003e#253: fixed `proxyXHR.loaded`\u003c/li\u003e\n\t\u003cli\u003e#250: + check `disabled`-attr\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.8\n\u003cul\u003e\n\t\u003cli\u003eTwo new resize strategies `width` and `height`\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.7\n\u003cul\u003e\n\t\u003cli\u003e#214: iframe transport under IE8\u003c/li\u003e\n\t\u003cli\u003eFixed iframe-transport (remove `disabled`-attr for input)\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.6\n\u003cul\u003e\n\t\u003cli\u003e#240: Fixed `FileAPI.event.dnd.off`\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.5\n\u003cul\u003e\n\t\u003cli\u003e+ #228: check callbacks with regexp\u003c/li\u003e\n\t\u003cli\u003e* Updated devDepending\u003c/li\u003e\n\t\u003cli\u003e+ #207: support EXIF.Orientation == 4, 5 \u0026 7 \u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 2.0.4\n\u003cul\u003e\n\t\u003cli\u003e+ #176: Add params to the beginning of form\u003c/li\u003e\n\t\u003cli\u003e+ #190: Add 204 as a successful response\u003c/li\u003e\n\t\u003cli\u003e+ #192: many bugfixes; + `retry` \u0026 `multipass` options; + QUnit-tests for BigSizeImage\u003c/li\u003e\n\u003c/ul\u003e\n\n### 2.0.3\n\u003cul\u003e\n\t\u003cli\u003e+ QUnit-tests for iframe-transport\u003c/li\u003e\n\t\u003cli\u003e+ `postMessage` for iframe-transport\u003c/li\u003e\n\t\u003cli\u003e+ `jsonp: \"callback\"` option\u003c/li\u003e\n\t\u003cli\u003e* resize: `imageTransform.type` rename to `imageTransform.strategy` (!!!)\u003c/li\u003e\n\t\u003cli\u003e+ https://github.com/mailru/FileAPI/pull/165 (#140: fix)\u003c/li\u003e\n\u003c/ul\u003e\n\n### 2.0.2\n\u003cul\u003e\n\t\u003cli\u003e+ test: upload headers\u003c/li\u003e\n\t\u003cli\u003e+ test: upload + camanjs\u003c/li\u003e\n\t\u003cli\u003e+ test: upload + autoOrientation\u003c/li\u003e\n\t\u003cli\u003eFileAPI.class.php: + HTTP header Content-Type: application/json\u003c/li\u003e\n\t\u003cli\u003e#143: + `FileAPI.flashWebcamUrl` option\u003c/li\u003e\n\t\u003cli\u003e* merge v1.2.7\u003c/li\u003e\n\t\u003cli\u003e+ `FileAPI.formData: true` option\u003c/li\u003e\n\u003c/ul\u003e\n\n### 2.0.1\n\u003cul\u003e\n\t\u003cli\u003e+ support 'filter' prop in imageTransform\u003c/li\u003e\n\u003c/ul\u003e\n\n### 2.0.0\n\u003cul\u003e\n\t\u003cli\u003e+ FileAPI.Camera (HTML5 and Flash fallback)\u003c/li\u003e\n\t\u003cli\u003e+ jquery.fileapi.js, see \u003ca href=\"http://rubaxa.github.io/jquery.fileapi/\"\u003edemo\u003c/a\u003e\u003c/li\u003e\n\t\u003cli\u003e+ npm support\u003c/li\u003e\n\t\u003cli\u003e+ grunt support\u003c/li\u003e\n\t\u003cli\u003e+ requirejs support\u003c/li\u003e\n\t\u003cli\u003e+ [#80](https://https://github.com/mailru/FileAPI/issues/80): FileAPI.Image.fn.overlay\u003c/li\u003e\n \t\u003cli\u003e`imageTransform` — now supports: `crop`, `type`, `quality` and `overlay` properties.\u003c/li\u003e\n\t\u003cli\u003eImproved the documentation\u003c/li\u003e\n\t\u003cli\u003e+iOS fix (https://github.com/blueimp/JavaScript-Load-Image)\u003c/li\u003e\n\t\u003cli\u003e[#121](https://github.com/mailru/FileAPI/issues/121): + FileAPI.`postNameConcat:Function(name, idx)`\u003c/li\u003e\n\t\u003cli\u003e[#116](https://github.com/mailru/FileAPI/issues/116): + `cache:false` option for FileAPI.upload\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.6\n\u003cul\u003e\n\t\u003cli\u003e[#91](https://github.com/mailru/FileAPI/issues/91): replace `new Image` to `FileAPI.newImage`\u003c/li\u003e\n\t\u003cli\u003e+ FileAPI.withCredentials: true\u003c/li\u003e\n\t\u003cli\u003e[#90](https://github.com/mailru/FileAPI/issues/90): Fixed `progress` event\u003c/li\u003e\n\t\u003cli\u003e[#105](https://github.com/mailru/FileAPI/issues/105): Fixed `image/jpg` -\u003e `image/jpeg`\u003c/li\u003e\n\t\u003cli\u003e[#108](https://github.com/mailru/FileAPI/issues/108): Check width/height before resize by type(min/max)\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.5\n\u003cul\u003e\n\t\u003cli\u003e[#86](https://github.com/mailru/FileAPI/issues/86): Smarter upload recovery\u003c/li\u003e\n\t\u003cli\u003e[#87](https://github.com/mailru/FileAPI/issues/87): Fixed upload files into browsers that do not support FormData\u003c/li\u003e\n\t\u003cli\u003eFixed support \"accept\" attribute for Flash.\u003c/li\u003e\n\t\u003cli\u003eFixed detection of HTML5 support for FireFox 3.6\u003c/li\u003e\n\t\u003cli\u003e + FileAPI.html5 option, default \"true\"\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.4\n\u003cul\u003e\n\t\u003cli\u003eFixed auto orientation image by EXIF (Flash)\u003c/li\u003e\n\t\u003cli\u003eFixed image dimensions after rotate (Flash)\u003c/li\u003e\n\t\u003cli\u003e[#82](https://github.com/mailru/FileAPI/issues/82): \"undefined\" data-fields cause exceptions\u003c/li\u003e\n\t\u003cli\u003e[#83](https://github.com/mailru/FileAPI/issues/83): Allow requests without files\u003c/li\u003e\n\t\u003cli\u003e[#84](https://github.com/mailru/FileAPI/pull/84): Fixed connection abort when waiting for connection recovery\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.3\n\u003cul\u003e\n\t\u003cli\u003e[#77](https://github.com/mailru/FileAPI/pull/77): Fixed flash.abort(), [#75](https://github.com/mailru/FileAPI/issues/75)\u003c/li\u003e\n\t\u003cli\u003e- `FileAPI.addMime`\u003c/li\u003e\n\t\u003cli\u003e+ `FileAPI.accept` — fallback for flash.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.2\n\u003cul\u003e\n\t\u003cli\u003e[#67](https://github.com/mailru/FileAPI/pull/67): Added correct httpStatus for upload fail, [#62](https://github.com/mailru/FileAPI/pull/68)\u003c/li\u003e\n\t\u003cli\u003e[#68](https://github.com/mailru/FileAPI/pull/68) Added \"Content-Type\" for chunked upload, [#65](https://github.com/mailru/FileAPI/pull/65)\u003c/li\u003e\n\t\u003cli\u003e[#69](https://github.com/mailru/FileAPI/issues/69): Fixed network down recovery\u003c/li\u003e\n\t\u003cli\u003eFixed progress event, [#66](https://github.com/mailru/FileAPI/issues/66)\u003c/li\u003e\n\t\u003cli\u003eIncrease flash stage size, [#73](https://github.com/mailru/FileAPI/pull/73)\u003c/li\u003e\n\t\u003cli\u003e- array index from POST-param \"name\", [#72](https://github.com/mailru/FileAPI/issues/72)\u003c/li\u003e\n\t\u003cli\u003e- dependency on FileAPI.Image for FileAPI.Flash\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.1\n\u003cul\u003e\n\t\u003cli\u003e[#64](https://github.com/mailru/FileAPI/issues/64): Bufixed for [#63](https://github.com/mailru/FileAPI/issues/63)\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.2.0\n\u003cul\u003e\n\t\u003cli\u003e[#57](https://github.com/mailru/FileAPI/issues/57): Chunked file upload\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.1.0\n\u003cul\u003e\n\t\u003cli\u003e[#54](https://github.com/mailru/FileAPI/issues/54): added `FileAPI.flashUrl` and `FileAPI.flashImageUrl`\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.0.1\n\u003cul\u003e\n\t\u003cli\u003e[#51](https://github.com/mailru/FileAPI/issues/51): remove circular references from `file-objects` (Flash transport)\u003c/li\u003e\n\t\u003cli\u003eadded `changelog`\u003c/li\u003e\n\u003c/ul\u003e\n\n\n### 1.0.0\n\u003cul\u003e\n\t\u003cli\u003efirst release\u003c/li\u003e\n\u003c/ul\u003e\n","funding_links":[],"categories":["Web 前端","Form Widgets","JavaScript","\u003e 3k ★","目录","Form Widgets [🔝](#readme)","表单组件","Инструменты разработчика"],"sub_categories":["File Uploader","文件上传"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmailru%2FFileAPI","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmailru%2FFileAPI","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmailru%2FFileAPI/lists"}