Thanks to visit codestin.com
Credit goes to github.com

Skip to content

LEFapps/uploader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UPLOADER

This react Component is an interface for uploading files. This component does not handle the upload itself, you should use your own upload logic like edgee:slingshot for Meteor apps.

This Component does support selecting files, previewing them and add metadata.

For images, auto-rotating, resizing and cropping is possible client side. (Note that this depends on the browser used by the client!)

Install

Install from npm:

$ npm install @lefapps/uploader --save

Usage

import React from 'react'
import Uploader, { Preview } from '@lefapps/uploader'

const FormComponent = ({ onChange }) => {
  const config = {
    // config of thumbnails for images
    sizes: [
      {
        label: 'banner-sm',
        width: 1280,
        height: 240,
        crop: true,
        retina: true,
        quality: 60
      }
    ],
    // logic to handle your file upload
    // e.g. Edgee Slingshot directive
    uploader: { send: (file, callback = (error, url) => {}) => {} }
  }
  return <Uploader {...config} onChange={onChange}>
}

Uploader

The Uploader renders the file input, together with selected files while they are being processed. After processing, they are passed to the onChange handler. It is up to you to display these files by using the Preview component, which can be passed as children to the Uploader.

class Form extends React.Component {
  render () {
    const bindInput = {
      onChange: value => this.setState(({ values }) =>
        ({ values: values.concat(value) })
      )
    }
    return
      <Uploader {...bindInput}>
        {this.state.values.map((value, index) =>
          <Preview {...value} key={index} />
        )}
      </Uploader>
  }
}

Preview

The Preview component is exposed to make it possible to render the already uploaded files consistent with the files being processed. It also accepts children where you can add functionality like sorting and removing.

<Preview url={} name={}>
  <Button onClick={remove}>x</Button>
</Preview>

The Uploader

Configuration

Prop Type Required
Default
Description
label String
Component
Label to display above the file input
placeholder String Label to display inside the file input
name String Name attribute of the file input element
multiple Bool false Allow multiple files to be selected for upload
uploader Object
Class
Logic to send the file to your storage of choice
See below for specific information. Works seamlessly with edgee:slingshot directives.
sizes [Object] Thumbnail configuration for image files
invalid Bool Whether the input is valid or not
id String Id attribute for DOM reference
className String Class attribute for custom styling
metaData Object Optional metadata to add to the file

Upload handler class

You should provide the upload handler yourself. It should have at least a method send which accepts the file and a callback. The callback expects error and result as arguments.

class UploadHandler {
  send (file, callback) {
    // ... send file to cloud storage
    if (error) callback(error)
    else callback(null, url)
  }
}

If you use a Meteor application, you can use edgee:slingshot.

import Uploader, { Preview } from '@lefapps/uploader'
import { Slingshot } from 'meteor/edgee:slingshot'

<Uploader {...props} uploader={new Slingshot.Upload('files')}>

Check edgee:slingshot documentation on how to set up directives.

Thumbnails

When you use the uploader to upload images, you can make this component to attempt creating thumbnails client-side. you can specify them through the sizes prop.

Key Type Required
Default
Description
label String Prefix for this thumbnail, easy to reference later
E.g. square-sm, banner-lg, …
width Integer Width of thumbnail
height Integer Height of thumbnail
crop Bool false Whether the image should be cropped or resized
If crop isn't true, width and height act as maximal dimensions; one edge of the thumbnail will be smaller to fit within specified size.
quality Number 60 Image quality between .25 and 1 or 25 and 100 %
Numbers greater than 100 set the quality to maximum (100 %).
retina Bool false Create a retina version of the current thumbnail
Size: double; Quality: 80 % of set quality.

The label of the size props will be used as a prefix for the uploaded thumbnail. The above examples will be stored as follows: https://your.cdn/uploader/square-sm/filename.jpeg

OnChange handler

After a succesful upload, the file is passed to the onChange handler on the component. This "file" is actually an object with various properties which you can use to your own liking.

Note: when the attribute multiple is set on the uploader, the onChange handler is called for every file.

Key Type Description
name String Unique filename for all uploaded files
url String success from the send callback, most likely the full url to the uploaded original
local Blob use this to display the image in the preview to prevent bandwidth usage by downloading the uploaded file from url immediately after upload. Note: do not save this value in your database.
isImage Bool Whether the uploaded file was seen as an image
error String If an error occured during the process, it will appear here

Image processing

