Commit 8b021c8e authored by astaxie's avatar astaxie

Merge pull request #664 from kioopi/renderform-textarea

Makes RenderForm use textarea-element when form type is `textarea`
parents 4dde2c59 34572193
...@@ -327,14 +327,6 @@ func ParseForm(form url.Values, obj interface{}) error { ...@@ -327,14 +327,6 @@ func ParseForm(form url.Values, obj interface{}) error {
return nil 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{ var unKind = map[reflect.Kind]bool{
reflect.Uintptr: true, reflect.Uintptr: true,
reflect.Complex64: true, reflect.Complex64: true,
...@@ -368,44 +360,75 @@ func RenderForm(obj interface{}) template.HTML { ...@@ -368,44 +360,75 @@ func RenderForm(obj interface{}) template.HTML {
} }
fieldT := objT.Field(i) 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]
}
}
raw = append(raw, fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`, label, name, fType, ignored := parseFormTag(fieldT)
label, name, fType, fieldV.Interface())) if ignored {
continue
}
raw = append(raw, renderFormField(label, name, fType, fieldV.Interface()))
} }
return template.HTML(strings.Join(raw, "</br>")) return template.HTML(strings.Join(raw, "</br>"))
} }
// 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<input name="%v" type="%v" value="%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 { func isStructPtr(t reflect.Type) bool {
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
} }
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"net/url" "net/url"
"testing" "testing"
"time" "time"
"reflect"
) )
func TestSubstr(t *testing.T) { func TestSubstr(t *testing.T) {
...@@ -147,9 +148,10 @@ func TestRenderForm(t *testing.T) { ...@@ -147,9 +148,10 @@ func TestRenderForm(t *testing.T) {
Sex string Sex string
Email []string Email []string
Intro string `form:",textarea"` Intro string `form:",textarea"`
Ignored string `form:"-"`
} }
u := user{Name: "test"} u := user{Name: "test", Intro: "Some Text"}
output := RenderForm(u) output := RenderForm(u)
if output != template.HTML("") { if output != template.HTML("") {
t.Errorf("output should be empty but got %v", output) t.Errorf("output should be empty but got %v", output)
...@@ -159,8 +161,58 @@ func TestRenderForm(t *testing.T) { ...@@ -159,8 +161,58 @@ func TestRenderForm(t *testing.T) {
`Name: <input name="username" type="text" value="test"></br>` + `Name: <input name="username" type="text" value="test"></br>` +
`年龄:<input name="age" type="text" value="0"></br>` + `年龄:<input name="age" type="text" value="0"></br>` +
`Sex: <input name="Sex" type="text" value=""></br>` + `Sex: <input name="Sex" type="text" value=""></br>` +
`Intro: <input name="Intro" type="textarea" value="">`) `Intro: <textarea name="Intro">Some Text</textarea>`)
if output != result { if output != result {
t.Errorf("output should equal `%v` but got `%v`", result, output) 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: <input name="Name" type="text" value="Value">` {
t.Errorf("Wrong html output for input[type=text]: %v ", html)
}
html = renderFormField("Label: ", "Name", "textarea", "Value")
if html != `Label: <textarea name="Name">Value</textarea>` {
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.")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment