import org.apache.wicket.markup.html.IHeaderResponse;
import org.wamblee.wicket.behavior.CompositeBehavior;
+import flexjson.JSONSerializer;
+
/**
* Abstract JQuery hehavior class that makes it easy to write jQuery behaviors:
* <ul>
* <li>Creating a ready function which will be invoked for the component</li>
* <li>Checking that the component is not a page</li>
* <li>Ensuring tha the markup id of the component is output</li>
- * <li>Creating a call to an intialization function from the ready handler using the component id </li>
+ * <li>Creating a call to an intialization function from the ready handler using
+ * the component id</li>
* </ul>
*
+ * The ready function will be invoked as part of a ready handler and will invoke
+ * a function with two arguments. The first is the id of the component and the second
+ * is a configuration object.
+ * <p>
+ * The second parameter is obtained through a call to {@link #getConfigurationJavascript()}.
+ *
+ *
* @author Erik Brakkee
*
+ * <ConfigType>
*/
-public class AbstractJQueryBehavior extends CompositeBehavior {
+public class AbstractJQueryBehavior<ConfigType> extends CompositeBehavior {
+
+ private static final String DEFAULT_NAMESPACE = "org.wamblee";
+ private static JSONSerializer DEFAULT_JSON_SERIALIZER = new JSONSerializer();
private Component component;
private String function;
* Constructs the behavior.
*
* @param aFunction
- * Function to be invoked from the ready handler. This function is invoked with a
- * CSS selector that identifies the component.
+ * Function to be invoked from the ready handler. This function
+ * is invoked with a CSS selector that identifies the component.
* @param aBehaviors
* Behaviors to add in addition to the basic JQuery stuff.
*/
@Override
public void renderHead(IHeaderResponse aResponse) {
super.renderHead(aResponse);
- String jsString = createReadyFunction(function, component);
+ String jsString = createReadyFunction();
aResponse.renderJavascript(jsString, null);
}
/**
* Creates a jQuery ready handler that invokes a given javascript function
- * with the id of a component.
+ * with the id of a component and with a second parameter of parameters to
+ * pass additional information to the function.
*
* @param aFunction
- * Javascript function to invoke.
+ * Javascript function to invoke, the name of this function must
+ * include the namespace as it is called from a global scope.
* @param aComponent
* Component to invoke the id for.
* @return
*/
- public static String createReadyFunction(String aFunction,
- Component aComponent) {
- if (!aComponent.getOutputMarkupId()) {
+ String createReadyFunction() {
+ if (!component.getOutputMarkupId()) {
throw new IllegalStateException(
"The component " +
- aComponent +
+ component +
" does not have its markup id set so this ready handler will not have any effect");
}
StringBuffer js = new StringBuffer();
js.append("jQuery(function(){");
- js.append("org.wamblee." + aFunction + "(\"#" +
- aComponent.getMarkupId() + "\");");
+ js.append(function + "(");
+ js.append("\"#" + component.getMarkupId() + "\"");
+ String config = getConfigurationJavascript();
+ if (config != null) {
+ js.append(",");
+ js.append(config);
+ }
+ js.append(");");
js.append("});");
String jsString = js.toString();
return jsString;
}
+
+ /**
+ * Returns a javascript object that is passed as second argument to the
+ * ready function. This method uses {@link #getConfigurationObject()} to
+ * obtain the configuration object to use which is then serialized to
+ * javascript using {@link JSONSerializer}. Subclasses can override the
+ * default JSONSerializer by implementing {@link #getCustomSerializer()}.
+ * <p>
+ * Subclasses should override this method to perform custom serialization.
+ *
+ * @return Configuration object in javascript.
+ */
+ protected String getConfigurationJavascript() {
+ Object config = getConfigurationObject();
+ return getActualSerializer().serialize(config);
+ }
+
+ /**
+ * Gets the actual serializer to use. It uses {@link #getCustomSerializer()}
+ * to check if there is a custom serializer available.
+ *
+ * @return Serializer.
+ */
+ private JSONSerializer getActualSerializer() {
+ JSONSerializer serializer = getCustomSerializer();
+ if (serializer != null) {
+ return serializer;
+ }
+ return DEFAULT_JSON_SERIALIZER;
+ }
+
+ /**
+ * Returns the serializer to use. Implementations can override this method
+ * to perform custom initialization of the serializer knowing the type of
+ * configuration object to use.
+ *
+ * @return Custom serializer to use.
+ */
+ protected JSONSerializer getCustomSerializer() {
+ return null;
+ }
+
+ /**
+ * Gets the configuration object to use. This is transformed to JSON using
+ * the serializer.
+ *
+ * @return Configuration object.
+ */
+ protected ConfigType getConfigurationObject() {
+ return null;
+ }
}
import org.junit.Test;
import org.wamblee.wicket.MyPage;
+import flexjson.JSONSerializer;
+
import static junit.framework.TestCase.*;
public class AbstractJQueryBehaviorTest {
public void tearDown() {
wicket.destroy();
}
-
+
@Test
- public void testVerifyBasicFunc() {
+ public void testVerifyBasicFunc() {
MyPage page = new MyPage();
page.getLabel().add(new AbstractJQueryBehavior("initfunc"));
wicket.startPage(page);
assertTrue(doc.contains("jquery-noconflict"));
assertTrue(doc.contains("initfunc"));
}
-
+
@Test
- public void testCreateReadyJavascript() {
+ public void testCreateReadyJavascript() {
Component component = new Label("label");
component.setOutputMarkupId(true);
- String readyHandler = AbstractJQueryBehavior.createReadyFunction("myfunc", component);
- assertEquals("jQuery(function(){org.wamblee.myfunc(\"#" + component.getMarkupId() + "\");});", readyHandler);
+ AbstractJQueryBehavior behavior = new AbstractJQueryBehavior("myfunc");
+ behavior.bind(component);
+ String readyHandler = behavior.createReadyFunction();
+ assertEquals("jQuery(function(){myfunc(\"#" + component.getMarkupId() +
+ "\",null);});", readyHandler);
+ }
+
+ @Test
+ public void testCreateReadyJavaScriptWithCustomConfigJavascript() {
+ Component component = new Label("label");
+ component.setOutputMarkupId(false);
+ AbstractJQueryBehavior behavior = new AbstractJQueryBehavior("myfunc") {
+ @Override
+ protected String getConfigurationJavascript() {
+ return "bla";
+ }
+ };
+ behavior.bind(component);
+ String readyHandler = behavior.createReadyFunction();
+ assertEquals("jQuery(function(){myfunc(\"#" + component.getMarkupId() +
+ "\",bla);});", readyHandler);
+ }
+
+ public static final class X {
+ private int x = 10;
+ public int getX() {
+ return x;
+ }
+ }
+
+ @Test
+ public void testCreateReadyJavaScriptWithConfig() {
+ Component component = new Label("label");
+ component.setOutputMarkupId(false);
+ AbstractJQueryBehavior behavior = new AbstractJQueryBehavior("myfunc") {
+ @Override
+ protected Object getConfigurationObject() {
+ return new X();
+ }
+ };
+ behavior.bind(component);
+ String readyHandler = behavior.createReadyFunction();
+ String config = new JSONSerializer().serialize(new X());
+ assertEquals("jQuery(function(){myfunc(\"#" + component.getMarkupId() +
+ "\"," + config + ");});", readyHandler);
}
- @Test(expected = IllegalStateException.class)
- public void testCreateReadyJavascriptNoMarkupId() {
+ @Test
+ public void testCreateReadyJavaScriptWithConfigWithCustomSerializer() {
Component component = new Label("label");
- String readyHandler = AbstractJQueryBehavior.createReadyFunction("myfunc", component);
+ component.setOutputMarkupId(false);
+ AbstractJQueryBehavior behavior = new AbstractJQueryBehavior("myfunc") {
+ @Override
+ protected Object getConfigurationObject() {
+ return new X();
+ }
+ @Override
+ protected JSONSerializer getCustomSerializer() {
+ return new JSONSerializer().exclude("x");
+ }
+ };
+ behavior.bind(component);
+ String readyHandler = behavior.createReadyFunction();
+ String config = new JSONSerializer().exclude("x").serialize(new X());
+ assertEquals("jQuery(function(){myfunc(\"#" + component.getMarkupId() +
+ "\"," + config + ");});", readyHandler);
}
+
}