-
-
Notifications
You must be signed in to change notification settings - Fork 144
/
dom_js.go
153 lines (125 loc) · 3.48 KB
/
dom_js.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// +build js
package vecty
import "syscall/js"
// Event represents a DOM event.
type Event struct {
js.Value
Target js.Value
}
// Node returns the underlying JavaScript Element or TextNode.
//
// It panics if it is called before the DOM node has been attached, i.e. before
// the associated component's Mounter interface would be invoked.
func (h *HTML) Node() js.Value {
if h.node == nil {
panic("vecty: cannot call (*HTML).Node() before DOM node creation / component mount")
}
return h.node.(wrappedObject).j
}
// RenderIntoNode renders the given component into the existing HTML element by
// replacing it.
//
// If the Component's Render method does not return an element of the same type,
// an error of type ElementMismatchError is returned.
func RenderIntoNode(node js.Value, c Component) error {
return renderIntoNode("RenderIntoNode", wrapObject(node), c)
}
func toLower(s string) string {
// We must call the prototype method here to workaround a limitation of
// syscall/js in both Go and GopherJS where we cannot call the
// `toLowerCase` string method. See https://github.com/golang/go/issues/35917
return js.Global().Get("String").Get("prototype").Get("toLowerCase").Call("call", js.ValueOf(s)).String()
}
var globalValue jsObject
func global() jsObject {
if globalValue == nil {
globalValue = wrapObject(js.Global())
}
return globalValue
}
func undefined() wrappedObject {
return wrappedObject{js.Undefined()}
}
func funcOf(fn func(this jsObject, args []jsObject) interface{}) jsFunc {
return &jsFuncImpl{
f: js.FuncOf(func(this js.Value, args []js.Value) interface{} {
wrappedArgs := make([]jsObject, len(args))
for i, arg := range args {
wrappedArgs[i] = wrapObject(arg)
}
return unwrap(fn(wrapObject(this), wrappedArgs))
}),
goFunc: fn,
}
}
type jsFuncImpl struct {
f js.Func
goFunc func(this jsObject, args []jsObject) interface{}
}
func (j *jsFuncImpl) String() string {
// fmt.Sprint(j) would produce the actual implementation of the function in
// JS code which differs across WASM/GopherJS/TinyGo so we instead just
// return an opaque string for testing purposes.
return "func"
}
func (j *jsFuncImpl) Release() { j.f.Release() }
func valueOf(v interface{}) jsObject {
return wrapObject(js.ValueOf(v))
}
func wrapObject(j js.Value) jsObject {
if j.IsNull() {
return nil
}
return wrappedObject{j: j}
}
func unwrap(value interface{}) interface{} {
if v, ok := value.(wrappedObject); ok {
return v.j
}
if v, ok := value.(*jsFuncImpl); ok {
return v.f
}
return value
}
type wrappedObject struct {
j js.Value
}
func (w wrappedObject) Set(key string, value interface{}) {
w.j.Set(key, unwrap(value))
}
func (w wrappedObject) Get(key string) jsObject {
return wrapObject(w.j.Get(key))
}
func (w wrappedObject) Delete(key string) {
w.j.Delete(key)
}
func (w wrappedObject) Call(name string, args ...interface{}) jsObject {
for i, arg := range args {
args[i] = unwrap(arg)
}
return wrapObject(w.j.Call(name, args...))
}
func (w wrappedObject) String() string {
return w.j.String()
}
func (w wrappedObject) Truthy() bool {
return w.j.Truthy()
}
func (w wrappedObject) IsUndefined() bool {
return w.j.IsUndefined()
}
func (w wrappedObject) Equal(other jsObject) bool {
if w.j.IsNull() != (other == nil) {
return false
}
return w.j.Equal(unwrap(other).(js.Value))
}
func (w wrappedObject) Bool() bool {
return w.j.Bool()
}
func (w wrappedObject) Int() int {
return w.j.Int()
}
func (w wrappedObject) Float() float64 {
return w.j.Float()
}