netresearch / assetpicker
A free asset or file picker with abstraction layer allowing several adapters like GitHub, EnterMediaDB, Amazon S3, Google Drive, Dropbox etc.
Installs: 131
Dependents: 1
Suggesters: 0
Security: 0
Stars: 22
Watchers: 7
Forks: 4
Open Issues: 0
Language:JavaScript
Requires
- jenssegers/proxy: ^2.2
README
AssetPicker is a free asset or file picker designed to be easily included into web application interfaces. It has a file abstraction layer allowing adapters to connect to any remote storage, be it cloud storages like Amazon S3, Google Drive or Dropbox or assets from a custom web application server. In opposite to other file managers or pickers, AssetPicker is suitable for hierarchical as well as associative file storages.
Try the demo
Manual
- How it works
- Browser compatibility
- Installation
- Configuration
- API
- Adapters
- Customize the app
- Roadmap
How it works
AssetPicker consists of two bundles: The picker (AssetPicker
in picker.js
) and the app (AssetPickerApp
in app.js
). The picker is a lightweight script without any dependencies that will add it's listeners to elements matching the configured selector. When one of these was clicked it'll setup a modal from a template, inject the styles for it into the header (both, template and style are customizable), loads the app into and iframe in the modal and passes it the config. The communication with the iframe is done with cross window messaging so it is CORS aware.
The app provides the actual user interface and functionality. It has a default configuration which will be merged with the configuration passed to the picker. The key part of this configuration are the storages, which will be mounted as top level entries on the navigation bar (and on the start screen when you use multiple storages). Each of the storages can have a separate configuration and use other adapters. It reads the storages and adapters from the config and loads the adapter source scripts into the iframe, when they are used by one of the storages - thus unneeded storages don't bloat the size of the app.
Both, app and adapters are Vue.js components which allows for a modern and maintainable application structure.
Unless you want to customize the app itself, the picker will be the only API you'll have to use.
Browser compatibility
Modern browsers (IE >= 10) - tested in Chrome 53, Firefox 35 - 47, IE 10 - 11, Edge
Installation
CDN
The easiest way to integrate AssetPicker is to use include the picker script from a CDN:
<script src="https://cdn.rawgit.com/netresearch/assetpicker/1.3.4/dist/js/picker.js"></script> <script> new AssetPicker(config, options); </script> <button rel="assetpicker">Select a file</button>
It doesn't matter if you include the script in head or at footer - it will register on dom ready anyway.
If you don't want to use a CDN, you can download the dist directory to a web server and include the picker-min.js
from there (the other files from dist must be available).
Docker
The best way to host AssetPicker on your own is to use it with docker or even easier with docker-compose:
git clone https://github.com/netresearch/assetpicker.git
cd assetpicker
docker-compose up -d
If you want to use the built in proxy, you'll need to run the following once:
docker exec -tiu www-data assetpicker_php '/bin/bash' composer install
Composer
You can include AssetPicker into your PHP application easily with composer (but you might need to make it's directory within the vendor directory available by linking it to an adequate public folder):
composer require netresearch/assetpicker ln -s vendor/netresearch/assetpicker web/assetpicker
Symfony Application
Feel free to use the AssetPicker Bundle.
npm
You can happily install AssetPicker using npm:
npm install --save assetpicker
but you'll need to tell it the source of the app (please open an issue or PR if you find a way to workaround this):
var AssetPicker = require('assetpicker'); new AssetPicker( config, { modal: { src: 'node_modules/assetpicker/dist' } } );
See more on setting AssetPicker with npm below.
Configuration
The AssetPicker
constructor takes two arguments: config
(required) and options
(both of type object
). config
is the configuration that will be passed to the AssetPickerApp
and options
can contain options for the picker and the modal.
new AssetPicker(config); /* or */ new AssetPicker(config, options);
Feel free to play around with some of the options on the demo page.
config
options
Buttons
Data attributes on the buttons can control what may be picked and what should happen after something was picked.
<button
rel="assetpicker"
data-limit="0"
data-exts="jpeg,jpg,png">Select multiple images</button>
API
The AssetPicker
provides a basic API including some methods and some events.
Methods
Events
The picker provides a simple events API with some events - the listeners will always be bound to the picker instance and receive arguments depending on the event. Register your events as follows:
var picker = new AssetPicker(config); picker.on('pick', function(picked) { console.log(picked, this.element); });
Adapters
Google Drive
The Google Drive adapter utilizes the Google API to retrieve assets from the users drive account, which he will have to pick when he has multiple accounts. For this to work you'll need to register your project on Google API Console and activate the Drive API for it. After that you'll need to create an API key and an OAuth client ID in the credentials area of the project.
Authentication
The Google Drive adapter uses Google Sign-In for Web - this means that your users will have to authenticate with Google and authorize AssetPicker in a pop up window. AssetPicker will then receive a short-lived token to access the API for the user - no further information will be stored by AssetPicker. Thus it will likely occur that AssetPicker will have to reopen this window when the token expired - as pop up blockers will likely block automatic pop ups your users will have to click a button manually to do that until we found a better solution.
Configuration
new AssetPicker({ storages: { drive: { adapter: 'googledrive', // OAuth client id from API console, required client_id: 'xxx', // API key from API console, required api_key: 'xxx', // Google Apps Domain to which users must belong, optional hosted_domain: 'mycompany.com', // Requests to Google APIs are limited and AssetPicker requires some // of them to show the doc tree - use this to force start new requests // at least this amount of milliseconds after the last ones // (defaults for Google Drive adapter is 100), optional http: { throttle: 250 } } } });
GitHub
The GitHub adapter utilizes the GitHub API to provide files and folders in a GitHub repository to AssetPicker. For this to work, you either need an GitHub API token or the user will need a GitHub account.
Authentication
In case you don't provide an API token, the user will be asked for his GitHub credentials. Those credentials will then only be used to create a personal access token which will be stored in his browsers local storage. From then on this personal token will be used for authentication with GitHub. The users login and password won't be stored in any way.
Configuration
new AssetPicker({ storages: { somegithubrepo: { adapter: 'github', // Owner of the repository, required: username: 'netresearch', // The repository name, required: repository: 'assetpicker' } }, github: { // Token for authentication with GitHub API, optional (see above): token: '29782sdwhd2eu2e823jdjhw9832ijs92' } });
EnterMediaDB
The EnterMediaDB adapter utilizes the EnterMediaDB API to provide categories and assets to AssetPicker.
Authentication
Authentication with EnterMediaDB API is session based and requires the user to provide his credentials to authenticate with the API. Thus you have to make sure, that the users using AssetPicker have the permissions to use the API inside EnterMediaDB.
Configuration
EnterMediaDB currently doesn't provide CORS support and thus, if AssetPicker is served from a different host, protocol or port than EnterMediaDB, you'll likely need a proxy.
new AssetPicker({ storages: { somegithubrepo: { adapter: 'entermediadb', // URL to the catalogue, required: url: 'http://em9.entermediadb.org/openinstitute', // Proxy is likely required proxy: true } } });
Register your own adapter
Adapters are actually vue components which's template will be rendered in the navigation bar. Loading of items is completely controlled by events. Have a look at the existing adapters to see details.
The standard way to do this, is to create a standalone script, that contains the adapter and reference it in the config. The script is required as standalone because it won't be loaded in the same window as where the picker is included but from an iframe.
The following example shows a basic adapter, loading a hierarchical structure from an endpoint:
https://myapp.example.com/myadapter.js
AssetPickerAdapterMine = { events: { 'load-items': function(tree) { this.http.get(this.config.url + '/files/' + (tree.item ? tree.item.id : '')).then( function(response) { tree.items = response.data.map(this.createItem); } ); } } }
https://myapp.example.com/index.html (where the picker is included)
new AssetPicker({ storages: { mystorage: { adapter: 'mine', url: 'https://example.com' } }, adapters: { mine: 'https://myapp.example.com/myadapter.js' } });
Also you can add custom adapters when you have installed the App with npm - see below for an example.
Customize the app
Apart from simply forking this repository, you can also include the app into your project. For this you'll need a npm app built with browserify to customize the app. AssetPickerApp is using [Vue.js] - so you might consider reading it's docs before.
-
Initialize the app
npm init npm install --save assetpicker
-
Customize the AssertPickerApp or it's compontents
src/app.js:
var Storage = require('assetpicker/src/js/app/components/storage'); Storage.components.myadapter = require('./myadapter'); var config = require('assetpicker/src/js/app/config'); config.storages = { myadapterstorage: { adapter: 'myadapter', label: 'My Adapter' // ... options for myadapter } } module.exports = require('assetpicker/src/js/app');
-
Build an HTML page for the app:
app.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>AssetPicker</title> <link rel="stylesheet" href="node_modules/assetpicker/dist/css/main.css" </head> <body> <div id="app"></div> <script src="dist/js/app.js"></script> <script> new AssetPickerApp({el: '#app'}); </script> </body> </html>
-
Build a HTML page to which the picker should be included:
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>AssetPicker</title> </head> <body> <script src="node_modules/assetpicker/dist/js/picker.js"></script> <script> new AssetPicker(null, { modal: { src: 'app.html' } }); </script> <button rel="assetpicker">Pick an asset</button> </body> </html>
-
Setup gulp or any other build tool
npm install -g gulp npm install -S browserify vinyl-source-stream
gulp.js
var gulp = require('gulp'); var browserify = require('browserify'); var source = require('vinyl-source-stream'); gulp.task('js', function () { var b = browserify({ entries: './src/app.js', standalone: 'AssetPickerApp', debug: true }); return b.bundle() .pipe(source('app.js')) .pipe(gulp.dest('./dist/js/')); });
gulp js
Roadmap
- Adapters
- Amazon S3
- Dropbox
- Google Drive
- IE compatibility
- Reauthentication without user interaction required
- github:
- Two Factor Auth
- Branch selector
- Deal with submodules and symlinks
- Management features like upload, renaming, moving etc.