active_storage_drag_and_drop 0.3.5 → 0.4.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.
- 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
|
}
|