選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

upload_images_controller.js 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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.outputTarget.innerText = ''
  45. this.dropzoneTarget.classList.add('hidden')
  46. }
  47. const figure = document.createElement('figure')
  48. const img = document.createElement('img')
  49. img.file = image // Required for future upload, fragile?
  50. img.src = window.URL.createObjectURL(image)
  51. img.onload = event =>
  52. window.URL.revokeObjectURL(event.target.src)
  53. img.alt = 'Picture preview'
  54. figure.appendChild(img)
  55. const figcaption = document.createElement('figcaption')
  56. figcaption.innerText = imageName
  57. figure.appendChild(figcaption)
  58. this.outputTarget.appendChild(figure)
  59. })
  60. }
  61. submit(event) {
  62. event.preventDefault()
  63. const images = this.outputTarget.querySelectorAll('img')
  64. Array.from(images).forEach(image => {
  65. const formdata = new FormData()
  66. formdata.append('images', image.file)
  67. const options = {
  68. method: this.element.method,
  69. body: formdata
  70. }
  71. console.log(`Uploading "${image.file.name}"`)
  72. this._request(
  73. this.element.action,
  74. options,
  75. this._displayPercentage
  76. )
  77. .then(response => console.log('Uploaded!'))
  78. .catch(console.log.bind(console))
  79. })
  80. }
  81. _request(url, options = {}, onProgress) {
  82. // See https://github.com/github/fetch/issues/89#issuecomment-256610849
  83. return new Promise((resolve, reject) => {
  84. const xhr = new XMLHttpRequest()
  85. xhr.open(options.method || 'get', url)
  86. for (let header in options.headers || {})
  87. xhr.setRequestHeader(header, options.headers[header])
  88. xhr.onload = event => resolve(event.target.responseText)
  89. xhr.onerror = reject
  90. if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress
  91. xhr.send(options.body)
  92. })
  93. }
  94. _displayPercentage(event) {
  95. if (event.lengthComputable) {
  96. const percentage = Math.round(
  97. (event.loaded * 100) / event.total
  98. )
  99. console.log(percentage)
  100. }
  101. }
  102. }
  103. )