123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- package presets
- import (
- "fmt"
- "path/filepath"
- "reflect"
- "time"
- "github.com/iancoleman/strcase"
- . "github.com/qor5/ui/vuetify"
- "github.com/qor5/ui/vuetifyx"
- "github.com/qor5/web"
- "github.com/qor5/x/i18n"
- "github.com/sunfmin/reflectutils"
- h "github.com/theplant/htmlgo"
- )
- type FieldDefaultBuilder struct {
- valType reflect.Type
- compFunc FieldComponentFunc
- setterFunc FieldSetterFunc
- }
- type FieldMode int
- const (
- WRITE FieldMode = iota
- LIST
- DETAIL
- )
- func NewFieldDefault(t reflect.Type) (r *FieldDefaultBuilder) {
- r = &FieldDefaultBuilder{valType: t}
- return
- }
- func (b *FieldDefaultBuilder) ComponentFunc(v FieldComponentFunc) (r *FieldDefaultBuilder) {
- b.compFunc = v
- return b
- }
- func (b *FieldDefaultBuilder) SetterFunc(v FieldSetterFunc) (r *FieldDefaultBuilder) {
- b.setterFunc = v
- return b
- }
- var numberVals = []interface{}{
- int(0), int8(0), int16(0), int32(0), int64(0),
- uint(0), uint(8), uint16(0), uint32(0), uint64(0),
- float32(0.0), float64(0.0),
- }
- var stringVals = []interface{}{
- string(""),
- []rune(""),
- []byte(""),
- }
- var timeVals = []interface{}{
- time.Now(),
- ptrTime(time.Now()),
- }
- type FieldDefaults struct {
- mode FieldMode
- fieldTypes []*FieldDefaultBuilder
- excludesPatterns []string
- }
- func NewFieldDefaults(t FieldMode) (r *FieldDefaults) {
- r = &FieldDefaults{
- mode: t,
- }
- r.builtInFieldTypes()
- return
- }
- func (b *FieldDefaults) FieldType(v interface{}) (r *FieldDefaultBuilder) {
- return b.fieldTypeByTypeOrCreate(reflect.TypeOf(v))
- }
- func (b *FieldDefaults) Exclude(patterns ...string) (r *FieldDefaults) {
- b.excludesPatterns = patterns
- return b
- }
- func (b *FieldDefaults) InspectFields(val interface{}) (r *FieldsBuilder) {
- r, _ = b.inspectFieldsAndCollectName(val, nil)
- r.Model(val)
- return
- }
- func (b *FieldDefaults) inspectFieldsAndCollectName(val interface{}, collectType reflect.Type) (r *FieldsBuilder, names []string) {
- v := reflect.ValueOf(val)
- for v.Elem().Kind() == reflect.Ptr {
- v = v.Elem()
- }
- v = v.Elem()
- t := v.Type()
- r = &FieldsBuilder{
- model: val,
- }
- r.Defaults(b)
- for i := 0; i < t.NumField(); i++ {
- f := t.Field(i)
- ft := b.fieldTypeByType(f.Type)
- if !hasMatched(b.excludesPatterns, f.Name) && ft != nil {
- r.Field(f.Name).
- ComponentFunc(ft.compFunc).
- SetterFunc(ft.setterFunc)
- }
- if collectType != nil && f.Type == collectType {
- names = append(names, strcase.ToSnake(f.Name))
- }
- }
- return
- }
- func hasMatched(patterns []string, name string) bool {
- for _, p := range patterns {
- ok, err := filepath.Match(p, name)
- if err != nil {
- panic(err)
- }
- if ok {
- return true
- }
- }
- return false
- }
- func (b *FieldDefaults) String() string {
- var types []string
- for _, t := range b.fieldTypes {
- types = append(types, fmt.Sprint(t.valType))
- }
- return fmt.Sprintf("mode: %d, types %v", b.mode, types)
- }
- func (b *FieldDefaults) fieldTypeByType(tv reflect.Type) (r *FieldDefaultBuilder) {
- for _, ft := range b.fieldTypes {
- if ft.valType == tv {
- return ft
- }
- }
- return nil
- }
- func (b *FieldDefaults) fieldTypeByTypeOrCreate(tv reflect.Type) (r *FieldDefaultBuilder) {
- if r = b.fieldTypeByType(tv); r != nil {
- return
- }
- r = NewFieldDefault(tv)
- if b.mode == LIST {
- r.ComponentFunc(cfTextTd)
- } else {
- r.ComponentFunc(cfTextField)
- }
- b.fieldTypes = append(b.fieldTypes, r)
- return
- }
- func cfTextTd(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return h.Td(h.Text(field.StringValue(obj)))
- }
- func cfCheckbox(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return VCheckbox().
- FieldName(field.FormKey).
- Label(field.Label).
- InputValue(reflectutils.MustGet(obj, field.Name).(bool)).
- ErrorMessages(field.Errors...).
- Disabled(field.Disabled)
- }
- func cfNumber(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return VTextField().
- Type("number").
- FieldName(field.FormKey).
- Label(field.Label).
- Value(fmt.Sprint(reflectutils.MustGet(obj, field.Name))).
- ErrorMessages(field.Errors...).
- Disabled(field.Disabled)
- }
- func cfTime(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- msgr := i18n.MustGetModuleMessages(ctx.R, CoreI18nModuleKey, Messages_en_US).(*Messages)
- val := ""
- if v := field.Value(obj); v != nil {
- switch vt := v.(type) {
- case time.Time:
- val = vt.Format("2006-01-02 15:04")
- case *time.Time:
- val = vt.Format("2006-01-02 15:04")
- default:
- panic(fmt.Sprintf("unknown time type: %T\n", v))
- }
- }
- return vuetifyx.VXDateTimePicker().
- Label(field.Label).
- FieldName(field.FormKey).
- Value(val).
- TimePickerProps(vuetifyx.TimePickerProps{
- Format: "24hr",
- Scrollable: true,
- }).
- ClearText(msgr.Clear).
- OkText(msgr.OK)
- }
- func cfTimeSetter(obj interface{}, field *FieldContext, ctx *web.EventContext) (err error) {
- v := ctx.R.Form.Get(field.FormKey)
- if v == "" {
- return reflectutils.Set(obj, field.Name, nil)
- }
- t, err := time.ParseInLocation("2006-01-02 15:04", v, time.Local)
- if err != nil {
- return err
- }
- return reflectutils.Set(obj, field.Name, t)
- }
- func cfTextField(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return VTextField().
- Type("text").
- FieldName(field.FormKey).
- Label(field.Label).
- Value(fmt.Sprint(reflectutils.MustGet(obj, field.Name))).
- ErrorMessages(field.Errors...).
- Disabled(field.Disabled)
- }
- func cfReadonlyText(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return vuetifyx.VXReadonlyField().
- Label(field.Label).
- Value(field.StringValue(obj))
- }
- func cfReadonlyCheckbox(obj interface{}, field *FieldContext, ctx *web.EventContext) h.HTMLComponent {
- return vuetifyx.VXReadonlyField().
- Label(field.Label).
- Value(reflectutils.MustGet(obj, field.Name)).
- Checkbox(true)
- }
- func (b *FieldDefaults) builtInFieldTypes() {
- if b.mode == LIST {
- b.FieldType(true).
- ComponentFunc(cfTextTd)
- for _, v := range numberVals {
- b.FieldType(v).
- ComponentFunc(cfTextTd)
- }
- for _, v := range stringVals {
- b.FieldType(v).
- ComponentFunc(cfTextTd)
- }
- return
- }
- if b.mode == DETAIL {
- b.FieldType(true).
- ComponentFunc(cfReadonlyCheckbox)
- for _, v := range numberVals {
- b.FieldType(v).
- ComponentFunc(cfReadonlyText)
- }
- for _, v := range stringVals {
- b.FieldType(v).
- ComponentFunc(cfReadonlyText)
- }
- return
- }
- b.FieldType(true).
- ComponentFunc(cfCheckbox)
- for _, v := range numberVals {
- b.FieldType(v).
- ComponentFunc(cfNumber)
- }
- for _, v := range stringVals {
- b.FieldType(v).
- ComponentFunc(cfTextField)
- }
- for _, v := range timeVals {
- b.FieldType(v).
- ComponentFunc(cfTime).
- SetterFunc(cfTimeSetter)
- }
- b.Exclude("ID")
- return
- }
|