|
@@ -0,0 +1,203 @@
|
|
1
|
+// The UXToolkit Project
|
|
2
|
+// Copyright (c) Wirecog, LLC. All rights reserved.
|
|
3
|
+// Use of this source code is governed by a BSD-style
|
|
4
|
+// license, which can be found in the LICENSE file.
|
|
5
|
+
|
|
6
|
+package cog
|
|
7
|
+
|
|
8
|
+import (
|
|
9
|
+ "errors"
|
|
10
|
+ "reflect"
|
|
11
|
+ "strings"
|
|
12
|
+
|
|
13
|
+ "github.com/isomorphicgo/isokit"
|
|
14
|
+ "github.com/uxtoolkit/reconcile"
|
|
15
|
+ _ "golang.org/x/net/html"
|
|
16
|
+ "honnef.co/go/js/dom"
|
|
17
|
+)
|
|
18
|
+
|
|
19
|
+type UXCog struct {
|
|
20
|
+ Cog
|
|
21
|
+ cogType reflect.Type
|
|
22
|
+ cogPrefixName string
|
|
23
|
+ cogPackagePath string
|
|
24
|
+ cogTemplatePath string
|
|
25
|
+ templateSet *isokit.TemplateSet
|
|
26
|
+ Props map[string]interface{}
|
|
27
|
+ element *dom.Element
|
|
28
|
+ id string
|
|
29
|
+ hasBeenRendered bool
|
|
30
|
+ parseTree *reconcile.ParseTree
|
|
31
|
+}
|
|
32
|
+
|
|
33
|
+func (u *UXCog) getCogPrefixName() string {
|
|
34
|
+
|
|
35
|
+ if u.cogType != nil {
|
|
36
|
+ result := strings.Split(u.cogType.PkgPath(), `/`)
|
|
37
|
+ return "cog:" + result[len(result)-1]
|
|
38
|
+ } else {
|
|
39
|
+ return ""
|
|
40
|
+ }
|
|
41
|
+}
|
|
42
|
+
|
|
43
|
+func (u *UXCog) ID() string {
|
|
44
|
+ return u.id
|
|
45
|
+}
|
|
46
|
+
|
|
47
|
+func (u *UXCog) SetID(id string) {
|
|
48
|
+ u.id = id
|
|
49
|
+}
|
|
50
|
+
|
|
51
|
+func (u *UXCog) SetElement(element *dom.Element) {
|
|
52
|
+ u.element = element
|
|
53
|
+}
|
|
54
|
+
|
|
55
|
+func (u *UXCog) Element() *dom.Element {
|
|
56
|
+ return u.element
|
|
57
|
+}
|
|
58
|
+
|
|
59
|
+func (u *UXCog) CogInit(ts *isokit.TemplateSet) {
|
|
60
|
+ u.hasBeenRendered = false
|
|
61
|
+ u.Props = make(map[string]interface{})
|
|
62
|
+ if ts != nil {
|
|
63
|
+ u.templateSet = ts
|
|
64
|
+ }
|
|
65
|
+ u.cogTemplatePath = DefaultGoSourcePath + "/" + u.cogType.PkgPath() + "/" + DefaultTemplatesDirectoryName
|
|
66
|
+ u.cogPrefixName = u.getCogPrefixName()
|
|
67
|
+
|
|
68
|
+ if isokit.OperatingEnvironment() == isokit.ServerEnvironment {
|
|
69
|
+ u.RegisterCogTemplates()
|
|
70
|
+ }
|
|
71
|
+}
|
|
72
|
+
|
|
73
|
+func (u *UXCog) TemplateSet() *isokit.TemplateSet {
|
|
74
|
+ return u.templateSet
|
|
75
|
+}
|
|
76
|
+
|
|
77
|
+func (u *UXCog) SetTemplateSet(ts *isokit.TemplateSet) {
|
|
78
|
+ u.templateSet = ts
|
|
79
|
+}
|
|
80
|
+
|
|
81
|
+func (u *UXCog) CogType() reflect.Type {
|
|
82
|
+ return u.cogType
|
|
83
|
+}
|
|
84
|
+
|
|
85
|
+func (u *UXCog) SetCogType(cogType reflect.Type) {
|
|
86
|
+ u.cogType = cogType
|
|
87
|
+}
|
|
88
|
+
|
|
89
|
+func (u *UXCog) CogTemplatePath() string {
|
|
90
|
+ return u.cogTemplatePath
|
|
91
|
+}
|
|
92
|
+
|
|
93
|
+func (u *UXCog) SetCogTemplatePath(path string) {
|
|
94
|
+ u.cogTemplatePath = path
|
|
95
|
+}
|
|
96
|
+
|
|
97
|
+func (u *UXCog) RegisterCogTemplates() {
|
|
98
|
+ u.templateSet.GatherCogTemplates(u.cogTemplatePath, u.cogPrefixName, ".tmpl")
|
|
99
|
+}
|
|
100
|
+
|
|
101
|
+func (u *UXCog) GetProps() map[string]interface{} {
|
|
102
|
+ return u.Props
|
|
103
|
+
|
|
104
|
+}
|
|
105
|
+
|
|
106
|
+func (u *UXCog) SetProp(key string, value interface{}) {
|
|
107
|
+
|
|
108
|
+ u.Props[key] = value
|
|
109
|
+ if ReactivityEnabled == true && u.hasBeenRendered == true {
|
|
110
|
+ u.Render()
|
|
111
|
+ }
|
|
112
|
+
|
|
113
|
+}
|
|
114
|
+
|
|
115
|
+func (u *UXCog) BatchPropUpdate(props map[string]interface{}) {
|
|
116
|
+
|
|
117
|
+ for k, v := range props {
|
|
118
|
+ u.Props[k] = v
|
|
119
|
+ }
|
|
120
|
+ if ReactivityEnabled == true && u.hasBeenRendered == true {
|
|
121
|
+ u.Render()
|
|
122
|
+ }
|
|
123
|
+
|
|
124
|
+}
|
|
125
|
+
|
|
126
|
+func (u *UXCog) RenderCogTemplate() {
|
|
127
|
+
|
|
128
|
+ var populateRenderedContent bool
|
|
129
|
+ if u.hasBeenRendered == false {
|
|
130
|
+ populateRenderedContent = true
|
|
131
|
+ } else {
|
|
132
|
+ populateRenderedContent = false
|
|
133
|
+ }
|
|
134
|
+
|
|
135
|
+ rp := isokit.RenderParams{Data: u.Props, Disposition: isokit.PlacementReplaceInnerContents, Element: *u.element, ShouldPopulateRenderedContent: populateRenderedContent}
|
|
136
|
+
|
|
137
|
+ u.templateSet.Render(u.getCogPrefixName()+"/"+strings.Split(u.getCogPrefixName(), ":")[1], &rp)
|
|
138
|
+
|
|
139
|
+ if u.hasBeenRendered == false {
|
|
140
|
+ u.hasBeenRendered = true
|
|
141
|
+
|
|
142
|
+ D := dom.GetWindow().Document()
|
|
143
|
+ cogRoot := D.GetElementByID(u.id).FirstChild().(*dom.HTMLDivElement)
|
|
144
|
+ contents := cogRoot.InnerHTML()
|
|
145
|
+ parseTree, err := reconcile.NewParseTree([]byte(contents))
|
|
146
|
+ if err != nil {
|
|
147
|
+ println("Encountered an error: ", err)
|
|
148
|
+ } else {
|
|
149
|
+ u.parseTree = parseTree
|
|
150
|
+ }
|
|
151
|
+
|
|
152
|
+ }
|
|
153
|
+}
|
|
154
|
+
|
|
155
|
+func (u *UXCog) Render() error {
|
|
156
|
+ document := dom.GetWindow().Document()
|
|
157
|
+
|
|
158
|
+ e := document.GetElementByID(u.ID())
|
|
159
|
+ if strings.ToLower(e.GetAttribute("data-component")) != "cog" {
|
|
160
|
+ return errors.New("The cog container div must have a \"data-component\" attribute with a value specified as \"cog\".")
|
|
161
|
+ }
|
|
162
|
+
|
|
163
|
+ if u.hasBeenRendered == false {
|
|
164
|
+ // Initial Render
|
|
165
|
+ u.SetElement(&e)
|
|
166
|
+ u.RenderCogTemplate()
|
|
167
|
+
|
|
168
|
+ return nil
|
|
169
|
+ } else if u.element != nil {
|
|
170
|
+ // Re-render
|
|
171
|
+ if VDOMEnabled == true {
|
|
172
|
+
|
|
173
|
+ rp := isokit.RenderParams{Data: u.Props, Disposition: isokit.PlacementReplaceInnerContents, Element: *u.element, ShouldPopulateRenderedContent: true, ShouldSkipFinalRenderStep: true}
|
|
174
|
+ u.templateSet.Render(u.getCogPrefixName()+"/"+strings.Split(u.getCogPrefixName(), ":")[1], &rp)
|
|
175
|
+
|
|
176
|
+ D := dom.GetWindow().Document()
|
|
177
|
+ cogRoot := D.GetElementByID(u.id).FirstChild().(*dom.HTMLDivElement)
|
|
178
|
+ //contents := cogRoot.InnerHTML()
|
|
179
|
+ newTree, err := reconcile.NewParseTree([]byte(rp.RenderedContent))
|
|
180
|
+
|
|
181
|
+ if err != nil {
|
|
182
|
+ println("Encountered an error: ", err)
|
|
183
|
+ }
|
|
184
|
+
|
|
185
|
+ changes, err := u.parseTree.Compare(newTree)
|
|
186
|
+ if err != nil {
|
|
187
|
+ println("Encountered an error: ", err)
|
|
188
|
+ }
|
|
189
|
+ if len(changes) > 0 {
|
|
190
|
+ changes.ApplyChanges(cogRoot)
|
|
191
|
+ u.parseTree = newTree
|
|
192
|
+ }
|
|
193
|
+
|
|
194
|
+ } else {
|
|
195
|
+ u.RenderCogTemplate()
|
|
196
|
+
|
|
197
|
+ }
|
|
198
|
+ return nil
|
|
199
|
+ }
|
|
200
|
+
|
|
201
|
+ return nil
|
|
202
|
+
|
|
203
|
+}
|