001 /*
002 * Apache License
003 * Version 2.0, January 2004
004 * http://www.apache.org/licenses/
005 *
006 * Copyright 2008-2010 by chenillekit.org
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 */
014
015 package org.chenillekit.tapestry.core.components;
016
017 import java.util.List;
018
019 import org.apache.tapestry5.BindingConstants;
020 import org.apache.tapestry5.ClientElement;
021 import org.apache.tapestry5.ComponentResources;
022 import org.apache.tapestry5.EventConstants;
023 import org.apache.tapestry5.EventContext;
024 import org.apache.tapestry5.Link;
025 import org.apache.tapestry5.MarkupWriter;
026 import org.apache.tapestry5.annotations.Environmental;
027 import org.apache.tapestry5.annotations.Import;
028 import org.apache.tapestry5.annotations.Mixin;
029 import org.apache.tapestry5.annotations.Parameter;
030 import org.apache.tapestry5.annotations.RequestParameter;
031 import org.apache.tapestry5.annotations.SupportsInformalParameters;
032 import org.apache.tapestry5.corelib.mixins.DiscardBody;
033 import org.apache.tapestry5.ioc.annotations.Inject;
034 import org.apache.tapestry5.json.JSONLiteral;
035 import org.apache.tapestry5.json.JSONObject;
036 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
037
038 /**
039 * a "just in place" checkbox component that does not have to be embedded in a form.
040 * sends an event after click named "clicked".
041 *
042 * @version $Id: InPlaceCheckbox.java 704 2010-10-16 10:17:41Z homburgs $
043 */
044 @SupportsInformalParameters
045 @Import(library = {"../Chenillekit.js", "InPlaceCheckbox.js"})
046 public class InPlaceCheckbox implements ClientElement
047 {
048 public static final String EVENT_NAME = "clicked";
049
050 /**
051 * If true, then the field will render out with a disabled attribute (to turn off client-side
052 * behavior). Further, a disabled field ignores any value in the request when the form is
053 * submitted.
054 */
055 @Parameter(value = "false", defaultPrefix = BindingConstants.PROP)
056 private boolean disabled;
057
058 /**
059 * The id used to generate a page-unique client-side identifier for the component. If a
060 * component renders multiple times, a suffix will be appended to the to id to ensure
061 * uniqueness. The unique value may be accessed via the
062 * {@link #getClientId() clientId property}.
063 */
064 @Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL)
065 private String clientId;
066
067 /**
068 * The value to read or update.
069 */
070 @Parameter(required = true, defaultPrefix = BindingConstants.PROP, allowNull = false)
071 private boolean value;
072
073 /**
074 * the javascript callback function (optional).
075 * function has one parameter: the response text
076 */
077 @Parameter(required = false, defaultPrefix = BindingConstants.LITERAL)
078 private String onCompleteCallback;
079
080 /**
081 * the javascript callback function (optional).
082 * function has one parameter: the response text
083 */
084 @Parameter(required = false, defaultPrefix = BindingConstants.PROP)
085 private List<?> context;
086
087 @Mixin
088 private DiscardBody discardBody;
089
090 /**
091 * For blocks, messages, create actionlink, trigger event.
092 */
093 @Inject
094 private ComponentResources resources;
095
096 /**
097 * RenderSupport to get unique client side id.
098 */
099 @Environmental
100 private JavaScriptSupport javascriptSupport;
101
102 private String assignedClientId;
103
104 private Object[] contextArray;
105
106 void setupRender()
107 {
108 assignedClientId = javascriptSupport.allocateClientId(clientId);
109 contextArray = context == null ? new Object[0] : context.toArray();
110 }
111
112 /**
113 * Tapestry render phase method.
114 * Start a tag here, end it in afterRender
115 *
116 * @param writer the markup writer
117 */
118 void beginRender(MarkupWriter writer)
119 {
120 writer.element("input",
121 "type", "checkbox",
122 "id", getClientId(),
123 "checked", value ? "checked" : null);
124
125 resources.renderInformalParameters(writer);
126 }
127
128 /**
129 * Tapestry render phase method. End a tag here.
130 *
131 * @param writer the markup writer
132 */
133 void afterRender(MarkupWriter writer)
134 {
135 writer.end(); // input
136
137 Link link = resources.createEventLink(EventConstants.ACTION, contextArray);
138
139 JSONObject spec = new JSONObject();
140 spec.put("elementId", getClientId());
141 spec.put("requestUrl", link.toURI());
142
143 if (onCompleteCallback != null)
144 spec.put("onCompleteCallback", new JSONLiteral(onCompleteCallback));
145
146 javascriptSupport.addInitializerCall("ckinplacecheckbox", spec);
147 }
148
149 JSONObject onAction(EventContext context, @RequestParameter("checked") boolean checked)
150 {
151 Object[] eventContextArray = new Object[context.getCount()+1];
152 for (int x = 0; x < context.getCount(); x++)
153 eventContextArray[x] = context.get(String.class, x);
154
155 eventContextArray[context.getCount()] = checked;
156 resources.triggerEvent(EVENT_NAME, eventContextArray, null);
157
158 return new JSONObject().put("value", checked);
159 }
160
161 /**
162 * Returns a unique id for the element. This value will be unique for any given rendering of a page. This value is
163 * intended for use as the id attribute of the client-side element, and will be used with any DHTML/Ajax related
164 * JavaScript.
165 */
166 public String getClientId()
167 {
168 return assignedClientId;
169 }
170 }