package ht import "bytes" import "fmt" import "html" import "strings" type Ht interface { Bytes() []byte String() string } type AttrList []string type htImpl struct { guts string } func (p *htImpl) String() string { return p.guts } func (p *htImpl) Bytes() []byte { z := make([]byte, len(p.guts)) copy(z, p.guts) return z } func newImplFromString(s string) Ht { return &htImpl{guts: html.EscapeString(s)} } func newImplRawHtml(s string) Ht { return &htImpl{guts: s} } func Cat(things ...interface{}) Ht { buf := bytes.NewBuffer(make([]byte, 0)) for _, thing := range things { switch t := thing.(type) { case Ht: buf.WriteString(t.String()) case string: buf.WriteString(html.EscapeString(t)) case fmt.Stringer: buf.WriteString(html.EscapeString(t.String())) default: buf.WriteString(html.EscapeString(fmt.Sprintf("%v", t))) } } return newImplRawHtml(buf.String()) } func strcat(strs ...string) string { return strings.Join(strs, "") } func formatAttrs(attrs AttrList) string { buf := bytes.NewBuffer(make([]byte, 0)) k := "" for i, e := range attrs { if i&1 == 0 { k = e } else { buf.WriteString(` `) buf.WriteString(html.EscapeString(k)) buf.WriteString(`="`) buf.WriteString(html.EscapeString(e)) buf.WriteString(`"`) } } return buf.String() } func Tag(tag string, attrs AttrList, body Ht) Ht { front := newImplRawHtml(strcat(`<`, tag, formatAttrs(attrs), `>`)) back := newImplRawHtml(strcat(``)) return Cat(front, body, back) } func Attrs(kvList ...string) AttrList { return kvList }