From 48aab263d1d60612be05a67c46172b5a5a718dba Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Tue, 4 Jan 2022 00:53:53 +0800
Subject: [PATCH] Fix EasyMDE validation (#18161)

---
 web_src/js/features/comp/CommentEasyMDE.js | 52 +++++++++++++---------
 web_src/js/features/repo-diff.js           |  2 +-
 web_src/js/features/repo-wiki.js           | 14 +++---
 3 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/web_src/js/features/comp/CommentEasyMDE.js b/web_src/js/features/comp/CommentEasyMDE.js
index 8efbe4d34d..d3447d7ba2 100644
--- a/web_src/js/features/comp/CommentEasyMDE.js
+++ b/web_src/js/features/comp/CommentEasyMDE.js
@@ -75,13 +75,27 @@ export function createCommentEasyMDE(textarea) {
     }
   });
   attachTribute(inputField, {mentions: true, emoji: true});
-
-  // TODO: that's the only way we can do now to attach the EasyMDE object to a HTMLElement
-  inputField._data_easyMDE = easyMDE;
-  textarea._data_easyMDE = easyMDE;
+  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
@@ -98,29 +112,27 @@ export function getAttachedEasyMDE(el) {
 }
 
 /**
- * validate if the given textarea from a form, is non-empty.
- * @param {jQuery | HTMLElement} form
- * @param {jQuery | HTMLElement} textarea
+ * validate if the given EasyMDE textarea is is non-empty.
+ * @param {jQuery} $textarea
  * @returns {boolean} returns true if validation succeeded.
  */
-export function validateTextareaNonEmpty(form, textarea) {
-  if (form instanceof jQuery) {
-    form = form[0];
-  }
-  if (textarea instanceof jQuery) {
-    textarea = textarea[0];
-  }
-
-  const $markdownEditorTextArea = $(getAttachedEasyMDE(textarea).codemirror.getInputField());
+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.value.length) {
-    $markdownEditorTextArea.prop('required', true);
-    form.reportValidity();
+  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;
   }
-  $markdownEditorTextArea.prop('required', 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 d2502315b4..3378222ae1 100644
--- a/web_src/js/features/repo-diff.js
+++ b/web_src/js/features/repo-diff.js
@@ -27,7 +27,7 @@ export function initRepoDiffConversationForm() {
 
     const form = $(e.target);
     const $textArea = form.find('textarea');
-    if (!validateTextareaNonEmpty(form, $textArea)) {
+    if (!validateTextareaNonEmpty($textArea)) {
       return;
     }
 
diff --git a/web_src/js/features/repo-wiki.js b/web_src/js/features/repo-wiki.js
index c7b902d31d..b76dac030e 100644
--- a/web_src/js/features/repo-wiki.js
+++ b/web_src/js/features/repo-wiki.js
@@ -1,5 +1,5 @@
 import {initMarkupContent} from '../markup/content.js';
-import {validateTextareaNonEmpty} from './comp/CommentEasyMDE.js';
+import {attachEasyMDEToElements, validateTextareaNonEmpty} from './comp/CommentEasyMDE.js';
 import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
 
 const {csrfToken} = window.config;
@@ -119,11 +119,15 @@ export function initRepoWikiForm() {
       ]
     });
 
-    const $markdownEditorTextArea = $(easyMDE.codemirror.getInputField());
-    $markdownEditorTextArea.addClass('js-quick-submit');
+    attachEasyMDEToElements(easyMDE);
 
-    $form.on('submit', function () {
-      validateTextareaNonEmpty(this, $editArea);
+    const $mdeInputField = $(easyMDE.codemirror.getInputField());
+    $mdeInputField.addClass('js-quick-submit');
+
+    $form.on('submit', () => {
+      if (!validateTextareaNonEmpty($editArea)) {
+        return false;
+      }
     });
 
     setTimeout(() => {