From 3fe9e6a28afda1cfc4d24fc49df4308f8988bfa1 Mon Sep 17 00:00:00 2001 From: Vangelis Tsoumenis Date: Sun, 29 Jun 2014 19:19:32 +0200 Subject: [PATCH 1/4] extract func `parseFormTag` from templatefunc.RenderForm Extracted a func `parseFormTag` that takes a reflect.StructField and returns the different positional parts of the `form` structTag with default values as documented in http://beego.me/docs/mvc/view/view.md#renderform This makes RenderForm shorter and makes it possible to test the parsing separately. --- templatefunc.go | 72 ++++++++++++++++++++++++++------------------ templatefunc_test.go | 39 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 84624d2e..3d42321b 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -368,37 +368,11 @@ 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())) @@ -406,6 +380,44 @@ func RenderForm(obj interface{}) template.HTML { return template.HTML(strings.Join(raw, "
")) } +// 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..a19d9bc5 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -15,6 +15,7 @@ import ( "net/url" "testing" "time" + "reflect" ) func TestSubstr(t *testing.T) { @@ -164,3 +165,41 @@ func TestRenderForm(t *testing.T) { t.Errorf("output should equal `%v` but got `%v`", result, output) } } + +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.") + } +} From a991b9dcdea080ff3bd6586b44e775e7759e7ac5 Mon Sep 17 00:00:00 2001 From: Vangelis Tsoumenis Date: Sun, 29 Jun 2014 19:29:43 +0200 Subject: [PATCH 2/4] Removes unused FormType map from templatefunc --- templatefunc.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 3d42321b..f51eaac4 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -327,13 +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, From 4994d36b663951d93d90b865cb18876bb0f20e42 Mon Sep 17 00:00:00 2001 From: Vangelis Tsoumenis Date: Sun, 29 Jun 2014 20:30:11 +0200 Subject: [PATCH 3/4] templateform.RenderForm now renders textarea When RenderForm encounters a field with the structTag `form` value type `textarea` it renders an actual `) 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 { From 34572193c6ebb493815776c14fa82340e54648f4 Mon Sep 17 00:00:00 2001 From: Vangelis Tsoumenis Date: Mon, 30 Jun 2014 10:38:32 +0200 Subject: [PATCH 4/4] Adds html5 input types to valid intput types of RenderForm. --- templatefunc.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index ea98470a..274e3af9 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -371,6 +371,7 @@ func RenderForm(obj interface{}) template.HTML { 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) @@ -379,8 +380,9 @@ func renderFormField(label, name, fType string, value interface{}) string { return fmt.Sprintf(`%v<%v name="%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") + 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 @@ -389,7 +391,6 @@ func isValidForInput(fType string) bool { 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) {