start refactoring forms. Allow list for recipe ingredients

This commit is contained in:
Niko Abeler 2023-08-05 21:24:26 +02:00
parent 349aa0dd5d
commit 74760707dd
4 changed files with 124 additions and 10 deletions

View File

@ -15,7 +15,7 @@ type RecipeMetaData struct {
Title string `owl:"inputType=text"`
Yield string `owl:"inputType=text"`
Duration string `owl:"inputType=text"`
Ingredients []string `owl:"inputType=text widget=textarea"`
Ingredients []string `owl:"inputType=text widget=textlist"`
Content string `owl:"inputType=text widget=textarea"`
}

View File

@ -0,0 +1,27 @@
<small>
{{ if .MetaData.Yield }}
Servings: <span class="p-yield">{{ .MetaData.Yield }}</span>
{{ if .MetaData.Duration }}, {{end}}
{{ end }}
{{ if .MetaData.Duration }}
Prep Time: <time class="dt-duration" value="{{ .MetaData.Duration }}">
{{ .MetaData.Duration }}
</time>
{{ end }}
</small>
<br> <br>
<h2>Ingredients</h2>
<ul>
{{ range $ingredient := .MetaData.Ingredients }}
<li class="p-ingredient">
{{ $ingredient }}
</li>
{{ end }}
</ul>
<h2>Instructions</h2>
{{.MetaData.Content | markdown }}

View File

@ -32,7 +32,7 @@ type FormFieldParams struct {
type FormField struct {
Name string
Value string
Value reflect.Value
Params FormFieldParams
}
@ -55,18 +55,30 @@ func (s *FormFieldParams) ApplyTag(tagKey string, tagValue string) error {
return nil
}
func (s *FormField) ToWidget() Widget {
switch s.Params.Widget {
case "textarea":
return &TextareaWidget{*s}
case "textlist":
return &TextListWidget{*s}
default:
return &TextWidget{*s}
}
}
func (s *FormField) Html() string {
html := ""
html += fmt.Sprintf("<label for=\"%v\">%v</label>\n", s.Name, s.Name)
if s.Params.InputType == "text" && s.Params.Widget == "textarea" {
html += fmt.Sprintf("<textarea name=\"%v\" id=\"%v\" rows=\"20\">%v</textarea>\n", s.Name, s.Name, s.Value)
} else {
if s.Params.InputType == "file" {
html += fmt.Sprintf("<input type=\"%v\" name=\"%v\" id=\"%v\" value=\"%v\" />\n", s.Params.InputType, s.Name, s.Name, s.Value)
} else {
html += s.ToWidget().Html()
html += "\n"
}
return html
}
func FieldToFormField(field reflect.StructField, value string) (FormField, error) {
func FieldToFormField(field reflect.StructField, value reflect.Value) (FormField, error) {
formField := FormField{
Name: field.Name,
Value: value,
@ -92,7 +104,10 @@ func StructToFormFields(data interface{}) ([]FormField, error) {
numFields := dataType.NumField()
fields := []FormField{}
for i := 0; i < numFields; i++ {
field, err := FieldToFormField(dataType.Field(i), dataValue.FieldByIndex([]int{i}).String())
field, err := FieldToFormField(
dataType.Field(i),
dataValue.FieldByIndex([]int{i}),
)
if err != nil {
return nil, err
}
@ -134,10 +149,10 @@ func (s *Form) Parse(ctx HttpFormData) (interface{}, error) {
file, err := ctx.FormFile(fieldName)
if err != nil {
// If field already has a value, we can ignore the error
if field.Value != "" {
if field.Value != reflect.Zero(field.Value.Type()) {
metaField := dataVal.Elem().FieldByName(fieldName)
if metaField.IsValid() {
metaField.SetString(field.Value)
metaField.SetString(field.Value.String())
}
continue
}
@ -167,7 +182,7 @@ func (s *Form) Parse(ctx HttpFormData) (interface{}, error) {
formValue := ctx.FormValue(fieldName)
metaField := dataVal.Elem().FieldByName(fieldName)
if metaField.IsValid() {
metaField.SetString(formValue)
field.ToWidget().ParseValue(formValue, metaField)
}
}

72
web/forms/widget.go Normal file
View File

@ -0,0 +1,72 @@
package forms
import (
"fmt"
"reflect"
"strings"
)
type Widget interface {
Html() string
ParseValue(value string, output reflect.Value) error
}
type TextWidget struct {
FormField
}
func (s *TextWidget) Html() string {
html := ""
html += fmt.Sprintf("<input type=\"text\" name=\"%v\" value=\"%v\">\n", s.Name, s.Value.String())
return html
}
func (s *TextWidget) ParseValue(value string, output reflect.Value) error {
output.SetString(value)
return nil
}
type TextareaWidget struct {
FormField
}
func (s *TextareaWidget) Html() string {
html := ""
html += fmt.Sprintf("<textarea name=\"%v\" rows=\"20\">%v</textarea>\n", s.Name, s.Value.String())
return html
}
func (s *TextareaWidget) ParseValue(value string, output reflect.Value) error {
output.SetString(value)
return nil
}
type TextListWidget struct {
FormField
}
func (s *TextListWidget) Html() string {
valueList := s.Value.Interface().([]string)
value := strings.Join(valueList, "\n")
html := ""
html += fmt.Sprintf("<textarea name=\"%v\" rows=\"20\">%v</textarea>\n", s.Name, value)
return html
}
func (s *TextListWidget) ParseValue(value string, output reflect.Value) error {
list := strings.Split(value, "\n")
// trim entries
for i, item := range list {
list[i] = strings.TrimSpace(item)
}
// remove empty entries
for i := len(list) - 1; i >= 0; i-- {
if list[i] == "" {
list = append(list[:i], list[i+1:]...)
}
}
output.Set(reflect.ValueOf(list))
return nil
}