summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--management/editor/repeaters.go101
-rw-r--r--system/admin/static/dashboard/css/admin.css4
2 files changed, 91 insertions, 14 deletions
diff --git a/management/editor/repeaters.go b/management/editor/repeaters.go
index f9c4da6..f84c5ad 100644
--- a/management/editor/repeaters.go
+++ b/management/editor/repeaters.go
@@ -5,11 +5,11 @@ import (
"strings"
)
-// RepeatSelect returns the []byte of a <select> HTML element plus internal <options> with a label.
+// SelectRepeater 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 RepeatSelect(fieldName string, p interface{}, attrs, options map[string]string) []byte {
+func SelectRepeater(fieldName string, p interface{}, attrs, options map[string]string) []byte {
// options are the value attr and the display value, i.e.
// <option value="{map key}">{map value}</option>
scope := tagNameFromStructField(fieldName, p)
@@ -78,12 +78,86 @@ func RepeatSelect(fieldName string, p interface{}, attrs, options map[string]str
}
html.WriteString(`</span>`)
- return append(html.Bytes(), RepeatController(fieldName, p, "select")...)
+ return append(html.Bytes(), RepeatController(fieldName, p, "select", ".input-field")...)
+}
+
+// FileRepeater returns the []byte of a <input type="file"> HTML element 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 FileRepeater(fieldName string, p interface{}, attrs map[string]string) []byte {
+ name := tagNameFromStructField(fieldName, p)
+ tmpl :=
+ `<div class="file-input ` + name + ` input-field col s12">
+ <label class="active">` + attrs["label"] + `</label>
+ <div class="file-field input-field">
+ <div class="btn">
+ <span>Upload</span>
+ <input class="upload" type="file">
+ </div>
+ <div class="file-path-wrapper">
+ <input class="file-path validate" placeholder="` + attrs["label"] + `" type="text">
+ </div>
+ </div>
+ <div class="preview"><div class="img-clip"></div></div>
+ <input class="store ` + name + `" type="hidden" name="` + name + `" value="` + valueFromStructField(fieldName, p) + `" />
+ </div>`
+
+ script :=
+ `<script>
+ $(function() {
+ var $file = $('.file-input.` + name + `'),
+ upload = $file.find('input.upload'),
+ store = $file.find('input.store'),
+ preview = $file.find('.preview'),
+ clip = preview.find('.img-clip'),
+ reset = document.createElement('div'),
+ img = document.createElement('img'),
+ uploadSrc = store.val();
+ preview.hide();
+
+ // when ` + name + ` input changes (file is selected), remove
+ // the 'name' and 'value' attrs from the hidden store input.
+ // add the 'name' attr to ` + name + ` input
+ upload.on('change', function(e) {
+ resetImage();
+ });
+
+ if (uploadSrc.length > 0) {
+ $(img).attr('src', store.val());
+ clip.append(img);
+ preview.show();
+
+ $(reset).addClass('reset ` + name + ` btn waves-effect waves-light grey');
+ $(reset).html('<i class="material-icons tiny">clear<i>');
+ $(reset).on('click', function(e) {
+ e.preventDefault();
+ preview.animate({"opacity": 0.1}, 200, function() {
+ preview.slideUp(250, function() {
+ resetImage();
+ });
+ })
+
+ });
+ clip.append(reset);
+ }
+
+ function resetImage() {
+ store.val('');
+ store.attr('name', '');
+ upload.attr('name', '` + name + `');
+ clip.empty();
+ }
+ });
+ </script>`
+
+ html := `<span class="__ponzu-repeat ` + name + `">` + tmpl + `</span>`
+ return append([]byte(html+script), RepeatController(fieldName, p, "input.store."+name, "div.file-input."+name)...)
}
// RepeatController generates the javascript to control any repeatable form
// element in an editor based on its type, field name and HTML tag name
-func RepeatController(fieldName string, p interface{}, htmlTagName string) []byte {
+func RepeatController(fieldName string, p interface{}, inputSelector, cloneSelector string) []byte {
scope := tagNameFromStructField(fieldName, p)
script := `
<script>
@@ -92,7 +166,7 @@ func RepeatController(fieldName string, p interface{}, htmlTagName string) []byt
var scope = $('.__ponzu-repeat.` + scope + `');
var getChildren = function() {
- return scope.find('` + htmlTagName + `')
+ return scope.find('` + inputSelector + `')
}
var resetFieldNames = function() {
@@ -113,15 +187,17 @@ func RepeatController(fieldName string, p interface{}, htmlTagName string) []byt
var addRepeater = function(e) {
e.preventDefault();
+ var add = e.target;
+
// find and clone the repeatable input-like element
- var controls = $(e.target).parent();
- var clone = controls.parent().clone();
+ var subject = $(add).parent().closest('` + cloneSelector + `');
+ var clone = subject.clone();
// if repeat has label, remove it
clone.find('label').remove();
// remove the pre-filled value from clone
- clone.find('` + htmlTagName + `').val("");
+ clone.find('` + inputSelector + `').val("");
// remove controls if already present
clone.find('.controls').remove();
@@ -144,15 +220,12 @@ func RepeatController(fieldName string, p interface{}, htmlTagName string) []byt
var del = e.target;
// pass label onto next input-like element if del 0 index
- var wrapper = $(del).parent().parent();
- if (wrapper.find('` + htmlTagName + `').attr('name') === '` + scope + `.0') {
+ var wrapper = $(del).parent().closest('` + cloneSelector + `');
+ if (wrapper.find('` + inputSelector + `').attr('name') === '` + scope + `.0') {
wrapper.next().append(wrapper.find('label'))
}
- // find the outermost element which is the input-like element
- // within the scope that contains the repeater control (-) and
- // delete it
- $(del).parent().parent().remove();
+ wrapper.remove();
resetFieldNames();
}
diff --git a/system/admin/static/dashboard/css/admin.css b/system/admin/static/dashboard/css/admin.css
index 4d6e444..9cba7d0 100644
--- a/system/admin/static/dashboard/css/admin.css
+++ b/system/admin/static/dashboard/css/admin.css
@@ -221,4 +221,8 @@ li:hover .quick-delete-post, li:hover .delete-user {
.approve-details {
text-align: right;
padding: 10px 0 !important;
+}
+
+select {
+ border: 1px solid #e2e2e2;
} \ No newline at end of file