gopherjs - mutation/mutation.go
1 // Package mutation provides a wrapper for the MutationObserver API
2 package mutation // import "vimagination.zapto.org/gopherjs/mutation"
3
4 import (
5 "github.com/gopherjs/gopherjs/js"
6 "honnef.co/go/js/dom"
7 )
8
9 // Observer wraps a MutationObserver javascript object
10 type Observer struct {
11 *js.Object
12 }
13
14 // New creates a new wrapper around MutationObserver, which is created with the
15 // given callback
16 func New(f func([]*Record, *Observer)) *Observer {
17 return &Observer{js.Global.Get("MutationObserver").New(f)}
18 }
19
20 // Observe registers a DOM Node to receive events for
21 func (m *Observer) Observe(n dom.Node, i ObserverInit) {
22 j := js.Global.Get("Object").Get("constructor").New()
23 j.Set("childList", i.ChildList)
24 j.Set("attributes", i.Attributes)
25 j.Set("characterData", i.CharacterData)
26 j.Set("subtree", i.Subtree)
27 j.Set("attributeOldValue", i.AttributeOldValue)
28 j.Set("characterDataOldValue", i.CharacterDataOldValue)
29 if i.Attributes {
30 a := js.Get("Array").New(len(i.AttributeFilter))
31 for i, f := range i.AttributeFilter {
32 a.SetIndex(i, f)
33 }
34 j.Set("attributeFilter", a)
35 }
36 m.Call("observe", n.Underlying(), j)
37 }
38
39 // Disconnect stops the observer from receiving events
40 func (m *Observer) Disconnect() {
41 m.Call("disconnect")
42 }
43
44 // TakeRecords empties the record queue, returning what was in it
45 func (m *Observer) TakeRecords() []*Record {
46 o := m.Call("takeRecords")
47 l := o.Length()
48 mrs := make([]*Record, l)
49 for i := 0; i < l; i++ {
50 mrs[i] = &Record{Object: o.Index(i)}
51 }
52 return mrs
53 }
54
55 // Record is a wrapper around a MutationRecord js type
56 type Record struct {
57 *js.Object
58 Type string `js:"type"`
59 AttributeName string `js:"attributeName"`
60 AttributeNamespace string `js:"attributeNamespace"`
61 OldValue string `js:"oldValue"`
62 }
63
64 // Target returns the node associated with the record
65 func (r *Record) Target() dom.Node {
66 return dom.WrapNode(r.Get("target"))
67 }
68
69 func wrapNodes(o *js.Object) []dom.Node {
70 l := o.Length()
71 toRet := make([]dom.Node, l)
72 for i := 0; i < l; i++ {
73 toRet[i] = dom.WrapNode(o.Index(i))
74 }
75 return toRet
76 }
77
78 // AddedNodes returns any nodes that were added
79 func (r *Record) AddedNodes() []dom.Node {
80 return wrapNodes(r.Get("addedNodes"))
81 }
82
83 // RemovedNodes returns any nodes that were added
84 func (r *Record) RemovedNodes() []dom.Node {
85 return wrapNodes(r.Get("removedNodes"))
86 }
87
88 // PreviousSibling returns the previous sibling to any added or removed nodes
89 func (r *Record) PreviousSibling() dom.Node {
90 return dom.WrapNode(r.Get("previousSibling"))
91 }
92
93 // NextSibling returns the next sibling to any added or removed nodes
94 func (r *Record) NextSibling() dom.Node {
95 return dom.WrapNode(r.Get("nextSibling"))
96 }
97
98 // ObserverInit contains the options for observing a Node
99 type ObserverInit struct {
100 ChildList bool
101 Attributes bool
102 CharacterData bool
103 Subtree bool
104 AttributeOldValue bool
105 CharacterDataOldValue bool
106 AttributeFilter []string
107 }
108
109 type observerInit struct {
110 *js.Object
111 ChildList bool `js:"childList"`
112 Attributes bool `js:"attributes"`
113 CharacterData bool `js:"characterData"`
114 Subtree bool `js:"subtree"`
115 AttributeOldValue bool `js:"attributeOldValue"`
116 CharacterDataOldValue bool `js:"characterDataOldValue"`
117 AttributeFilter []string `js:"attributeFilter"`
118 }