mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-23 19:47:07 +09:00
refactor: replace Fomantic modal with native dialog (#39846)
Replace Fomantic's hard-forked jQuery modal with native `<dialog>` elements, advancing https://github.com/go-gitea/gitea/issues/29849. The UI is visually unchanged. Dialogs open with `show()` over an `inert` page, so tooltips, popups and toasts mounted on `<body>` stay usable above them, unlike with `showModal()` (https://github.com/whatwg/html/issues/9936). - Remove the Fomantic modal and dimmer, add `showModal` and `hideModal` - Declare modals as `<dialog class="modal-dialog">`, shown inside a `.modal-backdrop`, instead of `ui modal` with its unused size classes - Remove two modals that could never be opened - Block the page while a modal is open, close the topmost one on Escape and restore focus to its opener - Allow stacked modals, use a confirm modal instead of `window.confirm` for deleting content history - Hide popups and toasts when a modal opens or closes - Keep the release notes modal open when generating notes fails Fixes: https://github.com/go-gitea/gitea/issues/39643 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
1 parent
7610336d74
commit
e645afbb3f
95 files changed
+607
-1719
No files matched your search
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="delete-badge-modal">
|
<dialog class="modal-dialog" id="delete-badge-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "admin.badges.delete_badge"}}
|
{{ctx.Locale.Tr "admin.badges.delete_badge"}}
|
||||||
@@ -39,6 +39,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="change-email-modal">
|
<dialog class="modal-dialog" id="change-email-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "admin.emails.change_email_header"}}
|
{{ctx.Locale.Tr "admin.emails.change_email_header"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -61,9 +61,9 @@
|
|||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui modal admin" id="detail-modal">
|
<dialog class="modal-dialog admin" id="detail-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "admin.notices.view_detail_header"}}</div>
|
<div class="header">{{ctx.Locale.Tr "admin.notices.view_detail_header"}}</div>
|
||||||
<div class="content"><pre></pre></div>
|
<div class="content"><pre></pre></div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -83,12 +83,14 @@
|
|||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="ui small modal form-fetch-action" method="post" id="admin-package-delete-modal">
|
<dialog class="modal-dialog" id="admin-package-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "packages.settings.delete.version"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "packages.settings.delete.version"}}</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post">
|
||||||
{{ctx.Locale.Tr "packages.settings.delete.notice" (HTMLFormat `<span class="%s"></span>` "package-name") (HTMLFormat `<span class="%s"></span>` "package-version")}}
|
<div class="content">
|
||||||
</div>
|
{{ctx.Locale.Tr "packages.settings.delete.notice" (HTMLFormat `<span class="%s"></span>` "package-name") (HTMLFormat `<span class="%s"></span>` "package-version")}}
|
||||||
{{template "base/modal_actions_confirm" .}}
|
</div>
|
||||||
</form>
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -96,14 +96,16 @@
|
|||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="ui small modal form-fetch-action" id="admin-repo-delete-modal" method="post">
|
<dialog class="modal-dialog" id="admin-repo-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.delete"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.delete"}}</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post">
|
||||||
<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p>
|
<div class="content">
|
||||||
{{ctx.Locale.Tr "repo.settings.delete_notices_2" (HTMLFormat `<span class="%s"></span>` "repo-name")}}<br>
|
<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p>
|
||||||
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}
|
{{ctx.Locale.Tr "repo.settings.delete_notices_2" (HTMLFormat `<span class="%s"></span>` "repo-name")}}<br>
|
||||||
</div>
|
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}
|
||||||
{{template "base/modal_actions_confirm" .}}
|
</div>
|
||||||
</form>
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<span class="tw-flex-1"> {{svg "octicon-file-directory-fill"}} {{$dir}}</span>
|
<span class="tw-flex-1"> {{svg "octicon-file-directory-fill"}} {{$dir}}</span>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}">{{svg "octicon-plus"}} {{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</button>
|
<button type="button" class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}">{{svg "octicon-plus"}} {{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</button>
|
||||||
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
|
<dialog class="modal-dialog" id="adopt-unadopted-modal-{{$dirI}}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
|
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,9 +38,9 @@
|
|||||||
<input type="hidden" name="page" value="{{$.CurrentPage}}">
|
<input type="hidden" name="page" value="{{$.CurrentPage}}">
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
<button type="button" class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}">{{svg "octicon-x"}} {{ctx.Locale.Tr "repo.delete_preexisting_label"}}</button>
|
<button type="button" class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}">{{svg "octicon-x"}} {{ctx.Locale.Tr "repo.delete_preexisting_label"}}</button>
|
||||||
<div class="ui g-modal-confirm modal" id="delete-unadopted-modal-{{$dirI}}">
|
<dialog class="modal-dialog" id="delete-unadopted-modal-{{$dirI}}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
|
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<input type="hidden" name="page" value="{{$.CurrentPage}}">
|
<input type="hidden" name="page" value="{{$.CurrentPage}}">
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="delete-user-modal">
|
<dialog class="modal-dialog" id="delete-user-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.delete_account_title"}}
|
{{ctx.Locale.Tr "settings.delete_account_title"}}
|
||||||
@@ -241,6 +241,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "admin/layout_footer" .}}
|
{{template "admin/layout_footer" .}}
|
||||||
@@ -5,18 +5,20 @@
|
|||||||
<span>{{ctx.Locale.Tr "settings.organization"}} ({{ctx.Locale.Tr "admin.total" $userOrgsTotal}})</span>
|
<span>{{ctx.Locale.Tr "settings.organization"}} ({{ctx.Locale.Tr "admin.total" $userOrgsTotal}})</span>
|
||||||
{{if $userOrgs}}
|
{{if $userOrgs}}
|
||||||
<button type="button" class="ui red tiny button show-modal" data-modal="#remove-all-orgs-modal">{{ctx.Locale.Tr "remove_all"}}</button>
|
<button type="button" class="ui red tiny button show-modal" data-modal="#remove-all-orgs-modal">{{ctx.Locale.Tr "remove_all"}}</button>
|
||||||
<form class="ui small modal form-fetch-action" id="remove-all-orgs-modal" method="post" action="{{ctx.RootData.Link}}/orgs/remove-all">
|
<dialog class="modal-dialog" id="remove-all-orgs-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "admin.users.remove_all_orgs_title"}}
|
{{ctx.Locale.Tr "admin.users.remove_all_orgs_title"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post" action="{{ctx.RootData.Link}}/orgs/remove-all">
|
||||||
<p>{{ctx.Locale.Tr "admin.users.remove_all_orgs_desc" $user.Name $userOrgsTotal}}</p>
|
<div class="content">
|
||||||
</div>
|
<p>{{ctx.Locale.Tr "admin.users.remove_all_orgs_desc" $user.Name $userOrgsTotal}}</p>
|
||||||
<div class="actions">
|
</div>
|
||||||
<div class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</div>
|
<div class="actions">
|
||||||
<button class="ui red button" type="submit">{{ctx.Locale.Tr "remove_all"}}</button>
|
<div class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</div>
|
||||||
</div>
|
<button class="ui red button" type="submit">{{ctx.Locale.Tr "remove_all"}}</button>
|
||||||
</form>
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
Single danger button (GitHub-like):
|
Single danger button (GitHub-like):
|
||||||
* ModalButtonDangerText "This action will destroy your data"
|
* ModalButtonDangerText "This action will destroy your data"
|
||||||
|
|
||||||
The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal internally
|
The ".ok.button" and ".cancel.button" selectors are also used by "modules/modal.ts"
|
||||||
*/}}
|
*/}}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
{{if .ModalButtonDangerText}}
|
{{if .ModalButtonDangerText}}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{{template "devtest/devtest-header"}}
|
{{template "devtest/devtest-header"}}
|
||||||
<div class="page-content devtest ui container">
|
<div class="page-content devtest ui container">
|
||||||
<div class="modal-buttons flex-text-block tw-flex-wrap"></div>
|
<div class="modal-buttons flex-text-block tw-flex-wrap"></div>
|
||||||
<div id="test-modal-form-1" class="ui mini modal">
|
<dialog id="test-modal-form-1" class="modal-dialog">
|
||||||
<div class="header">Form dialog (layout 1)</div>
|
<div class="header">Form dialog (layout 1)</div>
|
||||||
<form class="content" method="post" action="?mock_response_delay=1">
|
<form class="content" method="post" action="?mock_response_delay=1">
|
||||||
<div class="ui input tw-w-full"><input name="user_input"></div>
|
<div class="ui input tw-w-full"><input name="user_input"></div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div id="test-modal-form-2" class="ui mini modal">
|
<dialog id="test-modal-form-2" class="modal-dialog">
|
||||||
<div class="header">Form dialog (layout 2)</div>
|
<div class="header">Form dialog (layout 2)</div>
|
||||||
<form method="post" action="?mock_response_delay=1">
|
<form method="post" action="?mock_response_delay=1">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div id="test-modal-form-3" class="ui mini modal">
|
<dialog id="test-modal-form-3" class="modal-dialog">
|
||||||
<div class="header">Form dialog (layout 3)</div>
|
<div class="header">Form dialog (layout 3)</div>
|
||||||
<form method="post" action="?mock_response_delay=1">
|
<form method="post" action="?mock_response_delay=1">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div id="test-modal-form-4" class="ui mini modal">
|
<dialog id="test-modal-form-4" class="modal-dialog">
|
||||||
<div class="header">Form dialog (layout 4)</div>
|
<div class="header">Form dialog (layout 4)</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="ui input tw-w-full"><input name="user_input"></div>
|
<div class="ui input tw-w-full"><input name="user_input"></div>
|
||||||
@@ -37,9 +37,9 @@
|
|||||||
<form method="post" action="?mock_response_delay=1">
|
<form method="post" action="?mock_response_delay=1">
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div id="test-modal-form-5" class="ui mini modal">
|
<dialog id="test-modal-form-5" class="modal-dialog">
|
||||||
<div class="header">Form dialog (layout 5)</div>
|
<div class="header">Form dialog (layout 5)</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<form method="post" action="?mock_response_delay=1">
|
<form method="post" action="?mock_response_delay=1">
|
||||||
@@ -47,27 +47,27 @@
|
|||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="test-modal-default">
|
<dialog class="modal-dialog" id="test-modal-default">
|
||||||
<div class="header">{{svg "octicon-file"}} Default dialog <span>title</span></div>
|
<div class="header">{{svg "octicon-file"}} Default dialog <span>title</span></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
very long aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
very long aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="test-modal-confirm">
|
<dialog class="modal-dialog" id="test-modal-confirm">
|
||||||
<div class="header">Confirm dialog</div>
|
<div class="header">Confirm dialog</div>
|
||||||
<div class="content">hello, this is the modal dialog content</div>
|
<div class="content">hello, this is the modal dialog content</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="test-modal-danger">
|
<dialog class="modal-dialog" id="test-modal-danger">
|
||||||
<div class="header">dangerous action dialog <button type="button" class="close-modal"></button></div>
|
<div class="header">dangerous action dialog <button type="button" class="close-modal"></button></div>
|
||||||
<div class="content">hello, this is the modal dialog content, this is a dangerous operation</div>
|
<div class="content">hello, this is the modal dialog content, this is a dangerous operation</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do this is dangerous operation")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do this is dangerous operation")}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
data-modal-a.text-content="fill with attr"
|
data-modal-a.text-content="fill with attr"
|
||||||
>test-modal-fill-values</button>
|
>test-modal-fill-values</button>
|
||||||
|
|
||||||
<div id="test-modal-fill-values" class="ui mini modal" data-skip-button>
|
<dialog id="test-modal-fill-values" class="modal-dialog" data-skip-button>
|
||||||
<div class="header">Modal dialog (fill values)</div>
|
<div class="header">Modal dialog (fill values)</div>
|
||||||
<form class="content">
|
<form class="content">
|
||||||
<div id="fill-by-id"></div>
|
<div id="fill-by-id"></div>
|
||||||
@@ -89,6 +89,6 @@
|
|||||||
<a href="#">link</a>
|
<a href="#">link</a>
|
||||||
{{template "base/modal_actions_confirm" dict}}
|
{{template "base/modal_actions_confirm" dict}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{template "devtest/devtest-footer"}}
|
{{template "devtest/devtest-footer"}}
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="change-visibility-org-modal">
|
<dialog class="modal-dialog" id="change-visibility-org-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.settings.change_visibility"}}
|
{{ctx.Locale.Tr "org.settings.change_visibility"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -70,9 +70,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui small modal" id="rename-org-modal">
|
<dialog class="modal-dialog" id="rename-org-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.settings.rename"}}
|
{{ctx.Locale.Tr "org.settings.rename"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -106,9 +106,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-org-modal">
|
<dialog class="modal-dialog" id="delete-org-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.settings.delete_account"}}
|
{{ctx.Locale.Tr "org.settings.delete_account"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -139,4 +139,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -72,13 +72,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="ui small modal form-fetch-action" method="post" id="remove-team-member">
|
<dialog class="modal-dialog" id="remove-team-member">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.members.remove"}}
|
{{ctx.Locale.Tr "org.members.remove"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post">
|
||||||
<p>{{ctx.Locale.Tr "org.members.remove.detail" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "team-name")}}</p>
|
<div class="content">
|
||||||
</div>
|
<p>{{ctx.Locale.Tr "org.members.remove.detail" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "team-name")}}</p>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
</div>
|
||||||
</form>
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -194,7 +194,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-team">
|
<dialog class="modal-dialog" id="delete-team">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "org.teams.delete_team_title"}}
|
{{ctx.Locale.Tr "org.teams.delete_team_title"}}
|
||||||
@@ -203,5 +203,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "org.teams.delete_team_desc"}}</p>
|
<p>{{ctx.Locale.Tr "org.teams.delete_team_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui mini modal" id="org-member-leave-team">
|
<dialog class="modal-dialog" id="org-member-leave-team">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.teams.leave"}}
|
{{ctx.Locale.Tr "org.teams.leave"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -99,4 +99,4 @@
|
|||||||
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "to-leave-team-name")}}</p>
|
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "to-leave-team-name")}}</p>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui mini modal" id="org-member-leave-team">
|
<dialog class="modal-dialog" id="org-member-leave-team">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.teams.leave"}}
|
{{ctx.Locale.Tr "org.teams.leave"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -71,5 +71,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "to-leave-team-name")}}</p>
|
<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "to-leave-team-name")}}</p>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<div class="item-trailing">
|
<div class="item-trailing">
|
||||||
<button type="button" class="ui basic red show-modal button" data-modal="#delete-package-modal">{{ctx.Locale.Tr "packages.settings.delete"}}</button>
|
<button type="button" class="ui basic red show-modal button" data-modal="#delete-package-modal">{{ctx.Locale.Tr "packages.settings.delete"}}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui tiny modal" id="delete-package-modal">
|
<dialog class="modal-dialog" id="delete-package-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "packages.settings.delete"}}
|
{{ctx.Locale.Tr "packages.settings.delete"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
<a class="show-modal" href data-modal="#delete-package-version-modal">{{ctx.Locale.Tr "packages.settings.delete.version"}}</a>
|
<a class="show-modal" href data-modal="#delete-package-version-modal">{{ctx.Locale.Tr "packages.settings.delete.version"}}</a>
|
||||||
<div class="ui tiny modal" id="delete-package-version-modal">
|
<dialog class="modal-dialog" id="delete-package-version-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "packages.settings.delete.version"}}
|
{{ctx.Locale.Tr "packages.settings.delete.version"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -94,9 +94,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
|
{{if and $.CanWriteProjects (not $.Repository.IsArchived)}}
|
||||||
<div class="ui small modal" id="repo-project-delete-modal">
|
<dialog class="modal-dialog" id="repo-project-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.projects.deletion"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.projects.deletion"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.projects.deletion_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.projects.deletion_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if $canWriteProject}}
|
{{if $canWriteProject}}
|
||||||
<div class="ui small modal" id="project-column-modal-edit">
|
<dialog class="modal-dialog" id="project-column-modal-edit">
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.projects.column.edit"}}</div>
|
<div class="header">{{ctx.Locale.Tr "repo.projects.column.edit"}}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<form class="ui form ignore-dirty" method="post" data-action-base-link="{{$.Link}}">
|
<form class="ui form ignore-dirty" method="post" data-action-base-link="{{$.Link}}">
|
||||||
@@ -155,5 +155,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if $showCreateWorkflowBadge}}
|
{{if $showCreateWorkflowBadge}}
|
||||||
<div id="workflow-status-badge-modal" class="ui tiny modal">
|
<dialog id="workflow-status-badge-modal" class="modal-dialog">
|
||||||
<div class="header">{{ctx.Locale.Tr "actions.workflow.status_badge"}}</div>
|
<div class="header">{{ctx.Locale.Tr "actions.workflow.status_badge"}}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="ui form" data-global-init="initWorkflowBadgeForm"
|
<div class="ui form" data-global-init="initWorkflowBadgeForm"
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<button type="button" class="ui mini button show-modal" data-modal="#runWorkflowDispatchModal">{{ctx.Locale.Tr "actions.workflow.run"}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}</button>
|
<button type="button" class="ui mini button show-modal" data-modal="#runWorkflowDispatchModal">{{ctx.Locale.Tr "actions.workflow.run"}}{{svg "octicon-triangle-down" 14 "dropdown icon"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="runWorkflowDispatchModal" class="ui tiny modal">
|
<dialog id="runWorkflowDispatchModal" class="modal-dialog">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<form id="runWorkflowDispatchForm" class="ui form ignore-dirty" action="{{$.Link}}/run?workflow={{$.CurWorkflow}}&scoped_workflow_source_repo_id={{$.CurWorkflowRepoID}}&actor={{$.CurActor}}&status={{$.CurStatus}}&branch={{$.CurBranch}}" method="post">
|
<form id="runWorkflowDispatchForm" class="ui form ignore-dirty" action="{{$.Link}}/run?workflow={{$.CurWorkflow}}&scoped_workflow_source_repo_id={{$.CurWorkflowRepoID}}&actor={{$.CurActor}}&status={{$.CurStatus}}&branch={{$.CurBranch}}" method="post">
|
||||||
<div class="ui inline field required tw-flex tw-items-center">
|
<div class="ui inline field required tw-flex tw-items-center">
|
||||||
@@ -55,4 +55,4 @@
|
|||||||
{{template "repo/actions/workflow_dispatch_inputs" .}}
|
{{template "repo/actions/workflow_dispatch_inputs" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -218,18 +218,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="ui small modal form-fetch-action" method="post" id="delete-branch-modal">
|
<dialog class="modal-dialog" id="delete-branch-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "repo.branch.delete_html"}} <span class="name"></span>
|
{{ctx.Locale.Tr "repo.branch.delete_html"}} <span class="name"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post">
|
||||||
<p>{{ctx.Locale.Tr "repo.branch.delete_desc"}}</p>
|
<div class="content">
|
||||||
</div>
|
<p>{{ctx.Locale.Tr "repo.branch.delete_desc"}}</p>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
</div>
|
||||||
</form>
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
<div class="ui mini modal" id="create-branch-modal">
|
<dialog class="modal-dialog" id="create-branch-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.branch.new_branch"}}
|
{{ctx.Locale.Tr "repo.branch.new_branch"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -247,9 +249,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui mini modal" id="rename-branch-modal">
|
<dialog class="modal-dialog" id="rename-branch-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.rename_branch"}}
|
{{ctx.Locale.Tr "repo.settings.rename_branch"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -266,5 +268,5 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="cite-repo-modal">
|
<dialog class="modal-dialog" id="cite-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.cite_this_repo"}}
|
{{ctx.Locale.Tr "repo.cite_this_repo"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -28,4 +28,4 @@
|
|||||||
{{ctx.Locale.Tr "cancel"}}
|
{{ctx.Locale.Tr "cancel"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
data-modal-cherry-pick-header="{{ctx.Locale.Tr "repo.commit.cherry-pick-header" (ShortSha .CommitID)}}"
|
data-modal-cherry-pick-header="{{ctx.Locale.Tr "repo.commit.cherry-pick-header" (ShortSha .CommitID)}}"
|
||||||
data-modal-cherry-pick-content="{{ctx.Locale.Tr "repo.commit.cherry-pick-content"}}"
|
data-modal-cherry-pick-content="{{ctx.Locale.Tr "repo.commit.cherry-pick-content"}}"
|
||||||
data-modal-cherry-pick-submit="{{ctx.Locale.Tr "repo.commit.cherry-pick"}}">{{ctx.Locale.Tr "repo.commit.cherry-pick"}}</div>
|
data-modal-cherry-pick-submit="{{ctx.Locale.Tr "repo.commit.cherry-pick"}}">{{ctx.Locale.Tr "repo.commit.cherry-pick"}}</div>
|
||||||
<div class="ui g-modal-confirm modal" id="cherry-pick-modal">
|
<dialog class="modal-dialog" id="cherry-pick-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span id="cherry-pick-header"></span>
|
<span id="cherry-pick-header"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,8 +68,8 @@
|
|||||||
<button type="submit" id="cherry-pick-submit" class="ui primary button"></button>
|
<button type="submit" id="cherry-pick-submit" class="ui primary button"></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
<div class="ui small modal" id="create-branch-modal">
|
<dialog class="modal-dialog" id="create-branch-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.branch.new_branch"}}
|
{{ctx.Locale.Tr "repo.branch.new_branch"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
<div class="ui small modal" id="create-tag-modal">
|
<dialog class="modal-dialog" id="create-tag-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.tag.create_tag_operation"}}
|
{{ctx.Locale.Tr "repo.tag.create_tag_operation"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<span class="ui small label">{{CountFmt $.Repository.NumForks}}</span>
|
<span class="ui small label">{{CountFmt $.Repository.NumForks}}</span>
|
||||||
</a>
|
</a>
|
||||||
{{if $.ShowForkModal}}
|
{{if $.ShowForkModal}}
|
||||||
<div class="ui small modal" id="fork-repo-modal">
|
<dialog class="modal-dialog" id="fork-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.already_forked" $.Repository.Name}}
|
{{ctx.Locale.Tr "repo.already_forked" $.Repository.Name}}
|
||||||
</div>
|
</div>
|
||||||
@@ -39,5 +39,5 @@
|
|||||||
<a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a>
|
<a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="issue-label-edit-modal" data-global-init="initLabelEditModal"
|
<dialog class="modal-dialog" id="issue-label-edit-modal" data-global-init="initLabelEditModal"
|
||||||
data-current-page-link="{{$.Link}}"{{/*will be used to construct "new label" and "edit label" URLs*/}}
|
data-current-page-link="{{$.Link}}"{{/*will be used to construct "new label" and "edit label" URLs*/}}
|
||||||
data-text-new-label="{{ctx.Locale.Tr "repo.issues.new_label"}}"
|
data-text-new-label="{{ctx.Locale.Tr "repo.issues.new_label"}}"
|
||||||
data-text-edit-label="{{ctx.Locale.Tr "repo.issues.label_modify"}}"
|
data-text-edit-label="{{ctx.Locale.Tr "repo.issues.label_modify"}}"
|
||||||
@@ -66,4 +66,4 @@
|
|||||||
{{ctx.Locale.Tr "save"}}
|
{{ctx.Locale.Tr "save"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -92,11 +92,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if or .CanWriteIssues .CanWritePulls}}
|
{{if or .CanWriteIssues .CanWritePulls}}
|
||||||
<div class="ui small modal" id="repo-milestone-delete-modal">
|
<dialog class="modal-dialog" id="repo-milestone-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.milestones.deletion"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.milestones.deletion"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.milestones.deletion_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.milestones.deletion_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -127,18 +127,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if and .CanCreateIssueDependencies (not .Repository.IsArchived)}}
|
{{if and .CanCreateIssueDependencies (not .Repository.IsArchived)}}
|
||||||
<form id="issue-remove-dependency-confirm" class="ui g-modal-confirm modal form-fetch-action" method="post" action="{{.Issue.Link}}/dependency/delete">
|
<dialog class="modal-dialog" id="issue-remove-dependency-confirm">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.issues.dependency.remove_header"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.issues.dependency.remove_header"}}</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post" action="{{.Issue.Link}}/dependency/delete">
|
||||||
<input type="hidden" value="" name="removeDependencyID" class="remove-dependency-id">
|
<div class="content">
|
||||||
<input type="hidden" value="" name="dependencyType" class="dependency-type">
|
<input type="hidden" value="" name="removeDependencyID" class="remove-dependency-id">
|
||||||
<p>
|
<input type="hidden" value="" name="dependencyType" class="dependency-type">
|
||||||
{{ctx.Locale.Tr (Iif .Issue.IsPull "repo.issues.dependency.pr_remove_text" "repo.issues.dependency.issue_remove_text")}}
|
<p>
|
||||||
</p>
|
{{ctx.Locale.Tr (Iif .Issue.IsPull "repo.issues.dependency.pr_remove_text" "repo.issues.dependency.issue_remove_text")}}
|
||||||
{{$ModalButtonCancelText := ctx.Locale.Tr "repo.issues.dependency.cancel"}}
|
</p>
|
||||||
{{$ModalButtonOkText := ctx.Locale.Tr "repo.issues.dependency.remove"}}
|
{{$ModalButtonCancelText := ctx.Locale.Tr "repo.issues.dependency.cancel"}}
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonCancelText" $ModalButtonCancelText "ModalButtonOkText" $ModalButtonOkText)}}
|
{{$ModalButtonOkText := ctx.Locale.Tr "repo.issues.dependency.remove"}}
|
||||||
</div>
|
{{template "base/modal_actions_confirm" (dict "ModalButtonCancelText" $ModalButtonCancelText "ModalButtonOkText" $ModalButtonOkText)}}
|
||||||
</form>
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
{{svg "octicon-lock"}} {{ctx.Locale.Tr "repo.issues.lock"}}
|
{{svg "octicon-lock"}} {{ctx.Locale.Tr "repo.issues.lock"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</button>
|
</button>
|
||||||
<div class="ui tiny modal" id="lock-conversation">
|
<dialog class="modal-dialog" id="lock-conversation">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{if .Issue.IsLocked}}
|
{{if .Issue.IsLocked}}
|
||||||
{{ctx.Locale.Tr "repo.issues.unlock.title"}}
|
{{ctx.Locale.Tr "repo.issues.unlock.title"}}
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button type="button" class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
|
<button type="button" class="ui cancel button">{{ctx.Locale.Tr "settings.cancel"}}</button>
|
||||||
{{/* explicitly focus the submit button, to avoid Fomantic modal focuses and popups the dropdown */}}
|
{{/* explicitly focus the submit button, otherwise the modal focuses and pops up the dropdown */}}
|
||||||
<button type="submit" class="ui red button" autofocus>
|
<button type="submit" class="ui red button" autofocus>
|
||||||
{{if .Issue.IsLocked}}
|
{{if .Issue.IsLocked}}
|
||||||
{{ctx.Locale.Tr "repo.issues.unlock_confirm"}}
|
{{ctx.Locale.Tr "repo.issues.unlock_confirm"}}
|
||||||
@@ -78,12 +78,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
<button type="button" class="tw-mt-1 fluid ui show-modal button" data-modal="#sidebar-delete-issue">
|
<button type="button" class="tw-mt-1 fluid ui show-modal button" data-modal="#sidebar-delete-issue">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "repo.issues.delete"}}
|
{{ctx.Locale.Tr "repo.issues.delete"}}
|
||||||
</button>
|
</button>
|
||||||
<div class="ui g-modal-confirm modal" id="sidebar-delete-issue">
|
<dialog class="modal-dialog" id="sidebar-delete-issue">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{if .Issue.IsPull}}
|
{{if .Issue.IsPull}}
|
||||||
{{ctx.Locale.Tr "repo.pulls.delete.title"}}
|
{{ctx.Locale.Tr "repo.pulls.delete.title"}}
|
||||||
@@ -103,5 +103,5 @@
|
|||||||
<form action="{{.Issue.Link}}/delete" method="post">
|
<form action="{{.Issue.Link}}/delete" method="post">
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if $data.CurrentPullReviewers}}
|
{{if $data.CurrentPullReviewers}}
|
||||||
<div class="ui small modal" id="issue-sidebar-dismiss-review-modal">
|
<dialog class="modal-dialog" id="issue-sidebar-dismiss-review-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.issues.dismiss_review"}}
|
{{ctx.Locale.Tr "repo.issues.dismiss_review"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -126,6 +126,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{/* set time estimate modal */}}
|
{{/* set time estimate modal */}}
|
||||||
<div class="ui mini modal" id="issue-time-set-estimate-modal">
|
<dialog class="modal-dialog" id="issue-time-set-estimate-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.time_estimate_set"}}</div>
|
<div class="header">{{ctx.Locale.Tr "repo.issues.time_estimate_set"}}</div>
|
||||||
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/time_estimate">
|
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/time_estimate">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -46,10 +46,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{/* manually add time modal */}}
|
{{/* manually add time modal */}}
|
||||||
<div class="ui mini modal" id="issue-time-manually-add-modal">
|
<dialog class="modal-dialog" id="issue-time-manually-add-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.add_time_manually"}}</div>
|
<div class="header">{{ctx.Locale.Tr "repo.issues.add_time_manually"}}</div>
|
||||||
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/times/add">
|
<form method="post" class="ui form form-fetch-action" action="{{.Issue.Link}}/times/add">
|
||||||
<div class="content flex-text-block">
|
<div class="content flex-text-block">
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.timetracker_timer_manually_add"}}</button>
|
<button type="submit" class="ui primary button">{{ctx.Locale.Tr "repo.issues.timetracker_timer_manually_add"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .WorkingUsers}}
|
{{if .WorkingUsers}}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="reference-issue-modal">
|
<dialog class="modal-dialog" id="reference-issue-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}
|
{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -24,4 +24,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-repo-modal">
|
<dialog class="modal-dialog" id="delete-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.delete"}}
|
{{ctx.Locale.Tr "repo.settings.delete"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -67,9 +67,9 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="cancel-repo-modal">
|
<dialog class="modal-dialog" id="cancel-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.cancel_migrating_title"}}
|
{{ctx.Locale.Tr "repo.migrate.cancel_migrating_title"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -79,6 +79,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -116,17 +116,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if (and ($.Permission.CanWrite ctx.Consts.RepoUnitTypeCode) .PageIsTagList)}}
|
|
||||||
<div class="ui g-modal-confirm delete modal">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-trash"}}
|
|
||||||
{{ctx.Locale.Tr "repo.release.delete_tag"}}
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{ctx.Locale.Tr "repo.release.deletion_tag_desc"}}</p>
|
|
||||||
</div>
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="generate-release-notes-modal" class="ui mini modal">
|
<dialog id="generate-release-notes-modal" class="modal-dialog">
|
||||||
<div class="content ui form">
|
<div class="content ui form">
|
||||||
<p>{{ctx.Locale.Tr "repo.release.generate_notes_desc"}}</p>
|
<p>{{ctx.Locale.Tr "repo.release.generate_notes_desc"}}</p>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@@ -156,6 +156,6 @@
|
|||||||
<button type="button" class="ui primary ok button">{{ctx.Locale.Tr "repo.release.generate_notes"}}</button>
|
<button type="button" class="ui primary ok button">{{ctx.Locale.Tr "repo.release.generate_notes"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -65,10 +65,10 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="repo-branch-protection-delete-modal">
|
<dialog class="modal-dialog" id="repo-branch-protection-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.protected_branch_deletion"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.protected_branch_deletion"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.protected_branch_deletion_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.protected_branch_deletion_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "repo/settings/layout_footer" .}}
|
{{template "repo/settings/layout_footer" .}}
|
||||||
@@ -118,10 +118,10 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="repo-collaborator-delete-modal">
|
<dialog class="modal-dialog" id="repo-collaborator-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.collaborator_deletion"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.settings.collaborator_deletion"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.collaborator_deletion_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.collaborator_deletion_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "repo/settings/layout_footer" .}}
|
{{template "repo/settings/layout_footer" .}}
|
||||||
@@ -60,16 +60,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="repo-deploy-key-delete-modal">
|
<dialog class="modal-dialog" id="repo-deploy-key-delete-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "remove"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "remove"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.deploy_key_deletion_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.deploy_key_deletion_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui small modal" id="repo-deploy-token-regenerate-modal">
|
<dialog class="modal-dialog" id="repo-deploy-token-regenerate-modal">
|
||||||
<div class="header">{{svg "octicon-sync"}} {{ctx.Locale.Tr "settings.regenerate_token"}}</div>
|
<div class="header">{{svg "octicon-sync"}} {{ctx.Locale.Tr "settings.regenerate_token"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.regenerate_deploy_token_desc"}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.settings.regenerate_deploy_token_desc"}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "repo/settings/layout_footer" .}}
|
{{template "repo/settings/layout_footer" .}}
|
||||||
@@ -37,12 +37,12 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
<div class="ui g-modal-confirm modal" id="delete-lfs-object">
|
<dialog class="modal-dialog" id="delete-lfs-object">
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<form class="content" method="post">
|
<form class="content" method="post">
|
||||||
<p>{{ctx.Locale.Tr "repo.settings.lfs_delete_warning"}}</p>
|
<p>{{ctx.Locale.Tr "repo.settings.lfs_delete_warning"}}</p>
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/settings/layout_footer" .}}
|
{{template "repo/settings/layout_footer" .}}
|
||||||
@@ -919,7 +919,7 @@
|
|||||||
|
|
||||||
{{if $.CanManagerDangerZone}}
|
{{if $.CanManagerDangerZone}}
|
||||||
{{if .Repository.IsMirror}}
|
{{if .Repository.IsMirror}}
|
||||||
<div class="ui small modal" id="convert-mirror-repo-modal">
|
<dialog class="modal-dialog" id="convert-mirror-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.convert"}}
|
{{ctx.Locale.Tr "repo.settings.convert"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -934,10 +934,10 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_confirm")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_confirm")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .CanConvertFork}}
|
{{if .CanConvertFork}}
|
||||||
<div class="ui small modal" id="convert-fork-repo-modal">
|
<dialog class="modal-dialog" id="convert-fork-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.convert_fork"}}
|
{{ctx.Locale.Tr "repo.settings.convert_fork"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -952,9 +952,9 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="ui small modal" id="transfer-repo-modal">
|
<dialog class="modal-dialog" id="transfer-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.transfer"}}
|
{{ctx.Locale.Tr "repo.settings.transfer"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -972,9 +972,9 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.transfer_perform")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.transfer_perform")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-repo-modal">
|
<dialog class="modal-dialog" id="delete-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.delete"}}
|
{{ctx.Locale.Tr "repo.settings.delete"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -993,10 +993,10 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_delete")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{if not .Repository.IsFork}}
|
{{if not .Repository.IsFork}}
|
||||||
<div class="ui small modal" id="visibility-repo-modal">
|
<dialog class="modal-dialog" id="visibility-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.visibility"}}
|
{{ctx.Locale.Tr "repo.visibility"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -1040,11 +1040,11 @@
|
|||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (Iif .Repository.IsPrivate (ctx.Locale.Tr "repo.settings.visibility.public.button") (ctx.Locale.Tr "repo.settings.visibility.private.button")))}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (Iif .Repository.IsPrivate (ctx.Locale.Tr "repo.settings.visibility.public.button") (ctx.Locale.Tr "repo.settings.visibility.private.button")))}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}}
|
{{if .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}}
|
||||||
<div class="ui small modal" id="delete-wiki-modal">
|
<dialog class="modal-dialog" id="delete-wiki-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.wiki_delete"}}
|
{{ctx.Locale.Tr "repo.settings.wiki_delete"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -1060,11 +1060,11 @@
|
|||||||
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete")
|
"RepoOperationText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete")
|
||||||
)}}
|
)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if not .Repository.IsMirror}}
|
{{if not .Repository.IsMirror}}
|
||||||
<div class="ui g-modal-confirm modal" id="archive-repo-modal">
|
<dialog class="modal-dialog" id="archive-repo-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{if .Repository.IsArchived}}
|
{{if .Repository.IsArchived}}
|
||||||
{{ctx.Locale.Tr "repo.settings.unarchive.header"}}
|
{{ctx.Locale.Tr "repo.settings.unarchive.header"}}
|
||||||
@@ -1086,7 +1086,7 @@
|
|||||||
<input type="hidden" name="repo_id" value="{{.Repository.ID}}">
|
<input type="hidden" name="repo_id" value="{{.Repository.ID}}">
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="push-mirror-edit-modal">
|
<dialog class="modal-dialog" id="push-mirror-edit-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.edit_sync_time"}}
|
{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.edit_sync_time"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -24,4 +24,4 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if $.Permission.CanWrite ctx.Consts.RepoUnitTypeCode}}
|
{{if $.Permission.CanWrite ctx.Consts.RepoUnitTypeCode}}
|
||||||
<div id="confirm-delete-tag-modal" class="ui small modal">
|
<dialog id="confirm-delete-tag-modal" class="modal-dialog">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.release.delete_tag"}}
|
{{ctx.Locale.Tr "repo.release.delete_tag"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
<p>{{ctx.Locale.Tr "repo.release.deletion_tag_desc"}}</p>
|
<p>{{ctx.Locale.Tr "repo.release.deletion_tag_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="repo-watch-options-modal">
|
<dialog class="modal-dialog" id="repo-watch-options-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "notifications"}}</div>
|
<div class="header">{{ctx.Locale.Tr "notifications"}}</div>
|
||||||
<form class="ui form form-fetch-action" method="post">
|
<form class="ui form form-fetch-action" method="post">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -19,4 +19,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" dict "ModalButtonTypes" "confirm"}}
|
{{template "base/modal_actions_confirm" dict "ModalButtonTypes" "confirm"}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -96,10 +96,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="repo-wiki-delete-page-modal">
|
<dialog class="modal-dialog" id="repo-wiki-delete-page-modal">
|
||||||
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.wiki.delete_page_button"}}</div>
|
<div class="header">{{svg "octicon-trash"}} {{ctx.Locale.Tr "repo.wiki.delete_page_button"}}</div>
|
||||||
<div class="content"><p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" $title}}</p></div>
|
<div class="content"><p>{{ctx.Locale.Tr "repo.wiki.delete_page_notice_1" $title}}</p></div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
</table>
|
</table>
|
||||||
{{template "base/paginate" .}}
|
{{template "base/paginate" .}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui small modal" id="runner-delete-modal">
|
<dialog class="modal-dialog" id="runner-delete-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "actions.runners.delete_runner_header"}}
|
{{ctx.Locale.Tr "actions.runners.delete_runner_header"}}
|
||||||
@@ -104,5 +104,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "actions.runners.delete_runner_notice"}}</p>
|
<p>{{ctx.Locale.Tr "actions.runners.delete_runner_notice"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/* Add secret dialog */}}
|
{{/* Add secret dialog */}}
|
||||||
<div class="ui small modal" id="add-secret-modal">
|
<dialog class="modal-dialog" id="add-secret-modal">
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<form class="ui form form-fetch-action" method="post">
|
<form class="ui form form-fetch-action" method="post">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -105,4 +105,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-token">
|
<dialog class="modal-dialog" id="delete-token">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.access_token_deletion"}}
|
{{ctx.Locale.Tr "settings.access_token_deletion"}}
|
||||||
@@ -110,10 +110,10 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{if not .IsBot}}
|
{{if not .IsBot}}
|
||||||
<div class="ui small modal" id="regenerate-token">
|
<dialog class="modal-dialog" id="regenerate-token">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "settings.access_token_regeneration"}}
|
{{ctx.Locale.Tr "settings.access_token_regeneration"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -121,5 +121,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.access_token_regeneration_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.access_token_regeneration_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm"}}
|
{{template "base/modal_actions_confirm"}}
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="ui small modal" id="block-user-modal">
|
<dialog class="modal-dialog" id="block-user-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "user.block.title"}}</div>
|
<div class="header">{{ctx.Locale.Tr "user.block.title"}}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="ui warning message">{{ctx.Locale.Tr "user.block.info"}} <a target="_blank" href="https://docs.gitea.com/usage/access-control/blocking-user">{{ctx.Locale.Tr "user.block.info.docs"}}</a></div>
|
<div class="ui warning message">{{ctx.Locale.Tr "user.block.info"}} <a target="_blank" href="https://docs.gitea.com/usage/access-control/blocking-user">{{ctx.Locale.Tr "user.block.info.docs"}}</a></div>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="block-note">{{ctx.Locale.Tr "user.block.note.title"}}</label>
|
<label for="block-note">{{ctx.Locale.Tr "user.block.note.title"}}</label>
|
||||||
<input id="block-note" name="note">
|
<input id="block-note" name="note" autofocus>
|
||||||
<p class="help">{{ctx.Locale.Tr "user.block.note.info"}}</p>
|
<p class="help">{{ctx.Locale.Tr "user.block.note.info"}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
@@ -19,4 +19,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui small modal" id="block-user-note-modal">
|
<dialog class="modal-dialog" id="block-user-note-modal">
|
||||||
<div class="header">{{ctx.Locale.Tr "user.block.note.edit"}}</div>
|
<div class="header">{{ctx.Locale.Tr "user.block.note.edit"}}</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<form class="ui form form-fetch-action" action="{{$.Link}}" method="post">
|
<form class="ui form form-fetch-action" action="{{$.Link}}" method="post">
|
||||||
@@ -69,4 +69,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/** Edit variable dialog */}}
|
{{/** Edit variable dialog */}}
|
||||||
<div class="ui small modal" id="edit-variable-modal">
|
<dialog class="modal-dialog" id="edit-variable-modal">
|
||||||
<div class="header"></div>
|
<div class="header"></div>
|
||||||
<form class="ui form form-fetch-action" method="post">
|
<form class="ui form form-fetch-action" method="post">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -103,5 +103,5 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="ui small modal" id="delete-account">
|
<dialog class="modal-dialog" id="delete-account">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.delete_account_title"}}
|
{{ctx.Locale.Tr "settings.delete_account_title"}}
|
||||||
@@ -136,12 +136,12 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.delete_account_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-email">
|
<dialog class="modal-dialog" id="delete-email">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.email_deletion"}}
|
{{ctx.Locale.Tr "settings.email_deletion"}}
|
||||||
@@ -150,6 +150,6 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.email_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.email_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
|
|
||||||
{{template "user/settings/layout_footer" .}}
|
{{template "user/settings/layout_footer" .}}
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="remove-gitea-oauth2-application">
|
<dialog class="modal-dialog" id="remove-gitea-oauth2-application">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.remove_oauth2_application"}}
|
{{ctx.Locale.Tr "settings.remove_oauth2_application"}}
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
<p>{{ctx.Locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui bottom attached segment">
|
<div class="ui bottom attached segment">
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="revoke-gitea-oauth2-grant">
|
<dialog class="modal-dialog" id="revoke-gitea-oauth2-grant">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-shield" 16 "tw-mr-1"}}
|
{{svg "octicon-shield" 16 "tw-mr-1"}}
|
||||||
{{ctx.Locale.Tr "settings.revoke_oauth2_grant"}}
|
{{ctx.Locale.Tr "settings.revoke_oauth2_grant"}}
|
||||||
@@ -36,5 +36,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.revoke_oauth2_grant_description"}}</p>
|
<p>{{ctx.Locale.Tr "settings.revoke_oauth2_grant_description"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui small modal" id="delete-gpg">
|
<dialog class="modal-dialog" id="delete-gpg">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.gpg_key_deletion"}}
|
{{ctx.Locale.Tr "settings.gpg_key_deletion"}}
|
||||||
@@ -132,5 +132,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.gpg_key_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.gpg_key_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-principal">
|
<dialog class="modal-dialog" id="delete-principal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.ssh_principal_deletion"}}
|
{{ctx.Locale.Tr "settings.ssh_principal_deletion"}}
|
||||||
@@ -64,5 +64,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.ssh_principal_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.ssh_principal_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui small modal" id="delete-ssh">
|
<dialog class="modal-dialog" id="delete-ssh">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.ssh_key_deletion"}}
|
{{ctx.Locale.Tr "settings.ssh_key_deletion"}}
|
||||||
@@ -112,5 +112,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.ssh_key_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.ssh_key_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,14 +38,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="ui small modal form-fetch-action" method="post" id="leave-organization">
|
<dialog class="modal-dialog" id="leave-organization">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "org.members.leave"}}
|
{{ctx.Locale.Tr "org.members.leave"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<form class="form-fetch-action" method="post">
|
||||||
<p>{{ctx.Locale.Tr "org.members.leave.detail" (HTMLFormat `<span class="%s"></span>` "organization-name")}}</p>
|
<div class="content">
|
||||||
</div>
|
<p>{{ctx.Locale.Tr "org.members.leave.detail" (HTMLFormat `<span class="%s"></span>` "organization-name")}}</p>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
</div>
|
||||||
</form>
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
{{template "user/settings/layout_footer" .}}
|
{{template "user/settings/layout_footer" .}}
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<div class="tw-float-right">
|
<div class="tw-float-right">
|
||||||
{{if $.allowAdopt}}
|
{{if $.allowAdopt}}
|
||||||
<button type="button" class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
|
<button type="button" class="ui button primary show-modal tw-p-2" data-modal="#adopt-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-plus"}}</span><span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting_label"}}</span></button>
|
||||||
<div class="ui g-modal-confirm modal" id="adopt-unadopted-modal-{{$dirI}}">
|
<dialog class="modal-dialog" id="adopt-unadopted-modal-{{$dirI}}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
|
<span class="label">{{ctx.Locale.Tr "repo.adopt_preexisting"}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,11 +47,11 @@
|
|||||||
<input type="hidden" name="action" value="adopt">
|
<input type="hidden" name="action" value="adopt">
|
||||||
{{template "base/modal_actions_confirm" $}}
|
{{template "base/modal_actions_confirm" $}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if $.allowDelete}}
|
{{if $.allowDelete}}
|
||||||
<button type="button" class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{ctx.Locale.Tr "repo.delete_preexisting_label"}}</span></button>
|
<button type="button" class="ui button red show-modal tw-p-2" data-modal="#delete-unadopted-modal-{{$dirI}}"><span class="icon">{{svg "octicon-x"}}</span><span class="label">{{ctx.Locale.Tr "repo.delete_preexisting_label"}}</span></button>
|
||||||
<div class="ui g-modal-confirm modal" id="delete-unadopted-modal-{{$dirI}}">
|
<dialog class="modal-dialog" id="delete-unadopted-modal-{{$dirI}}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
|
<span class="label">{{ctx.Locale.Tr "repo.delete_preexisting"}}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
<input type="hidden" name="action" value="delete">
|
<input type="hidden" name="action" value="delete">
|
||||||
{{template "base/modal_actions_confirm" $}}
|
{{template "base/modal_actions_confirm" $}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -114,15 +114,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-trash"}}
|
|
||||||
{{ctx.Locale.Tr "settings.remove_account_link"}}
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{ctx.Locale.Tr "settings.remove_account_link_desc"}}</p>
|
|
||||||
</div>
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{template "user/settings/layout_footer" .}}
|
{{template "user/settings/layout_footer" .}}
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-account-link">
|
<dialog class="modal-dialog" id="delete-account-link">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.remove_account_link"}}
|
{{ctx.Locale.Tr "settings.remove_account_link"}}
|
||||||
@@ -57,6 +57,6 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.remove_account_link_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.remove_account_link_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="ui small modal" id="delete-openid">
|
<dialog class="modal-dialog" id="delete-openid">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.openid_deletion"}}
|
{{ctx.Locale.Tr "settings.openid_deletion"}}
|
||||||
@@ -57,5 +57,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.openid_deletion_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.openid_deletion_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<div class="ui small modal" id="disable-twofa">
|
<dialog class="modal-dialog" id="disable-twofa">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.twofa_disable"}}
|
{{ctx.Locale.Tr "settings.twofa_disable"}}
|
||||||
@@ -31,5 +31,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.twofa_disable_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.twofa_disable_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="button" id="register-webauthn" class="ui primary button">{{svg "octicon-key"}} {{ctx.Locale.Tr "settings.webauthn_register_key"}}</button>
|
<button type="button" id="register-webauthn" class="ui primary button">{{svg "octicon-key"}} {{ctx.Locale.Tr "settings.webauthn_register_key"}}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui small modal" id="rename-webauthn-nickname">
|
<dialog class="modal-dialog" id="rename-webauthn-nickname">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-pencil"}}
|
{{svg "octicon-pencil"}}
|
||||||
{{ctx.Locale.Tr "rename"}}
|
{{ctx.Locale.Tr "rename"}}
|
||||||
@@ -48,8 +48,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</dialog>
|
||||||
<div class="ui small modal" id="delete-registration">
|
<dialog class="modal-dialog" id="delete-registration">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
{{ctx.Locale.Tr "settings.webauthn_delete_key"}}
|
{{ctx.Locale.Tr "settings.webauthn_delete_key"}}
|
||||||
@@ -58,5 +58,5 @@
|
|||||||
<p>{{ctx.Locale.Tr "settings.webauthn_delete_key_desc"}}</p>
|
<p>{{ctx.Locale.Tr "settings.webauthn_delete_key_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {env} from 'node:process';
|
import {env} from 'node:process';
|
||||||
import {test, expect} from '@playwright/test';
|
import {test, expect} from '@playwright/test';
|
||||||
import {login, apiCreateRepo, apiCreateIssue, randomString} from './utils.ts';
|
import {login, apiCreateRepo, apiCreateIssue, apiEditIssue, randomString} from './utils.ts';
|
||||||
|
|
||||||
test('comment on and close an issue', async ({page, request}) => {
|
test('comment on and close an issue', async ({page, request}) => {
|
||||||
const repoName = `e2e-issue-comment-${randomString(8)}`;
|
const repoName = `e2e-issue-comment-${randomString(8)}`;
|
||||||
@@ -48,3 +48,25 @@ test('unsaved issue description prompts before leaving', async ({page, request})
|
|||||||
expect((await dialogPromise).type()).toBe('beforeunload');
|
expect((await dialogPromise).type()).toBe('beforeunload');
|
||||||
await expect(page).toHaveURL(/\/issues\/new$/);
|
await expect(page).toHaveURL(/\/issues\/new$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('delete an edit history entry via a confirm over the history modal', async ({page, request}) => {
|
||||||
|
const repoName = `e2e-issue-history-${randomString(8)}`;
|
||||||
|
const owner = env.GITEA_TEST_E2E_USER;
|
||||||
|
await Promise.all([
|
||||||
|
(async () => {
|
||||||
|
await apiCreateRepo(request, {name: repoName, autoInit: false});
|
||||||
|
await apiCreateIssue(request, {owner, repo: repoName, title: 'History test', body: 'first'});
|
||||||
|
await apiEditIssue(request, owner, repoName, 1, {body: 'second'});
|
||||||
|
})(),
|
||||||
|
login(page),
|
||||||
|
]);
|
||||||
|
await page.goto(`/${owner}/${repoName}/issues/1`);
|
||||||
|
const historyMenu = page.locator('.content-history-menu');
|
||||||
|
await historyMenu.click();
|
||||||
|
await historyMenu.getByRole('menuitem').last().click();
|
||||||
|
const history = page.getByRole('dialog');
|
||||||
|
await history.getByText('Options').click();
|
||||||
|
await history.getByRole('menuitem', {name: 'Delete from history'}).click();
|
||||||
|
await page.getByRole('dialog', {name: 'Delete from history?'}).getByRole('button', {name: 'Confirm'}).click();
|
||||||
|
await expect(page.getByRole('dialog')).toHaveCount(0);
|
||||||
|
});
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import {env} from 'node:process';
|
||||||
|
import {test, expect} from '@playwright/test';
|
||||||
|
import {login, apiCreateRepo, randomString} from './utils.ts';
|
||||||
|
|
||||||
|
test('create a label in the modal with a color from the picker popup', async ({page}) => {
|
||||||
|
const repoName = `e2e-label-${randomString(8)}`;
|
||||||
|
await Promise.all([login(page), apiCreateRepo(page.request, {name: repoName, autoInit: false})]);
|
||||||
|
await page.goto(`/${env.GITEA_TEST_E2E_USER}/${repoName}/labels`);
|
||||||
|
await page.getByRole('button', {name: 'New Label'}).click();
|
||||||
|
const modal = page.getByRole('dialog');
|
||||||
|
await modal.getByRole('button', {name: 'Save'}).click();
|
||||||
|
await modal.getByPlaceholder('Label name').fill('e2e-label');
|
||||||
|
const colorInput = modal.locator('.color-picker-combo input');
|
||||||
|
await colorInput.fill('');
|
||||||
|
await page.locator('hex-color-picker').click({position: {x: 10, y: 10}});
|
||||||
|
await expect(colorInput).toHaveValue(/^#[0-9a-f]{6}$/);
|
||||||
|
await modal.getByRole('button', {name: 'Save'}).click();
|
||||||
|
await expect(page.locator('.issue-label-list')).toContainText('e2e-label');
|
||||||
|
});
|
||||||
+20
-2
@@ -1,6 +1,6 @@
|
|||||||
import {env} from 'node:process';
|
import {env} from 'node:process';
|
||||||
import {test} from '@playwright/test';
|
import {test, expect} from '@playwright/test';
|
||||||
import {login, randomString} from './utils.ts';
|
import {login, apiCreateBranch, apiCreateRepo, randomString} from './utils.ts';
|
||||||
|
|
||||||
test('create a repository', async ({page}) => {
|
test('create a repository', async ({page}) => {
|
||||||
const repoName = `e2e-repo-${randomString(8)}`;
|
const repoName = `e2e-repo-${randomString(8)}`;
|
||||||
@@ -10,3 +10,21 @@ test('create a repository', async ({page}) => {
|
|||||||
await page.getByRole('button', {name: 'Create Repository'}).click();
|
await page.getByRole('button', {name: 'Create Repository'}).click();
|
||||||
await page.waitForURL(new RegExp(`/${env.GITEA_TEST_E2E_USER}/${repoName}$`));
|
await page.waitForURL(new RegExp(`/${env.GITEA_TEST_E2E_USER}/${repoName}$`));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('delete a branch via its modal', async ({page, request}) => {
|
||||||
|
const repoName = `e2e-branch-${randomString(8)}`;
|
||||||
|
const owner = env.GITEA_TEST_E2E_USER;
|
||||||
|
await Promise.all([
|
||||||
|
(async () => {
|
||||||
|
await apiCreateRepo(request, {name: repoName});
|
||||||
|
await apiCreateBranch(request, owner, repoName, 'feature');
|
||||||
|
})(),
|
||||||
|
login(page),
|
||||||
|
]);
|
||||||
|
await page.goto(`/${owner}/${repoName}/branches`);
|
||||||
|
await page.getByRole('button', {name: 'Delete Branch "feature"'}).click();
|
||||||
|
const modal = page.getByRole('dialog');
|
||||||
|
await expect(modal).toContainText('feature');
|
||||||
|
await modal.getByRole('button', {name: 'Yes'}).click();
|
||||||
|
await expect(page.locator('.flash-message')).toContainText('Branch "feature" has been deleted.');
|
||||||
|
});
|
||||||
@@ -91,6 +91,20 @@ export async function apiCloseIssue(requestContext: APIRequestContext, owner: st
|
|||||||
}), 'apiCloseIssue');
|
}), 'apiCloseIssue');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function apiEditIssue(requestContext: APIRequestContext, owner: string, repo: string, issueIndex: number, data: Record<string, unknown>) {
|
||||||
|
await apiRetry(() => requestContext.patch(`${baseUrl()}/api/v1/repos/${owner}/${repo}/issues/${issueIndex}`, {
|
||||||
|
headers: apiHeaders(),
|
||||||
|
data,
|
||||||
|
}), 'apiEditIssue');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apiCreateBranch(requestContext: APIRequestContext, owner: string, repo: string, name: string) {
|
||||||
|
await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/branches`, {
|
||||||
|
headers: apiHeaders(),
|
||||||
|
data: {new_branch_name: name},
|
||||||
|
}), 'apiCreateBranch');
|
||||||
|
}
|
||||||
|
|
||||||
/** Create a PR via API. Returns the PR index for subsequent operations. */
|
/** Create a PR via API. Returns the PR index for subsequent operations. */
|
||||||
export async function apiCreatePR(requestContext: APIRequestContext, owner: string, repo: string, head: string, base: string, title: string, {headers}: {headers?: Record<string, string>} = {}): Promise<number> {
|
export async function apiCreatePR(requestContext: APIRequestContext, owner: string, repo: string, head: string, base: string, title: string, {headers}: {headers?: Record<string, string>} = {}): Promise<number> {
|
||||||
const response = await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls`, {
|
const response = await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls`, {
|
||||||
|
|||||||
@@ -845,7 +845,7 @@ table th[data-sortt-desc] .svg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* this is useful to make a left-right (e.g.: title .... operations) layout with default gap, and it wrap for small widths */
|
/* this is useful to make a left-right (e.g.: title .... operations) layout with default gap, and it wrap for small widths */
|
||||||
.ui.modal .header.flex-left-right,
|
.modal-dialog .header.flex-left-right,
|
||||||
.flex-left-right {
|
.flex-left-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
/* These are the remnants of the fomantic dimmer module */
|
.modal-backdrop {
|
||||||
|
|
||||||
.ui.dimmer {
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: none;
|
display: none;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: var(--color-overlay-backdrop);
|
background: var(--color-overlay-backdrop);
|
||||||
opacity: 0;
|
z-index: var(--z-index-modal);
|
||||||
z-index: 1000;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
animation-name: fadein;
|
animation-name: fadein;
|
||||||
animation-duration: .2s;
|
animation-duration: .2s;
|
||||||
|
overscroll-behavior: contain;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.active.dimmer {
|
.modal-backdrop:has(> [open]) {
|
||||||
display: flex;
|
display: flex;
|
||||||
opacity: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.dimmer > .ui.modal {
|
.modal-backdrop > .modal-dialog {
|
||||||
position: static;
|
position: static;
|
||||||
margin-top: auto !important;
|
margin-top: auto;
|
||||||
margin-bottom: auto !important;
|
margin-bottom: auto;
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
/* to keep the changes minimal and easy to revert or fine tune, the legacy classes
|
.modal-page-blocked {
|
||||||
like "small" and "mini" are still kept for the HTML elements, these can be cleaned up in the future */
|
overflow: hidden;
|
||||||
.ui.modal {
|
}
|
||||||
position: absolute;
|
|
||||||
display: none;
|
.modal-dialog {
|
||||||
z-index: var(--z-index-modal);
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: var(--color-body);
|
background: var(--color-body);
|
||||||
border: none;
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: inherit;
|
||||||
box-shadow: 1px 3px 3px 0 var(--color-shadow), 1px 3px 15px 2px var(--color-shadow);
|
box-shadow: 1px 3px 3px 0 var(--color-shadow), 1px 3px 15px 2px var(--color-shadow);
|
||||||
transform-origin: 50% 25%;
|
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
user-select: text;
|
user-select: text;
|
||||||
will-change: top, left, margin, transform, opacity;
|
|
||||||
|
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
/* on small screens, the modal should not exceed 90% of the viewport width;
|
/* on small screens, the modal should not exceed 90% of the viewport width;
|
||||||
@@ -22,17 +22,17 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
min-width: min(800px, max(min(300px, 90vw), 30vw));
|
min-width: min(800px, max(min(300px, 90vw), 30vw));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > :first-child {
|
.modal-dialog > :first-child {
|
||||||
border-top-left-radius: var(--border-radius);
|
border-top-left-radius: var(--border-radius);
|
||||||
border-top-right-radius: var(--border-radius);
|
border-top-right-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > :last-child {
|
.modal-dialog > :last-child {
|
||||||
border-bottom-left-radius: var(--border-radius);
|
border-bottom-left-radius: var(--border-radius);
|
||||||
border-bottom-right-radius: var(--border-radius);
|
border-bottom-right-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .close-modal {
|
.modal-dialog .close-modal {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -47,7 +47,7 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .close-modal::before {
|
.modal-dialog .close-modal::before {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -57,11 +57,11 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
mask-size: cover;
|
mask-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .close-modal:hover {
|
.modal-dialog .close-modal:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > .header {
|
.modal-dialog > .header {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@@ -76,8 +76,8 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
border-top-right-radius: var(--border-radius);
|
border-top-right-radius: var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > .content,
|
.modal-dialog > .content,
|
||||||
.ui.modal form > .content {
|
.modal-dialog form > .content {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@@ -87,9 +87,9 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal > .actions,
|
.modal-dialog > .actions,
|
||||||
.ui.modal .content + .actions,
|
.modal-dialog .content + .actions,
|
||||||
.ui.modal .content + form > .actions {
|
.modal-dialog .content + form > .actions {
|
||||||
background: var(--color-secondary-bg);
|
background: var(--color-secondary-bg);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-top: 1px solid var(--color-secondary);
|
border-top: 1px solid var(--color-secondary);
|
||||||
@@ -97,17 +97,13 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.active.modal {
|
.modal-dialog .content > form > .actions,
|
||||||
display: block;
|
.modal-dialog .content > .actions {
|
||||||
}
|
|
||||||
|
|
||||||
.ui.modal .content > form > .actions,
|
|
||||||
.ui.modal .content > .actions {
|
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .actions > .ui.button {
|
.modal-dialog .actions > .ui.button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
gap: var(--gap-inline);
|
gap: var(--gap-inline);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -116,7 +112,7 @@ like "small" and "mini" are still kept for the HTML elements, these can be clean
|
|||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal .actions > .ui.button.danger {
|
.modal-dialog .actions > .ui.button.danger {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
/* styles for Fomantic transition (toggle): dimmer, modal, dropdown menu */
|
/* styles for Fomantic transition (toggle): dropdown menu */
|
||||||
|
|
||||||
/* this is the only place using "hidden" and "visible" classes, it can safely work with tailwind without prefix in the future */
|
/* this is the only place using "hidden" and "visible" classes, it can safely work with tailwind without prefix in the future */
|
||||||
.ui.modal.transition.hidden,
|
|
||||||
.ui.dropdown > .menu.transition.hidden {
|
.ui.dropdown > .menu.transition.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.modal.transition.visible,
|
|
||||||
.ui.dropdown > .menu.transition.visible {
|
.ui.dropdown > .menu.transition.visible {
|
||||||
display: block;
|
display: block;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dimmer uses "active" but not "hidden/visible" classes, no special classes for it here */
|
|
||||||
|
|
||||||
/* only modal and dimmer need animation, dropdown menu doesn't */
|
|
||||||
.ui.modal.transition {
|
|
||||||
animation-name: fadein;
|
|
||||||
animation-duration: 100ms;
|
|
||||||
animation-timing-function: ease-in-out;
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,4 @@
|
|||||||
import './components/api.js';
|
import './components/api.js';
|
||||||
import './components/dropdown.js';
|
import './components/dropdown.js';
|
||||||
import './components/modal.js';
|
|
||||||
|
|
||||||
// Hard-forked from Fomantic UI 2.8.7, patches are commented with "GITEA-PATCH"
|
// Hard-forked from Fomantic UI 2.8.7, patches are commented with "GITEA-PATCH"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import {checkAppUrl} from '../common-page.ts';
|
import {checkAppUrl} from '../common-page.ts';
|
||||||
import {hideElem, queryElems, showElem, toggleElem} from '../../utils/dom.ts';
|
import {hideElem, queryElems, showElem, toggleElem} from '../../utils/dom.ts';
|
||||||
import {POST} from '../../modules/fetch.ts';
|
import {POST} from '../../modules/fetch.ts';
|
||||||
import {showFomanticModal} from '../../modules/fomantic/modal.ts';
|
import {showModal} from '../../modules/modal.ts';
|
||||||
import {pathEscape} from '../../utils/url.ts';
|
import {pathEscape} from '../../utils/url.ts';
|
||||||
import {registerGlobalInitFunc} from '../../modules/observer.ts';
|
import {registerGlobalInitFunc} from '../../modules/observer.ts';
|
||||||
|
|
||||||
@@ -274,7 +274,7 @@ function initAdminNotice() {
|
|||||||
const pageContent = document.querySelector('.page-content.admin.notice');
|
const pageContent = document.querySelector('.page-content.admin.notice');
|
||||||
if (!pageContent) return;
|
if (!pageContent) return;
|
||||||
|
|
||||||
const detailModal = document.querySelector<HTMLDivElement>('#detail-modal')!;
|
const detailModal = document.querySelector<HTMLDialogElement>('#detail-modal')!;
|
||||||
|
|
||||||
// Attach view detail modals
|
// Attach view detail modals
|
||||||
queryElems(pageContent, '.view-detail', (el) => el.addEventListener('click', (e) => {
|
queryElems(pageContent, '.view-detail', (el) => el.addEventListener('click', (e) => {
|
||||||
@@ -282,7 +282,7 @@ function initAdminNotice() {
|
|||||||
const elNoticeDesc = el.closest('tr')!.querySelector('.notice-description')!;
|
const elNoticeDesc = el.closest('tr')!.querySelector('.notice-description')!;
|
||||||
const elModalDesc = detailModal.querySelector('.content pre')!;
|
const elModalDesc = detailModal.querySelector('.content pre')!;
|
||||||
elModalDesc.textContent = elNoticeDesc.textContent;
|
elModalDesc.textContent = elNoticeDesc.textContent;
|
||||||
showFomanticModal(detailModal);
|
showModal(detailModal);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Select actions
|
// Select actions
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {addDelegatedEventListener, hideElem, isElemVisible, showElem, toggleElem} from '../utils/dom.ts';
|
import {addDelegatedEventListener, hideElem, isElemVisible, showElem, toggleElem} from '../utils/dom.ts';
|
||||||
import {showFomanticModal} from '../modules/fomantic/modal.ts';
|
import {showModal} from '../modules/modal.ts';
|
||||||
import {camelize} from 'vue';
|
import {camelize} from 'vue';
|
||||||
import {applyAutoFocus} from './common-page.ts';
|
import {applyAutoFocus} from './common-page.ts';
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ function onShowModalClick(el: HTMLElement, e: MouseEvent) {
|
|||||||
// to make the template variables get correctly escaped in the URL.
|
// to make the template variables get correctly escaped in the URL.
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const modalSelector = el.getAttribute('data-modal')!;
|
const modalSelector = el.getAttribute('data-modal')!;
|
||||||
const elModal = document.querySelector(modalSelector);
|
const elModal = document.querySelector<HTMLDialogElement>(modalSelector);
|
||||||
if (!elModal) throw new Error('no modal for this action');
|
if (!elModal) throw new Error('no modal for this action');
|
||||||
|
|
||||||
const modalAttrPrefix = 'data-modal-';
|
const modalAttrPrefix = 'data-modal-';
|
||||||
@@ -123,11 +123,11 @@ function onShowModalClick(el: HTMLElement, e: MouseEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showFomanticModal(elModal);
|
showModal(elModal);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initGlobalButtons(): void {
|
export function initGlobalButtons(): void {
|
||||||
// There are many "cancel button" elements in modal dialogs, Fomantic UI expects they are button-like elements but never submit a form.
|
// There are many "cancel button" elements in modal dialogs, they are expected to be button-like elements but never submit a form.
|
||||||
// However, Gitea misuses the modal dialog and put the cancel buttons inside forms, so we must prevent the form submission.
|
// However, Gitea misuses the modal dialog and put the cancel buttons inside forms, so we must prevent the form submission.
|
||||||
// There are a few cancel buttons in non-modal forms, and there are some dynamically created forms (eg: the "Edit Issue Content")
|
// There are a few cancel buttons in non-modal forms, and there are some dynamically created forms (eg: the "Edit Issue Content")
|
||||||
addDelegatedEventListener(document, 'click', 'form button.ui.cancel.button', (_ /* el */, e) => e.preventDefault());
|
addDelegatedEventListener(document, 'click', 'form button.ui.cancel.button', (_ /* el */, e) => e.preventDefault());
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ function autoFocusEnd(el: HTMLInputElement | HTMLTextAreaElement) {
|
|||||||
export function applyAutoFocus(container: Element) {
|
export function applyAutoFocus(container: Element) {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/autofocus
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/autofocus
|
||||||
// "autofocus" behavior is defined by the standard: when a container (e.g.: dialog) becomes visible, focus the element with "autofocus" attribute
|
// "autofocus" behavior is defined by the standard: when a container (e.g.: dialog) becomes visible, focus the element with "autofocus" attribute
|
||||||
// Fomantic UI already supports it for its modal dialog, we need to cover more cases (e.g.: ".show-panel" button)
|
// The native modal dialog already supports it, we need to cover more cases (e.g.: ".show-panel" button)
|
||||||
// Here is just a simple support, we don't expect more than one element that need "autofocus" appearing in the same container
|
// Here is just a simple support, we don't expect more than one element that need "autofocus" appearing in the same container
|
||||||
container.querySelector<HTMLElement>('[autofocus]')?.focus();
|
container.querySelector<HTMLElement>('[autofocus]')?.focus();
|
||||||
// Also, apply our autoFocusEnd behavior
|
// Also, apply our autoFocusEnd behavior
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import {svg} from '../../svg.ts';
|
import {svg} from '../../svg.ts';
|
||||||
import {html, htmlRaw} from '../../utils/html.ts';
|
import {html, htmlRaw} from '../../utils/html.ts';
|
||||||
import {createElementFromHTML} from '../../utils/dom.ts';
|
import {createElementFromHTML} from '../../utils/dom.ts';
|
||||||
import {showFomanticModal} from '../../modules/fomantic/modal.ts';
|
import {showModal} from '../../modules/modal.ts';
|
||||||
import {hideToastsAll} from '../../modules/toast.ts';
|
|
||||||
|
|
||||||
const {i18n} = window.config;
|
const {i18n} = window.config;
|
||||||
|
|
||||||
@@ -12,27 +11,24 @@ type ConfirmModalOptions = {
|
|||||||
confirmButtonColor?: 'primary' | 'red' | 'green' | 'blue';
|
confirmButtonColor?: 'primary' | 'red' | 'green' | 'blue';
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createConfirmModal({header = '', content = '', confirmButtonColor = 'primary'}:ConfirmModalOptions = {}): HTMLElement {
|
export function createConfirmModal({header = '', content = '', confirmButtonColor = 'primary'}:ConfirmModalOptions = {}): HTMLDialogElement {
|
||||||
const headerHtml = header ? html`<div class="header">${header}</div>` : '';
|
const headerHtml = header ? html`<div class="header">${header}</div>` : '';
|
||||||
return createElementFromHTML(html`
|
return createElementFromHTML(html`
|
||||||
<div class="ui g-modal-confirm modal">
|
<dialog class="modal-dialog">
|
||||||
${htmlRaw(headerHtml)}
|
${htmlRaw(headerHtml)}
|
||||||
<div class="content">${content}</div>
|
<div class="content">${content}</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="ui cancel button">${htmlRaw(svg('octicon-x'))} ${i18n.modal_cancel}</button>
|
<button class="ui cancel button">${htmlRaw(svg('octicon-x'))} ${i18n.modal_cancel}</button>
|
||||||
<button class="ui ${confirmButtonColor} ok button" autofocus>${htmlRaw(svg('octicon-check'))} ${i18n.modal_confirm}</button>
|
<button class="ui ${confirmButtonColor} ok button" autofocus>${htmlRaw(svg('octicon-check'))} ${i18n.modal_confirm}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
`.trim());
|
`.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function confirmModal(modal: HTMLElement | ConfirmModalOptions): Promise<boolean> {
|
export function confirmModal(modal: HTMLDialogElement | ConfirmModalOptions): Promise<boolean> {
|
||||||
if (!(modal instanceof HTMLElement)) modal = createConfirmModal(modal);
|
if (!(modal instanceof HTMLDialogElement)) modal = createConfirmModal(modal);
|
||||||
// hide existing toasts when we need to show a new modal, otherwise the toasts only interfere the UI
|
|
||||||
// it's fine to do so because the modal is triggered by user's explicit action, so the user should already have read the toast messages
|
|
||||||
hideToastsAll();
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
showFomanticModal(modal, {
|
showModal(modal, {
|
||||||
onApprove() {
|
onApprove() {
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {queryElems, toggleElem} from '../../utils/dom.ts';
|
import {queryElems, toggleElem} from '../../utils/dom.ts';
|
||||||
import {showFomanticModal} from '../../modules/fomantic/modal.ts';
|
import {showModal} from '../../modules/modal.ts';
|
||||||
import {submitFormFetchAction} from '../../modules/fetch-action.ts';
|
import {submitFormFetchAction} from '../../modules/fetch-action.ts';
|
||||||
import {registerGlobalInitFunc} from '../../modules/observer.ts';
|
import {registerGlobalInitFunc} from '../../modules/observer.ts';
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ function nameHasScope(name: string): boolean {
|
|||||||
return /.*[^/]\/[^/].*/.test(name);
|
return /.*[^/]\/[^/].*/.test(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initLabelEditModal(elModal: HTMLElement) {
|
function initLabelEditModal(elModal: HTMLDialogElement) {
|
||||||
const elLabelId = elModal.querySelector<HTMLInputElement>('input[name="id"]')!;
|
const elLabelId = elModal.querySelector<HTMLInputElement>('input[name="id"]')!;
|
||||||
const elNameInput = elModal.querySelector<HTMLInputElement>('.label-name-input')!;
|
const elNameInput = elModal.querySelector<HTMLInputElement>('.label-name-input')!;
|
||||||
const elExclusiveField = elModal.querySelector('.label-exclusive-input-field')!;
|
const elExclusiveField = elModal.querySelector('.label-exclusive-input-field')!;
|
||||||
@@ -59,7 +59,7 @@ function initLabelEditModal(elModal: HTMLElement) {
|
|||||||
form.action = isEdit ? `${curPageLink}/edit` : `${curPageLink}/new`;
|
form.action = isEdit ? `${curPageLink}/edit` : `${curPageLink}/new`;
|
||||||
toggleElem(elIsArchivedField, isEdit);
|
toggleElem(elIsArchivedField, isEdit);
|
||||||
syncModalUi();
|
syncModalUi();
|
||||||
showFomanticModal(elModal, {
|
showModal(elModal, {
|
||||||
onApprove() {
|
onApprove() {
|
||||||
if (!form.checkValidity()) {
|
if (!form.checkValidity()) {
|
||||||
form.reportValidity();
|
form.reportValidity();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {toggleElem} from '../utils/dom.ts';
|
import {toggleElem} from '../utils/dom.ts';
|
||||||
import {showFomanticModal} from '../modules/fomantic/modal.ts';
|
import {showModal} from '../modules/modal.ts';
|
||||||
import {trString} from '../modules/i18n.ts';
|
import {trString} from '../modules/i18n.ts';
|
||||||
import {registerGlobalEventFunc} from '../modules/observer.ts';
|
import {registerGlobalEventFunc} from '../modules/observer.ts';
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ function initRepoCreateBranchButton() {
|
|||||||
const fromSpanName = el.getAttribute('data-modal-from-span') || '#modal-create-branch-from-span';
|
const fromSpanName = el.getAttribute('data-modal-from-span') || '#modal-create-branch-from-span';
|
||||||
document.querySelector(fromSpanName)!.textContent = el.getAttribute('data-branch-from');
|
document.querySelector(fromSpanName)!.textContent = el.getAttribute('data-branch-from');
|
||||||
|
|
||||||
showFomanticModal(document.querySelector(el.getAttribute('data-modal')!));
|
showModal(document.querySelector(el.getAttribute('data-modal')!)!);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {GET, POST} from '../modules/fetch.ts';
|
|||||||
import {createElementFromHTML, showElem} from '../utils/dom.ts';
|
import {createElementFromHTML, showElem} from '../utils/dom.ts';
|
||||||
import {parseIssuePageInfo} from '../utils.ts';
|
import {parseIssuePageInfo} from '../utils.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
import {hideFomanticModal, showFomanticModal} from '../modules/fomantic/modal.ts';
|
import {hideModal, showModal} from '../modules/modal.ts';
|
||||||
|
import {confirmModal} from './comp/ConfirmModal.ts';
|
||||||
import {html, htmlRaw} from '../utils/html.ts';
|
import {html, htmlRaw} from '../utils/html.ts';
|
||||||
import type {JQueryElem} from '../types.ts';
|
import type {JQueryElem} from '../types.ts';
|
||||||
|
|
||||||
@@ -14,8 +15,8 @@ let i18nTextDeleteFromHistory: string;
|
|||||||
let i18nTextDeleteFromHistoryConfirm: string;
|
let i18nTextDeleteFromHistoryConfirm: string;
|
||||||
|
|
||||||
function showContentHistoryDetail(issueBaseUrl: string, commentId: string, historyId: string, itemTitleHtml: string) {
|
function showContentHistoryDetail(issueBaseUrl: string, commentId: string, historyId: string, itemTitleHtml: string) {
|
||||||
const elDetailDialog = createElementFromHTML(html`
|
const elDetailDialog = createElementFromHTML<HTMLDialogElement>(html`
|
||||||
<div class="ui modal content-history-detail-dialog">
|
<dialog class="modal-dialog content-history-detail-dialog">
|
||||||
<div class="header flex-left-right">
|
<div class="header flex-left-right">
|
||||||
<div>${htmlRaw(itemTitleHtml)}</div>
|
<div>${htmlRaw(itemTitleHtml)}</div>
|
||||||
<div class="ui dropdown dialog-header-options tw-mx-4 tw-hidden">
|
<div class="ui dropdown dialog-header-options tw-mx-4 tw-hidden">
|
||||||
@@ -28,9 +29,8 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
|
|||||||
<button type="button" class="close-modal"></button>
|
<button type="button" class="close-modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="comment-diff-data is-loading"></div>
|
<div class="comment-diff-data is-loading"></div>
|
||||||
</div>
|
</dialog>
|
||||||
`);
|
`);
|
||||||
document.body.append(elDetailDialog);
|
|
||||||
const elOptionsDropdown = elDetailDialog.querySelector('.ui.dropdown.dialog-header-options')!;
|
const elOptionsDropdown = elDetailDialog.querySelector('.ui.dropdown.dialog-header-options')!;
|
||||||
const $fomanticDropdownOptions = fomanticQuery(elOptionsDropdown);
|
const $fomanticDropdownOptions = fomanticQuery(elOptionsDropdown);
|
||||||
$fomanticDropdownOptions.dropdown({
|
$fomanticDropdownOptions.dropdown({
|
||||||
@@ -39,8 +39,7 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
|
|||||||
async onChange(_value: string, _text: string, $item: JQueryElem) {
|
async onChange(_value: string, _text: string, $item: JQueryElem) {
|
||||||
const optionItem = $item.data('option-item');
|
const optionItem = $item.data('option-item');
|
||||||
if (optionItem === 'delete') {
|
if (optionItem === 'delete') {
|
||||||
// TODO: to use confirmModal instead of window.confirm, need to support multiple modals on the same page first.
|
if (await confirmModal({content: i18nTextDeleteFromHistoryConfirm, confirmButtonColor: 'red'})) {
|
||||||
if (window.confirm(i18nTextDeleteFromHistoryConfirm)) {
|
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.append('comment_id', commentId);
|
params.append('comment_id', commentId);
|
||||||
@@ -50,7 +49,7 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
|
|||||||
const resp = await response.json();
|
const resp = await response.json();
|
||||||
|
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
hideFomanticModal(elDetailDialog);
|
hideModal(elDetailDialog);
|
||||||
} else {
|
} else {
|
||||||
showErrorToast(resp.message);
|
showErrorToast(resp.message);
|
||||||
}
|
}
|
||||||
@@ -67,7 +66,7 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
|
|||||||
$fomanticDropdownOptions.dropdown('clear', true);
|
$fomanticDropdownOptions.dropdown('clear', true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
showFomanticModal(elDetailDialog, {
|
showModal(elDetailDialog, {
|
||||||
async onShow() {
|
async onShow() {
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {ComboMarkdownEditor, getComboMarkdownEditor, initComboMarkdownEditor} fr
|
|||||||
import {GET, POST} from '../modules/fetch.ts';
|
import {GET, POST} from '../modules/fetch.ts';
|
||||||
import {showErrorToast} from '../modules/toast.ts';
|
import {showErrorToast} from '../modules/toast.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
import {showFomanticModal} from '../modules/fomantic/modal.ts';
|
import {showModal} from '../modules/modal.ts';
|
||||||
import {ignoreAreYouSure} from '../modules/are-you-sure.ts';
|
import {ignoreAreYouSure} from '../modules/are-you-sure.ts';
|
||||||
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts';
|
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts';
|
||||||
import type {FomanticApiResponse} from '../types.ts';
|
import type {FomanticApiResponse} from '../types.ts';
|
||||||
@@ -325,10 +325,10 @@ export function initRepoIssueReferenceIssue() {
|
|||||||
const poster = el.getAttribute('data-poster-username');
|
const poster = el.getAttribute('data-poster-username');
|
||||||
const reference = el.getAttribute('data-reference')!;
|
const reference = el.getAttribute('data-reference')!;
|
||||||
const modalSelector = el.getAttribute('data-modal')!;
|
const modalSelector = el.getAttribute('data-modal')!;
|
||||||
const modal = document.querySelector(modalSelector)!;
|
const modal = document.querySelector<HTMLDialogElement>(modalSelector)!;
|
||||||
const textarea = modal.querySelector<HTMLTextAreaElement>('textarea[name="content"]')!;
|
const textarea = modal.querySelector<HTMLTextAreaElement>('textarea[name="content"]')!;
|
||||||
textarea.value = `${content}\n\n_Originally posted by @${poster} in ${reference}_`;
|
textarea.value = `${content}\n\n_Originally posted by @${poster} in ${reference}_`;
|
||||||
showFomanticModal(modal);
|
showModal(modal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {contrastColor} from '../utils/color.ts';
|
|||||||
import {createSortable} from '../modules/sortable.ts';
|
import {createSortable} from '../modules/sortable.ts';
|
||||||
import {POST} from '../modules/fetch.ts';
|
import {POST} from '../modules/fetch.ts';
|
||||||
import {performFetchActionRequest} from '../modules/fetch-action.ts';
|
import {performFetchActionRequest} from '../modules/fetch-action.ts';
|
||||||
import {hideFomanticModal} from '../modules/fomantic/modal.ts';
|
import {hideModal} from '../modules/modal.ts';
|
||||||
import {queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
|
import {queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
|
||||||
import type {SortableEvent} from 'sortablejs';
|
import type {SortableEvent} from 'sortablejs';
|
||||||
import {toggleFullScreen} from '../utils.ts';
|
import {toggleFullScreen} from '../utils.ts';
|
||||||
@@ -82,7 +82,7 @@ function initRepoProjectSortable(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initRepoProjectColumnEdit(writableProjectBoard: Element): void {
|
function initRepoProjectColumnEdit(writableProjectBoard: Element): void {
|
||||||
const elModal = document.querySelector<HTMLElement>('.ui.modal#project-column-modal-edit')!;
|
const elModal = document.querySelector<HTMLDialogElement>('#project-column-modal-edit')!;
|
||||||
const elForm = elModal.querySelector<HTMLFormElement>('form')!;
|
const elForm = elModal.querySelector<HTMLFormElement>('form')!;
|
||||||
|
|
||||||
const elColumnId = elForm.querySelector<HTMLInputElement>('input[name="id"]')!;
|
const elColumnId = elForm.querySelector<HTMLInputElement>('input[name="id"]')!;
|
||||||
@@ -140,7 +140,7 @@ function initRepoProjectColumnEdit(writableProjectBoard: Element): void {
|
|||||||
queryElemChildren(elBoardColumn, '.divider', (divider: HTMLElement) => divider.style.removeProperty('color'));
|
queryElemChildren(elBoardColumn, '.divider', (divider: HTMLElement) => divider.style.removeProperty('color'));
|
||||||
}
|
}
|
||||||
|
|
||||||
hideFomanticModal(elModal);
|
hideModal(elModal);
|
||||||
} finally {
|
} finally {
|
||||||
elForm.classList.remove('is-loading');
|
elForm.classList.remove('is-loading');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {hideToastsAll, showErrorToast} from '../modules/toast.ts';
|
|||||||
import {getComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
|
import {getComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
|
||||||
import {hideElem} from '../utils/dom.ts';
|
import {hideElem} from '../utils/dom.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
import {hideFomanticModal, showFomanticModal} from '../modules/fomantic/modal.ts';
|
import {hideModal, showModal} from '../modules/modal.ts';
|
||||||
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts';
|
import {registerGlobalEventFunc, registerGlobalInitFunc} from '../modules/observer.ts';
|
||||||
import {htmlEscape} from '../utils/html.ts';
|
import {htmlEscape} from '../utils/html.ts';
|
||||||
import {compareVersions} from 'compare-versions';
|
import {compareVersions} from 'compare-versions';
|
||||||
@@ -84,7 +84,7 @@ function initGenerateReleaseNotes(elForm: HTMLFormElement) {
|
|||||||
const textMissingTag = buttonShowModal.getAttribute('data-text-missing-tag')!;
|
const textMissingTag = buttonShowModal.getAttribute('data-text-missing-tag')!;
|
||||||
const generateUrl = buttonShowModal.getAttribute('data-generate-url')!;
|
const generateUrl = buttonShowModal.getAttribute('data-generate-url')!;
|
||||||
|
|
||||||
const elModal = document.querySelector('#generate-release-notes-modal')!;
|
const elModal = document.querySelector<HTMLDialogElement>('#generate-release-notes-modal')!;
|
||||||
|
|
||||||
const doSubmit = async (tagName: string) => {
|
const doSubmit = async (tagName: string) => {
|
||||||
const elPreviousTag = elModal.querySelector<HTMLSelectElement>('[name=previous_tag]')!;
|
const elPreviousTag = elModal.querySelector<HTMLSelectElement>('[name=previous_tag]')!;
|
||||||
@@ -111,18 +111,18 @@ function initGenerateReleaseNotes(elForm: HTMLFormElement) {
|
|||||||
} else {
|
} else {
|
||||||
comboEditor.value(data.content);
|
comboEditor.value(data.content);
|
||||||
}
|
}
|
||||||
|
hideModal(elModal);
|
||||||
|
comboEditor.focus();
|
||||||
} finally {
|
} finally {
|
||||||
elModal.classList.remove('loading', 'disabled');
|
elModal.classList.remove('loading', 'disabled');
|
||||||
hideFomanticModal(elModal);
|
|
||||||
comboEditor.focus();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let inited = false;
|
let inited = false;
|
||||||
const doShowModal = () => {
|
const doShowModal = () => {
|
||||||
hideToastsAll();
|
|
||||||
const tagName = tagNameInput.value.trim();
|
const tagName = tagNameInput.value.trim();
|
||||||
if (!tagName) {
|
if (!tagName) {
|
||||||
|
hideToastsAll();
|
||||||
showErrorToast(textMissingTag, {duration: 3000});
|
showErrorToast(textMissingTag, {duration: 3000});
|
||||||
tagNameInput.focus();
|
tagNameInput.focus();
|
||||||
return;
|
return;
|
||||||
@@ -140,7 +140,7 @@ function initGenerateReleaseNotes(elForm: HTMLFormElement) {
|
|||||||
}
|
}
|
||||||
$dropdown.dropdown('set selected', guessPreviousReleaseTag(tagName, existingTags));
|
$dropdown.dropdown('set selected', guessPreviousReleaseTag(tagName, existingTags));
|
||||||
|
|
||||||
showFomanticModal(elModal, {
|
showModal(elModal, {
|
||||||
onApprove: () => {
|
onApprove: () => {
|
||||||
doSubmit(tagName); // don't await, need to return false to keep the modal
|
doSubmit(tagName); // don't await, need to return false to keep the modal
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Vendored
-3
@@ -1,12 +1,9 @@
|
|||||||
interface JQuery {
|
interface JQuery {
|
||||||
fomanticExt: {
|
fomanticExt: {
|
||||||
onDropdownAfterFiltered?: (this: HTMLElement) => void,
|
onDropdownAfterFiltered?: (this: HTMLElement) => void,
|
||||||
onModalBeforeHidden?: (this: HTMLElement) => void,
|
|
||||||
}; // fomantic extension
|
}; // fomantic extension
|
||||||
api: any, // fomantic
|
api: any, // fomantic
|
||||||
dimmer: any, // fomantic
|
|
||||||
dropdown: any; // fomantic
|
dropdown: any; // fomantic
|
||||||
modal: any; // fomantic
|
|
||||||
transition: any, // fomantic
|
transition: any, // fomantic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,13 @@ import {initDevtest} from './modules/devtest.ts';
|
|||||||
import {initRepoWatch} from './features/repo-watch.ts';
|
import {initRepoWatch} from './features/repo-watch.ts';
|
||||||
import {initPackagesView} from './features/packages.ts';
|
import {initPackagesView} from './features/packages.ts';
|
||||||
import {initAsyncHashChangeListeners} from './modules/hashchange.ts';
|
import {initAsyncHashChangeListeners} from './modules/hashchange.ts';
|
||||||
|
import {initGlobalModal} from './modules/modal.ts';
|
||||||
|
|
||||||
const initStartTime = performance.now();
|
const initStartTime = performance.now();
|
||||||
const initPerformanceTracer = callInitFunctions([
|
const initPerformanceTracer = callInitFunctions([
|
||||||
initGiteaFomantic,
|
initGiteaFomantic,
|
||||||
|
|
||||||
|
initGlobalModal,
|
||||||
initGlobalComponent,
|
initGlobalComponent,
|
||||||
initGlobalDropdown,
|
initGlobalDropdown,
|
||||||
initGlobalFetchAction,
|
initGlobalFetchAction,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {showSuccessToast, showInfoToast, showWarningToast, showErrorToast} from './toast.ts';
|
import {showSuccessToast, showInfoToast, showWarningToast, showErrorToast} from './toast.ts';
|
||||||
import {registerGlobalInitFunc} from './observer.ts';
|
import {registerGlobalInitFunc} from './observer.ts';
|
||||||
import {showFomanticModal} from './fomantic/modal.ts';
|
import {showModal} from './modal.ts';
|
||||||
import {createElementFromHTML} from '../utils/dom.ts';
|
import {createElementFromHTML} from '../utils/dom.ts';
|
||||||
import {html} from '../utils/html.ts';
|
import {html} from '../utils/html.ts';
|
||||||
import {showGlobalErrorMessage} from './errors.ts';
|
import {showGlobalErrorMessage} from './errors.ts';
|
||||||
@@ -25,9 +25,9 @@ function initDevtestPage() {
|
|||||||
|
|
||||||
const modalButtons = document.querySelector('.modal-buttons');
|
const modalButtons = document.querySelector('.modal-buttons');
|
||||||
if (modalButtons) {
|
if (modalButtons) {
|
||||||
for (const el of document.querySelectorAll('.ui.modal:not([data-skip-button])')) {
|
for (const el of document.querySelectorAll<HTMLDialogElement>('.modal-dialog:not([data-skip-button])')) {
|
||||||
const btn = createElementFromHTML(html`<button class="ui button">${el.id}</button`);
|
const btn = createElementFromHTML(html`<button class="ui button">${el.id}</button`);
|
||||||
btn.addEventListener('click', () => showFomanticModal(el));
|
btn.addEventListener('click', () => showModal(el));
|
||||||
modalButtons.append(btn);
|
modalButtons.append(btn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,10 +231,10 @@ export async function submitFormFetchAction(elForm: HTMLFormElement, opts: Submi
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function confirmFetchAction(el: HTMLElement) {
|
async function confirmFetchAction(el: HTMLElement) {
|
||||||
let elModal: HTMLElement | null = null;
|
let elModal: HTMLDialogElement | null = null;
|
||||||
const dataModalConfirm = el.getAttribute('data-modal-confirm') || '';
|
const dataModalConfirm = el.getAttribute('data-modal-confirm') || '';
|
||||||
if (dataModalConfirm.startsWith('#') && dataModalConfirm.length > 1) {
|
if (dataModalConfirm.startsWith('#') && dataModalConfirm.length > 1) {
|
||||||
elModal = document.querySelector<HTMLElement>(`#${CSS.escape(dataModalConfirm.substring(1))}`);
|
elModal = document.querySelector<HTMLDialogElement>(`#${CSS.escape(dataModalConfirm.substring(1))}`);
|
||||||
if (elModal) {
|
if (elModal) {
|
||||||
elModal = createElementFromHTML(elModal.outerHTML);
|
elModal = createElementFromHTML(elModal.outerHTML);
|
||||||
elModal.removeAttribute('id');
|
elModal.removeAttribute('id');
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import {initAriaDropdownPatch} from './fomantic/dropdown.ts';
|
import {initAriaDropdownPatch} from './fomantic/dropdown.ts';
|
||||||
import {initAriaModalPatch} from './fomantic/modal.ts';
|
|
||||||
import {initFomanticTransition} from './fomantic/transition.ts';
|
import {initFomanticTransition} from './fomantic/transition.ts';
|
||||||
import {initFomanticDimmer} from './fomantic/dimmer.ts';
|
|
||||||
import {svg} from '../svg.ts';
|
import {svg} from '../svg.ts';
|
||||||
|
|
||||||
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
||||||
@@ -20,9 +18,7 @@ export function initGiteaFomantic() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
initFomanticTransition();
|
initFomanticTransition();
|
||||||
initFomanticDimmer();
|
|
||||||
|
|
||||||
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
||||||
initAriaDropdownPatch();
|
initAriaDropdownPatch();
|
||||||
initAriaModalPatch();
|
|
||||||
}
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import {queryElemChildren} from '../../utils/dom.ts';
|
|
||||||
|
|
||||||
export function initFomanticDimmer() {
|
|
||||||
// stand-in for removed dimmer module
|
|
||||||
$.fn.dimmer = function (this: any, arg0: string, arg1: any) {
|
|
||||||
if (arg0 === 'add content') {
|
|
||||||
const $el = arg1;
|
|
||||||
const existingDimmer = document.querySelector('body > .ui.dimmer');
|
|
||||||
if (existingDimmer) {
|
|
||||||
queryElemChildren(existingDimmer, '*', (el) => el.classList.add('hidden'));
|
|
||||||
this._dimmer = existingDimmer;
|
|
||||||
} else {
|
|
||||||
this._dimmer = document.createElement('div');
|
|
||||||
this._dimmer.classList.add('ui', 'dimmer');
|
|
||||||
document.body.append(this._dimmer);
|
|
||||||
}
|
|
||||||
this._dimmer.append($el[0]);
|
|
||||||
} else if (arg0 === 'get dimmer') {
|
|
||||||
return $(this._dimmer);
|
|
||||||
} else if (arg0 === 'show') {
|
|
||||||
this._dimmer.classList.add('active');
|
|
||||||
document.body.classList.add('tw-overflow-hidden');
|
|
||||||
} else if (arg0 === 'hide') {
|
|
||||||
const cb = arg1;
|
|
||||||
this._dimmer.classList.remove('active');
|
|
||||||
document.body.classList.remove('tw-overflow-hidden');
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import type {FomanticInitFunction, JQueryElem} from '../../types.ts';
|
|
||||||
import {queryElems} from '../../utils/dom.ts';
|
|
||||||
import {hideToastsFrom} from '../toast.ts';
|
|
||||||
|
|
||||||
type ModalOpts = {
|
|
||||||
closable?: boolean;
|
|
||||||
onApprove?: (this: HTMLElement) => boolean | void;
|
|
||||||
onShow?: (this: HTMLElement) => void | Promise<void>;
|
|
||||||
onHide?: (this: HTMLElement) => void;
|
|
||||||
onHidden?: (this: HTMLElement) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
// thin wrapper around Fomantic's jQuery modal plugin so callers don't have to touch jQuery or fomanticQuery
|
|
||||||
export function showFomanticModal(el: Element | null, opts: ModalOpts = {}) {
|
|
||||||
if (!el) return;
|
|
||||||
const $el = $(el);
|
|
||||||
if (Object.keys(opts).length) $el.modal(opts);
|
|
||||||
$el.modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideFomanticModal(el: Element | null) {
|
|
||||||
if (!el) return;
|
|
||||||
$(el).modal('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
const fomanticModalFn = $.fn.modal;
|
|
||||||
|
|
||||||
// use our own `$.fn.modal` to patch Fomantic's modal module
|
|
||||||
export function initAriaModalPatch() {
|
|
||||||
if ($.fn.modal === ariaModalFn) throw new Error('initAriaModalPatch could only be called once');
|
|
||||||
$.fn.modal = ariaModalFn;
|
|
||||||
(ariaModalFn as FomanticInitFunction).settings = fomanticModalFn.settings;
|
|
||||||
$.fn.fomanticExt.onModalBeforeHidden = onModalBeforeHidden;
|
|
||||||
$.fn.modal.settings.onApprove = onModalApproveDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the patched `$.fn.modal` modal function
|
|
||||||
// * it does the one-time attaching on the first call
|
|
||||||
function ariaModalFn(this: JQueryElem, ...args: Parameters<FomanticInitFunction>) {
|
|
||||||
const ret = fomanticModalFn.apply(this, args);
|
|
||||||
if (args[0] === 'show' || args[0]?.autoShow) {
|
|
||||||
for (const el of this) {
|
|
||||||
el.querySelector('.close-modal')?.setAttribute('aria-label', 'Close');
|
|
||||||
// If there is a form in the modal, there might be a "cancel" button before "ok" button (all buttons are "type=submit" by default).
|
|
||||||
// In such case, the "Enter" key will trigger the "cancel" button instead of "ok" button, then the dialog will be closed.
|
|
||||||
// It breaks the user experience - the "Enter" key should confirm the dialog and submit the form.
|
|
||||||
// So, all "cancel" buttons without "[type]" must be marked as "type=button".
|
|
||||||
// Although there are lint rules for "button type", some HTML code is generated in JS/Vue/Go which isn't linted, so we still need this patch.
|
|
||||||
for (const button of el.querySelectorAll('form button.cancel:not([type])')) {
|
|
||||||
button.setAttribute('type', 'button');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onModalBeforeHidden(this: HTMLElement) {
|
|
||||||
const $modal = $(this);
|
|
||||||
const elModal = $modal[0];
|
|
||||||
hideToastsFrom(elModal.closest('.ui.dimmer') ?? document.body);
|
|
||||||
|
|
||||||
// reset the form after the modal is hidden, after other modal events and handlers (e.g. "onApprove", form submit)
|
|
||||||
setTimeout(() => {
|
|
||||||
queryElems(elModal, 'form', (form: HTMLFormElement) => form.reset());
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onModalApproveDefault(this: HTMLElement) {
|
|
||||||
const $modal = $(this);
|
|
||||||
const selectors = $modal.modal('setting', 'selector');
|
|
||||||
const elModal = $modal[0];
|
|
||||||
const elApprove = elModal.querySelector<HTMLElement>(selectors.approve);
|
|
||||||
const elForm = elApprove?.closest<HTMLFormElement>('form');
|
|
||||||
if (!elForm) return true; // no form, just allow closing the modal
|
|
||||||
|
|
||||||
// "form-fetch-action" can handle network errors gracefully,
|
|
||||||
// so keep the modal dialog to make users can re-submit the form if anything wrong happens.
|
|
||||||
if (elForm.matches('.form-fetch-action')) return false;
|
|
||||||
|
|
||||||
// There is an abuse for the "modal" + "form" combination, the "Approve" button is a traditional form submit button in the form.
|
|
||||||
// Then "approve" and "submit" occur at the same time, the modal will be closed immediately before the form is submitted.
|
|
||||||
// So here we prevent the modal from closing automatically by returning false, add the "is-loading" class to the form element.
|
|
||||||
if (!elForm.reportValidity()) return false;
|
|
||||||
elForm.classList.add('is-loading');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
export function initFomanticTransition() {
|
export function initFomanticTransition() {
|
||||||
const transitionNopBehaviors = new Set([
|
|
||||||
'clear queue', 'stop', 'stop all', 'destroy',
|
|
||||||
'force repaint', 'repaint', 'reset',
|
|
||||||
'looping', 'remove looping', 'disable', 'enable',
|
|
||||||
'set duration', 'save conditions', 'restore conditions',
|
|
||||||
]);
|
|
||||||
// stand-in for removed transition module
|
// stand-in for removed transition module
|
||||||
$.fn.transition = function (arg0: any, arg1?: number, arg2?: (this: HTMLElement) => void) {
|
$.fn.transition = function (arg0: any) {
|
||||||
if (arg0 === 'is supported') return true;
|
if (arg0 === 'is supported') return true;
|
||||||
if (arg0 === 'is animating') return false;
|
if (arg0 === 'is animating') return false;
|
||||||
if (arg0 === 'is inward') return false;
|
if (arg0 === 'is inward') return false;
|
||||||
@@ -14,10 +8,8 @@ export function initFomanticTransition() {
|
|||||||
|
|
||||||
let argObj: Record<string, any>;
|
let argObj: Record<string, any>;
|
||||||
if (typeof arg0 === 'string') {
|
if (typeof arg0 === 'string') {
|
||||||
// many behaviors are no-op now. https://fomantic-ui.com/modules/transition.html#/usage
|
if (arg0 === 'stop all') return this;
|
||||||
if (transitionNopBehaviors.has(arg0)) return this;
|
argObj = {animation: arg0};
|
||||||
// now, the arg0 is an animation name, the syntax: (animation, duration, complete)
|
|
||||||
argObj = {animation: arg0, ...(arg1 && {duration: arg1}), ...(arg2 && {onComplete: arg2})};
|
|
||||||
} else if (typeof arg0 === 'object') {
|
} else if (typeof arg0 === 'object') {
|
||||||
argObj = arg0;
|
argObj = arg0;
|
||||||
} else {
|
} else {
|
||||||
@@ -38,12 +30,10 @@ export function initFomanticTransition() {
|
|||||||
el.classList.remove('hidden');
|
el.classList.remove('hidden');
|
||||||
el.classList.add('visible', 'transition');
|
el.classList.add('visible', 'transition');
|
||||||
if (argObj.displayType) el.style.setProperty('display', argObj.displayType, 'important');
|
if (argObj.displayType) el.style.setProperty('display', argObj.displayType, 'important');
|
||||||
argObj.onShow?.call(el);
|
|
||||||
} else {
|
} else {
|
||||||
el.classList.add('hidden');
|
el.classList.add('hidden');
|
||||||
el.classList.remove('visible'); // don't remove the transition class because the Fomantic animation style is `.hidden.transition`.
|
el.classList.remove('visible'); // don't remove the transition class because the Fomantic animation style is `.hidden.transition`.
|
||||||
el.style.removeProperty('display');
|
el.style.removeProperty('display');
|
||||||
argObj.onHidden?.call(el);
|
|
||||||
}
|
}
|
||||||
argObj.onComplete?.call(el);
|
argObj.onComplete?.call(el);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import {userEvent} from 'vitest/browser';
|
||||||
|
import {createElementFromHTML} from '../utils/dom.ts';
|
||||||
|
import {hideModal, initGlobalModal, showModal} from './modal.ts';
|
||||||
|
import {showErrorToast} from './toast.ts';
|
||||||
|
|
||||||
|
test('showModal blocks the page and restores focus until closed by actions, backdrop or unconsumed Escape on the topmost modal', async () => {
|
||||||
|
initGlobalModal();
|
||||||
|
document.body.innerHTML = `
|
||||||
|
<button id="opener">Opener</button>
|
||||||
|
<dialog class="modal-dialog">
|
||||||
|
<div class="header">Header <button type="button" class="close-modal"></button></div>
|
||||||
|
<form class="content">
|
||||||
|
<input name="text">
|
||||||
|
<div class="actions"><button class="ui cancel button">Cancel</button><button type="button" class="ui ok button">OK</button></div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
`;
|
||||||
|
const opener = document.querySelector<HTMLElement>('#opener')!;
|
||||||
|
const modal = document.querySelector<HTMLDialogElement>('.modal-dialog')!;
|
||||||
|
const onHidden = vi.fn();
|
||||||
|
let approve = false;
|
||||||
|
opener.focus();
|
||||||
|
showModal(modal, {onApprove: () => approve, onHidden});
|
||||||
|
const backdrop = modal.parentElement!;
|
||||||
|
expect(opener.inert).toBe(true);
|
||||||
|
expect(backdrop.inert).toBe(false);
|
||||||
|
expect(modal.getAttribute('aria-labelledby')).toBe(modal.querySelector('.header')!.id);
|
||||||
|
expect(document.body.classList.contains('modal-page-blocked')).toBe(true);
|
||||||
|
expect(modal.querySelector('.cancel')!.getAttribute('type')).toBe('button');
|
||||||
|
|
||||||
|
modal.querySelector('input')!.value = 'changed';
|
||||||
|
modal.querySelector<HTMLElement>('.ok')!.click();
|
||||||
|
expect(modal.open).toBe(true);
|
||||||
|
approve = true;
|
||||||
|
modal.querySelector<HTMLElement>('.ok')!.click();
|
||||||
|
expect(onHidden).toHaveBeenCalledOnce();
|
||||||
|
expect(modal.querySelector('input')!.value).toBe('');
|
||||||
|
expect(document.body.classList.contains('modal-page-blocked')).toBe(false);
|
||||||
|
expect(opener.inert).toBe(false);
|
||||||
|
expect(document.activeElement).toBe(opener);
|
||||||
|
|
||||||
|
for (const selector of ['.cancel', '.close-modal']) {
|
||||||
|
showModal(modal);
|
||||||
|
modal.querySelector<HTMLElement>(selector)!.click();
|
||||||
|
expect(modal.open).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
showModal(modal);
|
||||||
|
await userEvent.click(modal.querySelector('input')!);
|
||||||
|
expect(modal.open).toBe(true);
|
||||||
|
backdrop.dispatchEvent(new PointerEvent('pointerdown'));
|
||||||
|
backdrop.click();
|
||||||
|
expect(modal.open).toBe(false);
|
||||||
|
|
||||||
|
showModal(modal);
|
||||||
|
document.addEventListener('keydown', (e) => e.preventDefault(), {once: true});
|
||||||
|
await userEvent.keyboard('{Escape}');
|
||||||
|
expect(modal.open).toBe(true);
|
||||||
|
|
||||||
|
const nested = createElementFromHTML<HTMLDialogElement>('<dialog class="modal-dialog"></dialog>');
|
||||||
|
showModal(nested, {onHidden: () => nested.remove()});
|
||||||
|
const nestedBackdrop = nested.parentElement!;
|
||||||
|
expect(backdrop.inert).toBe(true);
|
||||||
|
await userEvent.keyboard('{Escape}');
|
||||||
|
expect(nestedBackdrop.isConnected).toBe(false);
|
||||||
|
expect(modal.open).toBe(true);
|
||||||
|
expect(backdrop.inert).toBe(false);
|
||||||
|
expect(opener.inert).toBe(true);
|
||||||
|
expect(modal.contains(document.activeElement)).toBe(true);
|
||||||
|
|
||||||
|
showErrorToast('error in modal');
|
||||||
|
expect(document.querySelector('.toastify.on')).not.toBeNull();
|
||||||
|
await userEvent.keyboard('{Escape}');
|
||||||
|
expect(modal.open).toBe(false);
|
||||||
|
expect(document.querySelector('.toastify.on')).toBeNull();
|
||||||
|
|
||||||
|
(document.activeElement as HTMLElement).blur();
|
||||||
|
showModal(modal);
|
||||||
|
hideModal(modal);
|
||||||
|
expect(document.activeElement).toBe(document.body);
|
||||||
|
|
||||||
|
showModal(modal, {onHidden: () => modal.remove()});
|
||||||
|
hideModal(modal);
|
||||||
|
opener.focus();
|
||||||
|
expect(backdrop.isConnected).toBe(false);
|
||||||
|
expect(document.activeElement).toBe(opener);
|
||||||
|
});
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
import {hideAll} from 'tippy.js';
|
||||||
|
import {generateElemId, queryElems} from '../utils/dom.ts';
|
||||||
|
import {hideToastsAll} from './toast.ts';
|
||||||
|
|
||||||
|
type ModalOpts = {
|
||||||
|
onApprove?: () => boolean | void, // return false to keep the modal open
|
||||||
|
onShow?: () => void | Promise<void>,
|
||||||
|
onHidden?: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modalStates = new WeakMap<Element, {opts: ModalOpts, opener: Element | null}>();
|
||||||
|
|
||||||
|
const topModal = () => Array.from(document.querySelectorAll<HTMLDialogElement>('.modal-dialog[open]')).at(-1);
|
||||||
|
|
||||||
|
function blockPage(elBackdrop?: Element | null) {
|
||||||
|
const wasBlocked = document.body.classList.contains('modal-page-blocked');
|
||||||
|
const shouldBlock = Boolean(elBackdrop);
|
||||||
|
if (wasBlocked !== shouldBlock) {
|
||||||
|
// keep the page width when its scrollbar disappears
|
||||||
|
document.body.style.marginRight = shouldBlock ? `${window.innerWidth - document.documentElement.clientWidth}px` : '';
|
||||||
|
document.body.classList.toggle('modal-page-blocked', shouldBlock);
|
||||||
|
}
|
||||||
|
for (const el of document.body.children) {
|
||||||
|
(el as HTMLElement).inert = shouldBlock && el !== elBackdrop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initGlobalModal() {
|
||||||
|
// on window, so popups handling Escape on document can consume it first
|
||||||
|
window.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key !== 'Escape' || e.defaultPrevented || e.isComposing) return;
|
||||||
|
const elModal = topModal();
|
||||||
|
if (elModal) hideModal(elModal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultApprove(elApprove: Element): boolean {
|
||||||
|
const elForm = elApprove.closest('form');
|
||||||
|
if (!elForm) return true;
|
||||||
|
|
||||||
|
// if there is traditional form, keep the modal open while the form submits
|
||||||
|
// "form-fetch-action" form's submit (is-loading) is handled by the fetch-action module
|
||||||
|
if (!elForm.matches('.form-fetch-action') && elForm.reportValidity()) {
|
||||||
|
elForm.classList.add('is-loading');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createModalBackdrop(elModal: HTMLDialogElement): HTMLElement {
|
||||||
|
const elBackdrop = document.createElement('div');
|
||||||
|
elBackdrop.className = 'modal-backdrop';
|
||||||
|
elBackdrop.append(elModal);
|
||||||
|
|
||||||
|
const elAriaLabelTarget = elModal.querySelector(':scope > .header, :scope > .content');
|
||||||
|
if (elAriaLabelTarget) {
|
||||||
|
elAriaLabelTarget.id ||= generateElemId('_modal_label_');
|
||||||
|
elModal.setAttribute('aria-labelledby', elAriaLabelTarget.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let backdropPressed = false;
|
||||||
|
elBackdrop.addEventListener('pointerdown', (event) => { backdropPressed = event.target === elBackdrop });
|
||||||
|
elBackdrop.addEventListener('click', (event) => {
|
||||||
|
const target = event.target as Element;
|
||||||
|
if (target === elBackdrop) {
|
||||||
|
if (backdropPressed) hideModal(elModal);
|
||||||
|
} else if (target.closest('.close-modal, .actions .cancel')) {
|
||||||
|
hideModal(elModal);
|
||||||
|
} else {
|
||||||
|
const elApprove = target.closest('.actions :is(.approve, .ok)');
|
||||||
|
if (!elApprove) return;
|
||||||
|
const {onApprove} = modalStates.get(elModal)!.opts;
|
||||||
|
if ((onApprove ? onApprove() : defaultApprove(elApprove)) !== false) hideModal(elModal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.body.append(elBackdrop);
|
||||||
|
return elBackdrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showModal(elModal: HTMLDialogElement, opts: ModalOpts = {}) {
|
||||||
|
if (elModal.open) return;
|
||||||
|
|
||||||
|
const elBackdrop = elModal.parentElement?.matches('.modal-backdrop') ? elModal.parentElement : createModalBackdrop(elModal);
|
||||||
|
modalStates.set(elModal, {opts, opener: document.activeElement});
|
||||||
|
elModal.querySelector('.close-modal')?.setAttribute('aria-label', 'Close');
|
||||||
|
|
||||||
|
// Avoid "cancel" buttons submitting the form, otherwise "Enter" in the form clicks this "cancel" button before the "ok" button
|
||||||
|
queryElems(elModal, 'form button.cancel:not([type])', (button) => button.setAttribute('type', 'button'));
|
||||||
|
|
||||||
|
hideToastsAll();
|
||||||
|
hideAll();
|
||||||
|
blockPage(elBackdrop);
|
||||||
|
|
||||||
|
elModal.show(); // not showModal: popups and toasts mounted on body must stay usable above it, see https://github.com/whatwg/html/issues/9936
|
||||||
|
opts.onShow?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideModal(elModal: HTMLDialogElement) {
|
||||||
|
if (!elModal.open) return;
|
||||||
|
const {opts, opener} = modalStates.get(elModal)!;
|
||||||
|
const elBackdrop = elModal.parentElement!;
|
||||||
|
elModal.close();
|
||||||
|
blockPage(topModal()?.parentElement);
|
||||||
|
|
||||||
|
// don't leave the focus in the closed dialog when the opener is gone
|
||||||
|
if (document.activeElement instanceof HTMLElement) document.activeElement.blur();
|
||||||
|
if (opener instanceof HTMLElement) opener.focus();
|
||||||
|
|
||||||
|
hideToastsAll();
|
||||||
|
queryElems(elModal, 'form', (form: HTMLFormElement) => form.reset());
|
||||||
|
opts.onHidden?.();
|
||||||
|
if (!elBackdrop.contains(elModal)) elBackdrop.remove();
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import '../../fomantic/build/fomantic.js';
|
|
||||||
import {userEvent} from 'vitest/browser';
|
|
||||||
import {initGlobalShortcut, makeFullKeyFromEvent} from './shortcut.ts';
|
import {initGlobalShortcut, makeFullKeyFromEvent} from './shortcut.ts';
|
||||||
import {initGlobalSelectorObserver} from './observer.ts';
|
import {initGlobalSelectorObserver} from './observer.ts';
|
||||||
import {initGiteaFomantic} from './fomantic.ts';
|
import {initGlobalModal} from './modal.ts';
|
||||||
|
|
||||||
function press(key: string, options: KeyboardEventInit = {}, target: HTMLElement = document.body) {
|
function press(key: string, options: KeyboardEventInit = {}, target: HTMLElement = document.body) {
|
||||||
const event = new KeyboardEvent('keydown', {key, bubbles: true, cancelable: true, ...options});
|
const event = new KeyboardEvent('keydown', {key, bubbles: true, cancelable: true, ...options});
|
||||||
@@ -21,7 +19,7 @@ beforeAll(() => {
|
|||||||
<select><option>Value</option></select>
|
<select><option>Value</option></select>
|
||||||
<div contenteditable="true"><span>Editable</span></div>
|
<div contenteditable="true"><span>Editable</span></div>
|
||||||
`;
|
`;
|
||||||
initGiteaFomantic();
|
initGlobalModal();
|
||||||
initGlobalShortcut();
|
initGlobalShortcut();
|
||||||
initGlobalSelectorObserver(null);
|
initGlobalSelectorObserver(null);
|
||||||
});
|
});
|
||||||
@@ -106,7 +104,7 @@ test('normalizes keys and sorts modifiers alphabetically', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('shows current shortcuts with ? and closes with Escape or the close button', async () => {
|
test('shows current shortcuts with ? and closes with Escape or the close button', () => {
|
||||||
const input = document.querySelector('input')!;
|
const input = document.querySelector('input')!;
|
||||||
const click = vi.spyOn(document.querySelector('button')!, 'click');
|
const click = vi.spyOn(document.querySelector('button')!, 'click');
|
||||||
press('?', {shiftKey: true}, input);
|
press('?', {shiftKey: true}, input);
|
||||||
@@ -115,20 +113,20 @@ test('shows current shortcuts with ? and closes with Escape or the close button'
|
|||||||
expect(document.querySelector('#global-shortcut-help')).toBeNull();
|
expect(document.querySelector('#global-shortcut-help')).toBeNull();
|
||||||
press('g');
|
press('g');
|
||||||
expect(press('?', {shiftKey: true}).defaultPrevented).toBe(true);
|
expect(press('?', {shiftKey: true}).defaultPrevented).toBe(true);
|
||||||
const modal = document.querySelector<HTMLElement>('#global-shortcut-help')!;
|
const modal = document.querySelector<HTMLDialogElement>('#global-shortcut-help')!;
|
||||||
expect(modal.classList.contains('active')).toBe(true);
|
expect(modal.open).toBe(true);
|
||||||
expect(modal.querySelector('.shortcut-list tr:nth-child(2) td:last-child')!.textContent).toBe('Issues');
|
expect(modal.querySelector('.shortcut-list tr:nth-child(2) td:last-child')!.textContent).toBe('Issues');
|
||||||
expect(modal.querySelector('.shortcut-list')!.textContent).toContain('Search code');
|
expect(modal.querySelector('.shortcut-list')!.textContent).toContain('Search code');
|
||||||
expect(modal.querySelectorAll('.shortcut-list tr')).toHaveLength(3);
|
expect(modal.querySelectorAll('.shortcut-list tr')).toHaveLength(3);
|
||||||
press('g');
|
press('g');
|
||||||
press('i');
|
press('i');
|
||||||
expect(click).not.toHaveBeenCalled();
|
expect(click).not.toHaveBeenCalled();
|
||||||
await userEvent.keyboard('{Escape}');
|
press('Escape');
|
||||||
expect(modal.classList.contains('active')).toBe(false);
|
expect(modal.open).toBe(false);
|
||||||
|
|
||||||
input.setAttribute('placeholder', '<b>Updated search</b>');
|
input.setAttribute('placeholder', '<b>Updated search</b>');
|
||||||
press('?');
|
press('?');
|
||||||
expect(document.querySelectorAll('.ui.modal')).toHaveLength(1);
|
expect(document.querySelectorAll('.modal-dialog')).toHaveLength(1);
|
||||||
expect(modal.querySelector('.shortcut-list')!.textContent).toContain('<b>Updated search</b>');
|
expect(modal.querySelector('.shortcut-list')!.textContent).toContain('<b>Updated search</b>');
|
||||||
expect(modal.querySelector('.shortcut-list b')).toBeNull();
|
expect(modal.querySelector('.shortcut-list b')).toBeNull();
|
||||||
expect(modal.querySelectorAll('.shortcut-list tr')).toHaveLength(3);
|
expect(modal.querySelectorAll('.shortcut-list tr')).toHaveLength(3);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {registerGlobalInitFunc} from './observer.ts';
|
import {registerGlobalInitFunc} from './observer.ts';
|
||||||
import {createElementFromHTML, hideElem, toggleElem} from '../utils/dom.ts';
|
import {createElementFromHTML, hideElem, toggleElem} from '../utils/dom.ts';
|
||||||
import {showFomanticModal} from './fomantic/modal.ts';
|
import {showModal} from './modal.ts';
|
||||||
import {html, htmlRaw} from '../utils/html.ts';
|
import {html, htmlRaw} from '../utils/html.ts';
|
||||||
|
|
||||||
type ShortcutHandler = (el: HTMLElement) => boolean;
|
type ShortcutHandler = (el: HTMLElement) => boolean;
|
||||||
@@ -69,10 +69,10 @@ function getShortcutTextContent(elem: Element): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showShortcutHelp() {
|
function showShortcutHelp() {
|
||||||
let modal = document.querySelector<HTMLElement>('#global-shortcut-help');
|
let modal = document.querySelector<HTMLDialogElement>('#global-shortcut-help');
|
||||||
if (!modal) {
|
if (!modal) {
|
||||||
modal = createElementFromHTML<HTMLElement>(html`
|
modal = createElementFromHTML<HTMLDialogElement>(html`
|
||||||
<div id="global-shortcut-help" class="ui small modal" role="dialog" aria-modal="true">
|
<dialog id="global-shortcut-help" class="modal-dialog">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
Keyboard Shortcuts
|
Keyboard Shortcuts
|
||||||
<button type="button" class="close-modal"></button>
|
<button type="button" class="close-modal"></button>
|
||||||
@@ -82,9 +82,8 @@ function showShortcutHelp() {
|
|||||||
<tbody class="shortcut-list"></tbody>
|
<tbody class="shortcut-list"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</dialog>
|
||||||
`);
|
`);
|
||||||
document.body.append(modal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const seenShortcuts = new Set<string>();
|
const seenShortcuts = new Set<string>();
|
||||||
@@ -112,7 +111,7 @@ function showShortcutHelp() {
|
|||||||
}
|
}
|
||||||
list.append(createElementFromHTML(html`<tr><td>${htmlRaw(keysHtml)}</td><td>${label}</td></tr>`));
|
list.append(createElementFromHTML(html`<tr><td>${htmlRaw(keysHtml)}</td><td>${label}</td></tr>`));
|
||||||
}
|
}
|
||||||
showFomanticModal(modal);
|
showModal(modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerShortcutHandler(name: string, handler: ShortcutHandler) {
|
export function registerShortcutHandler(name: string, handler: ShortcutHandler) {
|
||||||
@@ -151,7 +150,7 @@ export function initGlobalShortcut() {
|
|||||||
// Don't trigger shortcuts when typing in input fields or contenteditable areas
|
// Don't trigger shortcuts when typing in input fields or contenteditable areas
|
||||||
let shouldSkip = target.matches('input, textarea, select') || target.isContentEditable;
|
let shouldSkip = target.matches('input, textarea, select') || target.isContentEditable;
|
||||||
// Skip shortcuts when a modal or dropdown is open (active), to avoid interfering with their own keyboard handling
|
// Skip shortcuts when a modal or dropdown is open (active), to avoid interfering with their own keyboard handling
|
||||||
shouldSkip = shouldSkip || Boolean(document.querySelector('.ui.modal.active') || document.querySelector('.ui.dropdown.active'));
|
shouldSkip = shouldSkip || Boolean(document.querySelector('.modal-dialog[open], .ui.dropdown.active'));
|
||||||
if (shouldSkip) {
|
if (shouldSkip) {
|
||||||
shortcutPresses.length = 0;
|
shortcutPresses.length = 0;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -44,12 +44,11 @@ type ToastifyElement = HTMLElement & {_giteaToastifyInstance?: Toast};
|
|||||||
|
|
||||||
/** See https://github.com/apvarun/toastify-js#api for options */
|
/** See https://github.com/apvarun/toastify-js#api for options */
|
||||||
function showToast(message: string, level: Intent = 'info', {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast | null {
|
function showToast(message: string, level: Intent = 'info', {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast | null {
|
||||||
const parent = document.querySelector('.ui.dimmer.active') ?? document.body;
|
|
||||||
const duplicateKey = preventDuplicates ? (typeof preventDuplicates === 'string' ? preventDuplicates : `${level}-${message}`) : '';
|
const duplicateKey = preventDuplicates ? (typeof preventDuplicates === 'string' ? preventDuplicates : `${level}-${message}`) : '';
|
||||||
|
|
||||||
// prevent showing duplicate toasts with the same level and message, and give visual feedback for end users
|
// prevent showing duplicate toasts with the same level and message, and give visual feedback for end users
|
||||||
if (preventDuplicates) {
|
if (preventDuplicates) {
|
||||||
const toastEl = parent.querySelector(`:scope > .toastify.on[data-toast-unique-key="${CSS.escape(duplicateKey)}"]`);
|
const toastEl = document.body.querySelector(`:scope > .toastify.on[data-toast-unique-key="${CSS.escape(duplicateKey)}"]`);
|
||||||
if (toastEl) {
|
if (toastEl) {
|
||||||
const toastDupNumEl = toastEl.querySelector('.toast-duplicate-number')!;
|
const toastDupNumEl = toastEl.querySelector('.toast-duplicate-number')!;
|
||||||
showElem(toastDupNumEl);
|
showElem(toastDupNumEl);
|
||||||
@@ -62,7 +61,6 @@ function showToast(message: string, level: Intent = 'info', {gravity, position,
|
|||||||
const {icon, duration: levelDuration} = levels[level];
|
const {icon, duration: levelDuration} = levels[level];
|
||||||
const bodyHtml = useHtmlBody ? message : htmlEscape(message);
|
const bodyHtml = useHtmlBody ? message : htmlEscape(message);
|
||||||
const toast = Toastify({
|
const toast = Toastify({
|
||||||
selector: parent,
|
|
||||||
text: html`
|
text: html`
|
||||||
<div class='toast-icon'>${svgRaw(icon)}</div>
|
<div class='toast-icon'>${svgRaw(icon)}</div>
|
||||||
<div class='toast-body'><span class="toast-duplicate-number tw-hidden">1</span>${htmlRaw(bodyHtml)}</div>
|
<div class='toast-body'><span class="toast-duplicate-number tw-hidden">1</span>${htmlRaw(bodyHtml)}</div>
|
||||||
@@ -104,10 +102,6 @@ function hideToastByElement(el: Element): void {
|
|||||||
(el as ToastifyElement)?._giteaToastifyInstance?.hideToast();
|
(el as ToastifyElement)?._giteaToastifyInstance?.hideToast();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hideToastsFrom(parent: Element): void {
|
|
||||||
queryElems(parent, ':scope > .toastify.on', hideToastByElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideToastsAll(): void {
|
export function hideToastsAll(): void {
|
||||||
queryElems(document, '.toastify.on', hideToastByElement);
|
queryElems(document, '.toastify.on', hideToastByElement);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user