2019-03-21 18:40:54 +00:00
package hatmill
2019-03-21 17:26:40 +00:00
2019-04-03 03:42:16 +00:00
//go:generate go run internal/codegen/codegen.go -input defs.json -elemfile element/generated.go -elempkg element -attribfile attribute/generated.go -attribpkg attribute
2019-03-21 17:26:40 +00:00
import "io"
2019-04-28 21:28:57 +00:00
// Term represents a fragment of HTML markup, and is one of VoidElement, ParentElement, Terms, 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-04-28 21:27:46 +00:00
Children Terms
2019-03-21 17:26:40 +00:00
}
2019-03-25 02:46:38 +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.
2019-03-25 02:46:38 +00:00
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-04-28 21:27:46 +00:00
var nChildren int64
nChildren , err = e . Children . WriteTo ( w )
n += nChildren
if err != nil {
return
2019-03-21 18:40:54 +00:00
}
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.
2019-03-25 02:46:38 +00:00
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
}
2019-04-28 21:27:46 +00:00
// Terms is a list of HTML nodes.
type Terms [ ] Term
func ( Terms ) isHtml ( ) { }
func ( ts Terms ) WriteTo ( w io . Writer ) ( n int64 , err error ) {
for _ , t := range ts {
var nCurr int64
nCurr , err = t . WriteTo ( w )
n += int64 ( nCurr )
if err != nil {
return
}
}
return
}