active_storage_drag_and_drop 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_storage_drag_and_drop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave O'Keeffe
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2019-01-29 00:00:00.000000000 Z
12
+ date: 2019-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bootsnap
@@ -283,14 +283,14 @@ dependencies:
283
283
  requirements:
284
284
  - - "~>"
285
285
  - !ruby/object:Gem::Version
286
- version: '5.2'
286
+ version: 5.2.2.1
287
287
  type: :runtime
288
288
  prerelease: false
289
289
  version_requirements: !ruby/object:Gem::Requirement
290
290
  requirements:
291
291
  - - "~>"
292
292
  - !ruby/object:Gem::Version
293
- version: '5.2'
293
+ version: 5.2.2.1
294
294
  description: Provides a form helper to make it easy to make drag and drop file upload
295
295
  fields that work with Rails' Active Storage.
296
296
  email:
@@ -299,9 +299,11 @@ executables: []
299
299
  extensions: []
300
300
  extra_rdoc_files: []
301
301
  files:
302
+ - ".babelrc"
302
303
  - ".codeclimate.yml"
303
304
  - ".eslintignore"
304
305
  - ".eslintrc.yml"
306
+ - ".flowconfig"
305
307
  - ".gitignore"
306
308
  - ".rubocop.yml"
307
309
  - ".travis.yml"
@@ -315,14 +317,15 @@ files:
315
317
  - active_storage_drag_and_drop.gemspec
316
318
  - app/assets/javascripts/active_storage_drag_and_drop.js
317
319
  - app/assets/stylesheets/active_storage_drag_and_drop.css
318
- - app/assets/stylesheets/direct_uploads.css
319
- - app/javascript/active_storage_drag_and_drop/direct_upload_controller.js
320
+ - app/javascript/active_storage_drag_and_drop/default_ui.js
321
+ - app/javascript/active_storage_drag_and_drop/drag_and_drop_form_controller.js
322
+ - app/javascript/active_storage_drag_and_drop/drag_and_drop_upload_controller.js
320
323
  - app/javascript/active_storage_drag_and_drop/helpers.js
321
324
  - app/javascript/active_storage_drag_and_drop/index.js
322
325
  - app/javascript/active_storage_drag_and_drop/ujs.js
323
- - app/javascript/active_storage_drag_and_drop/upload_queue_processor.js
324
326
  - bin/console
325
327
  - bin/setup
328
+ - demo.webp
326
329
  - lib/active_storage_drag_and_drop.rb
327
330
  - lib/active_storage_drag_and_drop/form_builder.rb
328
331
  - lib/active_storage_drag_and_drop/version.rb
