hatmill/hatmill.go

141 lines
3.2 KiB
Go
Raw Normal View History

2019-03-21 18:40:54 +00:00
package hatmill
2019-03-21 17:26:40 +00:00
import "io"
2019-03-29 02:18:25 +00:00
// Term represents a fragment of HTML markup, and is one of VoidElement, ParentElement, or Text.
2019-03-22 03:31:24 +00:00
type Term interface {
2019-03-21 18:40:54 +00:00
io.WriterTo
2019-03-21 17:26:40 +00:00
2019-03-22 03:31:24 +00:00
// isHtml is a no-op method to prevent external Term implementations, because
2019-03-21 18:40:54 +00:00
// Go doesn't have sum types.
isHtml()
2019-03-21 17:26:40 +00:00
}
2019-03-21 18:40:54 +00:00
// writeStringsTo attempts to write the strings in ss to w, incrementing n by the
// number of bytes written.
func writeStringsTo(w io.Writer, n *int64, ss ...string) error {
for _, s := range ss {
nCurr, err := io.WriteString(w, s)
*n += int64(nCurr)
if err != nil {
return err
}
}
return nil
2019-03-21 17:26:40 +00:00
}
2019-03-25 02:54:09 +00:00
// Attrib represents an HTML attribute.
2019-03-21 17:26:40 +00:00
type Attrib struct {
2019-03-21 18:40:54 +00:00
Key string
Value string
2019-03-21 17:26:40 +00:00
}
2019-03-25 02:54:09 +00:00
// WriteTo writes a to w as an HTML attribute in the form key="value", or
// simply key if value is empty. It returns the number of bytes written and any
// error encountered.
2019-03-21 17:26:40 +00:00
func (a Attrib) WriteTo(w io.Writer) (n int64, err error) {
2019-03-21 18:40:54 +00:00
err = writeStringsTo(w, &n, a.Key)
if err != nil {
return
}
if a.Value != "" {
err = writeStringsTo(w, &n, "='", a.Value, "'")
}
return
2019-03-21 17:26:40 +00:00
}
2019-03-29 02:18:25 +00:00
// VoidElement represents a void HTML element, that is one that cannot have
2019-03-25 02:54:09 +00:00
// children.
2019-03-29 02:18:25 +00:00
type VoidElement struct {
2019-03-21 18:40:54 +00:00
TagName string
Attribs []Attrib
}
2019-03-21 17:26:40 +00:00
2019-03-29 02:18:25 +00:00
func (VoidElement) isHtml() {}
2019-03-21 17:26:40 +00:00
2019-03-25 02:54:09 +00:00
// WriteTo writes the HTML markup represented by e to w, returning the number
// of bytes written and any error encountered.
2019-03-25 03:00:36 +00:00
//
// See the warning about sanitization in the (Attrib).WriteTo documentation.
2019-03-29 02:18:25 +00:00
func (e VoidElement) WriteTo(w io.Writer) (n int64, err error) {
2019-03-21 18:40:54 +00:00
err = writeStringsTo(w, &n, "<", e.TagName)
if err != nil {
return
}
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
for _, attrib := range e.Attribs {
err = writeStringsTo(w, &n, " ")
if err != nil {
return
}
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
var nCurr int64
nCurr, err = attrib.WriteTo(w)
n += int64(nCurr)
if err != nil {
return
}
}
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
err = writeStringsTo(w, &n, ">")
return
2019-03-21 17:26:40 +00:00
}
2019-03-25 02:54:09 +00:00
// ParentElement represents an HTML element that can have children.
2019-03-21 18:40:54 +00:00
type ParentElement struct {
2019-03-29 02:18:25 +00:00
VoidElement
2019-03-22 03:31:24 +00:00
Children []Term
2019-03-21 17:26:40 +00:00
}
func (e ParentElement) isHtml() {}
2019-03-21 18:40:54 +00:00
2019-03-25 02:54:09 +00:00
// WriteTo writes the HTML markup represented by e to w, returning the number
// of bytes written and any error encountered.
2019-03-25 03:00:36 +00:00
//
// See the warning about sanitization in the (Attrib).WriteTo documentation.
func (e ParentElement) WriteTo(w io.Writer) (n int64, err error) {
2019-03-29 02:18:25 +00:00
n, err = e.VoidElement.WriteTo(w)
2019-03-21 18:40:54 +00:00
if err != nil {
return
}
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
for _, child := range e.Children {
var nCurr int64
nCurr, err = child.WriteTo(w)
n += int64(nCurr)
if err != nil {
return
}
}
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
err = writeStringsTo(w, &n, "</", e.TagName, ">")
return
2019-03-21 17:26:40 +00:00
}
2019-03-25 02:54:09 +00:00
// Text represents an HTML text node.
2019-03-21 18:40:54 +00:00
type Text string
2019-03-21 17:26:40 +00:00
2019-03-21 18:40:54 +00:00
func (Text) isHtml() {}
2019-03-21 17:26:40 +00:00
2019-03-25 02:54:09 +00:00
// WriteTo writes the contents of t to w, returning the number of bytes written
2019-03-25 03:00:36 +00:00
// and any error encountered. It does not replace special characters with HTML
// entities; use html.EscapeString for this purpose.
2019-03-21 18:40:54 +00:00
func (t Text) WriteTo(w io.Writer) (n int64, err error) {
err = writeStringsTo(w, &n, string(t))
return
2019-03-21 17:26:40 +00:00
}
2019-03-21 18:40:54 +00:00
// WriteDocument writes an HTML5 doctype declaration, followed by root.
// root should probably be an <html> element.
func WriteDocument(w io.Writer, root ParentElement) (n int64, err error) {
2019-03-21 18:40:54 +00:00
err = writeStringsTo(w, &n, "<!DOCTYPE html>")
if err != nil {
return
}
var nroot int64
nroot, err = root.WriteTo(w)
n += nroot
return
}