diff --git a/core/static/webpack/easymde-index.ts b/core/static/webpack/easymde-index.ts index 4961a1b1..3e64f5fa 100644 --- a/core/static/webpack/easymde-index.ts +++ b/core/static/webpack/easymde-index.ts @@ -7,188 +7,189 @@ import type CodeMirror from "codemirror"; import EasyMDE from "easymde"; import { markdownRenderMarkdown } from "#openapi"; +const loadEasyMde = (textarea: HTMLTextAreaElement) => { + new EasyMDE({ + element: textarea, + spellChecker: false, + autoDownloadFontAwesome: false, + previewRender: Alpine.debounce((plainText: string, preview: MarkdownInput) => { + const func = async (plainText: string, preview: MarkdownInput): Promise => { + preview.innerHTML = ( + await markdownRenderMarkdown({ body: { text: plainText } }) + ).data as string; + return null; + }; + func(plainText, preview); + return null; + }, 300), + forceSync: true, // Avoid validation error on generic create view + toolbar: [ + { + name: "heading-smaller", + action: EasyMDE.toggleHeadingSmaller, + className: "fa fa-header", + title: gettext("Heading"), + }, + { + name: "italic", + action: EasyMDE.toggleItalic, + className: "fa fa-italic", + title: gettext("Italic"), + }, + { + name: "bold", + action: EasyMDE.toggleBold, + className: "fa fa-bold", + title: gettext("Bold"), + }, + { + name: "strikethrough", + action: EasyMDE.toggleStrikethrough, + className: "fa fa-strikethrough", + title: gettext("Strikethrough"), + }, + { + name: "underline", + action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { + const cm = editor.codemirror; + cm.replaceSelection(`__${cm.getSelection()}__`); + }, + className: "fa fa-underline", + title: gettext("Underline"), + }, + { + name: "superscript", + action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { + const cm = editor.codemirror; + cm.replaceSelection(`^${cm.getSelection()}^`); + }, + className: "fa fa-superscript", + title: gettext("Superscript"), + }, + { + name: "subscript", + action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { + const cm = editor.codemirror; + cm.replaceSelection(`~${cm.getSelection()}~`); + }, + className: "fa fa-subscript", + title: gettext("Subscript"), + }, + { + name: "code", + action: EasyMDE.toggleCodeBlock, + className: "fa fa-code", + title: gettext("Code"), + }, + "|", + { + name: "quote", + action: EasyMDE.toggleBlockquote, + className: "fa fa-quote-left", + title: gettext("Quote"), + }, + { + name: "unordered-list", + action: EasyMDE.toggleUnorderedList, + className: "fa fa-list-ul", + title: gettext("Unordered list"), + }, + { + name: "ordered-list", + action: EasyMDE.toggleOrderedList, + className: "fa fa-list-ol", + title: gettext("Ordered list"), + }, + "|", + { + name: "link", + action: EasyMDE.drawLink, + className: "fa fa-link", + title: gettext("Insert link"), + }, + { + name: "image", + action: EasyMDE.drawImage, + className: "fa-regular fa-image", + title: gettext("Insert image"), + }, + { + name: "table", + action: EasyMDE.drawTable, + className: "fa fa-table", + title: gettext("Insert table"), + }, + "|", + { + name: "clean-block", + action: EasyMDE.cleanBlock, + className: "fa fa-eraser fa-clean-block", + title: gettext("Clean block"), + }, + "|", + { + name: "preview", + action: EasyMDE.togglePreview, + className: "fa fa-eye no-disable", + title: gettext("Toggle preview"), + }, + { + name: "side-by-side", + action: EasyMDE.toggleSideBySide, + className: "fa fa-columns no-disable no-mobile", + title: gettext("Toggle side by side"), + }, + { + name: "fullscreen", + action: EasyMDE.toggleFullScreen, + className: "fa fa-expand no-mobile", + title: gettext("Toggle fullscreen"), + }, + "|", + { + name: "guide", + action: "/page/Aide_sur_la_syntaxe", + className: "fa fa-question-circle", + title: gettext("Markdown guide"), + }, + ], + }); + + const submits: HTMLInputElement[] = Array.from( + textarea.closest("form").querySelectorAll('input[type="submit"]'), + ); + const parentDiv = textarea.parentElement; + let submitPressed = false; + + function checkMarkdownInput(_event: Event) { + // an attribute is null if it does not exist, else a string + const required = this.getAttribute("required") != null; + const length = this.value.trim().length; + + if (required && length === 0) { + parentDiv.style.boxShadow = "red 0px 0px 1.5px 1px"; + } else { + parentDiv.style.boxShadow = ""; + } + } + + function onSubmitClick(e: Event) { + if (!submitPressed) { + this.codemirror.on("change", checkMarkdownInput); + } + submitPressed = true; + checkMarkdownInput(e); + } + + for (const submit of submits) { + submit.addEventListener("click", onSubmitClick); + } +}; + class MarkdownInput extends HTMLTextAreaElement { constructor() { super(); - new EasyMDE({ - element: this, - spellChecker: false, - autoDownloadFontAwesome: false, - previewRender: Alpine.debounce((plainText: string, preview: MarkdownInput) => { - const func = async ( - plainText: string, - preview: MarkdownInput, - ): Promise => { - preview.innerHTML = ( - await markdownRenderMarkdown({ body: { text: plainText } }) - ).data as string; - return null; - }; - func(plainText, preview); - return null; - }, 300), - forceSync: true, // Avoid validation error on generic create view - toolbar: [ - { - name: "heading-smaller", - action: EasyMDE.toggleHeadingSmaller, - className: "fa fa-header", - title: gettext("Heading"), - }, - { - name: "italic", - action: EasyMDE.toggleItalic, - className: "fa fa-italic", - title: gettext("Italic"), - }, - { - name: "bold", - action: EasyMDE.toggleBold, - className: "fa fa-bold", - title: gettext("Bold"), - }, - { - name: "strikethrough", - action: EasyMDE.toggleStrikethrough, - className: "fa fa-strikethrough", - title: gettext("Strikethrough"), - }, - { - name: "underline", - action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { - const cm = editor.codemirror; - cm.replaceSelection(`__${cm.getSelection()}__`); - }, - className: "fa fa-underline", - title: gettext("Underline"), - }, - { - name: "superscript", - action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { - const cm = editor.codemirror; - cm.replaceSelection(`^${cm.getSelection()}^`); - }, - className: "fa fa-superscript", - title: gettext("Superscript"), - }, - { - name: "subscript", - action: function customFunction(editor: { codemirror: CodeMirror.Editor }) { - const cm = editor.codemirror; - cm.replaceSelection(`~${cm.getSelection()}~`); - }, - className: "fa fa-subscript", - title: gettext("Subscript"), - }, - { - name: "code", - action: EasyMDE.toggleCodeBlock, - className: "fa fa-code", - title: gettext("Code"), - }, - "|", - { - name: "quote", - action: EasyMDE.toggleBlockquote, - className: "fa fa-quote-left", - title: gettext("Quote"), - }, - { - name: "unordered-list", - action: EasyMDE.toggleUnorderedList, - className: "fa fa-list-ul", - title: gettext("Unordered list"), - }, - { - name: "ordered-list", - action: EasyMDE.toggleOrderedList, - className: "fa fa-list-ol", - title: gettext("Ordered list"), - }, - "|", - { - name: "link", - action: EasyMDE.drawLink, - className: "fa fa-link", - title: gettext("Insert link"), - }, - { - name: "image", - action: EasyMDE.drawImage, - className: "fa-regular fa-image", - title: gettext("Insert image"), - }, - { - name: "table", - action: EasyMDE.drawTable, - className: "fa fa-table", - title: gettext("Insert table"), - }, - "|", - { - name: "clean-block", - action: EasyMDE.cleanBlock, - className: "fa fa-eraser fa-clean-block", - title: gettext("Clean block"), - }, - "|", - { - name: "preview", - action: EasyMDE.togglePreview, - className: "fa fa-eye no-disable", - title: gettext("Toggle preview"), - }, - { - name: "side-by-side", - action: EasyMDE.toggleSideBySide, - className: "fa fa-columns no-disable no-mobile", - title: gettext("Toggle side by side"), - }, - { - name: "fullscreen", - action: EasyMDE.toggleFullScreen, - className: "fa fa-expand no-mobile", - title: gettext("Toggle fullscreen"), - }, - "|", - { - name: "guide", - action: "/page/Aide_sur_la_syntaxe", - className: "fa fa-question-circle", - title: gettext("Markdown guide"), - }, - ], - }); - - const submits: HTMLInputElement[] = Array.from( - this.closest("form").querySelectorAll('input[type="submit"]'), - ); - const parentDiv = this.parentElement; - let submitPressed = false; - - function checkMarkdownInput(_event: Event) { - // an attribute is null if it does not exist, else a string - const required = this.getAttribute("required") != null; - const length = this.value.trim().length; - - if (required && length === 0) { - parentDiv.style.boxShadow = "red 0px 0px 1.5px 1px"; - } else { - parentDiv.style.boxShadow = ""; - } - } - - function onSubmitClick(e: Event) { - if (!submitPressed) { - this.codemirror.on("change", checkMarkdownInput); - } - submitPressed = true; - checkMarkdownInput(e); - } - - for (const submit of submits) { - submit.addEventListener("click", onSubmitClick); - } + window.addEventListener("DOMContentLoaded", () => loadEasyMde(this)); } }