assetpicker
v1.3.4
Published
A free asset or file picker with abstraction layer allowing several adapters like GitHub, EnterMediaDB, Amazon S3, Google Drive, Dropbox etc.
Downloads
18
Readme
AssetPicker
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
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.3/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
key | type | default | description
--- | --- | --- | ---
title | string | "AssetPicker"
| The title that will be shown in the navigation header
storages | object | - | The storages that should be available, each entry must be an object, which will be passed to the storage adapter
storages.xyz.adapter | string | - | Required: name of the adapter to use (currently github
and entermediadb
possible)
storages.xyz.label | string | key of storage | Optional: Label for the storage in navigation bar and search results
storages.xyz.proxy | bool|object | - | Controls proxy configuration for this storage (true: Use proxy with global configuration, false: disable the proxy - even when enabled for all storages, object: Use proxy with custom configuration)
proxy | object | {} | Global proxy configuration
proxy.url | string | "proxy.php?to={{url}}"
| Url to the proxy - the string is interpolated by vue, so you can use filters and JS expressions. Use {{url}}
for a urlencoded version of the target url and {{url.raw}}
for the unencoded target url. The default value resolves to the included PHP proxy (which's dependencies must be installed with composer install before you can use it)
proxy.all | bool | false
| Whether to enable the proxy for all storages (unless they disable it)
language | string | "auto"
| Language for the interface - use "auto" to detect the language from the browser. Possible languages are de
and en
for now.
debug | boolean | false
| En-/disables Vue.config.debug
github.token | string | - | Optional token for the GitHub adapter
picker | object | {} | Default configuration to control what can be picked - overriden by buttons attributes
picker.limit | number | 1
| Maximum of assets that can be picked (0 for unlimited)
picker.types | array | ['file']
| Asset types allowed to be picked
picker.extensions | array | []
| File extensions allowed to be picked (empty means all)
adapters | object | see here | Sources of the possible adapters - here you can register your own adapters
adapters.xyz.src | string | - | Required: The URL to the adapter script - relative to the app script (a leading / loads it relative from the modal src origin, use an absolute URL if the adapter source is not on the same origin as the app script or html file)
adapers.xyz.name | string | - | Required: Name of adapter object in global scope
thumbnails | string | "url"
| Way to deliver thumbnails in the resulting asset objects: "url" for the url, "data" for the data-uri (helpfull, when AssetPicker uses the proxy and your page doesn't)
options
key | type | default | description
--- | --- | --- | ---
selector | string | '[rel="assetpicker"]'
| CSS selector for the buttons you want to act as picker
distUrl | string | url of the picker script popped by two path parts (f.e. http://example.com/dist when picker script url is http://example.com/dist/js/picker.js) | Base URL of the AssetPicker dist directory
modal | object | {} | Options for the modal
modal.src | string | distUrl + '/index.html'
| URL to the AssetPicker application
modal.template | string | see here | Template for the modal - requires an outer div with an iframe somewhere nested
modal.css | string | see here | CSS injected before any other CSS into head
modal.openClassName | string | 'assetpicker-modal-open'
| Class to add/remove to the modal template outer div on opening/closing
ui.enabled | bool | true
| Whether to show a user interface for the selected assets
ui.readonly | bool | false
| Whether to show add and delete buttons on the user interface
ui.unique | bool | true
| Whether the UI should filter out duplicate assets after selection
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>
attribute | description
--- | ---
data-limit | Number of elements allowed to be picked (0 for no limit) - overrides config.picker.limit
data-exts | Comma separated list of file extensions allowed to be picked (empty for any) - overrides config.picker.extensions
data-types | Comma separated list of element types allowed to be picked (currently dir
, file
and category
are supported by the adapters) - overrides config.picker.extensions
data-ui | Overrides options.ui.enabled
(<button ... data-ui>
or <button ... data-ui="false">
)
data-ro | Overrides options.ui.readonly
(<button ... data-ro>
or <button ... data-ro="false">
)
data-unique | Overrides options.ui.readonly
(<button ... data-unique>
or <button ... data-unique="false">
)
API
The AssetPicker
provides a basic API including some methods and some events.
Methods
method | description
--- | ---
on(String event, Function listener)
| Register an event listener on an event
register(DomElement element)
| Register an element as AssetPicker button (will get the click event added).
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);
});
event | description --- | --- pick | Triggered after assets were picked (and the picker was closed). Listeners receive the picked assets as first argument (single asset when limit is 1 or array of assets otherwise) ready | Triggered when the picker application was loaded resize | Triggered when user minimizes or maximizes the application window
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.