Skip to content

Commit

Permalink
Merge pull request #139 from gochigo/update-modules
Browse files Browse the repository at this point in the history
updated dependencies and improved bootstrap 5 support
  • Loading branch information
paganotoni authored Nov 19, 2021
2 parents 7a17e32 + 9a292f2 commit 19b83ad
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ jobs:
- name: Test
run: |
go mod tidy -v
go test -tags "sqlite" -cover ./...
go test -tags "sqlite" -cover ./...
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,3 @@ Documentation is currently in [this repository Wiki](https://github.com/gobuffal
If you want to contribute, please read this article first: [Contributing to Open Source Git Repositories in Go](https://splice.com/blog/contributing-open-source-git-repositories-go/). It shows how to configure your git environment to avoid common pitfalls. This article is recommended to all those who are looking to contribute to any Go projects.

^ Taken from [gobuffalo.io](https://https://gobuffalo.io/docs/contributing)

### ⚠️ Send PRs to development branch

The way we release in Tags is:

1. We use `development` branch to accumulate changes to be released
2. Once we decide to make a release we send a PR from `development` to `master` with those changes to be added.
3. Once that PR gets merged we tag a new release with the vX.X.X scheme.
63 changes: 53 additions & 10 deletions form/bootstrap/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,37 @@ func buildOptions(opts tags.Options, err bool) {
}

if opts["tag_only"] != true {
opts["class"] = strings.Join([]string{fmt.Sprint(opts["class"]), "form-control"}, " ")
if opts["type"] == "checkbox" {
opts["class"] = strings.Join([]string{fmt.Sprint(opts["class"]), "form-check-input"}, " ")
} else {
opts["class"] = strings.Join([]string{fmt.Sprint(opts["class"]), "form-control"}, " ")
}
}

if err {
opts["class"] = strings.Join([]string{fmt.Sprint(opts["class"]), "is-invalid"}, " ")
}

opts["class"] = strings.TrimSpace(opts["class"].(string))
delete(opts, "hide_label")
}

func divWrapper(opts tags.Options, fn func(opts tags.Options) tags.Body) *tags.Tag {
divClass := "form-group"
divClass := "form-group" // btw, form-group was deprecated in Bootstrap 5
labelClass := "form-label"
hasErrors := false
errors := []string{}
hasHelp := false
helpMessage := ""

if opts["errors"] != nil && len(opts["errors"].([]string)) > 0 {
divClass = "form-group has-error"
hasErrors = true
errors = opts["errors"].([]string)
delete(opts, "errors")
if opts["div_class"] != nil {
divClass = opts["div_class"].(string)
delete(opts, "div_class")
}

if opts["label_class"] != nil {
labelClass = opts["label_class"].(string)
delete(opts, "label_class")
}

if opts["bootstrap"] != nil {
Expand All @@ -45,6 +56,19 @@ func divWrapper(opts tags.Options, fn func(opts tags.Options) tags.Body) *tags.T
delete(opts, "bootstrap")
}

if opts["help"] != nil {
hasHelp = true
helpMessage = opts["help"].(string)
delete(opts, "help")
}

if opts["errors"] != nil && len(opts["errors"].([]string)) > 0 {
divClass += " has-error"
hasErrors = true
errors = opts["errors"].([]string)
delete(opts, "errors")
}

div := tags.New("div", tags.Options{
"class": divClass,
})
Expand All @@ -55,13 +79,14 @@ func divWrapper(opts tags.Options, fn func(opts tags.Options) tags.Body) *tags.T
opts["label"] = flect.Titleize(tf)
}
}

delete(opts, "tags-field")

useLabel := opts["hide_label"] == nil
if useLabel && opts["label"] != nil {
div.Prepend(tags.New("label", tags.Options{
"body": opts["label"],
"for": opts["id"],
"body": opts["label"],
"class": labelClass,
}))
delete(opts, "label")
}
Expand All @@ -72,7 +97,16 @@ func divWrapper(opts tags.Options, fn func(opts tags.Options) tags.Body) *tags.T
return fn(opts).(*tags.Tag)
}

div.Append(fn(opts))
isFloatingLabel := strings.Contains(divClass, "form-floating")
if opts["type"] == "checkbox" || isFloatingLabel {
if isFloatingLabel && opts["placeholder"] == nil {
// bootstrap 5 floating label requires this
opts["placeholder"] = opts["name"]
}
div.Prepend(fn(opts))
} else {
div.Append(fn(opts))
}

if hasErrors {
for _, err := range errors {
Expand All @@ -82,5 +116,14 @@ func divWrapper(opts tags.Options, fn func(opts tags.Options) tags.Body) *tags.T
}))
}
}