When images are selected, the uploader performs the following actions:

  1. Auto rotate the image JPEGs can have 8 rotations. When such an image is displayed on a webpage, the orientation is not always corrected. This is handled by the uploader before uploading or generating thumbnails. This auto rotation is always performed.
  2. Generate thumbnails Based on your configuration, the requested thumbnails are created in browser using html canvas. If the user’s browser does not support the canvas element, no thumbnails are generated.
  3. Upload Originals and thumbnails are uploaded sequentially.
  4. Call onChange handler The handler is called once per selected image after a successful upload of the original and its thumbnails.

Example: a user selects 4 images and a pdf. The configuration requests 2 thumbnails per image.

  1. The four images are rotated if necessary.
  2. The 4 × 2 thumbnails are generated.
  3. 1 pdf, 4 original images and 8 thumbnails are uploaded.
  4. The handler is called 5 times. If n uploads fail, the handler is called 5 - n times.

The Preview

Simple usage: if you pass the onChange argument as ...props to the Preview component, it will be displayed fine.

Configuration

Prop Type Required
Default
Description
name String '' Name of the file
url String '' Url of preview (image)
If no preview is available, the file type will be shown instead.
local String '' Urlstring of the local image, overrides url if present
error String '' Display an error message instead of the preview
children Component Extend preview functionality to remove, sort, …
extras Component Optional children below the filename
Use this prop to add e.g. alt-tag and/or copyright information after upload.

Children

Example of sorting and removing:

class FormComponent extends React.Component {
  _getValue () {
    const { bindInput, element } = this.props
    return bindInput(element.name) // see @lefapps/forms
  }
  _modifyModel (action, { index, model, direction }) {
    let { name, value, onChange, multiple } = this._getValue()
    switch (action) {
      case 'create':
        multiple ? value.splice(value.length, 0, model) : (value = model)
        break
      case 'update':
        multiple ? value.splice(index, 1, model) : (value = model)
        break
      case 'delete':
        if (confirm('Are you sure you want to delete this file?')) {
          multiple ? value.splice(index, 1) : (value = undefined)
        }
        break
      case 'move':
        if (multiple) {
          value.splice(index, 1)
          value.splice(index + direction, 0, model)
        }
        break
    }
    this.setState({ value })
    return value
  }
  move = (index, direction) => {
    const model = this._getValue().value[index]
    this._modifyModel('move', { index, direction, model })
  }
  remove = index => {
    this._modifyModel('delete', { index })
  }
  canMove = (index, direction) => {
    const { value, multiple } = this.props.bindInput(this.props.element.name)
    return (
      multiple &&
      ((direction > 0 && index < value.length - 1) ||
        (direction < 0 && index > 0))
    )
  }
  render() {
    return
      <Uploader onChange={model => this._modifyModel('create', { model })} {...config}>
        {this.state.values.map((value, index) =>
          <Preview key={index} {...value}>
            <ButtonGroup>
              <Button onClick={() => this.move(index, -1)} disabled={!this.canMove(index, -1)}></Button>
              <Button onClick={() => this.move(index, 1)} disabled={!this.canMove(index, 1)} ></Button>
              <Button onClick={() => this.remove(index)}></Button>
            </ButtonGroup>
          </Preview>
        )}
      </Uploader>
  }
}

Extras

If you want even more options, you can an extra set of children to display below the filename.

Example of an alt-tag field:

class FormComponent extends React.Component {
  _getValue () {
    const { bindInput, element } = this.props
    return bindInput(element.name) // see @lefapps/forms
  }
  _modifyModel (action, { index, model, direction }) {
    let { name, value, onChange, multiple } = this._getValue()
    switch (action) {
      case 'create':
        multiple ? value.splice(value.length, 0, model) : (value = model)
        break
      case 'update':
        multiple ? value.splice(index, 1, model) : (value = model)
        break
      case 'delete':
        if (confirm('Are you sure you want to delete this file?')) {
          multiple ? value.splice(index, 1) : (value = undefined)
        }
        break
      case 'move':
        if (multiple) {
          value.splice(index, 1)
          value.splice(index + direction, 0, model)
        }
        break
    }
    this.setState({ value })
    return value
  }
  metaFields (isImage) {
    return isImage ? [{ name: 'alt', type: 'text' }] : []
  }
  metaFieldBuilder (value, index) {
    return ({ name, type }, key) => (
      <Input
        key={key}
        type={type}
        defaultValue={value[name]}
        placeholder={name}
        onChange={({ target }) =>
          this._modifyModel('update', {
            index,
            model: Object.assign(value, {
              [name]: target.value
            })
          })
        }
      />
    )
  }
  render () {
    return
      <Uploader
        onChange={model => this._modifyModel('create', { model })}
        {...config}
      >
        {values.map((value, index) =>
          <Preview
            {...value}
            key={index}
            extras={this.metaFields(value.isImage).map(this.metaFieldBuilder(value, index))}
          />
        )}
      </Uploader>
  }
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •