diff --git a/components/input/field-binder.go b/components/input/field-binder.go new file mode 100644 index 0000000..cb0b842 --- /dev/null +++ b/components/input/field-binder.go @@ -0,0 +1,169 @@ +package input + +import ( + "fmt" + "strconv" +) + +// FieldBinder is an interface that everything that every type that wants to bind to an input field must implement. +type FieldBinder interface { + String() string // String returns the bound variable formatted in the users/current locale. + SetString(string) error // SetString parses the string value in the users/current locale and sets the value of the bound variable. + HTMLInputType() string // HTMLInputType returns the to be used type parameter for the HTML input element. +} + +// FieldBindAny implements the FieldBinder interface for all basic types. +type FieldBindAny struct{ Value any } + +func (f FieldBindAny) String() string { + switch v := f.Value.(type) { + case *string: + return *v + case *int: + return strconv.FormatInt(int64(*v), 10) + case *int8: + return strconv.FormatInt(int64(*v), 10) + case *int16: + return strconv.FormatInt(int64(*v), 10) + case *int32: + return strconv.FormatInt(int64(*v), 10) + case *int64: + return strconv.FormatInt(int64(*v), 10) + case *uint: + return strconv.FormatUint(uint64(*v), 10) + case *uint8: + return strconv.FormatUint(uint64(*v), 10) + case *uint16: + return strconv.FormatUint(uint64(*v), 10) + case *uint32: + return strconv.FormatUint(uint64(*v), 10) + case *uint64: + return strconv.FormatUint(uint64(*v), 10) + case *float32: + return strconv.FormatFloat(float64(*v), 'f', -1, 32) // TODO: Format number in current user's locale + case *float64: + return strconv.FormatFloat(float64(*v), 'f', -1, 64) + } + + return "" +} + +func (f FieldBindAny) SetString(value string) error { + switch v := f.Value.(type) { + case *string: + *v = value + case *int: + val, err := strconv.ParseInt(value, 10, 0) + if err != nil { + return err + } + *v = int(val) + case *int8: + val, err := strconv.ParseInt(value, 10, 8) + if err != nil { + return err + } + *v = int8(val) + case *int16: + val, err := strconv.ParseInt(value, 10, 16) + if err != nil { + return err + } + *v = int16(val) + case *int32: + val, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + *v = int32(val) + case *int64: + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + *v = int64(val) + case *uint: + val, err := strconv.ParseUint(value, 10, 0) + if err != nil { + return err + } + *v = uint(val) + case *uint8: + val, err := strconv.ParseUint(value, 10, 8) + if err != nil { + return err + } + *v = uint8(val) + case *uint16: + val, err := strconv.ParseUint(value, 10, 16) + if err != nil { + return err + } + *v = uint16(val) + case *uint32: + val, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return err + } + *v = uint32(val) + case *uint64: + val, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return err + } + *v = uint64(val) + case *float32: + val, err := strconv.ParseFloat(value, 32) + if err != nil { + return err + } + *v = float32(val) + case *float64: + val, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *v = float64(val) + default: + return fmt.Errorf("bound type %T is not supported", f.Value) + } + + return nil +} + +func (f FieldBindAny) HTMLInputType() string { + switch f.Value.(type) { + case *string: + return "text" + case *int, *int8, *int16, *int32, *int64, *uint, *uint8, *uint16, *uint32, *uint64: + return "number" + case *float32, *float64: + return "number" + } + + return "text" +} + +// FieldBindPassword implements the FieldBinder interface for strings. +type FieldBindPassword struct{ Value *string } + +func (f FieldBindPassword) String() string { + if f.Value != nil { + return *f.Value + } + + return "" +} + +func (f FieldBindPassword) SetString(value string) error { + if f.Value != nil { + *f.Value = value + return nil + } + + return fmt.Errorf("no value is bound to this component") +} + +func (f FieldBindPassword) HTMLInputType() string { + return "password" +} diff --git a/components/input/field.go b/components/input/field.go index ff15531..17bc7ab 100644 --- a/components/input/field.go +++ b/components/input/field.go @@ -1,13 +1,10 @@ package input import ( - "fmt" - "strconv" - "github.com/vugu/vugu" ) -// Field is a Any text or number based input component. +// Field is a text or number based input component. // The HTML input type is determined by the bound data type. type Field struct { AttrMap vugu.AttrMap @@ -42,165 +39,3 @@ func (c *Field) handleChange(event vugu.DOMEvent) { c.err = c.Bind.SetString(val) } } - -type FieldBinder interface { - String() string // String returns the bound variable formatted in the users/current locale. - SetString(string) error // SetString parses the string value in the users/current locale and sets the value of the bound variable. - HTMLInputType() string // HTMLInputType returns the to be used type parameter for the HTML input element. -} - -// FieldBindAny implements the FieldBinder interface for all basic types. -type FieldBindAny struct{ Value any } - -func (f FieldBindAny) String() string { - switch v := f.Value.(type) { - case *string: - return *v - case *int: - return strconv.FormatInt(int64(*v), 10) - case *int8: - return strconv.FormatInt(int64(*v), 10) - case *int16: - return strconv.FormatInt(int64(*v), 10) - case *int32: - return strconv.FormatInt(int64(*v), 10) - case *int64: - return strconv.FormatInt(int64(*v), 10) - case *uint: - return strconv.FormatUint(uint64(*v), 10) - case *uint8: - return strconv.FormatUint(uint64(*v), 10) - case *uint16: - return strconv.FormatUint(uint64(*v), 10) - case *uint32: - return strconv.FormatUint(uint64(*v), 10) - case *uint64: - return strconv.FormatUint(uint64(*v), 10) - case *float32: - return strconv.FormatFloat(float64(*v), 'f', -1, 32) // TODO: Format number in current user's locale - case *float64: - return strconv.FormatFloat(float64(*v), 'f', -1, 64) - } - - return "" -} - -func (f FieldBindAny) SetString(value string) error { - switch v := f.Value.(type) { - case *string: - *v = value - case *int: - val, err := strconv.ParseInt(value, 10, 0) - if err != nil { - return err - } - *v = int(val) - case *int8: - val, err := strconv.ParseInt(value, 10, 8) - if err != nil { - return err - } - *v = int8(val) - case *int16: - val, err := strconv.ParseInt(value, 10, 16) - if err != nil { - return err - } - *v = int16(val) - case *int32: - val, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return err - } - *v = int32(val) - case *int64: - val, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - *v = int64(val) - case *uint: - val, err := strconv.ParseUint(value, 10, 0) - if err != nil { - return err - } - *v = uint(val) - case *uint8: - val, err := strconv.ParseUint(value, 10, 8) - if err != nil { - return err - } - *v = uint8(val) - case *uint16: - val, err := strconv.ParseUint(value, 10, 16) - if err != nil { - return err - } - *v = uint16(val) - case *uint32: - val, err := strconv.ParseUint(value, 10, 32) - if err != nil { - return err - } - *v = uint32(val) - case *uint64: - val, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - *v = uint64(val) - case *float32: - val, err := strconv.ParseFloat(value, 32) - if err != nil { - return err - } - *v = float32(val) - case *float64: - val, err := strconv.ParseFloat(value, 64) - if err != nil { - return err - } - *v = float64(val) - default: - return fmt.Errorf("bound type %T is not supported", f.Value) - } - - return nil -} - -func (f FieldBindAny) HTMLInputType() string { - switch f.Value.(type) { - case *string: - return "text" - case *int, *int8, *int16, *int32, *int64, *uint, *uint8, *uint16, *uint32, *uint64: - return "number" - case *float32, *float64: - return "number" - } - - return "text" -} - -// FieldBindPassword implements the FieldBinder interface for strings. -type FieldBindPassword struct{ Value *string } - -func (f FieldBindPassword) String() string { - if f.Value != nil { - return *f.Value - } - - return "" -} - -func (f FieldBindPassword) SetString(value string) error { - if f.Value != nil { - *f.Value = value - return nil - } - - return fmt.Errorf("no value is bound to this component") -} - -func (f FieldBindPassword) HTMLInputType() string { - return "password" -}