package editform import ( "bytes" "fmt" "reflect" "strconv" "strings" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" ) // Render renders a generic editing UI for any kind of datatype that has an ID. func Render(obj interface{}, title string, user *arn.User) string { t := reflect.TypeOf(obj).Elem() v := reflect.ValueOf(obj).Elem() id := findMainID(t, v) lowerCaseTypeName := strings.ToLower(t.Name()) endpoint := `/api/` + lowerCaseTypeName + `/` + id.String() var b bytes.Buffer b.WriteString(`
") return b.String() } // 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) v := reflect.ValueOf(obj) if t.Kind() == reflect.Ptr { t = t.Elem() v = v.Elem() } // Fields for i := 0; i < t.NumField(); i++ { field := t.Field(i) RenderField(b, &v, field, idPrefix) } } // RenderField ... func RenderField(b *bytes.Buffer, v *reflect.Value, field reflect.StructField, idPrefix string) { if field.Anonymous || field.Tag.Get("editable") != "true" { return } fieldValue := reflect.Indirect(v.FieldByName(field.Name)) fieldType := field.Type.String() // String if fieldType == "string" { idType := field.Tag.Get("idType") // Try to infer the ID type by the field name if idType == "" { switch field.Name { case "AnimeID": idType = "Anime" case "CharacterID": idType = "Character" } } showPreview := idType != "" && fieldValue.String() != "" if showPreview { b.WriteString(" ") } return } // Int if fieldType == "int" { b.WriteString(components.InputNumber(idPrefix+field.Name, float64(fieldValue.Int()), field.Name, field.Tag.Get("tooltip"), "", "", "1")) return } // Float if fieldType == "float64" { b.WriteString(components.InputNumber(idPrefix+field.Name, fieldValue.Float(), field.Name, field.Tag.Get("tooltip"), "", "", "")) return } // Bool if fieldType == "bool" { if field.Name == "IsDraft" { return } // 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(` `) return } // Any custom field type will be recursively rendered via another RenderObject call b.WriteString(` `) } // findMainID finds the main ID of the object. func findMainID(t reflect.Type, v reflect.Value) reflect.Value { idField := v.FieldByName("ID") if idField.IsValid() { return reflect.Indirect(idField) } for i := 0; i < t.NumField(); i++ { field := t.Field(i) if field.Tag.Get("mainID") == "true" { return reflect.Indirect(v.Field(i)) } } panic("Type " + t.Name() + " doesn't have a main ID!") }