mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +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
@@ -1,8 +1,7 @@
|
||||
import {svg} from '../../svg.ts';
|
||||
import {html, htmlRaw} from '../../utils/html.ts';
|
||||
import {createElementFromHTML} from '../../utils/dom.ts';
|
||||
import {showFomanticModal} from '../../modules/fomantic/modal.ts';
|
||||
import {hideToastsAll} from '../../modules/toast.ts';
|
||||
import {showModal} from '../../modules/modal.ts';
|
||||
|
||||
const {i18n} = window.config;
|
||||
|
||||
@@ -12,27 +11,24 @@ type ConfirmModalOptions = {
|
||||
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>` : '';
|
||||
return createElementFromHTML(html`
|
||||
<div class="ui g-modal-confirm modal">
|
||||
<dialog class="modal-dialog">
|
||||
${htmlRaw(headerHtml)}
|
||||
<div class="content">${content}</div>
|
||||
<div class="actions">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
`.trim());
|
||||
}
|
||||
|
||||
export function confirmModal(modal: HTMLElement | ConfirmModalOptions): Promise<boolean> {
|
||||
if (!(modal instanceof HTMLElement)) 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();
|
||||
export function confirmModal(modal: HTMLDialogElement | ConfirmModalOptions): Promise<boolean> {
|
||||
if (!(modal instanceof HTMLDialogElement)) modal = createConfirmModal(modal);
|
||||
return new Promise((resolve) => {
|
||||
showFomanticModal(modal, {
|
||||
showModal(modal, {
|
||||
onApprove() {
|
||||
resolve(true);
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 {registerGlobalInitFunc} from '../../modules/observer.ts';
|
||||
|
||||
@@ -7,7 +7,7 @@ function nameHasScope(name: string): boolean {
|
||||
return /.*[^/]\/[^/].*/.test(name);
|
||||
}
|
||||
|
||||
function initLabelEditModal(elModal: HTMLElement) {
|
||||
function initLabelEditModal(elModal: HTMLDialogElement) {
|
||||
const elLabelId = elModal.querySelector<HTMLInputElement>('input[name="id"]')!;
|
||||
const elNameInput = elModal.querySelector<HTMLInputElement>('.label-name-input')!;
|
||||
const elExclusiveField = elModal.querySelector('.label-exclusive-input-field')!;
|
||||
@@ -59,7 +59,7 @@ function initLabelEditModal(elModal: HTMLElement) {
|
||||
form.action = isEdit ? `${curPageLink}/edit` : `${curPageLink}/new`;
|
||||
toggleElem(elIsArchivedField, isEdit);
|
||||
syncModalUi();
|
||||
showFomanticModal(elModal, {
|
||||
showModal(elModal, {
|
||||
onApprove() {
|
||||
if (!form.checkValidity()) {
|
||||
form.reportValidity();
|
||||
|
||||
Reference in new issue
Block a user