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 * <p/>
032 * Alerts are created using the {@link org.apache.tapestry5.alerts.AlertManager} service.
033 *
034 * @tapestrydoc
035 * @since 5.3
036 */
037@SupportsInformalParameters
038@Import(stack = "core")
039public class Alerts extends BaseClientElement
040{
041
042    /**
043     * Allows the button used to dismiss all alerts to be customized (and localized).
044     *
045     * @deprecated Deprecated in Tapestry 5.4; override the {@code core-dismiss-label} message key in
046     * your application's message catalog. This parameter is now ignored.
047     */
048    @Parameter(value = "message:core-dismiss-label", defaultPrefix = BindingConstants.LITERAL)
049    private String dismissText;
050
051    /**
052     * If set to true, then the "dismiss all" button will not be rendered on the client.
053     *
054     * @since 5.4
055     */
056    @Parameter(value = "message:private-core-alerts-show-dismiss-all", defaultPrefix = BindingConstants.LITERAL)
057    private boolean showDismissAll;
058
059    @SessionState(create = false)
060    private AlertStorage storage;
061
062    @Inject
063    private DeprecationWarning deprecationWarning;
064
065    @Inject
066    private Request request;
067
068    void onPageLoaded()
069    {
070        deprecationWarning.ignoredComponentParameters(resources, "dismissText");
071    }
072
073    boolean beginRender(MarkupWriter writer)
074    {
075        Link dismissLink = resources.createEventLink("dismiss");
076
077        storeElement(writer.element("div",
078                "data-container-type", "alerts",
079                "data-show-dismiss-all", showDismissAll,
080                "data-dismiss-url", dismissLink));
081
082        resources.renderInformalParameters(writer);
083        writer.end();
084
085        addAlertsFromStorage();
086
087        return false;
088    }
089
090    Object onDismiss(@RequestParameter(value = "id", allowBlank = true) Long alertId)
091    {
092        // If the alert was created inside an Ajax request and AlertStorage did not previously
093        // exist, it can be null when the dismiss event comes up from the client.
094        if (storage != null)
095        {
096            if (alertId != null)
097            {
098                storage.dismiss(alertId);
099            } else
100            {
101                storage.dismissAll();
102            }
103        }
104
105        // See TAP5-1941
106        if (!request.isXHR())
107        {
108            return true;
109        }
110
111        return new JSONObject();
112    }
113
114    @HeartbeatDeferred
115    void addAlertsFromStorage()
116    {
117        if (storage == null)
118        {
119            return;
120        }
121
122        for (Alert alert : storage.getAlerts())
123        {
124            javaScriptSupport.require("t5/core/alert").with(alert.toJSON());
125        }
126
127        storage.dismissNonPersistent();
128    }
129}