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,44 +360,75 @@ func RenderForm(obj interface{}) template.HTML { ...@@ -368,44 +360,75 @@ func RenderForm(obj interface{}) template.HTML {
368 } 360 }
369 361
370 fieldT := objT.Field(i) 362 fieldT := objT.Field(i)
371 tags := strings.Split(fieldT.Tag.Get("form"), ",")
372 label := fieldT.Name + ": "
373 name := fieldT.Name
374 fType := "text"
375
376 switch len(tags) {
377 case 1:
378 if tags[0] == "-" {
379 continue
380 }
381 if len(tags[0]) > 0 {
382 name = tags[0]
383 }
384 case 2:
385 if len(tags[0]) > 0 {
386 name = tags[0]
387 }
388 if len(tags[1]) > 0 {
389 fType = tags[1]
390 }
391 case 3:
392 if len(tags[0]) > 0 {
393 name = tags[0]
394 }
395 if len(tags[1]) > 0 {
396 fType = tags[1]
397 }
398 if len(tags[2]) > 0 {
399 label = tags[2]
400 }
401 }
402 363
403 raw = append(raw, fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`, 364 label, name, fType, ignored := parseFormTag(fieldT)
404 label, name, fType, fieldV.Interface())) 365 if ignored {
366 continue
367 }
368
369 raw = append(raw, renderFormField(label, name, fType, fieldV.Interface()))
405 } 370 }
406 return template.HTML(strings.Join(raw, "</br>")) 371 return template.HTML(strings.Join(raw, "</br>"))
407 } 372 }
408 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) {
397 tags := strings.Split(fieldT.Tag.Get("form"), ",")
398 label = fieldT.Name + ": "
399 name = fieldT.Name
400 fType = "text"
401 ignored = false;
402
403 switch len(tags) {
404 case 1:
405 if tags[0] == "-" {
406 ignored = true
407 }
408 if len(tags[0]) > 0 {
409 name = tags[0]
410 }
411 case 2:
412 if len(tags[0]) > 0 {
413 name = tags[0]
414 }
415 if len(tags[1]) > 0 {
416 fType = tags[1]
417 }
418 case 3:
419 if len(tags[0]) > 0 {
420 name = tags[0]
421 }
422 if len(tags[1]) > 0 {
423 fType = tags[1]
424 }
425 if len(tags[2]) > 0 {
426 label = tags[2]
427 }
428 }
429 return
430 }
431
409 func isStructPtr(t reflect.Type) bool { 432 func isStructPtr(t reflect.Type) bool {
410 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct 433 return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
411 } 434 }
......
...@@ -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!