mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +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:
		| @@ -3,7 +3,10 @@ | ||||
| 	{{template "repo/header" .}} | ||||
| 	<div class="ui container"> | ||||
| 		{{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}} | ||||
| 			<input type="hidden" name="last_commit" value="{{.last_commit}}"> | ||||
| 			<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}"> | ||||
| @@ -29,7 +32,7 @@ | ||||
| 				<div class="ui top attached header"> | ||||
| 					<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="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}} | ||||
| 						<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}} | ||||
| @@ -38,8 +41,6 @@ | ||||
| 				<div class="ui bottom attached segment tw-p-0"> | ||||
| 					<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}}" | ||||
| 							data-url="{{.Repository.Link}}/markup" | ||||
| 							data-context="{{.RepoLink}}" | ||||
| 							data-previewable-extensions="{{.PreviewableExtensions}}" | ||||
| 							data-line-wrap-extensions="{{.LineWrapExtensions}}">{{.FileContent}}</textarea> | ||||
| 						<div class="editor-loading is-loading"></div> | ||||
| @@ -55,24 +56,5 @@ | ||||
| 			{{template "repo/editor/commit_form" .}} | ||||
| 		</form> | ||||
| 	</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> | ||||
| {{template "base/footer" .}} | ||||
|   | ||||
| @@ -3,7 +3,10 @@ | ||||
| 	{{template "repo/header" .}} | ||||
| 	<div class="ui container"> | ||||
| 		{{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}} | ||||
| 			<input type="hidden" name="last_commit" value="{{.last_commit}}"> | ||||
| 			<input type="hidden" name="page_has_posted" value="{{.PageHasPosted}}"> | ||||
| @@ -33,25 +36,5 @@ | ||||
| 			{{template "repo/editor/commit_form" .}} | ||||
| 		</form> | ||||
| 	</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> | ||||
| {{template "base/footer" .}} | ||||
|   | ||||
| @@ -134,19 +134,17 @@ function getFileBasedOptions(filename: string, lineWrapExts: string[]) { | ||||
| } | ||||
|  | ||||
| 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 (previewable) { | ||||
|     const newUrl = (previewTab.getAttribute('data-url') || '').replace(/(.*)\/.*/, `$1/markup`); | ||||
|     previewTab.setAttribute('data-url', newUrl); | ||||
|     previewTab.style.display = ''; | ||||
|   } else { | ||||
|     previewTab.style.display = 'none'; | ||||
|     // 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 | ||||
|     if (previewTab.classList.contains('active')) { | ||||
|       const writeTab = document.querySelector('a[data-tab="write"]'); | ||||
|       const writeTab = document.querySelector<HTMLElement>('a[data-tab="write"]'); | ||||
|       writeTab.click(); | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import {fomanticQuery} from '../../modules/fomantic/base.ts'; | ||||
|  | ||||
| const {i18n} = window.config; | ||||
|  | ||||
| export function confirmModal({header = '', content = '', confirmButtonColor = 'primary'} = {}) { | ||||
| export function confirmModal({header = '', content = '', confirmButtonColor = 'primary'} = {}): Promise<boolean> { | ||||
|   return new Promise((resolve) => { | ||||
|     const headerHtml = header ? `<div class="header">${htmlEscape(header)}</div>` : ''; | ||||
|     const modal = createElementFromHTML(` | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import $ from 'jquery'; | ||||
| import {htmlEscape} from 'escape-goat'; | ||||
| import {createCodeEditor} from './codeeditor.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 {POST} from '../modules/fetch.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) { | ||||
|   const $tabMenu = $form.find('.repo-editor-menu'); | ||||
|   $tabMenu.find('.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('/')); | ||||
| function initEditPreviewTab(elForm: HTMLFormElement) { | ||||
|   const elTabMenu = elForm.querySelector('.repo-editor-menu'); | ||||
|   fomanticQuery(elTabMenu.querySelectorAll('.item')).tab(); | ||||
|  | ||||
|       const formData = new FormData(); | ||||
|       formData.append('mode', mode); | ||||
|       formData.append('context', context); | ||||
|       formData.append('text', $form.find('.tab[data-tab="write"] textarea').val()); | ||||
|       formData.append('file_path', $treePathEl.val()); | ||||
|       try { | ||||
|         const response = await POST($this.data('url'), {data: formData}); | ||||
|         const data = await response.text(); | ||||
|         const $previewPanel = $form.find('.tab[data-tab="preview"]'); | ||||
|         if ($previewPanel.length) { | ||||
|           renderPreviewPanelContent($previewPanel, data); | ||||
|         } | ||||
|       } catch (error) { | ||||
|         console.error('Error:', error); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|   const elPreviewTab = elTabMenu.querySelector('a[data-tab="preview"]'); | ||||
|   const elPreviewPanel = elForm.querySelector('.tab[data-tab="preview"]'); | ||||
|   if (!elPreviewTab || !elPreviewPanel) return; | ||||
|  | ||||
|   elPreviewTab.addEventListener('click', async () => { | ||||
|     const elTreePath = elForm.querySelector<HTMLInputElement>('input#tree_path'); | ||||
|     const previewUrl = elPreviewTab.getAttribute('data-preview-url'); | ||||
|     const previewContextRef = elPreviewTab.getAttribute('data-preview-context-ref'); | ||||
|     let previewContext = `${previewContextRef}/${elTreePath.value}`; | ||||
|     previewContext = previewContext.substring(0, previewContext.lastIndexOf('/')); | ||||
|     const formData = new FormData(); | ||||
|     formData.append('mode', 'file'); | ||||
|     formData.append('context', previewContext); | ||||
|     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() { | ||||
| @@ -151,8 +144,8 @@ export function initRepoEditor() { | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   const $form = $('.repository.editor .edit.form'); | ||||
|   initEditPreviewTab($form); | ||||
|   const elForm = document.querySelector<HTMLFormElement>('.repository.editor .edit.form'); | ||||
|   initEditPreviewTab(elForm); | ||||
|  | ||||
|   (async () => { | ||||
|     const editor = await createCodeEditor(editArea, filenameInput); | ||||
| @@ -160,16 +153,16 @@ export function initRepoEditor() { | ||||
|     // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage | ||||
|     // to enable or disable the commit button | ||||
|     const commitButton = document.querySelector<HTMLButtonElement>('#commit-button'); | ||||
|     const $editForm = $('.ui.edit.form'); | ||||
|     const dirtyFileClass = 'dirty-file'; | ||||
|  | ||||
|     // 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; | ||||
|     } | ||||
|  | ||||
|     // 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, | ||||
|       dirtyClass: dirtyFileClass, | ||||
|       fieldSelector: ':input:not(.commit-form-wrapper :input)', | ||||
| @@ -187,15 +180,17 @@ export function initRepoEditor() { | ||||
|       editor.setValue(value); | ||||
|     } | ||||
|  | ||||
|     commitButton?.addEventListener('click', (e) => { | ||||
|     commitButton?.addEventListener('click', async (e) => { | ||||
|       // A modal which asks if an empty file should be committed | ||||
|       if (!editArea.value) { | ||||
|         $('#edit-empty-content-modal').modal({ | ||||
|           onApprove() { | ||||
|             $('.edit.form').trigger('submit'); | ||||
|           }, | ||||
|         }).modal('show'); | ||||
|         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) { | ||||
|   $(selector).areYouSure(); | ||||
| export function applyAreYouSure(selectorOrEl: string|Element|$, opts = {}) { | ||||
|   $(selectorOrEl).areYouSure(opts); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user