@@ -1,43 +0,0 @@
1
- /* direct_uploads.css */
2
-
3
- .direct-upload {
4
- display: inline-block;
5
- position: relative;
6
- padding: 2px 4px;
7
- margin: 0 3px 3px 0;
8
- border: 1px solid rgba(0, 0, 0, 0.3);
9
- border-radius: 3px;
10
- font-size: 11px;
11
- line-height: 13px;
12
- }
13
-
14
- .direct-upload--pending {
15
- opacity: 0.6;
16
- }
17
-
18
- .direct-upload__progress {
19
- position: absolute;
20
- top: 0;
21
- left: 0;
22
- bottom: 0;
23
- opacity: 0.2;
24
- background: #0076ff;
25
- transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
26
- transform: translate3d(0, 0, 0);
27
- }
28
-
29
- .direct-upload--complete .direct-upload__progress {
30
- opacity: 0.4;
31
- }
32
-
33
- .direct-upload--error {
34
- border-color: red;
35
- }
36
-
37
- .direct-upload__remove {
38
- font-size: 0.5em;
39
- }
40
-
41
- input[type=file][data-direct-upload-url][disabled] {
42
- display: none;
43
- }
@@ -1,76 +0,0 @@
1
- import { dispatchEvent, defaultErrorEventUI, defaultEndEventUI, fileUploadUIPainter } from './helpers'
2
- import { DirectUpload } from 'activestorage'
3
- const eventFamily = 'dnd-upload'
4
-
5
- export class DragAndDropUploadController {
6
- constructor (input, file) {
7
- this.input = input
8
- this.form = input.closest('form')
9
- this.url = this.input.dataset.directUploadUrl
10
- this.iconContainer = document.getElementById(this.input.dataset.iconContainerId)
11
- this.file = file
12
- this.upload = new DirectUpload(this.file, this.url, this)
13
- let event = this.dispatch('initialize')
14
- if (!event.defaultPrevented) {
15
- const { detail } = event
16
- const { id, file, iconContainer } = detail
17
- fileUploadUIPainter(iconContainer, id, file.name, false)
18
- }
19
- }
20
-
21
- start (callback) {
22
- this.upload.create((error, blob) => {
23
- if (error) {
24
- // Handle the error
25
- this.dispatchError(error)
26
- callback(error)
27
- } else {
28
- // Add an appropriately-named hidden input to the form with a
29
- // value of blob.signed_id so that the blob ids will be
30
- // transmitted in the normal upload flow
31
- const hiddenField = document.createElement('input')
32
- hiddenField.setAttribute('type', 'hidden')
33
- hiddenField.setAttribute('value', blob.signed_id)
34
- hiddenField.name = this.input.name
35
- hiddenField.setAttribute('data-direct-upload-id', this.upload.id)
36
- this.form.appendChild(hiddenField)
37
- let event = this.dispatch('end')
38
- defaultEndEventUI(event)
39
- callback(error)
40
- }
41
- })
42
- }
43
-
44
- dispatch (name, detail = {}) {
45
- detail.file = this.file
46
- detail.id = this.upload.id
47
- detail.iconContainer = this.iconContainer
48
- return dispatchEvent(this.input, `${eventFamily}:${name}`, { detail })
49
- }
50
-
51
- dispatchError (error) {
52
- const event = this.dispatch('error', { error })
53
- defaultErrorEventUI(event)
54
- }
55
-
56
- directUploadWillCreateBlobWithXHR (xhr) {
57
- this.dispatch('before-blob-request', { xhr })
58
- }
59
- // directUploadWillStoreFileWithXHR
60
- directUploadWillStoreFileWithXHR (xhr) {
61
- this.dispatch('before-storage-request', { xhr })
62
- xhr.upload.addEventListener('progress', event => this.uploadRequestDidProgress(event))
63
- }
64
-
65
- uploadRequestDidProgress (event) {
66
- const progress = event.loaded / event.total * 100
67
- if (progress) {
68
- let event = this.dispatch('progress', { progress })
69
- if (!event.defaultPrevented) {
70
- const { id, progress } = event.detail
71
- const progressElement = document.getElementById(`direct-upload-progress-${id}`)
72
- progressElement.style.width = `${progress}%`
73
- }
74
- }
75
- }
76
- }
@@ -1,113 +0,0 @@
1
- import { dispatchEvent, defaultErrorEventUI, defaultEndEventUI, fileUploadUIPainter } from './helpers'
2
- import { DragAndDropUploadController } from './direct_upload_controller'
3
- export const uploaders = []
4
-
5
- class ValidationError extends Error {
6
- constructor (...args) {
7
- super(...args)
8
- Error.captureStackTrace(this, ValidationError)
9
- }
10
- }
11
-
12
- export class UploadQueueProcessor {
13
- constructor (form) {
14
- this.form = form
15
- this.current_uploaders = []
16
- uploaders.forEach(uploader => {
17
- if (form === uploader.form) {
18
- this.current_uploaders.push(uploader)
19
- }
20
- })
21
- }
22
-
23
- start (callback) {
24
- const startNextUploader = () => {
25
- const nextUploader = this.current_uploaders.shift()
26
- if (nextUploader) {
27
- nextUploader.start(error => {
28
- if (error) {
29
- this.dispatchError(error)
30
- callback(error)
31
- } else {
32
- startNextUploader()
33
- }
34
- })
35
- } else {
36
- callback()
37
- let event = this.dispatch('end')
38
- defaultEndEventUI(event)
39
- }
40
- }
41
-
42
- this.dispatch('start')
43
- startNextUploader()
44
- }
45
-
46
- dispatch (name, detail = {}) {
47
- return dispatchEvent(this.form, `dnd-uploads:${name}`, { detail })
48
- }
49
-
50
- dispatchError (error) {
51
- const event = this.dispatch('error', { error })
52
- defaultErrorEventUI(event)
53
- }
54
- }
55
-
56
- export function createUploader (input, file) {
57
- // your form needs the file_field direct_upload: true, which
58
- // provides data-direct-upload-url
59
- const error = validateUploader(input, file)
60
- if (error) {
61
- let detail = {
62
- id: null,
63
- file: file,
64
- iconContainer: input.dataset.iconContainerId,
65
- error: error
66
- }
67
- return dispatchErrorWithoutAttachment(input, detail)
68
- }
69
- if (!input.multiple) { removeAttachedFiles(input) }
70
- uploaders.push(new DragAndDropUploadController(input, file))
71
- }
72
-
73
- function removeAttachedFiles (input) {
74
- input.closest('label.asdndzone').querySelectorAll('[data-direct-upload-id]').forEach(element => {
75
- element.remove()
76
- })
77
- uploaders.splice(0, uploaders.length)
78
- }
79
-
80
- function dispatchErrorWithoutAttachment (input, detail) {
81
- let event = dispatchEvent(input, 'dnd-upload:error', { detail })
82
- if (!event.defaultPrevented) {
83
- const { error, iconContainer, file } = event.detail
84
- fileUploadUIPainter(iconContainer, 'error', file.name, true)
85
- const element = document.getElementById(`direct-upload-error`)
86
- element.classList.add('direct-upload--error')
87
- element.setAttribute('title', error)
88
- }
89
- return event
90
- }
91
-
92
- function validateUploader (input, file) {
93
- const sizeLimit = input.getAttribute('size_limit')
94
- if (input.accept !== '' && !input.accept.split(', ').includes(file.type)) {
95
- return new ValidationError('Invalid filetype')
96
- } else if (sizeLimit && file.size > sizeLimit) {
97
- return new ValidationError(`File too large. Can be no larger than ${humanFileSize(sizeLimit)}`)
98
- }
99
- }
100
-
101
- function humanFileSize (bytes) {
102
- var thresh = 1000
103
- if (Math.abs(bytes) < thresh) {
104
- return bytes + ' B'
105
- }
106
- var units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
107
- var u = -1
108
- do {
109
- bytes /= thresh
110
- ++u
111
- } while (Math.abs(bytes) >= thresh && u < units.length - 1)
112
- return bytes.toFixed(1) + ' ' + units[u]
113
- }