-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathreference.go
151 lines (126 loc) · 4.44 KB
/
reference.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
// Package reference is a Ponzu addon to enable content editors to create
// references to other content types which are stored as query strings within
// the referencer's content DB
package reference
import (
"bytes"
"encoding/json"
"fmt"
"html"
"html/template"
"log"
"strings"
"github.com/ponzu-cms/ponzu/management/editor"
"github.com/ponzu-cms/ponzu/system/addon"
)
// Select returns the []byte of a <select> HTML element plus internal <options> with a label.
// IMPORTANT:
// The `fieldName` argument will cause a panic if it is not exactly the string
// form of the struct field that this editor input is representing
func Select(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
options, err := encodeDataToOptions(contentType, tmplString)
if err != nil {
log.Println("Error encoding data to options for", contentType, err)
return nil
}
return editor.Select(fieldName, p, attrs, options)
}
// SelectRepeater returns the []byte of a <select> HTML element plus internal <options> with a label.
// It also includes repeat controllers (+ / -) so the element can be
// dynamically multiplied or reduced.
// IMPORTANT:
// The `fieldName` argument will cause a panic if it is not exactly the string
// form of the struct field that this editor input is representing
func SelectRepeater(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte {
scope := editor.TagNameFromStructField(fieldName, p)
html := bytes.Buffer{}
_, err := html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`)
if err != nil {
log.Println("Error writing HTML string to SelectRepeater buffer")
return nil
}
if _, ok := attrs["class"]; ok {
attrs["class"] += " browser-default"
} else {
attrs["class"] = "browser-default"
}
// find the field values in p to determine if an option is pre-selected
fieldVals := editor.ValueFromStructField(fieldName, p)
vals := strings.Split(fieldVals, "__ponzu")
options, err := encodeDataToOptions(contentType, tmplString)
if err != nil {
log.Println("Error encoding data to options for", contentType, err)
return nil
}
for _, val := range vals {
sel := editor.NewElement("select", attrs["label"], fieldName, p, attrs)
var opts []*editor.Element
// provide a call to action for the select element
cta := &editor.Element{
TagName: "option",
Attrs: map[string]string{"disabled": "true", "selected": "true"},
Data: "Select an option...",
ViewBuf: &bytes.Buffer{},
}
// provide a selection reset (will store empty string in db)
reset := &editor.Element{
TagName: "option",
Attrs: map[string]string{"value": ""},
Data: "None",
ViewBuf: &bytes.Buffer{},
}
opts = append(opts, cta, reset)
for k, v := range options {
optAttrs := map[string]string{"value": k}
if k == val {
optAttrs["selected"] = "true"
}
opt := &editor.Element{
TagName: "option",
Attrs: optAttrs,
Data: v,
ViewBuf: &bytes.Buffer{},
}
opts = append(opts, opt)
}
_, err := html.Write(editor.DOMElementWithChildrenSelect(sel, opts))
if err != nil {
log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer")
return nil
}
}
_, err = html.WriteString("</span>")
if err != nil {
log.Println("Error writing HTML string to SelectRepeater buffer")
return nil
}
return append(html.Bytes(), editor.RepeatController(fieldName, p, "select", ".input-field")...)
}
func encodeDataToOptions(contentType, tmplString string) (map[string]string, error) {
// encode all content type from db into options map
// options in form of map["/api/content?type=<contentType>&id=<id>"]t.String()
options := make(map[string]string)
var all map[string]interface{}
j := addon.ContentAll(contentType)
err := json.Unmarshal(j, &all)
if err != nil {
return nil, err
}
// make template for option html display
tmpl := template.Must(template.New(contentType).Parse(tmplString))
// make data something usable to iterate over and assign options
data := all["data"].([]interface{})
for i := range data {
item := data[i].(map[string]interface{})
k := fmt.Sprintf("/api/content?type=%s&id=%.0f", contentType, item["id"].(float64))
v := &bytes.Buffer{}
err := tmpl.Execute(v, item)
if err != nil {
return nil, fmt.Errorf(
"Error executing template for reference of %s: %s",
contentType, err.Error())
}
options[k] = html.UnescapeString(v.String())
}
return options, nil
}