Browse Source

Refactored isomorphic redirect code to be more idiomatic. Added isomorphic template rendering functionality.

Wirecog 7 years ago
parent
commit
31baad93f4
4 changed files with 333 additions and 32 deletions
  1. 15
    32
      redirect.go
  2. 145
    0
      template.go
  3. 117
    0
      templateset.go
  4. 56
    0
      templatesetcontents.go

+ 15
- 32
redirect.go View File

6
 package isokit
6
 package isokit
7
 
7
 
8
 import (
8
 import (
9
+	"errors"
9
 	"net/http"
10
 	"net/http"
10
 
11
 
11
 	"github.com/gopherjs/gopherjs/js"
12
 	"github.com/gopherjs/gopherjs/js"
22
 	js.Get("location").Set("href", destinationURL)
23
 	js.Get("location").Set("href", destinationURL)
23
 }
24
 }
24
 
25
 
25
-// Redirect performs a redirect operation based on the environment that
26
-// the program is operating under.
27
-func Redirect(items ...interface{}) {
28
-	var url string
29
-	var w http.ResponseWriter
30
-	var r *http.Request
31
-
32
-	if OperatingEnvironment() == ServerEnvironment && len(items) != 3 {
33
-		return
34
-	}
35
-
36
-	if OperatingEnvironment() == WebBrowserEnvironment && len(items) != 1 {
37
-		return
38
-	}
39
-
40
-	for _, item := range items {
41
-
42
-		switch t := item.(type) {
43
-		case http.ResponseWriter:
44
-			w = t
45
-		case *http.Request:
46
-			r = t
47
-		case string:
48
-			url = t
49
-		}
26
+type RedirectParams struct {
27
+	ResponseWriter http.ResponseWriter
28
+	Request        *http.Request
29
+	URL            string
30
+}
50
 
31
 
51
-	}
32
+func Redirect(params *RedirectParams) error {
52
 
33
 
53
-	if OperatingEnvironment() == ServerEnvironment && (w == nil || r == nil) {
54
-		return
34
+	if params.URL == "" {
35
+		return errors.New("The URL must be specified!")
55
 	}
36
 	}
56
 
37
 
57
-	if url == "" {
58
-		return
38
+	if OperatingEnvironment() == ServerEnvironment && (params.ResponseWriter == nil || params.Request == nil) {
39
+		return errors.New("Either the response writer and/or the request is nil!")
59
 	}
40
 	}
60
 
41
 
61
 	switch OperatingEnvironment() {
42
 	switch OperatingEnvironment() {
62
 	case WebBrowserEnvironment:
43
 	case WebBrowserEnvironment:
63
-		ClientRedirect(url)
44
+		ClientRedirect(params.URL)
64
 
45
 
65
 	case ServerEnvironment:
46
 	case ServerEnvironment:
66
-		ServerRedirect(w, r, url)
47
+		ServerRedirect(params.ResponseWriter, params.Request, params.URL)
67
 	}
48
 	}
49
+
50
+	return nil
68
 }
51
 }

+ 145
- 0
template.go View File

