From 1caa4b6de51617b68342eaae921b1afb5a734c4a Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 27 Nov 2017 18:04:28 +0100 Subject: [PATCH] Improved EditForm --- styles/widgets.scarlet | 7 ++- utils/editform/editform.go | 89 ++++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 29 deletions(-) diff --git a/styles/widgets.scarlet b/styles/widgets.scarlet index 30e39289..38f70ab7 100644 --- a/styles/widgets.scarlet +++ b/styles/widgets.scarlet @@ -31,7 +31,7 @@ width 100% .widget-title - text-align left + horizontal padding-bottom 0.5rem border-bottom 1px solid rgba(0, 0, 0, 0.1) // We need !important here to overwrite the h3:first-child rule @@ -56,4 +56,7 @@ .widget-form width 100% max-width 650px - margin 0 auto \ No newline at end of file + margin 0 auto + +.indent + margin-left 1rem \ No newline at end of file diff --git a/utils/editform/editform.go b/utils/editform/editform.go index a467ed25..a089c2d3 100644 --- a/utils/editform/editform.go +++ b/utils/editform/editform.go @@ -60,10 +60,16 @@ func Render(obj interface{}, title string, user *arn.User) string { return b.String() } -// RenderObject ... +// RenderObject renders the UI for the object into the bytes buffer and appends an ID prefix for all API requests. +// The ID prefix should either be empty or end with a dot character. func RenderObject(b *bytes.Buffer, obj interface{}, idPrefix string) { - t := reflect.TypeOf(obj).Elem() - v := reflect.ValueOf(obj).Elem() + t := reflect.TypeOf(obj) + v := reflect.ValueOf(obj) + + if t.Kind() == reflect.Ptr { + t = t.Elem() + v = v.Elem() + } // Fields for i := 0; i < t.NumField(); i++ { @@ -79,9 +85,10 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i } fieldValue := reflect.Indirect(v.FieldByName(field.Name)) + fieldType := field.Type.String() - switch field.Type.String() { - case "string": + // String + if fieldType == "string" { if field.Tag.Get("datalist") != "" { dataList := field.Tag.Get("datalist") values := arn.DataLists[dataList] @@ -91,16 +98,48 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i } else { b.WriteString(components.InputText(idPrefix+field.Name, fieldValue.String(), field.Name, field.Tag.Get("tooltip"))) } - case "[]string": - b.WriteString(components.InputTags(idPrefix+field.Name, fieldValue.Interface().([]string), field.Name, field.Tag.Get("tooltip"))) - case "bool": + + return + } + + // Bool + if fieldType == "bool" { if field.Name == "IsDraft" { return } - case "[]*arn.ExternalMedia", "[]*arn.Link": + + // TODO: Render bool type + return + } + + // Array of strings + if fieldType == "[]string" { + b.WriteString(components.InputTags(idPrefix+field.Name, fieldValue.Interface().([]string), field.Name, field.Tag.Get("tooltip"))) + return + } + + // Any kind of array + if strings.HasPrefix(fieldType, "[]") { + b.WriteString(`
`) + b.WriteString(`

`) + b.WriteString(field.Name) + b.WriteString(`

`) + for sliceIndex := 0; sliceIndex < fieldValue.Len(); sliceIndex++ { b.WriteString(`
`) - b.WriteString(`
` + strconv.Itoa(sliceIndex+1) + ". " + field.Name + `
`) + + b.WriteString(`
`) + + // Title + b.WriteString(strconv.Itoa(sliceIndex+1) + ". " + field.Name) + b.WriteString(`
`) + + // Remove button + b.WriteString(``) + + b.WriteString(`
`) arrayObj := fieldValue.Index(sliceIndex).Interface() arrayIDPrefix := fmt.Sprintf("%s[%d].", field.Name, sliceIndex) @@ -109,15 +148,10 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i // Preview // elementValue := fieldValue.Index(sliceIndex) // RenderArrayElement(b, &elementValue) - if field.Type.String() == "[]*arn.ExternalMedia" { + if fieldType == "[]*arn.ExternalMedia" { b.WriteString(components.ExternalMedia(fieldValue.Index(sliceIndex).Interface().(*arn.ExternalMedia))) } - // Remove button - b.WriteString(`
`) - b.WriteString(`
`) } @@ -125,17 +159,18 @@ func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, i b.WriteString(``) b.WriteString(`
`) - case "arn.CompanyName": - b.WriteString(`
`) - b.WriteString(`
` + field.Name + `
`) - - for i := 0; i < field.Type.NumField(); i++ { - subField := field.Type.Field(i) - RenderField(b, &fieldValue, subField, field.Name+".") - } - b.WriteString(`
`) - default: - panic("No edit form implementation for " + idPrefix + field.Name + " with type " + field.Type.String()) + return } + + // Any custom field type will be recursively rendered via another RenderObject call + b.WriteString(`
`) + b.WriteString(`

` + field.Name + `

`) + + // Indent the fields + b.WriteString(`
`) + RenderObject(b, fieldValue.Interface(), field.Name+".") + b.WriteString(`
`) + + b.WriteString(`
`) }