Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 efa000c9c -> 421dc2a93


FREEMARKER-55: skeletal design


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/150ad7f6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/150ad7f6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/150ad7f6

Branch: refs/heads/3
Commit: 150ad7f6039446e2d0e3ee66010abe5be920d8d1
Parents: efa000c
Author: Woonsan Ko <woon...@apache.org>
Authored: Fri Dec 22 23:21:37 2017 -0500
Committer: Woonsan Ko <woon...@apache.org>
Committed: Fri Dec 22 23:21:37 2017 -0500

----------------------------------------------------------------------
 .../AbstractSpringTemplateDirectiveModel.java   |   2 +-
 ...aBoundFormElementTemplateDirectiveModel.java |  16 +++
 .../AbstractFormTemplateDirectiveModel.java     |  17 +++
 ...stractHtmlElementTemplateDirectiveModel.java | 139 +++++++++++++++++++
 ...tHtmlInputElementTemplateDirectiveModel.java |  13 ++
 .../model/form/InputTemplateDirectiveModel.java |  86 ++++++++++++
 6 files changed, 272 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
----------------------------------------------------------------------
diff --git 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
index c91b387..4366841 100644
--- 
a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java
@@ -36,7 +36,7 @@ import org.springframework.web.servlet.support.RequestContext;
 /**
  * Abstract TemplateDirectiveModel for derived classes to support Spring MVC 
based templating environment.
  */
