active_storage_drag_and_drop 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
- }