mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 21:31:56 +01:00
Moved Vuex bindings 'mvue' to external repo
This commit is contained in:
parent
04c6f0d397
commit
286b8b9b46
@ -1,109 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"reflect"
|
||||
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func wrapGoActionFunc(reflectedGoFunc reflect.Value ) (jsFunc *js.Object, err error) {
|
||||
|
||||
numGoArgs := reflectedGoFunc.Type().NumIn() //Number of arguments of the Go target method
|
||||
if numGoArgs < 3 || numGoArgs > 4{
|
||||
return nil, eWrongActionArgCount
|
||||
}
|
||||
// Check if first arg 0 is of type *Store
|
||||
if arg := reflectedGoFunc.Type().In(0); arg.Kind() != reflect.Ptr || arg.Elem() != jsStoreType {
|
||||
return nil, eWrongFirstActionArg
|
||||
}
|
||||
// Check if first arg 1 is of type *ActionContext
|
||||
if arg := reflectedGoFunc.Type().In(1); arg.Kind() != reflect.Ptr || arg.Elem() != jsActioContextType {
|
||||
return nil, eWrongSecondActionArg
|
||||
}
|
||||
//Check if the remaining args are pointers to structs with *js.Object as first field
|
||||
for i := 2; i < numGoArgs; i++ {
|
||||
if arg:=reflectedGoFunc.Type().In(i); arg.Kind() != reflect.Ptr || !checkIfJSStruct(arg.Elem()) {
|
||||
return nil, errors.New("Arg at position " + strconv.Itoa(i) +" isn't a pointer to a struct with *js.Object in first field")
|
||||
}
|
||||
}
|
||||
|
||||
goCallArgTargetTypes := make([]reflect.Type, numGoArgs) //store handler parameter types in slice
|
||||
for i := 0; i < reflectedGoFunc.Type().NumIn(); i++ { goCallArgTargetTypes[i] = reflectedGoFunc.Type().In(i) }
|
||||
|
||||
goCallArgsTargetValues := make([]reflect.Value,numGoArgs) //create a slice for the parameter values, used in the call to the Go function
|
||||
|
||||
|
||||
jsFunc = js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} {
|
||||
// this: points to the store
|
||||
// arg0: points to a context representation of the store
|
||||
// arg1: point to an optional argument for the action (undefined otherwise)
|
||||
|
||||
// argument passing to the handler
|
||||
// goHandler(store *Store, context *ActionContext, state *{CustomStateType} [, callArg *{CustomArgType])
|
||||
// --> the store is the root store of Vuex (the handler should use the context instead)
|
||||
// --> the context is a representation of the store, dedicated for this action (async access)
|
||||
// --> == context.State, but casted to the Go type presented by the handler function
|
||||
// --> (optional) in case the handler function takes an additional argument, arg1 from the JS call will be casted to this
|
||||
|
||||
/*
|
||||
println("Action this:", this)
|
||||
println("Action args:", arguments)
|
||||
//Globalize args (context) for investigation
|
||||
js.Global.Set("actionargs", arguments)
|
||||
*/
|
||||
|
||||
storeVal,err := castToType(goCallArgTargetTypes[0], this) //cast 'this' to type of first function arg (type = *Store)
|
||||
if err != nil { panic("Error converting JavaScript provided 'this' for action function to *Store: " + err.Error()) }
|
||||
goCallArgsTargetValues[0] = storeVal
|
||||
|
||||
contextVal,err := castToType(goCallArgTargetTypes[1], arguments[0]) //cast arg0 to type of second function arg (type = *ActionContext)
|
||||
if err != nil { panic("Error converting JavaScript provided first argument for action function to *ActionContext: " + err.Error()) }
|
||||
goCallArgsTargetValues[1] = contextVal
|
||||
|
||||
//extract state from context, in order to cast it to the provided type
|
||||
jsStateObj := arguments[0].Get("state")
|
||||
stateVal,err := castToType(goCallArgTargetTypes[2], jsStateObj) //cast 'context.state' to type of third function arg
|
||||
if err != nil { panic("Error converting JavaScript provided context.state for action function to *" + goCallArgTargetTypes[2].Elem().Name() + ": " + err.Error()) }
|
||||
goCallArgsTargetValues[2] = stateVal
|
||||
|
||||
//Check if handler receives 4th arg
|
||||
if numGoArgs == 4 {
|
||||
// check if argument 1 is provided by JS
|
||||
if arguments[1] == js.Undefined {
|
||||
panic("The action handler awaits an argument of type " + goCallArgTargetTypes[3].Name() + " but the dispatched action doesn't provide this parameter")
|
||||
}
|
||||
|
||||
// try to convert to target type
|
||||
actionParamVal,err := castToType(goCallArgTargetTypes[3], arguments[1])
|
||||
if err != nil { panic("Error converting JavaScript provided optional parameter for action function to *" + goCallArgTargetTypes[3].Elem().Name() + ": " + err.Error()) }
|
||||
goCallArgsTargetValues[3] = actionParamVal
|
||||
}
|
||||
|
||||
// Call the go function and return the result
|
||||
return reflectedGoFunc.Call(goCallArgsTargetValues)
|
||||
})
|
||||
|
||||
return jsFunc, nil
|
||||
}
|
||||
|
||||
|
||||
func Action(name string, goFunc interface{}) StoreOption {
|
||||
return func(c *StoreConfig) {
|
||||
//println("Creating ACTION FUNC")
|
||||
if c.Actions == js.Undefined { c.Actions = o() }
|
||||
|
||||
reflectedGoFunc := reflect.ValueOf(goFunc)
|
||||
if reflectedGoFunc.Kind() != reflect.Func { //check if the provided interface is a go function
|
||||
panic("Action " + name + " is not a func")
|
||||
}
|
||||
|
||||
//try to convert the provided function to a JavaScript function usable as Mutation
|
||||
jsFunc, err := wrapGoActionFunc(reflectedGoFunc)
|
||||
if err != nil {panic("Error exposing the action function '"+ name + "' to JavaScript: " + err.Error())}
|
||||
|
||||
c.Actions.Set(name, jsFunc)
|
||||
//c.Mutations.Set(name, makeMethod(name, false, reflectGoFunc.Type(), reflectGoFunc))
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
import "github.com/gopherjs/gopherjs/js"
|
||||
|
||||
// Actions use a context instead of the store itself: https://vuex.vuejs.org/guide/actions.html
|
||||
type ActionContext struct { //Don't use Context as name to avoid conflicts
|
||||
*js.Object
|
||||
|
||||
Getters *js.Object `js:"getters"`
|
||||
Commit func(...interface{}) *js.Object `js:"commit"`
|
||||
Dispatch func(...interface{}) *js.Object `js:"dispatch"`
|
||||
State *js.Object `js:"state"`
|
||||
RootGetters *js.Object `js:"rootGetters"`
|
||||
RootState *js.Object `js:"rootState"`
|
||||
|
||||
}
|
||||
|
@ -1,117 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
//ToDo: check for Vuex in js.Global scope and panic if missing
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"reflect"
|
||||
"errors"
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
eTooFewMutationArgs = errors.New("Mutation function has too few arguments (min 2)")
|
||||
eTooManyMutationArgs = errors.New("Mutation function has too many arguments (max 3)")
|
||||
eWrongActionArgCount = errors.New("Wrong argument count! An action handler takes 3 or 4 args: actionHandler(store *Store, context *ActionContext, state *{CustomStateType} [, callArg *{CustomArgType])")
|
||||
eTooFewMutationArgsOnCall = errors.New("Mutation function called with too few arguments from JavaScrip")
|
||||
eWrongFirstMutationArg = errors.New("Mutation function has to have *Store as first argument type")
|
||||
eWrongFirstActionArg = errors.New("Mutation function has to have *Store as first argument type")
|
||||
eWrongSecondActionArg = errors.New("Mutation function has to have *ActionContext as second argument type")
|
||||
eWrongSecondMutationArg = errors.New("The second argument of the mutation function has to be a pointer to a struct of the type used for state")
|
||||
eFirstFieldIsNotPtrJsObject = errors.New("The first field of the struct has to be of type *js.Object")
|
||||
|
||||
|
||||
jsObjectType = reflect.TypeOf(js.Object{})
|
||||
jsStoreType = reflect.TypeOf(Store{})
|
||||
jsActioContextType = reflect.TypeOf(ActionContext{})
|
||||
)
|
||||
|
||||
|
||||
func o() *js.Object { return js.Global.Get("Object").New() } //Helper to create *js.Object
|
||||
|
||||
|
||||
func castToType(targetType reflect.Type, sourceVal *js.Object) (result reflect.Value, err error) {
|
||||
|
||||
switch kind := targetType.Kind(); kind {
|
||||
case reflect.Int:
|
||||
//try to convert sourceVal to int before generating reflect.Value
|
||||
result = reflect.ValueOf(sourceVal.Int())
|
||||
case reflect.Int8:
|
||||
result = reflect.ValueOf(int8(sourceVal.Int64()))
|
||||
case reflect.Int16:
|
||||
result = reflect.ValueOf(int16(sourceVal.Int64()))
|
||||
case reflect.Int32:
|
||||
result = reflect.ValueOf(int32(sourceVal.Int64()))
|
||||
case reflect.Int64:
|
||||
result = reflect.ValueOf(sourceVal.Int64())
|
||||
case reflect.Float64:
|
||||
result = reflect.ValueOf(sourceVal.Float())
|
||||
case reflect.Float32:
|
||||
result = reflect.ValueOf(float32(sourceVal.Float()))
|
||||
case reflect.Bool:
|
||||
result = reflect.ValueOf(sourceVal.Bool())
|
||||
case reflect.Uint:
|
||||
result = reflect.ValueOf(uint(sourceVal.Uint64()))
|
||||
case reflect.Uint64:
|
||||
result = reflect.ValueOf(sourceVal.Uint64())
|
||||
case reflect.Uint32:
|
||||
result = reflect.ValueOf(uint32(sourceVal.Uint64()))
|
||||
case reflect.Uint16:
|
||||
result = reflect.ValueOf(uint16(sourceVal.Uint64()))
|
||||
case reflect.Uint8:
|
||||
result = reflect.ValueOf(uint8(sourceVal.Uint64()))
|
||||
case reflect.Uintptr:
|
||||
result = reflect.ValueOf(sourceVal.Unsafe())
|
||||
case reflect.String:
|
||||
result = reflect.ValueOf(sourceVal.String())
|
||||
case reflect.Struct:
|
||||
//WE ASSUME THAT THE FIRST FIELD OF THE STRUCT IS OF TYPE *js.Object
|
||||
//check if first field is *js.Object
|
||||
if !checkIfJSStruct(targetType) {
|
||||
return result, eFirstFieldIsNotPtrJsObject
|
||||
}
|
||||
|
||||
//create a pointer to a new instance of this struct
|
||||
pStructInstance := reflect.New(targetType)
|
||||
|
||||
|
||||
//Assign the sourceValue to the first field of the struct, which is assume to be *js.Object
|
||||
// fN := pStructInstance.Elem().Type().Name()
|
||||
// println("Assigning to '" + fN + "': ", reflect.TypeOf(sourceVal).Elem().Name(), sourceVal)
|
||||
pStructInstance.Elem().Field(0).Set(reflect.ValueOf(sourceVal))
|
||||
|
||||
result = pStructInstance.Elem()
|
||||
case reflect.Ptr:
|
||||
//follow pointer one level
|
||||
derefType := targetType.Elem()
|
||||
//recursive call
|
||||
derefVal,err := castToType(derefType, sourceVal)
|
||||
if err != nil { return result, err}
|
||||
//println("dereferenced Value of type ", derefType.Kind().String(), ": ", derefVal)
|
||||
|
||||
//create a pointer to the dereferenced value after it has been created itself
|
||||
result = derefVal.Addr()
|
||||
case reflect.Interface:
|
||||
result = reflect.ValueOf(sourceVal.Interface())
|
||||
default:
|
||||
// ToDo: func parsing
|
||||
println("No conversion for following type implemented", kind.String() , " from ", sourceVal)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
||||
// checks if the obj given is a struct, with *js.Object type in first field
|
||||
func checkIfJSStruct(objType reflect.Type) bool {
|
||||
|
||||
//check if Struct
|
||||
if objType.Kind() != reflect.Struct { return false } //not a struct
|
||||
// fetch first field
|
||||
typeField0 := objType.Field(0).Type
|
||||
//check if first field is pointer
|
||||
if typeField0.Kind() != reflect.Ptr { return false } //not a pointer
|
||||
// dereference ptr and check if equal to type js.Object
|
||||
if typeField0.Elem() != jsObjectType { return false } // not pointing to js.Object
|
||||
return true
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
)
|
||||
|
||||
func wrapGoMutationFunc(reflectedGoFunc reflect.Value ) (jsFunc *js.Object, err error) {
|
||||
// A mutationfunction is assumed to have this prototype
|
||||
// func(
|
||||
// store *Store, //first argument is of type store
|
||||
// ptrToStateStruct struct{}, //ptr to a struct with same type as the struct provided as state
|
||||
// additionalArgs ...interface{} //optional arguments for the mutation (Go types)
|
||||
// )
|
||||
|
||||
numGoArgs := reflectedGoFunc.Type().NumIn() //Number of arguments of the Go target method
|
||||
if numGoArgs < 2 {
|
||||
return nil, eTooFewMutationArgs
|
||||
}
|
||||
if numGoArgs > 3 {
|
||||
return nil, eTooManyMutationArgs
|
||||
}
|
||||
if goArg0 := reflectedGoFunc.Type().In(0); goArg0.Kind() != reflect.Ptr || goArg0.Elem() != jsStoreType {
|
||||
return nil, eWrongFirstMutationArg
|
||||
}
|
||||
if goArg1 := reflectedGoFunc.Type().In(1); goArg1.Kind() != reflect.Ptr || goArg1.Elem().Kind() != reflect.Struct {
|
||||
return nil, eWrongSecondMutationArg
|
||||
}
|
||||
|
||||
|
||||
// Here we know, the goFunc has at least two args, with first arg being *Store type
|
||||
// and second arg being a custom data struct.
|
||||
// The JavaScript call received, should provide two args at minimum:
|
||||
// - arg 0: state data instance
|
||||
// - arg 1..n: arguments handed in when the respective mutation function is called via commit, in case the
|
||||
// mutation function is called without arguments, arg 1 is of type "undefined"
|
||||
// Additionally, the "this" argument provides the store instance, which we hand to the Go function as first argument
|
||||
|
||||
// following two lines moved out of the inner function to avoid rerunning
|
||||
goCallArgTargetTypes := make([]reflect.Type, numGoArgs)
|
||||
goCallArgsTargetValues := make([]reflect.Value,numGoArgs) //create call args slice, containing the store arg
|
||||
for i := 0; i < reflectedGoFunc.Type().NumIn(); i++ {
|
||||
goCallArgTargetTypes[i] = reflectedGoFunc.Type().In(i)
|
||||
}
|
||||
|
||||
|
||||
jsFunc = js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} {
|
||||
//check if js provides enough args
|
||||
if len(arguments) < numGoArgs - 1 {
|
||||
panic(eTooFewMutationArgsOnCall.Error())
|
||||
}
|
||||
|
||||
//Note: All the logic in MakeFunc ends up in the final JS function and reruns every tim the function is triggered
|
||||
|
||||
storeVal,err := castToType(goCallArgTargetTypes[0], this) //cast 'this' to type of first function arg (type = *Store)
|
||||
if err != nil { panic("Error converting JavaScript provided argument for mutation function to *Store: " + err.Error()) }
|
||||
goCallArgsTargetValues[0] = storeVal
|
||||
|
||||
|
||||
|
||||
//add the remaining args
|
||||
for idx,jsArg := range arguments {
|
||||
//If the target function in Go has less arguments than we got provided from JavaScript, we gonna ignore the rest
|
||||
targetIdx := idx+1 //offset by one, as we started with *Store as first arg for the Go function
|
||||
if targetIdx >= numGoArgs { break }
|
||||
|
||||
//get method argument type at this poistion
|
||||
goTargetArgT := goCallArgTargetTypes[targetIdx]
|
||||
castedArg, err := castToType(goTargetArgT, jsArg)
|
||||
|
||||
if err != nil { panic("Error converting JS object to " + goTargetArgT.Kind().String()) }
|
||||
|
||||
goCallArgsTargetValues[targetIdx] = castedArg
|
||||
}
|
||||
|
||||
results := reflectedGoFunc.Call(goCallArgsTargetValues)
|
||||
|
||||
return results
|
||||
})
|
||||
|
||||
return jsFunc, nil
|
||||
}
|
||||
|
||||
func Mutation(name string, goFunc interface{}) StoreOption {
|
||||
return func(c *StoreConfig) {
|
||||
//println("Creating MUTATION FUNC")
|
||||
if c.Mutations == js.Undefined { c.Mutations = o() }
|
||||
|
||||
reflectedGoFunc := reflect.ValueOf(goFunc)
|
||||
if reflectedGoFunc.Kind() != reflect.Func { //check if the provided interface is a go function
|
||||
panic("Mutation " + name + " is not a func")
|
||||
}
|
||||
|
||||
//try to convert the provided function to a JavaScript function usable as Mutation
|
||||
jsFunc, err := wrapGoMutationFunc(reflectedGoFunc)
|
||||
if err != nil {panic("Error exposing the mutation function '"+ name + "' to JavaScript: " + err.Error())}
|
||||
|
||||
c.Mutations.Set(name, jsFunc)
|
||||
//c.Mutations.Set(name, makeMethod(name, false, reflectGoFunc.Type(), reflectGoFunc))
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func State(value interface{}) StoreOption {
|
||||
|
||||
// Check if value is struct with *js.Object in first field
|
||||
if !checkIfJSStruct(reflect.TypeOf(value)) {
|
||||
panic(eFirstFieldIsNotPtrJsObject)
|
||||
}
|
||||
|
||||
return func(c *StoreConfig) {
|
||||
if c.State != js.Undefined {
|
||||
//if state has been defined before
|
||||
panic("Cannot use mvuex.Sate more than once")
|
||||
}
|
||||
c.Object.Set("state", value)
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package mvuex
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
|
||||
type StoreOption func(*StoreConfig)
|
||||
|
||||
type Store struct {
|
||||
*js.Object
|
||||
|
||||
Getters *js.Object `js:"getters"`
|
||||
Commit func(...interface{}) *js.Object `js:"commit"`
|
||||
Dispatch func(...interface{}) *js.Object `js:"dispatch"`
|
||||
Strict bool `js:"strict"`
|
||||
}
|
||||
|
||||
// StoreConfig is the config object for NewStore.
|
||||
type StoreConfig struct {
|
||||
*js.Object
|
||||
State *js.Object `js:"state"`
|
||||
Mutations *js.Object `js:"mutations"`
|
||||
Actions *js.Object `js:"actions"`
|
||||
|
||||
stateValue reflect.Value
|
||||
}
|
||||
|
||||
|
||||
// Option sets the options specified.
|
||||
func (c *StoreConfig) Option(opts ...StoreOption) {
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
}
|
||||
|
||||
func NewStore(opts ...StoreOption) *Store {
|
||||
c := &StoreConfig{Object: o()}
|
||||
c.Option(opts...)
|
||||
store := &Store{Object: js.Global.Get("Vuex").Get("Store").New(c)}
|
||||
|
||||
|
||||
return store
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user