summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/ponzu/options.go23
-rw-r--r--content/post.go24
-rw-r--r--management/editor/elements.go88
-rw-r--r--system/admin/static/dashboard/css/admin.css4
4 files changed, 111 insertions, 28 deletions
diff --git a/cmd/ponzu/options.go b/cmd/ponzu/options.go
index cabe91a..6f42f0c 100644
--- a/cmd/ponzu/options.go
+++ b/cmd/ponzu/options.go
@@ -72,12 +72,12 @@ type {{ .name }} struct {
editor editor.Editor
// required: all maintained {{ .name }} fields must have json tags!
- Title string ` + "`json:" + `"title"` + "`" + `
- Content string ` + "`json:" + `"content"` + "`" + `
- Author string ` + "`json:" + `"author"` + "`" + `
- Picture string ` + "`json:" + `"picture"` + "`" + `
- Category []string ` + "`json:" + `"category"` + "`" + `
- ThemeStyle string ` + "`json:" + `"theme"` + "`" + `
+ Title string ` + "`json:" + `"title"` + "`" + `
+ Content string ` + "`json:" + `"content"` + "`" + `
+ Author string ` + "`json:" + `"author"` + "`" + `
+ Photo string ` + "`json:" + `"picture"` + "`" + `
+ Category []string ` + "`json:" + `"category"` + "`" + `
+ Theme string ` + "`json:" + `"theme"` + "`" + `
}
func init() {
@@ -101,7 +101,6 @@ func ({{ .initial }} *{{ .name }}) Editor() *editor.Editor { return &{{ .initial
// MarshalEditor writes a buffer of html to edit a {{ .name }} and partially implements editor.Editable
func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
-/* EXAMPLE CODE (from post.go, the default content type) */
view, err := editor.Form({{ .initial }},
editor.Field{
// Take careful note that the first argument to these Input-like methods
@@ -127,22 +126,18 @@ func ({{ .initial }} *{{ .name }}) MarshalEditor() ([]byte, error) {
}),
},
editor.Field{
- View: editor.File("Picture", {{ .initial }}, map[string]string{
+ View: editor.File("Photo", {{ .initial }}, map[string]string{
"label": "Author Photo",
"placeholder": "Upload a profile picture for the author",
}),
},
editor.Field{
- View: editor.Checkbox("Category", {{ .initial }}, map[string]string{
+ View: editor.Tags("Category", {{ .initial }}, map[string]string{
"label": "{{ .name }} Category",
- }, map[string]string{
- "important": "Important",
- "active": "Active",
- "unplanned": "Unplanned",
}),
},
editor.Field{
- View: editor.Select("ThemeStyle", {{ .initial }}, map[string]string{
+ View: editor.Select("Theme", {{ .initial }}, map[string]string{
"label": "Theme Style",
}, map[string]string{
"dark": "Dark",
diff --git a/content/post.go b/content/post.go
index 7dc99c1..d121ed7 100644
--- a/content/post.go
+++ b/content/post.go
@@ -11,12 +11,12 @@ type Post struct {
Item
editor editor.Editor
- Title string `json:"title"`
- Content string `json:"content"`
- Photo string `json:"photo"`
- Author string `json:"author"`
- Category []string `json:"category"`
- ThemeStyle string `json:"theme"`
+ Title string `json:"title"`
+ Content string `json:"content"`
+ Photo string `json:"photo"`
+ Author string `json:"author"`
+ Category []string `json:"category"`
+ Theme string `json:"theme"`
}
func init() {
@@ -55,7 +55,7 @@ func (p *Post) MarshalEditor() ([]byte, error) {
}),
},
editor.Field{
- View: editor.File("Picture", p, map[string]string{
+ View: editor.File("Photo", p, map[string]string{
"label": "Author Photo",
"placeholder": "Upload a profile picture for the author",
}),
@@ -68,16 +68,12 @@ func (p *Post) MarshalEditor() ([]byte, error) {
}),
},
editor.Field{
- View: editor.Checkbox("Category", p, map[string]string{
- "label": "Post Category",
- }, map[string]string{
- "important": "Important",
- "active": "Active",
- "unplanned": "Unplanned",
+ View: editor.Tags("Category", p, map[string]string{
+ "label": "Post Categories",
}),
},
editor.Field{
- View: editor.Select("ThemeStyle", p, map[string]string{
+ View: editor.Select("Theme", p, map[string]string{
"label": "Theme Style",
}, map[string]string{
"dark": "Dark",
diff --git a/management/editor/elements.go b/management/editor/elements.go
index 4d829ad..2326358 100644
--- a/management/editor/elements.go
+++ b/management/editor/elements.go
@@ -332,6 +332,94 @@ func Checkbox(fieldName string, p interface{}, attrs, options map[string]string)
return domElementWithChildrenCheckbox(div, opts)
}
+// Tags returns the []byte of a tag input (in the style of Materialze 'Chips') 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 Tags(fieldName string, p interface{}, attrs map[string]string) []byte {
+ name := tagNameFromStructField(fieldName, p)
+
+ // get the saved tags if this is already an existing post
+ values := valueFromStructField(fieldName, p) // returns refelct.Value
+ tags := values.Slice(0, values.Len()).Interface().([]string) // casts reflect.Value to []string
+
+ html := `
+ <div class="col s12 tags ` + name + `">
+ <label class="active">` + attrs["label"] + ` (Type and press "Enter")</label>
+ <div class="chips ` + name + `"></div>
+ `
+
+ var initial []string
+ i := 0
+ for _, tag := range tags {
+ tagName := tagNameFromStructFieldMulti(fieldName, i, p)
+ html += `<input type="hidden" class="tag ` + tag + `" name=` + tagName + ` value="` + tag + `"/>`
+ initial = append(initial, `{tag: '`+tag+`'}`)
+ i++
+ }
+
+ script := `
+ <script>
+ $(function() {
+ var tags = $('.tags.` + name + `');
+ $('.chips.` + name + `').material_chip({
+ data: [` + strings.Join(initial, ",") + `],
+ secondaryPlaceholder: '+` + name + `'
+ });
+
+ // handle events specific to tags
+ var chips = tags.find('.chips');
+
+ chips.on('chip.add', function(e, chip) {
+ chips.parent().find('.empty-tag').remove();
+
+ var input = $('<input>');
+ input.attr({
+ class: 'tag '+chip.tag,
+ name: '` + name + `.'+String(tags.find('input[type=hidden]').length),
+ value: chip.tag,
+ type: 'hidden'
+ });
+
+ tags.append(input);
+ });
+
+ chips.on('chip.delete', function(e, chip) {
+ // convert tag string to class-like selector "some tag" -> ".some.tag"
+ var sel = '.tag.'+chip.tag.split(' ').join('.');
+ console.log(sel);
+ console.log(chips.parent().find(sel));
+ chips.parent().find(sel).remove();
+
+ // iterate through all hidden tag inputs to re-name them with the correct ` + name + `.index
+ var hidden = chips.parent().find('input[type=hidden]');
+
+ // if there are no tags, set a blank
+ if (hidden.length === 0) {
+ var input = $('<input>');
+ input.attr({
+ class: 'empty-tag',
+ name: '` + name + `',
+ type: 'hidden'
+ });
+
+ tags.append(input);
+ return;
+ }
+
+ for (var i = 0; i < hidden.length; i++) {
+ $(hidden[i]).attr('name', '` + name + `.'+String(i));
+ }
+ });
+ });
+ </script>
+ `
+
+ html += `</div>`
+
+ return []byte(html + script)
+}
+
// domElementSelfClose is a special DOM element which is parsed as a
// self-closing tag and thus needs to be created differently
func domElementSelfClose(e *element) []byte {
diff --git a/system/admin/static/dashboard/css/admin.css b/system/admin/static/dashboard/css/admin.css
index 7acffab..1de966d 100644
--- a/system/admin/static/dashboard/css/admin.css
+++ b/system/admin/static/dashboard/css/admin.css
@@ -203,3 +203,7 @@ li:hover .quick-delete-post, li:hover .delete-user {
-o-transform: translateY(-140%);
transform: translateY(-140%);
}
+
+.chips {
+ margin-top: 10px;
+} \ No newline at end of file