func GetEmbedEditable(ctx context.Context, node *node.Node, embed *system.Reference) (editable.Editable, error) { if node == nil || node.Null || node.Missing { return nil, nil } if *node.Type.Id == *embed { return GetEditable(ctx, node), nil } jcache := jsonctx.FromContext(ctx) nf, df, ok := jcache.GetNewFunc(embed.Package, embed.Name) if !ok { return nil, kerr.New("DGWDERFPVV", "Can't find %s in jsonctx", embed.String()) } t := reflect.TypeOf(nf()) if df != nil { t = t.Elem() } v := node.Val for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { v = v.Elem() } var field reflect.Value for i := 0; i < v.Type().NumField(); i++ { f := v.Type().Field(i) if f.Anonymous && f.Type == t { field = v.Field(i) break } } if field == (reflect.Value{}) { return nil, kerr.New("UDBOWYUBER", "Can't find %s field in struct", t) } // This is the recommended method of presenting an custom editor. if ed, ok := field.Interface().(editable.Editable); ok { return ed, nil } editors := clientctx.FromContext(ctx) // Don't do this. Implement the Editable interface instead. We can't do this // for system types so we use this method instead. if e, ok := editors.Get(embed.String()); ok { return e, nil } return nil, nil }
func NewStructFragmentView(ctx context.Context, node *node.Node, origin *system.Reference) *StructFragmentView { v := &StructFragmentView{} v.View = New(ctx, v) v.model = v.App.Editors.Get(node) v.origin = origin if ti, ok := sysctx.FromContext(ctx).GetType(origin.Package, origin.Name); ok { v.originType = ti.(*system.Type) } else { v.App.Fail <- kerr.New("DNMXCJXNVU", "Type %s not found in system context", origin.String()) return nil } return v }
func extractType(ctx context.Context, in system.Packed, rule *system.RuleWrapper) (*system.Type, error) { parentInterface := rule != nil && rule.Parent != nil && rule.Parent.Interface ruleInterface := rule != nil && rule.Struct != nil && rule.Struct.Interface if parentInterface && ruleInterface { return nil, kerr.New("TDXTPGVFAK", "Can't have interface type and interface rule at the same time") } if rule != nil && rule.Parent != nil && !parentInterface && !ruleInterface { // If we have a rule with the parent, and it's not an interface, then // we just return the parent type of the rule. return rule.Parent, nil } // if the rule is nil (e.g. unpacking into an unknown type) or the type is // an interface, we ensure the input is a map if rule == nil || parentInterface { if in == nil { return nil, nil } switch in.Type() { case system.J_NULL: // item is nil, so we don't know the concrete type yet. return nil, nil case system.J_MAP: break default: return nil, kerr.New("DLSQRFLINL", "Input %s should be J_MAP if rule is nil or an interface type", in.Type()) } } // if the rule is an interface rule, we ensure the input is a map or a native value if ruleInterface { if in == nil { return nil, nil } switch in.Type() { case system.J_NULL: // item is nil, so we don't know the concrete type yet. return nil, nil case system.J_MAP: break case system.J_STRING, system.J_NUMBER, system.J_BOOL: // if the input value is a native value, we will be unpacking into // the parent type of the rule return rule.Parent, nil default: return nil, kerr.New("SNYLGBJYTM", "Input %s should be J_MAP, J_STRING, J_NUMBER or J_BOOL if rule is interface rule", in.Type()) } } ob := in.Map() typeField, ok := ob["type"] if !ok { return nil, kerr.New("HBJVDKAKBJ", "Input must have type field if rule is nil or an interface type") } var r system.Reference if err := r.Unpack(ctx, typeField, false); err != nil { return nil, kerr.Wrap("YXHGIBXCOC", err) } t, ok := r.GetType(ctx) if !ok { return nil, kerr.New("IJFMJJWVCA", "Could not find type %s", r.Value()) } return t, nil }