001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005//     http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.corelib.components;
014
015import org.apache.tapestry5.BindingConstants;
016import org.apache.tapestry5.Link;
017import org.apache.tapestry5.MarkupWriter;
018import org.apache.tapestry5.alerts.Alert;
019import org.apache.tapestry5.alerts.AlertStorage;
020import org.apache.tapestry5.annotations.*;
021import org.apache.tapestry5.corelib.base.BaseClientElement;
022import org.apache.tapestry5.ioc.annotations.Inject;
023import org.apache.tapestry5.json.JSONObject;
024import org.apache.tapestry5.services.Request;
025import org.apache.tapestry5.services.compatibility.DeprecationWarning;
026
027/**
028 * Renders out an empty {@code <div>} element and provides JavaScript initialization to make the element
029 * the container for alerts. After rendering markup (and initialization JavaScript), it
030 * {@linkplain org.apache.tapestry5.alerts.AlertStorage#dismissNonPersistent() removes all non-persistent alerts}.
031 *
032 * Alerts are created using the {@link org.apache.tapestry5.alerts.AlertManager} service.
033 *
034 * @tapestrydoc
035 * @since 5.3
036 */
037@SupportsInformalParameters
038public class Alerts extends BaseClientElement
039{
040
041    /**
042     * Allows the button used to dismiss all alerts to be customized (and localized).
043     *
044     * @deprecated Deprecated in Tapestry 5.4; override the {@code core-dismiss-label} message key in
045     * your application's message catalog. This parameter is now ignored.
046     */
047    @Parameter(value = "message:core-dismiss-label", defaultPrefix = BindingConstants.LITERAL)
048    private String dismissText;
049
050    /**
051     * If set to true, then the "dismiss all" button will not be rendered on the client.
052     *
053     * @since 5.4
054     */
055    @Parameter(value = "message:private-core-alerts-show-dismiss-all", defaultPrefix = BindingConstants.LITERAL)
056    private boolean showDismissAll;
057
058    @SessionState(create = false)
059    private AlertStorage storage;
060
061    @Inject
062    private DeprecationWarning deprecationWarning;
063
064    @Inject
065    private Request request;
066
067    void onPageLoaded()
068    {
069        deprecationWarning.ignoredComponentParameters(resources, "dismissText");
070    }
071
072    boolean beginRender(MarkupWriter writer)
073    {
074        Link dismissLink = resources.createEventLink("dismiss");
075
076        storeElement(writer.element("div",
077                "data-container-type", "alerts",
078                "data-show-dismiss-all", showDismissAll,
079                "data-dismiss-url", dismissLink));
080
081        resources.renderInformalParameters(writer);
082        writer.end();
083
084        addAlertsFromStorage();
085
086        return false;
087    }
088
089    Object onDismiss(@RequestParameter(value = "id", allowBlank = true) Long alertId)
090    {
091        // If the alert was created inside an Ajax request and AlertStorage did not previously
092        // exist, it can be null when the dismiss event comes up from the client.
093        if (storage != null)
094        {
095            if (alertId != null)
096            {
097                storage.dismiss(alertId);
098            } else
099            {
100                storage.dismissAll();
101            }
102        }
103
104        // See TAP5-1941
105        if (!request.isXHR())
106        {
107            return true;
108        }
109
110        return new JSONObject();
111    }
112
113    @HeartbeatDeferred
114    void addAlertsFromStorage()
115    {
116        if (storage == null)
117        {
118            return;
119        }
120
121        for (Alert alert : storage.getAlerts())
122        {
123            javaScriptSupport.require("t5/core/alert").with(alert.toJSON());
124        }
125
126        storage.dismissNonPersistent();
127    }
128}