diff --git a/templatefunc.go b/templatefunc.go
index 84624d2e..274e3af9 100644
--- a/templatefunc.go
+++ b/templatefunc.go
@@ -327,14 +327,6 @@ func ParseForm(form url.Values, obj interface{}) error {
return nil
}
-// form types for RenderForm function
-var FormType = map[string]bool{
- "text": true,
- "textarea": true,
- "hidden": true,
- "password": true,
-}
-
var unKind = map[reflect.Kind]bool{
reflect.Uintptr: true,
reflect.Complex64: true,
@@ -368,44 +360,75 @@ func RenderForm(obj interface{}) template.HTML {
}
fieldT := objT.Field(i)
- tags := strings.Split(fieldT.Tag.Get("form"), ",")
- label := fieldT.Name + ": "
- name := fieldT.Name
- fType := "text"
- switch len(tags) {
- case 1:
- if tags[0] == "-" {
- continue
- }
- if len(tags[0]) > 0 {
- name = tags[0]
- }
- case 2:
- if len(tags[0]) > 0 {
- name = tags[0]
- }
- if len(tags[1]) > 0 {
- fType = tags[1]
- }
- case 3:
- if len(tags[0]) > 0 {
- name = tags[0]
- }
- if len(tags[1]) > 0 {
- fType = tags[1]
- }
- if len(tags[2]) > 0 {
- label = tags[2]
- }
- }
+ label, name, fType, ignored := parseFormTag(fieldT)
+ if ignored {
+ continue
+ }
- raw = append(raw, fmt.Sprintf(`%v`,
- label, name, fType, fieldV.Interface()))
+ raw = append(raw, renderFormField(label, name, fType, fieldV.Interface()))
}
return template.HTML(strings.Join(raw, ""))
}
+// renderFormField returns a string containing HTML of a single form field.
+func renderFormField(label, name, fType string, value interface{}) string {
+ if isValidForInput(fType) {
+ return fmt.Sprintf(`%v`, label, name, fType, value)
+ }
+
+ return fmt.Sprintf(`%v<%v name="%v">%v%v>`, label, fType, name, value, fType)
+}
+
+// isValidForInput checks if fType is a valid value for the `type` property of an HTML input element.
+func isValidForInput(fType string) bool {
+ validInputTypes := strings.Fields("text password checkbox radio submit reset hidden image file button search email url tel number range date month week time datetime datetime-local color")
+ for _, validType := range validInputTypes {
+ if fType == validType {
+ return true
+ }
+ }
+ return false
+}
+
+// parseFormTag takes the stuct-tag of a StructField and parses the `form` value.
+// returned are the form label, name-property, type and wether the field should be ignored.
+func parseFormTag(fieldT reflect.StructField) (label, name, fType string, ignored bool) {
+ tags := strings.Split(fieldT.Tag.Get("form"), ",")
+ label = fieldT.Name + ": "
+ name = fieldT.Name
+ fType = "text"
+ ignored = false;
+
+ switch len(tags) {
+ case 1:
+ if tags[0] == "-" {
+ ignored = true
+ }
+ if len(tags[0]) > 0 {
+ name = tags[0]
+ }
+ case 2:
+ if len(tags[0]) > 0 {
+ name = tags[0]
+ }
+ if len(tags[1]) > 0 {
+ fType = tags[1]
+ }
+ case 3:
+ if len(tags[0]) > 0 {
+ name = tags[0]
+ }
+ if len(tags[1]) > 0 {
+ fType = tags[1]
+ }
+ if len(tags[2]) > 0 {
+ label = tags[2]
+ }
+ }
+ return
+}
+
func isStructPtr(t reflect.Type) bool {
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
}
diff --git a/templatefunc_test.go b/templatefunc_test.go
index c3879fbb..373b11fa 100644
--- a/templatefunc_test.go
+++ b/templatefunc_test.go
@@ -15,6 +15,7 @@ import (
"net/url"
"testing"
"time"
+ "reflect"
)
func TestSubstr(t *testing.T) {
@@ -147,9 +148,10 @@ func TestRenderForm(t *testing.T) {
Sex string
Email []string
Intro string `form:",textarea"`
+ Ignored string `form:"-"`
}
- u := user{Name: "test"}
+ u := user{Name: "test", Intro: "Some Text"}
output := RenderForm(u)
if output != template.HTML("") {
t.Errorf("output should be empty but got %v", output)
@@ -159,8 +161,58 @@ func TestRenderForm(t *testing.T) {
`Name: ` +
`年龄:` +
`Sex: ` +
- `Intro: `)
+ `Intro: `)
if output != result {
t.Errorf("output should equal `%v` but got `%v`", result, output)
}
}
+
+func TestRenderFormField(t *testing.T) {
+ html := renderFormField("Label: ", "Name", "text", "Value")
+ if html != `Label: ` {
+ t.Errorf("Wrong html output for input[type=text]: %v ", html)
+ }
+
+ html = renderFormField("Label: ", "Name", "textarea", "Value")
+ if html != `Label: ` {
+ t.Errorf("Wrong html output for textarea: %v ", html)
+ }
+}
+
+func TestParseFormTag(t *testing.T) {
+ // create struct to contain field with different types of struct-tag `form`
+ type user struct {
+ All int `form:"name,text,年龄:"`
+ NoName int `form:",hidden,年龄:"`
+ OnlyLabel int `form:",,年龄:"`
+ OnlyName int `form:"name"`
+ Ignored int `form:"-"`
+ }
+
+ objT := reflect.TypeOf(&user{}).Elem()
+
+ label, name, fType, ignored := parseFormTag(objT.Field(0))
+ if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) {
+ t.Errorf("Form Tag with name, label and type was not correctly parsed.")
+ }
+
+ label, name, fType, ignored = parseFormTag(objT.Field(1))
+ if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) {
+ t.Errorf("Form Tag with label and type but without name was not correctly parsed.")
+ }
+
+ label, name, fType, ignored = parseFormTag(objT.Field(2))
+ if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) {
+ t.Errorf("Form Tag containing only label was not correctly parsed.")
+ }
+
+ label, name, fType, ignored = parseFormTag(objT.Field(3))
+ if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false) {
+ t.Errorf("Form Tag containing only name was not correctly parsed.")
+ }
+
+ label, name, fType, ignored = parseFormTag(objT.Field(4))
+ if (ignored == false) {
+ t.Errorf("Form Tag that should be ignored was not correctly parsed.")
+ }
+}