Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve AJAX link and modal confirm dialog #25210

Merged
merged 8 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion templates/admin/user/edit.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@

<div class="field">
<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>
silverwind marked this conversation as resolved.
Show resolved Hide resolved
</div>
</form>
</div>
Expand Down
12 changes: 7 additions & 5 deletions templates/base/head_script.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
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 */}}
i18n: {
copy_success: '{{.locale.Tr "copy_success"}}',
copy_error: '{{.locale.Tr "copy_error"}}',
error_occurred: '{{.locale.Tr "error.occurred"}}',
network_error: '{{.locale.Tr "error.network_error"}}',
remove_label_str: '{{.locale.Tr "remove_label_str"}}',
copy_success: {{.locale.Tr "copy_success"}},
copy_error: {{.locale.Tr "copy_error"}},
error_occurred: {{.locale.Tr "error.occurred"}},
network_error: {{.locale.Tr "error.network_error"}},
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 */}}
Expand Down
2 changes: 1 addition & 1 deletion templates/org/settings/options.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

<div class="field">
<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>
</form>
</div>
Expand Down
10 changes: 4 additions & 6 deletions templates/org/team/members.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
{{template "org/team/navbar" .}}
{{if .IsOrganizationOwner}}
<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}}
<input type="hidden" name="uid" value="{{.SignedUser.ID}}">
<div class="inline field ui left">
<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">
<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required>
</div>
<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 class="ui input">
<input class="prompt" name="uname" placeholder="{{.locale.Tr "repo.settings.search_user_placeholder"}}" autocomplete="off" required>
</div>
</div>
<button class="ui green button">{{.locale.Tr "org.teams.add_team_member"}}</button>
Expand Down
52 changes: 12 additions & 40 deletions templates/org/team/repositories.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,19 @@
{{template "org/team/navbar" .}}
{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
{{if $canAddRemove}}
<div class="ui attached segment" id="repo-top-segment">
<div class="inline ui field left">
<form class="ui form ignore-dirty" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
{{.CsrfTokenHtml}}
<div class="inline field ui left">
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
<div class="ui input">
<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
</div>
</div>
<div class="ui attached segment gt-df gt-fw gt-gap-3">
<form class="ui form ignore-dirty gt-f1 gt-dif" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/action/repo/add" method="post">
{{.CsrfTokenHtml}}
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
<div class="ui input">
<input class="prompt" name="repo_name" placeholder="{{.locale.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
</div>
<button class="ui green button">{{.locale.Tr "add"}}</button>
</form>
</div>
<div class="inline ui field right">
<form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName | PathEscape}}/repositories" method="post">
<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 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>
<button class="ui green button gt-ml-3">{{.locale.Tr "add"}}</button>
</form>
<div class="gt-dib">
<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 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>
</div>
</div>
{{end}}
Expand Down Expand Up @@ -64,26 +58,4 @@
</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" .}}
2 changes: 1 addition & 1 deletion templates/repo/branch/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
{{end}}
{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived) (not .IsProtected)}}
{{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">
{{svg "octicon-reply"}}
</span>
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/settings/options.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

<div class="field">
<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>
</form>

Expand Down
2 changes: 1 addition & 1 deletion templates/user/settings/profile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@

<div class="field">
<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>
</form>
</div>
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/branches_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestDeleteBranch(t *testing.T) {
func TestUndoDeleteBranch(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
deleteBranch(t)
htmlDoc, name := branchAction(t, ".undo-button")
htmlDoc, name := branchAction(t, ".restore-branch-button")
assert.Contains(t,
htmlDoc.doc.Find(".ui.positive.message").Text(),
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
Expand Down
23 changes: 0 additions & 23 deletions web_src/css/org.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,29 +205,6 @@
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 {
background: var(--color-box-body) !important;
}
134 changes: 57 additions & 77 deletions web_src/js/features/common-global.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
silverwind marked this conversation as resolved.
Show resolved Hide resolved

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();
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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');
});
});
}

/**
Expand Down