Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove jQuery from repo wiki creation page #29271

Merged
merged 6 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions web_src/js/features/comp/ComboMarkdownEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import '@github/markdown-toolbar-element';
import '@github/text-expander-element';
import $ from 'jquery';
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 {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
import {renderPreviewPanelContent} from '../repo-editor.js';
Expand All @@ -14,17 +14,17 @@ let elementIdCounter = 0;

/**
* 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.
*/
export function validateTextareaNonEmpty($textarea) {
export function validateTextareaNonEmpty(textarea) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC there is not only one call to this function.

Does these PR changes all of the callers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any other callers
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see 2 on the main branch.

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea why my editor lied to me... Done 8d74e01

// 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.
if (!$textarea.val()) {
if ($textarea.is(':visible')) {
$textarea.prop('required', true);
const $form = $textarea.parents('form');
$form[0]?.reportValidity();
if (!textarea.value) {
if (isElemVisible(textarea)) {
textarea.required = true;
const form = textarea.closest('form');
form?.reportValidity();
} else {
// The alert won't hurt users too much, because we are dropping the EasyMDE and the check only occurs in a few places.
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
showErrorToast('Require non-empty content');
Expand Down
4 changes: 2 additions & 2 deletions web_src/js/features/repo-diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ function initRepoDiffConversationForm() {
e.preventDefault();

const $form = $(e.target);
const $textArea = $form.find('textarea');
if (!validateTextareaNonEmpty($textArea)) {
const textArea = e.target.querySelector('textarea');
if (!validateTextareaNonEmpty(textArea)) {
return;
}

Expand Down
56 changes: 29 additions & 27 deletions web_src/js/features/repo-wiki.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
import $ from 'jquery';
import {initMarkupContent} from '../markup/content.js';
import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
import {fomanticMobileScreen} from '../modules/fomantic.js';

const {csrfToken} = window.config;
import {POST} from '../modules/fetch.js';

async function initRepoWikiFormEditor() {
const $editArea = $('.repository.wiki .combo-markdown-editor textarea');
if (!$editArea.length) return;
const editArea = document.querySelector('.repository.wiki .combo-markdown-editor textarea');
if (!editArea) return;

const $form = $('.repository.wiki.new .ui.form');
const $editorContainer = $form.find('.combo-markdown-editor');
const form = document.querySelector('.repository.wiki.new .ui.form');
const editorContainer = form.querySelector('.combo-markdown-editor');
let editor;

let renderRequesting = false;
let lastContent;
const renderEasyMDEPreview = function () {
const renderEasyMDEPreview = async function () {
if (renderRequesting) return;

const $previewFull = $editorContainer.find('.EasyMDEContainer .editor-preview-active');
const $previewSide = $editorContainer.find('.EasyMDEContainer .editor-preview-active-side');
const $previewTarget = $previewSide.length ? $previewSide : $previewFull;
const newContent = $editArea.val();
if (editor && $previewTarget.length && lastContent !== newContent) {
const previewFull = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active');
const previewSide = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active-side');
const previewTarget = previewSide || previewFull;
const newContent = editArea.value;
if (editor && previewTarget && lastContent !== newContent) {
renderRequesting = true;
$.post(editor.previewUrl, {
_csrf: csrfToken,
mode: editor.previewMode,
context: editor.previewContext,
text: newContent,
wiki: editor.previewWiki,
}).done((data) => {
const formData = new FormData();
formData.append('mode', editor.previewMode);
formData.append('context', editor.previewContext);
formData.append('text', newContent);
formData.append('wiki', editor.previewWiki);
try {
const response = await POST(editor.previewUrl, {data: formData});
const data = await response.text();
lastContent = newContent;
$previewTarget.html(`<div class="markup ui segment">${data}</div>`);
previewTarget.innerHTML = `<div class="markup ui segment">${data}</div>`;
initMarkupContent();
}).always(() => {
} catch (error) {
console.error('Error rendering preview:', error);
} finally {
renderRequesting = false;
setTimeout(renderEasyMDEPreview, 1000);
});
}
} else {
setTimeout(renderEasyMDEPreview, 1000);
}
};
renderEasyMDEPreview();

editor = await initComboMarkdownEditor($editorContainer, {
editor = await initComboMarkdownEditor(editorContainer, {
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.
// And another benefit is that we only need to write the style once for both editors.
Expand All @@ -64,9 +65,10 @@ async function initRepoWikiFormEditor() {
},
});

$form.on('submit', () => {
if (!validateTextareaNonEmpty($editArea)) {
return false;
form.addEventListener('submit', (e) => {
if (!validateTextareaNonEmpty(editArea)) {
e.preventDefault();
e.stopPropagation();
}
});
}
Expand Down
12 changes: 12 additions & 0 deletions web_src/js/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,15 @@ export function initSubmitEventPolyfill() {
document.body.addEventListener('click', 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);
}
delvh marked this conversation as resolved.
Show resolved Hide resolved
Loading