forked from gitea/gitea
Remove jQuery from repo wiki creation page (#29271)
- Switched to plain JavaScript - Tested the wiki creation form functionality and it works as before # Demo using JavaScript without jQuery ![action](https://github.com/go-gitea/gitea/assets/20454870/2dfc95fd-40cc-4ffb-9ae6-50f798fddd67) --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
8c21bc0d51
commit
ade1110e8b
|
@ -2,7 +2,7 @@ import '@github/markdown-toolbar-element';
|
||||||
import '@github/text-expander-element';
|
import '@github/text-expander-element';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {attachTribute} from '../tribute.js';
|
import {attachTribute} from '../tribute.js';
|
||||||
import {hideElem, showElem, autosize} from '../../utils/dom.js';
|
import {hideElem, showElem, autosize, isElemVisible} from '../../utils/dom.js';
|
||||||
import {initEasyMDEImagePaste, initTextareaImagePaste} from './ImagePaste.js';
|
import {initEasyMDEImagePaste, initTextareaImagePaste} from './ImagePaste.js';
|
||||||
import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
|
import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
|
||||||
import {renderPreviewPanelContent} from '../repo-editor.js';
|
import {renderPreviewPanelContent} from '../repo-editor.js';
|
||||||
|
@ -14,17 +14,17 @@ let elementIdCounter = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* validate if the given textarea is non-empty.
|
* validate if the given textarea is non-empty.
|
||||||
* @param {jQuery} $textarea
|
* @param {HTMLElement} textarea - The textarea element to be validated.
|
||||||
* @returns {boolean} returns true if validation succeeded.
|
* @returns {boolean} returns true if validation succeeded.
|
||||||
*/
|
*/
|
||||||
export function validateTextareaNonEmpty($textarea) {
|
export function validateTextareaNonEmpty(textarea) {
|
||||||
// When using EasyMDE, the original edit area HTML element is hidden, breaking HTML5 input validation.
|
// When using EasyMDE, the original edit area HTML element is hidden, breaking HTML5 input validation.
|
||||||
// The workaround (https://github.com/sparksuite/simplemde-markdown-editor/issues/324) doesn't work with contenteditable, so we just show an alert.
|
// The workaround (https://github.com/sparksuite/simplemde-markdown-editor/issues/324) doesn't work with contenteditable, so we just show an alert.
|
||||||
if (!$textarea.val()) {
|
if (!textarea.value) {
|
||||||
if ($textarea.is(':visible')) {
|
if (isElemVisible(textarea)) {
|
||||||
$textarea.prop('required', true);
|
textarea.required = true;
|
||||||
const $form = $textarea.parents('form');
|
const form = textarea.closest('form');
|
||||||
$form[0]?.reportValidity();
|
form?.reportValidity();
|
||||||
} else {
|
} else {
|
||||||
// The alert won't hurt users too much, because we are dropping the EasyMDE and the check only occurs in a few places.
|
// The alert won't hurt users too much, because we are dropping the EasyMDE and the check only occurs in a few places.
|
||||||
showErrorToast('Require non-empty content');
|
showErrorToast('Require non-empty content');
|
||||||
|
|
|
@ -47,8 +47,8 @@ function initRepoDiffConversationForm() {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const $form = $(e.target);
|
const $form = $(e.target);
|
||||||
const $textArea = $form.find('textarea');
|
const textArea = e.target.querySelector('textarea');
|
||||||
if (!validateTextareaNonEmpty($textArea)) {
|
if (!validateTextareaNonEmpty(textArea)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
import $ from 'jquery';
|
|
||||||
import {initMarkupContent} from '../markup/content.js';
|
import {initMarkupContent} from '../markup/content.js';
|
||||||
import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
|
import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
|
||||||
import {fomanticMobileScreen} from '../modules/fomantic.js';
|
import {fomanticMobileScreen} from '../modules/fomantic.js';
|
||||||
|
import {POST} from '../modules/fetch.js';
|
||||||
const {csrfToken} = window.config;
|
|
||||||
|
|
||||||
async function initRepoWikiFormEditor() {
|
async function initRepoWikiFormEditor() {
|
||||||
const $editArea = $('.repository.wiki .combo-markdown-editor textarea');
|
const editArea = document.querySelector('.repository.wiki .combo-markdown-editor textarea');
|
||||||
if (!$editArea.length) return;
|
if (!editArea) return;
|
||||||
|
|
||||||
const $form = $('.repository.wiki.new .ui.form');
|
const form = document.querySelector('.repository.wiki.new .ui.form');
|
||||||
const $editorContainer = $form.find('.combo-markdown-editor');
|
const editorContainer = form.querySelector('.combo-markdown-editor');
|
||||||
let editor;
|
let editor;
|
||||||
|
|
||||||
let renderRequesting = false;
|
let renderRequesting = false;
|
||||||
let lastContent;
|
let lastContent;
|
||||||
const renderEasyMDEPreview = function () {
|
const renderEasyMDEPreview = async function () {
|
||||||
if (renderRequesting) return;
|
if (renderRequesting) return;
|
||||||
|
|
||||||
const $previewFull = $editorContainer.find('.EasyMDEContainer .editor-preview-active');
|
const previewFull = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active');
|
||||||
const $previewSide = $editorContainer.find('.EasyMDEContainer .editor-preview-active-side');
|
const previewSide = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active-side');
|
||||||
const $previewTarget = $previewSide.length ? $previewSide : $previewFull;
|
const previewTarget = previewSide || previewFull;
|
||||||
const newContent = $editArea.val();
|
const newContent = editArea.value;
|
||||||
if (editor && $previewTarget.length && lastContent !== newContent) {
|
if (editor && previewTarget && lastContent !== newContent) {
|
||||||
renderRequesting = true;
|
renderRequesting = true;
|
||||||
$.post(editor.previewUrl, {
|
const formData = new FormData();
|
||||||
_csrf: csrfToken,
|
formData.append('mode', editor.previewMode);
|
||||||
mode: editor.previewMode,
|
formData.append('context', editor.previewContext);
|
||||||
context: editor.previewContext,
|
formData.append('text', newContent);
|
||||||
text: newContent,
|
formData.append('wiki', editor.previewWiki);
|
||||||
wiki: editor.previewWiki,
|
try {
|
||||||
}).done((data) => {
|
const response = await POST(editor.previewUrl, {data: formData});
|
||||||
|
const data = await response.text();
|
||||||
lastContent = newContent;
|
lastContent = newContent;
|
||||||
$previewTarget.html(`<div class="markup ui segment">${data}</div>`);
|
previewTarget.innerHTML = `<div class="markup ui segment">${data}</div>`;
|
||||||
initMarkupContent();
|
initMarkupContent();
|
||||||
}).always(() => {
|
} catch (error) {
|
||||||
|
console.error('Error rendering preview:', error);
|
||||||
|
} finally {
|
||||||
renderRequesting = false;
|
renderRequesting = false;
|
||||||
setTimeout(renderEasyMDEPreview, 1000);
|
setTimeout(renderEasyMDEPreview, 1000);
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
setTimeout(renderEasyMDEPreview, 1000);
|
setTimeout(renderEasyMDEPreview, 1000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
renderEasyMDEPreview();
|
renderEasyMDEPreview();
|
||||||
|
|
||||||
editor = await initComboMarkdownEditor($editorContainer, {
|
editor = await initComboMarkdownEditor(editorContainer, {
|
||||||
useScene: 'wiki',
|
useScene: 'wiki',
|
||||||
// EasyMDE has some problems of height definition, it has inline style height 300px by default, so we also use inline styles to override it.
|
// EasyMDE has some problems of height definition, it has inline style height 300px by default, so we also use inline styles to override it.
|
||||||
// And another benefit is that we only need to write the style once for both editors.
|
// And another benefit is that we only need to write the style once for both editors.
|
||||||
|
@ -64,9 +65,10 @@ async function initRepoWikiFormEditor() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$form.on('submit', () => {
|
form.addEventListener('submit', (e) => {
|
||||||
if (!validateTextareaNonEmpty($editArea)) {
|
if (!validateTextareaNonEmpty(editArea)) {
|
||||||
return false;
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,3 +227,15 @@ export function initSubmitEventPolyfill() {
|
||||||
document.body.addEventListener('click', submitEventPolyfillListener);
|
document.body.addEventListener('click', submitEventPolyfillListener);
|
||||||
document.body.addEventListener('focus', submitEventPolyfillListener);
|
document.body.addEventListener('focus', submitEventPolyfillListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an element is visible, equivalent to jQuery's `:visible` pseudo.
|
||||||
|
* Note: This function doesn't account for all possible visibility scenarios.
|
||||||
|
* @param {HTMLElement} element The element to check.
|
||||||
|
* @returns {boolean} True if the element is visible.
|
||||||
|
*/
|
||||||
|
export function isElemVisible(element) {
|
||||||
|
if (!element) return false;
|
||||||
|
|
||||||
|
return Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue