You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by wo...@apache.org on 2018/06/25 03:42:41 UTC
freemarker git commit: FREEMARKER-55 Adding checkbox directive.
checked option completed
Repository: freemarker
Updated Branches:
refs/heads/3 e8e58ffa5 -> bde40b5e5
FREEMARKER-55 Adding checkbox directive. checked option completed
Project: http://git-wip-us.apache.org/repos/asf/freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/freemarker/commit/bde40b5e
Tree: http://git-wip-us.apache.org/repos/asf/freemarker/tree/bde40b5e
Diff: http://git-wip-us.apache.org/repos/asf/freemarker/diff/bde40b5e
Branch: refs/heads/3
Commit: bde40b5e55a171b75254607b38f0acd7ece93f39
Parents: e8e58ff
Author: Woonsan Ko <wo...@apache.org>
Authored: Sun Jun 24 23:42:27 2018 -0400
Committer: Woonsan Ko <wo...@apache.org>
Committed: Sun Jun 24 23:42:27 2018 -0400
----------------------------------------------------------------------
...actCheckedElementTemplateDirectiveModel.java | 71 ++++++++
.../AbstractFormTemplateDirectiveModel.java | 6 +
...gleCheckedElementTemplateDirectiveModel.java | 77 +++++++++
.../form/CheckboxTemplateDirectiveModel.java | 161 +++++++++++++++++++
.../SpringFormTemplateCallableHashModel.java | 1 +
.../spring/example/mvc/users/User.java | 26 ++-
.../example/mvc/users/UserRepository.java | 20 +++
.../CheckboxTemplateDirectiveModelTest.java | 111 +++++++++++++
.../model/form/checkbox-directive-usages.f3ah | 50 ++++++
9 files changed, 522 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java
new file mode 100644
index 0000000..f6f27f3
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractCheckedElementTemplateDirectiveModel.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.spring.model.form;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+
+/**
+ * Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractCheckedElementTag</code>.
+ */
+abstract class AbstractCheckedElementTemplateDirectiveModel extends AbstractHtmlInputElementTemplateDirectiveModel {
+
+ protected AbstractCheckedElementTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) {
+ super(request, response);
+ }
+
+ /**
+ * Return "checkbox" or "radio".
+ */
+ protected abstract String getInputType();
+
+ protected void renderFromValue(Environment env, Object value, TagOutputter tagOut)
+ throws TemplateException, IOException {
+ renderFromValue(env, value, value, tagOut);
+ }
+
+ protected void renderFromValue(Environment env, Object item, Object value, TagOutputter tagOut)
+ throws TemplateException, IOException {
+ String displayValue = getDisplayString(value, getBindStatus());
+ tagOut.writeAttribute("value", processFieldValue(env, getName(), displayValue, getInputType()));
+
+ if (isOptionSelected(value) || (value != item && isOptionSelected(item))) {
+ tagOut.writeAttribute("checked", "checked");
+ }
+ }
+
+ protected void renderFromBoolean(Environment env, Boolean boundValue, TagOutputter tagOut)
+ throws TemplateException, IOException {
+ tagOut.writeAttribute("value", processFieldValue(env, getName(), "true", getInputType()));
+
+ if (boundValue != null && boundValue.booleanValue()) {
+ tagOut.writeAttribute("checked", "checked");
+ }
+ }
+
+ private boolean isOptionSelected(Object value) throws TemplateException {
+ return SelectableValueComparisonUtils.isEqualValueBoundTo(value, getBindStatus());
+ }
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java
index 83f078e..fa0152e 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java
@@ -29,6 +29,7 @@ import org.apache.freemarker.core.CustomStateKey;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.spring.model.AbstractSpringTemplateDirectiveModel;
import org.springframework.util.ObjectUtils;
+import org.springframework.web.servlet.support.BindStatus;
/**
* Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractFormTag</code>.
@@ -55,6 +56,11 @@ abstract class AbstractFormTemplateDirectiveModel extends AbstractSpringTemplate
return displayValue;
}
+ public static String getDisplayString(Object value, BindStatus bindStatus) {
+ final PropertyEditor editor = (bindStatus != null && value != null) ? bindStatus.findEditor(value.getClass()) : null;
+ return getDisplayString(value, editor);
+ }
+
public static String getDisplayString(Object value, PropertyEditor propertyEditor) {
if (propertyEditor != null && !(value instanceof String)) {
try {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java
new file mode 100644
index 0000000..48b9498
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractSingleCheckedElementTemplateDirectiveModel.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.spring.model.form;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.springframework.web.servlet.support.RequestContext;
+
+/**
+ * Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractSingleCheckedElementTag</code>.
+ */
+abstract class AbstractSingleCheckedElementTemplateDirectiveModel extends AbstractCheckedElementTemplateDirectiveModel {
+
+ protected AbstractSingleCheckedElementTemplateDirectiveModel(HttpServletRequest request,
+ HttpServletResponse response) {
+ super(request, response);
+ }
+
+ @Override
+ protected void executeInternal(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env,
+ ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
+ throws TemplateException, IOException {
+ super.executeInternal(args, callPlace, out, env, objectWrapperAndUnwrapper, requestContext);
+
+ TagOutputter tagOut = new TagOutputter(out);
+
+ tagOut.beginTag("input");
+ String id = resolveId();
+ writeOptionalAttribute(tagOut, "id", id);
+ writeOptionalAttribute(tagOut, "name", getName());
+ writeOptionalAttributes(tagOut);
+ writeAdditionalDetails(env, tagOut);
+ tagOut.endTag();
+
+ Object resolvedLabel = evaluate("label", getLabel());
+
+ if (resolvedLabel != null) {
+ tagOut.beginTag("label");
+ tagOut.writeAttribute("for", id);
+ tagOut.appendValue(getDisplayString(resolvedLabel, getBindStatus()));
+ tagOut.endTag();
+ }
+ }
+
+ public abstract Object getValue();
+
+ public abstract Object getLabel();
+
+ protected abstract void writeAdditionalDetails(Environment env, TagOutputter tagOut) throws TemplateException, IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java
new file mode 100644
index 0000000..95da416
--- /dev/null
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModel.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.spring.model.form;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.CallPlace;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util.CallableUtils;
+import org.apache.freemarker.core.util.StringToIndexMap;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.servlet.support.RequestContext;
+
+/**
+ * Provides <code>TemplateModel</code> for data-binding-aware HTML '{@code <input type="checkbox"/>}' element.
+ * This tag is provided for completeness if the application relies on a
+ * <code>org.springframework.web.servlet.support.RequestDataValueProcessor</code>.
+ * <P>
+ * This directive supports the following parameters:
+ * <UL>
+ * <LI>
+ * ... TODO ...
+ * </LI>
+ * </UL>
+ * </P>
+ * <P>
+ * Some valid example(s):
+ * </P>
+ * <PRE>
+ * <@form.checkbox 'user.receiveNewsletter' />
+ * </PRE>
+ * <P>
+ * <EM>Note:</EM> Unlike Spring Framework's <code><form:button /></code> JSP Tag Library, this directive
+ * does not support <code>htmlEscape</code> parameter. It always renders HTML's without escaping
+ * because it is much easier to control escaping in FreeMarker Template expressions.
+ * </P>
+ */
+
+class CheckboxTemplateDirectiveModel extends AbstractSingleCheckedElementTemplateDirectiveModel {
+
+ public static final String NAME = "checkbox";
+
+ private static final int NAMED_ARGS_OFFSET = AbstractHtmlInputElementTemplateDirectiveModel.ARGS_LAYOUT
+ .getPredefinedNamedArgumentsEndIndex();
+
+ private static final int VALUE_PARAM_IDX = NAMED_ARGS_OFFSET;
+ private static final String VALUE_PARAM_NAME = "value";
+
+ private static final int LABEL_PARAM_IDX = NAMED_ARGS_OFFSET + 1;
+ private static final String LABEL_PARAM_NAME = "label";
+
+ protected static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(1, false,
+ StringToIndexMap.of(AbstractHtmlInputElementTemplateDirectiveModel.ARGS_LAYOUT.getPredefinedNamedArgumentsMap(),
+ new StringToIndexMap.Entry(VALUE_PARAM_NAME, VALUE_PARAM_IDX),
+ new StringToIndexMap.Entry(LABEL_PARAM_NAME, LABEL_PARAM_IDX)),
+ true);
+
+ private String value;
+ private String label;
+
+ protected CheckboxTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) {
+ super(request, response);
+ }
+
+ @Override
+ public ArgumentArrayLayout getDirectiveArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+
+ @Override
+ public boolean isNestedContentSupported() {
+ return false;
+ }
+
+ @Override
+ protected void executeInternal(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env,
+ ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext)
+ throws TemplateException, IOException {
+ value = CallableUtils.getOptionalStringArgument(args, VALUE_PARAM_IDX, this);
+ label = CallableUtils.getOptionalStringArgument(args, LABEL_PARAM_IDX, this);
+
+ super.executeInternal(args, callPlace, out, env, objectWrapperAndUnwrapper, requestContext);
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String getLabel() {
+ return label;
+ }
+
+ @Override
+ protected void writeAdditionalDetails(Environment env, TagOutputter tagOut) throws TemplateException, IOException {
+ tagOut.writeAttribute("type", getInputType());
+
+ Object boundValue = getBindStatus().getValue();
+ Class<?> valueType = getBindStatus().getValueType();
+
+ if (Boolean.class == valueType || boolean.class == valueType) {
+ if (boundValue instanceof String) {
+ boundValue = Boolean.valueOf((String) boundValue);
+ }
+
+ final Boolean booleanValue = (boundValue != null) ? (Boolean) boundValue : Boolean.FALSE;
+ renderFromBoolean(env, booleanValue, tagOut);
+ } else {
+ Object value = getValue();
+
+ if (value == null) {
+ throw new IllegalArgumentException("value attribute is missing. It's required to bind to a non-boolean value(s).");
+ }
+
+ Object resolvedValue = (value instanceof String ? evaluate("value", value) : value);
+ renderFromValue(env, resolvedValue, tagOut);
+ }
+
+ if (!isDisabled()) {
+ // Spring Web MVC requires to render a hidden input as a 'field was present' marker.
+ tagOut.beginTag("input");
+ tagOut.writeAttribute("type", "hidden");
+ String name = WebDataBinder.DEFAULT_FIELD_MARKER_PREFIX + getName();
+ tagOut.writeAttribute("name", name);
+ tagOut.writeAttribute("value", processFieldValue(env, name, "on", getInputType()));
+ tagOut.endTag();
+ }
+ }
+
+ @Override
+ protected String getInputType() {
+ return "checkbox";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java
index b460c4c..aaab1f1 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/SpringFormTemplateCallableHashModel.java
@@ -56,6 +56,7 @@ public final class SpringFormTemplateCallableHashModel implements TemplateHashMo
modelsMap.put(OptionsTemplateDirectiveModel.NAME, new OptionsTemplateDirectiveModel(request, response));
modelsMap.put(OptionTemplateDirectiveModel.NAME, new OptionTemplateDirectiveModel(request, response));
modelsMap.put(ErrorsTemplateDirectiveModel.NAME, new ErrorsTemplateDirectiveModel(request, response));
+ modelsMap.put(CheckboxTemplateDirectiveModel.NAME, new CheckboxTemplateDirectiveModel(request, response));
}
@Override
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
index 028f920..56330e6 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/User.java
@@ -31,6 +31,8 @@ public class User {
private Date birthDate;
private String description;
private String favoriteSport;
+ private boolean receiveNewsletter;
+ private String[] favoriteFood;
public User() {
}
@@ -99,10 +101,32 @@ public class User {
this.favoriteSport = favoriteSport;
}
+ public boolean isReceiveNewsletter() {
+ return receiveNewsletter;
+ }
+
+ public void setReceiveNewsletter(boolean receiveNewsletter) {
+ this.receiveNewsletter = receiveNewsletter;
+ }
+
+ public String[] getFavoriteFood() {
+ if (favoriteFood == null) {
+ return null;
+ }
+
+ String[] cloned = new String[favoriteFood.length];
+ System.arraycopy(favoriteFood, 0, cloned, 0, favoriteFood.length);
+ return cloned;
+ }
+
+ public void setFavoriteFood(String[] favoriteFood) {
+ this.favoriteFood = favoriteFood;
+ }
+
@Override
public String toString() {
return super.toString() + " {id=" + id + ", firstName='" + firstName + "', lastName='" + lastName + "', email='"
+ email + "', birthDate='" + birthDate + "', description='" + description + "', favoriteSport='"
- + favoriteSport + "'}";
+ + favoriteSport + "', receiveNewsletter=" + receiveNewsletter + ", favoriteFood=" + favoriteFood + "}";
}
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
index e2a2283..57af289 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/example/mvc/users/UserRepository.java
@@ -58,6 +58,8 @@ public class UserRepository {
user.setDescription("Lorem ipsum dolor sit amet, \r\nconsectetur adipiscing elit, \r\n"
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
user.setFavoriteSport("baseball");
+ user.setReceiveNewsletter(false);
+ user.setFavoriteFood(new String[] { "Sandwich", "Spaghetti" });
usersMap.put(id, user);
id = 102L;
@@ -74,6 +76,8 @@ public class UserRepository {
user.setDescription("Ut enim ad minim veniam, \r\n"
+ "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.");
user.setFavoriteSport("marathon");
+ user.setReceiveNewsletter(true);
+ user.setFavoriteFood(new String[] { "Sandwich", "Sushi" });
usersMap.put(id, user);
}
@@ -95,6 +99,20 @@ public class UserRepository {
return null;
}
+ public synchronized User getUserByEmail(final String email) {
+ if (email == null) {
+ throw new IllegalArgumentException("E-Mail must be non-null.");
+ }
+
+ for (User user : usersMap.values()) {
+ if (email.equals(user.getEmail())) {
+ return cloneUser(user, user.getId());
+ }
+ }
+
+ return null;
+ }
+
public synchronized User addOrUpdateUser(final User user) {
final Long id = user.getId();
User newUser = cloneUser(user, id);
@@ -120,6 +138,8 @@ public class UserRepository {
clone.setBirthDate(source.getBirthDate());
clone.setDescription(source.getDescription());
clone.setFavoriteSport(source.getFavoriteSport());
+ clone.setReceiveNewsletter(source.isReceiveNewsletter());
+ clone.setFavoriteFood(source.getFavoriteFood());
return clone;
}
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java
new file mode 100644
index 0000000..5d74d8c
--- /dev/null
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/CheckboxTemplateDirectiveModelTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.spring.model.form;
+
+import org.apache.freemarker.spring.example.mvc.users.User;
+import org.apache.freemarker.spring.example.mvc.users.UserRepository;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@WebAppConfiguration("classpath:META-INF/web-resources")
+@ContextConfiguration(locations = { "classpath:org/apache/freemarker/spring/example/mvc/users/users-mvc-context.xml" })
+public class CheckboxTemplateDirectiveModelTest {
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ private MockMvc mockMvc;
+
+ @Before
+ public void setUp() {
+ mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ }
+
+ @Test
+ public void testSingleCheckboxWithNotChecked() throws Exception {
+ final User user = userRepository.getUserByEmail("john@example.com");
+ mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@value").string("true"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@checked").doesNotExist())
+ .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_receiveNewsletter']/@value").string("on"));
+ }
+
+ @Test
+ public void testSingleCheckboxWithChecked() throws Exception {
+ final User user = userRepository.getUserByEmail("jane@example.com");
+ mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@value").string("true"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='receiveNewsletter' and @name='receiveNewsletter']/@checked").string("checked"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_receiveNewsletter']/@value").string("on"));
+ }
+
+ @Test
+ public void testMultipleCheckboxes101() throws Exception {
+ final User user = userRepository.getUserByEmail("john@example.com");
+ mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_favoriteFood' and @value='on']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']/@checked").string("checked"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']/@checked").string("checked"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']/@checked").doesNotExist());
+ }
+
+ @Test
+ public void testMultipleCheckboxes102() throws Exception {
+ final User user = userRepository.getUserByEmail("jane@example.com");
+ mockMvc.perform(get("/users/{userId}/", user.getId()).param("viewName", "test/model/form/checkbox-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='hidden' and @name='_favoriteFood' and @value='on']").exists())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sandwich']/@checked").string("checked"))
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Spaghetti']/@checked").doesNotExist())
+ .andExpect(xpath("//form[@id='form1']//input[@type='checkbox' and @id='favoriteFood' and @name='favoriteFood' and @value='Sushi']/@checked").string("checked"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/bde40b5e/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah
new file mode 100644
index 0000000..e1d395a
--- /dev/null
+++ b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/checkbox-directive-usages.f3ah
@@ -0,0 +1,50 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html>
+<body>
+
+ <h1>Form 1</h1>
+ <hr/>
+ <form id="form1">
+ <table>
+ <tr>
+ <th>User:</th>
+ <td>
+ ${user.firstName} ${user.lastName} (${user.email})
+ </td>
+ </tr>
+ <tr>
+ <th>Receive Newsletter?</th>
+ <td>
+ <@form.checkbox "user.receiveNewsletter" />
+ </td>
+ </tr>
+ <tr>
+ <th>Favorite Food</th>
+ <td>
+ <@form.checkbox "user.favoriteFood" value="Sandwich" />Sandwich
+ <@form.checkbox "user.favoriteFood" value="Spaghetti" />Spaghetti
+ <@form.checkbox "user.favoriteFood" value="Sushi" />Sushi
+ </td>
+ </tr>
+ </table>
+ </form>
+
+</body>
+</html>