Discourse 3.1.0.beta6 поставляется с новым API на основе компонента <DModal>.
Это решение заменяет устаревший API на основе контроллеров. Если у вас есть существующие модальные окна, использующие старый API, ознакомьтесь с руководством по миграции здесь.
Отрисовка модального окна
Модальные окна отрисовываются путем включения компонента <DModal> в шаблон Handlebars. Если у вас еще нет подходящего шаблона, ознакомьтесь с материалом по ссылке: Using Plugin Outlet Connectors from a Theme or Plugin.
Простое модальное окно будет выглядеть примерно так:
<DButton
@translatedLabel="Показать модальное окно"
@action={{fn (mut this.modalIsVisible) true}}
/>
{{#if this.modalIsVisible}}
<DModal @title="Мое модальное окно" @closeModal={{fn (mut this.modalIsVisible) false}}>
Привет, мир, это содержимое модального окна
</DModal>
{{/if}}
Здесь помощник
mutиспользуется как способ установки значения, доступный только в hbs. Вы также можете установитьmodalIsVisibleс помощью любого другого стандартного метода Ember.
Этот пример создаст простое модальное окно, похожее на это:
Обертка в компонент
Прежде чем добавлять какую-либо сложность, обычно лучше обернуть новое модальное окно в собственное определение компонента. Переместим содержимое <DModal> внутрь нового компонента <MyModal />.
// components/my-modal.gjs
<template>
<DModal @title="Мое модальное окно" @closeModal={{@closeModal}}>
Привет, мир, это содержимое модального окна
</DModal>
</template>
Обновление этого файла .gjs до компонентного класса позволит вам внедрять более сложную логику и состояние.
Чтобы использовать новый компонент, обновите место вызова, чтобы ссылаться на него, не забудьте передать аргумент @closeModal.
<DButton
@translatedLabel="Показать модальное окно"
@action={{fn (mut this.modalIsVisible) true}}
/>
{{#if this.modalIsVisible}}
<MyModal @closeModal={{fn (mut this.modalIsVisible) false}} />
{{/if}}
Добавление нижнего колонтитула
Во многих модальных окнах есть призыв к действию. В Discourse они обычно расположены в нижней части модального окна. Чтобы это стало возможным, DModal имеет несколько «именованных блоков», в которые можно отрисовывать содержимое. Вот обновленный пример с двумя кнопками в нижнем колонтитуле, одна из которых — наша стандартная кнопка DModalCancel.
<DModal @title="Мое модальное окно" @closeModal={{@closeModal}}>
<:body>
Привет, мир, это содержимое модального окна
</:body>
<:footer>
<DButton class="btn-primary" @translatedLabel="Отправить" />
<DModalCancel @close={{@closeModal}} />
</:footer>
</DModal>
Отрисовка модального окна из контекста, отличного от hbs
В идеале экземпляры <DModal> должны отрисовываться из шаблона Ember с использованием декларативного метода, продемонстрированного выше. Если это невозможно для вашего случая использования, это можно сделать, внедрив сервис modal и вызвав modal.show().
Убедитесь, что вы обернули модальное окно в собственный компонент, как описано выше. Затем запустите модальное окно, передав ссылку на класс вашего компонента в showModal:
import MyModal from "discourse/components/my-modal";
// (внедрите сервис modal в соответствующем месте)
// Добавьте этот вызов всякий раз, когда нужно открыть модальное окно.
// Аргумент `@closeModal` будет автоматически передан вашему компоненту.
this.modal.show(MyModal);
// Опционально передайте параметр `model`. Он будет передан вашему компоненту как `@model`.
// Это может включать данные, а также действия/обратные вызовы для использования вашим модальным окном.
this.modal.show(MyModal, {
model: { topic: this.topic, someAction: this.someAction },
});
// `modal.show()` возвращает промис, поэтому вы можете дождаться его закрытия.
// Он будет разрешен с данными, переданными в действие `@closeModal`.
const result = await this.modal.show(MyModal);
Еще больше возможностей настройки!
<DModal> имеет ряд именованных блоков и аргументов.
Аргументы
| Аргумент | Назначение |
|---|---|
@closeModal |
Обязательно для отображения UI закрытия. |
@title |
Отрисовывает <h1 id="discourse-modal-title">; связывает aria-labelledby. |
@subtitle |
Небольшой текст под заголовком. |
@flash / @flashType |
Встроенное уведомление в верхней части модального окна (DFlashMessage). |
@hideHeader, @hideFooter |
Скрывает целые области. |
@headerClass, @bodyClass |
Дополнительные классы для обертки заголовка/тела. |
@dismissable |
По умолчанию true, если установлен @closeModal. Отключает Esc / клик по фону / крестик. |
@autofocus |
По умолчанию true. Автоматически фокусирует первый доступный для фокусировки элемент через dTrapTab. |
@submitOnEnter |
По умолчанию true. Enter нажимает .d-modal__footer .btn-primary, если фокус не находится в форме / textarea / select-kit. |
@beforeClose |
async ({ initiatedBy }) => boolean. Верните false, чтобы отменить закрытие (например, подтверждение формы с несохраненными изменениями). |
@hidden |
Приостанавливает обработку клавиатуры; используется, когда поверх находится вложенное модальное окно. |
@tagName |
"div" (по умолчанию) или "form". Используйте "form" для форм, чтобы работала нативная отправка. |
Блоки
| Блок | Позиция | Когда использовать |
|---|---|---|
default / :body |
Основная область содержимого | Область по умолчанию |
:aboveHeader |
Самая верхняя часть, до заголовка | Редко требуется; для содержимого, которое должно находиться над панелью заголовка (например, баннер). |
:headerAboveTitle |
Внутри заголовка, до заголовка | Присутствует, но не используется. Редко требуется. |
:belowModalTitle |
Внутри .d-modal__title, после <h1> |
Отличное место для дополнительной мета-информации. |
:headerBelowTitle |
Внутри заголовка, после блока заголовка | Вкладки, подменю или поле поиска, являющиеся частью заголовка. |
:headerPrimaryAction |
Правая сторона заголовка только на мобильных | Заменяет кнопку закрытия X на основное действие (например, «Сохранить»). Также автоматически отрисовывает кнопку «Отмена» слева и добавляет .--has-primary-action к заголовку. |
:belowHeader |
Между заголовком и телом | Постоянный контент подзаголовка (например, поиск), находящийся вне прокручиваемого тела, для закрепленного отображения. |
:aboveFooter |
Между телом и нижним колонтитулом | Скрывается, если установлен @hideFooter. Используйте для содержимого, связанного с нижним колонтитулом, но находящегося вне его. Также редко требуется. |
:footer |
Нижняя панель действий | Основные и второстепенные кнопки. Первая .btn-primary здесь активируется нажатием Enter. |
:belowFooter |
После нижнего колонтитула | Редко требуется; игнорирует @hideFooter. Полезно для текста статуса вне области нижнего колонтитула с рамкой. |
Источники: интерактивный гайдлайн для аргументов и реализация шаблона d-modal для именованных блоков.
CSS
Используйте классы .d-modal как якорь для переопределения базовых стилей и избегайте устаревшего селектора .modal.
Доступно 4 модификатора:
.--largeустанавливает максимальную ширину в 800px (только для десктопов).--maxустанавливает максимальную ширину в 90vw (только для десктопов).has-searchустанавливает фиксированную высоту (80vh): предназначено для модальных окон с системой поиска/фильтрации, чтобы избежать изменения высоты в зависимости от длины результатов (только для десктопов).--stackedустанавливает кнопки нижнего колонтитула в вертикальное расположение (только для мобильных устройств)
Этот документ находится под контролем версий — предложите изменения на GitHub.