if hasHelp {
div.Append(tags.New("div", tags.Options{
"id": fmt.Sprintf("%v-help", opts["name"]),
"class": "form-text",
"body": helpMessage,
}))
}

return div
}
4 changes: 2 additions & 2 deletions form/bootstrap/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func Test_BootstrapFormGroupClass(t *testing.T) {
expected string
}{
{
expected: `<div class="form-group row"><label>Name</label><input class=" form-control" id="-Name" name="Name" type="text" value="" /></div>`,
expected: `<div class="form-group row"><label class="form-label" for="-Name">Name</label><input class="form-control" id="-Name" name="Name" type="text" value="" /></div>`,
options: tags.Options{
"bootstrap": map[string]interface{}{
"form-group-class": "form-group row",
Expand All @@ -25,7 +25,7 @@ func Test_BootstrapFormGroupClass(t *testing.T) {
},

{
expected: `<div class="form-group"><label>Name</label><input class=" form-control" id="-Name" name="Name" type="text" value="" /></div>`,
expected: `<div class="form-group"><label class="form-label" for="-Name">Name</label><input class="form-control" id="-Name" name="Name" type="text" value="" /></div>`,
options: tags.Options{},
},
}
Expand Down
61 changes: 33 additions & 28 deletions form/bootstrap/form_for.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package bootstrap

import (
"fmt"
"strings"
"html/template"

"github.com/gobuffalo/tags/v3"
"github.com/gobuffalo/tags/v3/form"
Expand All @@ -16,37 +15,43 @@ type FormFor struct {

//CheckboxTag adds a checkbox to a form wrapped with a form-control and a label
func (f FormFor) CheckboxTag(field string, opts tags.Options) *tags.Tag {
opts["type"] = "checkbox"
opts = f.buildOptions(field, opts)

label := field
if opts["label"] != nil {
label = fmt.Sprint(opts["label"])
}
hl := opts["hide_label"]
delete(opts, "label")

fieldKey := validators.GenerateKey(field)
if err := f.Errors.Get(fieldKey); err != nil {
opts["errors"] = err
}
opts["div_class"] = "form-check"
opts["label_class"] = "form-check-label"

return divWrapper(opts, func(o tags.Options) tags.Body {
if o["class"] != nil {
cls := strings.Split(o["class"].(string), " ")
ncls := make([]string, 0, len(cls))
for _, c := range cls {
if c != "form-control" {
ncls = append(ncls, c)
}
}
o["class"] = strings.Join(ncls, " ")
value := opts["value"]
delete(opts, "value")

checked := opts["checked"]
delete(opts, "checked")
if checked == nil {
checked = "true"
}
if label != "" {
o["label"] = label
opts["value"] = checked

unchecked := opts["unchecked"]
delete(opts, "unchecked")

if opts["tag_only"] == true {
tag := f.FormFor.InputTag(field, opts)
tag.Checked = template.HTMLEscaper(value) == template.HTMLEscaper(checked)
return tag
}
if hl != nil {
o["hide_label"] = hl

tag := f.FormFor.InputTag(field, opts)
tag.Checked = template.HTMLEscaper(value) == template.HTMLEscaper(checked)

if opts["name"] != nil && unchecked != nil {
tag.AfterTag = append(tag.AfterTag, tags.New("input", tags.Options{
"type": "hidden",
"name": opts["name"],
"value": unchecked,
}))
}
return f.FormFor.CheckboxTag(field, o)
return tag
})
}

Expand Down Expand Up @@ -126,6 +131,6 @@ func (f FormFor) buildOptions(field string, opts tags.Options) tags.Options {
if err := f.Errors.Get(fieldName); err != nil {
opts["errors"] = err
}

f.FormFor.BuildOptions(field, opts)
return opts
}
Loading

0 comments on commit 19b83ad

Please sign in to comment.