From 74760707dda9d354369bc87df9da4ed1b349f9e9 Mon Sep 17 00:00:00 2001 From: Niko Abeler Date: Sat, 5 Aug 2023 21:24:26 +0200 Subject: [PATCH] start refactoring forms. Allow list for recipe ingredients --- entry_types/recipe.go | 2 +- render/templates/entry/Recipe.tmpl | 27 +++++++++++ web/forms/form.go | 33 ++++++++++---- web/forms/widget.go | 72 ++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 render/templates/entry/Recipe.tmpl create mode 100644 web/forms/widget.go diff --git a/entry_types/recipe.go b/entry_types/recipe.go index 20b0a87..d6c8a51 100644 --- a/entry_types/recipe.go +++ b/entry_types/recipe.go @@ -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"` } diff --git a/render/templates/entry/Recipe.tmpl b/render/templates/entry/Recipe.tmpl new file mode 100644 index 0000000..def1d17 --- /dev/null +++ b/render/templates/entry/Recipe.tmpl @@ -0,0 +1,27 @@ + + {{ if .MetaData.Yield }} + Servings: {{ .MetaData.Yield }} + {{ if .MetaData.Duration }}, {{end}} + + {{ end }} + + {{ if .MetaData.Duration }} + Prep Time: + {{ end }} + +

+ +

Ingredients

+ + + +

Instructions

+{{.MetaData.Content | markdown }} diff --git a/web/forms/form.go b/web/forms/form.go index 398a081..5eae1ba 100644 --- a/web/forms/form.go +++ b/web/forms/form.go @@ -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("\n", s.Name, s.Name) - if s.Params.InputType == "text" && s.Params.Widget == "textarea" { - html += fmt.Sprintf("\n", s.Name, s.Name, s.Value) - } else { + if s.Params.InputType == "file" { html += fmt.Sprintf("\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) } } diff --git a/web/forms/widget.go b/web/forms/widget.go new file mode 100644 index 0000000..af010e2 --- /dev/null +++ b/web/forms/widget.go @@ -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("\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("\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("\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 +}