mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +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:
		| @@ -186,7 +186,7 @@ | |||||||
|  |  | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
| 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | ||||||
| 					<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a>{{/* TODO: Convert links without href to buttons for a11y */}} | 					<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button> | ||||||
| 				</div> | 				</div> | ||||||
| 			</form> | 			</form> | ||||||
| 		</div> | 		</div> | ||||||
|   | |||||||
| @@ -32,11 +32,13 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly. | |||||||
| 		mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}}, | 		mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}}, | ||||||
| 		{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}} | 		{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}} | ||||||
| 		i18n: { | 		i18n: { | ||||||
| 			copy_success: '{{.locale.Tr "copy_success"}}', | 			copy_success: {{.locale.Tr "copy_success"}}, | ||||||
| 			copy_error: '{{.locale.Tr "copy_error"}}', | 			copy_error: {{.locale.Tr "copy_error"}}, | ||||||
| 			error_occurred: '{{.locale.Tr "error.occurred"}}', | 			error_occurred: {{.locale.Tr "error.occurred"}}, | ||||||
| 			network_error: '{{.locale.Tr "error.network_error"}}', | 			network_error: {{.locale.Tr "error.network_error"}}, | ||||||
| 			remove_label_str: '{{.locale.Tr "remove_label_str"}}', | 			remove_label_str: {{.locale.Tr "remove_label_str"}}, | ||||||
|  | 			modal_confirm: {{.locale.Tr "modal.confirm"}}, | ||||||
|  | 			modal_cancel: {{.locale.Tr "modal.cancel"}}, | ||||||
| 		}, | 		}, | ||||||
| 	}; | 	}; | ||||||
| 	{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}} | 	{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}} | ||||||
|   | |||||||
| @@ -90,7 +90,7 @@ | |||||||
|  |  | ||||||
| 						<div class="field"> | 						<div class="field"> | ||||||
| 							<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | 							<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | ||||||
| 							<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a> | 							<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button> | ||||||
| 						</div> | 						</div> | ||||||
| 					</form> | 					</form> | ||||||
| 				</div> | 				</div> | ||||||
|   | |||||||
| @@ -9,14 +9,12 @@ | |||||||
| 				{{template "org/team/navbar" .}} | 				{{template "org/team/navbar" .}} | ||||||
| 				{{if .IsOrganizationOwner}} | 				{{if .IsOrganizationOwner}} | ||||||
| 					<div class="ui attached segment"> | 					<div class="ui attached segment"> | ||||||
| 						<form class="ui form ignore-dirty" id="add-member-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post"> | 						<form class="ui form ignore-dirty gt-df gt-fw gt-gap-3" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/add" method="post"> | ||||||
| 							{{.CsrfTokenHtml}} | 							{{.CsrfTokenHtml}} | ||||||
| 							<input type="hidden" name="uid" value="{{.SignedUser.ID}}"> | 							<input type="hidden" name="uid" value="{{.SignedUser.ID}}"> | ||||||
| 							<div class="inline field ui left"> | 							<div id="search-user-box" class="ui search gt-mr-3"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{.locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}> | ||||||
| 								<div id="search-user-box" class="ui search"{{if .IsEmailInviteEnabled}} data-allow-email="true" data-allow-email-description="{{.locale.Tr "org.teams.invite_team_member" $.Team.Name}}"{{end}}> | 								<div class="ui input"> | ||||||
| 									<div class="ui input"> | 									<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required> | ||||||
| 										<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required> |  | ||||||
| 									</div> |  | ||||||
| 								</div> | 								</div> | ||||||
| 							</div> | 							</div> | ||||||
| 							<button class="ui green button">{{.locale.Tr "org.teams.add_team_member"}}</button> | 							<button class="ui green button">{{.locale.Tr "org.teams.add_team_member"}}</button> | ||||||
|   | |||||||
| @@ -9,25 +9,19 @@ | |||||||
| 				{{template "org/team/navbar" .}} | 				{{template "org/team/navbar" .}} | ||||||
| 				{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}} | 				{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}} | ||||||
| 				{{if $canAddRemove}} | 				{{if $canAddRemove}} | ||||||
| 					<div class="ui attached segment" id="repo-top-segment"> | 					<div class="ui attached segment gt-df gt-fw gt-gap-3"> | ||||||
| 						<div class="inline ui field left"> | 						<form class="ui form ignore-dirty gt-f1 gt-dif" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post"> | ||||||
| 							<form class="ui form ignore-dirty" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post"> | 							{{.CsrfTokenHtml}} | ||||||
| 								{{.CsrfTokenHtml}} | 							<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search"> | ||||||
| 								<div class="inline field ui left"> | 								<div class="ui input"> | ||||||
| 									<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search"> | 									<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required> | ||||||
| 										<div class="ui input"> |  | ||||||
| 											<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required> |  | ||||||
| 										</div> |  | ||||||
| 									</div> |  | ||||||
| 								</div> | 								</div> | ||||||
| 								<button class="ui green button">{{.locale.Tr "add"}}</button> | 							</div> | ||||||
| 							</form> | 							<button class="ui green button gt-ml-3">{{.locale.Tr "add"}}</button> | ||||||
| 						</div> | 						</form> | ||||||
| 						<div class="inline ui field right"> | 						<div class="gt-dib"> | ||||||
| 							<form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/repositories" method="post"> | 							<button class="ui green button link-action" data-modal-confirm="{{.locale.Tr "org.teams.add_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{.locale.Tr "add_all"}}</button> | ||||||
| 								<button class="ui green button add-all-button" data-modal-id="org-team-add-all-repo" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/addall">{{.locale.Tr "add_all"}}</button> | 							<button class="ui red button link-action" data-modal-confirm="{{.locale.Tr "org.teams.remove_all_repos_desc"}}" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{.locale.Tr "remove_all"}}</button> | ||||||
| 								<button class="ui red button delete-button" data-modal-id="org-team-remove-all-repo" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/removeall">{{.locale.Tr "remove_all"}}</button> |  | ||||||
| 							</form> |  | ||||||
| 						</div> | 						</div> | ||||||
| 					</div> | 					</div> | ||||||
| 				{{end}} | 				{{end}} | ||||||
| @@ -64,26 +58,4 @@ | |||||||
| 	</div> | 	</div> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <div class="ui g-modal-confirm delete modal" id="org-team-remove-all-repo"> |  | ||||||
| 	<div class="header"> |  | ||||||
| 		{{svg "octicon-trash"}} |  | ||||||
| 		{{.locale.Tr "org.teams.remove_all_repos_title"}} |  | ||||||
| 	</div> |  | ||||||
| 	<div class="content"> |  | ||||||
| 		<p>{{.locale.Tr "org.teams.remove_all_repos_desc"}}</p> |  | ||||||
| 	</div> |  | ||||||
| 	{{template "base/modal_actions_confirm" .}} |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| <div class="ui g-modal-confirm addall modal" id="org-team-add-all-repo"> |  | ||||||
| 	<div class="header"> |  | ||||||
| 		{{svg "octicon-globe"}} |  | ||||||
| 		{{.locale.Tr "org.teams.add_all_repos_title"}} |  | ||||||
| 	</div> |  | ||||||
| 	<div class="content"> |  | ||||||
| 		<p>{{.locale.Tr "org.teams.add_all_repos_desc"}}</p> |  | ||||||
| 	</div> |  | ||||||
| 	{{template "base/modal_actions_confirm" .}} |  | ||||||
| </div> |  | ||||||
|  |  | ||||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||||
|   | |||||||
| @@ -165,7 +165,7 @@ | |||||||
| 										{{end}} | 										{{end}} | ||||||
| 										{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}} | 										{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}} | ||||||
| 											{{if .IsDeleted}} | 											{{if .IsDeleted}} | ||||||
| 												<button class="btn interact-bg gt-p-3 undo-button" data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID}}&name={{.DeletedBranch.Name}}&page={{$.Page.Paginater.Current}}" data-tooltip-content="{{$.locale.Tr "repo.branch.restore" (.Name)}}"> | 												<button class="btn interact-bg gt-p-3 link-action restore-branch-button" data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID}}&name={{.DeletedBranch.Name}}&page={{$.Page.Paginater.Current}}" data-tooltip-content="{{$.locale.Tr "repo.branch.restore" (.Name)}}"> | ||||||
| 													<span class="text blue"> | 													<span class="text blue"> | ||||||
| 														{{svg "octicon-reply"}} | 														{{svg "octicon-reply"}} | ||||||
| 													</span> | 													</span> | ||||||
|   | |||||||
| @@ -61,7 +61,7 @@ | |||||||
|  |  | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
| 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | ||||||
| 					<a class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</a> | 					<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button> | ||||||
| 				</div> | 				</div> | ||||||
| 			</form> | 			</form> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -125,7 +125,7 @@ | |||||||
|  |  | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
| 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | 					<button class="ui green button">{{$.locale.Tr "settings.update_avatar"}}</button> | ||||||
| 					<button class="ui red button delete-post" data-request-url="{{.Link}}/avatar/delete" data-done-url="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button> | 					<button class="ui red button link-action" data-url="{{.Link}}/avatar/delete" data-redirect="{{.Link}}">{{$.locale.Tr "settings.delete_current_avatar"}}</button> | ||||||
| 				</div> | 				</div> | ||||||
| 			</form> | 			</form> | ||||||
| 		</div> | 		</div> | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ func TestDeleteBranch(t *testing.T) { | |||||||
| func TestUndoDeleteBranch(t *testing.T) { | func TestUndoDeleteBranch(t *testing.T) { | ||||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||||
| 		deleteBranch(t) | 		deleteBranch(t) | ||||||
| 		htmlDoc, name := branchAction(t, ".undo-button") | 		htmlDoc, name := branchAction(t, ".restore-branch-button") | ||||||
| 		assert.Contains(t, | 		assert.Contains(t, | ||||||
| 			htmlDoc.doc.Find(".ui.positive.message").Text(), | 			htmlDoc.doc.Find(".ui.positive.message").Text(), | ||||||
| 			translation.NewLocale("en-US").Tr("repo.branch.restore_success", name), | 			translation.NewLocale("en-US").Tr("repo.branch.restore_success", name), | ||||||
|   | |||||||
| @@ -205,29 +205,6 @@ | |||||||
|   margin: 0; |   margin: 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| .organization.teams #add-repo-form input, |  | ||||||
| .organization.teams #repo-multiple-form input, |  | ||||||
| .organization.teams #add-member-form input { |  | ||||||
|   margin-left: 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .organization.teams #add-repo-form .ui.button, |  | ||||||
| .organization.teams #repo-multiple-form .ui.button, |  | ||||||
| .organization.teams #add-member-form .ui.button { |  | ||||||
|   margin-left: 5px; |  | ||||||
|   margin-top: -3px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .organization.teams #repo-top-segment { |  | ||||||
|   height: 60px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @media (max-width: 767.98px) { |  | ||||||
|   .organization.teams #repo-top-segment { |  | ||||||
|     height: 100px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .org-team-navbar .active.item { | .org-team-navbar .active.item { | ||||||
|   background: var(--color-box-body) !important; |   background: var(--color-box-body) !important; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import {svg} from '../svg.js'; | |||||||
| import {hideElem, showElem, toggleElem} from '../utils/dom.js'; | import {hideElem, showElem, toggleElem} from '../utils/dom.js'; | ||||||
| import {htmlEscape} from 'escape-goat'; | import {htmlEscape} from 'escape-goat'; | ||||||
|  |  | ||||||
| const {appUrl, csrfToken} = window.config; | const {appUrl, csrfToken, i18n} = window.config; | ||||||
|  |  | ||||||
| export function initGlobalFormDirtyLeaveConfirm() { | export function initGlobalFormDirtyLeaveConfirm() { | ||||||
|   // Warn users that try to leave a page after entering data into a form. |   // 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() { | export function initGlobalLinkActions() { | ||||||
|   function showDeletePopup(e) { |   function showDeletePopup(e) { | ||||||
|     e.preventDefault(); |     e.preventDefault(); | ||||||
| @@ -217,75 +273,9 @@ export function initGlobalLinkActions() { | |||||||
|     }).modal('show'); |     }).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. |   // Helpers. | ||||||
|   $('.delete-button').on('click', showDeletePopup); |   $('.delete-button').on('click', showDeletePopup); | ||||||
|   $('.link-action').on('click', linkAction); |   $('.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() { | export function initGlobalButtons() { | ||||||
| @@ -346,16 +336,6 @@ export function initGlobalButtons() { | |||||||
|       initCompColorPicker(); |       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
	 wxiaoguang
					wxiaoguang