1
+// The Isomorphic Go 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 isokit
7
+
8
+import (
9
+	"bytes"
10
+	"errors"
11
+	"html/template"
12
+	"net/http"
13
+	"strings"
14
+
15
+	"honnef.co/go/js/dom"
16
+)
17
+
18
+const (
19
+	TemplateRegular = iota
20
+	TemplatePartial
21
+	TemplateLayout
22
+)
23
+
24
+var (
25
+	PrefixNamePartial     = "partials/"
26
+	PrefixNameLayout      = "layouts/"
27
+	TemplateFileExtension = ".tmpl"
28
+	TemplateFilesPath     = "./templates"
29
+)
30
+
31
+type Template struct {
32
+	*template.Template
33
+	templateType int8
34
+}
35
+
36
+const (
37
+	PlacementAppendTo = iota
38
+	PlacementReplaceInnerContents
39
+	PlacementInsertBefore
40
+)
41
+
42
+type RenderParams struct {
43
+	Data           interface{}
44
+	ResponseWriter http.ResponseWriter
45
+	Element        dom.Element
46
+	Disposition    int8
47
+	Attributes     map[string]string
48
+}
49
+
50
+func (t *Template) GetTemplateType() int8 {
51
+
52
+	if t == nil {
53
+		return -1
54
+	} else {
55
+		return t.templateType
56
+	}
57
+}
58
+
59
+func (t *Template) NameWithPrefix() string {
60
+
61
+	var prefixName string
62
+	switch t.templateType {
63
+
64
+	case TemplateRegular:
65
+		prefixName = ""
66
+
67
+	case TemplatePartial:
68
+		prefixName = PrefixNamePartial
69
+
70
+	case TemplateLayout:
71
+		prefixName = PrefixNameLayout
72
+
73
+	}
74
+
75
+	if strings.HasPrefix(t.Name(), prefixName) {
76
+		return t.Name()
77
+	} else {
78
+		return prefixName + t.Name()
79
+	}
80
+
81
+}
82
+
83
+func (t *Template) Render(params *RenderParams) error {
84
+
85
+	if OperatingEnvironment() == ServerEnvironment && (params.ResponseWriter == nil) {
86
+		return errors.New("Either the response writer and/or the request is nil!")
87
+	}
88
+
89
+	if OperatingEnvironment() == WebBrowserEnvironment && params.Element == nil {
90
+		return errors.New("The element to render relative to is nil!")
91
+	}
92
+
93
+	switch OperatingEnvironment() {
94
+	case WebBrowserEnvironment:
95
+		t.RenderTemplateOnClient(params)
96
+
97
+	case ServerEnvironment:
98
+		t.RenderTemplateOnServer(params)
99
+	}
100
+
101
+	return nil
102
+}
103
+
104
+func (t *Template) RenderTemplateOnClient(params *RenderParams) {
105
+
106
+	var tpl bytes.Buffer
107
+
108
+	if err := t.Execute(&tpl, params.Data); err != nil {
109
+		println("error: ", err)
110
+	}
111
+
112
+	div := dom.GetWindow().Document().CreateElement("div").(*dom.HTMLDivElement)
113
+	div.SetInnerHTML(string(tpl.Bytes()))
114
+
115
+	if _, ok := params.Attributes["id"]; ok {
116
+		div.SetID(params.Attributes["id"])
117
+	}
118
+
119
+	if _, ok := params.Attributes["class"]; ok {
120
+		div.SetAttribute("class", params.Attributes["class"])
121
+	}
122
+
123
+	switch params.Disposition {
124
+	case PlacementAppendTo:
125
+		params.Element.AppendChild(div)
126
+	case PlacementReplaceInnerContents:
127
+		params.Element.SetInnerHTML(div.OuterHTML())
128
+	case PlacementInsertBefore:
129
+		params.Element.ParentNode().InsertBefore(div, params.Element)
130
+	default:
131
+		params.Element.AppendChild(div)
132
+	}
133
+
134
+}
135
+
136
+func (t *Template) RenderTemplateOnServer(params *RenderParams) {
137
+
138
+	w := params.ResponseWriter
139
+
140
+	var tpl bytes.Buffer
141
+	if err := t.Execute(&tpl, params.Data); err != nil {
142
+		println("error: ", err)
143
+	}
144
+	w.Write(tpl.Bytes())
145
+}

+ 117
- 0
templateset.go View File

