8b021c8e by astaxie

Merge pull request #664 from kioopi/renderform-textarea

Makes RenderForm use textarea-element when form type is `textarea`
2 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 {
327 return nil 327 return nil
328 } 328 }
329 329
330 // form types for RenderForm function
331 var FormType = map[string]bool{
332 "text": true,
333 "textarea": true,
334 "hidden": true,
335 "password": true,
336 }
337
338 var unKind = map[reflect.Kind]bool{ 330 var unKind = map[reflect.Kind]bool{
339 reflect.Uintptr: true, 331 reflect.Uintptr: true,
340 reflect.Complex64: true, 332 reflect.Complex64: true,
...@@ -368,15 +360,50 @@ func RenderForm(obj interface{}) template.HTML { ...@@ -368,15 +360,50 @@ func RenderForm(obj interface{}) template.HTML {
368 } 360 }
369 361
370 fieldT := objT.Field(i) 362 fieldT := objT.Field(i)
363
364 label, name, fType, ignored := parseFormTag(fieldT)
365 if ignored {
366 continue
367 }
368
369 raw = append(raw, renderFormField(label, name, fType, fieldV.Interface()))
370 }
371 return template.HTML(strings.Join(raw, "</br>"))
372 }
373
374 // renderFormField returns a string containing HTML of a single form field.
375 func renderFormField(label, name, fType string, value interface{}) string {
376 if isValidForInput(fType) {
377 return fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`, label, name, fType, value)
378 }
379
380 return fmt.Sprintf(`%v<%v name="%v">%v</%v>`, label, fType, name, value, fType)
381 }
382
383 // isValidForInput checks if fType is a valid value for the `type` property of an HTML input element.
384 func isValidForInput(fType string) bool {
385 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")
386 for _, validType := range validInputTypes {
387 if fType == validType {
388 return true
389 }
390 }
391 return false
392 }
393
394 // parseFormTag takes the stuct-tag of a StructField and parses the `form` value.
395 // returned are the form label, name-property, type and wether the field should be ignored.
396 func parseFormTag(fieldT reflect.StructField) (label, name, fType string, ignored bool) {
371 tags := strings.Split(fieldT.Tag.Get("form"), ",") 397 tags := strings.Split(fieldT.Tag.Get("form"), ",")
372 label := fieldT.Name + ": " 398 label = fieldT.Name + ": "
373 name := fieldT.Name 399 name = fieldT.Name
374 fType := "text" 400 fType = "text"
401 ignored = false;
375 402
376 switch len(tags) { 403 switch len(tags) {
377 case 1: 404 case 1:
378 if tags[0] == "-" { 405 if tags[0] == "-" {
379 continue 406 ignored = true
380 } 407 }
381 if len(tags[0]) > 0 { 408 if len(tags[0]) > 0 {
382 name = tags[0] 409 name = tags[0]
...@@ -399,11 +426,7 @@ func RenderForm(obj interface{}) template.HTML { ...@@ -399,11 +426,7 @@ func RenderForm(obj interface{}) template.HTML {
399 label = tags[2] 426 label = tags[2]
400 } 427 }
401 } 428 }
402 429 return
403 raw = append(raw, fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`,
404 label, name, fType, fieldV.Interface()))
405 }
406 return template.HTML(strings.Join(raw, "</br>"))
407 } 430 }
408 431
409 func isStructPtr(t reflect.Type) bool { 432 func isStructPtr(t reflect.Type) bool {
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
15 "net/url" 15 "net/url"
16 "testing" 16 "testing"
17 "time" 17 "time"
18 "reflect"
18 ) 19 )
19 20
20 func TestSubstr(t *testing.T) { 21 func TestSubstr(t *testing.T) {
...@@ -147,9 +148,10 @@ func TestRenderForm(t *testing.T) { ...@@ -147,9 +148,10 @@ func TestRenderForm(t *testing.T) {
147 Sex string 148 Sex string
148 Email []string 149 Email []string
149 Intro string `form:",textarea"` 150 Intro string `form:",textarea"`
151 Ignored string `form:"-"`
150 } 152 }
151 153
152 u := user{Name: "test"} 154 u := user{Name: "test", Intro: "Some Text"}
153 output := RenderForm(u) 155 output := RenderForm(u)
154 if output != template.HTML("") { 156 if output != template.HTML("") {
155 t.Errorf("output should be empty but got %v", output) 157 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) {
159 `Name: <input name="username" type="text" value="test"></br>` + 161 `Name: <input name="username" type="text" value="test"></br>` +
160 `年龄:<input name="age" type="text" value="0"></br>` + 162 `年龄:<input name="age" type="text" value="0"></br>` +
161 `Sex: <input name="Sex" type="text" value=""></br>` + 163 `Sex: <input name="Sex" type="text" value=""></br>` +
162 `Intro: <input name="Intro" type="textarea" value="">`) 164 `Intro: <textarea name="Intro">Some Text</textarea>`)
163 if output != result { 165 if output != result {
164 t.Errorf("output should equal `%v` but got `%v`", result, output) 166 t.Errorf("output should equal `%v` but got `%v`", result, output)
165 } 167 }
166 } 168 }
169
170 func TestRenderFormField(t *testing.T) {
171 html := renderFormField("Label: ", "Name", "text", "Value")
172 if html != `Label: <input name="Name" type="text" value="Value">` {
173 t.Errorf("Wrong html output for input[type=text]: %v ", html)
174 }
175
176 html = renderFormField("Label: ", "Name", "textarea", "Value")
177 if html != `Label: <textarea name="Name">Value</textarea>` {
178 t.Errorf("Wrong html output for textarea: %v ", html)
179 }
180 }
181
182 func TestParseFormTag(t *testing.T) {
183 // create struct to contain field with different types of struct-tag `form`
184 type user struct {
185 All int `form:"name,text,年龄:"`
186 NoName int `form:",hidden,年龄:"`
187 OnlyLabel int `form:",,年龄:"`
188 OnlyName int `form:"name"`
189 Ignored int `form:"-"`
190 }
191
192 objT := reflect.TypeOf(&user{}).Elem()
193
194 label, name, fType, ignored := parseFormTag(objT.Field(0))
195 if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) {
196 t.Errorf("Form Tag with name, label and type was not correctly parsed.")
197 }
198
199 label, name, fType, ignored = parseFormTag(objT.Field(1))
200 if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) {
201 t.Errorf("Form Tag with label and type but without name was not correctly parsed.")
202 }
203
204 label, name, fType, ignored = parseFormTag(objT.Field(2))
205 if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) {
206 t.Errorf("Form Tag containing only label was not correctly parsed.")
207 }
208
209 label, name, fType, ignored = parseFormTag(objT.Field(3))
210 if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false) {
211 t.Errorf("Form Tag containing only name was not correctly parsed.")
212 }
213
214 label, name, fType, ignored = parseFormTag(objT.Field(4))
215 if (ignored == false) {
216 t.Errorf("Form Tag that should be ignored was not correctly parsed.")
217 }
218 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!