DragDrop.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import Utils from '../core/Utils'
  2. import Plugin from './Plugin'
  3. /**
  4. * Drag & Drop plugin
  5. *
  6. */
  7. export default class DragDrop extends Plugin {
  8. constructor (core, opts) {
  9. super(core, opts)
  10. this.type = 'selecter'
  11. // Default options
  12. const defaultOptions = {
  13. target: '.UppyDragDrop'
  14. }
  15. // Merge default options with the ones set by user
  16. this.opts = Object.assign({}, defaultOptions, opts)
  17. // Check for browser dragDrop support
  18. this.isDragDropSupported = this.checkDragDropSupport()
  19. // Bind `this` to class methods
  20. this.initEvents = this.initEvents.bind(this)
  21. this.handleDrop = this.handleDrop.bind(this)
  22. this.checkDragDropSupport = this.checkDragDropSupport.bind(this)
  23. this.handleInputChange = this.handleInputChange.bind(this)
  24. }
  25. render () {
  26. return `<form class="UppyDragDrop-inner"
  27. method="post"
  28. action="${this.opts.endpoint}"
  29. enctype="multipart/form-data">
  30. <input class="UppyDragDrop-input"
  31. id="UppyDragDrop-input"
  32. type="file"
  33. name="files[]"
  34. multiple />
  35. <label class="UppyDragDrop-label" for="UppyDragDrop-input">
  36. <strong>${this.core.i18n('chooseFile')}</strong>
  37. <span class="UppyDragDrop-dragText">${this.core.i18n('orDragDrop')}</span>.
  38. </label>
  39. ${!this.core.opts.autoProceed
  40. ? `<button class="UppyDragDrop-uploadBtn" type="submit">${this.core.i18n('upload')}</button>`
  41. : ''}
  42. </form>`
  43. }
  44. /**
  45. * Checks if the browser supports Drag & Drop,
  46. * not supported on mobile devices, for example.
  47. * @return {Boolean} true if supported, false otherwise
  48. */
  49. checkDragDropSupport () {
  50. const div = document.createElement('div')
  51. if (!('draggable' in div) || !('ondragstart' in div && 'ondrop' in div)) {
  52. return false
  53. }
  54. if (!('FormData' in window)) {
  55. return false
  56. }
  57. if (!('FileReader' in window)) {
  58. return false
  59. }
  60. return true
  61. }
  62. initEvents () {
  63. this.core.log(`waiting for some files to be dropped on ${this.target}`)
  64. // prevent default actions for all drag & drop events
  65. const strEvents = 'drag dragstart dragend dragover dragenter dragleave drop'
  66. Utils.addListenerMulti(this.dropzone, strEvents, (e) => {
  67. e.preventDefault()
  68. e.stopPropagation()
  69. })
  70. // Toggle is-dragover state when files are dragged over or dropped
  71. Utils.addListenerMulti(this.dropzone, 'dragover dragenter', (e) => {
  72. Utils.addClass(this.container, 'is-dragover')
  73. })
  74. Utils.addListenerMulti(this.dropzone, 'dragleave dragend drop', (e) => {
  75. Utils.removeClass(this.container, 'is-dragover')
  76. })
  77. const onDrop = new Promise((resolve, reject) => {
  78. this.dropzone.addEventListener('drop', (e) => {
  79. resolve(this.handleDrop.bind(null, e))
  80. })
  81. })
  82. const onInput = new Promise((resolve, reject) => {
  83. this.input.addEventListener('change', (e) => {
  84. resolve(this.handleInputChange.bind(null, e))
  85. })
  86. })
  87. this.container.addEventListener('progress', (e) => {
  88. const percentage = e.detail
  89. this.setProgress(percentage)
  90. })
  91. // document.addEventListener('dragover', (e) => {
  92. // console.log('ну пиздец')
  93. // })
  94. return Promise.race([onDrop, onInput]).then(handler => handler())
  95. }
  96. handleDrop (e) {
  97. this.core.log('all right, someone dropped something...')
  98. const files = e.dataTransfer.files
  99. return this.result(files)
  100. }
  101. handleInputChange () {
  102. this.core.log('all right, something selected through input...')
  103. const files = this.input.files
  104. return this.result(files)
  105. }
  106. result (files) {
  107. return new Promise((resolve, reject) => {
  108. const result = {from: 'DragDrop', files}
  109. // if autoProceed is false, wait for upload button to be pushed,
  110. // otherwise just pass files to uploaders right away
  111. if (this.core.opts.autoProceed) {
  112. return resolve(result)
  113. } else {
  114. this.dropzone.addEventListener('submit', (e) => {
  115. e.preventDefault()
  116. return resolve(result)
  117. })
  118. }
  119. })
  120. }
  121. install () {
  122. // Initialize dragdrop component, mount it to container DOM node
  123. // this.container = document.querySelector(this.opts.target)
  124. // this.container.innerHTML = this.render()
  125. const caller = this
  126. this.target = this.getTarget(this.opts.target, caller)
  127. this.container = document.querySelector(this.target)
  128. this.container.innerHTML = this.render()
  129. // this.target.innerHTML = this.render()
  130. // Set selectors
  131. this.dropzone = document.querySelector(`${this.target} .UppyDragDrop-inner`)
  132. this.input = document.querySelector(`${this.target} .UppyDragDrop-input`)
  133. Utils.addClass(this.container, 'UppyDragDrop')
  134. if (this.isDragDropSupported) {
  135. Utils.addClass(this.container, 'is-dragdrop-supported')
  136. }
  137. }
  138. run (results) {
  139. this.core.log({
  140. class: this.constructor.name,
  141. method: 'run',
  142. results: results
  143. })
  144. return this.initEvents()
  145. }
  146. }