184 lines
3.1 KiB
Go
184 lines
3.1 KiB
Go
|
package main
|
||
|
|
||
|
import "fmt"
|
||
|
import "io"
|
||
|
import "os"
|
||
|
import "strings"
|
||
|
|
||
|
// Html is either Element or Text
|
||
|
type Html interface {
|
||
|
io.WriterTo
|
||
|
// isHtml is a non-functional marker to differentiate Html from interface{}
|
||
|
isHtml()
|
||
|
}
|
||
|
|
||
|
func Reader() io.Reader {
|
||
|
// TODO in-order traversal of HTML tree to spit out bytes
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func String() string {
|
||
|
panic("this could be trivially implemented with a Reader and a bytes.Buffer")
|
||
|
}
|
||
|
|
||
|
type Attrib struct {
|
||
|
Key string
|
||
|
Value string
|
||
|
}
|
||
|
|
||
|
type element struct {
|
||
|
tagName string
|
||
|
attribs []Attrib
|
||
|
empty bool
|
||
|
children []Html
|
||
|
}
|
||
|
|
||
|
// writeTo attempts to write the strings in ss to w, incrementing n by the
|
||
|
// number of bytes written.
|
||
|
func writeTo(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
|
||
|
}
|
||
|
|
||
|
func (a Attrib) WriteTo(w io.Writer) (n int64, err error) {
|
||
|
err = writeTo(w, &n, a.Key)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if a.Value != "" {
|
||
|
err = writeTo(w, &n, "='", a.Value, "'")
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (e *element) WriteTo(w io.Writer) (n int64, err error) {
|
||
|
err = writeTo(w, &n, "<", e.tagName)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
for _, attrib := range e.attribs {
|
||
|
err = writeTo(w, &n, " ")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var nCurr int64
|
||
|
nCurr, err = attrib.WriteTo(w)
|
||
|
n += int64(nCurr)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = writeTo(w, &n, ">")
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if !e.empty {
|
||
|
for _, child := range e.children {
|
||
|
var nCurr int64
|
||
|
nCurr, err = child.WriteTo(w)
|
||
|
n += int64(nCurr)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = writeTo(w, &n, "</", e.tagName, ">")
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (*element) isHtml() {}
|
||
|
|
||
|
func emptyElement(tagName string, attribs []Attrib) Html {
|
||
|
return &element{
|
||
|
tagName: tagName,
|
||
|
attribs: attribs,
|
||
|
empty: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func elementFunc(tagName string, attribs []Attrib) func(...Html) Html {
|
||
|
return func(children ...Html) Html {
|
||
|
return &element{
|
||
|
tagName: tagName,
|
||
|
attribs: attribs,
|
||
|
children: children,
|
||
|
empty: false,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type text string
|
||
|
|
||
|
func Text(s string) Html {
|
||
|
return text(s)
|
||
|
}
|
||
|
|
||
|
func (text) isHtml() {}
|
||
|
|
||
|
func (t text) WriteTo(w io.Writer) (n int64, err error) {
|
||
|
err = writeTo(w, &n, string(t))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
type rText struct {
|
||
|
io.Reader
|
||
|
}
|
||
|
|
||
|
func RText(r io.Reader) Html {
|
||
|
return rText{Reader: r}
|
||
|
}
|
||
|
|
||
|
func (rText) isHtml() {}
|
||
|
|
||
|
func (rt rText) WriteTo(w io.Writer) (n int64, err error) {
|
||
|
return io.Copy(w, rt.Reader)
|
||
|
}
|
||
|
|
||
|
// Html5 functions
|
||
|
|
||
|
func Div(attribs ...Attrib) func(children ...Html) Html {
|
||
|
return elementFunc("div", attribs)
|
||
|
}
|
||
|
|
||
|
func Img(attribs ...Attrib) Html {
|
||
|
return emptyElement("img", attribs)
|
||
|
}
|
||
|
|
||
|
func Id(id string) Attrib {
|
||
|
return Attrib{
|
||
|
Key: "id",
|
||
|
Value: id,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func Disabled() Attrib {
|
||
|
return Attrib {
|
||
|
Key: "disabled",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var page = Div(Disabled(), Id("container"))(
|
||
|
Img(Id("profile-photo")),
|
||
|
Text("hello"),
|
||
|
Img(Disabled()),
|
||
|
RText(strings.NewReader("goodbye!")),
|
||
|
)
|
||
|
|
||
|
n, err := page.WriteTo(os.Stdout)
|
||
|
fmt.Println()
|
||
|
fmt.Println(n)
|
||
|
fmt.Println(err)
|
||
|
}
|