David Vogel
a587fea398
- Rename FieldBinder to ValueBinder - Split ValueBinder interface into ValueGetter, ValueSetter and HTMLInputTyper - Add non pointer types to ValueBindAny.StringValue - Move encoding.TextMarshaler in type switch - Simplify ListBinder, and reuse ValueBinder logic - Add ListBindGenericValues type
113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package input
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
// ListBinder describes an interface that simple lists can implement to be compatible with list based UI components.
|
|
type ListBinder interface {
|
|
ListKeyValuePairs() []ListKeyValuePair
|
|
ListDeleteKey(key string) bool // Removes the entry with the given key, and returns true if it got deleted successfully.
|
|
ListAddKeyValuePair(key, value string) error // Adds the key value pair to the list.
|
|
ListLen() int // Returns the length of the list.
|
|
}
|
|
|
|
type ListKeyValuePair struct {
|
|
Key, Value string
|
|
}
|
|
|
|
// ListBindGenericSlice implements ListBinder for slices that are of some arbitrary type.
|
|
//
|
|
// List keys will be bound to slice indices, and list values will be bound to a string representation of the slice elements.
|
|
type ListBindGenericSlice[T any] struct {
|
|
Slice *[]T
|
|
}
|
|
|
|
func (l ListBindGenericSlice[T]) ListKeyValuePairs() []ListKeyValuePair {
|
|
if l.Slice == nil {
|
|
return nil
|
|
}
|
|
|
|
result := make([]ListKeyValuePair, 0, len(*l.Slice))
|
|
for i, entry := range *l.Slice {
|
|
str := ValueBindAny{entry}.StringValue()
|
|
result = append(result, ListKeyValuePair{Key: strconv.Itoa(i), Value: str})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (l ListBindGenericSlice[T]) ListDeleteKey(key string) bool {
|
|
if l.Slice == nil {
|
|
return false
|
|
}
|
|
|
|
index, err := strconv.Atoi(key)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
if index < 0 || index >= len(*l.Slice) {
|
|
return false
|
|
}
|
|
|
|
*l.Slice = slices.Delete(*l.Slice, index, index+1)
|
|
return true
|
|
}
|
|
|
|
func (l ListBindGenericSlice[T]) ListAddKeyValuePair(key, value string) error {
|
|
index, err := strconv.Atoi(key)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse index: %w", err)
|
|
}
|
|
|
|
if index < 0 || index > len(*l.Slice) {
|
|
return fmt.Errorf("index %d out of bounds", index)
|
|
}
|
|
|
|
var val T
|
|
if err := (ValueBindAny{&val}).SetStringValue(value); err != nil {
|
|
return err
|
|
}
|
|
|
|
*l.Slice = slices.Insert(*l.Slice, index, val)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l ListBindGenericSlice[T]) ListLen() int {
|
|
return len(*l.Slice)
|
|
}
|
|
|
|
// ListBindGenericValues implements ListBinder for slices that are of some arbitrary type.
|
|
//
|
|
// List keys and values will be bound to the string representation of the slice elements.
|
|
//
|
|
// This is useful for dropdown components, as the key of the selected element will be set to the bound value.
|
|
//
|
|
// This can not modify the bound list.
|
|
type ListBindGenericValues[T any] []T
|
|
|
|
func (l ListBindGenericValues[T]) ListKeyValuePairs() []ListKeyValuePair {
|
|
result := make([]ListKeyValuePair, 0, len(l))
|
|
for _, entry := range l {
|
|
str := ValueBindAny{entry}.StringValue()
|
|
result = append(result, ListKeyValuePair{Key: str, Value: str})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (l ListBindGenericValues[T]) ListDeleteKey(key string) bool {
|
|
return false
|
|
}
|
|
|
|
func (l ListBindGenericValues[T]) ListAddKeyValuePair(key, value string) error {
|
|
return fmt.Errorf("the list binder doesn't support list modifications")
|
|
}
|
|
|
|
func (l ListBindGenericValues[T]) ListLen() int {
|
|
return len(l)
|
|
}
|