From a38ba634a4da15fbb2d1b6ac6742cf01c1503ea4 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 5 Jan 2022 20:17:25 +0800 Subject: Load EasyMDE/CodeMirror dynamically, remove RequireEasyMDE (#18069) This PR makes frontend load EasyMDE/CodeMirror dynamically, and removes `RequireEasyMDE`. --- web_src/js/features/comp/CommentEasyMDE.js | 138 ------------- web_src/js/features/comp/EasyMDE.js | 186 +++++++++++++++++ web_src/js/features/repo-diff.js | 2 +- web_src/js/features/repo-issue.js | 13 +- web_src/js/features/repo-legacy.js | 5 +- web_src/js/features/repo-release.js | 18 +- web_src/js/features/repo-wiki.js | 319 +++++++++++++++-------------- 7 files changed, 369 insertions(+), 312 deletions(-) delete mode 100644 web_src/js/features/comp/CommentEasyMDE.js create mode 100644 web_src/js/features/comp/EasyMDE.js (limited to 'web_src/js/features') diff --git a/web_src/js/features/comp/CommentEasyMDE.js b/web_src/js/features/comp/CommentEasyMDE.js deleted file mode 100644 index d3447d7ba2..0000000000 --- a/web_src/js/features/comp/CommentEasyMDE.js +++ /dev/null @@ -1,138 +0,0 @@ -import attachTribute from '../tribute.js'; - -/** - * create an EasyMDE editor for comment - * @param textarea jQuery or HTMLElement - * @returns {null|EasyMDE} - */ -export function createCommentEasyMDE(textarea) { - if (textarea instanceof jQuery) { - textarea = textarea[0]; - } - if (!textarea) { - return null; - } - - const easyMDE = new window.EasyMDE({ - autoDownloadFontAwesome: false, - element: textarea, - forceSync: true, - renderingConfig: { - singleLineBreaks: false - }, - indentWithTabs: false, - tabSize: 4, - spellChecker: false, - toolbar: ['bold', 'italic', 'strikethrough', '|', - 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', - 'code', 'quote', '|', { - name: 'checkbox-empty', - action(e) { - const cm = e.codemirror; - cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); - cm.focus(); - }, - className: 'fa fa-square-o', - title: 'Add Checkbox (empty)', - }, - { - name: 'checkbox-checked', - action(e) { - const cm = e.codemirror; - cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); - cm.focus(); - }, - className: 'fa fa-check-square-o', - title: 'Add Checkbox (checked)', - }, '|', - 'unordered-list', 'ordered-list', '|', - 'link', 'image', 'table', 'horizontal-rule', '|', - 'clean-block', '|', - { - name: 'revert-to-textarea', - action(e) { - e.toTextArea(); - }, - className: 'fa fa-file', - title: 'Revert to simple textarea', - }, - ] - }); - const inputField = easyMDE.codemirror.getInputField(); - inputField.classList.add('js-quick-submit'); - easyMDE.codemirror.setOption('extraKeys', { - Enter: () => { - const tributeContainer = document.querySelector('.tribute-container'); - if (!tributeContainer || tributeContainer.style.display === 'none') { - return CodeMirror.Pass; - } - }, - Backspace: (cm) => { - if (cm.getInputField().trigger) { - cm.getInputField().trigger('input'); - } - cm.execCommand('delCharBefore'); - } - }); - attachTribute(inputField, {mentions: true, emoji: true}); - attachEasyMDEToElements(easyMDE); - return easyMDE; -} - -/** - * attach the EasyMDE object to its input elements (InputField, TextArea) - * @param {EasyMDE} easyMDE - */ -export function attachEasyMDEToElements(easyMDE) { - // TODO: that's the only way we can do now to attach the EasyMDE object to a HTMLElement - - // InputField is used by CodeMirror to accept user input - const inputField = easyMDE.codemirror.getInputField(); - inputField._data_easyMDE = easyMDE; - - // TextArea is the real textarea element in the form - const textArea = easyMDE.codemirror.getTextArea(); - textArea._data_easyMDE = easyMDE; -} - - -/** - * get the attached EasyMDE editor created by createCommentEasyMDE - * @param el jQuery or HTMLElement - * @returns {null|EasyMDE} - */ -export function getAttachedEasyMDE(el) { - if (el instanceof jQuery) { - el = el[0]; - } - if (!el) { - return null; - } - return el._data_easyMDE; -} - -/** - * validate if the given EasyMDE textarea is is non-empty. - * @param {jQuery} $textarea - * @returns {boolean} returns true if validation succeeded. - */ -export function validateTextareaNonEmpty($textarea) { - const $mdeInputField = $(getAttachedEasyMDE($textarea).codemirror.getInputField()); - // The original edit area HTML element is hidden and replaced by the - // SimpleMDE/EasyMDE editor, breaking HTML5 input validation if the text area is empty. - // This is a workaround for this upstream bug. - // See https://github.com/sparksuite/simplemde-markdown-editor/issues/324 - if (!$textarea.val()) { - $mdeInputField.prop('required', true); - const $form = $textarea.parents('form'); - if (!$form.length) { - // this should never happen. we put a alert here in case the textarea would be forgotten to be put in a form - alert('Require non-empty content'); - } else { - $form[0].reportValidity(); - } - return false; - } - $mdeInputField.prop('required', false); - return true; -} diff --git a/web_src/js/features/comp/EasyMDE.js b/web_src/js/features/comp/EasyMDE.js new file mode 100644 index 0000000000..d5c1a4c734 --- /dev/null +++ b/web_src/js/features/comp/EasyMDE.js @@ -0,0 +1,186 @@ +import attachTribute from '../tribute.js'; + +const {appSubUrl} = window.config; + +function loadScript(url) { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.async = true; + script.addEventListener('load', () => { + resolve(); + }); + script.addEventListener('error', (e) => { + reject(e.error); + }); + script.src = url; + document.body.appendChild(script); + }); +} + +/** + * @returns {EasyMDE} + */ +export async function importEasyMDE() { + // for CodeMirror: the plugins should be loaded dynamically + // https://github.com/codemirror/CodeMirror/issues/5484 + // https://github.com/codemirror/CodeMirror/issues/4838 + + const [{default: EasyMDE}, {default: CodeMirror}] = await Promise.all([ + import(/* webpackChunkName: "easymde" */'easymde'), + import(/* webpackChunkName: "codemirror" */'codemirror'), + import(/* webpackChunkName: "easymde" */'easymde/dist/easymde.min.css'), + ]); + + // CodeMirror plugins must be loaded by a "Plain browser env" + window.CodeMirror = CodeMirror; + await Promise.all([ + loadScript(`${appSubUrl}/assets/vendor/plugins/codemirror/addon/mode/loadmode.js`), + loadScript(`${appSubUrl}/assets/vendor/plugins/codemirror/mode/meta.js`), + ]); + + // the loadmode.js/meta.js would set the modeURL/modeInfo properties, so we check it to make sure our loading works + if (!CodeMirror.modeURL || !CodeMirror.modeInfo) { + throw new Error('failed to load plugins for CodeMirror'); + } + + CodeMirror.modeURL = `${appSubUrl}/assets/vendor/plugins/codemirror/mode/%N/%N.js`; + return EasyMDE; +} + +/** + * create an EasyMDE editor for comment + * @param textarea jQuery or HTMLElement + * @returns {null|EasyMDE} + */ +export async function createCommentEasyMDE(textarea) { + if (textarea instanceof jQuery) { + textarea = textarea[0]; + } + if (!textarea) { + return null; + } + + const EasyMDE = await importEasyMDE(); + const easyMDE = new EasyMDE({ + autoDownloadFontAwesome: false, + element: textarea, + forceSync: true, + renderingConfig: { + singleLineBreaks: false, + }, + indentWithTabs: false, + tabSize: 4, + spellChecker: false, + toolbar: ['bold', 'italic', 'strikethrough', '|', + 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', + 'code', 'quote', '|', { + name: 'checkbox-empty', + action(e) { + const cm = e.codemirror; + cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); + cm.focus(); + }, + className: 'fa fa-square-o', + title: 'Add Checkbox (empty)', + }, + { + name: 'checkbox-checked', + action(e) { + const cm = e.codemirror; + cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); + cm.focus(); + }, + className: 'fa fa-check-square-o', + title: 'Add Checkbox (checked)', + }, '|', + 'unordered-list', 'ordered-list', '|', + 'link', 'image', 'table', 'horizontal-rule', '|', + 'clean-block', '|', + { + name: 'revert-to-textarea', + action(e) { + e.toTextArea(); + }, + className: 'fa fa-file', + title: 'Revert to simple textarea', + }, + ], + }); + const inputField = easyMDE.codemirror.getInputField(); + inputField.classList.add('js-quick-submit'); + easyMDE.codemirror.setOption('extraKeys', { + Enter: () => { + const tributeContainer = document.querySelector('.tribute-container'); + if (!tributeContainer || tributeContainer.style.display === 'none') { + return window.CodeMirror.Pass; + } + }, + Backspace: (cm) => { + if (cm.getInputField().trigger) { + cm.getInputField().trigger('input'); + } + cm.execCommand('delCharBefore'); + }, + }); + attachTribute(inputField, {mentions: true, emoji: true}); + attachEasyMDEToElements(easyMDE); + return easyMDE; +} + +/** + * attach the EasyMDE object to its input elements (InputField, TextArea) + * @param {EasyMDE} easyMDE + */ +export function attachEasyMDEToElements(easyMDE) { + // TODO: that's the only way we can do now to attach the EasyMDE object to a HTMLElement + + // InputField is used by CodeMirror to accept user input + const inputField = easyMDE.codemirror.getInputField(); + inputField._data_easyMDE = easyMDE; + + // TextArea is the real textarea element in the form + const textArea = easyMDE.codemirror.getTextArea(); + textArea._data_easyMDE = easyMDE; +} + + +/** + * get the attached EasyMDE editor created by createCommentEasyMDE + * @param el jQuery or HTMLElement + * @returns {null|EasyMDE} + */ +export function getAttachedEasyMDE(el) { + if (el instanceof jQuery) { + el = el[0]; + } + if (!el) { + return null; + } + return el._data_easyMDE; +} + +/** + * validate if the given EasyMDE textarea is is non-empty. + * @param {jQuery} $textarea + * @returns {boolean} returns true if validation succeeded. + */ +export function validateTextareaNonEmpty($textarea) { + const $mdeInputField = $(getAttachedEasyMDE($textarea).codemirror.getInputField()); + // The original edit area HTML element is hidden and replaced by the + // SimpleMDE/EasyMDE editor, breaking HTML5 input validation if the text area is empty. + // This is a workaround for this upstream bug. + // See https://github.com/sparksuite/simplemde-markdown-editor/issues/324 + if (!$textarea.val()) { + $mdeInputField.prop('required', true); + const $form = $textarea.parents('form'); + if (!$form.length) { + // this should never happen. we put a alert here in case the textarea would be forgotten to be put in a form + alert('Require non-empty content'); + } else { + $form[0].reportValidity(); + } + return false; + } + $mdeInputField.prop('required', false); + return true; +} diff --git a/web_src/js/features/repo-diff.js b/web_src/js/features/repo-diff.js index 3378222ae1..3d937bbdb1 100644 --- a/web_src/js/features/repo-diff.js +++ b/web_src/js/features/repo-diff.js @@ -1,6 +1,6 @@ import {initCompReactionSelector} from './comp/ReactionSelector.js'; import {initRepoIssueContentHistory} from './repo-issue-content.js'; -import {validateTextareaNonEmpty} from './comp/CommentEasyMDE.js'; +import {validateTextareaNonEmpty} from './comp/EasyMDE.js'; const {csrfToken} = window.config; export function initRepoDiffReviewButton() { diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 545f59a4d8..c2b0254a81 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -1,6 +1,6 @@ import {htmlEscape} from 'escape-goat'; import attachTribute from './tribute.js'; -import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/CommentEasyMDE.js'; +import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; import {initCompImagePaste} from './comp/ImagePaste.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; @@ -439,16 +439,17 @@ export function initRepoPullRequestReview() { $(`#show-outdated-${id}`).removeClass('hide'); }); - $(document).on('click', 'button.comment-form-reply', function (e) { + $(document).on('click', 'button.comment-form-reply', async function (e) { e.preventDefault(); + $(this).hide(); const form = $(this).closest('.comment-code-cloud').find('.comment-form'); form.removeClass('hide'); const $textarea = form.find('textarea'); let easyMDE = getAttachedEasyMDE($textarea); if (!easyMDE) { - attachTribute($textarea.get(), {mentions: true, emoji: true}); - easyMDE = createCommentEasyMDE($textarea); + await attachTribute($textarea.get(), {mentions: true, emoji: true}); + easyMDE = await createCommentEasyMDE($textarea); } $textarea.focus(); easyMDE.codemirror.focus(); @@ -515,8 +516,8 @@ export function initRepoPullRequestReview() { td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed'); td.find("input[name='path']").val(path); const $textarea = commentCloud.find('textarea'); - attachTribute($textarea.get(), {mentions: true, emoji: true}); - const easyMDE = createCommentEasyMDE($textarea); + await attachTribute($textarea.get(), {mentions: true, emoji: true}); + const easyMDE = await createCommentEasyMDE($textarea); $textarea.focus(); easyMDE.codemirror.focus(); } diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 87d311716a..fccec8ccac 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -1,4 +1,4 @@ -import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/CommentEasyMDE.js'; +import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; import {initCompImagePaste, initEasyMDEImagePaste} from './comp/ImagePaste.js'; import { @@ -256,6 +256,7 @@ export function initRepoCommentForm() { async function onEditContent(event) { event.preventDefault(); + $(this).closest('.dropdown').find('.menu').toggle('visible'); const $segment = $(this).closest('.header').next(); const $editContentZone = $segment.find('.edit-content-zone'); @@ -341,7 +342,7 @@ async function onEditContent(event) { $tabMenu.find('.preview.item').attr('data-tab', $editContentZone.data('preview')); $editContentForm.find('.write').attr('data-tab', $editContentZone.data('write')); $editContentForm.find('.preview').attr('data-tab', $editContentZone.data('preview')); - easyMDE = createCommentEasyMDE($textarea); + easyMDE = await createCommentEasyMDE($textarea); initCompMarkupContentPreviewTab($editContentForm); if ($dropzone.length === 1) { diff --git a/web_src/js/features/repo-release.js b/web_src/js/features/repo-release.js index f69ce37d6b..915e722546 100644 --- a/web_src/js/features/repo-release.js +++ b/web_src/js/features/repo-release.js @@ -1,7 +1,7 @@ import attachTribute from './tribute.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; import {initEasyMDEImagePaste} from './comp/ImagePaste.js'; -import {createCommentEasyMDE} from './comp/CommentEasyMDE.js'; +import {createCommentEasyMDE} from './comp/EasyMDE.js'; export function initRepoRelease() { $(document).on('click', '.remove-rel-attach', function() { @@ -19,11 +19,13 @@ export function initRepoReleaseEditor() { return false; } - const $textarea = $editor.find('textarea'); - attachTribute($textarea.get(), {mentions: false, emoji: true}); - const $files = $editor.parent().find('.files'); - const easyMDE = createCommentEasyMDE($textarea); - initCompMarkupContentPreviewTab($editor); - const dropzone = $editor.parent().find('.dropzone')[0]; - initEasyMDEImagePaste(easyMDE, dropzone, $files); + (async () => { + const $textarea = $editor.find('textarea'); + await attachTribute($textarea.get(), {mentions: false, emoji: true}); + const $files = $editor.parent().find('.files'); + const easyMDE = await createCommentEasyMDE($textarea); + initCompMarkupContentPreviewTab($editor); + const dropzone = $editor.parent().find('.dropzone')[0]; + initEasyMDEImagePaste(easyMDE, dropzone, $files); + })(); } diff --git a/web_src/js/features/repo-wiki.js b/web_src/js/features/repo-wiki.js index b76dac030e..c0dc8d1b41 100644 --- a/web_src/js/features/repo-wiki.js +++ b/web_src/js/features/repo-wiki.js @@ -1,186 +1,191 @@ import {initMarkupContent} from '../markup/content.js'; -import {attachEasyMDEToElements, validateTextareaNonEmpty} from './comp/CommentEasyMDE.js'; +import {attachEasyMDEToElements, importEasyMDE, validateTextareaNonEmpty} from './comp/EasyMDE.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; const {csrfToken} = window.config; -export function initRepoWikiForm() { +async function initRepoWikiFormEditor() { const $editArea = $('.repository.wiki textarea#edit_area'); + if (!$editArea.length) return; + let sideBySideChanges = 0; let sideBySideTimeout = null; let hasEasyMDE = true; - if ($editArea.length > 0) { - const $form = $('.repository.wiki.new .ui.form'); - const easyMDE = new window.EasyMDE({ - autoDownloadFontAwesome: false, - element: $editArea[0], - forceSync: true, - previewRender(plainText, preview) { // Async method - // FIXME: still send render request when return back to edit mode - const render = function () { - sideBySideChanges = 0; + const $form = $('.repository.wiki.new .ui.form'); + const EasyMDE = await importEasyMDE(); + const easyMDE = new EasyMDE({ + autoDownloadFontAwesome: false, + element: $editArea[0], + forceSync: true, + previewRender(plainText, preview) { // Async method + // FIXME: still send render request when return back to edit mode + const render = function () { + sideBySideChanges = 0; + if (sideBySideTimeout !== null) { + clearTimeout(sideBySideTimeout); + sideBySideTimeout = null; + } + $.post($editArea.data('url'), { + _csrf: csrfToken, + mode: 'gfm', + context: $editArea.data('context'), + text: plainText, + wiki: true + }, (data) => { + preview.innerHTML = `
${data}
`; + initMarkupContent(); + }); + }; + + setTimeout(() => { + if (!easyMDE.isSideBySideActive()) { + render(); + } else { + // delay preview by keystroke counting + sideBySideChanges++; + if (sideBySideChanges > 10) { + render(); + } + // or delay preview by timeout if (sideBySideTimeout !== null) { clearTimeout(sideBySideTimeout); sideBySideTimeout = null; } - $.post($editArea.data('url'), { - _csrf: csrfToken, - mode: 'gfm', - context: $editArea.data('context'), - text: plainText, - wiki: true - }, (data) => { - preview.innerHTML = `
${data}
`; - initMarkupContent(); - }); - }; - - setTimeout(() => { - if (!easyMDE.isSideBySideActive()) { - render(); - } else { - // delay preview by keystroke counting - sideBySideChanges++; - if (sideBySideChanges > 10) { - render(); - } - // or delay preview by timeout - if (sideBySideTimeout !== null) { - clearTimeout(sideBySideTimeout); - sideBySideTimeout = null; - } - sideBySideTimeout = setTimeout(render, 600); - } - }, 0); - if (!easyMDE.isSideBySideActive()) { - return 'Loading...'; + sideBySideTimeout = setTimeout(render, 600); } - return preview.innerHTML; - }, - renderingConfig: { - singleLineBreaks: false + }, 0); + if (!easyMDE.isSideBySideActive()) { + return 'Loading...'; + } + return preview.innerHTML; + }, + renderingConfig: { + singleLineBreaks: false + }, + indentWithTabs: false, + tabSize: 4, + spellChecker: false, + toolbar: ['bold', 'italic', 'strikethrough', '|', + 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', + { + name: 'code-inline', + action(e) { + const cm = e.codemirror; + const selection = cm.getSelection(); + cm.replaceSelection(`\`${selection}\``); + if (!selection) { + const cursorPos = cm.getCursor(); + cm.setCursor(cursorPos.line, cursorPos.ch - 1); + } + cm.focus(); + }, + className: 'fa fa-angle-right', + title: 'Add Inline Code', + }, 'code', 'quote', '|', { + name: 'checkbox-empty', + action(e) { + const cm = e.codemirror; + cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); + cm.focus(); + }, + className: 'fa fa-square-o', + title: 'Add Checkbox (empty)', }, - indentWithTabs: false, - tabSize: 4, - spellChecker: false, - toolbar: ['bold', 'italic', 'strikethrough', '|', - 'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', - { - name: 'code-inline', - action(e) { - const cm = e.codemirror; - const selection = cm.getSelection(); - cm.replaceSelection(`\`${selection}\``); - if (!selection) { - const cursorPos = cm.getCursor(); - cm.setCursor(cursorPos.line, cursorPos.ch - 1); - } - cm.focus(); - }, - className: 'fa fa-angle-right', - title: 'Add Inline Code', - }, 'code', 'quote', '|', { - name: 'checkbox-empty', - action(e) { - const cm = e.codemirror; - cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); - cm.focus(); - }, - className: 'fa fa-square-o', - title: 'Add Checkbox (empty)', + { + name: 'checkbox-checked', + action(e) { + const cm = e.codemirror; + cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); + cm.focus(); }, - { - name: 'checkbox-checked', - action(e) { - const cm = e.codemirror; - cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); - cm.focus(); - }, - className: 'fa fa-check-square-o', - title: 'Add Checkbox (checked)', - }, '|', - 'unordered-list', 'ordered-list', '|', - 'link', 'image', 'table', 'horizontal-rule', '|', - 'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', - { - name: 'revert-to-textarea', - action(e) { - e.toTextArea(); - hasEasyMDE = false; - const $root = $form.find('.field.content'); - const loading = $root.data('loading'); - $root.append(`
${loading}
`); - initCompMarkupContentPreviewTab($form); - }, - className: 'fa fa-file', - title: 'Revert to simple textarea', + className: 'fa fa-check-square-o', + title: 'Add Checkbox (checked)', + }, '|', + 'unordered-list', 'ordered-list', '|', + 'link', 'image', 'table', 'horizontal-rule', '|', + 'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', + { + name: 'revert-to-textarea', + action(e) { + e.toTextArea(); + hasEasyMDE = false; + const $root = $form.find('.field.content'); + const loading = $root.data('loading'); + $root.append(`
${loading}
`); + initCompMarkupContentPreviewTab($form); }, - ] - }); + className: 'fa fa-file', + title: 'Revert to simple textarea', + }, + ] + }); + + attachEasyMDEToElements(easyMDE); - attachEasyMDEToElements(easyMDE); + const $mdeInputField = $(easyMDE.codemirror.getInputField()); + $mdeInputField.addClass('js-quick-submit'); - const $mdeInputField = $(easyMDE.codemirror.getInputField()); - $mdeInputField.addClass('js-quick-submit'); + $form.on('submit', () => { + if (!validateTextareaNonEmpty($editArea)) { + return false; + } + }); - $form.on('submit', () => { - if (!validateTextareaNonEmpty($editArea)) { + setTimeout(() => { + const $bEdit = $('.repository.wiki.new .previewtabs a[data-tab="write"]'); + const $bPrev = $('.repository.wiki.new .previewtabs a[data-tab="preview"]'); + const $toolbar = $('.editor-toolbar'); + const $bPreview = $('.editor-toolbar button.preview'); + const $bSideBySide = $('.editor-toolbar a.fa-columns'); + $bEdit.on('click', (e) => { + if (!hasEasyMDE) { return false; } - }); + e.stopImmediatePropagation(); + if ($toolbar.hasClass('disabled-for-preview')) { + $bPreview.trigger('click'); + } - setTimeout(() => { - const $bEdit = $('.repository.wiki.new .previewtabs a[data-tab="write"]'); - const $bPrev = $('.repository.wiki.new .previewtabs a[data-tab="preview"]'); - const $toolbar = $('.editor-toolbar'); - const $bPreview = $('.editor-toolbar button.preview'); - const $bSideBySide = $('.editor-toolbar a.fa-columns'); - $bEdit.on('click', (e) => { - if (!hasEasyMDE) { - return false; - } - e.stopImmediatePropagation(); + return false; + }); + $bPrev.on('click', (e) => { + if (!hasEasyMDE) { + return false; + } + e.stopImmediatePropagation(); + if (!$toolbar.hasClass('disabled-for-preview')) { + $bPreview.trigger('click'); + } + return false; + }); + $bPreview.on('click', () => { + setTimeout(() => { if ($toolbar.hasClass('disabled-for-preview')) { - $bPreview.trigger('click'); + if ($bEdit.hasClass('active')) { + $bEdit.removeClass('active'); + } + if (!$bPrev.hasClass('active')) { + $bPrev.addClass('active'); + } + } else { + if (!$bEdit.hasClass('active')) { + $bEdit.addClass('active'); + } + if ($bPrev.hasClass('active')) { + $bPrev.removeClass('active'); + } } + }, 0); - return false; - }); - $bPrev.on('click', (e) => { - if (!hasEasyMDE) { - return false; - } - e.stopImmediatePropagation(); - if (!$toolbar.hasClass('disabled-for-preview')) { - $bPreview.trigger('click'); - } - return false; - }); - $bPreview.on('click', () => { - setTimeout(() => { - if ($toolbar.hasClass('disabled-for-preview')) { - if ($bEdit.hasClass('active')) { - $bEdit.removeClass('active'); - } - if (!$bPrev.hasClass('active')) { - $bPrev.addClass('active'); - } - } else { - if (!$bEdit.hasClass('active')) { - $bEdit.addClass('active'); - } - if ($bPrev.hasClass('active')) { - $bPrev.removeClass('active'); - } - } - }, 0); + return false; + }); + $bSideBySide.on('click', () => { + sideBySideChanges = 10; + }); + }, 0); +} - return false; - }); - $bSideBySide.on('click', () => { - sideBySideChanges = 10; - }); - }, 0); - } +export function initRepoWikiForm() { + initRepoWikiFormEditor(); } -- cgit v1.2.3