goh4

package module
v0.0.0-...-d4dca70 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2024 License: BSD-3-Clause Imports: 14 Imported by: 0

README

goh4

Build Status

WARNING: This package is in flux. You should not use it in production yet. API will / might break.

type save html and css generation for golang with functions (inspired by http://godoc.org/github.com/daaku/go.h)

example

package main

import (
	"fmt"
	"github.com/metakeule/goh4"
)

func main(){
	font := NewCss(
		Class("default-font"),
		Style("font-size","20","font-weight","normal"))

	css := NewCss(
		Class("yellow-button"),
		Tags("a","button"),
		Style("background-color","yellow"),
		font)

	a := A(css)

	doc := NewTemplate(
		Doc(
			Head(),
			Body(a)))

	doc.AddCss(css)

	fmt.Println(doc)
}

results in

<head>
	<style>
		a.yellow-button,
		button.yellow-button {
			background-color: yellow;
			font-weight: normal;	/* inherited from ».default-font« */
			font-size: 20;	/* inherited from ».default-font« */
		}
	</style>
</head>
<body><a class="yellow-button"></a></body>

Documentation

see http://godoc.org/github.com/metakeule/goh4

TODO

Documentation

Overview

Package goh4 constructs html element trees (something like DOM), html templates and integrates them with css rules. All of them are done by using types, not strings. This makes reuse and shortcuts easy.

It is inspired by http://godoc.org/github.com/daaku/go.h

It is easy to extend goh4 and build upon it and you may bring in some html and css strings as well.

Elements

There are some helper functions to generate elements for you. For instance

element := A()

gives you an anchor element. Here is how A() is defined and how you may define your own shortcuts.

func A(objects ...Stringer) (t *Element) {
	t = NewElement(Tag("a"), Inline)
	t.Set(objects...)
	return
}

A() calls NewElement() with a typed Tag (created from a string) and a flag that indicates that it's an inline element. All flags are defined as constants and may be combined with the bitwise or | or given as seperate parameters.

Then A() sets up the element by passing the optional Stringer to the Set() method. This allows you do some neat things, for instance

a := A(
	Class("button"),
	Id("start"),
	Text("begin"))

a.String() // <a class="button" id="start">begin</a>

a = A(
	Attr("href","#","_target","_blank"),
	Text("something"))

a.String() // <a href="#" target="_blank">something</a>

a = A(
	Style("color","red"),
	Strong(
		Html("not <escaped>!")))
a.String() // <a style="color:red;"><strong>not <escaped></strong></a>

Then you may get all the nice methods of element

children := a.Children() // only the Elements
inner := a.InnerHtml()   // everything inside
buttons := a.All(Class("button"))
start := a.Any(Id("start"))
...

You may define your own Matcher and pass it to All() and Any().

Templates and Css

Template is an element that can Assign() anything that can be inside an element to any element within the tree, that has the given Id().

content := Div(Id("content"))
body := NewTemplate(Body(content))
body.Assign(Id("content"), P(Text("here I am")))
body.String() // <body><div id="content"><p>here I am</p></div></body>

Template may also add css to your head element. In this case you need to use the Doc() pseudo element, that holds the root of the document. And you need a head obviously.

doc := NewTemplate(Doc(Head()))
doc.AddCss("body{ color: red; }")
doc.String() // <head><style>body { color: red; }</style></head>

Element and Template are structs you can inherit from them, e.g.

type Layout struct {
	*Template
}

func (xyyy *Layout) String() string {
	// do your thing here
}

If you want type safe reusable css, you can use Css.

fontsize := NewCss(Class("default-font-size"),Style("font-size","20"))
css := NewCss(
	Class("yellow-button"),
	Tags("a","button"),
	Style("background-color","yellow"),
	fontsize)

and then you might apply it to your elements.

a := A()
a.ApplyCss(css)
a.String() // <a class="yellow-button"></a>

don't forget to put your css into the template (we don't put fontsize into it, since it is only a building block)

doc := NewTemplate(Doc(Head(),Body(a)))
doc.AddCss(css)
doc.String()

this results in the following (no auto indentation at the moment, sorry):

