From 2120913329d4ad3a92a103c47a3e16d2d133d5d6 Mon Sep 17 00:00:00 2001 From: Exequiel Rozas Date: Mon, 27 Jan 2025 03:21:05 -0400 Subject: [PATCH] Add image uploads to the EasyMDE editor --- .../easy_mde_field/edit_component.html.erb | 1 + .../controllers/fields/easy_mde_controller.js | 69 +++++++++++++++++++ lib/avo/fields/easy_mde_field.rb | 12 +++- spec/dummy/app/avo/resources/project.rb | 2 +- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/app/components/avo/fields/easy_mde_field/edit_component.html.erb b/app/components/avo/fields/easy_mde_field/edit_component.html.erb index 7ed3b7f7ac..d5fcc96abc 100644 --- a/app/components/avo/fields/easy_mde_field/edit_component.html.erb +++ b/app/components/avo/fields/easy_mde_field/edit_component.html.erb @@ -7,6 +7,7 @@ view: view, 'easy-mde-target': 'element', 'component-options': @field.options.to_json, + upload_url: @field.options[:upload_url] }, disabled: disabled?, placeholder: @field.placeholder, diff --git a/app/javascript/js/controllers/fields/easy_mde_controller.js b/app/javascript/js/controllers/fields/easy_mde_controller.js index 3d504af39c..48947beef2 100644 --- a/app/javascript/js/controllers/fields/easy_mde_controller.js +++ b/app/javascript/js/controllers/fields/easy_mde_controller.js @@ -1,5 +1,6 @@ import { Controller } from '@hotwired/stimulus' import EasyMDE from 'easymde' +import { DirectUpload } from '@rails/activestorage' export default class extends Controller { static targets = ['element'] @@ -17,6 +18,7 @@ export default class extends Controller { } connect() { + const options = { element: this.elementTarget, spellChecker: this.componentOptions.spell_checker, @@ -28,9 +30,76 @@ export default class extends Controller { options.status = false } + + if (this.componentOptions.image_upload) { + this.#configureImageUploads(options) + } + const easyMde = new EasyMDE(options) if (this.view === 'show') { easyMde.codemirror.options.readOnly = true } } + + #configureImageUploads(options) { + options.uploadImage = true + options.imageUploadEndpoint = this.elementTarget.dataset.uploadUrl + options.imageUploadFunction = this.#handleImageUpload.bind(this) + options.imageAccept = 'image/*' + options.previewImagesInEditor = true + options.toolbar = this.toolbarItems + return options + } + + #handleImageUpload(file, onSuccess, onError) { + const upload = new DirectUpload(file, this.elementTarget.dataset.uploadUrl) + upload.create((error, blob) => { + if (error) return onError(error) + const imageUrl = this.#encodedImageUrl(blob) + onSuccess(imageUrl) + }) + } + + #encodedImageUrl(blob) { + return `/rails/active_storage/blobs/redirect/${ + blob.signed_id + }/${encodeURIComponent(blob.filename)}` + } + + get toolbarItems() { + const baseItems = [ + 'bold', + 'italic', + 'heading', + '|', + 'quote', + 'unordered-list', + 'ordered-list', + '|', + 'link', + 'image', + ] + + const uploadImageItem = this.componentOptions.image_upload + ? [ + { + name: 'upload-image', + action: EasyMDE.drawUploadedImage, + className: 'fa fa-file-picture-o', + title: 'Upload & insert image', + }, + ] + : [] + + return [ + ...baseItems, + ...uploadImageItem, + '|', + 'preview', + 'side-by-side', + 'fullscreen', + '|', + 'guide', + ] + } } diff --git a/lib/avo/fields/easy_mde_field.rb b/lib/avo/fields/easy_mde_field.rb index 2dc572fa79..d9daba3366 100644 --- a/lib/avo/fields/easy_mde_field.rb +++ b/lib/avo/fields/easy_mde_field.rb @@ -10,13 +10,23 @@ def initialize(id, **args, &block) @always_show = args[:always_show].present? ? args[:always_show] : false @height = args[:height].present? ? args[:height].to_s : "auto" + @upload_url = args[:upload_url].present? ? args[:upload_url] : direct_uploads_url + @image_upload = args[:image_upload].present? ? args[:image_upload] : false @spell_checker = args[:spell_checker].present? ? args[:spell_checker] : false @options = { spell_checker: @spell_checker, always_show: @always_show, - height: @height + height: @height, + image_upload: @image_upload, + upload_url: direct_uploads_url } end + + private + + def direct_uploads_url + "/rails/active_storage/direct_uploads" + end end end end diff --git a/spec/dummy/app/avo/resources/project.rb b/spec/dummy/app/avo/resources/project.rb index 8e81a8a413..710ed63fba 100644 --- a/spec/dummy/app/avo/resources/project.rb +++ b/spec/dummy/app/avo/resources/project.rb @@ -60,7 +60,7 @@ def fields relative: true, timezone: "EET", format: "MMMM dd, y HH:mm:ss z" - field :description, as: :easy_mde, height: "350px" + field :description, as: :easy_mde, height: "350px", image_upload: true field :files, as: :files, translation_key: "avo.field_translations.files",