diff --git a/app/javascript/controllers/file_preview_controller.js b/app/javascript/controllers/file_preview_controller.js new file mode 100644 index 00000000..9eaaab2d --- /dev/null +++ b/app/javascript/controllers/file_preview_controller.js @@ -0,0 +1,19 @@ +import { Controller } from 'stimulus' +import bsCustomFileInput from "bs-custom-file-input"; + +document.addEventListener("turbolinks:load", () => { + bsCustomFileInput.init(); +}); + +export default class extends Controller { + static targets = ["preview", "input"]; + + connect() { + } + + update(event = undefined) { + if (!this.hasPreviewTarget) return; + + this.previewTarget.src = window.URL.createObjectURL(this.inputTarget.files[0]) + } +} diff --git a/app/javascript/etc/image_preview.js b/app/javascript/etc/image_preview.js deleted file mode 100644 index fcdeec85..00000000 --- a/app/javascript/etc/image_preview.js +++ /dev/null @@ -1,11 +0,0 @@ -document.addEventListener('turbolinks:load', () => { - document.querySelectorAll('input[type=file]').forEach(file => { - if (!file.dataset.preview) return - - file.addEventListener('change', event => { - if (file.files.length === 0) return - - document.querySelector('#' + file.dataset.preview).src = window.URL.createObjectURL(file.files[0]) - }) - }) -}) diff --git a/app/javascript/etc/index.js b/app/javascript/etc/index.js index 9ee6a95a..3a1ef75c 100644 --- a/app/javascript/etc/index.js +++ b/app/javascript/etc/index.js @@ -1,5 +1,4 @@ import './external_links' -import './image_preview' import './input-date' import './input-tag' import './prosemirror' diff --git a/app/views/posts/attributes/_file.haml b/app/views/posts/attributes/_file.haml index 54f9f81a..20c27399 100644 --- a/app/views/posts/attributes/_file.haml +++ b/app/views/posts/attributes/_file.haml @@ -1,12 +1,14 @@ -.form-group +.form-group{ data: { controller: 'file-preview' } } - if metadata.static_file - case metadata.static_file.blob.content_type - when %r{\Avideo/} = video_tag url_for(metadata.static_file), - controls: true, class: 'img-fluid' + controls: true, class: 'img-fluid', + data: { target: 'file-preview.preview' } - when %r{\Aaudio/} = audio_tag url_for(metadata.static_file), - controls: true, class: 'img-fluid' + controls: true, class: 'img-fluid', + data: { target: 'file-preview.preview' } - when 'application/pdf' %iframe{ src: url_for(metadata.static_file) } - else @@ -24,7 +26,7 @@ = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", - data: { preview: "#{attribute}-preview" }) + data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' = render 'posts/attribute_feedback', diff --git a/app/views/posts/attributes/_image.haml b/app/views/posts/attributes/_image.haml index 84fe56fd..241a78e8 100644 --- a/app/views/posts/attributes/_image.haml +++ b/app/views/posts/attributes/_image.haml @@ -1,9 +1,9 @@ -.form-group +.form-group{ data: { controller: 'file-preview' } } - if metadata.static_file = image_tag url_for(metadata.static_file), alt: metadata.value['description'], class: 'img-fluid', - id: "#{attribute}-preview" + data: { target: 'file-preview.preview' } -# Mantener el valor si no enviamos ninguna imagen = hidden_field_tag "#{base}[#{attribute}][path]", metadata.value['path'] @@ -16,13 +16,14 @@ = image_tag '', alt: metadata.value['description'], class: 'img-fluid', - id: "#{attribute}-preview" + data: { target: 'file-preview.preview' } .custom-file = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", - accept: ActiveStorage.web_image_content_types.join(','), data: { preview: "#{attribute}-preview" }) + accept: ActiveStorage.web_image_content_types.join(','), + data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' = render 'posts/attribute_feedback', diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 91d287e0..c07c7751 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -7,7 +7,7 @@ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy Rails.application.config.content_security_policy do |policy| - policy.default_src :self + policy.default_src :self, :blob # XXX: Varios scripts generan estilos en línea policy.style_src :self, :unsafe_inline, :https # Repetimos la default para poder saber cuál es la política en falta diff --git a/package.json b/package.json index 74ff491a..eea0473f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@rails/webpacker": "5.4.4", "@suttyweb/editor": "^0.1.27", "babel-loader": "^8.2.2", + "bs-custom-file-input": "^1.3.4", "chart.js": "^3.5.1", "chartkick": "^4.0.5", "circular-dependency-plugin": "^5.2.2", diff --git a/yarn.lock b/yarn.lock index 829b7ed1..7a81a221 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2699,6 +2699,11 @@ browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +bs-custom-file-input@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz#c275cb8d4f1c02ba026324292509fa9a747dbda8" + integrity sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA== + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz"