Docs
- Getting Started
- SME Uploader
- Companion
- List of Plugins
- Common Plugin Options
- Custom Stores
- Locale Packs
UI Elements
Sources
- Drag & Drop
- File Input
- Webcam
- Provider Plugins
- ⓒ Dropbox
- ⓒ Google Drive
- ⓒ OneDrive
- ⓒ Zoom
- ⓒ Import From URL
Destinations
File Processing
- Image Editor
- Robodog Introduction
- Robodog File Picker
- Robodog Form
- Robodog Upload
- Robodog Dashboard
- Transloadit
Miscellaneous
Contributing
SME Uploader
This is the core module that orchestrates everything in SME Uploader, managing state and events and providing methods.
const SmeUploader = require('@sme-uploader/core'); const uploader = new SmeUploader(); |
Installation
Install from NPM:
npm install @sme-uploader/core |
In the CDN package, it is available on the SmeUploader
global object:
const Core = SmeUploader.Core; |
TypeScript
When using TypeScript, SME Uploader supports a strict typechecking mode. This mode typechecks the options passed in to plugins. This will be the only mode in SME Uploader 2.0, but is currently optional to preserve backwards compatibility. The strict mode can be enabled by passing a special generic type parameter to the SME Uploader constructor:
import SmeUploader = require('@sme-uploader/core') import Tus = require('@sme-uploader/tus') const uploader = SmeUploader<SmeUploader.StrictTypes>() uploader.use(Tus, { invalidOption: null // this will now make the compilation fail! }) |
If you are storing SME Uploader instances in your code, for example in a property on a React or Angular component class, make sure to add the StrictTypes
flag there as well:
class MyComponent extends React.Component { private uploader: SmeUploader<SmeUploader.StrictTypes> } |
In SME Uploader 2.0, this generic parameter will be removed, and your plugin options will always be type-checked.
Options
The SME Uploader core module has the following configurable options:
const uploader = new SmeUploader({ id: 'sme-uploader', autoProceed: false, allowMultipleUploads: true, debug: false, restrictions: { maxFileSize: null, minFileSize: null, maxNumberOfFiles: null, minNumberOfFiles: null, allowedFileTypes: null }, meta: {}, onBeforeFileAdded: (currentFile, files) => currentFile, onBeforeUpload: (files) => {}, locale: {}, store: new DefaultStore(), logger: justErrorsLogger }); |
id: 'sme-uploader'
A site-wide unique ID for the instance.
If multiple SME Uploader instances are being used, for instance, on two different pages, an id
should be specified. This allows SME Uploader to store information in localStorage
without colliding with other SME Uploader instances.
Note that this ID should be persistent across page reloads and navigation — it shouldn’t be a random number that is different every time SME Uploader is loaded.
For example, if one SME Uploader instance is used to upload user avatars, and another to add photos to a blog post, you might use:
const avatarSmeUploader = new SmeUploader({ id: 'avatar' }); const photoSmeUploader = new SmeUploader({ id: 'post' }); |
autoProceed: false
By default SME Uploader will wait for an upload button to be pressed in the UI, or an .upload()
method to be called, before starting an upload. Setting this to autoProceed: true
will start uploading automatically after the first file is selected.
allowMultipleUploads: true
Whether to allow multiple upload batches. This means multiple calls to .upload()
, or a user adding more files after already uploading some. An upload batch is made up of the files that were added since the previous .upload()
call.
With this option set to true
, users can upload some files, and then add more files and upload those as well. A model use case for this is uploading images to a gallery or adding attachments to an email.
With this option set to false
, users can upload some files, and you can listen for the ‘complete’ event to continue to the next step in your app’s upload flow. A typical use case for this is uploading a new profile picture. If you are integrating with an existing HTML form, this option gives the closest behaviour to a bare <input type="file">
.
logger
An object of methods that are called with debug information from uploader.log
.
Set logger: SmeUploader.debugLogger
to get debug info output to the browser console:
const SmeUploader = require('@sme-uploader/core'); const uploader = new SmeUploader({ logger: SmeUploader.debugLogger }); |
You can also provide your own logger object: it should expose debug
, warn
and error
methods, as shown in the examples below.
Here’s an example of a logger
that does nothing:
const nullLogger = { debug: (...args) => {}, warn: (...args) => {}, error: (...args) => {} }; |
logger: SmeUploader.debugLogger
looks like this:
const debugLogger = { debug: (...args) => { // IE 10 doesn’t support console.debug const debug = console.debug || console.log; debug.call(console, `[SmeUploader] [${getTimeStamp()}]`, ...args); }, warn: (...args) => console.warn(`[SmeUploader] [${getTimeStamp()}]`, ...args), error: (...args) => console.error(`[SmeUploader] [${getTimeStamp()}]`, ...args) }; |
By providing your own logger
, you can send the debug information to a server, choose to log errors only, etc.
restrictions: {}
Optionally, provide rules and conditions to limit the type and/or number of files that can be selected.
Parameters
maxFileSize
null | number — maximum file size in bytes for each individual file (total max size )minFileSize
null | number — minimum file size in bytes for each individual filemaxNumberOfFiles
null | number — total number of files that can be selectedminNumberOfFiles
null | number — minimum number of files that must be selected before the uploadallowedFileTypes
null | array of wildcardsimage/*
, exact mime typesimage/jpeg
, or file extensions.jpg
:['image/*', '.jpg', '.jpeg', '.png', '.gif']
maxNumberOfFiles
also affects the number of files a user is able to select via the system file dialog in UI plugins like DragDrop
, FileInput
and Dashboard
: when set to 1
, they will only be able to select a single file. When null
or another number is provided, they will be able to select multiple files.
allowedFileTypes
gets passed to the system file dialog via <input>
’s accept attribute, so only files matching these types will be selectable.
If you’d like to force a certain meta field data to be entered before the upload, you can:
const uploader = SmeUploader({ onBeforeUpload (files) { for (const [key, file] of Object.entries(files)) { if (!file.meta.caption) { uploaderDashboard.info('File is missing caption', 'error'); throw new Error('File is missing caption'); } } } }); |
If you need to restrict
allowedFileTypes
to a file extension with double dots, like.nii.gz
, you can do so by settingallowedFileTypes
to just the last part of the extension,allowedFileTypes: ['.gz']
, and then usingonBeforeFileAdded
to filter for.nii.gz
:
const uploaderDashboard = SmeUploader({ restrictions: { allowedFileTypes: ['.gz'] }, onBeforeFileAdded: (currentFile) => { const isCorrectExtension = currentFile.name.endsWith('.nii.gz'); if (!isCorrectExtension) { uploaderDashboard.info(uploaderDashboard.i18n('youCanOnlyUploadFileTypes', { types: '.nii.gz' }), 'error', 5000) return false; } else { return true; } } }) .use(Dashboard); |
meta: {}
Metadata object, used for passing things like public keys, usernames, tags and so on:
meta: { username: 'John' } |
This global metadata is added to each file in SME Uploader. It can be modified by two methods:
uploader.setMeta({ username: 'Peter' })
— set or update meta for all files.uploader.setFileMeta('myfileID', { resize: 1500 })
— set or update meta for specific file.
Metadata from each file is then attached to uploads in Tus and XHRUpload plugins.
Metadata can also be added from a <form>
element on your page, through the Form plugin or through the UI if you are using Dashboard with the metaFields
option.
onBeforeFileAdded: (currentFile, files) => currentFile
A function run before a file is added to SME Uploader. It gets passed (currentFile, files)
where currentFile
is a file that is about to be added, and files
is an object with all files that already are in SME Uploader.
Use this function to run any number of custom checks on the selected file, or manipulate it, for instance, by optimizing a file name.
⚠️ Note that this method is intended for quick synchronous checks/modifications only. If you need to do an async API call, or heavy work on a file (like compression or encryption), you should utilize a custom plugin instead.
Return true/nothing or a modified file object to proceed with adding the file:
onBeforeFileAdded: (currentFile, files) => { if (currentFile.name === 'forest-IMG_0616.jpg') { return true } } // or onBeforeFileAdded: (currentFile, files) => { const modifiedFile = { ...currentFile, name: currentFile.name + '__' + Date.now() } return modifiedFile } |
Return false to abort adding the file:
onBeforeFileAdded: (currentFile, files) => { if (!currentFile.type) { // log to console uploader.log(`Skipping file because it has no type`) // show error message to the user uploader.info(`Skipping file because it has no type`, 'error', 500) return false } } |
Note: it is up to you to show a notification to the user about a file not passing validation. We recommend showing a message using uploader.info() and logging to console for debugging purposes via uploader.log().
onBeforeUpload: (files) => files
A function run before an upload begins. Gets passed files
object with all the files that are already in SME Uploader.
Use this to check if all files or their total number match your requirements, or manipulate all the files at once before upload.
⚠️ Note that this method is intended for quick synchronous checks/modifications only. If you need to do an async API call, or heavy work on a file (like compression or encryption), you should utilize a custom plugin instead.
Return true or modified files
object to proceed:
onBeforeUpload: (files) => { // We’ll be careful to return a new object, not mutating the original `files` const updatedFiles = {} Object.keys(files).forEach(fileID => { updatedFiles[fileID] = { ...files[fileID], name: 'myCustomPrefix' + '__' + files[fileID].name } }) return updatedFiles } |
Return false to abort:
onBeforeUpload: (files) => { if (Object.keys(files).length < 2) { // log to console uploader.log(`Aborting upload because only ${Object.keys(files).length} files were selected`) // show error message to the user uploader.info(`You have to select at least 2 files`, 'error', 500) return false } } |
Note: it is up to you to show a notification to the user about a file not passing validation. We recommend showing a message using uploader.info() and logging to console for debugging purposes via uploader.log().
locale: {}
This allows you to override language strings:
locale: { strings: { youCanOnlyUploadX: { 0: 'You can only upload %{smart_count} file', 1: 'You can only upload %{smart_count} files' }, youHaveToAtLeastSelectX: { 0: 'You have to select at least %{smart_count} file', 1: 'You have to select at least %{smart_count} files' }, exceedsSize2: 'This file exceeds maximum allowed size of %{size}', youCanOnlyUploadFileTypes: 'You can only upload: %{types}', companionError: 'Connection with Companion failed' } } |
Instead of overriding strings yourself, consider using one of our language packs (or contributing one!):
const russianLocale = require('@sme-uploader/locales/lib/ru_RU') // ^-- OR: import russianLocale from '@sme-uploader/locales/lib/ru_RU' const uploader = new SmeUploader({ locale: russianLocale, }) |
If you use SME Uploader from a CDN, there’s an example showcasing how to change languages.
For flexibility, you can pass a locale
at the SmeUploader
/core level, or to Plugins individually. The locale strings that you set in core take precedence.
It also offers the pluralization function, which is used to determine which string will be used for the provided smart_count
number.
For example, for the Icelandic language, the pluralization function would be:
locale: { pluralize: (n) => (n % 10 !== 1 || n % 100 === 11) ? 1 : 0 } |
We are using a forked Polyglot.js.
store: defaultStore()
The Store that is used to keep track of internal state. By default, a simple object is used.
This option can be used to plug SME Uploader state into an external state management library, such as Redux. You can then write custom views with the library that is also used by the rest of the application.
File Objects
SME Uploader internally uses file objects that abstract over local files and files from remote providers, and that contain additional data like user-specified metadata and upload progress information.
file.source
Name of the plugin that was responsible for adding this file. Typically a remote provider plugin like 'GoogleDrive'
or a UI plugin like 'DragDrop'
.
file.id
Unique ID for the file.
file.meta
Object containing file metadata. Any file metadata should be JSON-serializable.
file.type
MIME type of the file. This may actually be guessed if a file type was not provided by the user’s browser, so this is a best-effort value and not guaranteed to be accurate.
file.data
For local files, this is the actual File
or Blob
object representing the file contents.
For files that are imported from remote providers, the file data is not available in the browser.
file.progress
An object with upload progress data.
Properties
bytesUploaded
- Number of bytes uploaded so far.bytesTotal
- Number of bytes that must be uploaded in total.uploadStarted
- Null if the upload has not started yet. Once started, this property contains a UNIX timestamp. Note that this is only set after preprocessing.uploadComplete
- Boolean indicating if the upload has completed. Note this does not mean that postprocessing has completed, too.percentage
- Integer percentage between 0 and 100.
file.size
Size in bytes of the file.
file.isRemote
Boolean: is this file imported from a remote provider?
file.remote
Grab bag of data for remote providers. Generally not interesting for end users.
file.preview
An optional URL to a visual thumbnail for the file.
file.uploadURL
When an upload is completed, this may contain a URL to the uploaded file. Depending on server configuration it may not be accessible or accurate.
Methods
uploader.use(plugin, opts)
Add a plugin to SME Uploader, with an optional plugin options object.
const SmeUploader = require('@sme-uploader/core') const DragDrop = require('@sme-uploader/drag-drop') const uploader = new SmeUploader() uploader.use(DragDrop, { target: 'body' }) |
uploader.removePlugin(instance)
Uninstall and remove a plugin.
uploader.getPlugin(id)
Get a plugin by its id
to access its methods.
uploader.getID()
Get the SME Uploader instance ID, see the id
option.
uploader.addFile(fileObject)
Add a new file to SME Uploader’s internal state.
uploader.addFile({ name: 'my-file.jpg', // file name type: 'image/jpeg', // file type data: blob, // file blob meta: { // optional, store the directory path of a file so SME Uploader can tell identical files in different directories apart relativePath: webkitFileSystemEntry.relativePath, }, source: 'Local', // optional, determines the source of the file, for example, Instagram isRemote: false // optional, set to true if actual file is not in the browser, but on some remote server, for example, when using companion in combination with Instagram }) |
addFile
gives an error if the file cannot be added, either because onBeforeFileAdded(file)
gave an error, or because uploader.opts.restrictions
checks failed.
If you try to add a file that already exists, addFile
will throw an error. Unless that duplicate file was dropped with a folder — duplicate files from different folders are allowed, when selected with that folder. This is because we add file.meta.relativePath
to the file.id
.
If uploader.opts.autoProceed === true
, SME Uploader will begin uploading automatically when files are added.
addFile
will return the generated id for the file that was added.
Sometimes you might need to add a remote file to SME Uploader. This can be achieved by fetching the file, then creating a Blob object, or using the Url plugin with Companion.
Sometimes you might need to mark some files as “already uploaded”, so that the user sees them, but they won’t actually be uploaded by SME Uploader. This can be achieved by looping through files and setting
uploadComplete: true, uploadStarted: false
on them:
uploader.getFiles().forEach(file => { uploader.setFileState(file.id, { progress: { uploadComplete: true, uploadStarted: false } }) }) |
uploader.removeFile(fileID)
Remove a file from SME Uploader.
uploader.removeFile('uploaderteamkongjpg1501851828779') |
Removing a file that is already being uploaded cancels that upload.
uploader.getFile(fileID)
Get a specific File Object by its ID.
const file = uploader.getFile('uploaderteamkongjpg1501851828779') file.id // 'uploaderteamkongjpg1501851828779' file.name // 'nature.jpg' file.extension // '.jpg' file.type // 'image/jpeg' file.data // the Blob object file.size // 3947642 (returns 'N/A' if size cannot be determined) file.preview // value that can be used to populate "src" attribute of an "img" tag |
uploader.getFiles()
Get an array of all File Objects that have been added to SME Uploader.
const prettierBytes = require('@sme-uploader/core/src/prettierBytes') const items = uploader.getFiles().map(() => `<li>${file.name} - ${prettierBytes(file.size)}</li>` ).join('') document.querySelector('.file-list').innerHTML = `<ul>${items}</ul>` |
uploader.upload()
Start uploading selected files.
Returns a Promise result
that resolves with an object containing two arrays of uploaded files:
result.successful
- Files that were uploaded successfully.result.failed
- Files that did not upload successfully. These File Objects will have a.error
property describing what went wrong.
uploader.upload().then((result) => { console.info('Successful uploads:', result.successful) if (result.failed.length > 0) { console.error('Errors:') result.failed.forEach((file) => { console.error(file.error) }) } }) |
uploader.pauseResume(fileID)
Toggle pause/resume on an upload. Will only work if resumable upload plugin, such as Tus, is used.
uploader.pauseAll()
Pause all uploads. Will only work if a resumable upload plugin, such as Tus, is used.
uploader.resumeAll()
Resume all uploads. Will only work if resumable upload plugin, such as Tus, is used.
uploader.retryUpload(fileID)
Retry an upload (after an error, for example).
uploader.retryAll()
Retry all uploads (after an error, for example).
uploader.cancelAll()
Cancel all uploads, reset progress and remove all files.
uploader.setState(patch)
Update SME Uploader’s internal state. Usually, this method is called internally, but in some cases it might be useful to alter something directly, especially when implementing your own plugins.
SME Uploader’s default state on initialization:
{ plugins: {}, files: {}, currentUploads: {}, capabilities: { resumableUploads: false }, totalProgress: 0, meta: Object.assign({}, this.opts.meta), info: { isHidden: true, type: 'info', message: '' } } |
Updating state:
uploader.setState({ smth: true }) |
State in SME Uploader is considered to be immutable. When updating values, it is your responsibility to not mutate them, but instead create copies. See Redux docs for more info on this. Here is an example from SME Uploader.Core that updates progress for a particular file in state:
// We use Object.assign({}, obj) to create a copy of `obj`. const updatedFiles = Object.assign({}, uploader.getState().files) // We use Object.assign({}, obj, update) to create an altered copy of `obj`. const updatedFile = Object.assign({}, updatedFiles[fileID], { progress: Object.assign({}, updatedFiles[fileID].progress, { bytesUploaded: data.bytesUploaded, bytesTotal: data.bytesTotal, percentage: Math.floor((data.bytesUploaded / data.bytesTotal * 100).toFixed(2)) }) }) updatedFiles[data.id] = updatedFile uploader.setState({files: updatedFiles}) |
uploader.getState()
Returns the current state from the Store.
uploader.setFileState(fileID, state)
Update the state for a single file. This is mostly useful for plugins that may want to store data on File Objects, or that need to pass file-specific configurations to other plugins that support it.
fileID
is the string file ID. state
is an object that will be merged into the file’s state object.
uploader.getPlugin('Url').addFile('path/to/remote-file.jpg') |
uploader.setMeta(data)
Alters global meta
object in state, the one that can be set in SME Uploader options and gets merged with all newly added files. Calling setMeta
will also merge newly added meta data with previously selected files.
uploader.setMeta({ resize: 1500, token: 'ab5kjfg' }) |
uploader.setFileMeta(fileID, data)
Update metadata for a specific file.
uploader.setFileMeta('myfileID', { resize: 1500 }) |
uploader.setOptions(opts)
Change SME Uploader options on the fly. For example, to conditionally change restrictions.allowedFileTypes
or locale
:
const uploader = new SmeUploader() uploader.setOptions({ restrictions: { maxNumberOfFiles: 3 }, autoProceed: true }) uploader.setOptions({ locale: { strings: { 'cancel': 'Отмена' } } }) |
You can also change options for plugin on the fly, like this:
// Change width of the Dashboard drag-and-drop aread on the fly uploader.getPlugin('Dashboard').setOptions({ width: 300 }) |
uploader.reset()
Stop all uploads in progress and clear file selection, set progress to 0. Basically, return things to the way they were before any user input.
uploader.close()
Uninstall all plugins and close down this SME Uploader instance. Also runs uploader.reset()
before uninstalling.
uploader.log()
Parameters
- message {string}
- type {string=}
error
orwarning
Logs stuff to logger
methods.
See logger
docs for details.
uploader.log('[Dashboard] adding files...') |
uploader.info()
Parameters
- message {(string|object)} —
'info message'
or{ message: 'Oh no!', details: 'File couldn’t be uploaded' }
- type {string} [type=’info’] —
info
,warning
,success
orerror
- duration {number} [duration = 3000] — in milliseconds
Sets a message in state, with optional details, that can be shown by notification UI plugins. Currently, that means just the Informer plugin, included by default in Dashboard.
this.info('Oh my, something good happened!', 'success', 3000) |
this.info({ message: 'Oh no, something bad happened!', details: 'File couldn’t be uploaded because there is no internet connection', }, 'error', 5000) |
info-visible
and info-hidden
events are emitted when this info message should be visible or hidden.
uploader.on('event', action)
Subscribe to an uploader-event. See below for the full list of events.
uploader.off('event', action)
Unsubscribe to an uploader-event. See below for the full list of events.
Events
SME Uploader exposes events that you can subscribe to in your app:
file-added
Fired each time a file is added.
Parameters
file
- The File Object representing the file that was added.
uploader.on('file-added', (file) => { console.log('Added file', file) }) |
file-removed
Fired each time a file is removed.
Parameters
file
- The File Object representing the file that was removed.reason
- A string explaining why the file was removed. Current reasons are:removed-by-user
andcancel-all
.
Example
uploader.on('file-removed', (file, reason) => { console.log('Removed file', file) }) |
uploader.on('file-removed', (file, reason) => { removeFileFromUploadingCounterUI(file) if (reason === 'removed-by-user') { sendDeleteRequestForFile(file) } }) |
upload
Fired when upload starts.
uploader.on('upload', (data) => { // data object consists of `id` with upload ID and `fileIDs` array // with file IDs in current upload // data: { id, fileIDs } console.log(`Starting upload ${id} for files ${fileIDs}`) }) |
upload-progress
Fired each time file upload progress is available:
Parameters
file
- The File Object for the file whose upload has progressed.progress
- Progress object.
Example
uploader.on('upload-progress', (file, progress) => { // file: { id, name, type, ... } // progress: { uploader, bytesUploaded, bytesTotal } console.log(file.id, progress.bytesUploaded, progress.bytesTotal) }) |
upload-success
Fired each time a single upload is completed.
Parameters
file
- The File Object that has just been fully uploaded.response
- An object with response data from the remote endpoint. The actual contents depend on the uploader plugin that is used.For
@sme-uploader/xhr-upload
, the shape is:{ status, // HTTP status code (0, 200, 300) body, // response body uploadURL // the file url, if it was returned }
Example
uploader.on('upload-success', (file, response) => { console.log(file.name, response.uploadURL) var img = new Image() img.width = 300 img.alt = file.id img.src = response.uploadURL document.body.appendChild(img) }) |
complete
Fired when all uploads are complete.
The result
parameter is an object with arrays of successful
and failed
files, just like in uploader.upload()
’s return value.
uploader.on('complete', (result) => { console.log('successful files:', result.successful) console.log('failed files:', result.failed) }) |
error
Fired when SME Uploader fails to upload/encode the entire upload. That error is then set to uploader.getState().error
.
Parameters
error
- The error object.
Example
uploader.on('error', (error) => { console.error(error.stack) }) |
upload-error
Fired each time a single upload has errored.
Parameters
file
- The File Object for the file whose upload has just errored.error
- The error object.response
- an optional parameter with response data from the upload endpoint. It may be undefined or contain different data depending on the uploader plugin in use.For
@sme-uploader/xhr-upload
, the shape is:{ status, // HTTP status code (0, 200, 300) body // response body }
Example
uploader.on('upload-error', (file, error, response) => { console.log('error with file:', file.id) console.log('error message:', error) }) |
If the error is related to network conditions — endpoint unreachable due to firewall or ISP blockage, for instance — the error will have error.isNetworkError
property set to true
. Here’s how you can check for network errors:
uploader.on('upload-error', (file, error, response) => { if (error.isNetworkError) { // Let your users know that file upload could have failed // due to firewall or ISP issues alertUserAboutPossibleFirewallOrISPIssues(error) } }) |
upload-retry
Fired when an upload has been retried (after an error, for example).
Parameters
fileID
- ID of the file that is being retried.
Example
uploader.on('upload-retry', (fileID) => { console.log('upload retried:', fileID) }) |
info-visible
Fired when “info” message should be visible in the UI. By default, Informer
plugin is displaying these messages (enabled by default in Dashboard
plugin). You can use this event to show messages in your custom UI:
uploader.on('info-visible', () => { const info = uploader.getState().info // info: { // isHidden: false, // type: 'error', // message: 'Failed to upload', // details: 'Error description' // } alert(`${info.message} ${info.details}`) }) |
info-hidden
Fired when “info” message should be hidden in the UI. See info-visible
.
cancel-all
Fired when uploader.cancelAll()
is called, all uploads are canceled, files removed and progress is reset.
restriction-failed
Fired when a file violates certain restrictions when added. This event is just providing another choice for those who want to customize the behavior of file upload restrictions.
uploader.on('restriction-failed', (file, error) => { // do some customized logic like showing system notice to users }) |
reset-progress
Fired when uploader.resetProgress()
is called, each file has its upload progress reset to zero.
uploader.on('reset-progress', () => { // progress was reset }) |