-abstract class AbstractSpringTemplateDirectiveModel extends 
AbstractSpringTemplateCallableModel
+public abstract class AbstractSpringTemplateDirectiveModel extends 
AbstractSpringTemplateCallableModel
         implements TemplateDirectiveModel {
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/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
new file mode 100644
index 0000000..f9afb84
--- /dev/null
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractDataBoundFormElementTemplateDirectiveModel.java
@@ -0,0 +1,16 @@
+package org.apache.freemarker.spring.model.form;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Corresponds to 
<code>org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag</code>.
+ */
+public abstract class AbstractDataBoundFormElementTemplateDirectiveModel 
extends AbstractFormTemplateDirectiveModel {
+
+    protected 
AbstractDataBoundFormElementTemplateDirectiveModel(HttpServletRequest request,
+            HttpServletResponse response) {
+        super(request, response);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/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
new file mode 100644
index 0000000..84ca87d
--- /dev/null
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractFormTemplateDirectiveModel.java
@@ -0,0 +1,17 @@
+package org.apache.freemarker.spring.model.form;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.spring.model.AbstractSpringTemplateDirectiveModel;
+
+/**
+ * Corresponds to 
<code>org.springframework.web.servlet.tags.form.AbstractFormTag</code>.
+ */
+public abstract class AbstractFormTemplateDirectiveModel extends 
AbstractSpringTemplateDirectiveModel {
+
+    protected AbstractFormTemplateDirectiveModel(HttpServletRequest request, 
HttpServletResponse response) {
+        super(request, response);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/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
new file mode 100644
index 0000000..a0766f8
--- /dev/null
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlElementTemplateDirectiveModel.java
@@ -0,0 +1,139 @@
+package org.apache.freemarker.spring.model.form;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateStringModel;
+import org.apache.freemarker.core.util.CallableUtils;
+import org.apache.freemarker.core.util._KeyValuePair;
+
+/**
+ * Corresponds to 
<code>org.springframework.web.servlet.tags.form.AbstractHtmlElementTag</code>.
+ */
+public abstract class AbstractHtmlElementTemplateDirectiveModel
+        extends AbstractDataBoundFormElementTemplateDirectiveModel {
+
+    protected static Map<String, String> createAttributeKeyNamePairsMap(String 
... attrNames) {
+        Map<String, String> map = new HashMap<>();
+        for (String attrName : attrNames) {
+            map.put(attrName.toUpperCase(), attrName);
+        }
+        return map;
+    }
+
+    private static final Map<String, String> ALLOWED_ATTRIBUTES = 
Collections.unmodifiableMap(
+            createAttributeKeyNamePairsMap(
+                    "class",
+                    "style",
+                    "lang",
+                    "title",
+                    "dir",
+                    "tabindex",
+                    "onclick",
+                    "ondblclick",
+                    "onmousedown",
+                    "onmouseup",
+                    "onmouseover",
+                    "onmousemove",
+                    "onmouseout",
+                    "onkeypress",
+                    "onkeyup",
+                    "onkeydown")
+            );
+
+    private Map<String, Object> attributes;
+    private Map<String, Object> unmodifiableAttributes = 
Collections.emptyMap();
+
+    protected AbstractHtmlElementTemplateDirectiveModel(HttpServletRequest 
request, HttpServletResponse response) {
+        super(request, response);
+    }
+
+    public Map<String, Object> getAttributes() {
+        return unmodifiableAttributes;
+    }
+
+    public void setAttribute(String localName, Object value) {
+        if (localName == null) {
+            throw new IllegalArgumentException("Attribute name must not be 
null.");
+        }
+
+        if (!isValidDynamicAttribute(localName, value)) {
+            throw new IllegalArgumentException("Invalid attribute: " + 
localName + "=" + value);
+        }
+
+        if (attributes == null) {
+            attributes = new LinkedHashMap<String, Object>();
+            unmodifiableAttributes = Collections.unmodifiableMap(attributes);
+        }
+
+        attributes.put(localName, value);
+    }
+
+    protected boolean isAllowedAttribute(String localName, Object value) {
+        return ALLOWED_ATTRIBUTES.containsKey(localName.toUpperCase());
+    }
+
+    protected boolean isValidDynamicAttribute(String localName, Object value) {
+        return true;
+    }
+
+    protected void setAttributes(TemplateModel[] args) throws 
TemplateException {
+        final int attrsVarargsIndex = 
getDirectiveArgumentArrayLayout().getNamedVarargsArgumentIndex();
+        final TemplateHashModelEx attrsHashModel = (TemplateHashModelEx) 
args[attrsVarargsIndex];
+
+        List<_KeyValuePair<String, String>> attrs = Collections.emptyList();
+
+        if (!attrsHashModel.isEmptyHash()) {
+            attrs = new ArrayList<>();
+
+            for (TemplateHashModelEx.KeyValuePairIterator attrIt = 
attrsHashModel.keyValuePairIterator(); attrIt.hasNext();) {
+                TemplateHashModelEx.KeyValuePair pair = attrIt.next();
+                TemplateModel attrNameModel = pair.getKey();
+                TemplateModel attrValueModel = pair.getValue();
+
+                if (!(attrNameModel instanceof TemplateStringModel)) {
+                    throw 
CallableUtils.newArgumentValueException(attrsVarargsIndex,
+                            "Parameter name must be a string.", this);
+                }
+
+                String attrName = ((TemplateStringModel) 
attrNameModel).getAsString();
+
+                if (attrName.isEmpty()) {
+                    throw 
CallableUtils.newArgumentValueException(attrsVarargsIndex,
+                            "Attribute name must be a non-blank string.", 
this);
+                }
+
+                // TODO: Don't assume attribute value is string. Treat it as 
object and convert properly by using Spring utils.
+
+                String attrValue;
+
+                if (attrValueModel instanceof TemplateStringModel) {
+                    attrValue = ((TemplateStringModel) 
attrValueModel).getAsString();
+                } else if (attrValueModel instanceof TemplateNumberModel) {
+                    attrValue = ((TemplateNumberModel) 
attrValueModel).getAsNumber().toString();
+                } else if (attrValueModel instanceof TemplateBooleanModel) {
+                    attrValue = Boolean.toString(((TemplateBooleanModel) 
attrValueModel).getAsBoolean());
+                } else {
+                    throw 
CallableUtils.newArgumentValueException(attrsVarargsIndex,
+                            "Format the attribute manually to properly coerce 
it to a URL parameter value string. "
+                                    + "e.g, date?string.iso, date?long, 
list?join('_'), etc.",
+                            this);
+                }
+
+                setAttribute(attrName, attrValue);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/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
new file mode 100644
index 0000000..dc2ae48
--- /dev/null
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/AbstractHtmlInputElementTemplateDirectiveModel.java
@@ -0,0 +1,13 @@
+package org.apache.freemarker.spring.model.form;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public abstract class AbstractHtmlInputElementTemplateDirectiveModel extends 
AbstractHtmlElementTemplateDirectiveModel {
+
+    protected 
AbstractHtmlInputElementTemplateDirectiveModel(HttpServletRequest request,
+            HttpServletResponse response) {
+        super(request, response);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/150ad7f6/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
new file mode 100644
index 0000000..293da38
--- /dev/null
+++ 
b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/form/InputTemplateDirectiveModel.java
@@ -0,0 +1,86 @@
+package org.apache.freemarker.spring.model.form;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Map;
+
+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.springframework.web.servlet.support.RequestContext;
+
+public class InputTemplateDirectiveModel extends 
AbstractHtmlElementTemplateDirectiveModel {
+
+    public static final String NAME = "input";
+
+    private static final Map<String, String> ALLOWED_ATTRIBUTES = 
Collections.unmodifiableMap(
+            createAttributeKeyNamePairsMap(
+                    "size",
+                    "maxlength",
+                    "alt",
+                    "onselect",
+                    "readonly",
+                    "autocomplete"
+                    )
+            );
+
+    private static final int PATH_PARAM_IDX = 0;
+
+    private static final ArgumentArrayLayout ARGS_LAYOUT =
+            ArgumentArrayLayout.create(
+                    1,
+                    false,
+                    null,
+                    true
+                    );
+
+    protected InputTemplateDirectiveModel(HttpServletRequest request, 
HttpServletResponse response) {
+        super(request, response);
+    }
+
+    @Override
+    public boolean isNestedContentSupported() {
+        return false;
+    }
+
+    @Override
+    public ArgumentArrayLayout getDirectiveArgumentArrayLayout() {
+        return ARGS_LAYOUT;
+    }
+
+    @Override
+    protected void executeInternal(TemplateModel[] args, CallPlace callPlace, 
Writer out, Environment env,
+            ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, 
RequestContext requestContext)
+            throws TemplateException, IOException {
+
+        final String path = CallableUtils.getStringArgument(args, 
PATH_PARAM_IDX, this);
+        setAttributes(args);
+
+        // TODO: convert value properly and write tag and attributes properly.
+        out.write("<input");
+
+        for (Map.Entry<String, Object> entry : getAttributes().entrySet()) {
+            out.write(' ');
+            out.write(entry.getKey());
+            out.write("=\"");
+            out.write(entry.getValue().toString());
+            out.write('\"');
+        }
+
+        out.write("/>");
+    }
+
+    @Override
+    protected boolean isAllowedAttribute(String localName, Object value) {
+        return super.isAllowedAttribute(localName, value) && 
ALLOWED_ATTRIBUTES.containsKey(localName);
+    }
+
+}

Reply via email to