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
|
// Package editor enables users to create edit views from their content
// structs so that admins can manage content
package editor
import (
"bytes"
)
// Editable ensures data is editable
type Editable interface {
SetContentID(id int)
ContentID() int
ContentName() string
SetSlug(slug string)
Editor() *Editor
MarshalEditor() ([]byte, error)
}
// Editor is a view containing fields to manage content
type Editor struct {
ViewBuf *bytes.Buffer
}
// Field is used to create the editable view for a field
// within a particular content struct
type Field struct {
View []byte
}
// Form takes editable content and any number of Field funcs to describe the edit
// page for any content struct added by a user
func Form(post Editable, fields ...Field) ([]byte, error) {
editor := post.Editor()
editor.ViewBuf = &bytes.Buffer{}
editor.ViewBuf.Write([]byte(`<table><tbody class="row"><tr class="col s8"><td>`))
for _, f := range fields {
addFieldToEditorView(editor, f)
}
editor.ViewBuf.Write([]byte(`</td></tr>`))
// content items with Item embedded have some default fields we need to render
editor.ViewBuf.Write([]byte(`<tr class="col s4 default-fields"><td>`))
addPostDefaultFieldsToEditorView(post, editor)
submit := `
<div class="input-field post-controls">
<button class="right waves-effect waves-light btn green save-post" type="submit">Save</button>
<button class="right waves-effect waves-light btn red delete-post" type="submit">Delete</button>
</div>
<script>
$(function() {
var form = $('form'),
del = form.find('button.delete-post'),
id = form.find('input[name=id]');
// hide delete button if this is a new post, or a non-post editor page
if (id.val() === '-1' || form.attr('action') !== '/admin/edit') {
del.hide();
}
del.on('click', function(e) {
e.preventDefault();
var action = form.attr('action');
action = action + '/delete';
form.attr('action', action);
if (confirm("[Ponzu] Please confirm:\n\nAre you sure you want to delete this post?\nThis cannot be undone.")) {
form.submit();
}
});
});
</script>
`
editor.ViewBuf.Write([]byte(submit + `</td></tr></tbody></table>`))
return editor.ViewBuf.Bytes(), nil
}
func addFieldToEditorView(e *Editor, f Field) {
e.ViewBuf.Write(f.View)
}
func addPostDefaultFieldsToEditorView(p Editable, e *Editor) {
defaults := []Field{
Field{
View: Input("Timestamp", p, map[string]string{
"label": "Publish Date",
"type": "date",
}),
},
Field{
View: Input("Slug", p, map[string]string{
"label": "URL Slug",
"type": "text",
"disabled": "true",
"placeholder": "Will be set automatically",
}),
},
}
for _, f := range defaults {
addFieldToEditorView(e, f)
}
}
|