├── .gitignore ├── helpers ├── math.go ├── math_test.go ├── utils.go └── utils_test.go ├── key.go ├── key_test.go ├── Makefile ├── attrs.go ├── h.go ├── textnode.go ├── attrs_test.go ├── textnode_test.go ├── Gopkg.toml ├── .travis.yml ├── h_test.go ├── patch.go ├── reconciler.go ├── Gopkg.lock ├── reconciler_test.go ├── dom └── dom.go ├── vnode.go ├── vnode_test.go ├── cover.out ├── README.md └── mock ├── dom.go └── node.go /.gitignore: -------------------------------------------------------------------------------- 1 | vendor -------------------------------------------------------------------------------- /helpers/math.go: -------------------------------------------------------------------------------- 1 | package vnh 2 | 3 | func Max(x int, y int) int { 4 | if x > y { 5 | return x 6 | } 7 | 8 | return y 9 | } 10 | -------------------------------------------------------------------------------- /helpers/math_test.go: -------------------------------------------------------------------------------- 1 | package vnh 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMathMax(t *testing.T) { 10 | min := 1 11 | max := 2 12 | 13 | assert.Equal(t, max, Max(min, max)) 14 | assert.Equal(t, max, Max(max, min)) 15 | } 16 | -------------------------------------------------------------------------------- /helpers/utils.go: -------------------------------------------------------------------------------- 1 | package vnh 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | func IsNil(toVerify interface{}) bool { 8 | if toVerify == nil { 9 | return true 10 | } 11 | 12 | return reflect.ValueOf(toVerify).IsNil() 13 | } 14 | 15 | func NotNil(toVerify interface{}) bool { 16 | return !IsNil(toVerify) 17 | } 18 | -------------------------------------------------------------------------------- /key.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | type KeyIdentifier interface { 4 | SetValue(string) 5 | GetValue() string 6 | } 7 | 8 | type Key struct { 9 | Value string 10 | } 11 | 12 | func (Key *Key) SetValue(value string) { 13 | Key.Value = value 14 | } 15 | 16 | func (key *Key) GetValue() string { 17 | return key.Value 18 | } 19 | -------------------------------------------------------------------------------- /key_test.go: -------------------------------------------------------------------------------- 1 | package vn_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | import vn "github.com/mfrachet/go-vdom-wasm" 10 | 11 | func TestKey_Accessors(t *testing.T) { 12 | key := vn.Key{} 13 | key.SetValue("Hello") 14 | 15 | assert.Equal(t, "Hello", key.GetValue()) 16 | } 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | # deps: 3 | # $(GOPATH)/bin/dep ensure 4 | prepare-test: 5 | $(GOPATH)/bin/mockgen -source=dom/dom.go -destination=mock/dom.go -package=mock 6 | $(GOPATH)/bin/mockgen -source=vnode.go -destination=mock/node.go -package=mock 7 | test: 8 | GOOS=js GOARCH=wasm go test ./... -exec="$(shell go env GOROOT)/misc/wasm/go_js_wasm_exec" 9 | test-cover: 10 | GOOS=js GOARCH=wasm go test ./... -exec="$(shell go env GOROOT)/misc/wasm/go_js_wasm_exec" -coverprofile=cover.out 11 | go tool cover -html=cover.out -------------------------------------------------------------------------------- /attrs.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | "syscall/js" 5 | 6 | vnh "github.com/mfrachet/go-vdom-wasm/helpers" 7 | ) 8 | 9 | type Ev = map[string]func(js.Value, []js.Value) interface{} 10 | 11 | type Props = map[string]string 12 | 13 | type Attrs struct { 14 | Props *Props 15 | Events *Ev 16 | } 17 | 18 | func Sanitize(attrs *Attrs) *Attrs { 19 | if vnh.IsNil(attrs) { 20 | return &Attrs{Props: &Props{}, Events: &Ev{}} 21 | } 22 | 23 | if vnh.IsNil(attrs.Props) { 24 | attrs.Props = &Props{} 25 | } 26 | 27 | if vnh.IsNil(attrs.Events) { 28 | attrs.Events = &Ev{} 29 | } 30 | 31 | return attrs 32 | } 33 | -------------------------------------------------------------------------------- /helpers/utils_test.go: -------------------------------------------------------------------------------- 1 | package vnh 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestIsNil(t *testing.T) { 9 | var node *[]int 10 | 11 | str := "Hello world" 12 | pointer := &str 13 | 14 | assert.Equal(t, true, IsNil(nil)) 15 | assert.Equal(t, true, IsNil(node)) 16 | assert.Equal(t, false, IsNil(pointer)) 17 | } 18 | 19 | func TestNotNil(t *testing.T) { 20 | var node *[]int 21 | 22 | str := "Hello world" 23 | pointer := &str 24 | 25 | assert.Equal(t, false, NotNil(nil)) 26 | assert.Equal(t, true, NotNil(pointer)) 27 | assert.Equal(t, false, NotNil(node)) 28 | } 29 | -------------------------------------------------------------------------------- /h.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | func H(tagName string, params ...interface{}) Node { 4 | var key KeyIdentifier 5 | var children Children 6 | var textNode *TextNode 7 | attrs := &Attrs{} 8 | 9 | for _, param := range params { 10 | switch (param).(type) { 11 | case string: 12 | textNode = NewTextnode((param).(string)) 13 | case KeyIdentifier: 14 | key = param.(KeyIdentifier) 15 | case *Props: 16 | attrs.Props = param.(*Props) 17 | case *Ev: 18 | attrs.Events = param.(*Ev) 19 | default: 20 | children = param.(Children) 21 | } 22 | } 23 | 24 | sanitizedAttrs := Sanitize(attrs) 25 | 26 | return NewNode(tagName, sanitizedAttrs, children, textNode, nil, key) 27 | } 28 | -------------------------------------------------------------------------------- /textnode.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 5 | ) 6 | 7 | type TextNode struct { 8 | value string 9 | element *vnd.DomNode 10 | } 11 | 12 | func NewTextnode(value string) *TextNode { 13 | return &TextNode{value, nil} 14 | } 15 | 16 | func (textNode *TextNode) GetElement() *vnd.DomNode { 17 | return textNode.element 18 | } 19 | 20 | func (textNode *TextNode) GetValue() string { 21 | return textNode.value 22 | } 23 | 24 | func (textNode *TextNode) SetElement(element vnd.DomNode) { 25 | textNode.element = &element 26 | } 27 | 28 | func (textNode *TextNode) IsSame(other *TextNode) bool { 29 | return textNode.GetValue() == other.GetValue() 30 | 31 | } 32 | -------------------------------------------------------------------------------- /attrs_test.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAttrs_Sanitize(t *testing.T) { 10 | attrs := &Attrs{} 11 | 12 | sanitized := Sanitize(attrs) 13 | 14 | assert.Equal(t, false, sanitized.Props == nil) 15 | assert.Equal(t, false, sanitized.Events == nil) 16 | } 17 | 18 | func TestAttrs_Sanitize_Nil_Attrs(t *testing.T) { 19 | attrs := &Attrs{Props: &Props{}, Events: &Ev{}} 20 | 21 | sanitized := Sanitize(nil) 22 | 23 | assert.Equal(t, sanitized, attrs) 24 | } 25 | 26 | func TestAttrs_Sanitize_No_Changes(t *testing.T) { 27 | attrs := &Attrs{Props: &Props{}, Events: &Ev{}} 28 | 29 | sanitized := Sanitize(attrs) 30 | 31 | assert.Equal(t, attrs, sanitized) 32 | } 33 | -------------------------------------------------------------------------------- /textnode_test.go: -------------------------------------------------------------------------------- 1 | package vn_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/golang/mock/gomock" 7 | vn "github.com/mfrachet/go-vdom-wasm" 8 | "github.com/mfrachet/go-vdom-wasm/mock" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestTextNode_IsSame(t *testing.T) { 13 | a := vn.NewTextnode("Hello world") 14 | b := vn.NewTextnode("Hello world") 15 | c := vn.NewTextnode("Hello world2") 16 | 17 | assert.Equal(t, true, a.IsSame(b)) 18 | assert.Equal(t, false, a.IsSame(c)) 19 | } 20 | 21 | func TestTextNode_Accessors(t *testing.T) { 22 | ctrl := gomock.NewController(t) 23 | defer ctrl.Finish() 24 | 25 | a := vn.NewTextnode("Hello world") 26 | 27 | mockDomNode := mock.NewMockDomNode(ctrl) 28 | a.SetElement(mockDomNode) 29 | 30 | assert.Equal(t, mockDomNode, *a.GetElement()) 31 | assert.Equal(t, "Hello world", a.GetValue()) 32 | } 33 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/golang/mock" 30 | version = "1.3.1" 31 | 32 | [[constraint]] 33 | name = "github.com/stretchr/testify" 34 | version = "1.4.0" 35 | 36 | [prune] 37 | go-tests = true 38 | unused-packages = true 39 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | install: 3 | # From vecty's https://github.com/gopherjs/vecty/blob/master/.travis.yml 4 | # Manually download and install Go 1.12 because the Travis / gimme version 5 | # is broken (see https://travis-ci.community/t/goos-js-goarch-wasm-go-run-fails-panic-newosproc-not-implemented/1651/6) 6 | - wget -O go.tar.gz https://dl.google.com/go/go1.12.linux-amd64.tar.gz 7 | - tar -C ~ -xzf go.tar.gz 8 | - rm go.tar.gz 9 | - export GOROOT=~/go 10 | - export GOPATH=/home/travis/go 11 | - export PATH=$GOROOT/bin:$PATH 12 | - export GOBIN=/home/travis/go/bin 13 | - go version 14 | - go env 15 | before_script: 16 | - mkdir /home/travis/go/src/mfrachet 17 | - mv /home/travis/build/mfrachet/go-vdom-wasm /home/travis/go/src/mfrachet/go-vdom-wasm 18 | - cd /home/travis/go/src/mfrachet/go-vdom-wasm 19 | - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 20 | - /home/travis/go/bin/dep ensure 21 | script: 22 | - make 23 | -------------------------------------------------------------------------------- /h_test.go: -------------------------------------------------------------------------------- 1 | package vn_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | import vn "github.com/mfrachet/go-vdom-wasm" 10 | 11 | func TestH_WithText(t *testing.T) { 12 | expected := vn.NewNode("div", &vn.Attrs{Props: &vn.Props{}, Events: &vn.Ev{}}, nil, vn.NewTextnode("Hello world"), nil, nil) 13 | 14 | vNode := vn.H("div", "Hello world") 15 | 16 | assert.Equal(t, expected, vNode) 17 | } 18 | 19 | func TestH_WithChildren(t *testing.T) { 20 | child := vn.H("span", "Hello world") 21 | 22 | expected := vn.NewNode("div", &vn.Attrs{Props: &vn.Props{}, Events: &vn.Ev{}}, vn.Children{child}, nil, nil, nil) 23 | 24 | vNode := vn.H("div", vn.Children{child}) 25 | 26 | assert.Equal(t, expected, vNode) 27 | } 28 | 29 | func TestH_WithAttributes(t *testing.T) { 30 | exectedWithoutAttrs := vn.NewNode("div", &vn.Attrs{Props: &vn.Props{}, Events: &vn.Ev{}}, nil, vn.NewTextnode("Hello world"), nil, nil) 31 | vNodeWithoutAttrs := vn.H("div", "Hello world") 32 | 33 | assert.Equal(t, exectedWithoutAttrs, vNodeWithoutAttrs) 34 | 35 | exectedWithAttrs := vn.NewNode("div", &vn.Attrs{Props: &vn.Props{"class": "navbar"}, Events: &vn.Ev{}}, nil, vn.NewTextnode("Hello world"), nil, nil) 36 | vNodeWithAttrs := vn.H("div", &vn.Props{"class": "navbar"}, "Hello world") 37 | 38 | assert.Equal(t, exectedWithAttrs, vNodeWithAttrs) 39 | } 40 | -------------------------------------------------------------------------------- /patch.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 5 | vnh "github.com/mfrachet/go-vdom-wasm/helpers" 6 | ) 7 | 8 | func updateElement(parent vnd.DomNode, newNode Node, oldNode Node) { 9 | if vnh.IsNil(newNode) { 10 | Remove(*oldNode.GetElement()) 11 | } else if vnh.IsNil(oldNode) { 12 | newElement := CreateIfNotExist(parent, newNode) 13 | 14 | Append(parent, newElement) 15 | } else if !newNode.IsSame(oldNode) { 16 | newElement := CreateIfNotExist(parent, newNode) 17 | 18 | oldElement := *oldNode.GetElement() 19 | oldElement.ReplaceWith(newElement) 20 | } else { 21 | newNode.SetElement(*oldNode.GetElement()) 22 | 23 | newChildrenCount := newNode.ChildrenCount() 24 | oldChildrenCount := oldNode.ChildrenCount() 25 | 26 | max := vnh.Max(newChildrenCount, oldChildrenCount) 27 | 28 | for i := 0; i < max; i++ { 29 | oldChild := oldNode.ChildAt(i) 30 | newChild := newNode.ChildAt(i) 31 | 32 | updateElement(*oldNode.GetElement(), newChild, oldChild) 33 | } 34 | } 35 | } 36 | 37 | func Patch(oldNodeRef interface{}, newVnode Node) { 38 | switch oldNodeRef.(type) { 39 | case string: 40 | rootNodeID := oldNodeRef.(string) 41 | rootNode := vnd.GetDocument().QuerySelector(rootNodeID) 42 | 43 | newElement := CreateIfNotExist(rootNode, newVnode) 44 | 45 | Append(rootNode, newElement) 46 | default: 47 | oldVnode := oldNodeRef.(Node) 48 | 49 | updateElement(*oldVnode.GetElement(), newVnode, oldVnode) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /reconciler.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 5 | vnh "github.com/mfrachet/go-vdom-wasm/helpers" 6 | ) 7 | 8 | func Append(parent vnd.DomNode, child vnd.DomNode) { 9 | parent.AppendChild(child) 10 | } 11 | 12 | func Remove(domNode vnd.DomNode) { 13 | domNode.Remove() 14 | } 15 | 16 | func CreateText(parent vnd.DomNode, virtualNode *TextNode) vnd.DomNode { 17 | return parent.CreateTextNode(virtualNode.GetValue()) 18 | } 19 | 20 | func CreateInstance(parent vnd.DomNode, vnode Node) vnd.DomNode { 21 | domNode := parent.CreateElement(vnode.GetTagName()) 22 | attrs := vnode.GetAttrs() 23 | 24 | for attr, attrValue := range *attrs.Props { 25 | domNode.SetAttribute(attr, attrValue) 26 | } 27 | 28 | for eventName, handler := range *attrs.Events { 29 | domNode.AddEventListener(eventName, handler) 30 | } 31 | 32 | return domNode 33 | } 34 | 35 | func ComputeChildren(parent vnd.DomNode, vnode Node) { 36 | textNode := vnode.GetText() 37 | if vnh.NotNil(textNode) { 38 | textElement := CreateText(parent, textNode) 39 | textNode.SetElement(textElement) 40 | 41 | Append(parent, textElement) 42 | } else { 43 | for _, el := range vnode.GetChildren() { 44 | childElement := CreateIfNotExist(parent, el) 45 | parent.AppendChild(childElement) 46 | } 47 | } 48 | } 49 | 50 | func CreateIfNotExist(parent vnd.DomNode, vnode Node) vnd.DomNode { 51 | if vnode.HasElement() { 52 | return *vnode.GetElement() 53 | } 54 | 55 | newElement := CreateInstance(parent, vnode) 56 | vnode.SetElement(newElement) 57 | 58 | ComputeChildren(newElement, vnode) 59 | 60 | return newElement 61 | } 62 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" 6 | name = "github.com/davecgh/go-spew" 7 | packages = ["spew"] 8 | pruneopts = "UT" 9 | revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" 10 | version = "v1.1.1" 11 | 12 | [[projects]] 13 | digest = "1:be408f349cae090a7c17a279633d6e62b00068e64af66a582cae0983de8890ea" 14 | name = "github.com/golang/mock" 15 | packages = ["gomock"] 16 | pruneopts = "UT" 17 | revision = "9fa652df1129bef0e734c9cf9bf6dbae9ef3b9fa" 18 | version = "1.3.1" 19 | 20 | [[projects]] 21 | digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" 22 | name = "github.com/pmezard/go-difflib" 23 | packages = ["difflib"] 24 | pruneopts = "UT" 25 | revision = "792786c7400a136282c1664665ae0a8db921c6c2" 26 | version = "v1.0.0" 27 | 28 | [[projects]] 29 | digest = "1:8548c309c65a85933a625be5e7d52b6ac927ca30c56869fae58123b8a77a75e1" 30 | name = "github.com/stretchr/testify" 31 | packages = ["assert"] 32 | pruneopts = "UT" 33 | revision = "221dbe5ed46703ee255b1da0dec05086f5035f62" 34 | version = "v1.4.0" 35 | 36 | [[projects]] 37 | digest = "1:b75b3deb2bce8bc079e16bb2aecfe01eb80098f5650f9e93e5643ca8b7b73737" 38 | name = "gopkg.in/yaml.v2" 39 | packages = ["."] 40 | pruneopts = "UT" 41 | revision = "1f64d6156d11335c3f22d9330b0ad14fc1e789ce" 42 | version = "v2.2.7" 43 | 44 | [solve-meta] 45 | analyzer-name = "dep" 46 | analyzer-version = 1 47 | input-imports = [ 48 | "github.com/golang/mock/gomock", 49 | "github.com/stretchr/testify/assert", 50 | ] 51 | solver-name = "gps-cdcl" 52 | solver-version = 1 53 | -------------------------------------------------------------------------------- /reconciler_test.go: -------------------------------------------------------------------------------- 1 | package vn_test 2 | 3 | import ( 4 | "syscall/js" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | "github.com/golang/mock/gomock" 10 | vn "github.com/mfrachet/go-vdom-wasm" 11 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 12 | "github.com/mfrachet/go-vdom-wasm/mock" 13 | ) 14 | 15 | func TestReconciler_Append(t *testing.T) { 16 | ctrl := gomock.NewController(t) 17 | defer ctrl.Finish() 18 | 19 | mockParentNode := mock.NewMockDomNode(ctrl) 20 | mockChildNode := mock.NewMockDomNode(ctrl) 21 | 22 | mockParentNode.EXPECT().AppendChild(mockChildNode).Times(1) 23 | 24 | vn.Append(mockParentNode, mockChildNode) 25 | } 26 | 27 | func TestReconciler_Remove(t *testing.T) { 28 | ctrl := gomock.NewController(t) 29 | defer ctrl.Finish() 30 | 31 | mockDNode := mock.NewMockDomNode(ctrl) 32 | 33 | mockDNode.EXPECT().Remove().Times(1) 34 | 35 | vn.Remove(mockDNode) 36 | } 37 | 38 | func TestReconciler_CreateText(t *testing.T) { 39 | ctrl := gomock.NewController(t) 40 | defer ctrl.Finish() 41 | 42 | textNode := vn.NewTextnode("Hello world") 43 | mockDNode := mock.NewMockDomNode(ctrl) 44 | 45 | mockDNode.EXPECT().CreateTextNode("Hello world").Times(1) 46 | 47 | vn.CreateText(mockDNode, textNode) 48 | } 49 | 50 | func handleClick(arg []js.Value) {} 51 | func TestReconciler_CreateInstance(t *testing.T) { 52 | ctrl := gomock.NewController(t) 53 | defer ctrl.Finish() 54 | 55 | vnode := vn.H("li", &vn.Props{"class": "navbar"}, &vn.Ev{"click": nil}, "Hello world") 56 | 57 | mockParent := mock.NewMockDomNode(ctrl) 58 | mockChild := mock.NewMockDomNode(ctrl) 59 | mockParent.EXPECT().CreateElement("li").Return(mockChild).Times(1) 60 | mockChild.EXPECT().SetAttribute("class", "navbar").Times(1) 61 | mockChild.EXPECT().AddEventListener("click", nil).Times(1) 62 | 63 | domNode := vn.CreateInstance(mockParent, vnode) 64 | 65 | assert.Equal(t, domNode, mockChild) 66 | } 67 | 68 | func TestReconciler_CreateIfNotExist_WithElement(t *testing.T) { 69 | ctrl := gomock.NewController(t) 70 | defer ctrl.Finish() 71 | 72 | domElement := vnd.DomElement{} 73 | vnode := vn.H("div", vn.Children{}) 74 | vnode.SetElement(domElement) 75 | 76 | mockParent := mock.NewMockDomNode(ctrl) 77 | 78 | domNode := vn.CreateIfNotExist(mockParent, vnode) 79 | 80 | assert.Equal(t, domNode, domElement) 81 | } 82 | -------------------------------------------------------------------------------- /dom/dom.go: -------------------------------------------------------------------------------- 1 | package vnd 2 | 3 | import ( 4 | vnh "github.com/mfrachet/go-vdom-wasm/helpers" 5 | "syscall/js" 6 | ) 7 | 8 | type DomNode interface { 9 | QuerySelector(string) DomNode 10 | AppendChild(DomNode) 11 | Remove() 12 | ReplaceWith(DomNode) 13 | CreateTextNode(string) DomNode 14 | CreateElement(string) DomNode 15 | SetAttribute(string, string) 16 | AddEventListener(string, func(js.Value, []js.Value) interface{}) 17 | ChildNodes(int) DomNode 18 | GetBinding() js.Value 19 | SetBinding(js.Value) 20 | } 21 | 22 | type DomElement struct { 23 | binding js.Value 24 | } 25 | 26 | var instance *DomElement 27 | 28 | func GetDocument() DomNode { 29 | if vnh.IsNil(instance) { 30 | docNode := js.Global().Get("document") 31 | instance = &DomElement{docNode} 32 | } 33 | 34 | return *instance 35 | } 36 | 37 | func (node DomElement) GetBinding() js.Value { 38 | return node.binding 39 | } 40 | 41 | func (node DomElement) SetBinding(nextBinding js.Value) { 42 | node.binding = nextBinding 43 | } 44 | 45 | func (node DomElement) QuerySelector(element string) DomNode { 46 | bindingNode := GetDocument().GetBinding().Call("querySelector", element) 47 | 48 | return DomElement{bindingNode} 49 | } 50 | 51 | func (node DomElement) AppendChild(child DomNode) { 52 | node.GetBinding().Call("appendChild", child.GetBinding()) 53 | } 54 | 55 | func (node DomElement) Remove() { 56 | node.GetBinding().Call("remove") 57 | } 58 | 59 | func (node DomElement) ReplaceWith(next DomNode) { 60 | node.GetBinding().Call("replaceWith", next.GetBinding()) 61 | } 62 | 63 | func (node DomElement) CreateTextNode(value string) DomNode { 64 | textNode := GetDocument().GetBinding().Call("createTextNode", value) 65 | 66 | return DomElement{textNode} 67 | } 68 | 69 | func (node DomElement) CreateElement(tag string) DomNode { 70 | element := GetDocument().GetBinding().Call("createElement", tag) 71 | 72 | return DomElement{element} 73 | } 74 | 75 | func (node DomElement) SetAttribute(attr string, value string) { 76 | node.GetBinding().Call("setAttribute", attr, value) 77 | } 78 | 79 | func (node DomElement) AddEventListener(eventName string, callback func(js.Value, []js.Value) interface{}) { 80 | node.GetBinding().Call("addEventListener", eventName, js.FuncOf(callback)) 81 | } 82 | 83 | func (node DomElement) ChildNodes(index int) DomNode { 84 | element := node.GetBinding().Get("childNodes").Index(index) 85 | 86 | return DomElement{element} 87 | } 88 | -------------------------------------------------------------------------------- /vnode.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | "fmt" 5 | 6 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 7 | vnh "github.com/mfrachet/go-vdom-wasm/helpers" 8 | ) 9 | 10 | type Children []Node 11 | 12 | type Node interface { 13 | GetElement() *vnd.DomNode 14 | GetTagName() string 15 | GetAttrs() *Attrs 16 | GetKey() *string 17 | HasElement() bool 18 | SetElement(vnd.DomNode) 19 | HashCode() string 20 | ChildrenCount() int 21 | ChildAt(int) Node 22 | GetText() *TextNode 23 | GetChildren() Children 24 | IsSame(Node) bool 25 | } 26 | 27 | type Vnode struct { 28 | tagname string 29 | attrs *Attrs 30 | children Children 31 | text *TextNode 32 | element *vnd.DomNode 33 | key KeyIdentifier 34 | } 35 | 36 | func NewNode(tagname string, attrs *Attrs, children Children, text *TextNode, element *vnd.DomNode, key KeyIdentifier) Node { 37 | return &Vnode{tagname, attrs, children, text, element, key} 38 | } 39 | 40 | func (vnode *Vnode) IsSame(other Node) bool { 41 | currKey := vnode.GetKey() 42 | otherKey := other.GetKey() 43 | 44 | if currKey != nil && otherKey != nil { 45 | return *currKey == *otherKey 46 | } 47 | 48 | if vnh.IsNil(vnode.text) { 49 | if vnh.IsNil(other.GetText()) { 50 | return vnode.HashCode() == other.HashCode() 51 | } 52 | 53 | return false 54 | } 55 | 56 | if vnh.NotNil(other.GetText()) { 57 | hasSameText := other.GetText().IsSame(vnode.text) 58 | return hasSameText && vnode.HashCode() == other.HashCode() 59 | } 60 | 61 | return false 62 | } 63 | 64 | func (vnode *Vnode) ChildrenCount() int { 65 | return len(vnode.children) 66 | } 67 | 68 | func (vnode *Vnode) ChildAt(index int) Node { 69 | size := len(vnode.children) 70 | 71 | if size > index { 72 | return vnode.children[index] 73 | } 74 | 75 | return nil 76 | } 77 | 78 | func (vnode *Vnode) GetKey() *string { 79 | if vnh.IsNil(vnode.key) { 80 | return nil 81 | } 82 | 83 | key := vnode.key.GetValue() 84 | return &key 85 | } 86 | 87 | func (vnode *Vnode) GetText() *TextNode { 88 | return vnode.text 89 | } 90 | 91 | func (vnode *Vnode) GetElement() *vnd.DomNode { 92 | return vnode.element 93 | } 94 | 95 | func (vnode *Vnode) HasElement() bool { 96 | return vnh.NotNil(vnode.GetElement()) 97 | } 98 | 99 | func (vnode *Vnode) GetTagName() string { 100 | return vnode.tagname 101 | } 102 | 103 | func (vnode *Vnode) GetAttrs() *Attrs { 104 | return vnode.attrs 105 | } 106 | 107 | func (vnode *Vnode) GetChildren() Children { 108 | return vnode.children 109 | } 110 | 111 | func (vnode *Vnode) SetElement(element vnd.DomNode) { 112 | vnode.element = &element 113 | } 114 | 115 | func (vnode *Vnode) HashCode() string { 116 | return fmt.Sprintf("%s/%v", vnode.tagname, *vnode.attrs.Props) 117 | } 118 | -------------------------------------------------------------------------------- /vnode_test.go: -------------------------------------------------------------------------------- 1 | package vn 2 | 3 | import ( 4 | "testing" 5 | 6 | vnd "github.com/mfrachet/go-vdom-wasm/dom" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestVnode_IsSame(t *testing.T) { 11 | a := H("div", "Hello world") 12 | b := H("div", "Hello world") 13 | c := H("span", "Hello world") 14 | 15 | d := H("span", &Props{"hello": "world"}, "Hello world") 16 | e := H("span", &Props{"hello": "world"}, "Hello world") 17 | f := H("div", &Props{"hello": "world"}, "Hello worldx") 18 | j := H("span", &Props{"hello": "world2"}, "Hello world") 19 | 20 | k := H("li", "Hello world") 21 | l := H("li", "Hello world2") 22 | 23 | m := H("li", Children{}) 24 | 25 | assert.Equal(t, true, a.IsSame(b)) 26 | assert.Equal(t, true, d.IsSame(e)) 27 | 28 | assert.Equal(t, false, a.IsSame(c)) 29 | assert.Equal(t, false, d.IsSame(f)) 30 | assert.Equal(t, false, d.IsSame(j)) 31 | assert.Equal(t, false, k.IsSame(l)) 32 | 33 | assert.Equal(t, false, m.IsSame(a)) 34 | assert.Equal(t, false, a.IsSame(m)) 35 | } 36 | 37 | func TestVnode_IsSame_WithChildren(t *testing.T) { 38 | a := H("ul", &Props{"class": "navbar"}, Children{ 39 | H("li", "First item"), 40 | H("li", "Second item"), 41 | }) 42 | 43 | b := H("ul", &Props{"class": "navbar"}, Children{ 44 | H("li", "First item"), 45 | H("li", "Second item"), 46 | }) 47 | 48 | assert.Equal(t, true, a.IsSame(b)) 49 | } 50 | 51 | func TestVnode_IsSame_WithKey(t *testing.T) { 52 | a := H("ul", &Props{"class": "navbar"}, Children{ 53 | H("li", "First item"), 54 | H("li", "Second item"), 55 | }, &Key{"1"}) 56 | 57 | b := H("ul", &Props{"class": "navbar"}, Children{ 58 | H("li", "First item"), 59 | H("li", "Second item"), 60 | }, &Key{"2"}) 61 | 62 | assert.Equal(t, false, a.IsSame(b)) 63 | } 64 | 65 | func TestVnode_ChildrenCount(t *testing.T) { 66 | a := H("div", Children{ 67 | H("span", "Hello"), 68 | H("span", "Hello"), 69 | }) 70 | 71 | assert.Equal(t, 2, a.ChildrenCount()) 72 | } 73 | 74 | func TestVnode_ChildAt(t *testing.T) { 75 | childAtOne := H("span", "Hello World") 76 | 77 | a := H("div", Children{ 78 | H("span", "Hello"), 79 | childAtOne, 80 | }) 81 | b := H("span", "Hello") 82 | 83 | assert.Equal(t, childAtOne, a.ChildAt(1)) 84 | assert.Equal(t, nil, b.ChildAt(1)) 85 | } 86 | 87 | func TestVnode_HasElement(t *testing.T) { 88 | element := H("span", "Hello world") 89 | assert.Equal(t, false, element.HasElement()) 90 | 91 | element.SetElement(vnd.DomElement{}) 92 | assert.Equal(t, true, element.HasElement()) 93 | } 94 | 95 | func TestVnode_GetTagName(t *testing.T) { 96 | element := H("span", "Hello world") 97 | 98 | assert.Equal(t, "span", element.GetTagName()) 99 | } 100 | 101 | func TestVnode_GetAttrs(t *testing.T) { 102 | props := &Props{"class": "navbar"} 103 | ev := &Ev{} 104 | attrs := &Attrs{Props: props, Events: ev} 105 | element := H("span", props, ev, "Hello world") 106 | 107 | assert.Equal(t, attrs, element.GetAttrs()) 108 | } 109 | 110 | func TestVnode_GetChildren(t *testing.T) { 111 | children := Children{} 112 | element := H("span", children) 113 | 114 | assert.Equal(t, children, element.GetChildren()) 115 | } 116 | -------------------------------------------------------------------------------- /cover.out: -------------------------------------------------------------------------------- 1 | mode: set 2 | github.com/mfrachet/go-vdom-wasm/helpers/math.go:3.28,4.11 1 1 3 | github.com/mfrachet/go-vdom-wasm/helpers/math.go:8.2,8.10 1 1 4 | github.com/mfrachet/go-vdom-wasm/helpers/math.go:4.11,6.3 1 1 5 | github.com/mfrachet/go-vdom-wasm/helpers/utils.go:7.39,8.21 1 1 6 | github.com/mfrachet/go-vdom-wasm/helpers/utils.go:12.2,12.42 1 1 7 | github.com/mfrachet/go-vdom-wasm/helpers/utils.go:8.21,10.3 1 1 8 | github.com/mfrachet/go-vdom-wasm/helpers/utils.go:15.40,17.2 1 1 9 | github.com/mfrachet/go-vdom-wasm/vnode.go:36.125,38.2 1 1 10 | github.com/mfrachet/go-vdom-wasm/vnode.go:40.45,44.39 3 1 11 | github.com/mfrachet/go-vdom-wasm/vnode.go:48.2,48.27 1 1 12 | github.com/mfrachet/go-vdom-wasm/vnode.go:56.2,56.33 1 1 13 | github.com/mfrachet/go-vdom-wasm/vnode.go:61.2,61.14 1 1 14 | github.com/mfrachet/go-vdom-wasm/vnode.go:44.39,46.3 1 1 15 | github.com/mfrachet/go-vdom-wasm/vnode.go:48.27,49.33 1 1 16 | github.com/mfrachet/go-vdom-wasm/vnode.go:53.3,53.15 1 1 17 | github.com/mfrachet/go-vdom-wasm/vnode.go:49.33,51.4 1 1 18 | github.com/mfrachet/go-vdom-wasm/vnode.go:56.33,59.3 2 1 19 | github.com/mfrachet/go-vdom-wasm/vnode.go:64.41,66.2 1 1 20 | github.com/mfrachet/go-vdom-wasm/vnode.go:68.45,71.18 2 1 21 | github.com/mfrachet/go-vdom-wasm/vnode.go:75.2,75.12 1 1 22 | github.com/mfrachet/go-vdom-wasm/vnode.go:71.18,73.3 1 1 23 | github.com/mfrachet/go-vdom-wasm/vnode.go:78.38,79.26 1 1 24 | github.com/mfrachet/go-vdom-wasm/vnode.go:83.2,84.13 2 1 25 | github.com/mfrachet/go-vdom-wasm/vnode.go:79.26,81.3 1 1 26 | github.com/mfrachet/go-vdom-wasm/vnode.go:87.41,89.2 1 1 27 | github.com/mfrachet/go-vdom-wasm/vnode.go:91.47,93.2 1 1 28 | github.com/mfrachet/go-vdom-wasm/vnode.go:95.39,97.2 1 1 29 | github.com/mfrachet/go-vdom-wasm/vnode.go:99.41,101.2 1 1 30 | github.com/mfrachet/go-vdom-wasm/vnode.go:103.39,105.2 1 1 31 | github.com/mfrachet/go-vdom-wasm/vnode.go:107.44,109.2 1 1 32 | github.com/mfrachet/go-vdom-wasm/vnode.go:111.53,113.2 1 1 33 | github.com/mfrachet/go-vdom-wasm/vnode.go:115.39,117.2 1 1 34 | github.com/mfrachet/go-vdom-wasm/attrs.go:18.36,19.22 1 1 35 | github.com/mfrachet/go-vdom-wasm/attrs.go:23.2,23.28 1 1 36 | github.com/mfrachet/go-vdom-wasm/attrs.go:27.2,27.29 1 1 37 | github.com/mfrachet/go-vdom-wasm/attrs.go:31.2,31.14 1 1 38 | github.com/mfrachet/go-vdom-wasm/attrs.go:19.22,21.3 1 1 39 | github.com/mfrachet/go-vdom-wasm/attrs.go:23.28,25.3 1 1 40 | github.com/mfrachet/go-vdom-wasm/attrs.go:27.29,29.3 1 1 41 | github.com/mfrachet/go-vdom-wasm/h.go:3.52,9.31 5 1 42 | github.com/mfrachet/go-vdom-wasm/h.go:24.2,26.71 2 1 43 | github.com/mfrachet/go-vdom-wasm/h.go:9.31,10.25 1 1 44 | github.com/mfrachet/go-vdom-wasm/h.go:11.15,12.44 1 1 45 | github.com/mfrachet/go-vdom-wasm/h.go:13.22,14.31 1 1 46 | github.com/mfrachet/go-vdom-wasm/h.go:15.15,16.32 1 1 47 | github.com/mfrachet/go-vdom-wasm/h.go:17.12,18.30 1 1 48 | github.com/mfrachet/go-vdom-wasm/h.go:19.11,20.31 1 1 49 | github.com/mfrachet/go-vdom-wasm/key.go:12.40,14.2 1 1 50 | github.com/mfrachet/go-vdom-wasm/key.go:16.35,18.2 1 1 51 | github.com/mfrachet/go-vdom-wasm/patch.go:8.68,9.24 1 0 52 | github.com/mfrachet/go-vdom-wasm/patch.go:9.24,11.3 1 0 53 | github.com/mfrachet/go-vdom-wasm/patch.go:11.8,11.31 1 0 54 | github.com/mfrachet/go-vdom-wasm/patch.go:11.31,15.3 2 0 55 | github.com/mfrachet/go-vdom-wasm/patch.go:15.8,15.37 1 0 56 | github.com/mfrachet/go-vdom-wasm/patch.go:15.37,20.3 3 0 57 | github.com/mfrachet/go-vdom-wasm/patch.go:20.8,28.28 5 0 58 | github.com/mfrachet/go-vdom-wasm/patch.go:28.28,33.4 3 0 59 | github.com/mfrachet/go-vdom-wasm/patch.go:37.51,38.27 1 0 60 | github.com/mfrachet/go-vdom-wasm/patch.go:39.14,45.31 4 0 61 | github.com/mfrachet/go-vdom-wasm/patch.go:46.10,49.60 2 0 62 | github.com/mfrachet/go-vdom-wasm/reconciler.go:8.52,10.2 1 1 63 | github.com/mfrachet/go-vdom-wasm/reconciler.go:12.34,14.2 1 1 64 | github.com/mfrachet/go-vdom-wasm/reconciler.go:16.72,18.2 1 1 65 | github.com/mfrachet/go-vdom-wasm/reconciler.go:20.65,24.44 3 1 66 | github.com/mfrachet/go-vdom-wasm/reconciler.go:28.2,28.48 1 1 67 | github.com/mfrachet/go-vdom-wasm/reconciler.go:32.2,32.16 1 1 68 | github.com/mfrachet/go-vdom-wasm/reconciler.go:24.44,26.3 1 1 69 | github.com/mfrachet/go-vdom-wasm/reconciler.go:28.48,30.3 1 1 70 | github.com/mfrachet/go-vdom-wasm/reconciler.go:35.54,37.26 2 0 71 | github.com/mfrachet/go-vdom-wasm/reconciler.go:37.26,42.3 3 0 72 | github.com/mfrachet/go-vdom-wasm/reconciler.go:42.8,43.42 1 0 73 | github.com/mfrachet/go-vdom-wasm/reconciler.go:43.42,46.4 2 0 74 | github.com/mfrachet/go-vdom-wasm/reconciler.go:50.67,51.24 1 1 75 | github.com/mfrachet/go-vdom-wasm/reconciler.go:55.2,60.19 4 0 76 | github.com/mfrachet/go-vdom-wasm/reconciler.go:51.24,53.3 1 1 77 | github.com/mfrachet/go-vdom-wasm/textnode.go:12.42,14.2 1 1 78 | github.com/mfrachet/go-vdom-wasm/textnode.go:16.53,18.2 1 1 79 | github.com/mfrachet/go-vdom-wasm/textnode.go:20.45,22.2 1 1 80 | github.com/mfrachet/go-vdom-wasm/textnode.go:24.59,26.2 1 1 81 | github.com/mfrachet/go-vdom-wasm/textnode.go:28.56,31.2 1 1 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

