Skip to content

Commit

Permalink
support ID, class attributes combined with selector
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Cooper committed Feb 12, 2020
1 parent 9a4eb66 commit c8d14b3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 42 deletions.
107 changes: 65 additions & 42 deletions m.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ type internalElement interface {
}

type htmlElement struct {
TagName string
Elements []Element
Empty bool
TagName string
Attributes []*attr
Children []Element
Void bool
}

// M returns an element that is an HTML tag that is specified by selector.
Expand All @@ -42,6 +43,8 @@ type htmlElement struct {
// class name, or attribute, omit the dynamic value from the selector string and use
// Attr or Attrf instead.
//
// Multiple class attributes are merged together into a space-separated string.
//
// elements are the children of the HTML tag. If Attr and Attrf values are used,
// they must be the first values included in elements.
//
Expand All @@ -52,32 +55,58 @@ func M(selector string, elements ...Element) Element {
panic(err)
}

if sel.TagName == "" {
sel.TagName = "div"
} else {
sel.TagName = strings.ToLower(sel.TagName)
tagName := "div"
if sel.TagName != "" {
tagName = strings.ToLower(sel.TagName)
}

allElements := make([]Element, 0, 3+len(elements))

var id *string
if sel.ID != "" {
allElements = append(allElements, Attr("id", sel.ID))
id = &sel.ID
}

if len(sel.Classes) > 0 {
allElements = append(allElements, Attr("class", strings.Join(sel.Classes, " ")))
classes := sel.Classes
for _, el := range elements {
if attribute, ok := el.(*attr); ok {
switch attribute.Key {
case "id":
id = &attribute.Value
case "class":
classes = append(classes, attribute.Value)
}
}
}

for _, attr := range sel.Attributes {
allElements = append(allElements, Attr(attr[0], attr[1]))
attributes := make([]*attr, 0, 1+1+len(sel.Attributes))
if id != nil {
attributes = append(attributes, &attr{"id", *id})
}
if len(classes) > 0 {
attributes = append(attributes, &attr{"class", strings.Join(classes, " ")})
}
for _, attribute := range sel.Attributes {
attributes = append(attributes, &attr{attribute[0], attribute[1]})
}

allElements = append(allElements, elements...)
var children []Element
for i, el := range elements {
if attr, ok := el.(*attr); ok {
switch attr.Key {
case "id", "class":
default:
attributes = append(attributes, attr)
}
} else if el != nil {
children = append([]Element(nil), elements[i:]...)
break
}
}

return &htmlElement{
TagName: sel.TagName,
Elements: allElements,
Empty: voidElements[sel.TagName],
TagName: tagName,
Attributes: attributes,
Children: children,
Void: voidElements[sel.TagName],
}
}

Expand Down Expand Up @@ -110,39 +139,33 @@ func (e *htmlElement) renderHTML(w io.Writer) error {
return err
}

var i int
// Attributes
for ; i < len(e.Elements); i++ {
el := e.Elements[i]
if attr, ok := el.(*attr); ok {
if _, err := io.WriteString(w, " "); err != nil {
return err
}
if _, err := io.WriteString(w, attr.Key); err != nil {
return err
}
if _, err := io.WriteString(w, "=\""); err != nil {
return err
}
if _, err := io.WriteString(w, template.HTMLEscapeString(attr.Value)); err != nil {
return err
}
if _, err := io.WriteString(w, "\""); err != nil {
return err
}
} else if el != nil {
break
for _, attr := range e.Attributes {
if _, err := io.WriteString(w, " "); err != nil {
return err
}
if _, err := io.WriteString(w, attr.Key); err != nil {
return err
}
if _, err := io.WriteString(w, "=\""); err != nil {
return err
}
if _, err := io.WriteString(w, template.HTMLEscapeString(attr.Value)); err != nil {
return err
}
if _, err := io.WriteString(w, "\""); err != nil {
return err
}
}

if _, err := io.WriteString(w, ">"); err != nil {
return err
}

if !e.Empty {
if !e.Void {
// Children
for ; i < len(e.Elements); i++ {
if err := Render(w, e.Elements[i]); err != nil {
for _, el := range e.Children {
if err := Render(w, el); err != nil {
return err
}
}
Expand Down
16 changes: 16 additions & 0 deletions m_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ func Test_map(t *testing.T) {
}),
`<option value="0">Element 0</option><option value="1">Element 1</option><option selected="" value="2">Element 2</option>`,
},
{
M("p.text-right", If(false, Attr("class", "m-0")), Attr("class", "alpha-25"), T("Text")),
`<p class="text-right alpha-25">Text</p>`,
},
{
M("p#id-0", If(false, Attr("id", "id-1")), T("Text")),
`<p id="id-0">Text</p>`,
},
{
M("p#id-0", If(true, Attr("id", "id-1")), T("Text")),
`<p id="id-1">Text</p>`,
},
{
M("p#id-0", If(true, Attr("id", "id-1")), Attr("id", "id-2"), T("Text")),
`<p id="id-2">Text</p>`,
},
}

for _, tt := range tests {
Expand Down

0 comments on commit c8d14b3

Please sign in to comment.