+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/_examples/tutorial/vuejs-todo-mvc/src/web/public/js/app.js b/_examples/tutorial/vuejs-todo-mvc/src/web/public/js/app.js
index 248c5333..b06ba921 100644
--- a/_examples/tutorial/vuejs-todo-mvc/src/web/public/js/app.js
+++ b/_examples/tutorial/vuejs-todo-mvc/src/web/public/js/app.js
@@ -1,19 +1,42 @@
-// Full spec-compliant TodoMVC with localStorage persistence
+// Full spec-compliant TodoMVC with Iris
// and hash-based routing in ~120 effective lines of JavaScript.
-// localStorage persistence
-var STORAGE_KEY = 'todos-vuejs-2.0'
+// var socket = new Ws("ws://localhost:8080/todos/sync");
+
+// socket.On("saved", function () {
+// console.log("receive: on saved");
+// todoStorage.fetch();
+// });
+
+var todos = [];
+
var todoStorage = {
fetch: function () {
- var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
- todos.forEach(function (todo, index) {
- todo.id = index
- })
- todoStorage.uid = todos.length
+ axios.get("/todos").then(response => {
+ if (response.data == null) {
+ return;
+ }
+ for (var i = 0; i < response.data.length; i++) {
+ // if (todos.length <=i || todos[i] === null) {
+ // todos.push(response.data[i]);
+ // } else {
+ // todos[i] = response.data[i];
+ // }
+ todos.push(response.data[i]);
+ }
+ });
+
return todos
},
save: function (todos) {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
+ axios.post("/todos", JSON.stringify(todos)).then(response => {
+ if (!response.data.success) {
+ window.alert("saving had a failure");
+ return;
+ }
+ // console.log("send: save");
+ // socket.Emit("save")
+ });
}
}
@@ -44,11 +67,18 @@ var app = new Vue({
visibility: 'all'
},
- // watch todos change for localStorage persistence
+ // watch todos change for persistence
watch: {
todos: {
handler: function (todos) {
- todoStorage.save(todos)
+ // // saved by this client.
+ // if (todos[todos.length - 1].id === 0) {
+ // todoStorage.save(todos);
+ // } else {
+ // console.log("item cannot be saved, already exists.");
+ // console.log(todos[todos.length - 1]);
+ // }
+ todoStorage.save(todos);
},
deep: true
}
@@ -90,7 +120,7 @@ var app = new Vue({
return
}
this.todos.push({
- id: todoStorage.uid++,
+ id: 0, // just for the client-side.
title: value,
completed: false
})
@@ -140,7 +170,7 @@ var app = new Vue({
})
// handle routing
-function onHashChange () {
+function onHashChange() {
var visibility = window.location.hash.replace(/#\/?/, '')
if (filters[visibility]) {
app.visibility = visibility
diff --git a/mvc/di/func.go b/mvc/di/func.go
index 36424b06..e49a55c0 100644
--- a/mvc/di/func.go
+++ b/mvc/di/func.go
@@ -11,6 +11,8 @@ type (
InputIndex int
}
+ // FuncInjector keeps the data that are needed in order to do the binding injection
+ // as fast as possible and with the best possible and safest way.
FuncInjector struct {
// the original function, is being used
// only the .Call, which is referring to the same function, always.
@@ -27,6 +29,10 @@ type (
}
)
+// MakeFuncInjector returns a new func injector, which will be the object
+// that the caller should use to bind input arguments of the "fn" function.
+//
+// The hijack and the goodFunc are optional, the "values" is the dependencies values.
func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, values ...reflect.Value) *FuncInjector {
typ := IndirectType(fn.Type())
s := &FuncInjector{
@@ -100,10 +106,14 @@ func MakeFuncInjector(fn reflect.Value, hijack Hijacker, goodFunc TypeChecker, v
return s
}
+// String returns a debug trace text.
func (s *FuncInjector) String() string {
return s.trace
}
+// Inject accepts an already created slice of input arguments
+// and fills them, the "ctx" is optional and it's used
+// on the dependencies that depends on one or more input arguments, these are the "ctx".
func (s *FuncInjector) Inject(in *[]reflect.Value, ctx ...reflect.Value) {
args := *in
for _, input := range s.inputs {
@@ -118,6 +128,12 @@ func (s *FuncInjector) Inject(in *[]reflect.Value, ctx ...reflect.Value) {
*in = args
}
+// Call calls the "Inject" with a new slice of input arguments
+// that are computed by the length of the input argument from the MakeFuncInjector's "fn" function.
+//
+// If the function needs a receiver, so
+// the caller should be able to in[0] = receiver before injection,
+// then the `Inject` method should be used instead.
func (s *FuncInjector) Call(ctx ...reflect.Value) []reflect.Value {
in := make([]reflect.Value, s.Length, s.Length)
s.Inject(&in, ctx...)
diff --git a/mvc/di/object.go b/mvc/di/object.go
index f33e7036..392abcc5 100644
--- a/mvc/di/object.go
+++ b/mvc/di/object.go
@@ -5,11 +5,17 @@ import (
"reflect"
)
+// BindType is the type of a binded object/value, it's being used to
+// check if the value is accessible after a function call with a "ctx" when needed ( Dynamic type)
+// or it's just a struct value (a service | Static type).
type BindType uint32
const (
- Static BindType = iota // simple assignable value, a static value.
- Dynamic // dynamic value, depends on some input arguments from the caller.
+ // Static is the simple assignable value, a static value.
+ Static BindType = iota
+ // Dynamic returns a value but it depends on some input arguments from the caller,
+ // on serve time.
+ Dynamic
)
func bindTypeString(typ BindType) string {
@@ -21,6 +27,9 @@ func bindTypeString(typ BindType) string {
}
}
+// BindObject contains the dependency value's read-only information.
+// FuncInjector and StructInjector keeps information about their
+// input arguments/or fields, these properties contain a `BindObject` inside them.
type BindObject struct {
Type reflect.Type // the Type of 'Value' or the type of the returned 'ReturnValue' .
Value reflect.Value
@@ -29,6 +38,11 @@ type BindObject struct {
ReturnValue func([]reflect.Value) reflect.Value
}
+// MakeBindObject accepts any "v" value, struct, pointer or a function
+// and a type checker that is used to check if the fields (if "v.elem()" is struct)
+// or the input arguments (if "v.elem()" is func)
+// are valid to be included as the final object's dependencies, even if the caller added more
+// the "di" is smart enough to select what each "v" needs and what not before serve time.
func MakeBindObject(v reflect.Value, goodFunc TypeChecker) (b BindObject, err error) {
if IsFunc(v) {
b.BindType = Dynamic
@@ -93,10 +107,13 @@ func MakeReturnValue(fn reflect.Value, goodFunc TypeChecker) (func([]reflect.Val
return bf, outTyp, nil
}
+// IsAssignable checks if "to" type can be used as "b.Value/ReturnValue".
func (b *BindObject) IsAssignable(to reflect.Type) bool {
return equalTypes(b.Type, to)
}
+// Assign sets the values to a setter, "toSetter" contains the setter, so the caller
+// can use it for multiple and different structs/functions as well.
func (b *BindObject) Assign(ctx []reflect.Value, toSetter func(reflect.Value)) {
if b.BindType == Dynamic {
toSetter(b.ReturnValue(ctx))
diff --git a/mvc/di/struct.go b/mvc/di/struct.go
index 091cd77f..df20d7c8 100644
--- a/mvc/di/struct.go
+++ b/mvc/di/struct.go
@@ -18,6 +18,8 @@ type (
FieldIndex []int
}
+ // StructInjector keeps the data that are needed in order to do the binding injection
+ // as fast as possible and with the best possible and safest way.
StructInjector struct {
initRef reflect.Value
initRefAsSlice []reflect.Value // useful when the struct is passed on a func as input args via reflection.
@@ -42,6 +44,12 @@ func (s *StructInjector) countBindType(typ BindType) (n int) {
return
}
+// MakeStructInjector returns a new struct injector, which will be the object
+// that the caller should use to bind exported fields or
+// embedded unexported fields that contain exported fields
+// of the "v" struct value or pointer.
+//
+// The hijack and the goodFunc are optional, the "values" is the dependencies values.
func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker, values ...reflect.Value) *StructInjector {
s := &StructInjector{
initRef: v,
@@ -149,6 +157,7 @@ func (s *StructInjector) fillStruct() {
}
}
+// String returns a debug trace message.
func (s *StructInjector) String() (trace string) {
for i, f := range s.fields {
elemField := s.elemType.FieldByIndex(f.FieldIndex)
diff --git a/mvc/di/values.go b/mvc/di/values.go
index d7aacb18..1033b957 100644
--- a/mvc/di/values.go
+++ b/mvc/di/values.go
@@ -2,8 +2,11 @@ package di
import "reflect"
+// Values is a shortcut of []reflect.Value,
+// it makes easier to remove and add dependencies.
type Values []reflect.Value
+// NewValues returns new empty (dependencies) values.
func NewValues() Values {
return Values{}
}
@@ -30,6 +33,7 @@ func (bv Values) CloneWithFieldsOf(s interface{}) Values {
return values
}
+// Len returns the length of the current "bv" values slice.
func (bv Values) Len() int {
return len(bv)
}
@@ -41,6 +45,8 @@ func (bv *Values) Add(values ...interface{}) {
bv.AddValues(ValuesOf(values)...)
}
+// AddValues same as `Add` but accepts reflect.Value dependencies instead of interface{}
+// and appends them to the list if they pass some checks.
func (bv *Values) AddValues(values ...reflect.Value) {
for _, v := range values {
if !goodVal(v) {