go-vdom-wasm

5 | 6 | This package allows to build frontend applications in Go targeting [Webassembly](https://webassembly.org/). It provides a conveniant syntax close to the [hyperscript](https://github.com/hyperhype/hyperscript) one in the JavaScript lands and aims to provide _efficient_ way to deal with the [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model). If you're not familiar the Virtual DOM notion, I suggest you take a look at [this document](). 7 | 8 | :warning: This package is not production ready. Use at your own risks. A [Todos](#todos) section is available if you want to take part of the projet and try to make it better. You can also check the [Go + WASM wiki](https://github.com/golang/go/wiki/WebAssembly) to get a better overview of the Webassembly support for the Go language. 9 | 10 | This module has been inspired by the awesome work of [@mbasso](https://github.com/mbasso) on https://github.com/mbasso/asm-dom. 11 | 12 | [Want to see go-vdom-wasm in action?](https://mfrachet.github.io/go-vdom-wasm/) 13 | 14 | # Ready to start? 15 | 16 | - [Before starting](#before-starting) 17 | - [Install the module](#install-the-module) 18 | - [Usage](#usage) 19 | - [Todos](#todos) 20 | 21 | ## Before starting 22 | 23 | You have to make some little configuration that are well explained in the [Go + WASM wiki - Getting started](https://github.com/golang/go/wiki/WebAssembly#getting-started) guide. 24 | 25 | If you prefer a _quickest_ solution, you can also rely on the [go-wasm-cli](https://github.com/mfrachet/go-wasm-cli) utility. It allows to create a WASM application in one command line and to have hot reload while coding. 26 | 27 | ## Install the module 28 | 29 | In your favorite terminal 30 | 31 | ```shell 32 | $ GOOS=js GOARCH=wasm go get github.com/mfrachet/go-vdom-wasm 33 | ``` 34 | 35 | ## Usage 36 | 37 | Let's define the root of our `go-vdom-wasm` application. Everything that the library will work on is **inside** that `div`: 38 | 39 | ```html 40 | 41 | 42 |
43 | ``` 44 | 45 | Let's now `Patch` that node with a virtual one to make something happen: 46 | 47 | ```go 48 | // main.go 49 | 50 | rootNode := vn.H("div", "Hello world") 51 | 52 | vn.Patch("#app", rootNode) 53 | ``` 54 | 55 | ### Passing attributes 56 | 57 | In this example, we set a `class="navbar"` to the underlying `ul` element 58 | 59 | ```go 60 | vn.H("ul", &vn.Props{"class": "navbar"}, vn.Children{ 61 | vn.H("li", "First item"), 62 | vn.H("li", "Second item"), 63 | }), 64 | ``` 65 | 66 | The [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) representation of the previous snippet is: 67 | 68 | ```html 69 | 73 | ``` 74 | 75 | ### Handling events 76 | 77 | The `Ev` structure allows to pass functions to handle specific events. 78 | 79 | In this example, we set a click event on of the the `li`: 80 | 81 | ```go 82 | func handleClick(args []js.Value){ 83 | fmt.Println("I've been clicked!") 84 | } 85 | 86 | func main() { 87 | rootNode := vn.H("ul", &vn.Props{"class": "navbar"}, vn.Children{ 88 | vn.H("li", &vn.Ev{"click": handleClick}, "First item"), 89 | vn.H("li", "Second item"), 90 | }) 91 | 92 | vn.patch("#app", rootNode) 93 | } 94 | 95 | ``` 96 | 97 | This module binds the event using the [`addEventListener` API](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) 98 | 99 | :warning: While using event handler, it's necessary to add en empty `select{}` at the end of the `main` function 100 | 101 | ### Using `keys` in list of item 102 | 103 | For efficient diffing while you're relying a list of items, you can rely on a `key` parameter: 104 | 105 | ```go 106 | vn.H("div", vn.Children{ 107 | vn.H("span", attrsChecked, "Some text"), 108 | }, &vn.Key{"UNIQUE KEY"}) 109 | ``` 110 | 111 | The key aims to identifiy a Node. It has to be unique and will ensure a quick comparison before handling the computation. 112 | The idea is the same (less advanced actually, but here's the idea) as the [React key system](https://reactjs.org/docs/lists-and-keys.html). 113 | 114 | ## Todos 115 | 116 | - [ ] Add more tests :woman_facepalming: :man_facepalming: 117 | - [ ] Find a better solution [to compare two virtual nodes](https://github.com/mfrachet/go-vdom-wasm/blob/bddbb032b6c048cf6ee58368241f4b3d3c427691/vnode.go#L24) 118 | - [ ] Ensure consistency and avoid unecessary rerendering that sometimes occur for the same DOMNodes :question: 119 | - [ ] Make a better abstraction concerning the reconciler (it's a really first step) 120 | - [ ] Rely on Go good practices (reference passing, better algorithms and so forth...) 121 | - [ ] Generating the API doc and adding decent comment in code 122 | - [ ] Find a way to abstract the `[]js.Value` passed in every event handler 123 | -------------------------------------------------------------------------------- /mock/dom.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: dom/dom.go 3 | 4 | // Package mock is a generated GoMock package. 5 | package mock 6 | 7 | import ( 8 | gomock "github.com/golang/mock/gomock" 9 | dom "github.com/mfrachet/go-vdom-wasm/dom" 10 | reflect "reflect" 11 | js "syscall/js" 12 | ) 13 | 14 | // MockDomNode is a mock of DomNode interface 15 | type MockDomNode struct { 16 | ctrl *gomock.Controller 17 | recorder *MockDomNodeMockRecorder 18 | } 19 | 20 | // MockDomNodeMockRecorder is the mock recorder for MockDomNode 21 | type MockDomNodeMockRecorder struct { 22 | mock *MockDomNode 23 | } 24 | 25 | // NewMockDomNode creates a new mock instance 26 | func NewMockDomNode(ctrl *gomock.Controller) *MockDomNode { 27 | mock := &MockDomNode{ctrl: ctrl} 28 | mock.recorder = &MockDomNodeMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use 33 | func (m *MockDomNode) EXPECT() *MockDomNodeMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // QuerySelector mocks base method 38 | func (m *MockDomNode) QuerySelector(arg0 string) dom.DomNode { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "QuerySelector", arg0) 41 | ret0, _ := ret[0].(dom.DomNode) 42 | return ret0 43 | } 44 | 45 | // QuerySelector indicates an expected call of QuerySelector 46 | func (mr *MockDomNodeMockRecorder) QuerySelector(arg0 interface{}) *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QuerySelector", reflect.TypeOf((*MockDomNode)(nil).QuerySelector), arg0) 49 | } 50 | 51 | // AppendChild mocks base method 52 | func (m *MockDomNode) AppendChild(arg0 dom.DomNode) { 53 | m.ctrl.T.Helper() 54 | m.ctrl.Call(m, "AppendChild", arg0) 55 | } 56 | 57 | // AppendChild indicates an expected call of AppendChild 58 | func (mr *MockDomNodeMockRecorder) AppendChild(arg0 interface{}) *gomock.Call { 59 | mr.mock.ctrl.T.Helper() 60 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendChild", reflect.TypeOf((*MockDomNode)(nil).AppendChild), arg0) 61 | } 62 | 63 | // Remove mocks base method 64 | func (m *MockDomNode) Remove() { 65 | m.ctrl.T.Helper() 66 | m.ctrl.Call(m, "Remove") 67 | } 68 | 69 | // Remove indicates an expected call of Remove 70 | func (mr *MockDomNodeMockRecorder) Remove() *gomock.Call { 71 | mr.mock.ctrl.T.Helper() 72 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockDomNode)(nil).Remove)) 73 | } 74 | 75 | // ReplaceWith mocks base method 76 | func (m *MockDomNode) ReplaceWith(arg0 dom.DomNode) { 77 | m.ctrl.T.Helper() 78 | m.ctrl.Call(m, "ReplaceWith", arg0) 79 | } 80 | 81 | // ReplaceWith indicates an expected call of ReplaceWith 82 | func (mr *MockDomNodeMockRecorder) ReplaceWith(arg0 interface{}) *gomock.Call { 83 | mr.mock.ctrl.T.Helper() 84 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceWith", reflect.TypeOf((*MockDomNode)(nil).ReplaceWith), arg0) 85 | } 86 | 87 | // CreateTextNode mocks base method 88 | func (m *MockDomNode) CreateTextNode(arg0 string) dom.DomNode { 89 | m.ctrl.T.Helper() 90 | ret := m.ctrl.Call(m, "CreateTextNode", arg0) 91 | ret0, _ := ret[0].(dom.DomNode) 92 | return ret0 93 | } 94 | 95 | // CreateTextNode indicates an expected call of CreateTextNode 96 | func (mr *MockDomNodeMockRecorder) CreateTextNode(arg0 interface{}) *gomock.Call { 97 | mr.mock.ctrl.T.Helper() 98 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTextNode", reflect.TypeOf((*MockDomNode)(nil).CreateTextNode), arg0) 99 | } 100 | 101 | // CreateElement mocks base method 102 | func (m *MockDomNode) CreateElement(arg0 string) dom.DomNode { 103 | m.ctrl.T.Helper() 104 | ret := m.ctrl.Call(m, "CreateElement", arg0) 105 | ret0, _ := ret[0].(dom.DomNode) 106 | return ret0 107 | } 108 | 109 | // CreateElement indicates an expected call of CreateElement 110 | func (mr *MockDomNodeMockRecorder) CreateElement(arg0 interface{}) *gomock.Call { 111 | mr.mock.ctrl.T.Helper() 112 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateElement", reflect.TypeOf((*MockDomNode)(nil).CreateElement), arg0) 113 | } 114 | 115 | // SetAttribute mocks base method 116 | func (m *MockDomNode) SetAttribute(arg0, arg1 string) { 117 | m.ctrl.T.Helper() 118 | m.ctrl.Call(m, "SetAttribute", arg0, arg1) 119 | } 120 | 121 | // SetAttribute indicates an expected call of SetAttribute 122 | func (mr *MockDomNodeMockRecorder) SetAttribute(arg0, arg1 interface{}) *gomock.Call { 123 | mr.mock.ctrl.T.Helper() 124 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAttribute", reflect.TypeOf((*MockDomNode)(nil).SetAttribute), arg0, arg1) 125 | } 126 | 127 | // AddEventListener mocks base method 128 | func (m *MockDomNode) AddEventListener(arg0 string, arg1 func(js.Value, []js.Value) interface{}) { 129 | m.ctrl.T.Helper() 130 | m.ctrl.Call(m, "AddEventListener", arg0, arg1) 131 | } 132 | 133 | // AddEventListener indicates an expected call of AddEventListener 134 | func (mr *MockDomNodeMockRecorder) AddEventListener(arg0, arg1 interface{}) *gomock.Call { 135 | mr.mock.ctrl.T.Helper() 136 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddEventListener", reflect.TypeOf((*MockDomNode)(nil).AddEventListener), arg0, arg1) 137 | } 138 | 139 | // ChildNodes mocks base method 140 | func (m *MockDomNode) ChildNodes(arg0 int) dom.DomNode { 141 | m.ctrl.T.Helper() 142 | ret := m.ctrl.Call(m, "ChildNodes", arg0) 143 | ret0, _ := ret[0].(dom.DomNode) 144 | return ret0 145 | } 146 | 147 | // ChildNodes indicates an expected call of ChildNodes 148 | func (mr *MockDomNodeMockRecorder) ChildNodes(arg0 interface{}) *gomock.Call { 149 | mr.mock.ctrl.T.Helper() 150 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChildNodes", reflect.TypeOf((*MockDomNode)(nil).ChildNodes), arg0) 151 | } 152 | 153 | // GetBinding mocks base method 154 | func (m *MockDomNode) GetBinding() js.Value { 155 | m.ctrl.T.Helper() 156 | ret := m.ctrl.Call(m, "GetBinding") 157 | ret0, _ := ret[0].(js.Value) 158 | return ret0 159 | } 160 | 161 | // GetBinding indicates an expected call of GetBinding 162 | func (mr *MockDomNodeMockRecorder) GetBinding() *gomock.Call { 163 | mr.mock.ctrl.T.Helper() 164 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBinding", reflect.TypeOf((*MockDomNode)(nil).GetBinding)) 165 | } 166 | 167 | // SetBinding mocks base method 168 | func (m *MockDomNode) SetBinding(arg0 js.Value) { 169 | m.ctrl.T.Helper() 170 | m.ctrl.Call(m, "SetBinding", arg0) 171 | } 172 | 173 | // SetBinding indicates an expected call of SetBinding 174 | func (mr *MockDomNodeMockRecorder) SetBinding(arg0 interface{}) *gomock.Call { 175 | mr.mock.ctrl.T.Helper() 176 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBinding", reflect.TypeOf((*MockDomNode)(nil).SetBinding), arg0) 177 | } 178 | -------------------------------------------------------------------------------- /mock/node.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: vnode.go 3 | 4 | // Package mock is a generated GoMock package. 5 | package mock 6 | 7 | import ( 8 | gomock "github.com/golang/mock/gomock" 9 | go_vdom_wasm "github.com/mfrachet/go-vdom-wasm" 10 | dom "github.com/mfrachet/go-vdom-wasm/dom" 11 | reflect "reflect" 12 | ) 13 | 14 | // MockNode is a mock of Node interface 15 | type MockNode struct { 16 | ctrl *gomock.Controller 17 | recorder *MockNodeMockRecorder 18 | } 19 | 20 | // MockNodeMockRecorder is the mock recorder for MockNode 21 | type MockNodeMockRecorder struct { 22 | mock *MockNode 23 | } 24 | 25 | // NewMockNode creates a new mock instance 26 | func NewMockNode(ctrl *gomock.Controller) *MockNode { 27 | mock := &MockNode{ctrl: ctrl} 28 | mock.recorder = &MockNodeMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use 33 | func (m *MockNode) EXPECT() *MockNodeMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // GetElement mocks base method 38 | func (m *MockNode) GetElement() *dom.DomNode { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "GetElement") 41 | ret0, _ := ret[0].(*dom.DomNode) 42 | return ret0 43 | } 44 | 45 | // GetElement indicates an expected call of GetElement 46 | func (mr *MockNodeMockRecorder) GetElement() *gomock.Call { 47 | mr.mock.ctrl.T.Helper() 48 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetElement", reflect.TypeOf((*MockNode)(nil).GetElement)) 49 | } 50 | 51 | // GetTagName mocks base method 52 | func (m *MockNode) GetTagName() string { 53 | m.ctrl.T.Helper() 54 | ret := m.ctrl.Call(m, "GetTagName") 55 | ret0, _ := ret[0].(string) 56 | return ret0 57 | } 58 | 59 | // GetTagName indicates an expected call of GetTagName 60 | func (mr *MockNodeMockRecorder) GetTagName() *gomock.Call { 61 | mr.mock.ctrl.T.Helper() 62 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTagName", reflect.TypeOf((*MockNode)(nil).GetTagName)) 63 | } 64 | 65 | // GetAttrs mocks base method 66 | func (m *MockNode) GetAttrs() *go_vdom_wasm.Attrs { 67 | m.ctrl.T.Helper() 68 | ret := m.ctrl.Call(m, "GetAttrs") 69 | ret0, _ := ret[0].(*go_vdom_wasm.Attrs) 70 | return ret0 71 | } 72 | 73 | // GetAttrs indicates an expected call of GetAttrs 74 | func (mr *MockNodeMockRecorder) GetAttrs() *gomock.Call { 75 | mr.mock.ctrl.T.Helper() 76 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttrs", reflect.TypeOf((*MockNode)(nil).GetAttrs)) 77 | } 78 | 79 | // GetKey mocks base method 80 | func (m *MockNode) GetKey() *string { 81 | m.ctrl.T.Helper() 82 | ret := m.ctrl.Call(m, "GetKey") 83 | ret0, _ := ret[0].(*string) 84 | return ret0 85 | } 86 | 87 | // GetKey indicates an expected call of GetKey 88 | func (mr *MockNodeMockRecorder) GetKey() *gomock.Call { 89 | mr.mock.ctrl.T.Helper() 90 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKey", reflect.TypeOf((*MockNode)(nil).GetKey)) 91 | } 92 | 93 | // HasElement mocks base method 94 | func (m *MockNode) HasElement() bool { 95 | m.ctrl.T.Helper() 96 | ret := m.ctrl.Call(m, "HasElement") 97 | ret0, _ := ret[0].(bool) 98 | return ret0 99 | } 100 | 101 | // HasElement indicates an expected call of HasElement 102 | func (mr *MockNodeMockRecorder) HasElement() *gomock.Call { 103 | mr.mock.ctrl.T.Helper() 104 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasElement", reflect.TypeOf((*MockNode)(nil).HasElement)) 105 | } 106 | 107 | // SetElement mocks base method 108 | func (m *MockNode) SetElement(arg0 dom.DomNode) { 109 | m.ctrl.T.Helper() 110 | m.ctrl.Call(m, "SetElement", arg0) 111 | } 112 | 113 | // SetElement indicates an expected call of SetElement 114 | func (mr *MockNodeMockRecorder) SetElement(arg0 interface{}) *gomock.Call { 115 | mr.mock.ctrl.T.Helper() 116 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetElement", reflect.TypeOf((*MockNode)(nil).SetElement), arg0) 117 | } 118 | 119 | // HashCode mocks base method 120 | func (m *MockNode) HashCode() string { 121 | m.ctrl.T.Helper() 122 | ret := m.ctrl.Call(m, "HashCode") 123 | ret0, _ := ret[0].(string) 124 | return ret0 125 | } 126 | 127 | // HashCode indicates an expected call of HashCode 128 | func (mr *MockNodeMockRecorder) HashCode() *gomock.Call { 129 | mr.mock.ctrl.T.Helper() 130 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HashCode", reflect.TypeOf((*MockNode)(nil).HashCode)) 131 | } 132 | 133 | // ChildrenCount mocks base method 134 | func (m *MockNode) ChildrenCount() int { 135 | m.ctrl.T.Helper() 136 | ret := m.ctrl.Call(m, "ChildrenCount") 137 | ret0, _ := ret[0].(int) 138 | return ret0 139 | } 140 | 141 | // ChildrenCount indicates an expected call of ChildrenCount 142 | func (mr *MockNodeMockRecorder) ChildrenCount() *gomock.Call { 143 | mr.mock.ctrl.T.Helper() 144 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChildrenCount", reflect.TypeOf((*MockNode)(nil).ChildrenCount)) 145 | } 146 | 147 | // ChildAt mocks base method 148 | func (m *MockNode) ChildAt(arg0 int) go_vdom_wasm.Node { 149 | m.ctrl.T.Helper() 150 | ret := m.ctrl.Call(m, "ChildAt", arg0) 151 | ret0, _ := ret[0].(go_vdom_wasm.Node) 152 | return ret0 153 | } 154 | 155 | // ChildAt indicates an expected call of ChildAt 156 | func (mr *MockNodeMockRecorder) ChildAt(arg0 interface{}) *gomock.Call { 157 | mr.mock.ctrl.T.Helper() 158 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChildAt", reflect.TypeOf((*MockNode)(nil).ChildAt), arg0) 159 | } 160 | 161 | // GetText mocks base method 162 | func (m *MockNode) GetText() *go_vdom_wasm.TextNode { 163 | m.ctrl.T.Helper() 164 | ret := m.ctrl.Call(m, "GetText") 165 | ret0, _ := ret[0].(*go_vdom_wasm.TextNode) 166 | return ret0 167 | } 168 | 169 | // GetText indicates an expected call of GetText 170 | func (mr *MockNodeMockRecorder) GetText() *gomock.Call { 171 | mr.mock.ctrl.T.Helper() 172 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetText", reflect.TypeOf((*MockNode)(nil).GetText)) 173 | } 174 | 175 | // GetChildren mocks base method 176 | func (m *MockNode) GetChildren() go_vdom_wasm.Children { 177 | m.ctrl.T.Helper() 178 | ret := m.ctrl.Call(m, "GetChildren") 179 | ret0, _ := ret[0].(go_vdom_wasm.Children) 180 | return ret0 181 | } 182 | 183 | // GetChildren indicates an expected call of GetChildren 184 | func (mr *MockNodeMockRecorder) GetChildren() *gomock.Call { 185 | mr.mock.ctrl.T.Helper() 186 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChildren", reflect.TypeOf((*MockNode)(nil).GetChildren)) 187 | } 188 | 189 | // IsSame mocks base method 190 | func (m *MockNode) IsSame(arg0 go_vdom_wasm.Node) bool { 191 | m.ctrl.T.Helper() 192 | ret := m.ctrl.Call(m, "IsSame", arg0) 193 | ret0, _ := ret[0].(bool) 194 | return ret0 195 | } 196 | 197 | // IsSame indicates an expected call of IsSame 198 | func (mr *MockNodeMockRecorder) IsSame(arg0 interface{}) *gomock.Call { 199 | mr.mock.ctrl.T.Helper() 200 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSame", reflect.TypeOf((*MockNode)(nil).IsSame), arg0) 201 | } 202 | --------------------------------------------------------------------------------