diff options
author | Steve Manuel <nilslice@gmail.com> | 2016-12-20 13:15:06 -0800 |
---|---|---|
committer | Steve Manuel <nilslice@gmail.com> | 2016-12-20 13:15:06 -0800 |
commit | f6b39f22c712a11842b83e12879c1ef899337291 (patch) | |
tree | c27918347c2ac39ff04020aaa9bb180b2013cb99 /management | |
parent | e4fa817d305f701be0aeb34c079c93108940e2c3 (diff) |
adding generic RepeatController JS creator and working RepeatSelect repeater input
Diffstat (limited to 'management')
-rw-r--r-- | management/editor/elements.go | 2 | ||||
-rw-r--r-- | management/editor/repeaters.go | 204 | ||||
-rw-r--r-- | management/manager/manager.go | 2 |
3 files changed, 206 insertions, 2 deletions
diff --git a/management/editor/elements.go b/management/editor/elements.go index 9b35c65..75c37e2 100644 --- a/management/editor/elements.go +++ b/management/editor/elements.go @@ -325,7 +325,7 @@ func Checkbox(fieldName string, p interface{}, attrs, options map[string]string) } } - // create a *element manually using the maodified tagNameFromStructFieldMulti + // create a *element manually using the modified tagNameFromStructFieldMulti // func since this is for a multi-value name input := &element{ TagName: "input", diff --git a/management/editor/repeaters.go b/management/editor/repeaters.go new file mode 100644 index 0000000..f9c4da6 --- /dev/null +++ b/management/editor/repeaters.go @@ -0,0 +1,204 @@ +package editor + +import ( + "bytes" + "strings" +) + +// RepeatSelect 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 { + // options are the value attr and the display value, i.e. + // <option value="{map key}">{map value}</option> + scope := tagNameFromStructField(fieldName, p) + html := &bytes.Buffer{} + html.WriteString(`<span class="__ponzu-repeat ` + scope + `">`) + + // find the field values in p to determine if an option is pre-selected + fieldVals := valueFromStructField(fieldName, p) + vals := strings.Split(fieldVals, "__ponzu") + + attrs["class"] = "browser-default" + + // loop through vals and create selects and options for each, adding to html + if len(vals) > 0 { + for i, val := range vals { + sel := &element{ + TagName: "select", + Attrs: attrs, + Name: tagNameFromStructFieldMulti(fieldName, i, p), + viewBuf: &bytes.Buffer{}, + } + + // only add the label to the first select in repeated list + if i == 0 { + sel.label = attrs["label"] + } + + // create options for select element + var opts []*element + + // provide a call to action for the select element + cta := &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 := &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 := &element{ + TagName: "option", + Attrs: optAttrs, + data: v, + viewBuf: &bytes.Buffer{}, + } + + opts = append(opts, opt) + } + + html.Write(domElementWithChildrenSelect(sel, opts)) + } + } + + html.WriteString(`</span>`) + return append(html.Bytes(), RepeatController(fieldName, p, "select")...) +} + +// 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 { + scope := tagNameFromStructField(fieldName, p) + script := ` + <script> + $(function() { + // define the scope of the repeater + var scope = $('.__ponzu-repeat.` + scope + `'); + + var getChildren = function() { + return scope.find('` + htmlTagName + `') + } + + var resetFieldNames = function() { + // loop through children, set its name to the fieldName.i where + // i is the current index number of children array + var children = getChildren(); + for (var i = 0; i < children.length; i++) { + var el = children[i]; + $(el).attr('name', '` + scope + `.'+String(i)); + + // reset controllers + $(el).find('.controls').remove(); + } + + applyRepeatControllers(); + } + + var addRepeater = function(e) { + e.preventDefault(); + + // find and clone the repeatable input-like element + var controls = $(e.target).parent(); + var clone = controls.parent().clone(); + + // if repeat has label, remove it + clone.find('label').remove(); + + // remove the pre-filled value from clone + clone.find('` + htmlTagName + `').val(""); + + // remove controls if already present + clone.find('.controls').remove(); + + // add clone to scope and reset field name attributes + scope.append(clone); + + resetFieldNames(); + } + + var delRepeater = function(e) { + e.preventDefault(); + + // do nothing if the input is the only child + var children = getChildren(); + if (children.length === 1) { + return; + } + + 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') { + 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(); + + resetFieldNames(); + } + + var createControls = function() { + // create + / - controls for each input-like child element of scope + var add = $('<button>+</button>'); + add.addClass('repeater-add'); + add.addClass('btn-flat waves-effect waves-green'); + + var del = $('<button>-</button>'); + del.addClass('repeater-del'); + del.addClass('btn-flat waves-effect waves-red'); + + var controls = $('<span></span>'); + controls.addClass('controls'); + controls.addClass('right'); + + // bind listeners to child's controls + add.on('click', addRepeater); + del.on('click', delRepeater); + + controls.append(add); + controls.append(del); + + return controls; + } + + var applyRepeatControllers = function() { + // add controls to each child + var children = getChildren() + for (var i = 0; i < children.length; i++) { + var el = children[i]; + + $(el).parent().find('.controls').remove(); + + var controls = createControls(); + $(el).parent().append(controls); + } + } + + applyRepeatControllers(); + }); + + </script> + ` + + return []byte(script) +} diff --git a/management/manager/manager.go b/management/manager/manager.go index c54918f..594c258 100644 --- a/management/manager/manager.go +++ b/management/manager/manager.go @@ -136,7 +136,7 @@ func Manage(e editor.Editable, typeName string) ([]byte, error) { ID: i.ItemID(), UUID: i.UniqueID(), Kind: typeName, - Slug: s.ItemSlug(), // TODO: just added this and its implementation -- need to rebuild & test + Slug: s.ItemSlug(), Editor: template.HTML(v), } |