Диалоговые окна
Интерфейс Dialogs
предназначен для отображения стандартных диалоговых окон. Диалоги – это небольшие окна, используемые для отображения информации и элементов UI поверх остального интерфейса.
Его методы createMessageDialog()
, createOptionDialog()
и createInputDialog()
являются точками входа в fluent API, позволяющий конструировать и отображать диалоги.
Внешний вид диалоговых окон можно настроить с помощью переменных SCSS с префиксом $jmix-window-modal-*
. Эти переменные можно изменить в визуальном редакторе после создания новой темы.
Диалог сообщения
Самый простой вариант использования диалогового окна – это показ пользователю некоторого сообщения.
В примере ниже диалог отображает сообщение при нажатии кнопки:
@Autowired
private Dialogs dialogs;
@Subscribe("msgDialogBtn")
public void onMsgDialogBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("Success")
.withMessage("Your invitation successfully send")
.show();
}
Используйте метод withMessage()
, чтобы передать текст сообщения.
Используя метод withContentMode()
, можно определить, как должен отображаться текст сообщения. Существует три предопределенных режима:
-
ContentMode.TEXT
- текстовые значения отображаются в виде обычного текста. -
ContentMode.PREFORMATTED
- текстовые значения отображаются в виде предварительно отформатированного текста. В этом режиме новые строки сохраняются при отображении на экран. -
ContentMode.HTML
- текстовые значения интерпретируются и отображаются как HTML. При использовании HTML обязательно экранируйте данные во избежание инжекции вредоносного кода.
В тексте можно использовать символы \n
для перевода строк. Для отображения HTML необходимо передать параметр ContentMode.HTML
в метод withContentMode()
.
Вы можете передать значение true
в метод withHtmlSanitizer()
, чтобы включить HTML санитизацию для содержимого диалога. Также в этом случае параметр ContentMode.HTML
должен быть передан в метод withContentMode().
protected static final String UNSAFE_HTML = "<i>Jackdaws </i><u>love</u> " +
"<font size=\"javascript:alert(1)\" " +
"color=\"moccasin\">my</font> " +
"<font size=\"7\">big</font> <sup>sphinx</sup> " +
"<font face=\"Verdana\">of</font> <span style=\"background-color: " +
"red;\">quartz</span><svg/onload=alert(\"XSS\")>";
@Autowired
private Dialogs dialogs;
@Subscribe("msgDialogOnBtn")
public void onMsgDialogOnBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("MessageDialog with Sanitizer")
.withMessage(UNSAFE_HTML)
.withContentMode(ContentMode.HTML)
.withHtmlSanitizer(true)
.show();
}
@Subscribe("msgDialogOffBtn")
public void onMsgDialogOffBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("MessageDialog without Sanitizer")
.withMessage(UNSAFE_HTML)
.withContentMode(ContentMode.HTML)
.withHtmlSanitizer(false)
.show();
}
Значение, переданное в метод withHtmlSanitizer()
, имеет приоритет над значением глобального свойства jmix.ui.component.html-sanitizer-enabled.
Следующие методы позволяют изменить параметры отображения и поведения диалога:
-
withModal()
- если переданоfalse
, диалог отображается как немодальный, что позволяет пользователю взаимодействовать с другими частями приложения. Диалоги являются модальными по умолчанию.
-
withCloseOnClickOutside()
- если переданоtrue
и диалог модальный, то пользователь может закрыть диалог, щелкнув на любой части окна приложения вне диалога.
-
withWindowMode()
- задает режим диалогового окна. Есть два предопределенных режима:-
WindowMode.NORMAL
- размер и положение окна определяются его состоянием. -
WindowMode.MAXIMIZED
- окно расположено в верхнем левом углу и заполняет весь экран.
-
-
Используя метод
withStyleName()
, для диалогового окна можно задать пользовательское имя CSS стиля. Подробнее см. в разделе Создание новых стилей.
-
withWidth()
,withHeight()
позволяют указать желаемую геометрию диалога.
Например:
@Autowired
private Dialogs dialogs;
@Subscribe("showDialogBtn")
public void onShowDialogBtnClick(Button.ClickEvent event) {
dialogs.createMessageDialog()
.withCaption("Information")
.withMessage("<i>Message<i/>")
.withContentMode(ContentMode.HTML)
.withCloseOnClickOutside(true)
.withWidth("100px")
.withHeight("300px")
.show();
}
Диалог выбора
Диалог выбора отображает некоторое сообщение и набор кнопок для выбора пользователем.
Передайте в метод withActions()
массив действий, для каждого из которых в диалоге создается кнопка. Например:
@Autowired
private Dialogs dialogs;
@Subscribe("optDialogBtn")
public void onOptDialogBtnClick(Button.ClickEvent event) {
dialogs.createOptionDialog()
.withCaption("Please confirm")
.withMessage("Do you really want to add a customer?")
.withActions(
new DialogAction(DialogAction.Type.YES, Action.Status.PRIMARY)
.withHandler(e -> doSomething()),
new DialogAction(DialogAction.Type.NO)
)
.show();
}
При нажатии на кнопку диалог закрывается и вызывается метод actionPerform()
соответствующего действия.
В качестве кнопок со стандартными названиями и значками удобно использовать классы, унаследованные от DialogAction
. Поддерживаются пять видов действий, определяемых перечислением DialogAction.Type
: OK
, CANCEL
, YES
, NO
, CLOSE
. Названия соответствующих кнопок извлекаются из главного пакета локализованных сообщений.
Второй параметр конструктора DialogAction
используется для задания визуального стиля кнопки, к которой привязано данное действие. Статус Status.PRIMARY
подсвечивает кнопку и задает ей выделение по умолчанию, что обеспечивается стилем jmix-primary-action
. Если для диалога задано несколько действий с Status.PRIMARY
, то фокус и стиль получает только кнопка первого такого действия в списке.
Диалог ввода
Диалог ввода – это мощный инструмент для конструирования форм ввода с помощью API, который часто может избавить от необходимости создавать экраны для тривиального ввода данных. Он позволяет вводить значения разнообразных типов, валидировать их и предоставлять различные действия для выбора пользователем.
Рассмотрим несколько примеров.
Стандартные параметры
В примере ниже представлен диалог ввода с параметрами стандартных типов и стандартными действиями OK
/Cancel
:
@Autowired
private Dialogs dialogs;
@Subscribe("inputDialogBtn")
public void onInputDialogBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Get values")
.withParameters(
InputParameter.dateTimeParameter("deliveryTime")
.withCaption("Delivery Time")
.withRequired(true),(1)
InputParameter.doubleParameter("amount")
.withCaption("Amount")
.withDefaultValue(1.0),(2)
InputParameter.entityParameter("customer", Customer.class)
.withCaption("Customer"),(3)
InputParameter.enumParameter("status", Status.class)
.withCaption("Status")(4)
)
.withActions(DialogActions.OK_CANCEL)(5)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {(6)
String name = closeEvent.getValue("name");(7)
Double quantity = closeEvent.getValue("quantity");
Customer customer = closeEvent.getValue("customer");
Status status = closeEvent.getValue("status");
// process entered values...
}
})
.show();
}
1 | Задает строковый обязательный параметр. |
2 | Задает числовой параметр со значением по умолчанию. |
3 | Задает параметр типа сущность. |
4 | Задает параметр типа перечисление. |
5 | Задает набор действий, представляемых кнопками внизу диалога. |
6 | В слушателе на закрытие можно определить, какое действие было выбрано пользователем. |
7 | Событие закрытия содержит введенные значения, которые можно получить по идентификаторам параметров. |
Нестандартные параметры
@Autowired
private Dialogs dialogs;
@Autowired
private UiComponents uiComponents;
@Subscribe("inpDlgParamsBtn")
public void onInpDlgParamsBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name"),
InputParameter.parameter("customer")(1)
.withField(() -> {
EntityComboBox<Customer> field = uiComponents.create(
EntityComboBox.of(Customer.class));
field.setOptionsList(dataManager.load(Customer.class).all().list());
field.setCaption("Customer");(2)
field.setWidthFull();
return field;
})
)
.withActions(DialogActions.OK_CANCEL)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {
String name = closeEvent.getValue("name");
Customer customer = closeEvent.getValue("customer");(3)
// process entered values...
}
})
.show();
}
1 | Задает нестандартный параметр. |
2 | В создаваемом компоненте задается заголовок нестандартного параметра. |
3 | Значение нестандартного параметра получается таким же способом, как и стандартного. |
Нестандартные действия
@Autowired
private Dialogs dialogs;
@Subscribe("inpDlgActionsBtn")
public void onInpDlgActionsBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name")
)
.withActions((1)
InputDialogAction.action("confirm")
.withCaption("Confirm")
.withPrimary(true)
.withHandler(actionEvent -> {
InputDialog dialog = actionEvent.getInputDialog();
String name = dialog.getValue("name");(2)
dialog.closeWithDefaultAction();(3)
// process entered values...
}),
InputDialogAction.action("refuse")
.withCaption("Refuse")
.withValidationRequired(false)
.withHandler(actionEvent ->
actionEvent.getInputDialog().closeWithDefaultAction())
)
.show();
}
1 | Метод withActions() может принимать массив нестандартных действий. |
2 | В обработчике действия можно получить значение параметра из объекта диалога. |
3 | Нестандартное действие не закрывает диалог само, поэтому в какой-то момент это надо сделать явно. |
Нестандартный валидатор
@Autowired
private Dialogs dialogs;
@Subscribe("inpDlgValidBtn")
public void onInpDlgValidBtnClick(Button.ClickEvent event) {
dialogs.createInputDialog(this)
.withCaption("Enter some values")
.withParameters(
InputParameter.stringParameter("name").withCaption("Name"),
InputParameter.entityParameter("customer", Customer.class).withCaption("Customer")
)
.withValidator(context -> {(1)
String name = context.getValue("name");(2)
Customer customer = context.getValue("customer");
if (Strings.isNullOrEmpty(name) && customer == null) {
return ValidationErrors.of("Enter name or select a customer");
}
return ValidationErrors.none();
})
.withActions(DialogActions.OK_CANCEL)
.withCloseListener(closeEvent -> {
if (closeEvent.closedWith(DialogOutcome.OK)) {
String name = closeEvent.getValue("name");
Customer customer = closeEvent.getValue("customer");
// process entered values...
}
})
.show();
}
1 | Нестандартный валидатор в данном примере необходим для того, чтобы обеспечить ввод как минимум одного параметра. |
2 | Значения параметров в валидаторе можно получить через объект контекста. |
Диалог исключения
Это специальный диалог для отображения исключений, содержащий сворачиваемую область с полным стектрейсом исключения.
Это диалоговое окно используется в обработчике по умолчанию, но вы можете использовать его и для своих исключений, например:
@Autowired
private Dialogs dialogs;
@Subscribe("expDlgBtn")
public void onExpDlgBtnClick(Button.ClickEvent event) {
try {
int d = 0;
int a = 42 / d;
}
catch (ArithmeticException e) {
dialogs.createExceptionDialog()
.withCaption("Alert")
.withMessage("Division by zero")
.withThrowable(e.fillInStackTrace())
.show();
}
}