<head>
	<style>
		a.yellow-button,
		button.yellow-button {
			background-color: yellow;
			font-size: 20;	\/* inherited from ».default-font-size« *\/
		}
	</style>
</head>
<body><a class="yellow-button"></a></body>

Index

Examples

Constants

View Source
const (
	IdForbidden       flag // element should not have an id attribute
	ClassForbidden         // element should not have a class attribute
	SelfClosing            // element is selfclosing and contains no content
	Inline                 // element is an inline element (only for visible elements)
	FormField              // element is a field of a form
	Invisible              // element doesn't render anything visible
	WithoutEscaping        // element does not escape inner Text
	WithoutDecoration      // element just prints the InnerHtml
)

Variables

View Source
var Escaper = templ.Escaper{
	"text":     handleStrings(html.EscapeString, true),
	"":         handleStrings(html.EscapeString, true),
	"html":     handleStrings(idem, true),
	"px":       units("%vpx"),
	"%":        units("%v%%"),
	"em":       units("%vem"),
	"pt":       units("%vpt"),
	"urlparam": handleStrings(url.QueryEscape, false),
}

Functions

func And

func And(m ...Matcher) and

func Child

func Child(selectors ...Selecter) combinator

F element child of an E element

func Classes

func Classes(c ...string) classes

func Descendant

func Descendant(selectors ...Selecter) combinator

F element descendant of an E element

func DirectFollows

func DirectFollows(selectors ...Selecter) combinator

F element immediately preceded by an E element

func Each

func Each(selectors ...Selecter) combinator

for each given selector the rules apply

func Follows

func Follows(selectors ...Selecter) combinator

F element preceded by an E element

func Not

func Not(m Matcher) *not

func Or

func Or(m ...Matcher) or

func Str

func Str(in interface{}) string

takes different types and outputs a string

func Tags

func Tags(tag string, xyyy ...string) (a tags)

func View

func View(stru interface{}, tag string) *view

Types

type Attrs

type Attrs []SingleAttr

func Attr

func Attr(key1, val1 string, xyyy ...string) (s Attrs)

helper to easily create multiple SingleAttrs use is like this Attr("width","200px","height","30px","value","hiho")

func (Attrs) Matches

func (xyyy Attrs) Matches(t *Element) (m bool)

func (Attrs) String

func (xyyy Attrs) String() (s string)

type Class

type Class string

func Classf

func Classf(format string, i ...interface{}) Class

func (Class) Matches

func (xyyy Class) Matches(t *Element) bool

func (Class) Placeholder

func (xyyy Class) Placeholder() Placeholder

func (Class) Selector

func (xyyy Class) Selector() string

func (Class) String

func (xyyy Class) String() string

type Comment

type Comment string

func (Comment) Placeholder

func (xyyy Comment) Placeholder() Placeholder

func (Comment) String

func (xyyy Comment) String() string

type CompiledTemplate

type CompiledTemplate struct {
	*templ.Template
	ElementTemplate *Template
}

type Csser

type Csser interface {
	Matcher
	Class() string
}

a Csser might be applied as Css to an Element

type Element

type Element struct {
	Comment Comment

	ParentTags tags
	// contains filtered or unexported fields
}

the base of what becomes a tag when printed

func NewElement

func NewElement(t Tag, flags ...flag) (xyyy *Element)

contruct a new element with some flags.

the tag constructors A(), Body(),... use these method, see tags.go file for examples

use it for your own tags

the following flags are supported

IdForbidden                        // element should not have an id attribute
ClassForbidden                     // element should not have a class attribute
SelfClosing                        // element is selfclosing and contains no content
Inline                             // element is an inline element (only for visible elements)
Field                              // element is a field of a form
Invisible                          // element doesn't render anything visible
WithoutEscaping                    // element does not escape inner Text
WithoutDecoration                  // element just prints the InnerHtml

see Add() and Set() methods for how to modify the Element

Example

create an element with a simple self defined tag

t := NewElement(Tag("special"))
fmt.Println(t)
Output:

<special></special>
Example (MultipleFlags)

multiple flags may be passed with bitwise or | and as several parameters

t := NewElement(Tag("input"), SelfClosing|Inline, FormField)
fmt.Println(t)
Output:

<input />
Example (Selfclosing)

a selfclosing tag can't have content

t := NewElement(Tag("special"), SelfClosing)
fmt.Println(t)
if err := t.Add("will fail"); err != nil {
	fmt.Println("can't add to selfclosing element")
}
Output:

<special />
can't add to selfclosing element
Example (WithoutDecoration)

create an element that does not output it tags when printed

doc := NewElement(Tag("doc"), WithoutDecoration)

layout := NewTemplate(doc)

body := NewElement(Tag("body"))
body.Add(Id("content"))

doc.Add(
	Html("<!DOCTYPE html>"),
	body,
	Html("</html>"))

layout.Assign("content", "in the body")
fmt.Println(layout)
Output:

<!DOCTYPE html><body id="content">in the body</body></html>

func (*Element) Add

func (xyyy *Element) Add(objects ...interface{}) (err error)

adds new inner content or properties based on Stringer objects and returns an error if changes could not be applied

the following types are handled in a special way:

  • Comment: sets the comment
  • Style: set a single style
  • Styles: sets multiple styles
  • Attr: set a single attribute // do not set id or class via Attr(s) directly, use Id() and Class() instead
  • Attrs: sets multiple attribute
  • Class: adds a class
  • Id: sets the id
  • *Css: applies the css, see ApplyCss()

the following types are added to the inner content:

  • Text: ís escaped if the WithoutEscaping flag isn't set
  • Html: is never escaped

If the Stringer can be casted to an Elementer (as Element can), it is added to the inner content as well otherwise it is handled like Text(), that means any type implementing Stringer can be added as (escaped) text

Example

html, text and elementer are added as inner content

div := NewElement(Tag("div"))
span := NewElement(Tag("span"))
span.Add("hiho")

div.Add(
	Html("<b>hello</b>"), // is not escaped
	Text("c > d"),        // is escaped
	span)                 // objects to tag constructors like Div(), Span(),... gets passed to Add()

fmt.Println(div)
Output:

<div><b>hello</b>c &gt; d<span>hiho</span></div>
Example (Properties)

add / set properties

//	css := NewCss(Class("yellow"), Style("background-color", "yellow"))
d := NewElement(Tag("div"))
d.Add(Class("first"))

d.Add(
	Id("main"),
	Class("second"),
	//		css, // adds the class of the css to the element, multiple *Css can be given
	Comment("main row"),
	Attr("height", "200")) // multiple attributes at once with Attrs{"height", "200", "width", "300"}
//Style("width", "500px")) // multiple styles at once with Styles{"height", "200", "width", "300"}

//fmt.Printf("---CSS---%s---HTML---%s\n", css, d)
Output:

func (*Element) AddAfter

func (xyyy *Element) AddAfter(v *Element, nu Elementer) (err error)

adds Elementer at the position before the Element in the inner content the following elements are moved down

func (*Element) AddAtPosition

func (xyyy *Element) AddAtPosition(pos int, v Elementer) (err error)

adds Elementer to the inner content at position pos

func (*Element) AddBefore

func (xyyy *Element) AddBefore(v *Element, nu Elementer) (err error)

adds Elementer at the position before the Element in the inner content the following elements are moved down

func (*Element) AddClass

func (xyyy *Element) AddClass(classes ...Class) (err error)

use this func to add the classes of the tag, do not set it via Attr directly

func (*Element) All

func (xyyy *Element) All(m Matcher) (r []*Element)

filter by anything that fullfills the matcher interface, e.g. Class, Id, Attr, Attrs, Css, Tag, Style, Styles recursive finds all tags from the children

func (*Element) Any

func (xyyy *Element) Any(m Matcher) (r *Element)

filter by anything that fullfills the matcher interface, e.g. Class, Id, Attr, Attrs, Css, Tag, Style, Styles returns the first tag in the children and the subchildren that matches

func (*Element) AsTemplate

func (xyyy *Element) AsTemplate() *Template

func (*Element) Attribute

func (xyyy *Element) Attribute(k string) string

func (*Element) Attributes

func (xyyy *Element) Attributes() map[string]string

func (*Element) AttrsString

func (xyyy *Element) AttrsString() (res string)

prepare the id attribute for output

func (*Element) Children

func (xyyy *Element) Children() (c []*Element)

returns only children that are Elements, no Text or Html

func (*Element) Classes

func (xyyy *Element) Classes() (c []Class)

use this method to get the classes since they won't show up in attributes

func (*Element) Clear

func (xyyy *Element) Clear()

clears the inner elements and strings

func (*Element) Compile

func (xyyy *Element) Compile(name string) *CompiledTemplate

func (*Element) Fields

func (xyyy *Element) Fields() (fields []*Element)

returns the formfields

func (*Element) HasClass

func (xyyy *Element) HasClass(class Class) bool

func (*Element) Id

func (xyyy *Element) Id() Id

use this method to get the id since it won't show up in attributes

func (*Element) InnerHtml

func (xyyy *Element) InnerHtml() (res string)

func (*Element) Is

func (xyyy *Element) Is(f flag) bool

checks if a given flag is set, e.g.

Is(Inline)

checks for the Inline flag

func (*Element) IsParentAllowed

func (xyyy *Element) IsParentAllowed(parent Tager) (allowed bool)

return false if the given Parent tag is not allowed for Elements tag

func (*Element) NotEscape

func (xyyy *Element) NotEscape() *Element

func (*Element) Parent

func (xyyy *Element) Parent() Pather

func (*Element) Path

func (xyyy *Element) Path() string

func (*Element) Placeholder

func (xyyy *Element) Placeholder(name string) *CompiledTemplate

func (*Element) PositionOf

func (xyyy *Element) PositionOf(v *Element) (pos int, found bool)

returns the position of the Element in the inner content. if it could not be found, the last parameter is false

func (*Element) RemoveAttribute

func (xyyy *Element) RemoveAttribute(k string)

removes an attribute

func (*Element) RemoveClass

func (xyyy *Element) RemoveClass(class Class)

func (*Element) Selecter

func (xyyy *Element) Selecter(other ...Selecter) Selecter

func (*Element) Selector

func (xyyy *Element) Selector() string

func (*Element) ServeHTTP

func (xyyy *Element) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Element) SetAtPosition

func (xyyy *Element) SetAtPosition(pos int, v Elementer) (err error)

set the Elementer to the inner content at position pos and overwrite the current content at that position

func (*Element) SetAttribute

func (xyyy *Element) SetAttribute(k, v string)

sets the attribute k to v as long as k is not "id" or "class" use SetId() to set the id and AddClass() to add a class

func (*Element) SetAttributes

func (xyyy *Element) SetAttributes(a ...string)

func (*Element) SetBottom

func (xyyy *Element) SetBottom(v Elementer) (err error)

sets the Elementer to the last position of the inner content and overwrites the current content at that position

If you want to append to the inner content, use Add() instead

func (*Element) SetClass

func (xyyy *Element) SetClass(classes ...Class)

use this func to set the classes of the Element do not set them via Attr directly

func (*Element) SetContent

func (xyyy *Element) SetContent(objects ...interface{}) (err error)

clears the inner object array and then calles Add() method to add content

see Add() method for more details

func (*Element) SetId

func (xyyy *Element) SetId(id Id) (err error)

use this func to set the id of the Element, do not set it via Attr directly returns error if IdForbidden flag is set

func (*Element) SetParent

func (xyyy *Element) SetParent(parent Pather)

func (*Element) String

func (xyyy *Element) String() (res string)

returns the html with inner content (and the own tags if WithoutDecoration is not set)

func (*Element) Tag

func (xyyy *Element) Tag() string

func (*Element) WrapChildren

func (xyyy *Element) WrapChildren(wrapper *Element)

wraps the children with the given element

func (*Element) WriteTo

func (xyyy *Element) WriteTo(w io.Writer)

type Elementer

type Elementer interface {
	Stringer
	Tager
	IsParentAllowed(Tager) bool
	SetParent(Pather)
}

an Elementer might be parent of an Element by implementing a type that fulfills this interface you might peek into the execution. when String() method is called, the html of the tree is built and when SetParent() it is embedded in another Elementer it could be combined with the Pather interface that allows you to modify specific css selectors for any children Elements

type FieldMatcher

type FieldMatcher int

func (FieldMatcher) Matches

func (xyyy FieldMatcher) Matches(t *Element) (m bool)

type Html

type Html string

func Htmlf

func Htmlf(format string, i ...interface{}) Html

func (Html) Matches

func (xyyy Html) Matches(t *Element) bool

matching an html string, ignoring whitespace

func (Html) Placeholder

func (xyyy Html) Placeholder() Placeholder

func (Html) String

func (xyyy Html) String() string

type Id

type Id string

func (Id) Matches

func (xyyy Id) Matches(t *Element) bool

func (Id) Placeholder

func (xyyy Id) Placeholder() Placeholder

func (Id) Selector

func (xyyy Id) Selector() string

func (Id) String

func (xyyy Id) String() string

type Matcher

type Matcher interface {
	Matches(*Element) bool
}

something that matches an Element

type Pather

type Pather interface {
	Path() string
}

type Placeholder

type Placeholder interface {
	templ.Setter
	Set(val interface{}) templ.Setter
	Setf(format string, val ...interface{}) templ.Setter
	String() string
	Type() interface{}
}

type PositionMatcher

type PositionMatcher struct {
	Element *Element
	Pos     int
	Found   bool
}

func (*PositionMatcher) Matches

func (xyyy *PositionMatcher) Matches(e *Element) (f bool)

type Scss

type Scss string

func (Scss) String

func (xyyy Scss) String() string

type Selecter

type Selecter interface {
	Selector() string
}

func Context

func Context(ctx Selecter, inner1 Selecter, inner ...Selecter) (r Selecter)

func ContextString

func ContextString(ctx string, inner1 Selecter, inner ...Selecter) (r Selecter)

func Selector

func Selector(sel1 Selecter, selects ...Selecter) Selecter

combine several selectors to one

type SelecterAdder

type SelecterAdder interface {
	Selector() string
	Add(Selecter) SelecterAdder
}

type SelectorString

type SelectorString string

func (SelectorString) Selector

func (xyyy SelectorString) Selector() string

type SingleAttr

type SingleAttr struct {
	Key   string
	Value string
}

func (SingleAttr) Matches

func (xyyy SingleAttr) Matches(t *Element) bool

func (SingleAttr) Placeholder

func (xyyy SingleAttr) Placeholder() Placeholder

func (SingleAttr) String

func (xyyy SingleAttr) String() string

type Stringer

type Stringer interface {
	String() string
}

type Style

type Style struct{ Property, Value string }

func Styles

func Styles(styles ...Style) (s []Style)

func (Style) Matches

func (xyyy Style) Matches(t *Element) bool

func (Style) Placeholder

func (xyyy Style) Placeholder() Placeholder

func (Style) String

func (xyyy Style) String() string

func (Style) Style

func (xyyy Style) Style() string

func (Style) Val

func (xyyy Style) Val(v string) Style

type Tag

type Tag string

func (Tag) Matches

func (xyyy Tag) Matches(t *Element) bool

func (Tag) Placeholder

func (xyyy Tag) Placeholder() Placeholder

func (Tag) Selector

func (xyyy Tag) Selector() string

func (Tag) String

func (xyyy Tag) String() string

type Tager

type Tager interface {
	Tag() string
}

type Templatable

type Templatable interface {
	String() string
	Tag() string
	Path() string
	Any(m Matcher) (r *Element)
	Add(objects ...interface{}) (err error)
}

type Template

type Template struct {
	Element Templatable //*Element
	// contains filtered or unexported fields
}

func NewTemplate

func NewTemplate(t Templatable) *Template

creates a new template with the given element as root

func (*Template) Add

func (xyyy *Template) Add(objects ...interface{}) (err error)

func (*Template) AddCss

func (xyyy *Template) AddCss(css ...Stringer) (err error)

add css to the head of the template returns an error if Element is no doc or has no head child

func (*Template) Assign

func (xyyy *Template) Assign(id Id, html interface{}) (err error)

replaces the content of an child Element with the given id with Stringer e.g.

t := NewTemplate(Body(Div(Id("content"))))
t.Assign("content", P(Text("here we go")))

results in <body><div id="content"><p>here we go</p></div></body>

func (*Template) Compile

func (xyyy *Template) Compile(name string) (c *CompiledTemplate, ſ error)

returns a *CompiledTemplate that is a template.Template (see github.com/metakeule/template) the template can then be initialized with New and merged with placeholders with Replace and Merge if you need to change the original template again, you can get it via CompiledTemplate.ElementTemplate then call Compile() again to get a new CompiledTemplate

func (*Template) MustCompile

func (xyyy *Template) MustCompile(name string) *CompiledTemplate

panics on error

func (*Template) String

func (xyyy *Template) String() string

type Text

type Text string

func Textf

func Textf(format string, i ...interface{}) Text

func (Text) Placeholder

func (xyyy Text) Placeholder() Placeholder

func (Text) String

func (xyyy Text) String() string

Directories

Path Synopsis
css
example
fn
sel
tag

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL