mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-30 19:08:37 +00:00 
			
		
		
		
	Improve AJAX link and modal confirm dialog (#25210)
Clarify the "link-action" behavior: > // A "link-action" can post AJAX request to its "data-url" > // Then the browser is redirect to: the "redirect" in response, or "data-redirect" attribute, or current URL by reloading. And enhance the "link-action" to support showing a modal dialog for confirm. A similar general approach could also help PRs like https://github.com/go-gitea/gitea/pull/22344#discussion_r1062883436 > // If the "link-action" has "data-modal-confirm(-html)" attribute, a confirm modal dialog will be shown before taking action. And a lot of duplicate code can be removed now. A good framework design can help to avoid code copying&pasting. --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
		| @@ -8,7 +8,7 @@ import {svg} from '../svg.js'; | ||||
| import {hideElem, showElem, toggleElem} from '../utils/dom.js'; | ||||
| import {htmlEscape} from 'escape-goat'; | ||||
|  | ||||
| const {appUrl, csrfToken} = window.config; | ||||
| const {appUrl, csrfToken, i18n} = window.config; | ||||
|  | ||||
| export function initGlobalFormDirtyLeaveConfirm() { | ||||
|   // Warn users that try to leave a page after entering data into a form. | ||||
| @@ -172,6 +172,62 @@ export function initGlobalDropzone() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| function linkAction(e) { | ||||
|   e.preventDefault(); | ||||
|  | ||||
|   // A "link-action" can post AJAX request to its "data-url" | ||||
|   // Then the browser is redirect to: the "redirect" in response, or "data-redirect" attribute, or current URL by reloading. | ||||
|   // If the "link-action" has "data-modal-confirm(-html)" attribute, a confirm modal dialog will be shown before taking action. | ||||
|  | ||||
|   const $this = $(e.target); | ||||
|   const redirect = $this.attr('data-redirect'); | ||||
|  | ||||
|   const request = () => { | ||||
|     $this.prop('disabled', true); | ||||
|     $.post($this.attr('data-url'), { | ||||
|       _csrf: csrfToken | ||||
|     }).done((data) => { | ||||
|       if (data && data.redirect) { | ||||
|         window.location.href = data.redirect; | ||||
|       } else if (redirect) { | ||||
|         window.location.href = redirect; | ||||
|       } else { | ||||
|         window.location.reload(); | ||||
|       } | ||||
|     }).always(() => { | ||||
|       $this.prop('disabled', false); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   const modalConfirmHtml = htmlEscape($this.attr('data-modal-confirm') || ''); | ||||
|   if (!modalConfirmHtml) { | ||||
|     request(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const okButtonColor = $this.hasClass('red') || $this.hasClass('yellow') || $this.hasClass('orange') || $this.hasClass('negative') ? 'orange' : 'green'; | ||||
|  | ||||
|   const $modal = $(` | ||||
| <div class="ui g-modal-confirm modal"> | ||||
|   <div class="content">${modalConfirmHtml}</div> | ||||
|   <div class="actions"> | ||||
|     <button class="ui basic cancel button">${svg('octicon-x')} ${i18n.modal_cancel}</button> | ||||
|     <button class="ui ${okButtonColor} ok button">${svg('octicon-check')} ${i18n.modal_confirm}</button> | ||||
|   </div> | ||||
| </div> | ||||
| `); | ||||
|  | ||||
|   $modal.appendTo(document.body); | ||||
|   $modal.modal({ | ||||
|     onApprove() { | ||||
|       request(); | ||||
|     }, | ||||
|     onHidden() { | ||||
|       $modal.remove(); | ||||
|     }, | ||||
|   }).modal('show'); | ||||
| } | ||||
|  | ||||
| export function initGlobalLinkActions() { | ||||
|   function showDeletePopup(e) { | ||||
|     e.preventDefault(); | ||||
| @@ -217,75 +273,9 @@ export function initGlobalLinkActions() { | ||||
|     }).modal('show'); | ||||
|   } | ||||
|  | ||||
|   function showAddAllPopup(e) { | ||||
|     e.preventDefault(); | ||||
|     const $this = $(this); | ||||
|     let filter = ''; | ||||
|     if ($this.attr('data-modal-id')) { | ||||
|       filter += `#${$this.attr('data-modal-id')}`; | ||||
|     } | ||||
|  | ||||
|     const dialog = $(`.addall.modal${filter}`); | ||||
|     dialog.find('.name').text($this.data('name')); | ||||
|  | ||||
|     dialog.modal({ | ||||
|       closable: false, | ||||
|       onApprove() { | ||||
|         if ($this.data('type') === 'form') { | ||||
|           $($this.data('form')).trigger('submit'); | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         $.post($this.data('url'), { | ||||
|           _csrf: csrfToken, | ||||
|           id: $this.data('id') | ||||
|         }).done((data) => { | ||||
|           window.location.href = data.redirect; | ||||
|         }); | ||||
|       } | ||||
|     }).modal('show'); | ||||
|   } | ||||
|  | ||||
|   function linkAction(e) { | ||||
|     e.preventDefault(); | ||||
|     const $this = $(this); | ||||
|     const redirect = $this.data('redirect'); | ||||
|     $this.prop('disabled', true); | ||||
|     $.post($this.data('url'), { | ||||
|       _csrf: csrfToken | ||||
|     }).done((data) => { | ||||
|       if (data.redirect) { | ||||
|         window.location.href = data.redirect; | ||||
|       } else if (redirect) { | ||||
|         window.location.href = redirect; | ||||
|       } else { | ||||
|         window.location.reload(); | ||||
|       } | ||||
|     }).always(() => { | ||||
|       $this.prop('disabled', false); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // Helpers. | ||||
|   $('.delete-button').on('click', showDeletePopup); | ||||
|   $('.link-action').on('click', linkAction); | ||||
|  | ||||
|   // FIXME: this function is only used once, and not common, not well designed. should be refactored later | ||||
|   $('.add-all-button').on('click', showAddAllPopup); | ||||
|  | ||||
|   // FIXME: this is only used once, and should be replace with `link-action` instead | ||||
|   $('.undo-button').on('click', function () { | ||||
|     const $this = $(this); | ||||
|     $this.prop('disabled', true); | ||||
|     $.post($this.data('url'), { | ||||
|       _csrf: csrfToken, | ||||
|       id: $this.data('id') | ||||
|     }).done((data) => { | ||||
|       window.location.href = data.redirect; | ||||
|     }).always(() => { | ||||
|       $this.prop('disabled', false); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export function initGlobalButtons() { | ||||
| @@ -346,16 +336,6 @@ export function initGlobalButtons() { | ||||
|       initCompColorPicker(); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   $('.delete-post.button').on('click', function (e) { | ||||
|     e.preventDefault(); | ||||
|     const $this = $(this); | ||||
|     $.post($this.attr('data-request-url'), { | ||||
|       _csrf: csrfToken | ||||
|     }).done(() => { | ||||
|       window.location.href = $this.attr('data-done-url'); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user