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/01/04 19:49:31 UTC
[08/13] incubator-freemarker git commit: FREEMARKER-55: Adding tests
and polishing
FREEMARKER-55: Adding tests and polishing
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/045c980c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/045c980c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/045c980c
Branch: refs/heads/3
Commit: 045c980cfcbc96b258334aaf4671451111914864
Parents: 1f7100c
Author: Woonsan Ko <wo...@apache.org>
Authored: Tue Jan 2 23:03:55 2018 -0500
Committer: Woonsan Ko <wo...@apache.org>
Committed: Tue Jan 2 23:03:55 2018 -0500
----------------------------------------------------------------------
.../AbstractSpringTemplateCallableModel.java | 15 ++++-
.../model/SpringTemplateCallableHashModel.java | 9 ++-
...aBoundFormElementTemplateDirectiveModel.java | 2 +-
.../AbstractFormTemplateDirectiveModel.java | 15 +++--
...stractHtmlElementTemplateDirectiveModel.java | 8 +--
...tHtmlInputElementTemplateDirectiveModel.java | 2 +-
.../model/form/FormTemplateDirectiveModel.java | 65 ++++++++++++++++++--
.../model/form/InputTemplateDirectiveModel.java | 34 +++++++++-
.../SpringFormTemplateCallableHashModel.java | 1 -
.../spring/model/form/TagOutputter.java | 3 +
.../form/FormTemplateDirectiveModelTest.java | 41 +++++++++++-
.../form/InputTemplateDirectiveModelTest.java | 35 +++++++++++
.../test/model/form/form-directive-usages.ftlh | 46 ++++++++++++--
.../test/model/form/input-directive-usages.ftlh | 52 +++++++++++++++-
14 files changed, 290 insertions(+), 38 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
index f7c75d9..4866557 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java
@@ -134,7 +134,20 @@ public abstract class AbstractSpringTemplateCallableModel implements TemplateCal
return (status != null) ? objectWrapperAndUnwrapper.wrap(status) : null;
}
- // TODO: Javadocs
+ /**
+ * Find {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext} by the {@code path}.
+ * <P>
+ * <EM>NOTE:</EM> In FreeMarker, there is no need to depend on <code>BindStatus#htmlEscape</code> option
+ * as FreeMarker template expressions can easily set escape option by themselves.
+ * Therefore, this method always get a {@link BindStatus} with {@code htmlEscape} option set to {@code false}.
+ * @param env Environment
+ * @param objectWrapperAndUnwrapper ObjectWrapperAndUnwrapper
+ * @param requestContext Spring RequestContext
+ * @param path bind path
+ * @param ignoreNestedPath flag whether or not to ignore the nested path
+ * @return a {@link BindStatus} with no {@code htmlEscape} option from {@link RequestContext} by the {@code path}
+ * @throws TemplateException if template exception occurs
+ */
protected final BindStatus getBindStatus(Environment env,
ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext, String path,
boolean ignoreNestedPath) throws TemplateException {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java
index 762222c..a859821 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java
@@ -35,7 +35,6 @@ import org.apache.freemarker.spring.model.form.SpringFormTemplateCallableHashMod
/**
* TemplateHashModel wrapper for templates using Spring directives, functions and internal models.
*/
-//TODO [FM3] Shouldn't this be a TemplateHashModelEx?
public final class SpringTemplateCallableHashModel implements TemplateHashModel, Serializable {
private static final long serialVersionUID = 1L;
@@ -77,19 +76,19 @@ public final class SpringTemplateCallableHashModel implements TemplateHashModel,
return modelsMap.get(key);
}
- TemplateStringModel getNestedPathModel() throws TemplateException {
+ public TemplateStringModel getNestedPathModel() throws TemplateException {
return (TemplateStringModel) get(NESTED_PATH_MODEL);
}
- void setNestedPathModel(TemplateStringModel nestedPathModel) {
+ public void setNestedPathModel(TemplateStringModel nestedPathModel) {
modelsMap.put(NESTED_PATH_MODEL, nestedPathModel);
}
- TemplateModel getEvaluationContextModel() throws TemplateException {
+ public TemplateModel getEvaluationContextModel() throws TemplateException {
return get(EVALUATION_CONTEXT_MODEL);
}
- void setEvaluationContextModel(TemplateModel evaluationContextModel) {
+ public void setEvaluationContextModel(TemplateModel evaluationContextModel) {
modelsMap.put(EVALUATION_CONTEXT_MODEL, evaluationContextModel);
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java
index 27bc4fd..d416fd4 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java
@@ -43,7 +43,7 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
/**
* Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag</code>.
*/
-public abstract class AbstractDataBoundFormElementTemplateDirectiveModel extends AbstractFormTemplateDirectiveModel {
+abstract class AbstractDataBoundFormElementTemplateDirectiveModel extends AbstractFormTemplateDirectiveModel {
private static final int PATH_PARAM_IDX = 0;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/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 45fa896..00c9f42 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
@@ -28,12 +28,11 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.freemarker.core.TemplateException;
import org.apache.freemarker.spring.model.AbstractSpringTemplateDirectiveModel;
import org.springframework.util.ObjectUtils;
-import org.springframework.web.util.HtmlUtils;
/**
* Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractFormTag</code>.
*/
-public abstract class AbstractFormTemplateDirectiveModel extends AbstractSpringTemplateDirectiveModel {
+abstract class AbstractFormTemplateDirectiveModel extends AbstractSpringTemplateDirectiveModel {
protected AbstractFormTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) {
super(request, response);
@@ -43,32 +42,32 @@ public abstract class AbstractFormTemplateDirectiveModel extends AbstractSpringT
return value;
}
- public static String getDisplayString(Object value, boolean htmlEscape) {
+ public static String getDisplayString(Object value) {
String displayValue = ObjectUtils.getDisplayString(value);
- return (htmlEscape ? HtmlUtils.htmlEscape(displayValue) : displayValue);
+ return displayValue;
}
- public static String getDisplayString(Object value, PropertyEditor propertyEditor, boolean htmlEscape) {
+ public static String getDisplayString(Object value, PropertyEditor propertyEditor) {
if (propertyEditor != null && !(value instanceof String)) {
try {
propertyEditor.setValue(value);
String text = propertyEditor.getAsText();
if (text != null) {
- return getDisplayString(text, htmlEscape);
+ return getDisplayString(text);
}
} catch (Throwable ex) {
// Ignore error if the PropertyEditor doesn't support this text value.
}
}
- return getDisplayString(value, htmlEscape);
+ return getDisplayString(value);
}
protected final void writeOptionalAttribute(TagOutputter tagOut, String attrName, Object attrValue)
throws TemplateException, IOException {
if (attrValue != null) {
- tagOut.writeOptionalAttributeValue(attrName, getDisplayString(evaluate(attrName, attrValue), false));
+ tagOut.writeOptionalAttributeValue(attrName, getDisplayString(evaluate(attrName, attrValue)));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java
index f711f3a..87b2394 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java
@@ -48,7 +48,7 @@ import org.springframework.web.servlet.support.RequestContext;
/**
* Corresponds to <code>org.springframework.web.servlet.tags.form.AbstractHtmlElementTag</code>.
*/
-public abstract class AbstractHtmlElementTemplateDirectiveModel
+abstract class AbstractHtmlElementTemplateDirectiveModel
extends AbstractDataBoundFormElementTemplateDirectiveModel {
private static final int NAMED_ARGS_OFFSET = AbstractDataBoundFormElementTemplateDirectiveModel.NAMED_ARGS_ENTRY_LIST
@@ -107,7 +107,6 @@ public abstract class AbstractHtmlElementTemplateDirectiveModel
private static final int CSSERRORCLASS_PARAM_IDX = NAMED_ARGS_OFFSET + 16;
private static final String CSSERRORCLASS_PARAM_NAME = "cssErrorClass";
- // TODO: It's a problem to see NAMED_ARGS_ENTRY_LIST is visible from child classes!
@SuppressWarnings("unchecked")
protected static List<StringToIndexMap.Entry> NAMED_ARGS_ENTRY_LIST =
_CollectionUtils.mergeImmutableLists(false,
@@ -196,7 +195,7 @@ public abstract class AbstractHtmlElementTemplateDirectiveModel
onkeydown = CallableUtils.getOptionalStringArgument(args, ONKEYDOWN_PARAM_IDX, this);
cssErrorClass = CallableUtils.getOptionalStringArgument(args, CSSERRORCLASS_PARAM_IDX, this);
- final int attrsVarargsIndex = ARGS_LAYOUT.getNamedVarargsArgumentIndex();
+ final int attrsVarargsIndex = getDirectiveArgumentArrayLayout().getNamedVarargsArgumentIndex();
final TemplateHashModelEx attrsHashModel = (TemplateHashModelEx) args[attrsVarargsIndex];
if (attrsHashModel != null && !attrsHashModel.isEmptyHash()) {
@@ -342,8 +341,7 @@ public abstract class AbstractHtmlElementTemplateDirectiveModel
if (!unmodifiableDynamicAttributes.isEmpty()) {
for (String attr : unmodifiableDynamicAttributes.keySet()) {
- tagOut.writeOptionalAttributeValue(attr,
- getDisplayString(unmodifiableDynamicAttributes.get(attr), false));
+ tagOut.writeOptionalAttributeValue(attr, getDisplayString(unmodifiableDynamicAttributes.get(attr)));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java
index ef81c1d..997ffc5 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java
@@ -38,7 +38,7 @@ import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util._CollectionUtils;
import org.springframework.web.servlet.support.RequestContext;
-public abstract class AbstractHtmlInputElementTemplateDirectiveModel extends AbstractHtmlElementTemplateDirectiveModel {
+abstract class AbstractHtmlInputElementTemplateDirectiveModel extends AbstractHtmlElementTemplateDirectiveModel {
private static final int NAMED_ARGS_OFFSET = AbstractHtmlElementTemplateDirectiveModel.NAMED_ARGS_ENTRY_LIST.size()
+ 1;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModel.java
index 565245b..a35699c 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModel.java
@@ -34,9 +34,12 @@ 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.model.TemplateStringModel;
import org.apache.freemarker.core.util.CallableUtils;
import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util._CollectionUtils;
+import org.apache.freemarker.spring.model.SpringTemplateCallableHashModel;
+import org.springframework.beans.PropertyAccessor;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.RequestContext;
@@ -44,7 +47,34 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.UriUtils;
-public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirectiveModel {
+/**
+ * Provides <code>TemplateModel</code> for data-binding-aware HTML '{@code form}' element whose inner directives
+ * are bound to properties on a <em>form object</em>.
+ * <P>
+ * This directive supports the following parameters:
+ * <UL>
+ * <LI><code>modelAttribute</code>: The first positional parameter pointing to the bean or bean property as its form object.</LI>
+ * <LI>
+ * ... TODO ...
+ * </LI>
+ * </UL>
+ * </P>
+ * <P>
+ * Some valid example(s):
+ * </P>
+ * <PRE>
+ * <#assign form=spring.form />
+ * <@form.form "user">
+ * <div>First name: <@form.input 'firstName' /></div>
+ * </@form.form>
+ * </PRE>
+ * <P>
+ * <EM>Note:</EM> Unlike Spring Framework's <code><form:input /></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 FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirectiveModel {
public static final String NAME = "form";
@@ -205,10 +235,22 @@ public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirec
tagOut.endTag();
}
- // TODO: expose the form object name for nested tags...
+ final String modelAttribute = getModelAttribute();
- // TODO: save previous nestedPath value, build and expose current nestedPath value.
+ // save previous nestedPath value, build and expose current nestedPath value.
+ final SpringTemplateCallableHashModel springTemplateModel = getSpringTemplateCallableHashModel(env);
+ final TemplateStringModel prevNestedPathModel = springTemplateModel.getNestedPathModel();
+ final String newNestedPath = modelAttribute + PropertyAccessor.NESTED_PROPERTY_SEPARATOR;
+ final TemplateStringModel newNestedPathModel = (TemplateStringModel) objectWrapperAndUnwrapper
+ .wrap(newNestedPath);
+ try {
+ springTemplateModel.setNestedPathModel(newNestedPathModel);
+ callPlace.executeNestedContent(null, out, env);
+ } finally {
+ springTemplateModel.setNestedPathModel(prevNestedPathModel);
+ tagOut.endTag();
+ }
}
protected String getModelAttribute() {
@@ -271,13 +313,22 @@ public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirec
return ("get".equalsIgnoreCase(method) || "post".equalsIgnoreCase(method));
}
+ /**
+ * Resolve the form action attribute.
+ * <p>If the {@code action} attribute is specified, then that value is used.
+ * If the {@code servletRelativeAction} is specified, then the value is prepended with context and servlet paths.
+ * Otherwise, the {@link org.springframework.web.servlet.support.RequestContext#getRequestUri() originating URI} is used.
+ * @param env environment
+ * @return the value that is to be used for the form action attribute
+ * @throws TemplateException if template exception occurs
+ */
protected String resolveAction(Environment env) throws TemplateException {
RequestContext requestContext = getRequestContext(env, false);
String action = getAction();
String servletRelativeAction = getServletRelativeAction();
if (StringUtils.hasText(action)) {
- action = getDisplayString(evaluate(ACTION_PARAM_NAME, action), false);
+ action = getDisplayString(evaluate(ACTION_PARAM_NAME, action));
return processAction(env, action);
} else if (StringUtils.hasText(servletRelativeAction)) {
String pathToServlet = requestContext.getPathToServlet();
@@ -287,7 +338,7 @@ public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirec
servletRelativeAction = pathToServlet + servletRelativeAction;
}
- servletRelativeAction = getDisplayString(evaluate(ACTION_PARAM_NAME, servletRelativeAction), false);
+ servletRelativeAction = getDisplayString(evaluate(ACTION_PARAM_NAME, servletRelativeAction));
return processAction(env, servletRelativeAction);
} else {
String requestUri = requestContext.getRequestUri();
@@ -296,7 +347,7 @@ public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirec
try {
requestUri = UriUtils.encodePath(requestUri, encoding);
} catch (UnsupportedEncodingException ex) {
- // shouldn't happen - if it does, proceed with requestUri as-is
+ // According to Spring MVC Javadoc, it shouldn't happen.
}
HttpServletResponse response = getResponse();
@@ -337,9 +388,11 @@ public class FormTemplateDirectiveModel extends AbstractHtmlElementTemplateDirec
private String processAction(Environment env, String action) throws TemplateException {
RequestDataValueProcessor processor = getRequestContext(env, false).getRequestDataValueProcessor();
HttpServletRequest request = getRequest();
+
if (processor != null && request != null) {
action = processor.processAction((HttpServletRequest) request, action, getHttpMethod());
}
+
return action;
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java
index e348da8..f155054 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java
@@ -38,7 +38,37 @@ import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util._CollectionUtils;
import org.springframework.web.servlet.support.RequestContext;
-public class InputTemplateDirectiveModel extends AbstractHtmlInputElementTemplateDirectiveModel {
+/**
+ * Provides <code>TemplateModel</code> for data-binding-aware HTML '{@code input}' element with a '{@code type}'
+ * of '{@code text}'.
+ * <P>
+ * This directive supports the following parameters:
+ * <UL>
+ * <LI><code>path</code>: The first positional parameter pointing to the bean or bean property to bind status information for.</LI>
+ * <LI>
+ * ... TODO ...
+ * </LI>
+ * </UL>
+ * </P>
+ * <P>
+ * Some valid example(s):
+ * </P>
+ * <PRE>
+ * <#assign form=spring.form />
+ * ...
+ * <@form.input 'user.firstName' />
+ *
+ * <@form.input 'user.email' id="customEmailId" />
+ *
+ * ...
+ * </PRE>
+ * <P>
+ * <EM>Note:</EM> Unlike Spring Framework's <code><form:input /></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 InputTemplateDirectiveModel extends AbstractHtmlInputElementTemplateDirectiveModel {
public static final String NAME = "input";
@@ -161,7 +191,7 @@ public class InputTemplateDirectiveModel extends AbstractHtmlInputElementTemplat
}
protected void writeValue(Environment env, TagOutputter tagOut) throws TemplateException, IOException {
- String value = getDisplayString(getBindStatus().getValue(), getBindStatus().getEditor(), false);
+ String value = getDisplayString(getBindStatus().getValue(), getBindStatus().getEditor());
String type = hasDynamicTypeAttribute() ? (String) getDynamicAttributes().get("type") : getType();
tagOut.writeAttribute("value", processFieldValue(env, getName(), value, type));
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/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 3c9becd..c7b1f5a 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
@@ -33,7 +33,6 @@ import org.apache.freemarker.core.model.TemplateModel;
/**
* TemplateHashModel wrapper for templates using Spring directives, functions and internal models.
*/
-//TODO [FM3] Shouldn't this be a TemplateHashModelEx?
public final class SpringFormTemplateCallableHashModel implements TemplateHashModel, Serializable {
private static final long serialVersionUID = 1L;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/TagOutputter.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/TagOutputter.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/TagOutputter.java
index 8569ad1..4e127b8 100644
--- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/TagOutputter.java
+++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/TagOutputter.java
@@ -26,6 +26,9 @@ import java.util.Stack;
import org.apache.freemarker.core.TemplateException;
import org.springframework.util.StringUtils;
+/**
+ * Utility to writing HTML content.
+ */
class TagOutputter {
private final Writer out;
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModelTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModelTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModelTest.java
index 2795171..8ac8413 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModelTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/FormTemplateDirectiveModelTest.java
@@ -37,6 +37,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
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")
@@ -62,7 +63,45 @@ public class FormTemplateDirectiveModelTest {
final User user = userRepository.getUser(userId);
mockMvc.perform(get("/users/{userId}/", userId).param("viewName", "test/model/form/form-directive-usages")
.accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
- .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print());
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form1']/@method").string("post"))
+ .andExpect(xpath("//form[@id='form1']//input[@name='firstName']/@value").string(user.getFirstName()))
+ .andExpect(xpath("//form[@id='form1']//input[@name='lastName']/@value").string(user.getLastName()));
+ }
+
+ @Test
+ public void testDefaultAttributes() throws Exception {
+ final Long userId = userRepository.getUserIds().iterator().next();
+ final User user = userRepository.getUser(userId);
+ mockMvc.perform(get("/users/{userId}/", userId).param("viewName", "test/model/form/form-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form2']/@class").string("my_cssClass"))
+ .andExpect(xpath("//form[@id='form2']/@style").string("my_cssStyle"))
+ .andExpect(xpath("//form[@id='form2']/@lang").string("my_lang"))
+ .andExpect(xpath("//form[@id='form2']/@title").string("my_title"))
+ .andExpect(xpath("//form[@id='form2']/@dir").string("my_dir"))
+ .andExpect(xpath("//form[@id='form2']/@tabindex").string("my_tabindex"))
+ .andExpect(xpath("//form[@id='form2']/@onclick").string("my_onclick()"))
+ .andExpect(xpath("//form[@id='form2']/@ondblclick").string("my_ondblclick()"))
+ .andExpect(xpath("//form[@id='form2']/@onmousedown").string("my_onmousedown()"))
+ .andExpect(xpath("//form[@id='form2']/@onmouseup").string("my_onmouseup()"))
+ .andExpect(xpath("//form[@id='form2']/@onmouseover").string("my_onmouseover()"))
+ .andExpect(xpath("//form[@id='form2']/@onmousemove").string("my_onmousemove()"))
+ .andExpect(xpath("//form[@id='form2']/@onmouseout").string("my_onmouseout()"))
+ .andExpect(xpath("//form[@id='form2']/@onkeypress").string("my_onkeypress()"))
+ .andExpect(xpath("//form[@id='form2']/@onkeyup").string("my_onkeyup()"))
+ .andExpect(xpath("//form[@id='form2']/@onkeydown").string("my_onkeydown()"))
+ .andExpect(xpath("//form[@id='form2']/@action").string("my_action"))
+ .andExpect(xpath("//form[@id='form2']/@method").string("post"))
+ .andExpect(xpath("//form[@id='form2']/@target").string("my_target"))
+ .andExpect(xpath("//form[@id='form2']/@enctype").string("my_enctype"))
+ .andExpect(xpath("//form[@id='form2']/@acceptCharset").string("my_acceptCharset"))
+ .andExpect(xpath("//form[@id='form2']/@onsubmit").string("my_onsubmit()"))
+ .andExpect(xpath("//form[@id='form2']/@onreset").string("my_onreset()"))
+ .andExpect(xpath("//form[@id='form2']/@autocomplete").string("my_autocomplete"))
+ .andExpect(xpath("//form[@id='form2']/@name").string("my_name"))
+ .andExpect(xpath("//form[@id='form2']/@autocomplete").string("my_autocomplete"));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModelTest.java
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModelTest.java b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModelTest.java
index 9d8a6e2..b7a0d91 100644
--- a/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModelTest.java
+++ b/freemarker-spring/src/test/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModelTest.java
@@ -69,4 +69,39 @@ public class InputTemplateDirectiveModelTest {
.andExpect(xpath("//form[@id='form1']//input[@id='lastName' and @name='lastName']/@value").string(user.getLastName()));
}
+ @Test
+ public void testDefaultAttributes() throws Exception {
+ final Long userId = userRepository.getUserIds().iterator().next();
+ mockMvc.perform(get("/users/{userId}/", userId).param("viewName", "test/model/form/input-directive-usages")
+ .accept(MediaType.parseMediaType("text/html"))).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith("text/html")).andDo(print())
+ .andExpect(xpath("//form[@id='form2']//input/@name").string("firstName"))
+ .andExpect(xpath("//form[@id='form2']//input/@class").string("my_cssClass"))
+ .andExpect(xpath("//form[@id='form2']//input/@style").string("my_cssStyle"))
+ .andExpect(xpath("//form[@id='form2']//input/@lang").string("my_lang"))
+ .andExpect(xpath("//form[@id='form2']//input/@title").string("my_title"))
+ .andExpect(xpath("//form[@id='form2']//input/@dir").string("my_dir"))
+ .andExpect(xpath("//form[@id='form2']//input/@tabindex").string("my_tabindex"))
+ .andExpect(xpath("//form[@id='form2']//input/@onclick").string("my_onclick()"))
+ .andExpect(xpath("//form[@id='form2']//input/@ondblclick").string("my_ondblclick()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onmousedown").string("my_onmousedown()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onmouseup").string("my_onmouseup()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onmouseover").string("my_onmouseover()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onmousemove").string("my_onmousemove()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onmouseout").string("my_onmouseout()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onkeypress").string("my_onkeypress()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onkeyup").string("my_onkeyup()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onkeydown").string("my_onkeydown()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onfocus").string("my_onfocus()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onblur").string("my_onblur()"))
+ .andExpect(xpath("//form[@id='form2']//input/@onchange").string("my_onchange()"))
+ .andExpect(xpath("//form[@id='form2']//input/@accesskey").string("my_accesskey"))
+ .andExpect(xpath("//form[@id='form2']//input/@disabled").string("disabled"))
+ .andExpect(xpath("//form[@id='form2']//input/@readonly").string("readonly"))
+ .andExpect(xpath("//form[@id='form2']//input/@size").string("my_size"))
+ .andExpect(xpath("//form[@id='form2']//input/@maxlength").string("my_maxlength"))
+ .andExpect(xpath("//form[@id='form2']//input/@alt").string("my_alt"))
+ .andExpect(xpath("//form[@id='form2']//input/@onselect").string("my_onselect()"))
+ .andExpect(xpath("//form[@id='form2']//input/@autocomplete").string("my_autocomplete"));
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/form-directive-usages.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/form-directive-usages.ftlh b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/form-directive-usages.ftlh
index 2338ed2..f70a4aa 100644
--- a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/form-directive-usages.ftlh
+++ b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/form-directive-usages.ftlh
@@ -19,24 +19,62 @@
<html>
<body>
+ <#assign form=spring.form />
+
<h1>Form 1</h1>
<hr/>
- <@spring.form.form "user">
+ <@form.form "user" id="form1">
<table>
<tr>
<th>First name:</th>
<td>
- <@spring.form.input 'user.firstName' />
+ <@form.input 'firstName' />
</td>
</tr>
<tr>
<th>Last name:</th>
<td>
- <@spring.form.input 'user.lastName' />
+ <@form.input 'lastName' />
</td>
</tr>
</table>
- </...@spring.form.form>
+ </...@form.form>
+
+ <hr/>
+
+ <h2>Testing default attributes</h2>
+ <@form.form "user" id="form2"
+ cssClass="my_cssClass"
+ cssStyle="my_cssStyle"
+ lang="my_lang"
+ title="my_title"
+ dir="my_dir"
+ tabindex="my_tabindex"
+ onclick="my_onclick()"
+ ondblclick="my_ondblclick()"
+ onmousedown="my_onmousedown()"
+ onmouseup="my_onmouseup()"
+ onmouseover="my_onmouseover()"
+ onmousemove="my_onmousemove()"
+ onmouseout="my_onmouseout()"
+ onkeypress="my_onkeypress()"
+ onkeyup="my_onkeyup()"
+ onkeydown="my_onkeydown()"
+ cssErrorClass="my_cssErrorClass"
+ action="my_action"
+ method="post"
+ target="my_target"
+ enctype="my_enctype"
+ acceptCharset="my_acceptCharset"
+ onsubmit="my_onsubmit()"
+ onreset="my_onreset()"
+ autocomplete="my_autocomplete"
+ name="my_name"
+ value="my_value"
+ type="my_type"
+ servletRelativeAction="my_servletRelativeAction"
+ methodParam="my_methodParam">
+ </...@form.form>
</body>
</html>
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/045c980c/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/input-directive-usages.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/input-directive-usages.ftlh b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/input-directive-usages.ftlh
index 614d2ae..b575ea0 100644
--- a/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/input-directive-usages.ftlh
+++ b/freemarker-spring/src/test/resources/META-INF/web-resources/views/test/model/form/input-directive-usages.ftlh
@@ -19,6 +19,8 @@
<html>
<body>
+ <#assign form=spring.form />
+
<h1>Form 1</h1>
<hr/>
<form id="form1">
@@ -26,19 +28,63 @@
<tr>
<th>E-Mail:</th>
<td>
- <@spring.form.input 'user.email' id="customEmailId" />
+ <@form.input 'user.email' id="customEmailId" />
</td>
</tr>
<tr>
<th>First name:</th>
<td>
- <@spring.form.input 'user.firstName' />
+ <@form.input 'user.firstName' />
</td>
</tr>
<tr>
<th>Last name:</th>
<td>
- <@spring.form.input 'user.lastName' />
+ <@form.input 'user.lastName' />
+ </td>
+ </tr>
+ </table>
+ </form>
+
+ <hr/>
+
+ <h2>Testing default attributes</h2>
+ <form id="form2">
+ <table>
+ <tr>
+ <th>First name:</th>
+ <td>
+ <@form.input "user.firstName"
+ id="my_id"
+ cssClass="my_cssClass"
+ cssStyle="my_cssStyle"
+ lang="my_lang"
+ title="my_title"
+ dir="my_dir"
+ tabindex="my_tabindex"
+ onclick="my_onclick()"
+ ondblclick="my_ondblclick()"
+ onmousedown="my_onmousedown()"
+ onmouseup="my_onmouseup()"
+ onmouseover="my_onmouseover()"
+ onmousemove="my_onmousemove()"
+ onmouseout="my_onmouseout()"
+ onkeypress="my_onkeypress()"
+ onkeyup="my_onkeyup()"
+ onkeydown="my_onkeydown()"
+ cssErrorClass="my_cssErrorClass"
+ onfocus="my_onfocus()"
+ onblur="my_onblur()"
+ onchange="my_onchange()"
+ accesskey="my_accesskey"
+ disabled=true
+ readonly=true
+ size="my_size"
+ maxlength="my_maxlength"
+ alt="my_alt"
+ onselect="my_onselect()"
+ autocomplete="my_autocomplete"
+ />
</td>
</tr>
</table>