2019-03-21 18:40:54 +00:00
|
|
|
package hatmill
|
2019-03-21 17:26:40 +00:00
|
|
|
|
|
|
|
import "io"
|
|
|
|
|
2019-03-22 03:31:24 +00:00
|
|
|
//go:generate go run ./internal/elementgen/main.go
|
|
|
|
|
|
|
|
// Term represents a fragment of HTML markup, and is one of EmptyElement, ParentElement, or Text.
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
type Attrib struct {
|
2019-03-21 18:40:54 +00:00
|
|
|
Key string
|
|
|
|
Value string
|
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-21 18:40:54 +00:00
|
|
|
type EmptyElement struct {
|
|
|
|
TagName string
|
|
|
|
Attribs []Attrib
|
|
|
|
}
|
2019-03-21 17:26:40 +00:00
|
|
|
|
2019-03-21 18:40:54 +00:00
|
|
|
func (EmptyElement) isHtml() {}
|
2019-03-21 17:26:40 +00:00
|
|
|
|
2019-03-21 18:40:54 +00:00
|
|
|
func (e EmptyElement) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
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-21 18:40:54 +00:00
|
|
|
type ParentElement struct {
|
|
|
|
EmptyElement
|
2019-03-22 03:31:24 +00:00
|
|
|
Children []Term
|
2019-03-21 17:26:40 +00:00
|
|
|
}
|
|
|
|
|
2019-03-21 18:40:54 +00:00
|
|
|
func (e *ParentElement) isHtml() {}
|
|
|
|
|
|
|
|
func (e *ParentElement) WriteTo(w io.Writer) (n int64, err error) {
|
|
|
|
n, err = e.EmptyElement.WriteTo(w)
|
|
|
|
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-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-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
|
|
|
}
|
|
|
|
|
|
|
|
// Html5 functions
|
|
|
|
|
2019-03-22 03:31:24 +00:00
|
|
|
// func Div(attribs ...Attrib) func(children ...Term) *ParentElement {
|
|
|
|
// return func(children ...Term) *ParentElement {
|
|
|
|
// return &ParentElement{
|
|
|
|
// EmptyElement: EmptyElement{
|
|
|
|
// TagName: "div",
|
|
|
|
// Attribs: attribs,
|
|
|
|
// },
|
|
|
|
// Children: children,
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// func Img(attribs ...Attrib) EmptyElement {
|
|
|
|
// return EmptyElement{
|
|
|
|
// TagName: "img",
|
|
|
|
// Attribs: attribs,
|
|
|
|
// }
|
|
|
|
// }
|
2019-03-21 17:26:40 +00:00
|
|
|
|
|
|
|
func Id(id string) Attrib {
|
2019-03-21 18:40:54 +00:00
|
|
|
return Attrib{
|
|
|
|
Key: "id",
|
|
|
|
Value: id,
|
|
|
|
}
|
2019-03-21 17:26:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func Disabled() Attrib {
|
2019-03-21 18:40:54 +00:00
|
|
|
return Attrib{
|
|
|
|
Key: "disabled",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
err = writeStringsTo(w, &n, "<!DOCTYPE html>")
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var nroot int64
|
|
|
|
nroot, err = root.WriteTo(w)
|
|
|
|
n += nroot
|
|
|
|
return
|
|
|
|
}
|