mirror of
https://github.com/go-gitea/gitea
synced 2024-12-22 16:44:26 +00:00
Fix file editor & preview (#32706)
Fix a regression caused by jQuery removal (`renderPreviewPanelContent`) And simplify the file editor, it doesn't need to be that complex. And remove jQuery code.
This commit is contained in:
parent
e45ffc530f
commit
838653d1df
@ -3,7 +3,10 @@
|
|||||||
{{template "repo/header" .}}
|
{{template "repo/header" .}}
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui edit form" method="post">
|
<form class="ui edit form" method="post"
|
||||||
|
data-text-empty-confirm-header="{{ctx.Locale.Tr "repo.editor.commit_empty_file_header"}}"
|
||||||
|
data-text-empty-confirm-content="{{ctx.Locale.Tr "repo.editor.commit_empty_file_text"}}"
|
||||||
|
>
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="last_commit" value="{{.last_commit}}">
|
<input type="hidden" name="last_commit" value="{{.last_commit}}">
|
||||||
<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}">
|
<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}">
|
||||||
@ -29,7 +32,7 @@
|
|||||||
<div class="ui top attached header">
|
<div class="ui top attached header">
|
||||||
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
<div class="ui compact small menu small-menu-items repo-editor-menu">
|
||||||
<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-preview-url="{{.Repository.Link}}/markup" data-preview-context-ref="{{.RepoLink}}/src/{{.BranchNameSubURL}}">{{svg "octicon-eye"}} {{ctx.Locale.Tr "preview"}}</a>
|
||||||
{{if not .IsNewFile}}
|
{{if not .IsNewFile}}
|
||||||
<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>
|
<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}}
|
||||||
@ -38,8 +41,6 @@
|
|||||||
<div class="ui bottom attached segment tw-p-0">
|
<div class="ui bottom attached segment tw-p-0">
|
||||||
<div class="ui active tab tw-rounded-b" data-tab="write">
|
<div class="ui active tab tw-rounded-b" data-tab="write">
|
||||||
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
<textarea id="edit_area" name="content" class="tw-hidden" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
|
||||||
data-url="{{.Repository.Link}}/markup"
|
|
||||||
data-context="{{.RepoLink}}"
|
|
||||||
data-previewable-extensions="{{.PreviewableExtensions}}"
|
data-previewable-extensions="{{.PreviewableExtensions}}"
|
||||||
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea>
|
||||||
<div class="editor-loading is-loading"></div>
|
<div class="editor-loading is-loading"></div>
|
||||||
@ -55,24 +56,5 @@
|
|||||||
{{template "repo/editor/commit_form" .}}
|
{{template "repo/editor/commit_form" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui g-modal-confirm modal" id="edit-empty-content-modal">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-file"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.commit_empty_file_header"}}
|
|
||||||
</div>
|
|
||||||
<div class="center content">
|
|
||||||
<p>{{ctx.Locale.Tr "repo.editor.commit_empty_file_text"}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<button class="ui cancel button">
|
|
||||||
{{svg "octicon-x"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.cancel"}}
|
|
||||||
</button>
|
|
||||||
<button class="ui primary ok button">
|
|
||||||
{{svg "fontawesome-save"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.commit_changes"}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
{{template "repo/header" .}}
|
{{template "repo/header" .}}
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui edit form" method="post" action="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}">
|
<form class="ui edit form" method="post" action="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}"
|
||||||
|
data-text-empty-confirm-header="{{ctx.Locale.Tr "repo.editor.commit_empty_file_header"}}"
|
||||||
|
data-text-empty-confirm-content="{{ctx.Locale.Tr "repo.editor.commit_empty_file_text"}}"
|
||||||
|
>
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<input type="hidden" name="last_commit" value="{{.last_commit}}">
|
<input type="hidden" name="last_commit" value="{{.last_commit}}">
|
||||||
<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}">
|
<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}">
|
||||||
@ -33,25 +36,5 @@
|
|||||||
{{template "repo/editor/commit_form" .}}
|
{{template "repo/editor/commit_form" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="edit-empty-content-modal">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-file"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.commit_empty_file_header"}}
|
|
||||||
</div>
|
|
||||||
<div class="center content">
|
|
||||||
<p>{{ctx.Locale.Tr "repo.editor.commit_empty_file_text"}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<button class="ui cancel button">
|
|
||||||
{{svg "octicon-x"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.cancel"}}
|
|
||||||
</button>
|
|
||||||
<button class="ui primary ok button">
|
|
||||||
{{svg "fontawesome-save"}}
|
|
||||||
{{ctx.Locale.Tr "repo.editor.commit_changes"}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
@ -134,19 +134,17 @@ function getFileBasedOptions(filename: string, lineWrapExts: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function togglePreviewDisplay(previewable: boolean) {
|
function togglePreviewDisplay(previewable: boolean) {
|
||||||
const previewTab = document.querySelector('a[data-tab="preview"]');
|
const previewTab = document.querySelector<HTMLElement>('a[data-tab="preview"]');
|
||||||
if (!previewTab) return;
|
if (!previewTab) return;
|
||||||
|
|
||||||
if (previewable) {
|
if (previewable) {
|
||||||
const newUrl = (previewTab.getAttribute('data-url') || '').replace(/(.*)\/.*/, `$1/markup`);
|
|
||||||
previewTab.setAttribute('data-url', newUrl);
|
|
||||||
previewTab.style.display = '';
|
previewTab.style.display = '';
|
||||||
} else {
|
} else {
|
||||||
previewTab.style.display = 'none';
|
previewTab.style.display = 'none';
|
||||||
// If the "preview" tab was active, user changes the filename to a non-previewable one,
|
// If the "preview" tab was active, user changes the filename to a non-previewable one,
|
||||||
// then the "preview" tab becomes inactive (hidden), so the "write" tab should become active
|
// then the "preview" tab becomes inactive (hidden), so the "write" tab should become active
|
||||||
if (previewTab.classList.contains('active')) {
|
if (previewTab.classList.contains('active')) {
|
||||||
const writeTab = document.querySelector('a[data-tab="write"]');
|
const writeTab = document.querySelector<HTMLElement>('a[data-tab="write"]');
|
||||||
writeTab.click();
|
writeTab.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import {fomanticQuery} from '../../modules/fomantic/base.ts';
|
|||||||
|
|
||||||
const {i18n} = window.config;
|
const {i18n} = window.config;
|
||||||
|
|
||||||
export function confirmModal({header = '', content = '', confirmButtonColor = 'primary'} = {}) {
|
export function confirmModal({header = '', content = '', confirmButtonColor = 'primary'} = {}): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const headerHtml = header ? `<div class="header">${htmlEscape(header)}</div>` : '';
|
const headerHtml = header ? `<div class="header">${htmlEscape(header)}</div>` : '';
|
||||||
const modal = createElementFromHTML(`
|
const modal = createElementFromHTML(`
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import $ from 'jquery';
|
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {createCodeEditor} from './codeeditor.ts';
|
import {createCodeEditor} from './codeeditor.ts';
|
||||||
import {hideElem, queryElems, showElem, createElementFromHTML} from '../utils/dom.ts';
|
import {hideElem, queryElems, showElem, createElementFromHTML} from '../utils/dom.ts';
|
||||||
@ -6,39 +5,33 @@ import {initMarkupContent} from '../markup/content.ts';
|
|||||||
import {attachRefIssueContextPopup} from './contextpopup.ts';
|
import {attachRefIssueContextPopup} from './contextpopup.ts';
|
||||||
import {POST} from '../modules/fetch.ts';
|
import {POST} from '../modules/fetch.ts';
|
||||||
import {initDropzone} from './dropzone.ts';
|
import {initDropzone} from './dropzone.ts';
|
||||||
|
import {confirmModal} from './comp/ConfirmModal.ts';
|
||||||
|
import {applyAreYouSure} from '../vendor/jquery.are-you-sure.ts';
|
||||||
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
|
|
||||||
function initEditPreviewTab($form) {
|
function initEditPreviewTab(elForm: HTMLFormElement) {
|
||||||
const $tabMenu = $form.find('.repo-editor-menu');
|
const elTabMenu = elForm.querySelector('.repo-editor-menu');
|
||||||
$tabMenu.find('.item').tab();
|
fomanticQuery(elTabMenu.querySelectorAll('.item')).tab();
|
||||||
const $previewTab = $tabMenu.find('a[data-tab="preview"]');
|
|
||||||
if ($previewTab.length) {
|
|
||||||
$previewTab.on('click', async function () {
|
|
||||||
const $this = $(this);
|
|
||||||
let context = `${$this.data('context')}/`;
|
|
||||||
const mode = $this.data('markup-mode') || 'comment';
|
|
||||||
const $treePathEl = $form.find('input#tree_path');
|
|
||||||
if ($treePathEl.length > 0) {
|
|
||||||
context += $treePathEl.val();
|
|
||||||
}
|
|
||||||
context = context.substring(0, context.lastIndexOf('/'));
|
|
||||||
|
|
||||||
const formData = new FormData();
|
const elPreviewTab = elTabMenu.querySelector('a[data-tab="preview"]');
|
||||||
formData.append('mode', mode);
|
const elPreviewPanel = elForm.querySelector('.tab[data-tab="preview"]');
|
||||||
formData.append('context', context);
|
if (!elPreviewTab || !elPreviewPanel) return;
|
||||||
formData.append('text', $form.find('.tab[data-tab="write"] textarea').val());
|
|
||||||
formData.append('file_path', $treePathEl.val());
|
elPreviewTab.addEventListener('click', async () => {
|
||||||
try {
|
const elTreePath = elForm.querySelector<HTMLInputElement>('input#tree_path');
|
||||||
const response = await POST($this.data('url'), {data: formData});
|
const previewUrl = elPreviewTab.getAttribute('data-preview-url');
|
||||||
const data = await response.text();
|
const previewContextRef = elPreviewTab.getAttribute('data-preview-context-ref');
|
||||||
const $previewPanel = $form.find('.tab[data-tab="preview"]');
|
let previewContext = `${previewContextRef}/${elTreePath.value}`;
|
||||||
if ($previewPanel.length) {
|
previewContext = previewContext.substring(0, previewContext.lastIndexOf('/'));
|
||||||
renderPreviewPanelContent($previewPanel, data);
|
const formData = new FormData();
|
||||||
}
|
formData.append('mode', 'file');
|
||||||
} catch (error) {
|
formData.append('context', previewContext);
|
||||||
console.error('Error:', error);
|
formData.append('text', elForm.querySelector<HTMLTextAreaElement>('.tab[data-tab="write"] textarea').value);
|
||||||
}
|
formData.append('file_path', elTreePath.value);
|
||||||
});
|
const response = await POST(previewUrl, {data: formData});
|
||||||
}
|
const data = await response.text();
|
||||||
|
renderPreviewPanelContent(elPreviewPanel, data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initRepoEditor() {
|
export function initRepoEditor() {
|
||||||
@ -151,8 +144,8 @@ export function initRepoEditor() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const $form = $('.repository.editor .edit.form');
|
const elForm = document.querySelector<HTMLFormElement>('.repository.editor .edit.form');
|
||||||
initEditPreviewTab($form);
|
initEditPreviewTab(elForm);
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const editor = await createCodeEditor(editArea, filenameInput);
|
const editor = await createCodeEditor(editArea, filenameInput);
|
||||||
@ -160,16 +153,16 @@ export function initRepoEditor() {
|
|||||||
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
||||||
// to enable or disable the commit button
|
// to enable or disable the commit button
|
||||||
const commitButton = document.querySelector<HTMLButtonElement>('#commit-button');
|
const commitButton = document.querySelector<HTMLButtonElement>('#commit-button');
|
||||||
const $editForm = $('.ui.edit.form');
|
|
||||||
const dirtyFileClass = 'dirty-file';
|
const dirtyFileClass = 'dirty-file';
|
||||||
|
|
||||||
// Disabling the button at the start
|
// Disabling the button at the start
|
||||||
if ($('input[name="page_has_posted"]').val() !== 'true') {
|
if (document.querySelector<HTMLInputElement>('input[name="page_has_posted"]').value !== 'true') {
|
||||||
commitButton.disabled = true;
|
commitButton.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registering a custom listener for the file path and the file content
|
// Registering a custom listener for the file path and the file content
|
||||||
$editForm.areYouSure({
|
// FIXME: it is not quite right here (old bug), it causes double-init, the global areYouSure "dirty" class will also be added
|
||||||
|
applyAreYouSure(elForm, {
|
||||||
silent: true,
|
silent: true,
|
||||||
dirtyClass: dirtyFileClass,
|
dirtyClass: dirtyFileClass,
|
||||||
fieldSelector: ':input:not(.commit-form-wrapper :input)',
|
fieldSelector: ':input:not(.commit-form-wrapper :input)',
|
||||||
@ -187,15 +180,17 @@ export function initRepoEditor() {
|
|||||||
editor.setValue(value);
|
editor.setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
commitButton?.addEventListener('click', (e) => {
|
commitButton?.addEventListener('click', async (e) => {
|
||||||
// A modal which asks if an empty file should be committed
|
// A modal which asks if an empty file should be committed
|
||||||
if (!editArea.value) {
|
if (!editArea.value) {
|
||||||
$('#edit-empty-content-modal').modal({
|
|
||||||
onApprove() {
|
|
||||||
$('.edit.form').trigger('submit');
|
|
||||||
},
|
|
||||||
}).modal('show');
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (await confirmModal({
|
||||||
|
header: elForm.getAttribute('data-text-empty-confirm-header'),
|
||||||
|
content: elForm.getAttribute('data-text-empty-confirm-content'),
|
||||||
|
})) {
|
||||||
|
elForm.classList.remove('dirty');
|
||||||
|
elForm.submit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
4
web_src/js/vendor/jquery.are-you-sure.ts
vendored
4
web_src/js/vendor/jquery.are-you-sure.ts
vendored
@ -196,6 +196,6 @@ export function initAreYouSure($) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyAreYouSure(selector: string) {
|
export function applyAreYouSure(selectorOrEl: string|Element|$, opts = {}) {
|
||||||
$(selector).areYouSure();
|
$(selectorOrEl).areYouSure(opts);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user