All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.flow.component.notification.Notification Maven / Gradle / Ivy

There is a newer version: 24.6.0
Show newest version
/*
 * Copyright 2000-2017 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.vaadin.flow.component.notification;

import java.util.Locale;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.Stream.Builder;

import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.ComponentUtil;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.dependency.HtmlImport;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.internal.HtmlUtils;
import com.vaadin.flow.shared.Registration;

/**
 * Server-side component for the vaadin-notification element.
 *
 * @author Vaadin Ltd
 */
@HtmlImport("frontend://flow-component-renderer.html")
public class Notification extends GeneratedVaadinNotification
        implements HasComponents {

    private static final int DEFAULT_DURATION = 5000;
    private static final Position DEFAULT_POSITION = Position.BOTTOM_START;

    private final Element container = new Element("div", false);
    private final Element templateElement = new Element("template", false);
    private boolean autoAddedToTheUi = false;

    /**
     * Enumeration of all available positions for notification component
     */
    public enum Position {
        TOP_STRETCH, TOP_START, TOP_CENTER, TOP_END, MIDDLE, BOTTOM_START, BOTTOM_CENTER, BOTTOM_END, BOTTOM_STRETCH,;

        private final String clientName;

        Position() {
            this.clientName = name().toLowerCase(Locale.ENGLISH).replace('_',
                    '-');
        }

        /**
         * Gets name that is used in the client side representation of the
         * component.
         *
         * @return the name used in the client side representation of the
         *         component.
         */
        public String getClientName() {
            return clientName;
        }

        /**
         * Creates {@link Position} from the client side representation property
         * name
         *
         * @param clientName
         *            the client side representation of the property
         * @return corresponding {@link Position}
         */
        static Position fromClientName(String clientName) {
            return clientName == null ? null
                    : Position.valueOf(clientName.replace('-', '_')
                            .toUpperCase(Locale.ENGLISH));
        }
    }

    /**
     * Default constructor. Create an empty notification with component support
     * and non-auto-closing
     * 

* Note: To mix text and child components in notification that also supports * child components, use the {@link Text} component for the textual parts. */ public Notification() { initBaseElementsAndListeners(); getElement().getNode() .runWhenAttached(ui -> ui.beforeClientResponse(this, context -> attachComponentTemplate(ui))); setPosition(DEFAULT_POSITION); setDuration(0); } /** * Creates a Notification with the given String rendered as its HTML text, * that does not close automatically. * * @param text * the text of the Notification */ public Notification(String text) { this(text, 0, DEFAULT_POSITION); } /** * Creates a Notification with given String rendered as its HTML text and * given Integer rendered as its duration. *

* Set to {@code 0} or a negative number to disable the notification * auto-closing. * * @param text * the text of the Notification * @param duration * the duration in milliseconds to show the notification */ public Notification(String text, int duration) { this(text, duration, DEFAULT_POSITION); } /** * Creates a Notification with given text String, duration and position *

* Set to {@code 0} or a negative number to disable the notification * auto-closing. * * @param text * the text of the notification * @param duration * the duration in milliseconds to show the notification * @param position * the position of the notification. Valid enumerate values are * TOP_STRETCH, TOP_START, TOP_CENTER, TOP_END, MIDDLE, * BOTTOM_START, BOTTOM_CENTER, BOTTOM_END, BOTTOM_STRETCH */ public Notification(String text, int duration, Position position) { initBaseElementsAndListeners(); setText(text); setDuration((double) duration); setPosition(position); } /** * Creates a notification with given components inside. *

* Note: To mix text and child components in a component that also supports * child components, use the {@link Text} component for the textual parts. * * @param components * the components inside the notification * @see #add(Component...) */ public Notification(Component... components) { this(); add(components); } private void initBaseElementsAndListeners() { getElement().appendChild(templateElement); getElement().appendVirtualChild(container); getElement().addEventListener("opened-changed", event -> { if (autoAddedToTheUi && !isOpened()) { getElement().removeFromParent(); autoAddedToTheUi = false; } }); } /** * Shows a notification in the current page with given text, duration and * position. * * @param text * the text of the Notification * @param duration * the duration in milliseconds to show the notification * @param position * the position of the notification. Valid enumerate values are * TOP_STRETCH, TOP_START, TOP_CENTER, TOP_END, MIDDLE, * BOTTOM_START, BOTTOM_CENTER, BOTTOM_END, BOTTOM_STRETCH * @return the notification */ public static Notification show(String text, int duration, Position position) { Notification notification = new Notification(text, duration, position); notification.open(); return notification; } /** * Shows a notification in the current page with given text. *

* This is the convenience method for {@link #show(String, int, Position)} * which uses default web-component values for duration (which is 5000 ms) * and position ({@literal Position.BOTTOM_START}). * * * @param text * the text of the Notification * @return the notification */ public static Notification show(String text) { return show(text, DEFAULT_DURATION, DEFAULT_POSITION); } /** * Set the text of the notification with given String *

* NOTE: When mixing this method with {@link #Notification()} and * {@link #Notification(Component...)}. Method will remove all the * components from the notification. * * @param text * the text of the Notification */ public void setText(String text) { removeAll(); getElement().getNode().runWhenAttached( ui -> ui.beforeClientResponse(this, context -> templateElement .setProperty("innerHTML", HtmlUtils.escape(text)))); } /** * Set position of the notification. *

* * @param position * the position of the notification. Valid enumerate values are * {@code TOP_STRETCH, TOP_START, TOP_CENTER, TOP_END, MIDDLE, BOTTOM_START, BOTTOM_CENTER, BOTTOM_END, BOTTOM_STRETCH}, * not {@code null} */ public void setPosition(Position position) { setPosition(position.getClientName()); } /** *

* Description copied from corresponding location in WebComponent: *

*

* Alignment of the notification in the viewport Valid values are * {@code top-stretch|top-start|top-center|top-end|middle|bottom-start|bottom-center|bottom-end|bottom-stretch} *

* This property is not synchronized automatically from the client side, so * the returned value may not be the same as in client side. *

*

* The default position value is {@literal Position.BOTTOM_START}. * * @return the {@link Position} property from the webcomponent */ public Position getPosition() { String position = getPositionString(); return Optional.ofNullable(position).map(Position::fromClientName) .orElse(DEFAULT_POSITION); } /** * Opens the notification. */ @Override public void open() { setOpened(true); } /** * Closes the notification. *

* Note: This method also removes the notification component from the DOM * after closing it, unless you have added the component manually. */ @Override public void close() { setOpened(false); } /** * Adds the given components into this notification. *

* The elements in the DOM will not be children of the * {@code } element, but will be inserted into an * overlay that is attached into the {@code }. *

* NOTE: When mixing this method with {@link #Notification(String)}, * {@link #Notification(String, int)} and * {@link #Notification(String, int, Position)} method will remove the text * content. * * @param components * the components to add */ @Override public void add(Component... components) { assert components != null; for (Component component : components) { assert component != null; container.appendChild(component.getElement()); } getElement().getNode() .runWhenAttached(ui -> ui.beforeClientResponse(this, context -> attachComponentTemplate(ui))); } /** * Remove the given components from this notification. * * @param components * the components to remove */ @Override public void remove(Component... components) { for (Component component : components) { assert component != null; if (container.equals(component.getElement().getParent())) { container.removeChild(component.getElement()); } else { throw new IllegalArgumentException("The given component (" + component + ") is not a child of this component"); } } } /** * Remove all the components from this notification. */ @Override public void removeAll() { container.removeAllChildren(); } @Override public Stream getChildren() { Builder childComponents = Stream.builder(); container.getChildren().forEach(childElement -> ComponentUtil .findComponents(childElement, childComponents::add)); return childComponents.build(); } private void attachComponentTemplate(UI ui) { String appId = ui.getInternals().getAppId(); int nodeId = container.getNode().getId(); String template = String.format( "", appId, nodeId); templateElement.setProperty("innerHTML", template); } /** * Opens or closes the notification. *

* Note: You don't need to add the component anywhere before opening it. * Since {@code }'s location in the DOM doesn't really * matter, opening a notification will automatically add it to the * {@code } if it's not yet attached anywhere. * * @param opened * {@code true} to open the notification, {@code false} to close * it */ @Override public void setOpened(boolean opened) { UI ui = UI.getCurrent(); if (ui == null) { throw new IllegalStateException("UI instance is not available. " + "It means that you are calling this method " + "out of a normal workflow where it's always implicitely set. " + "That may happen if you call the method from the custom thread without " + "'UI::access' or from tests without proper initialization."); } if (opened && getElement().getNode().getParent() == null) { ui.beforeClientResponse(ui, context -> { ui.add(this); autoAddedToTheUi = true; }); } super.setOpened(opened); } /** *

* Description copied from corresponding location in WebComponent: *

*

* True if the notification is currently displayed. *

* This property is synchronized automatically from client side when a * 'opened-changed' event happens. *

* * @return the {@code opened} property from the webcomponent */ public boolean isOpened() { return isOpenedBoolean(); } @Override public Registration addOpenedChangeListener( ComponentEventListener> listener) { return super.addOpenedChangeListener(listener); } /** *

* Description copied from corresponding location in WebComponent: *

*

* The duration in milliseconds to show the notification. Set to {@code 0} * or a negative number to disable the notification auto-closing. *

* * @param duration * the value to set */ public void setDuration(int duration) { setDuration((double) duration); } /** *

* Description copied from corresponding location in WebComponent: *

*

* The duration in milliseconds to show the notification. Set to {@code 0} * or a negative number to disable the notification auto-closing. *

* This property is not synchronized automatically from the client side, so * the returned value may not be the same as in client side. *

* * @return the {@code duration} property from the webcomponent */ public int getDuration() { return (int) getDurationDouble(); } /** * {@inheritDoc} *

* Note: To listen for opening the notification, you should use * {@link #addOpenedChangeListener(ComponentEventListener)}. */ @Override public Registration addAttachListener( ComponentEventListener listener) { return super.addAttachListener(listener); } /** * {@inheritDoc} *

* Note: To listen for closing the notification, you should use * {@link #addOpenedChangeListener(ComponentEventListener)}, as the * component is not necessarily removed from the DOM when closing. */ @Override public Registration addDetachListener( ComponentEventListener listener) { return super.addDetachListener(listener); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy