Browse Source

Initial import

Wirecog 6 years ago
commit
1e7faedce5
5 changed files with 275 additions and 0 deletions
  1. 6
    0
      .gitignore
  2. 29
    0
      LICENSE
  3. 10
    0
      Readme.md
  4. 27
    0
      cog.go
  5. 203
    0
      uxcog.go

+ 6
- 0
.gitignore View File

@@ -0,0 +1,6 @@
1
+*~
2
+*.swp
3
+*.swo
4
+*.tmp
5
+*.out
6
+.DS_Store

+ 29
- 0
LICENSE View File

@@ -0,0 +1,29 @@
1
+The UXToolkit Project
2
+Copyright (c) Wirecog, LLC. All rights reserved.
3
+
4
+Redistribution and use in source and binary forms, with or without
5
+modification, are permitted provided that the following conditions are
6
+met:
7
+
8
+   * Redistributions of source code must retain the above copyright
9
+notice, this list of conditions and the following disclaimer.
10
+   * Redistributions in binary form must reproduce the above
11
+copyright notice, this list of conditions and the following disclaimer
12
+in the documentation and/or other materials provided with the
13
+distribution.
14
+   * Neither the name of Wirecog, LLC. nor the names of its contributors
15
+may be used to endorse or promote products derived from
16
+this software without specific prior written permission.
17
+
18
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+

+ 10
- 0
Readme.md View File

@@ -0,0 +1,10 @@
1
+<p align="center"><a href="http://uxtoolkit.io" target="_blank"><img src="https://avatars3.githubusercontent.com/u/27899635?v=4&s=360"></a></p>
2
+
3
+# Cog
4
+
5
+[![Go Report Card](https://goreportcard.com/badge/github.com/uxtoolkit/cog)](https://goreportcard.com/report/github.com/uxtoolkit/cog)
6
+
7
+The cog package provides functionality to develop reusable components (cogs) for [Isomorphic Go](http://isomorphicgo.org) web applications.
8
+
9
+## License
10
+Cog is licensed under the BSD License. Read the [LICENSE](https://github.com/uxtoolkit/cog/blob/master/LICENSE) file for more information.

+ 27
- 0
cog.go View File

@@ -0,0 +1,27 @@
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
+	"os"
10
+)
11
+
12
+var DefaultTemplatesDirectoryName string
13
+var DefaultGoSourcePath string
14
+var TemplateFileExtension = ".tmpl"
15
+var ReactivityEnabled = true
16
+var VDOMEnabled = true
17
+
18
+type Cog interface {
19
+	Render() error
20
+}
21
+
22
+func init() {
23
+
24
+	DefaultTemplatesDirectoryName = "templates"
25
+	DefaultGoSourcePath = os.Getenv("GOPATH") + "/src"
26
+
27
+}

+ 203
- 0
uxcog.go View File

@@ -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
+}