2 * Copyright 2005-2010 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.wicket.jquery;
18 import java.util.Arrays;
20 import org.apache.wicket.Component;
21 import org.apache.wicket.Page;
22 import org.apache.wicket.behavior.IBehavior;
23 import org.apache.wicket.markup.html.IHeaderResponse;
24 import org.wamblee.wicket.behavior.CompositeBehavior;
26 import flexjson.JSONSerializer;
29 * Abstract JQuery hehavior class that makes it easy to write jQuery behaviors:
31 * <li>Creating a ready function which will be invoked for the component</li>
32 * <li>Checking that the component is not a page</li>
33 * <li>Ensuring tha the markup id of the component is output</li>
34 * <li>Creating a call to an intialization function from the ready handler using
35 * the component id</li>
38 * The ready function will be invoked as part of a ready handler and will invoke
39 * a function with two arguments. The first is the id of the component and the second
40 * is a configuration object.
42 * The second parameter is obtained through a call to {@link #getConfigurationJavascript()}.
45 * @author Erik Brakkee
49 public class AbstractJQueryBehavior<ConfigType> extends CompositeBehavior {
51 private static final String DEFAULT_NAMESPACE = "org.wamblee";
52 private static JSONSerializer DEFAULT_JSON_SERIALIZER = new JSONSerializer();
54 private Component component;
55 private String function;
58 * Constructs the behavior.
61 * Function to be invoked from the ready handler. This function
62 * is invoked with a CSS selector that identifies the component.
64 * Behaviors to add in addition to the basic JQuery stuff.
66 public AbstractJQueryBehavior(String aFunction, IBehavior... aBehaviors) {
67 super(getBehaviors(aBehaviors));
71 private static IBehavior[] getBehaviors(IBehavior[] aBehaviors) {
72 IBehavior[] behaviors = new IBehavior[aBehaviors.length + 1];
73 behaviors[0] = new JQueryHeaderContributor();
74 for (int i = 0; i < aBehaviors.length; i++) {
75 behaviors[i + 1] = aBehaviors[i];
81 public void bind(Component aComponent) {
82 if (component != null) {
83 throw new IllegalStateException(
84 "this kind of handler cannot be attached to " +
85 "multiple components; it is already attached to component " +
86 component + ", but component " + aComponent +
87 " wants to be attached too");
89 if (aComponent instanceof Page) {
90 throw new IllegalStateException(
91 "This behavior cannot be applied to a page: " + aComponent);
93 component = aComponent;
94 super.bind(aComponent);
95 aComponent.setOutputMarkupId(true);
99 public void renderHead(IHeaderResponse aResponse) {
100 super.renderHead(aResponse);
101 String jsString = createReadyFunction();
102 aResponse.renderJavascript(jsString, null);
106 * Creates a jQuery ready handler that invokes a given javascript function
107 * with the id of a component and with a second parameter of parameters to
108 * pass additional information to the function.
111 * Javascript function to invoke, the name of this function must
112 * include the namespace as it is called from a global scope.
114 * Component to invoke the id for.
117 String createReadyFunction() {
118 if (!component.getOutputMarkupId()) {
119 throw new IllegalStateException(
122 " does not have its markup id set so this ready handler will not have any effect");
124 StringBuffer js = new StringBuffer();
125 js.append("jQuery(function(){");
126 js.append(function + "(");
127 js.append("\"#" + component.getMarkupId() + "\"");
128 String config = getConfigurationJavascript();
129 if (config != null) {
135 String jsString = js.toString();
140 * Returns a javascript object that is passed as second argument to the
141 * ready function. This method uses {@link #getConfigurationObject()} to
142 * obtain the configuration object to use which is then serialized to
143 * javascript using {@link JSONSerializer}. Subclasses can override the
144 * default JSONSerializer by implementing {@link #getCustomSerializer()}.
146 * Subclasses should override this method to perform custom serialization.
148 * @return Configuration object in javascript.
150 protected String getConfigurationJavascript() {
151 Object config = getConfigurationObject();
152 return getActualSerializer().serialize(config);
156 * Gets the actual serializer to use. It uses {@link #getCustomSerializer()}
157 * to check if there is a custom serializer available.
159 * @return Serializer.
161 private JSONSerializer getActualSerializer() {
162 JSONSerializer serializer = getCustomSerializer();
163 if (serializer != null) {
166 return DEFAULT_JSON_SERIALIZER;
170 * Returns the serializer to use. Implementations can override this method
171 * to perform custom initialization of the serializer knowing the type of
172 * configuration object to use.
174 * @return Custom serializer to use.
176 protected JSONSerializer getCustomSerializer() {
181 * Gets the configuration object to use. This is transformed to JSON using
184 * @return Configuration object.
186 protected ConfigType getConfigurationObject() {