├── filepicker.png ├── .eslintignore ├── .babelrc ├── src ├── demo.css ├── options.js ├── demo.jsx └── ReactFilepicker.jsx ├── index.html ├── .eslintrc ├── .gitignore ├── package.json ├── webpack.config.js ├── README.md └── dist └── react-filepicker.js /filepicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/react-filepicker/HEAD/filepicker.png -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | webpack.config.js 3 | dist/ 4 | node_modules/ -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }], 4 | "react", 5 | "stage-1" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/demo.css: -------------------------------------------------------------------------------- 1 | .customButton { 2 | background: white; 3 | border: 1px solid black; 4 | cursor: pointer; 5 | border-radius:3px; 6 | } 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React-filepicker 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "parserOptions": { 5 | "ecmaVersion": 2017, 6 | "sourceType": "module", 7 | "ecmaFeatures": { 8 | "jsx": true, 9 | "experimentalObjectRestSpread": true 10 | } 11 | }, 12 | "rules": { 13 | "import/no-unresolved": 0, 14 | "global-require": 0, 15 | "no-console": 0, 16 | "max-len": 0, 17 | "no-param-reassign": [ 18 | "error", 19 | { 20 | "props": false 21 | } 22 | ], 23 | "object-curly-newline": ["error", { "multiline": true }] 24 | }, 25 | "plugins": [ 26 | "react", 27 | "jsx-a11y", 28 | "babel" 29 | ], 30 | "env": { 31 | "browser": true, 32 | "node": true 33 | } 34 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | logs 3 | *.log 4 | npm-debug.log* 5 | pids 6 | *.pid 7 | *.seed 8 | lib-cov 9 | .grunt 10 | .lock-wscript 11 | build/Release 12 | node_modules 13 | .idea 14 | jspm_packages 15 | .npm 16 | .node_repl_history 17 | .idea/tasks.xml 18 | .idea/dataSources.ids 19 | .idea/dataSources.xml 20 | .idea/dataSources.local.xml 21 | .idea/sqlDataSources.xml 22 | .idea/dynamic.xml 23 | .idea/uiDesigner.xml 24 | .idea/gradle.xml 25 | .idea/libraries 26 | .idea/mongoSettings.xml 27 | *.iws 28 | /out/ 29 | .idea_modules/ 30 | atlassian-ide-plugin.xml 31 | com_crashlytics_export_strings.xml 32 | crashlytics.properties 33 | crashlytics-build.properties 34 | fabric.properties 35 | /dist/react-filepicker.js.map 36 | /dist/demo.js.map 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-filepicker", 3 | "version": "0.11.0", 4 | "main": "dist/react-filepicker.js", 5 | "description": "react component for filepicker(a.k.a filestack)", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "rimraf dist && webpack --colors --debug --display-error-details", 9 | "prepublishOnly": "npm run build", 10 | "lint": "eslint" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/zerocho/react-filepicker.git" 15 | }, 16 | "keywords": [ 17 | "react-filepicker", 18 | "filestack", 19 | "filepicker", 20 | "react", 21 | "uploader", 22 | "upload", 23 | "file", 24 | "image", 25 | "ssr", 26 | "server" 27 | ], 28 | "author": "ZeroCho", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/zerocho/react-filepicker/issues" 32 | }, 33 | "homepage": "https://github.com/zerocho/react-filepicker#readme", 34 | "dependencies": { 35 | "filepicker-js": "^2.4.18", 36 | "prop-types": "^15.5.10" 37 | }, 38 | "devDependencies": { 39 | "babel-cli": "^6.24.0", 40 | "babel-core": "^6.24.0", 41 | "babel-eslint": "^8.2.1", 42 | "babel-loader": "^7.0.0", 43 | "babel-preset-es2015": "^6.24.0", 44 | "babel-preset-react": "^6.23.0", 45 | "babel-preset-stage-1": "^6.22.0", 46 | "css-loader": "^0.28.4", 47 | "eslint": "^4.17.0", 48 | "eslint-config-airbnb": "^16.1.0", 49 | "eslint-plugin-babel": "^4.1.1", 50 | "eslint-plugin-import": "^2.3.0", 51 | "eslint-plugin-jsx-a11y": "^6.0.3", 52 | "eslint-plugin-react": "^7.0.1", 53 | "imports-loader": "^0.7.1", 54 | "raw-loader": "^0.5.1", 55 | "react": "^16.2.0", 56 | "react-dom": "^16.2.0", 57 | "rimraf": "^2.6.1", 58 | "style-loader": "^0.18.1", 59 | "webpack": "^3.11.0" 60 | }, 61 | "peerDependencies": { 62 | "react": "^15.3.0 || ^16", 63 | "react-dom": "^15.3.0 || ^16" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const fs = require('fs'); 4 | 5 | const rules = [ 6 | { test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ }, 7 | { 8 | test: /\.css/, 9 | use: [ 10 | 'style-loader?sourcemap', 'css-loader?modules&importLoaders=1', 11 | ], 12 | }, 13 | ]; 14 | 15 | module.exports = [{ 16 | entry: './src/ReactFilepicker', 17 | output: { 18 | path: path.join(__dirname, 'dist'), 19 | filename: 'react-filepicker.js', 20 | libraryTarget: 'commonjs2', 21 | }, 22 | devtool: 'source-map', 23 | resolve: { 24 | modules: ['node_modules', 'src'], 25 | extensions: ['.js', '.json', '.jsx'], 26 | }, 27 | module: { rules }, 28 | plugins: [ 29 | new webpack.LoaderOptionsPlugin({ 30 | minimize: true, 31 | }), 32 | new webpack.DefinePlugin({ 33 | 'process.env.NODE_ENV': JSON.stringify('production'), 34 | }), 35 | new webpack.optimize.UglifyJsPlugin({ 36 | sourceMap: true, 37 | compress: { 38 | warnings: false, 39 | }, 40 | }), 41 | new webpack.ProvidePlugin({ 42 | filepicker: 'filepicker-js', 43 | 'window.filepicker': 'filepicker-js' 44 | }), 45 | ], 46 | }, { 47 | entry: './src/demo.jsx', 48 | output: { 49 | path: path.join(__dirname, 'dist'), 50 | filename: 'demo.js' 51 | }, 52 | devtool: 'source-map', 53 | resolve: { 54 | modules: ['node_modules', 'src'], 55 | extensions: ['.json', '.js', '.jsx'], 56 | }, 57 | module: { rules }, 58 | plugins: [ 59 | new webpack.LoaderOptionsPlugin({ 60 | minimize: true, 61 | }), 62 | new webpack.DefinePlugin({ 63 | 'process.env.NODE_ENV': JSON.stringify('production'), 64 | }), 65 | new webpack.optimize.UglifyJsPlugin({ 66 | sourceMap: true, 67 | compress: { 68 | warnings: false, 69 | }, 70 | }), 71 | new webpack.ProvidePlugin({ 72 | filepicker: 'filepicker-js', 73 | 'window.filepicker': 'filepicker-js' 74 | }), 75 | ], 76 | }]; 77 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | function setAttrIfExists(key, options, attrname, dom) { 2 | if (options[key]) { 3 | dom.setAttribute(attrname, options[key]); 4 | } 5 | } 6 | 7 | function setAttrIfExistsArray(fpoptions, domElement, optionsObj) { 8 | Object.keys(optionsObj).forEach((option) => { 9 | setAttrIfExists(optionsObj[option], fpoptions, option, domElement); 10 | }); 11 | } 12 | 13 | function joinIfExist(key, options) { 14 | if (options[key]) { 15 | options[key] = options[key].join(); 16 | } 17 | } 18 | 19 | export default function applyOptions(domElement, options, mode = 'pick') { 20 | const generalOptionsMap = { 21 | 'data-fp-container': 'container', 22 | 'data-fp-mimetype': 'mimetype', 23 | 'data-fp-extension': 'extension', 24 | 'data-fp-openTo': 'openTo', 25 | 'data-fp-debug': 'debug', 26 | 'data-fp-signature': 'signature', 27 | 'data-fp-policy': 'policy', 28 | 'data-fp-language': 'language', 29 | 'data-fp-background-upload': 'backgroundUpload', 30 | 'data-fp-hide': 'hide', 31 | 'data-fp-custom-css': 'customCss', 32 | 'data-fp-crop-force': 'cropForce', 33 | 'data-fp-crop-ratio': 'cropRatio', 34 | 'data-fp-crop-dim': 'cropDim', 35 | 'data-fp-crop-max': 'cropMax', 36 | 'data-fp-crop-min': 'cropMin', 37 | 'data-fp-show-close': 'showClose', 38 | 'data-fp-conversions': 'conversions', 39 | 'data-fp-custom-text': 'customText', 40 | 'data-fp-custom-source-container': 'customSourceContainer', 41 | 'data-fp-custom-source-path': 'customSourcePath', 42 | }; 43 | const pickOnlyOptionsMap = { 44 | 'data-fp-mimetypes': 'mimetypes', 45 | 'data-fp-extensions': 'extensions', 46 | 'data-fp-maxSize': 'maxSize', 47 | 'data-fp-maxFiles': 'maxFiles', 48 | 'data-fp-store-location': 'storeLocation', 49 | 'data-fp-store-path': 'storePath', 50 | 'data-fp-store-container': 'storeContainer', 51 | 'data-fp-store-region': 'storeRegion', 52 | 'data-fp-store-access': 'storeAccess', 53 | 'data-fp-image-quality': 'imageQuality', 54 | 'data-fp-image-dim': 'imageDim', 55 | 'data-fp-image-max': 'imageMax', 56 | 'data-fp-image-min': 'imageMin', 57 | }; 58 | const webcamOptionsMap = { 59 | 'data-fp-video-recording-resolution': 'videoRes', 60 | 'data-fp-webcam-dim': 'webcamDim', 61 | 'data-fp-video-length': 'videoLen', 62 | 'data-fp-audio-length': 'audioLen', 63 | }; 64 | setAttrIfExistsArray(options, domElement, generalOptionsMap); 65 | if (mode === 'export') { 66 | setAttrIfExists('suggestedFilename', options, 'data-fp-suggestedFilename', domElement); 67 | } else if (mode === 'pick' || mode === 'pickMultiple') { 68 | setAttrIfExistsArray(options, domElement, pickOnlyOptionsMap); 69 | options.webcam = {}; 70 | setAttrIfExistsArray(options.webcam, domElement, webcamOptionsMap); 71 | } 72 | if (options.services) { 73 | domElement.setAttribute('data-fp-services', options.services.join()); 74 | } 75 | if (options.service) { 76 | domElement.setAttribute('data-fp-service', options.service); 77 | } 78 | const arrayToJoin = ['extensions', 'mimetypes', 'imageDim', 'imageMin', 'imageMax', 'cropDim', 'cropMax', 'cropMin', 'webcamDim', 'conversions']; 79 | Object.keys(arrayToJoin).forEach((key) => { 80 | joinIfExist(arrayToJoin[key], options); 81 | }); 82 | if (options.folders === true) { 83 | domElement.setAttribute('data-fp-folders', 'true'); 84 | } 85 | if (options.multiple === true || mode === 'pickMultiple') { 86 | return domElement.setAttribute('data-fp-multiple', 'true'); 87 | } 88 | return domElement; 89 | } 90 | -------------------------------------------------------------------------------- /src/demo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import ReactFilepicker from './ReactFilepicker'; 4 | import styles from './demo.css'; 5 | 6 | document.addEventListener('DOMContentLoaded', () => { 7 | const rootNode = document.createElement('div'); 8 | document.body.appendChild(rootNode); 9 | const apikey = 'Acu94EFL1STGYvkM6a8usz'; 10 | const dragDropOptions = { 11 | buttonText: 'I can handle drag&drop!', 12 | multiple: true, 13 | mimetype: 'image/*', 14 | container: 'window', 15 | webcamDim: [1280, 720], 16 | webcam: { 17 | videoRes: '1280x720', 18 | }, 19 | services: ['COMPUTER', 'FACEBOOK', 'CLOUDAPP'], 20 | }; 21 | const convertOptions = { 22 | width: 200, 23 | height: 200, 24 | }; 25 | const customOptions = { 26 | buttonText: 'I\'m customized', 27 | buttonClass: styles.customButton, 28 | multiple: true, 29 | mimetype: 'image/*', 30 | container: 'window', 31 | services: ['COMPUTER', 'FACEBOOK', 'CLOUDAPP'], 32 | }; 33 | const blob = { 34 | url: 'https://www.filestackapi.com/api/file/9BWnyKPBQI23ukbT7sZA', 35 | filename: 'robot.png', 36 | mimetype: 'image/png', 37 | isWriteable: false, 38 | size: 28683, 39 | }; 40 | const pickAndStoreOptions = { 41 | buttonText: 'PickAndStore', 42 | location: 'S3', 43 | }; 44 | const exportOptions = { 45 | url: 'https://www.filestackapi.com/api/file/lQ9LalJTKmuou4WSw9LM', 46 | mimetype: 'image/png', 47 | buttonText: 'Export', 48 | suggestedFilename: 'newFile', 49 | }; 50 | const callback = (fpfiles) => { 51 | console.log('fpfiles', fpfiles); 52 | }; 53 | ReactDOM.render( 54 |
55 |
56 |
DefaultWidget
57 | 58 | 59 |
60 |
61 |
Drag&Drop Widget with custom options and Callback
62 | 63 | 64 |
65 |
66 |
Custom button(You can put className on the button to style)
67 | 68 | 69 |
70 |
71 |
Custom link(You can put className on the link to style)
72 | 73 | 74 |
75 |
76 |
Multiple files upload
77 | 78 | 79 |
80 |
81 |
Custom button with custom options and custom styles
82 | 83 | 84 |
85 |
86 |
PickAndStore button
87 | 94 | 95 |
96 |
97 |
Export button
98 | 105 | 106 |
107 |
108 |
Convert button
109 | 118 | 119 |
, 120 | rootNode, 121 | ); 122 | }); 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Filepicker 2 | react component for **filepicker** 3 | 4 | ## How to install 5 | 6 | **This is for v2 old filepicker api. If you want latest v3 filestack api, go [here](https://npmjs.com/package/react-filestack)** 7 | 8 | [Live Demo](https://zerocho.herokuapp.com/portfolio/ReactFilepicker) 9 | [NPM](https://npmjs.com/package/react-filepicker) 10 | [Github](https://github.com/zerocho/react-filepicker) 11 | ``` 12 | npm install react-filepicker 13 | ``` 14 | ## Import 15 | ``` 16 | var ReactFilepicker = require('react-filepicker'); 17 | ``` 18 | In ES2015 19 | ``` 20 | import ReactFilepicker from 'react-filepicker'; 21 | ``` 22 | ## Usage 23 | You should register for [Filestack(filepicker)](https://www.filestack.com) and get an **API key** first! 24 | 25 | **Default FileStack widget** 26 | ``` 27 | 28 | ``` 29 | 30 | **Custom Designed button** 31 | ``` 32 | 33 | ``` 34 | 35 | **Other mode than 'pick'** 36 | ``` 37 | 38 | ``` 39 | Available modes: 40 | * convert 41 | * export 42 | * pickAndStore 43 | * pickMultiple (Instead, you can use pick mode and put 'multiple: true' in **options** object) 44 | * read 45 | * store 46 | * storeUrl 47 | * write 48 | * writeUrl 49 | * stat 50 | 51 | make your own options and callback function, connect it to the component and get the results(either fpfiles or blob object) 52 | ``` 53 | const options = { 54 | buttonText: 'Pick Me', 55 | buttonClass: 'filepicker', 56 | mimetype: 'image/*', 57 | container: 'window', 58 | services: ['COMPUTER', 'FACEBOOK', 'CLOUDAPP'] 59 | }; 60 | yourCallbackFunction(fpfiles) { 61 | // handle fpfiles or blob object 62 | } 63 | ``` 64 | 65 | **Link instead of button** 66 | if you want a custom button to be a link, just put **link** props 67 | ``` 68 | 69 | ``` 70 | 71 | ## Result 72 | ![filepicker](https://cloud.githubusercontent.com/assets/10962668/16950040/17a2eb94-4df9-11e6-8995-fb120a466400.png) 73 | Works well with IE... 74 | 75 | ## Demo 76 | git clone this project and open index.html 77 | You can also see live demo here 78 | [Link](https://zerocho.herokuapp.com/portfolio/ReactFilepicker) 79 | 80 | ## Props 81 | [Official Filestack Documentation](https://filestack.com/docs) 82 | 83 | > ### apikey 84 | > **required** string. An API key for filestack 85 | 86 | > ### defaultWidget 87 | > **optional** boolean. **default** true. choose between the default widget and the custom button 88 | 89 | > ### mode 90 | > **optional** string. **default** 'pick'. **options** `['pick', 'dragdrop', 'convert', 'export']`. convert and export modes are for custom button. 91 | 92 | > ### blob 93 | > **optional** object. use if you need to insert blob object for convert, export, stat, write or writeUrl mode. 94 | 95 | > ### input 96 | > **optional** object. use this for read, store, storeUrl or write mode. 97 | 98 | > ### log 99 | > **optional** object. **default** false. choose whether to console.log filepicker process 100 | 101 | > ### onSuccess 102 | > **optional** function. get result(fpfiles or blob object) after upload is done. 103 | 104 | > ### onError 105 | > **optional** function. send error object as callback parameter 106 | 107 | > ### onProgress 108 | > **optional** function. send progress object as callback parameter 109 | 110 | > ### options 111 | > **optional** object. **Detailed options for button. See Javascript API of [official documentation](https://filestack.com/docs). Put everything in it if you think you have to** 112 | 113 | > ### buttonText 114 | > **optional** string. When using custom button, you can set your own text. It is included in **options** prop(as options.buttonText), so use only when it's necessary. 115 | 116 | > ### buttonClass 117 | > **optional** string. When using custom button, you can set className. It is included in **options** prop(as options.buttonClass), so use only when it's necessary. 118 | 119 | ## Wanna Contribute? 120 | Please contribute to this package via **Pull Request**, or you can open **Issues**! 121 | ``` 122 | npm install && npm run build 123 | run index.html 124 | ``` 125 | 126 | ## Contributors 127 | - Zero Cho 128 | - Łukasz Kornek 129 | 130 | ## License 131 | MIT 132 | -------------------------------------------------------------------------------- /src/ReactFilepicker.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import applyOptions from './options'; 4 | 5 | class ReactFilepicker extends Component { 6 | static defaultProps = { 7 | blob: null, 8 | input: null, 9 | link: false, 10 | buttonText: '', 11 | buttonClass: '', 12 | onSuccess: null, 13 | onProgress: null, 14 | onError: null, 15 | defaultWidget: true, 16 | mode: 'pick', 17 | log: false, 18 | options: { 19 | folders: false, 20 | buttonText: 'Pick File', 21 | container: 'modal', 22 | language: 'en', 23 | webcam: { 24 | videoRes: '640x480', 25 | audioLen: '3600', 26 | vidioLen: '3600', 27 | }, 28 | backgroundUpload: true, 29 | hide: false, 30 | imageQuality: 100, 31 | cropForce: false, 32 | }, 33 | }; 34 | 35 | static propTypes = { 36 | blob: PropTypes.objectOf(PropTypes.any), 37 | input: PropTypes.objectOf(PropTypes.any), 38 | apikey: PropTypes.string.isRequired, 39 | defaultWidget: PropTypes.bool, 40 | link: PropTypes.bool, 41 | mode: PropTypes.string, 42 | buttonText: PropTypes.string, 43 | buttonClass: PropTypes.string, 44 | onSuccess: PropTypes.func, 45 | onError: PropTypes.func, 46 | log: PropTypes.bool, 47 | onProgress: PropTypes.func, 48 | options: PropTypes.shape({ 49 | url: PropTypes.string, 50 | filename: PropTypes.string, 51 | suggestedFilename: PropTypes.string, 52 | buttonText: PropTypes.string, 53 | buttonClass: PropTypes.string, 54 | mimetype: PropTypes.string, 55 | mimetypes: PropTypes.arrayOf(PropTypes.string), 56 | extension: PropTypes.string, 57 | extensions: PropTypes.arrayOf(PropTypes.string), 58 | multiple: PropTypes.bool, 59 | maxSize: PropTypes.number, 60 | maxFiles: PropTypes.number, 61 | folders: PropTypes.bool, 62 | container: PropTypes.string, 63 | language: PropTypes.string, 64 | service: PropTypes.string, 65 | services: PropTypes.arrayOf(PropTypes.string), 66 | openTo: PropTypes.string, 67 | webcamDim: PropTypes.arrayOf(PropTypes.number), 68 | webcam: PropTypes.shape({ 69 | videoRes: PropTypes.string, 70 | audioLen: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 71 | videoLen: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 72 | }), 73 | customSourceContainer: PropTypes.string, 74 | customSourcePath: PropTypes.string, 75 | debug: PropTypes.bool, 76 | policy: PropTypes.string, 77 | signature: PropTypes.string, 78 | backgroundUpload: PropTypes.bool, 79 | hide: PropTypes.bool, 80 | customCss: PropTypes.string, 81 | customText: PropTypes.string, 82 | imageQuality: PropTypes.number, 83 | imageDim: PropTypes.arrayOf(PropTypes.number), 84 | imageMax: PropTypes.arrayOf(PropTypes.number), 85 | imageMin: PropTypes.arrayOf(PropTypes.number), 86 | conversions: PropTypes.arrayOf(PropTypes.string), 87 | cropRatio: PropTypes.number, 88 | cropDim: PropTypes.arrayOf(PropTypes.number), 89 | cropMax: PropTypes.arrayOf(PropTypes.number), 90 | cropMin: PropTypes.arrayOf(PropTypes.number), 91 | cropForce: PropTypes.bool, 92 | width: PropTypes.number, 93 | height: PropTypes.number, 94 | fit: PropTypes.oneOf(['clip', 'crop', 'scale', 'max']), 95 | align: PropTypes.oneOf(['top', 'bottom', 'left', 'right', 'faces']), 96 | crop: PropTypes.arrayOf(PropTypes.number), 97 | crop_first: PropTypes.bool, 98 | format: PropTypes.string, 99 | filter: PropTypes.oneOf(['blur', 'sharpen']), 100 | compress: PropTypes.bool, 101 | quality: PropTypes.number, 102 | rotate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 103 | watermark: PropTypes.string, 104 | watermark_position: PropTypes.string, 105 | watermark_size: PropTypes.number, 106 | location: PropTypes.string, 107 | path: PropTypes.string, 108 | storeRegion: PropTypes.string, 109 | storeContainer: PropTypes.string, 110 | access: PropTypes.string, 111 | base64encode: PropTypes.bool, 112 | base64decode: PropTypes.bool, 113 | asText: PropTypes.bool, 114 | cache: PropTypes.bool, 115 | uploaded: PropTypes.bool, 116 | writeable: PropTypes.bool, 117 | md5: PropTypes.bool, 118 | }), 119 | }; 120 | 121 | componentDidMount() { 122 | const filepicker = require('filepicker-js'); 123 | 124 | const { apikey, buttonText, buttonClass, onSuccess, options, mode, log } = this.props; 125 | const custom = this.fpButton; 126 | if (!custom) { // if using default widget 127 | const element = this.target; 128 | if (mode === 'dragdrop') { 129 | element.setAttribute('type', 'filepicker-dragdrop'); 130 | } else if (mode === 'pickMultiple') { 131 | options.multiple = true; 132 | } 133 | applyOptions(element, options, mode); 134 | element.setAttribute('data-fp-apikey', apikey); 135 | element.setAttribute('data-fp-button-text', buttonText || options.buttonText || 'Pick File'); 136 | element.setAttribute('data-fp-button-class', buttonClass || options.buttonClass || 'fp__btn'); 137 | element.onchange = (e) => { 138 | if (typeof onSuccess === 'function') { 139 | onSuccess(e.fpfiles.length === 1 ? e.fpfile : e.fpfiles); 140 | } 141 | if (log) { 142 | console.log(e.fpfile); 143 | } 144 | }; 145 | filepicker.constructWidget(element); 146 | element.setAttribute('type', ''); 147 | } 148 | } 149 | 150 | onClickPick = (e) => { 151 | const filepicker = require('filepicker-js'); 152 | 153 | e.stopPropagation(); 154 | e.preventDefault(); 155 | const { apikey, onSuccess, onError, onProgress, options, mode, blob, input, log } = this.props; 156 | const onFinished = (result) => { 157 | if (typeof onSuccess === 'function') { 158 | onSuccess(result); 159 | } 160 | if (log) { 161 | console.log(result); 162 | } 163 | }; 164 | const onFail = (error) => { 165 | if (typeof onError === 'function') { 166 | onError(error); 167 | } 168 | if (log) { 169 | console.error(error); 170 | } 171 | }; 172 | const onUploading = (progress) => { 173 | if (typeof onProgress === 'function') { 174 | onProgress(progress); 175 | } 176 | if (log) { 177 | console.log(progress); 178 | } 179 | }; 180 | filepicker.setKey(apikey); 181 | if (mode === 'export') { 182 | filepicker.exportFile(blob || options.url, options, onFinished, onFail, onUploading); 183 | } else if (mode === 'convert') { 184 | filepicker.convert(blob, options, options, onFinished, onFail, onUploading); 185 | } else if (mode === 'pickAndStore') { 186 | filepicker.pickAndStore(options, options, onFinished, onFail, onUploading); 187 | } else if (mode === 'pickMultiple' || options.multiple) { 188 | filepicker.pickMultiple(options, onFinished, onFail, onUploading); 189 | } else if (mode === 'read') { 190 | filepicker.read(input || options.url, options, onFinished, onError, onUploading); 191 | } else if (mode === 'store') { 192 | filepicker.store(input, options, onFinished, onError, onUploading); 193 | } else if (mode === 'storeUrl') { 194 | filepicker.storeUrl(options.url, options, onFinished, onError, onUploading); 195 | } else if (mode === 'stat') { 196 | filepicker.stat(blob, options, onFinished, onError); 197 | } else if (mode === 'write') { 198 | filepicker.write(blob, input, options, onFinished, onError, onUploading); 199 | } else if (mode === 'writeUrl') { 200 | filepicker.writeUrl(blob, options.url, options, onFinished, onError, onUploading); 201 | } else { 202 | filepicker.pick(options, onFinished, onFail, onUploading); 203 | } 204 | }; 205 | 206 | render() { 207 | const { defaultWidget, buttonClass, buttonText, link, options } = this.props; 208 | if (defaultWidget) { 209 | return ( 210 | { 212 | this.target = c; 213 | }} 214 | type="filepicker" 215 | /> 216 | ); 217 | } 218 | const Tag = link ? 'a' : 'button'; 219 | return ( 220 | { 222 | this.fpButton = c; 223 | }} 224 | onClick={this.onClickPick} 225 | className={buttonClass || options.buttonClass} 226 | > 227 | {buttonText || options.buttonText} 228 | 229 | ); 230 | } 231 | } 232 | 233 | export default ReactFilepicker; 234 | -------------------------------------------------------------------------------- /dist/react-filepicker.js: -------------------------------------------------------------------------------- 1 | module.exports=function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t,r){(function(t){r(13),e.exports=t}).call(t,r(0))},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var a=r(2),c=r.n(a),s=r(7),l=r.n(s),u=r(12),p=function(){function e(e,t){for(var r=0;rN.length&&N.push(e)}function d(e,t,r,o){var i=typeof e;"undefined"!==i&&"boolean"!==i||(e=null);var a=!1;if(null===e)a=!0;else switch(i){case"string":case"number":a=!0;break;case"object":switch(e.$$typeof){case k:case E:case A:case F:a=!0}}if(a)return r(o,e,""===t?"."+m(e,0):t),1;if(a=0,t=""===t?".":t+":",Array.isArray(e))for(var c=0;c2&&void 0!==arguments[2]?arguments[2]:"pick",a={"data-fp-container":"container","data-fp-mimetype":"mimetype","data-fp-extension":"extension","data-fp-openTo":"openTo","data-fp-debug":"debug","data-fp-signature":"signature","data-fp-policy":"policy","data-fp-language":"language","data-fp-background-upload":"backgroundUpload","data-fp-hide":"hide","data-fp-custom-css":"customCss","data-fp-crop-force":"cropForce","data-fp-crop-ratio":"cropRatio","data-fp-crop-dim":"cropDim","data-fp-crop-max":"cropMax","data-fp-crop-min":"cropMin","data-fp-show-close":"showClose","data-fp-conversions":"conversions","data-fp-custom-text":"customText","data-fp-custom-source-container":"customSourceContainer","data-fp-custom-source-path":"customSourcePath"},c={"data-fp-mimetypes":"mimetypes","data-fp-extensions":"extensions","data-fp-maxSize":"maxSize","data-fp-maxFiles":"maxFiles","data-fp-store-location":"storeLocation","data-fp-store-path":"storePath","data-fp-store-container":"storeContainer","data-fp-store-region":"storeRegion","data-fp-store-access":"storeAccess","data-fp-image-quality":"imageQuality","data-fp-image-dim":"imageDim","data-fp-image-max":"imageMax","data-fp-image-min":"imageMin"},s={"data-fp-video-recording-resolution":"videoRes","data-fp-webcam-dim":"webcamDim","data-fp-video-length":"videoLen","data-fp-audio-length":"audioLen"};o(t,e,a),"export"===r?n("suggestedFilename",t,"data-fp-suggestedFilename",e):"pick"!==r&&"pickMultiple"!==r||(o(t,e,c),t.webcam={},o(t.webcam,e,s)),t.services&&e.setAttribute("data-fp-services",t.services.join()),t.service&&e.setAttribute("data-fp-service",t.service);var l=["extensions","mimetypes","imageDim","imageMin","imageMax","cropDim","cropMax","cropMin","webcamDim","conversions"];return Object.keys(l).forEach(function(e){i(l[e],t)}),!0===t.folders&&e.setAttribute("data-fp-folders","true"),!0===t.multiple||"pickMultiple"===r?e.setAttribute("data-fp-multiple","true"):e}t.a=a},function(module,exports,__webpack_require__){"use strict";(function(__webpack_provided_window_dot_filepicker,filepicker){!function(){var e=function(){var e={},t=function(t,r,n){for(var o=t.split("."),i=0;i-1){var l=e.util.parseUrl(s).params;l=e.conversions.mapRestParams(l),l.crop&&e.util.setDefault(l,"crop_first",!0);for(var u in l)e.util.setDefault(c,u,l[u])}e.conversions.convert(e.util.trimConvert(s),c,o,i,a)},w=function(t){return e.widgets.constructWidget(t)},y=function(t,r){return e.dragdrop.makeDropPane(t,r)};return{setKey:t,setResponsiveOptions:function(t){return e.responsiveImages.setResponsiveOptions(t)},pick:n,pickFolder:a,pickMultiple:o,pickAndStore:i,read:c,write:l,writeUrl:u,export:p,exportFile:p,processImage:f,store:d,storeUrl:m,stat:h,metadata:h,remove:g,convert:v,constructWidget:w,makeDropPane:y,FilepickerException:r,responsive:function(){e.responsiveImages.update.apply(null,arguments)},logout:function(t){t=t||{},e.ajax.get(e.urls.LOGOUT,{success:t.onSuccess,error:t.onError,withCredentials:!0})},version:"2.4.18"}},!0),filepicker.extend("mimetypes",function(){var e=this,t={".stl":"application/sla",".hbs":"text/html",".pdf":"application/pdf",".jpg":"image/jpeg",".jpeg":"image/jpeg",".jpe":"image/jpeg",".imp":"application/x-impressionist",".vob":"video/dvd"},r=["application/octet-stream","application/download","application/force-download","octet/stream","application/unknown","application/x-download","application/x-msdownload","application/x-secure-download"];return{getMimetype:function(e){if(e.type){var n=e.type;n=n.toLowerCase();for(var o=!1,i=0;i=0||o.indexOf("?")>=0)&&(o=encodeURIComponent(o)),l+e(t,r)+"&curl="+o+n(t.conversions)},h=function(t,r){return u+e(t,r)},g=function(t,r,n){return(t.indexOf("&")>=0||t.indexOf("?")>=0)&&(t=encodeURIComponent(t)),s+e(r,n)+"&url="+t+(void 0!==r.mimetype?"&m="+r.mimetype:"")+(void 0!==r.extension?"&ext="+r.extension:"")+(r.suggestedFilename?"&defaultSaveasName="+r.suggestedFilename:"")},v=function(e){return p+e.location+"?key="+o.apikey+(e.base64decode?"&base64decode=true":"")+(e.mimetype?"&mimetype="+e.mimetype:"")+(e.filename?"&filename="+encodeURIComponent(e.filename):"")+(e.path?"&path="+e.path:"")+(e.container?"&container="+e.container:"")+(e.access?"&access="+e.access:"")+t(e)+"&plugin="+r()};return{BASE:i,DIALOG_BASE:a,API_COMM:i+"/dialog/comm_iframe/",COMM:a+"/dialog/comm_iframe/",FP_COMM_FALLBACK:a+"/dialog/comm_hash_iframe/",STORE:p,PICK:c,EXPORT:s,LOGOUT:i+"/api/clients/unauth",constructPickUrl:d,constructConvertUrl:m,constructPickFolderUrl:h,constructExportUrl:g,constructWriteUrl:function(e,n){return e+"?nonce=fp"+(n.base64decode?"&base64decode=true":"")+(n.mimetype?"&mimetype="+n.mimetype:"")+t(n)+"&plugin="+r()},constructStoreUrl:v,constructHostCommFallback:function(){return o.util.parseUrl(window.location.href).origin+"/404"},getPlugin:r}}),filepicker.extend("ajax",function(){var e=this,t=function(e,t){t.method="GET",i(e,t)},r=function(t,r){r.method="POST",t+=(t.indexOf("?")>=0?"&":"?")+"_cacheBust="+e.util.getId(),i(t,r)},n=function(t,r){var o=[];for(var i in t){var a=t[i];r&&(i=r+". + key + ");var c;switch(e.util.typeOf(a)){case"object":c=n(a,i);break;case"array":for(var s={},l=0;l=0?"&":"?")+"plugin="+e.urls.getPlugin(),u&&p&&(u=n(r.data));var v;if(r.xhr)v=r.xhr;else if(!(v=o()))return r.error("Ajax not allowed"),v;if(h&&window.XDomainRequest&&!("withCredentials"in v))return new a(t,r);r.progress&&v.upload&&v.upload.addEventListener("progress",function(e){e.lengthComputable&&r.progress(Math.round(95*e.loaded/e.total))},!1);var w=function(){if(4==v.readyState&&!g)if(r.progress&&r.progress(100),v.status>=200&&v.status<300){var t=v.responseText;if(r.json)try{t=e.json.decode(t)}catch(e){return void y.call(v,"Invalid json: "+t)}c(t,v.status,v),g=!0}else y.call(v,v.responseText),g=!0};v.onreadystatechange=w;var y=function(e){if(!g)return r.progress&&r.progress(100),g=!0,400==this.status?void s("bad_params",this.status,this):403==this.status?void s("not_authorized",this.status,this):404==this.status?void s("not_found",this.status,this):h?4==this.readyState&&0===this.status?void s("CORS_not_allowed",this.status,this):void s("CORS_error",this.status,this):void s(e,this.status,this)};v.onerror=y,u&&"GET"==i&&(t+=(-1!==t.indexOf("?")?"&":"?")+u,u=null),r.withCredentials&&(v.withCredentials=!0),v.open(i,t,l),r.json?v.setRequestHeader("Accept","application/json, text/javascript"):v.setRequestHeader("Accept","text/javascript, text/html, application/xml, text/xml, */*");var b=f["Content-Type"]||f["content-type"];if(u&&p&&("POST"==i||"PUT"==i)&&void 0===b&&v.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=utf-8"),f)for(var x in f)v.setRequestHeader(x,f[x]);return v.send(u),v},a=function(t,r){if(!window.XDomainRequest)return null;var o=r.method?r.method.toUpperCase():"POST",i=r.success||function(){},a=r.error||function(){},c=r.data||{};if("http:"==window.location.protocol?t=t.replace("https:","http:"):"https:"==window.location.protocol&&(t=t.replace("http:","https:")),r.async)throw new e.FilepickerException("Asyncronous Cross-domain requests are not supported");"GET"!==o&&"POST"!==o&&(c._method=o,o="POST"),!1!==r.processData&&(c=c?n(c):null),c&&"GET"==o&&(t+=(t.indexOf("?")>=0?"&":"?")+c,c=null),t+=(t.indexOf("?")>=0?"&":"?")+"_xdr=true&_cacheBust="+e.util.getId();var s=new window.XDomainRequest;return s.onload=function(){var t=s.responseText;if(r.progress&&r.progress(100),r.json)try{t=e.json.decode(t)}catch(e){return void a("Invalid json: "+t,200,s)}i(t,200,s)},s.onerror=function(){r.progress&&r.progress(100),a(s.responseText||"CORS_error",this.status||500,this)},s.onprogress=function(){},s.ontimeout=function(){},s.timeout=3e4,s.open(o,t,!0),s.send(c),s};return{get:t,post:r,request:i}}),filepicker.extend("files",function(){var e=this,t=function(t,n,o,i,a){var c=void 0===n.base64encode;c&&(n.base64encode=!0),n.base64encode=!1!==n.base64encode;var s=function(t){c&&(t=e.base64.decode(t,!!n.asText)),o(t)};r.call(this,t,n,s,i,a)},r=function(t,r,n,o,i){!0!==r.cache&&(r._cacheBust=e.util.getId()),e.ajax.get(t,{data:r,headers:{"X-NO-STREAM":!0},success:n,error:function(t,r,n){o("CORS_not_allowed"===t?new e.errors.FPError(113):"CORS_error"===t?new e.errors.FPError(114):"not_found"===t?new e.errors.FPError(115):"bad_params"===t?new e.errors.FPError(400):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(118))},progress:i})},n=function(t,r,n,o,i){if(!(window.File&&window.FileReader&&window.FileList&&window.Blob))return i(10),void e.files.storeFile(t,{},function(t){i(50),e.files.readFromFPUrl(t.url,r,n,o,function(e){i(50+e/2)})},o,function(e){i(e/2)});var a=!!r.base64encode,c=!!r.asText,s=new FileReader;s.onprogress=function(e){e.lengthComputable&&i(Math.round(e.loaded/e.total*100))},s.onload=function(t){i(100),n(a?e.base64.encode(t.target.result,c):t.target.result)},s.onerror=function(t){switch(t.target.error.code){case t.target.error.NOT_FOUND_ERR:o(new e.errors.FPError(115));break;case t.target.error.NOT_READABLE_ERR:o(new e.errors.FPError(116));break;case t.target.error.ABORT_ERR:o(new e.errors.FPError(117));break;default:o(new e.errors.FPError(118))}},c||!s.readAsBinaryString?s.readAsText(t):s.readAsBinaryString(t)},o=function(t,r,n,o,i,a){var c=n.mimetype||"text/plain";e.ajax.post(e.urls.constructWriteUrl(t,n),{headers:{"Content-Type":c},data:r,processData:!1,json:!0,success:function(t){o(e.util.standardizeFPFile(t))},error:function(t,r,n){i("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))},progress:a})},i=function(t,r,n,o,i,a){var c=function(t,r,n){i("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))},s=function(t){o(e.util.standardizeFPFile(t))};u(r,e.urls.constructWriteUrl(t,n),s,c,a)},a=function(t,r,n,o,i,a){var c=function(t,r,n){i("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))},s=function(t){o(e.util.standardizeFPFile(t))};n.mimetype=r.type,u(r,e.urls.constructWriteUrl(t,n),s,c,a)},c=function(t,r,n,o,i,a){e.ajax.post(e.urls.constructWriteUrl(t,n),{data:{url:r},json:!0,success:function(t){o(e.util.standardizeFPFile(t))},error:function(t,r,n){i("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))},progress:a})},s=function(t,r,n,o,i){if(t.files)return void(0===t.files.length?o(new e.errors.FPError(115)):l(t.files[0],r,n,o,i));e.util.setDefault(r,"location","S3"),r.filename||(r.filename=t.value.replace("C:\\fakepath\\","")||t.name);var a=t.name;t.name="fileUpload",e.iframeAjax.post(e.urls.constructStoreUrl(r),{data:t,processData:!1,json:!0,success:function(r){t.name=a,n(e.util.standardizeFPFile(r))},error:function(t,r,n){o("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))}})},l=function(t,r,n,o,i){e.util.setDefault(r,"location","S3");var a=function(t,r,n){"not_found"===t?o(new e.errors.FPError(121)):"bad_params"===t?o(new e.errors.FPError(122)):"not_authorized"===t?o(new e.errors.FPError(403)):(e.util.console.error(t),o(new e.errors.FPError(123)))},c=function(t){n(e.util.standardizeFPFile(t))};r.filename||(r.filename=t.name||t.fileName),u(t,e.urls.constructStoreUrl(r),c,a,i)},u=function(t,r,n,o,i){if(t.files&&(t=t.files[0]),!window.FormData||!window.XMLHttpRequest)e.iframeAjax.post(r,{data:t,json:!0,success:n,error:o});else{var a=new window.FormData;a.append("fileUpload",t),e.ajax.post(r,{json:!0,processData:!1,data:a,success:n,error:o,progress:i})}},p=function(t,r,n,o,i){e.util.setDefault(r,"location","S3"),e.util.setDefault(r,"mimetype","text/plain"),e.ajax.post(e.urls.constructStoreUrl(r),{headers:{"Content-Type":r.mimetype},data:t,processData:!1,json:!0,success:function(t){n(e.util.standardizeFPFile(t))},error:function(t,r,n){o("not_found"===t?new e.errors.FPError(121):"bad_params"===t?new e.errors.FPError(122):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(123))},progress:i})};return{readFromUrl:r,readFromFile:n,readFromFPUrl:t,writeDataToFPUrl:o,writeFileToFPUrl:a,writeFileInputToFPUrl:i,writeUrlToFPUrl:c,storeFileInput:s,storeFile:l,storeUrl:function(t,r,n,o,i){e.util.setDefault(r,"location","S3"),e.ajax.post(e.urls.constructStoreUrl(r),{data:{url:e.util.getFPUrl(t)},json:!0,success:function(t){n(e.util.standardizeFPFile(t))},error:function(t,r,n){o("not_found"===t?new e.errors.FPError(151):"bad_params"===t?new e.errors.FPError(152):"not_authorized"===t?new e.errors.FPError(403):new e.errors.FPError(153))},progress:i})},storeData:p,stat:function(t,r,n,o){var i=["uploaded","modified","created"];!0!==r.cache&&(r._cacheBust=e.util.getId()),e.ajax.get(t+"/metadata",{json:!0,data:r,success:function(e){for(var t=0;t=0?"&":"?")+"_cacheBust="+e.util.getId(),a(t,r)},i=function(){if(t.length>0){var e=t.shift();a(e.url,e.options)}},a=function(n,o){if(r)return void t.push({url:n,options:o});n+=(n.indexOf("?")>=0?"&":"?")+"plugin="+e.urls.getPlugin()+"&_cacheBust="+e.util.getId(),n+="&Content-Type=text%2Fhtml",e.comm.openChannel();var i;try{i=document.createElement('