active_storage_drag_and_drop 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +5 -0
- data/.eslintignore +5 -0
- data/.eslintrc.yml +1 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +9 -7
- data/.travis.yml +17 -1
- data/.yardopts +3 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +93 -0
- data/README.md +112 -17
- data/Rakefile +2 -0
- data/active_storage_drag_and_drop.gemspec +19 -2
- data/app/assets/javascripts/active_storage_drag_and_drop.js +6 -6
- data/app/javascript/active_storage_drag_and_drop/direct_upload_controller.js +32 -24
- data/app/javascript/active_storage_drag_and_drop/helpers.js +36 -46
- data/app/javascript/active_storage_drag_and_drop/index.js +2 -74
- data/app/javascript/active_storage_drag_and_drop/ujs.js +95 -65
- data/app/javascript/active_storage_drag_and_drop/upload_queue_processor.js +43 -17
- data/bin/console +1 -0
- data/lib/active_storage_drag_and_drop.rb +20 -1
- data/lib/active_storage_drag_and_drop/form_builder.rb +145 -0
- data/lib/active_storage_drag_and_drop/version.rb +1 -1
- data/package.json +6 -0
- data/webpack.config.js +7 -8
- data/yarn.lock +606 -13
- metadata +220 -10
- data/app/views/application/_active_storage_drag_and_drop.html.erb +0 -15
- data/lib/active_storage_drag_and_drop/rails.rb +0 -8
- data/lib/active_storage_drag_and_drop/rails/engine.rb +0 -11
- data/lib/active_storage_drag_and_drop/rails/form_builder.rb +0 -78
- data/lib/active_storage_drag_and_drop/rails/form_helper.rb +0 -16
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'active_storage_drag_and_drop/version'
|
@@ -8,9 +10,9 @@ Gem::Specification.new do |spec|
|
|
8
10
|
spec.authors = ["Dave O'Keeffe", 'Ian Grant']
|
9
11
|
spec.email = ['ian.grant@marinosoftware.com']
|
10
12
|
|
11
|
-
spec.summary = 'Provides
|
13
|
+
spec.summary = 'Provides JS drag and drop file upload functionality for active storage.'
|
12
14
|
spec.description = 'Provides a form helper to make it easy to make drag and drop file upload'\
|
13
|
-
"fields that work with Rails' Active Storage."
|
15
|
+
" fields that work with Rails' Active Storage."
|
14
16
|
spec.homepage = 'https://github.com/marinosoftware/active_storage_drag_and_drop'
|
15
17
|
spec.license = 'MIT'
|
16
18
|
|
@@ -29,9 +31,24 @@ Gem::Specification.new do |spec|
|
|
29
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
32
|
spec.require_paths = ['lib']
|
31
33
|
|
34
|
+
spec.add_development_dependency 'bootsnap'
|
32
35
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
36
|
+
spec.add_development_dependency 'capybara'
|
37
|
+
spec.add_development_dependency 'geckodriver-helper'
|
38
|
+
spec.add_development_dependency 'github-markup'
|
39
|
+
spec.add_development_dependency 'haml'
|
40
|
+
spec.add_development_dependency 'listen'
|
33
41
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
42
|
+
spec.add_development_dependency 'nokogiri'
|
43
|
+
spec.add_development_dependency 'pry'
|
44
|
+
spec.add_development_dependency 'pry-byebug'
|
45
|
+
spec.add_development_dependency 'puma'
|
34
46
|
spec.add_development_dependency 'rake', '~> 10.0'
|
47
|
+
spec.add_development_dependency 'redcarpet'
|
48
|
+
spec.add_development_dependency 'rubocop'
|
49
|
+
spec.add_development_dependency 'selenium-webdriver'
|
50
|
+
spec.add_development_dependency 'simplecov'
|
51
|
+
spec.add_development_dependency 'sqlite3'
|
35
52
|
spec.add_dependency 'rack', '~> 2.0.6'
|
36
53
|
spec.add_dependency 'rails', '~> 5.2'
|
37
54
|
end
|
@@ -104,7 +104,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|
104
104
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
105
105
|
|
106
106
|
"use strict";
|
107
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"DragAndDropUploadController\", function() { return DragAndDropUploadController; });\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n/* harmony import */ var activestorage__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! activestorage */ \"./node_modules/activestorage/app/assets/javascripts/activestorage.js\");\n/* harmony import */ var activestorage__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(activestorage__WEBPACK_IMPORTED_MODULE_1__);\n\n\nconst eventFamily = 'dnd-upload';\n\nclass DragAndDropUploadController {\n constructor(input, file) {\n this.input = input;\n this.form = input.closest('form');\n this.url = this.input.dataset.directUploadUrl;\n this.iconContainer = document.getElementById(this.input.dataset.iconContainerId);\n this.file = file;\n this.upload = new activestorage__WEBPACK_IMPORTED_MODULE_1__[\"DirectUpload\"](this.file, this.url, this);\n this.dispatch(\"
|
107
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"DragAndDropUploadController\", function() { return DragAndDropUploadController; });\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n/* harmony import */ var activestorage__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! activestorage */ \"./node_modules/activestorage/app/assets/javascripts/activestorage.js\");\n/* harmony import */ var activestorage__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(activestorage__WEBPACK_IMPORTED_MODULE_1__);\n\n\nconst eventFamily = 'dnd-upload';\n\nclass DragAndDropUploadController {\n constructor(input, file) {\n this.input = input;\n this.form = input.closest('form');\n this.url = this.input.dataset.directUploadUrl;\n this.iconContainer = document.getElementById(this.input.dataset.iconContainerId);\n this.file = file;\n this.upload = new activestorage__WEBPACK_IMPORTED_MODULE_1__[\"DirectUpload\"](this.file, this.url, this);\n let event = this.dispatch('initialize');\n if (!event.defaultPrevented) {\n const { detail } = event;\n const { id, file, iconContainer } = detail;\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"fileUploadUIPainter\"])(iconContainer, id, file.name, false);\n }\n }\n\n start(callback) {\n this.upload.create((error, blob) => {\n if (error) {\n // Handle the error\n this.dispatchError(error);\n callback(error);\n } else {\n // Add an appropriately-named hidden input to the form with a\n // value of blob.signed_id so that the blob ids will be\n // transmitted in the normal upload flow\n const hiddenField = document.createElement('input');\n hiddenField.setAttribute('type', 'hidden');\n hiddenField.setAttribute('value', blob.signed_id);\n hiddenField.name = this.input.name;\n hiddenField.setAttribute('data-direct-upload-id', this.upload.id);\n this.form.appendChild(hiddenField);\n let event = this.dispatch('end');\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"defaultEndEventUI\"])(event);\n callback(error);\n }\n });\n }\n\n dispatch(name, detail = {}) {\n detail.file = this.file;\n detail.id = this.upload.id;\n detail.iconContainer = this.iconContainer;\n return Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"dispatchEvent\"])(this.input, `${eventFamily}:${name}`, { detail });\n }\n\n dispatchError(error) {\n const event = this.dispatch('error', { error });\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"defaultErrorEventUI\"])(event);\n }\n\n directUploadWillCreateBlobWithXHR(xhr) {\n this.dispatch('before-blob-request', { xhr });\n }\n // directUploadWillStoreFileWithXHR\n directUploadWillStoreFileWithXHR(xhr) {\n this.dispatch('before-storage-request', { xhr });\n xhr.upload.addEventListener('progress', event => this.uploadRequestDidProgress(event));\n }\n\n uploadRequestDidProgress(event) {\n const progress = event.loaded / event.total * 100;\n if (progress) {\n let event = this.dispatch('progress', { progress });\n if (!event.defaultPrevented) {\n const { id, progress } = event.detail;\n const progressElement = document.getElementById(`direct-upload-progress-${id}`);\n progressElement.style.width = `${progress}%`;\n }\n }\n }\n}\n\n//# sourceURL=webpack://ActiveStorage/./app/javascript/active_storage_drag_and_drop/direct_upload_controller.js?");
|
108
108
|
|
109
109
|
/***/ }),
|
110
110
|
|
@@ -112,11 +112,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
112
112
|
/*!****************************************************************!*\
|
113
113
|
!*** ./app/javascript/active_storage_drag_and_drop/helpers.js ***!
|
114
114
|
\****************************************************************/
|
115
|
-
/*! exports provided: dispatchEvent, hasClassnameInHeirarchy, getClassnameFromHeirarchy */
|
115
|
+
/*! exports provided: dispatchEvent, defaultErrorEventUI, defaultEndEventUI, hasClassnameInHeirarchy, getClassnameFromHeirarchy, fileUploadUIPainter */
|
116
116
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
117
117
|
|
118
118
|
"use strict";
|
119
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"dispatchEvent\", function() { return dispatchEvent; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"hasClassnameInHeirarchy\", function() { return hasClassnameInHeirarchy; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getClassnameFromHeirarchy\", function() { return getClassnameFromHeirarchy; });\n\nfunction dispatchEvent(element, type, eventInit = {}) {\n const { bubbles, cancelable, detail } = eventInit;\n const event = document.createEvent(
|
119
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"dispatchEvent\", function() { return dispatchEvent; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultErrorEventUI\", function() { return defaultErrorEventUI; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultEndEventUI\", function() { return defaultEndEventUI; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"hasClassnameInHeirarchy\", function() { return hasClassnameInHeirarchy; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"getClassnameFromHeirarchy\", function() { return getClassnameFromHeirarchy; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"fileUploadUIPainter\", function() { return fileUploadUIPainter; });\nfunction dispatchEvent(element, type, eventInit = {}) {\n const { bubbles, cancelable, detail } = eventInit;\n const event = document.createEvent('Event');\n event.initEvent(type, bubbles || true, cancelable || true);\n event.detail = detail || {};\n element.dispatchEvent(event);\n return event;\n}\n\nfunction defaultErrorEventUI(event) {\n if (!event.defaultPrevented) {\n const { id, error } = event.detail;\n const element = document.getElementById(`direct-upload-${id}`);\n element.classList.add('direct-upload--error');\n element.setAttribute('title', error);\n }\n}\n\nfunction defaultEndEventUI(event) {\n if (!event.defaultPrevented) {\n const { id } = event.detail;\n const element = document.getElementById(`direct-upload-${id}`);\n element.classList.remove('direct-upload--pending');\n element.classList.add('direct-upload--complete');\n }\n}\n\nfunction hasClassnameInHeirarchy(element, classname) {\n if (element && element.classList) {\n if (element.classList.contains(classname)) {\n return true;\n } else {\n return hasClassnameInHeirarchy(element.parentNode, classname);\n }\n }\n}\n\nfunction getClassnameFromHeirarchy(element, classname) {\n if (element && element.classList) {\n if (element.classList.contains(classname)) {\n return element;\n } else {\n return getClassnameFromHeirarchy(element.parentNode, classname);\n }\n }\n}\n\nfunction fileUploadUIPainter(iconContainer, id, filename, complete) {\n // the only rule here is that all root level elements must have the data: { direct_upload_id: [id] } attribute ala: 'data-direct-upload-id=\"${id}\"'\n var cname = complete ? 'complete' : 'pending';\n var progress = complete ? 100 : 0;\n iconContainer.insertAdjacentHTML('beforeend', `\n <div id=\"direct-upload-${id}\" class=\"direct-upload direct-upload--${cname}\" data-direct-upload-id=\"${id}\">\n <div id=\"direct-upload-progress-${id}\" class=\"direct-upload__progress\" style=\"width: ${progress}%\"></div>\n <span class=\"direct-upload__filename\">${filename}</span>\n </div>\n <a href='remove' class='direct-upload__remove' data-dnd-delete='true' data-direct-upload-id=\"${id}\">x</a>\n `);\n}\n\n//# sourceURL=webpack://ActiveStorage/./app/javascript/active_storage_drag_and_drop/helpers.js?");
|
120
120
|
|
121
121
|
/***/ }),
|
122
122
|
|
@@ -128,7 +128,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
128
128
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
129
129
|
|
130
130
|
"use strict";
|
131
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ujs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ujs */ \"./app/javascript/active_storage_drag_and_drop/ujs.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"start\", function() { return _ujs__WEBPACK_IMPORTED_MODULE_0__[\"start\"]; });\n\n\n\n\n\nfunction autostart() {\n Object(_ujs__WEBPACK_IMPORTED_MODULE_0__[\"start\"])();\n}\n\nsetTimeout(autostart, 1);\n\n
|
131
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ujs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ujs */ \"./app/javascript/active_storage_drag_and_drop/ujs.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"start\", function() { return _ujs__WEBPACK_IMPORTED_MODULE_0__[\"start\"]; });\n\n\n\n\n\nfunction autostart() {\n Object(_ujs__WEBPACK_IMPORTED_MODULE_0__[\"start\"])();\n}\n\nsetTimeout(autostart, 1);\n\n//# sourceURL=webpack://ActiveStorage/./app/javascript/active_storage_drag_and_drop/index.js?");
|
132
132
|
|
133
133
|
/***/ }),
|
134
134
|
|
@@ -140,7 +140,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ujs
|
|
140
140
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
141
141
|
|
142
142
|
"use strict";
|
143
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"start\", function() { return start; });\n/* harmony import */ var _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./upload_queue_processor */ \"./app/javascript/active_storage_drag_and_drop/upload_queue_processor.js\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n\n\n\nlet started = false;\nlet formSubmitted = false;\n\nfunction didSubmitForm(event) {\n handleFormSubmissionEvent(event);\n}\n\nfunction didSubmitRemoteElement(event) {\n if (event.target.tagName
|
143
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"start\", function() { return start; });\n/* harmony import */ var _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./upload_queue_processor */ \"./app/javascript/active_storage_drag_and_drop/upload_queue_processor.js\");\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n\n\n\nlet started = false;\nlet formSubmitted = false;\n\nfunction didSubmitForm(event) {\n handleFormSubmissionEvent(event);\n}\n\nfunction didSubmitRemoteElement(event) {\n if (event.target.tagName === 'FORM') {\n handleFormSubmissionEvent(event);\n }\n}\n\nfunction processUploadQueue(event) {\n const form = event.target;\n const { callback } = event.detail;\n const nextUpload = new _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"UploadQueueProcessor\"](form);\n if (nextUpload.current_uploaders.length > 0) {\n nextUpload.start(error => {\n if (error) {\n callback(error);\n } else {\n callback();\n }\n });\n } else {\n callback();\n }\n}\n\nfunction handleFormSubmissionEvent(event) {\n if (formSubmitted) {\n return;\n }\n formSubmitted = true;\n const form = event.target;\n const nextUpload = new _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"UploadQueueProcessor\"](form);\n // if the upload processor has no dnd file inputs, then we let the event happen naturally\n // if it DOES have dnd file inputs, then we have to process our queue first and then submit the form\n if (nextUpload.current_uploaders.length > 0) {\n // inputs.forEach(disable)\n event.preventDefault();\n nextUpload.start(error => {\n if (error) {\n // inputs.forEach(enable)\n } else {\n form.submit();\n // The original ActiveStorage DirectUpload system did this action using\n // input.click(), but doing that either makes the form submission event\n // happen multiple times, or the browser seems to block the input.click()\n // event completely, because it's not a trusted 'as a result of a mouse\n // click' event.\n // HOWEVER\n // form.submit() doesn't trigger to any UJS submission events. This\n // results in remote forms being submitted locally whenever there's a\n // dnd file to upload. Instead we use Rails.fire(element, 'submit')\n // Rails.fire(form, 'submit')\n }\n });\n }\n}\n\nfunction addAttachedFileIcons() {\n document.querySelectorAll(\"input[type='hidden'][data-direct-upload-id][data-uploaded-file-name]\").forEach(uploadedFile => {\n const dataset = uploadedFile.dataset;\n let iconContainer = document.getElementById(dataset.iconContainerId);\n let detail = {\n id: dataset.directUploadId,\n fileName: dataset.uploadedFileName,\n iconContainer: iconContainer\n };\n let event = _helpers__WEBPACK_IMPORTED_MODULE_1__[\"dispatchEvent\"](uploadedFile, 'dnd-upload:placeholder', { detail });\n if (!event.defaultPrevented) {\n const { detail } = event;\n const { id, fileName, iconContainer } = detail;\n _helpers__WEBPACK_IMPORTED_MODULE_1__[\"fileUploadUIPainter\"](iconContainer, id, fileName, true);\n }\n });\n}\n\nfunction createUploadersForFileInput(event) {\n if (event.target.type === 'file' && event.target.dataset.dnd === 'true') {\n const input = event.target;\n Array.from(input.files).forEach(file => Object(_upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"createUploader\"])(input, file));\n input.value = null;\n }\n}\n\nfunction preventDragover(event) {\n if (_helpers__WEBPACK_IMPORTED_MODULE_1__[\"hasClassnameInHeirarchy\"](event.target, 'asdndzone')) {\n event.preventDefault();\n }\n}\n\nfunction createUploadersForDroppedFiles(event) {\n let asdndz = _helpers__WEBPACK_IMPORTED_MODULE_1__[\"getClassnameFromHeirarchy\"](event.target, 'asdndzone');\n if (asdndz) {\n event.preventDefault();\n // get the input associated with this dndz\n const input = document.getElementById(asdndz.dataset.dndInputId);\n Array.from(event.dataTransfer.files).forEach(file => Object(_upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"createUploader\"])(input, file));\n }\n}\n\nfunction removeFileFromQueue(event) {\n if (event.target.dataset.dndDelete === 'true' && event.target.hasAttribute('data-direct-upload-id')) {\n event.preventDefault();\n document.querySelectorAll('[data-direct-upload-id=\"' + event.target.dataset.directUploadId + '\"]').forEach(element => {\n element.remove();\n });\n for (var i = 0; i < _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"uploaders\"].length; i++) {\n if (_upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"uploaders\"][i].upload.id === event.target.dataset.directUploadId) {\n _upload_queue_processor__WEBPACK_IMPORTED_MODULE_0__[\"uploaders\"].splice(i, 1);\n break;\n }\n }\n }\n}\n\nfunction start() {\n if (started) {\n return;\n }\n started = true;\n document.addEventListener('submit', didSubmitForm);\n document.addEventListener('ajax:before', didSubmitRemoteElement);\n document.addEventListener('dnd-uploads:process-upload-queue', processUploadQueue);\n\n // input[type=file][data-dnd=true]\n document.addEventListener('change', createUploadersForFileInput);\n document.addEventListener('dragover', preventDragover);\n document.addEventListener('drop', createUploadersForDroppedFiles);\n document.addEventListener('click', removeFileFromQueue);\n addAttachedFileIcons();\n}\n\n//# sourceURL=webpack://ActiveStorage/./app/javascript/active_storage_drag_and_drop/ujs.js?");
|
144
144
|
|
145
145
|
/***/ }),
|
146
146
|
|
@@ -152,7 +152,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
152
152
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
153
153
|
|
154
154
|
"use strict";
|
155
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"uploaders\", function() { return uploaders; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UploadQueueProcessor\", function() { return UploadQueueProcessor; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"createUploader\", function() { return createUploader; });\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n/* harmony import */ var _direct_upload_controller__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./direct_upload_controller */ \"./app/javascript/active_storage_drag_and_drop/direct_upload_controller.js\");\n\n\nconst uploaders = [];\n\
|
155
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"uploaders\", function() { return uploaders; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UploadQueueProcessor\", function() { return UploadQueueProcessor; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"createUploader\", function() { return createUploader; });\n/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers */ \"./app/javascript/active_storage_drag_and_drop/helpers.js\");\n/* harmony import */ var _direct_upload_controller__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./direct_upload_controller */ \"./app/javascript/active_storage_drag_and_drop/direct_upload_controller.js\");\n\n\nconst uploaders = [];\n\nclass ValidationError extends Error {\n constructor(...args) {\n super(...args);\n Error.captureStackTrace(this, ValidationError);\n }\n}\n\nclass UploadQueueProcessor {\n constructor(form) {\n this.form = form;\n this.current_uploaders = [];\n uploaders.forEach(uploader => {\n if (form === uploader.form) {\n this.current_uploaders.push(uploader);\n }\n });\n }\n\n start(callback) {\n const startNextUploader = () => {\n const nextUploader = this.current_uploaders.shift();\n if (nextUploader) {\n nextUploader.start(error => {\n if (error) {\n this.dispatchError(error);\n callback(error);\n } else {\n startNextUploader();\n }\n });\n } else {\n callback();\n let event = this.dispatch('end');\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"defaultEndEventUI\"])(event);\n }\n };\n\n this.dispatch('start');\n startNextUploader();\n }\n\n dispatch(name, detail = {}) {\n return Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"dispatchEvent\"])(this.form, `dnd-uploads:${name}`, { detail });\n }\n\n dispatchError(error) {\n const event = this.dispatch('error', { error });\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"defaultErrorEventUI\"])(event);\n }\n}\n\nfunction createUploader(input, file) {\n // your form needs the file_field direct_upload: true, which\n // provides data-direct-upload-url\n const error = validateUploader(input, file);\n if (error) {\n let detail = {\n id: null,\n file: file,\n iconContainer: input.dataset.iconContainerId,\n error: error\n };\n return dispatchErrorWithoutAttachment(input, detail);\n }\n if (!input.multiple) {\n removeAttachedFiles(input);\n }\n uploaders.push(new _direct_upload_controller__WEBPACK_IMPORTED_MODULE_1__[\"DragAndDropUploadController\"](input, file));\n}\n\nfunction removeAttachedFiles(input) {\n input.closest('label.asdndzone').querySelectorAll('[data-direct-upload-id]').forEach(element => {\n element.remove();\n });\n uploaders.splice(0, uploaders.length);\n}\n\nfunction dispatchErrorWithoutAttachment(input, detail) {\n let event = Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"dispatchEvent\"])(input, 'dnd-upload:error', { detail });\n if (!event.defaultPrevented) {\n const { error, iconContainer, file } = event.detail;\n Object(_helpers__WEBPACK_IMPORTED_MODULE_0__[\"fileUploadUIPainter\"])(iconContainer, 'error', file.name, true);\n const element = document.getElementById(`direct-upload-error`);\n element.classList.add('direct-upload--error');\n element.setAttribute('title', error);\n }\n return event;\n}\n\nfunction validateUploader(input, file) {\n const sizeLimit = input.getAttribute('size_limit');\n if (input.accept !== '' && !input.accept.split(', ').includes(file.type)) {\n return new ValidationError('Invalid filetype');\n } else if (sizeLimit && file.size > sizeLimit) {\n return new ValidationError(`File too large. Can be no larger than ${humanFileSize(sizeLimit)}`);\n }\n}\n\nfunction humanFileSize(bytes) {\n var thresh = 1000;\n if (Math.abs(bytes) < thresh) {\n return bytes + ' B';\n }\n var units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n var u = -1;\n do {\n bytes /= thresh;\n ++u;\n } while (Math.abs(bytes) >= thresh && u < units.length - 1);\n return bytes.toFixed(1) + ' ' + units[u];\n}\n\n//# sourceURL=webpack://ActiveStorage/./app/javascript/active_storage_drag_and_drop/upload_queue_processor.js?");
|
156
156
|
|
157
157
|
/***/ }),
|
158
158
|
|
@@ -1,68 +1,76 @@
|
|
1
|
-
import { dispatchEvent } from './helpers'
|
1
|
+
import { dispatchEvent, defaultErrorEventUI, defaultEndEventUI, fileUploadUIPainter } from './helpers'
|
2
2
|
import { DirectUpload } from 'activestorage'
|
3
3
|
const eventFamily = 'dnd-upload'
|
4
4
|
|
5
5
|
export class DragAndDropUploadController {
|
6
|
-
constructor(input, file) {
|
6
|
+
constructor (input, file) {
|
7
7
|
this.input = input
|
8
8
|
this.form = input.closest('form')
|
9
9
|
this.url = this.input.dataset.directUploadUrl
|
10
10
|
this.iconContainer = document.getElementById(this.input.dataset.iconContainerId)
|
11
11
|
this.file = file
|
12
12
|
this.upload = new DirectUpload(this.file, this.url, this)
|
13
|
-
this.dispatch(
|
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
|
+
}
|
14
19
|
}
|
15
20
|
|
16
|
-
start(callback) {
|
21
|
+
start (callback) {
|
17
22
|
this.upload.create((error, blob) => {
|
18
23
|
if (error) {
|
19
24
|
// Handle the error
|
20
25
|
this.dispatchError(error)
|
21
26
|
callback(error)
|
22
27
|
} else {
|
23
|
-
//
|
24
|
-
//
|
25
|
-
//
|
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
|
26
31
|
const hiddenField = document.createElement('input')
|
27
|
-
hiddenField.setAttribute(
|
28
|
-
hiddenField.setAttribute(
|
32
|
+
hiddenField.setAttribute('type', 'hidden')
|
33
|
+
hiddenField.setAttribute('value', blob.signed_id)
|
29
34
|
hiddenField.name = this.input.name
|
30
35
|
hiddenField.setAttribute('data-direct-upload-id', this.upload.id)
|
31
36
|
this.form.appendChild(hiddenField)
|
32
|
-
this.dispatch(
|
37
|
+
let event = this.dispatch('end')
|
38
|
+
defaultEndEventUI(event)
|
33
39
|
callback(error)
|
34
40
|
}
|
35
41
|
})
|
36
42
|
}
|
37
43
|
|
38
|
-
dispatch(name, detail = {}) {
|
44
|
+
dispatch (name, detail = {}) {
|
39
45
|
detail.file = this.file
|
40
46
|
detail.id = this.upload.id
|
41
47
|
detail.iconContainer = this.iconContainer
|
42
48
|
return dispatchEvent(this.input, `${eventFamily}:${name}`, { detail })
|
43
49
|
}
|
44
50
|
|
45
|
-
dispatchError(error) {
|
46
|
-
const event = this.dispatch(
|
47
|
-
|
48
|
-
alert(error)
|
49
|
-
}
|
51
|
+
dispatchError (error) {
|
52
|
+
const event = this.dispatch('error', { error })
|
53
|
+
defaultErrorEventUI(event)
|
50
54
|
}
|
51
55
|
|
52
|
-
directUploadWillCreateBlobWithXHR(xhr) {
|
53
|
-
this.dispatch(
|
56
|
+
directUploadWillCreateBlobWithXHR (xhr) {
|
57
|
+
this.dispatch('before-blob-request', { xhr })
|
54
58
|
}
|
55
59
|
// directUploadWillStoreFileWithXHR
|
56
|
-
directUploadWillStoreFileWithXHR(xhr) {
|
57
|
-
this.dispatch(
|
58
|
-
xhr.upload.addEventListener(
|
60
|
+
directUploadWillStoreFileWithXHR (xhr) {
|
61
|
+
this.dispatch('before-storage-request', { xhr })
|
62
|
+
xhr.upload.addEventListener('progress', event => this.uploadRequestDidProgress(event))
|
59
63
|
}
|
60
64
|
|
61
|
-
uploadRequestDidProgress(event) {
|
65
|
+
uploadRequestDidProgress (event) {
|
62
66
|
const progress = event.loaded / event.total * 100
|
63
67
|
if (progress) {
|
64
|
-
this.dispatch(
|
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
|
+
}
|
65
74
|
}
|
66
75
|
}
|
67
|
-
|
68
76
|
}
|
@@ -1,69 +1,59 @@
|
|
1
|
-
|
2
|
-
export function dispatchEvent(element, type, eventInit = {}) {
|
1
|
+
export function dispatchEvent (element, type, eventInit = {}) {
|
3
2
|
const { bubbles, cancelable, detail } = eventInit
|
4
|
-
const event = document.createEvent(
|
3
|
+
const event = document.createEvent('Event')
|
5
4
|
event.initEvent(type, bubbles || true, cancelable || true)
|
6
5
|
event.detail = detail || {}
|
7
6
|
element.dispatchEvent(event)
|
8
7
|
return event
|
9
8
|
}
|
10
9
|
|
11
|
-
export function
|
12
|
-
if(
|
10
|
+
export function defaultErrorEventUI (event) {
|
11
|
+
if (!event.defaultPrevented) {
|
12
|
+
const { id, error } = event.detail
|
13
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
14
|
+
element.classList.add('direct-upload--error')
|
15
|
+
element.setAttribute('title', error)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
export function defaultEndEventUI (event) {
|
20
|
+
if (!event.defaultPrevented) {
|
21
|
+
const { id } = event.detail
|
22
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
23
|
+
element.classList.remove('direct-upload--pending')
|
24
|
+
element.classList.add('direct-upload--complete')
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
export function hasClassnameInHeirarchy (element, classname) {
|
29
|
+
if (element && element.classList) {
|
13
30
|
if (element.classList.contains(classname)) {
|
14
31
|
return true
|
15
32
|
} else {
|
16
33
|
return hasClassnameInHeirarchy(element.parentNode, classname)
|
17
34
|
}
|
18
|
-
} else {
|
19
|
-
return false
|
20
35
|
}
|
21
36
|
}
|
22
37
|
|
23
|
-
export function getClassnameFromHeirarchy(element, classname) {
|
24
|
-
if(element && element.classList) {
|
38
|
+
export function getClassnameFromHeirarchy (element, classname) {
|
39
|
+
if (element && element.classList) {
|
25
40
|
if (element.classList.contains(classname)) {
|
26
41
|
return element
|
27
42
|
} else {
|
28
43
|
return getClassnameFromHeirarchy(element.parentNode, classname)
|
29
44
|
}
|
30
|
-
} else {
|
31
|
-
return null
|
32
45
|
}
|
33
46
|
}
|
34
47
|
|
35
|
-
|
36
|
-
//
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
// return Array.from(value)
|
48
|
-
// } else {
|
49
|
-
// return [].slice.call(value)
|
50
|
-
// }
|
51
|
-
//}
|
52
|
-
|
53
|
-
//export function findElements(root, selector) {
|
54
|
-
// if (typeof root == "string") {
|
55
|
-
// selector = root
|
56
|
-
// root = document
|
57
|
-
// }
|
58
|
-
// const elements = root.querySelectorAll(selector)
|
59
|
-
// return toArray(elements)
|
60
|
-
//}
|
61
|
-
|
62
|
-
//export function findElement(root, selector) {
|
63
|
-
// if (typeof root == "string") {
|
64
|
-
// selector = root
|
65
|
-
// root = document
|
66
|
-
// }
|
67
|
-
// return root.querySelector(selector)
|
68
|
-
//}
|
69
|
-
|
48
|
+
export function fileUploadUIPainter (iconContainer, id, filename, complete) {
|
49
|
+
// the only rule here is that all root level elements must have the data: { direct_upload_id: [id] } attribute ala: 'data-direct-upload-id="${id}"'
|
50
|
+
var cname = (complete ? 'complete' : 'pending')
|
51
|
+
var progress = (complete ? 100 : 0)
|
52
|
+
iconContainer.insertAdjacentHTML('beforeend', `
|
53
|
+
<div id="direct-upload-${id}" class="direct-upload direct-upload--${cname}" data-direct-upload-id="${id}">
|
54
|
+
<div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: ${progress}%"></div>
|
55
|
+
<span class="direct-upload__filename">${filename}</span>
|
56
|
+
</div>
|
57
|
+
<a href='remove' class='direct-upload__remove' data-dnd-delete='true' data-direct-upload-id="${id}">x</a>
|
58
|
+
`)
|
59
|
+
}
|
@@ -1,81 +1,9 @@
|
|
1
|
-
import { start } from
|
1
|
+
import { start } from './ujs'
|
2
2
|
|
3
3
|
export { start }
|
4
4
|
|
5
|
-
function autostart() {
|
5
|
+
function autostart () {
|
6
6
|
start()
|
7
7
|
}
|
8
8
|
|
9
9
|
setTimeout(autostart, 1)
|
10
|
-
|
11
|
-
//----------------------------------------------------------------------------------------------------
|
12
|
-
// UI Events - this code is completely outside the draganddrop lib - it's just reacting to events
|
13
|
-
//----------------------------------------------------------------------------------------------------
|
14
|
-
var fileUploadUIPainter = function(iconContainer, id, filename, complete) {
|
15
|
-
// the only rule here is that all root level elements must have the data: { direct_upload_id: [id] } attribute ala: 'data-direct-upload-id="${id}"'
|
16
|
-
var cname = ( complete ? 'complete' : 'pending' )
|
17
|
-
var progress = ( complete ? 100 : 0 )
|
18
|
-
iconContainer.insertAdjacentHTML("beforeend", `
|
19
|
-
<div id="direct-upload-${id}" class="direct-upload direct-upload--${cname}" data-direct-upload-id="${id}">
|
20
|
-
<div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: ${progress}%"></div>
|
21
|
-
<span class="direct-upload__filename">${filename}</span>
|
22
|
-
</div>
|
23
|
-
<a href='remove' class='direct-upload__remove' data-dnd-delete='true' data-direct-upload-id="${id}">x</a>
|
24
|
-
`)
|
25
|
-
}
|
26
|
-
|
27
|
-
// addEventListener("dnd-uploads:start", event => {
|
28
|
-
// })
|
29
|
-
// addEventListener("dnd-uploads:end", event => {
|
30
|
-
// })
|
31
|
-
|
32
|
-
addEventListener("dnd-upload:initialize", event => {
|
33
|
-
if (!event.defaultPrevented) {
|
34
|
-
const { target, detail } = event
|
35
|
-
const { id, file, iconContainer } = detail
|
36
|
-
fileUploadUIPainter(iconContainer, id, file.name, false)
|
37
|
-
}
|
38
|
-
})
|
39
|
-
|
40
|
-
addEventListener("dnd-upload:placeholder", event => {
|
41
|
-
if (!event.defaultPrevented) {
|
42
|
-
const { target, detail } = event
|
43
|
-
const { id, fileName, iconContainer } = detail
|
44
|
-
fileUploadUIPainter(iconContainer, id, fileName, true)
|
45
|
-
}
|
46
|
-
})
|
47
|
-
|
48
|
-
addEventListener("dnd-upload:start", event => {
|
49
|
-
if (!event.defaultPrevented) {
|
50
|
-
const { id } = event.detail
|
51
|
-
const element = document.getElementById(`direct-upload-${id}`)
|
52
|
-
element.classList.remove("direct-upload--pending")
|
53
|
-
}
|
54
|
-
})
|
55
|
-
|
56
|
-
addEventListener("dnd-upload:progress", event => {
|
57
|
-
if (!event.defaultPrevented) {
|
58
|
-
const { id, progress } = event.detail
|
59
|
-
const progressElement = document.getElementById(`direct-upload-progress-${id}`)
|
60
|
-
progressElement.style.width = `${progress}%`
|
61
|
-
}
|
62
|
-
})
|
63
|
-
|
64
|
-
addEventListener("dnd-upload:error", event => {
|
65
|
-
if (!event.defaultPrevented) {
|
66
|
-
event.preventDefault()
|
67
|
-
const { id, error } = event.detail
|
68
|
-
const element = document.getElementById(`direct-upload-${id}`)
|
69
|
-
element.classList.add("direct-upload--error")
|
70
|
-
element.setAttribute("title", error)
|
71
|
-
}
|
72
|
-
})
|
73
|
-
|
74
|
-
addEventListener("dnd-upload:end", event => {
|
75
|
-
if (!event.defaultPrevented) {
|
76
|
-
const { id } = event.detail
|
77
|
-
const element = document.getElementById(`direct-upload-${id}`)
|
78
|
-
element.classList.remove("direct-upload--pending")
|
79
|
-
element.classList.add("direct-upload--complete")
|
80
|
-
}
|
81
|
-
})
|
@@ -1,104 +1,134 @@
|
|
1
|
-
import { UploadQueueProcessor, uploaders, createUploader } from
|
1
|
+
import { UploadQueueProcessor, uploaders, createUploader } from './upload_queue_processor'
|
2
2
|
import * as helpers from './helpers'
|
3
3
|
|
4
4
|
let started = false
|
5
5
|
let formSubmitted = false
|
6
6
|
|
7
|
-
function didSubmitForm(event) {
|
7
|
+
function didSubmitForm (event) {
|
8
8
|
handleFormSubmissionEvent(event)
|
9
9
|
}
|
10
10
|
|
11
|
-
function didSubmitRemoteElement(event) {
|
12
|
-
if (event.target.tagName
|
11
|
+
function didSubmitRemoteElement (event) {
|
12
|
+
if (event.target.tagName === 'FORM') {
|
13
13
|
handleFormSubmissionEvent(event)
|
14
14
|
}
|
15
15
|
}
|
16
16
|
|
17
|
-
function
|
18
|
-
|
17
|
+
function processUploadQueue (event) {
|
18
|
+
const form = event.target
|
19
|
+
const { callback } = event.detail
|
20
|
+
const nextUpload = new UploadQueueProcessor(form)
|
21
|
+
if (nextUpload.current_uploaders.length > 0) {
|
22
|
+
nextUpload.start(error => {
|
23
|
+
if (error) {
|
24
|
+
callback(error)
|
25
|
+
} else {
|
26
|
+
callback()
|
27
|
+
}
|
28
|
+
})
|
29
|
+
} else {
|
30
|
+
callback()
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
function handleFormSubmissionEvent (event) {
|
35
|
+
if (formSubmitted) { return }
|
19
36
|
formSubmitted = true
|
20
37
|
const form = event.target
|
21
|
-
const
|
38
|
+
const nextUpload = new UploadQueueProcessor(form)
|
22
39
|
// if the upload processor has no dnd file inputs, then we let the event happen naturally
|
23
40
|
// if it DOES have dnd file inputs, then we have to process our queue first and then submit the form
|
24
|
-
if(
|
25
|
-
event.preventDefault()
|
41
|
+
if (nextUpload.current_uploaders.length > 0) {
|
26
42
|
// inputs.forEach(disable)
|
27
|
-
|
43
|
+
event.preventDefault()
|
44
|
+
nextUpload.start(error => {
|
28
45
|
if (error) {
|
29
46
|
// inputs.forEach(enable)
|
30
47
|
} else {
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
48
|
+
form.submit()
|
49
|
+
// The original ActiveStorage DirectUpload system did this action using
|
50
|
+
// input.click(), but doing that either makes the form submission event
|
51
|
+
// happen multiple times, or the browser seems to block the input.click()
|
52
|
+
// event completely, because it's not a trusted 'as a result of a mouse
|
53
|
+
// click' event.
|
54
|
+
// HOWEVER
|
55
|
+
// form.submit() doesn't trigger to any UJS submission events. This
|
56
|
+
// results in remote forms being submitted locally whenever there's a
|
57
|
+
// dnd file to upload. Instead we use Rails.fire(element, 'submit')
|
58
|
+
// Rails.fire(form, 'submit')
|
42
59
|
}
|
43
60
|
})
|
44
61
|
}
|
45
62
|
}
|
46
63
|
|
47
|
-
function addAttachedFileIcons() {
|
48
|
-
document.querySelectorAll("input[type='hidden'][data-direct-upload-id][data-uploaded-file-name]").forEach(
|
64
|
+
function addAttachedFileIcons () {
|
65
|
+
document.querySelectorAll("input[type='hidden'][data-direct-upload-id][data-uploaded-file-name]").forEach(uploadedFile => {
|
49
66
|
const dataset = uploadedFile.dataset
|
50
|
-
let iconContainer = document.getElementById(dataset.iconContainerId)
|
67
|
+
let iconContainer = document.getElementById(dataset.iconContainerId)
|
51
68
|
let detail = {
|
52
69
|
id: dataset.directUploadId,
|
53
70
|
fileName: dataset.uploadedFileName,
|
54
71
|
iconContainer: iconContainer
|
55
72
|
}
|
56
|
-
helpers.dispatchEvent(uploadedFile,
|
73
|
+
let event = helpers.dispatchEvent(uploadedFile, 'dnd-upload:placeholder', { detail })
|
74
|
+
if (!event.defaultPrevented) {
|
75
|
+
const { detail } = event
|
76
|
+
const { id, fileName, iconContainer } = detail
|
77
|
+
helpers.fileUploadUIPainter(iconContainer, id, fileName, true)
|
78
|
+
}
|
57
79
|
})
|
58
80
|
}
|
59
81
|
|
60
|
-
|
82
|
+
function createUploadersForFileInput (event) {
|
83
|
+
if (event.target.type === 'file' && event.target.dataset.dnd === 'true') {
|
84
|
+
const input = event.target
|
85
|
+
Array.from(input.files).forEach(file => createUploader(input, file))
|
86
|
+
input.value = null
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
function preventDragover (event) {
|
91
|
+
if (helpers.hasClassnameInHeirarchy(event.target, 'asdndzone')) {
|
92
|
+
event.preventDefault()
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
function createUploadersForDroppedFiles (event) {
|
97
|
+
let asdndz = helpers.getClassnameFromHeirarchy(event.target, 'asdndzone')
|
98
|
+
if (asdndz) {
|
99
|
+
event.preventDefault()
|
100
|
+
// get the input associated with this dndz
|
101
|
+
const input = document.getElementById(asdndz.dataset.dndInputId)
|
102
|
+
Array.from(event.dataTransfer.files).forEach(file => createUploader(input, file))
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
function removeFileFromQueue (event) {
|
107
|
+
if (event.target.dataset.dndDelete === 'true' && event.target.hasAttribute('data-direct-upload-id')) {
|
108
|
+
event.preventDefault()
|
109
|
+
document.querySelectorAll('[data-direct-upload-id="' + event.target.dataset.directUploadId + '"]').forEach(element => {
|
110
|
+
element.remove()
|
111
|
+
})
|
112
|
+
for (var i = 0; i < uploaders.length; i++) {
|
113
|
+
if (uploaders[i].upload.id === event.target.dataset.directUploadId) {
|
114
|
+
uploaders.splice(i, 1)
|
115
|
+
break
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
export function start () {
|
61
122
|
if (started) { return }
|
62
123
|
started = true
|
63
|
-
document.addEventListener(
|
64
|
-
document.addEventListener(
|
124
|
+
document.addEventListener('submit', didSubmitForm)
|
125
|
+
document.addEventListener('ajax:before', didSubmitRemoteElement)
|
126
|
+
document.addEventListener('dnd-uploads:process-upload-queue', processUploadQueue)
|
65
127
|
|
66
128
|
// input[type=file][data-dnd=true]
|
67
|
-
document.addEventListener(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
}
|
73
|
-
})
|
74
|
-
document.addEventListener("dragover", event => {
|
75
|
-
if(helpers.hasClassnameInHeirarchy(event.target, 'asdndzone')) {
|
76
|
-
event.preventDefault();
|
77
|
-
}
|
78
|
-
})
|
79
|
-
document.addEventListener("drop", event => {
|
80
|
-
let asdndz = helpers.getClassnameFromHeirarchy(event.target, 'asdndzone')
|
81
|
-
if(asdndz) {
|
82
|
-
event.preventDefault()
|
83
|
-
// get the input associated with this dndz
|
84
|
-
const input = document.getElementById(asdndz.dataset.dndInputId)
|
85
|
-
Array.from(event.dataTransfer.files).forEach(file => createUploader(input, file))
|
86
|
-
}
|
87
|
-
})
|
88
|
-
document.addEventListener("click", event => {
|
89
|
-
if( event.target.dataset.dndDelete == 'true' && event.target.hasAttribute('data-direct-upload-id') ) {
|
90
|
-
event.preventDefault();
|
91
|
-
document.querySelectorAll('[data-direct-upload-id="'+event.target.dataset.directUploadId+'"]').forEach(element => {
|
92
|
-
element.remove()
|
93
|
-
})
|
94
|
-
for(var i=0;i<uploaders.length;i++) {
|
95
|
-
if(uploaders[i].upload.id == event.target.dataset.directUploadId) {
|
96
|
-
uploaders.splice( i, 1 )
|
97
|
-
break
|
98
|
-
}
|
99
|
-
}
|
100
|
-
}
|
101
|
-
})
|
102
|
-
addEventListener("turbolinks:load", addAttachedFileIcons);
|
103
|
-
addEventListener("load", addAttachedFileIcons);
|
129
|
+
document.addEventListener('change', createUploadersForFileInput)
|
130
|
+
document.addEventListener('dragover', preventDragover)
|
131
|
+
document.addEventListener('drop', createUploadersForDroppedFiles)
|
132
|
+
document.addEventListener('click', removeFileFromQueue)
|
133
|
+
addAttachedFileIcons()
|
104
134
|
}
|