Remove jQuery AJAX from the repo editor (#29636)

# Preview Tab
- Removed the jQuery AJAX call and replaced with our fetch wrapper
- Tested the preview tab functionality and it works as before

# Diff Tab
- Removed the jQuery AJAX call and replaced with htmx
- Tested the diff tab functionality and it works as before

## htmx Attributes
- `hx-post="{{.RepoLink}}..."`: make a POST request to the endpoint
- `hx-indicator=".tab[data-tab='diff']"`: attach the loading indicator
to the tab body
- `hx-target=".tab[data-tab='diff']"`: target the tab body for swapping
with the response
- `hx-swap="innerHTML"`: swap the target's inner HTML
- `hx-include="#edit_area"`: include the value of the textarea (content)
in the request body
- `hx-vals='{"context":"{{.BranchLink}}"}'`: include the context in the
request body
- `hx-params="context,content"`: include only these keys in the request
body

# Demo using `fetch` and `htmx` instead of jQuery AJAX

![demo](https://github.com/go-gitea/gitea/assets/20454870/585cd6e8-f329-4c9e-ab53-a540acbd7988)

---------

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: silverwind <me@silverwind.io>
(cherry picked from commit c1331d1f7ab60249ed2f080b24f3e32093fa708d)
This commit is contained in:
Yarden Shoham 2024-03-07 09:28:33 +02:00 committed by Earl Warren
parent 32c8860769
commit 6403d5fca7
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 0579CB2928A78A00
2 changed files with 16 additions and 30 deletions

View file

@ -30,7 +30,7 @@
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a> <a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{ctx.Locale.Tr "repo.editor.new_file"}}{{else}}{{ctx.Locale.Tr "repo.editor.edit_file"}}{{end}}</a>
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a> <a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markup" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-markup-mode="file">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
{{if not .IsNewFile}} {{if not .IsNewFile}}
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a> <a class="item" data-tab="diff" hx-params="context,content" hx-vals='{"context":"{{.BranchLink}}"}' hx-include="#edit_area" hx-swap="innerHTML" hx-target=".tab[data-tab='diff']" hx-indicator=".tab[data-tab='diff']" hx-post="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">{{svg "octicon-diff"}} {{ctx.Locale.Tr "repo.editor.preview_changes"}}</a>
{{end}} {{end}}
</div> </div>
<div class="ui bottom attached active tab segment" data-tab="write"> <div class="ui bottom attached active tab segment" data-tab="write">
@ -45,7 +45,7 @@
{{ctx.Locale.Tr "loading"}} {{ctx.Locale.Tr "loading"}}
</div> </div>
<div class="ui bottom attached tab segment diff edit-diff" data-tab="diff"> <div class="ui bottom attached tab segment diff edit-diff" data-tab="diff">
{{ctx.Locale.Tr "loading"}} <div class="tw-p-16"></div>
</div> </div>
</div> </div>
{{template "repo/editor/commit_form" .}} {{template "repo/editor/commit_form" .}}

View file

@ -4,15 +4,14 @@ import {createCodeEditor} from './codeeditor.js';
import {hideElem, showElem} from '../utils/dom.js'; import {hideElem, showElem} from '../utils/dom.js';
import {initMarkupContent} from '../markup/content.js'; import {initMarkupContent} from '../markup/content.js';
import {attachRefIssueContextPopup} from './contextpopup.js'; import {attachRefIssueContextPopup} from './contextpopup.js';
import {POST} from '../modules/fetch.js';
const {csrfToken} = window.config;
function initEditPreviewTab($form) { function initEditPreviewTab($form) {
const $tabMenu = $form.find('.tabular.menu'); const $tabMenu = $form.find('.tabular.menu');
$tabMenu.find('.item').tab(); $tabMenu.find('.item').tab();
const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`); const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`);
if ($previewTab.length) { if ($previewTab.length) {
$previewTab.on('click', function () { $previewTab.on('click', async function () {
const $this = $(this); const $this = $(this);
let context = `${$this.data('context')}/`; let context = `${$this.data('context')}/`;
const mode = $this.data('markup-mode') || 'comment'; const mode = $this.data('markup-mode') || 'comment';
@ -21,43 +20,30 @@ function initEditPreviewTab($form) {
context += treePathEl.val(); context += treePathEl.val();
} }
context = context.substring(0, context.lastIndexOf('/')); context = context.substring(0, context.lastIndexOf('/'));
$.post($this.data('url'), {
_csrf: csrfToken, const formData = new FormData();
mode, formData.append('mode', mode);
context, formData.append('context', context);
text: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val(), formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val());
file_path: treePathEl.val(), formData.append('file_path', treePathEl.val());
}, (data) => { try {
const response = await POST($this.data('url'), {data: formData});
const data = await response.text();
const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`); const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
renderPreviewPanelContent($previewPanel, data); renderPreviewPanelContent($previewPanel, data);
}); } catch (error) {
console.error('Error:', error);
}
}); });
} }
} }
function initEditDiffTab($form) {
const $tabMenu = $form.find('.tabular.menu');
$tabMenu.find('.item').tab();
$tabMenu.find(`.item[data-tab="${$tabMenu.data('diff')}"]`).on('click', function () {
const $this = $(this);
$.post($this.data('url'), {
_csrf: csrfToken,
context: $this.data('context'),
content: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val(),
}, (data) => {
const $diffPreviewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('diff')}"]`);
$diffPreviewPanel.html(data);
});
});
}
function initEditorForm() { function initEditorForm() {
if ($('.repository .edit.form').length === 0) { if ($('.repository .edit.form').length === 0) {
return; return;
} }
initEditPreviewTab($('.repository .edit.form')); initEditPreviewTab($('.repository .edit.form'));
initEditDiffTab($('.repository .edit.form'));
} }
function getCursorPosition($e) { function getCursorPosition($e) {