001// Copyright 2008, 2010, 2011, 2012 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.corelib.mixins;
016
017import org.apache.tapestry5.BindingConstants;
018import org.apache.tapestry5.ClientElement;
019import org.apache.tapestry5.Field;
020import org.apache.tapestry5.annotations.Environmental;
021import org.apache.tapestry5.annotations.HeartbeatDeferred;
022import org.apache.tapestry5.annotations.InjectContainer;
023import org.apache.tapestry5.annotations.Parameter;
024import org.apache.tapestry5.corelib.components.FormFragment;
025import org.apache.tapestry5.json.JSONObject;
026import org.apache.tapestry5.services.javascript.JavaScriptSupport;
027
028/**
029 * A mixin that can be applied to a {@link org.apache.tapestry5.corelib.components.Checkbox} or
030 * {@link org.apache.tapestry5.corelib.components.Radio} component that will link the input field and a
031 * {@link org.apache.tapestry5.corelib.components.FormFragment}, making the field control the client-side visibility of
032 * the FormFragment. See a full example with {@link FormFragment}'s documentation.
033 *
034 * @tapestrydoc
035 */
036public class TriggerFragment
037{
038    @InjectContainer
039    private Field container;
040
041    /**
042     * The {@link org.apache.tapestry5.corelib.components.FormFragment} instance to make dynamically visible or hidden.
043     */
044    @Parameter(required = true, defaultPrefix = BindingConstants.COMPONENT, allowNull = false)
045    private ClientElement fragment;
046
047    /**
048     * If true then the client-side logic is inverted; the fragment is made visible when the checkbox is NOT checked.
049     * The default is false (the fragment is visible when the checkbox IS checked).
050     *
051     * @since 5.2.0
052     */
053    @Parameter
054    private boolean invert;
055
056    @Environmental
057    private JavaScriptSupport javascriptSupport;
058
059    @HeartbeatDeferred
060    void beginRender()
061    {
062        String fragmentId = fragment.getClientId();
063        if (fragmentId == null)
064        {
065            throw new IllegalStateException("The fragment has returned a null client-side ID");
066        }
067        JSONObject spec = new JSONObject(
068                "triggerId", container.getClientId(),
069                "fragmentId", fragmentId);
070
071        if (invert)
072        {
073            spec.put("invert", true);
074        }
075
076        javascriptSupport.require("t5/core/form-fragment").invoke("linkTrigger").with(spec);
077    }
078}