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.mixins;
014
015import org.apache.tapestry5.*;
016import org.apache.tapestry5.annotations.AfterRender;
017import org.apache.tapestry5.annotations.Events;
018import org.apache.tapestry5.annotations.InjectContainer;
019import org.apache.tapestry5.annotations.Parameter;
020import org.apache.tapestry5.corelib.components.Zone;
021import org.apache.tapestry5.http.Link;
022import org.apache.tapestry5.internal.util.CaptureResultCallback;
023import org.apache.tapestry5.ioc.annotations.Inject;
024import org.apache.tapestry5.services.javascript.JavaScriptSupport;
025
026/**
027 *
028 * This mixin periodically refreshs a {@link org.apache.tapestry5.corelib.components.Zone zone}
029 * by triggering an event on the server using ajax requests.
030 *
031 *
032 * Server-side, the mixin triggers the "refresh" event with the mixin's context. A container may but
033 * does not need to handle the event. If the event is handled and a value is returned, that value is
034 * used to render the response. Otherwise, the Zone's body is re-rendered.
035 *
036 * <b>Note: </b> This mixin is only meant for a {@link org.apache.tapestry5.corelib.components.Zone zone}.
037 *
038 * @tapestrydoc
039 */
040@Events(EventConstants.REFRESH)
041public class ZoneRefresh
042{
043    /**
044     * Period between two consecutive refreshes (in seconds). If a new refresh occurs before the
045     * previous refresh has completed, it will be skipped.
046     */
047    @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
048    private int period;
049
050    /**
051     * Context passed to the event
052     */
053    @Parameter
054    private Object[] context;
055
056    @InjectContainer
057    private Zone zone;
058
059    @Inject
060    private JavaScriptSupport javaScriptSupport;
061
062    @Inject
063    private ComponentResources resources;
064
065    //For testing purpose
066    ZoneRefresh(Object[] context, ComponentResources resources, JavaScriptSupport javaScriptSupport, Zone zone)
067    {
068        this.context = context;
069        this.resources = resources;
070        this.javaScriptSupport = javaScriptSupport;
071        this.zone = zone;
072    }
073
074    @AfterRender
075    void addJavaScript()
076    {
077        Link link = resources.createEventLink("zoneRefresh", context);
078
079        javaScriptSupport.require("t5/core/zone-refresh").with(zone.getClientId(), period, link.toString());
080    }
081
082    Object onZoneRefresh(EventContext eventContext)
083    {
084        CaptureResultCallback<Object> callback = new CaptureResultCallback<Object>();
085        resources.triggerContextEvent(EventConstants.REFRESH, eventContext, callback);
086
087        if (callback.getResult() != null)
088        {
089            return callback.getResult();
090        }
091
092        return zone.getBody();
093    }
094
095}