npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

active_storage_drag_and_drop

v0.4.1

Published

Attach cloud and local files in Rails applications

Downloads

160

Readme

Active Storage Drag and Drop

Gem Version Build Status Test Coverage Maintainability Yard Docs JavaScript Style Guide

Provides a form helper to make it easy to make drag and drop file upload fields that work with Rails' ActiveStorage.

Demo

Table of Contents

Installation

Add this line to your application's Gemfile:

gem 'active_storage_drag_and_drop'

And then execute:

$ bundle

Or install it yourself as:

$ gem install active_storage_drag_and_drop

Include the styles in your application css:

/*
 *= require active_storage_drag_and_drop
 */

Asset Pipeline - Rails < 6

Include active_stroage_drag_and_drop.js in your application's JavaScript bundle.

//= require active_storage_drag_and_drop

Webpacker - Rails >= 6

Use yarn to add the js package as a dependency:

$ yarn add active_storage_drag_and_drop

Import the start function from the bundle and run it:

import ActiveStorageDragAndDrop from 'active_storage_drag_and_drop'

ActiveStorageDragAndDrop.start()

Usage

Add an ActiveStorage attachment to your model:

class Message < ApplicationRecord
  has_one_attached :image
end

or add multiple ActiveStorage attachments to your model:

class Message < ApplicationRecord
  has_many_attached :images
end

Call the method drag_and_drop_file_field on your model's form:

= form_with model: @message, local: true do |form|
  = form.drag_and_drop_file_field :images
  = form.submit

The first parameter is a symbol representing the method of the ActiveStorage attachment and an optional second parameter sets the text on the drag and drop zone.

form.drag_and_drop_file_field :images, 'Drag and drop images here!'

The content of the dropzone can also be passed as a block of ERB or HAML:

= form.drag_and_drop_file_field :images, disabled: false do
  %i.far.fa-images
  Drag images here!

Strong Parameters

In your controller you can permit the params like so:

# single file upload
params.permit(:message).require(:image)
# multiple upload
params.permit(:message).require(images: [])

Options

Options for the nested file field can be passed as key value pairs. The helper accepts the same options as the rails file_field form helper ActionView::Helpers::FormHelper#file_field

form.drag_and_drop_file_field :images, nil, disabled: true

Validation

Like with the ActionView::Helpers::FormHelper#file_field you can pass a list of acceptable mime-types for client-side validation:

form.drag_and_drop_file_field :images, nil, accept: 'image/png, image/jpeg, image/gif, image/tiff'

An additional size_limit option can be passed which provides validation on the maximum acceptable filesize in bytes:

form.drag_and_drop_file_field :images, nil, size_limit: 5_000_000 # 5MB upper limit on file size

When one of these errors occurs by default a JavaScript 'dnd-upload:error' event is dispatched and an alert detailing the validation error appears. To override this default behaviour listen for the event and call preventDefault() on the event.

JavaScript Events

| Event name | Event target | Event data (event.detail) | Description | | --- | --- | --- | --- | | dnd-uploads:start | <form> | None | All of the uploads begin either by submission of the form or a call to processUploadQueue() | | dnd-upload:initialize | <input> | { id, file, iconContainer } | Dispatched for every file before the UI elements representing the file are added to the dropzone, default can be prevented to add your own UI. | | dnd-upload:placeholder | <input> | { id, file, iconContainer } | Paints the UI for each file that has been queued for attachment but hasn't been attached yet (e.g. after a failed validation in the form) can be prevented as above. | | dnd-upload:start | <input> | { id, file, iconContainer } | An upload is starting. | | dnd-upload:before-blob-request | <input> | { id, file, iconContainer, xhr } | Before making a request to your application for upload metadata. | | dnd-upload:before-storage-request | <input> | { id, file, iconContainer, xhr } | Before making a request to store a file. | | dnd-upload:progress | <input> | { id, file, iconContainer, progress } | Called as requests to store files progress. Default UI sets the width of the direct-upload__progress element. | | dnd-upload:cancel | <input> | { id, file, iconContainer } | A user triggered the cancelation of an upload, the upload is removed from the queue and the preventable default UI removes matching upload icons from the iconContainer. | | dnd-upload:error | <input> | { id, file, iconContainer, error } | An error occurred pertaining to a specific file. The default can be prevented to supply your own UI for errors. | | dnd-upload:end | <input> | { id, file, iconContainer } | An upload has ended. Default can be prevented to supply your own UI for the end of an upload. | | dnd-uploads:error | <form> | { error } | An error occurred unrelated to a specific file. The default can be prevented to supply your own UI for errors. | | dnd-uploads:end | <form> | None | All uploads have ended. |

To override the default behaviour of any of these events catch them with an event listener and call preventDefault() on the event:

document.addEventListener('dnd-upload:error', function (event) {
  # do something…
  event.preventDefault()
})

Upload Asynchronously

To asynchronously trigger uploading without form submission, import the processUploadQueue function and pass the form containing the uploads and a callback function as arguments:

import { processUploadQueue } from 'active_storage_drag_and_drop'

var callback = function(error) {
  if (error) {
    // …handle error…
  } else {
    // …do your stuff
  }
}

processUploadQueue(form, callback)

Custom Upload Icons

To customise how the upload icons for each file are added to the DOM you pass an iconPainter option to the start function e.g:

import { start } from 'active_storage_drag_and_drop'

start({
  iconPainter (iconContainer, id, file, complete) {
    iconContainer.insertAdjacentHTML('beforeend', `
    <li data-direct-upload-id="${id}" class="direct-upload">
      <div class="direct-upload__progress" style="width: ${progress}"></div>
      ${file.name}
      <button class="direct-upload__remove">X</button>
    </li>
    `)
  }
})

The arguments that iconPainter receives are: | Parameter | Type | Description | | --- | --- | --- | | iconContainer | HTMLElement | The element to insert the upload icon markup into. | | id | string | A unique identifier which will be used for any future UI events on this upload. | | file | File | The object representing the file and its metadata. | | complete | boolean | Is true if the upload is finished and false otherwise. | This is the default implementation:

export function paintDefaultUploadIcon (iconContainer, id, file, complete) {
  const uploadStatus = (complete ? 'complete' : 'pending')
  const progress = (complete ? 100 : 0)
  iconContainer.insertAdjacentHTML('beforeend', `
  <div data-direct-upload-id="${id}">
    <div class="direct-upload direct-upload--${uploadStatus}">
      <div class="direct-upload__progress" style="width: ${progress}%"></div>
      <span class="direct-upload__filename">${file.name}</span>
      <span class="direct-upload__filesize">${fileSizeSI(file.size)}</span>
    </div>
    <a href='remove' class='direct-upload__remove'>X</a>
  </div>
  `)
}

All of the built in UI that manipulates these icons can be overriden by attaching to their event and preventing the default behaviour. But to take advantage of the built in ui events though you should follow these rules:

  • The root level element must have a data-direct-upload-id attribute set to the id passed to paintUploadIcon.
  • The progress section consists of a parent with the class direct-upload and a direct child with the class direct-upload__progress.
  • The element that will cancel the upload when clicked has the class direct-upload__remove.

Development

Install yarn to manage js dependencies. After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Use yarn dev to build JavaScript files automatically on change. Use with gem 'active_storage_drag_and_drop', path: [local-gem-repo] to develop and debug the gem in place in a rails app. You can run the JS tests with yarn test and you can see the coverage as well as the tests by running yarn cover.

After making changes to JavaScript run yarn build before committing changes to transpile the JavaScript for production.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/marinosoftware/active_storage_drag_and_drop. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the ActiveStorageDragAndDrop project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.