/** * ToastUi editor initializer * * This script transforms form textareas created with * "MarkdownFormBuilder" into ToastUi markdown editors. * */ const BACKTICK = 192; // These counters can be global. Scoping them to each editor becomes redundant // since they are reset to this state when switching editors. // Read more: https://github.com/openHPI/codeocean/pull/2242#discussion_r1576617432 let backtickPressedCount = 0; let justInsertedCodeBlock = false; const deleteSelection = (editor, count) => { // The backtick is a so-called dead key, which is waiting for further input to be combined with. // For example a backtick and the letter a are combined to à. // When we remove a selection ending with a backtick, we want to clear the keyboard buffer, too. // This ensures that typing a regular character a after this operation is not combined into à, but just inserted as a. // This solution is taken from https://stackoverflow.com/a/72634132. editor.blur(); setTimeout(() => editor.focus()); // Get current position const selectionRange = editor.getSelection(); // Replace the previous `count` characters with an empty string. // We use a replace function (rather than delete) to avoid issues with line breaks in ToastUi. // Otherwise, a line break following the cursor position might still be displayed normally, // but could be removed erroneously from the internal editor state. // If this happens, code blocks ending with \n``` are not recognized correctly. editor.replaceSelection( "", [selectionRange[0][0], selectionRange[0][1] - count], [selectionRange[1][0], selectionRange[1][1]] ); }; const resetCount = (withBlock = false) => { backtickPressedCount = 0; justInsertedCodeBlock = withBlock; }; const initializeMarkdownEditors = () => { const editors = document.querySelectorAll( '[data-behavior="markdown-editor-widget"]' ); editors.forEach((editor) => { const formInput = document.querySelector(`#${editor.dataset.id}`); if (!editor || !formInput) return; const toastEditor = new ToastUi({ el: editor, theme: window.getCurrentTheme(), initialValue: formInput.value, placeholder: formInput.placeholder, extendedAutolinks: true, linkAttributes: { target: "_blank", }, previewHighlight: false, height: "300px", autofocus: false, usageStatistics: false, language: I18n.locale, toolbarItems: [ ["heading", "bold", "italic"], ["link", "quote", "code", "codeblock"], ["image"], ["ul", "ol"], ], initialEditType: "markdown", events: { change: () => { // Keep real form