3.5.6. Диалоговые окна
Интерфейс Dialogs предназначен для отображения стандартных диалоговых окон. Его методы createMessageDialog(), createOptionDialog() и createInputDialog() являются точками входа в fluent API, позволяющий конструировать и отображать диалоги.
Внешний вид диалоговых окон можно настроить с помощью переменных SCSS с префиксом $cuba-window-modal-*. Эти переменные можно изменить в визуальном редакторе после расширения темы или создания новой темы.
- Message Dialog
-
В примере ниже диалог отображает сообщение при нажатии кнопки:
@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") protected void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createMessageDialog().withCaption("Information").withMessage("Message").show(); }С помощью метода
withMessage()можно передавать текст сообщения.В тексте можно использовать символы
\nдля перевода строк. Для отображения HTML необходимо передатьContentMode.HTMLв методwithContentMode(). При использовании HTML обязательно экранируйте данные, полученные из БД, во избежание инжекции вредоносного кода.Вы можете передать значение
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\")>"; @Inject private Dialogs dialogs; @Subscribe("showMessageDialogOnBtn") public void onShowMessageDialogOnBtnClick(Button.ClickEvent event) { dialogs.createMessageDialog() .withCaption("MessageDialog with Sanitizer") .withMessage(UNSAFE_HTML) .withContentMode(ContentMode.HTML) .withHtmlSanitizer(true) .show(); } @Subscribe("showMessageDialogOffBtn") public void onShowMessageDialogOffBtnClick(Button.ClickEvent event) { dialogs.createMessageDialog() .withCaption("MessageDialog without Sanitizer") .withMessage(UNSAFE_HTML) .withContentMode(ContentMode.HTML) .withHtmlSanitizer(false) .show(); }Значение, переданное в метод
withHtmlSanitizer(), имеет приоритет над значением глобального свойства cuba.web.htmlSanitizerEnabled.Следующие методы позволяют изменить параметры отображения и поведения диалога:
-
withModal()– если переданоfalse, диалог отображается как немодальный, что позволяет пользователю взаимодействовать с другими частями приложения.
-
withCloseOnClickOutside()– если переданоtrueи диалог модальный, то пользователь может закрыть диалог, щелкнув на любой части окна приложения вне диалога.
-
withMaximized()– если переданоtrue, диалог будет развёрнут во весь экран.
-
withWidth(),withHeight()позволяют указать желаемую геометрию диалога.
Например:
@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") protected void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createMessageDialog() .withCaption("Information") .withMessage("<i>Message<i/>") .withContentMode(ContentMode.HTML) .withCloseOnClickOutside(true) .withWidth("100px") .withHeight("300px") .show(); } -
- Option Dialog
-
Диалог выбора отображает некоторое сообщение и набор кнопок для выбора пользователем. При конструировании данного диалога необходимо передать в метод
withActions()массив действий, для каждого из которых в диалоге создается кнопка. Например:@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") protected void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createOptionDialog() .withCaption("Confirm") .withMessage("Are you sure?") .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подсвечивает кнопку и задаёт ей выделение по умолчанию, что обеспечивается стилемc-primary-action. Если для диалога задано несколько действий сStatus.PRIMARY, то фокус и стиль получает только кнопка первого такого действия в списке.
- Input Dialog
-
Диалог ввода - это мощный инструмент, позволяющий конструировать формы ввода с помощью API, который часто может избавить от необходимости создавать экраны для тривиального ввода данных. Он позволяет вводить значения разнообразных типов, валидировать их и предоставлять различные действия для выбора пользователем.
Рассмотрим несколько примеров.
-
Диалог ввода с параметрами стандартных типов и стандартными действиями OK/Cancel:
@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") private void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createInputDialog(this) .withCaption("Enter some values") .withParameters( InputParameter.stringParameter("name") .withCaption("Name").withRequired(true), (1) InputParameter.doubleParameter("quantity") .withCaption("Quantity").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"); Optional<Customer> customer = closeEvent.getOptional("customer"); (8) Status status = closeEvent.getValue("status"); // process entered values... } }) .show(); }1 - задает строковый обязательный параметр. 2 - задает числовой параметр со значением по умолчанию. 3 - задает параметр типа сущность. 4 - задает параметр типа перечисление. 5 - задает набор действий, представляемых кнопками внизу диалога. 6 - в слушателе на закрытие можно определить, какое действие было выбрано пользователем. 7 - событие закрытия содержит введенные значения, которые можно получить по идентификаторам параметров. 8 - можно получить значение, завернутое в Optional. -
Диалог ввода с нестандартным параметром:
@Inject private Dialogs dialogs; @Inject private UiComponents uiComponents; @Subscribe("showDialogBtn") private void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createInputDialog(this) .withCaption("Enter some values") .withParameters( InputParameter.stringParameter("name").withCaption("Name"), InputParameter.parameter("customer") (1) .withField(() -> { LookupField<Customer> field = uiComponents.create( LookupField.of(Customer.class)); field.setOptionsList(dataManager.load(Customer.class).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 - значение нестандартного параметра получается таким же способом, как и стандартного. -
Диалог ввода с нестандартными действиями:
@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") private void onShowDialogBtnClick(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 - кастомное действие не закрывает диалог само, поэтому это надо сделать в какой-то момент явно. -
Диалог ввода с валидатором:
@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") private void onShowDialogBtnClick(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 - значения параметров в валидаторе можно получить через объект контекста. -
Диалог ввода с параметром типа
FileDescriptor:@Inject private Dialogs dialogs; @Subscribe("showDialogBtn") public void onShowDialogBtnClick(Button.ClickEvent event) { dialogs.createInputDialog(this) .withCaption("Select the file") .withParameters( InputParameter.fileParameter("fileField") (1) .withCaption("File")) .withCloseListener(closeEvent -> { if (closeEvent.closedWith(DialogOutcome.OK)) { FileDescriptor fileDescriptor = closeEvent.getValue("fileField"); (2) } }) .show(); }1 - задает параметр типа FileDescriptor.2 - событие закрытия содержит введенное значение, которое можно получить по идентификатору параметра.
-