1
+// The Isomorphic Go 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 isokit
7
+
8
+import (
9
+	"html/template"
10
+	"io/ioutil"
11
+	"strings"
12
+)
13
+
14
+type TemplateSet struct {
15
+	members  map[string]*Template
16
+	Funcs    template.FuncMap
17
+	contents *TemplateSetContents
18
+}
19
+
20
+func NewTemplateSet() *TemplateSet {
21
+	return &TemplateSet{
22
+		members: map[string]*Template{},
23
+		Funcs:   template.FuncMap{},
24
+	}
25
+}
26
+
27
+func (t *TemplateSet) Members() map[string]*Template {
28
+	return t.members
29
+}
30
+
31
+func (t *TemplateSet) Contents() *TemplateSetContents {
32
+	return t.contents
33
+}
34
+
35
+func (t *TemplateSet) AddTemplateFile(name, filename string, templateType int8) error {
36
+	contents, err := ioutil.ReadFile(filename)
37
+	if err != nil {
38
+		return err
39
+	}
40
+
41
+	tpl, err := template.New(name).Funcs(t.Funcs).Parse(string(contents))
42
+	template := Template{
43
+		Template:     tpl,
44
+		templateType: templateType,
45
+	}
46
+
47
+	t.members[tpl.Name()] = &template
48
+	return nil
49
+
50
+}
51
+
52
+func (t *TemplateSet) MakeAllAssociations() error {
53
+
54
+	for _, template := range t.members {
55
+
56
+		for _, member := range t.members {
57
+
58
+			if member.Lookup(template.NameWithPrefix()) == nil {
59
+
60
+				if _, err := member.AddParseTree(template.NameWithPrefix(), template.Tree); err != nil {
61
+					println(err)
62
+					return err
63
+				}
64
+			}
65
+
66
+		}
67
+
68
+	}
69
+	return nil
70
+}
71
+
72
+func (t *TemplateSet) ImportTemplatesFromMap(templateMap map[string]string) error {
73
+
74
+	for name, templateContents := range templateMap {
75
+
76
+		var templateType int8
77
+		if strings.Contains(name, PrefixNamePartial) {
78
+			templateType = TemplatePartial
79
+		} else if strings.Contains(name, PrefixNameLayout) {
80
+			templateType = TemplateLayout
81
+		} else {
82
+			templateType = TemplateRegular
83
+		}
84
+
85
+		tpl, err := template.New(name).Funcs(t.Funcs).Parse(templateContents)
86
+
87
+		if err != nil {
88
+			println("Encountered error when attempting to parse template: ", err)
89
+
90
+			return err
91
+		}
92
+
93
+		tmpl := Template{
94
+			Template:     tpl,
95
+			templateType: templateType,
96
+		}
97
+		t.members[name] = &tmpl
98
+
99
+	}
100
+	t.MakeAllAssociations()
101
+	return nil
102
+}
103
+
104
+func (t *TemplateSet) RenderMember(templateName string, params *RenderParams) {
105
+
106
+	t.Members()[templateName].Render(params)
107
+
108
+}
109
+
110
+func (t *TemplateSet) GatherTemplates() {
111
+
112
+	contents := NewTemplateSetContents()
113
+	contents.importTemplateFileContents()
114
+	t.ImportTemplatesFromMap(contents.Items())
115
+	t.contents = contents
116
+
117
+}

+ 56
- 0
templatesetcontents.go View File

1
+// The Isomorphic Go 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 isokit
7
+
8
+import (
9
+	"fmt"
10
+	"io/ioutil"
11
+	"os"
12
+	"path/filepath"
13
+	"strings"
14
+)
15
+
16
+type TemplateSetContents struct {
17
+	items map[string]string
18
+}
19
+
20
+func NewTemplateSetContents() *TemplateSetContents {
21
+
22
+	return &TemplateSetContents{
23
+		items: map[string]string{},
24
+		// Funcs:   template.FuncMap{},
25
+	}
26
+
27
+}
28
+
29
+func (tsc *TemplateSetContents) Items() map[string]string {
30
+	return tsc.items
31
+}
32
+
33
+func (tsc *TemplateSetContents) importTemplateFileContents() error {
34
+
35
+	templateDirectory := filepath.Clean(TemplateFilesPath)
36
+
37
+	if err := filepath.Walk(templateDirectory, func(path string, info os.FileInfo, err error) error {
38
+		if strings.HasSuffix(path, TemplateFileExtension) {
39
+			name := strings.TrimSuffix(strings.TrimPrefix(path, templateDirectory+string(os.PathSeparator)), TemplateFileExtension)
40
+			contents, err := ioutil.ReadFile(path)
41
+			tsc.items[name] = string(contents)
42
+
43
+			if err != nil {
44
+				fmt.Println("error encountered while walking directory: ", err)
45
+				return err
46
+			}
47
+
48
+		}
49
+		return nil
50
+	}); err != nil {
51
+		return err
52
+	}
53
+
54
+	return nil
55
+
56
+}