You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

upload_images_controller.js 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. Resources:
  3. - https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications
  4. - https://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/
  5. - https://eloquentjavascript.net/18_http.html
  6. */
  7. application.register(
  8. 'upload-images',
  9. class extends Stimulus.Controller {
  10. static get targets() {
  11. return ['input', 'output', 'dropzone']
  12. }
  13. openFileSelector() {
  14. this.inputTarget.click()
  15. }
  16. addActiveClass(event) {
  17. event.preventDefault()
  18. this.dropzoneTarget.classList.add('active')
  19. }
  20. removeActiveClass() {
  21. this.dropzoneTarget.classList.remove('active')
  22. }
  23. handleImages(event) {
  24. event.preventDefault()
  25. let images = []
  26. if (event.type == 'change') {
  27. images = event.target.files
  28. } else if (event.type == 'drop') {
  29. images = event.dataTransfer.files
  30. }
  31. Array.from(images).forEach(image => {
  32. const imageName = image.name
  33. const imageSize = image.size
  34. const isOversized =
  35. Math.round(imageSize / 1024) >
  36. Number(this.data.get('maxSizeKb'))
  37. if (isOversized) {
  38. this.outputTarget.classList.add('oversized')
  39. this.outputTarget.innerText = `Oversized!`
  40. this.inputTarget.value = ''
  41. return
  42. } else {
  43. this.outputTarget.classList.remove('oversized')
  44. this.dropzoneTarget.classList.add('hidden')
  45. }
  46. const figure = document.createElement('figure')
  47. const img = document.createElement('img')
  48. img.file = image // Required for future upload, fragile?
  49. img.src = window.URL.createObjectURL(image)
  50. img.onload = event =>
  51. window.URL.revokeObjectURL(event.target.src)
  52. img.alt = 'Picture preview'
  53. figure.appendChild(img)
  54. const figcaption = document.createElement('figcaption')
  55. figcaption.innerText = imageName
  56. figure.appendChild(figcaption)
  57. this.outputTarget.appendChild(figure)
  58. })
  59. }
  60. submit(event) {
  61. event.preventDefault()
  62. const images = this.outputTarget.querySelectorAll('img')
  63. Array.from(images).forEach(image => {
  64. const formdata = new FormData()
  65. formdata.append('images', image.file)
  66. const options = {
  67. method: this.element.method,
  68. body: formdata
  69. }
  70. console.log(`Uploading "${image.file.name}"`)
  71. this._request(
  72. this.element.action,
  73. options,
  74. this._displayPercentage
  75. )
  76. .then(response => console.log('Uploaded!'))
  77. .catch(console.log.bind(console))
  78. })
  79. }
  80. _request(url, options = {}, onProgress) {
  81. // See https://github.com/github/fetch/issues/89#issuecomment-256610849
  82. return new Promise((resolve, reject) => {
  83. const xhr = new XMLHttpRequest()
  84. xhr.open(options.method || 'get', url)
  85. for (let header in options.headers || {})
  86. xhr.setRequestHeader(header, options.headers[header])
  87. xhr.onload = event => resolve(event.target.responseText)
  88. xhr.onerror = reject
  89. if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress
  90. xhr.send(options.body)
  91. })
  92. }
  93. _displayPercentage(event) {
  94. if (event.lengthComputable) {
  95. const percentage = Math.round(
  96. (event.loaded * 100) / event.total
  97. )
  98. console.log(percentage)
  99. }
  100. }
  101. }
  102. )