From bc27f98be7e68571a1da1ef57215d22791cf9397 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 5 Nov 2024 17:28:38 +0100 Subject: [PATCH 01/12] fix: update condition to not empty input value if image is present --- app/packs/src/decidim/editor.js | 152 ++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 app/packs/src/decidim/editor.js diff --git a/app/packs/src/decidim/editor.js b/app/packs/src/decidim/editor.js new file mode 100644 index 0000000000..09c47e47ee --- /dev/null +++ b/app/packs/src/decidim/editor.js @@ -0,0 +1,152 @@ +/* eslint-disable require-jsdoc */ + +import lineBreakButtonHandler from "src/decidim/editor/linebreak_module"; +import "src/decidim/editor/clipboard_override"; +import "src/decidim/vendor/image-resize.min"; +import "src/decidim/vendor/image-upload.min"; + +const quillFormats = [ + "bold", + "italic", + "link", + "underline", + "header", + "list", + "alt", + "break", + "width", + "style", + "code", + "blockquote", + "indent" +]; + +export default function createQuillEditor(container) { + const toolbar = $(container).data("toolbar"); + const disabled = $(container).data("disabled"); + + const allowedEmptyContentSelector = "iframe"; + let quillToolbar = [ + ["bold", "italic", "underline", "linebreak"], + [{ list: "ordered" }, { list: "bullet" }], + ["link", "clean"], + ["code", "blockquote"], + [{ indent: "-1" }, { indent: "+1" }] + ]; + + let addImage = false; + let addVideo = false; + + /** + * - basic = only basic controls without titles + * - content = basic + headings + * - full = basic + headings + image + video + */ + if (toolbar === "content") { + quillToolbar = [[{ header: [2, 3, 4, 5, 6, false] }], ...quillToolbar]; + } else if (toolbar === "full") { + addImage = true; + addVideo = true; + quillToolbar = [ + [{ header: [2, 3, 4, 5, 6, false] }], + ...quillToolbar, + ["video"], + ["image"] + ]; + } + + let modules = { + linebreak: {}, + toolbar: { + container: quillToolbar, + handlers: { + linebreak: lineBreakButtonHandler + } + } + }; + + const $input = $(container).siblings('input[type="hidden"]'); + container.innerHTML = $input.val() || ""; + const token = $('meta[name="csrf-token"]').attr("content"); + + if (addVideo) { + quillFormats.push("video"); + } + + if (addImage) { + // Attempt to allow images only if the image support is enabled at editor support. + // see: https://github.com/quilljs/quill/issues/1108 + quillFormats.push("image"); + + modules.imageResize = { + modules: ["Resize", "DisplaySize"] + }; + modules.imageUpload = { + url: $(container).data("uploadImagesPath"), + method: "POST", + name: "image", + withCredentials: false, + headers: { "X-CSRF-Token": token }, + callbackOK: (serverResponse, next) => { + $("div.ql-toolbar").last().removeClass("editor-loading"); + next(serverResponse.url); + }, + callbackKO: (serverError) => { + $("div.ql-toolbar").last().removeClass("editor-loading"); + console.log(`Image upload error: ${serverError.message}`); + }, + checkBeforeSend: (file, next) => { + $("div.ql-toolbar").last().addClass("editor-loading"); + next(file); + } + }; + + const text = $(container).data("dragAndDropHelpText"); + $(container).after( + `

${text}

` + ); + } + const quill = new Quill(container, { + modules: modules, + formats: quillFormats, + theme: "snow" + }); + + if (addImage === false) { + // Firefox natively implements image drop in contenteditable which is why we need to disable that + quill.root.addEventListener("drop", (ev) => ev.preventDefault()); + } + + if (disabled) { + quill.disable(); + } + + quill.on("text-change", () => { + + const text = quill.getText(); + // Triggers CustomEvent with the cursor position + // It is required in input_mentions.js + let event = new CustomEvent("quill-position", { + detail: quill.getSelection() + }); + container.dispatchEvent(event); + + if ( + (text === "\n" || text === "\n\n") && + quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0 && !$input.val().match(/img/) + ) { + $input.val(""); + } else { + const emptyParagraph = "


"; + const cleanHTML = quill.root.innerHTML.replace( + new RegExp(`^${emptyParagraph}|${emptyParagraph}$`, "g"), + "" + ); + $input.val(cleanHTML); + } + }); + // After editor is ready, linebreak_module deletes two extraneous new lines + quill.emitter.emit("editor-ready"); + + return quill; +} From eb237ec9dd4e4294d3877ce7f0e38ed662f5a3b7 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 5 Nov 2024 17:29:13 +0100 Subject: [PATCH 02/12] test: add system test to check for input value --- ...manages_survey_question_with_image_spec.rb | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 spec/system/admin/admin_manages_survey_question_with_image_spec.rb diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb new file mode 100644 index 0000000000..a50c0da1ab --- /dev/null +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe "Admin manages survey question with image", type: :system do + let(:manifest_name) { "surveys" } + let!(:component) do + create(:component, + manifest: manifest, + participatory_space: participatory_space, + published_at: nil) + end + let!(:questionnaire) { create(:questionnaire) } + let!(:survey) { create :survey, component: component, questionnaire: questionnaire } + + include_context "when managing a component as an admin" + + context "when survey is not published" do + before do + component.unpublish! + end + + let(:description_with_image) do + { + en: + <<~HTML +

+ HTML + } + end + + let!(:question) { create(:questionnaire_question, description: description_with_image, questionnaire: questionnaire) } + + it "after save, it renders image in description with hidden input value filled" do + Capybara.ignore_hidden_elements = false + visit questionnaire_edit_path + click_button "Save" + click_button "Expand all" + within "#questionnaire_question_#{question.id}-field" do + within "#questionnaire_question_#{question.id}-description-panel-0" do + description = find(".ql-editor p") + expect(description).to have_xpath('//img[@src="http://mon_image.png"]') + input = page.find("#questionnaire_questions_#{question.id}_description_en") + expect(input.value).to eq('

') + end + end + end + end + + def questionnaire_edit_path + manage_component_path(component) + end +end From 9c3d334cdfc4f5b8263f546adf6fb59b5a210cf6 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 09:38:38 +0100 Subject: [PATCH 03/12] test: update check for image --- .../admin/admin_manages_survey_question_with_image_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index a50c0da1ab..5545edead3 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -39,7 +39,7 @@ within "#questionnaire_question_#{question.id}-field" do within "#questionnaire_question_#{question.id}-description-panel-0" do description = find(".ql-editor p") - expect(description).to have_xpath('//img[@src="http://mon_image.png"]') + expect(description).to have_css("img[src='http://mon_image.png']") input = page.find("#questionnaire_questions_#{question.id}_description_en") expect(input.value).to eq('

') end From eed0d645e4b023f041aa34283fedad016fc377cf Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 10:17:57 +0100 Subject: [PATCH 04/12] test: update img check again --- .../admin/admin_manages_survey_question_with_image_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index 5545edead3..6897a803a1 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -36,10 +36,9 @@ visit questionnaire_edit_path click_button "Save" click_button "Expand all" + expect(page).to have_xpath('//img[@src="http://mon_image.png"]') within "#questionnaire_question_#{question.id}-field" do within "#questionnaire_question_#{question.id}-description-panel-0" do - description = find(".ql-editor p") - expect(description).to have_css("img[src='http://mon_image.png']") input = page.find("#questionnaire_questions_#{question.id}_description_en") expect(input.value).to eq('

') end From 76c855e9363be142fa6ef207174628602afa099a Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 10:56:30 +0100 Subject: [PATCH 05/12] test: last update check img --- .../admin/admin_manages_survey_question_with_image_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index 6897a803a1..90af943e33 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -36,7 +36,7 @@ visit questionnaire_edit_path click_button "Save" click_button "Expand all" - expect(page).to have_xpath('//img[@src="http://mon_image.png"]') + expect(page).to have_css("img[src$='mon_image.png']") within "#questionnaire_question_#{question.id}-field" do within "#questionnaire_question_#{question.id}-description-panel-0" do input = page.find("#questionnaire_questions_#{question.id}_description_en") From adcf21f8a0acf659aaac3b37ebf71afc12ccf2a9 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 11:08:39 +0100 Subject: [PATCH 06/12] test: update --- .../admin/admin_manages_survey_question_with_image_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index 90af943e33..8feacffba1 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -31,12 +31,11 @@ let!(:question) { create(:questionnaire_question, description: description_with_image, questionnaire: questionnaire) } - it "after save, it renders image in description with hidden input value filled" do + it "after save, it renders description with hidden input value filled" do Capybara.ignore_hidden_elements = false visit questionnaire_edit_path click_button "Save" click_button "Expand all" - expect(page).to have_css("img[src$='mon_image.png']") within "#questionnaire_question_#{question.id}-field" do within "#questionnaire_question_#{question.id}-description-panel-0" do input = page.find("#questionnaire_questions_#{question.id}_description_en") From 9b50298b274f7d9b966cbe07ac1409ec9e4896c2 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 12:08:44 +0100 Subject: [PATCH 07/12] test: another update --- ...dmin_manages_survey_question_with_image_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index 8feacffba1..96c483a61c 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -19,16 +19,15 @@ before do component.unpublish! end - + let(:image_url) { "https://unsplash.com/fr/photos/une-trainee-detoiles-est-vue-dans-le-ciel-au-dessus-de-locean-pjHseB_JLpg" } + let(:router) { Decidim::EngineRouter.main_proxy(component) } let(:description_with_image) do { - en: - <<~HTML -

- HTML + "en" => "

", + "ca" => "

", + "es" => "

" } end - let!(:question) { create(:questionnaire_question, description: description_with_image, questionnaire: questionnaire) } it "after save, it renders description with hidden input value filled" do @@ -36,10 +35,11 @@ visit questionnaire_edit_path click_button "Save" click_button "Expand all" + expect(page).to have_selector("img[src='#{image_url}']") within "#questionnaire_question_#{question.id}-field" do within "#questionnaire_question_#{question.id}-description-panel-0" do input = page.find("#questionnaire_questions_#{question.id}_description_en") - expect(input.value).to eq('

') + expect(input.value).to eq("

") end end end From a316833c61edd008a8fe1a7e6be8232a4dcc49d8 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 13:24:48 +0100 Subject: [PATCH 08/12] test: if img is present --- ...n_manages_survey_question_with_image_spec.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index 96c483a61c..de83de9476 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -19,6 +19,7 @@ before do component.unpublish! end + let(:image_url) { "https://unsplash.com/fr/photos/une-trainee-detoiles-est-vue-dans-le-ciel-au-dessus-de-locean-pjHseB_JLpg" } let(:router) { Decidim::EngineRouter.main_proxy(component) } let(:description_with_image) do @@ -33,15 +34,17 @@ it "after save, it renders description with hidden input value filled" do Capybara.ignore_hidden_elements = false visit questionnaire_edit_path - click_button "Save" click_button "Expand all" expect(page).to have_selector("img[src='#{image_url}']") - within "#questionnaire_question_#{question.id}-field" do - within "#questionnaire_question_#{question.id}-description-panel-0" do - input = page.find("#questionnaire_questions_#{question.id}_description_en") - expect(input.value).to eq("

") - end - end + #click_button "Save" + #click_button "Expand all" + #expect(page).to have_selector("img[src='#{image_url}']") + #within "#questionnaire_question_#{question.id}-field" do + # within "#questionnaire_question_#{question.id}-description-panel-0" do + # input = page.find("#questionnaire_questions_#{question.id}_description_en") + # expect(input.value).to eq("

") + # end + #end end end From aa22461b3ddf2076e387f7843f03c418804e2bbe Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 13:53:46 +0100 Subject: [PATCH 09/12] test: update other test to avoid ambiguous selector error --- ...uestion_in_questionnaire_templates_spec.rb | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/spec/system/admin/admin_updates_question_in_questionnaire_templates_spec.rb b/spec/system/admin/admin_updates_question_in_questionnaire_templates_spec.rb index b6d207ae0e..d574bb286d 100644 --- a/spec/system/admin/admin_updates_question_in_questionnaire_templates_spec.rb +++ b/spec/system/admin/admin_updates_question_in_questionnaire_templates_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe "Admin adds display condition to template's questionniaire question", type: :system do +describe "Admin adds display condition to template's questionnaire question", type: :system do let!(:organization) { create(:organization) } let!(:user) { create(:user, :admin, :confirmed, organization: organization) } let(:template) { create(:questionnaire_template, organization: organization) } @@ -23,14 +23,16 @@ # expand question two find("[data-toggle$=button--expand-question-questionnaire_question_#{question_two.id}]").click # add display condition - find(".add-display-condition").click - # select question - select translated(question_one.body), from: "questionnaire[questions][#{question_two.id}][display_conditions][questionnaire-display-condition-id][decidim_condition_question_id]" - # select equal - select "Equal", from: "questionnaire[questions][#{question_two.id}][display_conditions][questionnaire-display-condition-id][condition_type]" - # validate we have the 2 answer options from question one in the select - select = find("#questionnaire_questions_#{question_two.id}_display_conditions_questionnaire-display-condition-id_decidim_answer_option_id") - expect(select).to have_content(translated(question_one.answer_options.first.body)) - expect(select).to have_content(translated(question_one.answer_options.last.body)) + within "#questionnaire_question_#{question_two.id}-question-card" do + find(".add-display-condition").click + # select question + select translated(question_one.body), from: "questionnaire[questions][#{question_two.id}][display_conditions][questionnaire-display-condition-id][decidim_condition_question_id]" + # select equal + select "Equal", from: "questionnaire[questions][#{question_two.id}][display_conditions][questionnaire-display-condition-id][condition_type]" + # validate we have the 2 answer options from question one in the select + select = find("#questionnaire_questions_#{question_two.id}_display_conditions_questionnaire-display-condition-id_decidim_answer_option_id") + expect(select).to have_content(translated(question_one.answer_options.first.body)) + expect(select).to have_content(translated(question_one.answer_options.last.body)) + end end end From 8215754a5e2e9dbce53b3add22a3f40715adcea4 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 13:54:22 +0100 Subject: [PATCH 10/12] test: update to see if image is presnet after save --- .../admin/admin_manages_survey_question_with_image_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb index de83de9476..87318e1c37 100644 --- a/spec/system/admin/admin_manages_survey_question_with_image_spec.rb +++ b/spec/system/admin/admin_manages_survey_question_with_image_spec.rb @@ -36,9 +36,9 @@ visit questionnaire_edit_path click_button "Expand all" expect(page).to have_selector("img[src='#{image_url}']") - #click_button "Save" - #click_button "Expand all" - #expect(page).to have_selector("img[src='#{image_url}']") + click_button "Save" + click_button "Expand all" + expect(page).to have_selector("img[src='#{image_url}']") #within "#questionnaire_question_#{question.id}-field" do # within "#questionnaire_question_#{question.id}-description-panel-0" do # input = page.find("#questionnaire_questions_#{question.id}_description_en") From cb8adee7deb9f6cfdbaf4c28668b7e105c698591 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 6 Nov 2024 15:30:24 +0100 Subject: [PATCH 11/12] fix: override editor js in decidim_awesome --- .../decidim/decidim_awesome/editors/editor.js | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 app/packs/src/decidim/decidim_awesome/editors/editor.js diff --git a/app/packs/src/decidim/decidim_awesome/editors/editor.js b/app/packs/src/decidim/decidim_awesome/editors/editor.js new file mode 100644 index 0000000000..7bec3c9396 --- /dev/null +++ b/app/packs/src/decidim/decidim_awesome/editors/editor.js @@ -0,0 +1,214 @@ +/* eslint-disable require-jsdoc, func-style */ + +/* +* Since version 0.25 we follow a different strategy and opt to destroy and override completely the original editor +* That's because editors are instantiated directly instead of creating a global function to instantiate them +*/ + +import lineBreakButtonHandler from "src/decidim/editor/linebreak_module" +import InscrybMDE from "inscrybmde" +import Europa from "europa" +import "inline-attachment/src/inline-attachment"; +import "inline-attachment/src/codemirror-4.inline-attachment"; +import "inline-attachment/src/jquery.inline-attachment"; +import hljs from "highlight.js"; +import "highlight.js/styles/github.css"; +import "src/decidim/editor/clipboard_override" +import "src/decidim/vendor/image-resize.min" +import "src/decidim/vendor/image-upload.min" +import { marked } from "marked"; + +const DecidimAwesome = window.DecidimAwesome || {}; +const quillFormats = ["bold", "italic", "link", "underline", "header", "list", "video", "image", "alt", "break", "width", "style", "code", "blockquote", "indent"]; + +// A tricky way to destroy the quill editor +export function destroyQuillEditor(container) { + if (container) { + const content = $(container).find(".ql-editor").html(); + $(container).html(content); + $(container).siblings(".ql-toolbar").remove(); + $(container).find("*[class*='ql-']").removeClass((index, className) => (className.match(/(^|\s)ql-\S+/g) || []).join(" ")); + $(container).removeClass((index, className) => (className.match(/(^|\s)ql-\S+/g) || []).join(" ")); + if ($(container).next().is("p.help-text")) { + $(container).next().remove(); + } + } + else { + console.error(`editor [${container}] not exists`); + } +} + +export function createQuillEditor(container) { + const toolbar = $(container).data("toolbar"); + const disabled = $(container).data("disabled"); + const allowedEmptyContentSelector = "iframe,img"; + + let quillToolbar = [ + ["bold", "italic", "underline", "linebreak"], + [{ list: "ordered" }, { list: "bullet" }], + ["link", "clean"], + ["code", "blockquote"], + [{ "indent": "-1"}, { "indent": "+1" }] + ]; + + let addImage = false; + + if (toolbar === "full") { + quillToolbar = [ + [{ header: [2, 3, 4, 5, 6, false] }], + ...quillToolbar + ]; + if (DecidimAwesome.allow_images_in_full_editor) { + quillToolbar.push(["video", "image"]); + addImage = true; + } else { + quillToolbar.push(["video"]); + } + } else if (toolbar === "basic") { + if (DecidimAwesome.allow_images_in_small_editor) { + quillToolbar.push(["video", "image"]); + addImage = true; + } else { + quillToolbar.push(["video"]); + } + } else if (DecidimAwesome.allow_images_in_small_editor) { + quillToolbar.push(["image"]); + addImage = true; + } + + let modules = { + linebreak: {}, + toolbar: { + container: quillToolbar, + handlers: { + "linebreak": lineBreakButtonHandler + } + } + }; + + const $input = $(container).siblings('input[type="hidden"]'); + container.innerHTML = $input.val() || ""; + const token = $('meta[name="csrf-token"]').attr("content"); + if (addImage) { + modules.imageResize = { + modules: ["Resize", "DisplaySize"] + } + modules.imageUpload = { + url: DecidimAwesome.editor_uploader_path, + method: "POST", + name: "image", + withCredentials: false, + headers: { "X-CSRF-Token": token }, + callbackOK: (serverResponse, next) => { + $("div.ql-toolbar").last().removeClass("editor-loading") + next(serverResponse.url); + }, + callbackKO: (serverError) => { + $("div.ql-toolbar").last().removeClass("editor-loading") + let msg = serverError && serverError.body; + try { + msg = JSON.parse(msg).message; + } catch (evt) { console.error("Parsing error", evt); } + console.error(`Image upload error: ${msg}`); + let $p = $(`

${msg}

`); + $(container).after($p) + setTimeout(() => { + $p.fadeOut(1000, () => { + $p.destroy(); + }); + }, 3000); + }, + checkBeforeSend: (file, next) => { + $("div.ql-toolbar").last().addClass("editor-loading") + next(file); + } + } + } + const quill = new Quill(container, { + modules: modules, + formats: quillFormats, + theme: "snow" + }); + + if (disabled) { + quill.disable(); + } + + quill.on("text-change", () => { + const text = quill.getText(); + + // Triggers CustomEvent with the cursor position + // It is required in input_mentions.js + let event = new CustomEvent("quill-position", { + detail: quill.getSelection() + }); + container.dispatchEvent(event); + + if ((text === "\n" || text === "\n\n") && quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0 + && !$input.val().match(/img/)) { + $input.val(""); + } else { + const emptyParagraph = "


"; + const cleanHTML = quill.root.innerHTML.replace( + new RegExp(`^${emptyParagraph}|${emptyParagraph}$`, "g"), + "" + ); + $input.val(cleanHTML); + } + }); + // After editor is ready, linebreak_module deletes two extraneous new lines + quill.emitter.emit("editor-ready"); + + if (addImage) { + const text = $(container).data("dragAndDropHelpText") || DecidimAwesome.texts.drag_and_drop_image; + $(container).after(`

${text}

`); + } + + // After editor is ready, linebreak_module deletes two extraneous new lines + quill.emitter.emit("editor-ready"); + + return quill; +} + +export function createMarkdownEditor(container) { + const text = DecidimAwesome.texts.drag_and_drop_image; + const token = $('meta[name="csrf-token"]').attr("content"); + const $input = $(container).siblings('input[type="hidden"]'); + const $faker = $('