tplinator

package module
v0.0.0-...-2fb2212 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2018 License: MIT Imports: 9 Imported by: 0

README

tplinator

An HTML template renderer heavily inspired by the syntax used for Angular and VueJS applications.

Stage Go Report Card Coverage Status CircleCI

Features

String Interpolation

Uses the {{go:[VARIABLE_NAME]}} syntax which can be placed on attribute values and inside HTML elements. It only accepts variables which are of type string.

Example

Golang code snippet

bytes, err := template.RenderBytes(map[string]interface{}{
    "username": "bryanmdlx",
    "currentDisplayName": "Bryan Dela Cruz",
})

HTML template snippet

<h1>Username: {{go:username}}</h1>
<form action="/user/{{go:username}}/details" method="POST">
    <input type="text" name="displayName" value="{{go:currentDisplayName}}"/>
    <button type="submit">Update</button>
</form>

Output HTML

<h1>Username: bryanmdlx</h1>
<form action="/user/bryanmdlx/details" method="POST">
    <input type="text" name="displayName" value="Bryan Dela Cruz"/>
    <button type="submit">Update</button>
</form>
Conditional Rendering

Uses the go-if, go-else-if (or go-elif), and go-else to define that the target element/s will be rendered conditionally. The value of the conditional attribute must be a boolean expression.

Example

Golang code snippet

bytes, err := template.RenderBytes(map[string]interface{}{
    "hasOne": false,
    "hasTwo": true,
    "hasThree": true,
})

HTML template snippet

<div class="messages">
    <p go-if="hasOne">Has one</p>
    <p go-else-if="hasTwo && !hasThree">Has two but does not have three</p>
    <p go-else-if="hasTwo && hasThree">Has two and three</p>
    <p go-else>Does not have any</p>
</div>

Output HTML

<div class="messages">
    <p>Has two and three</p>
</div>
Conditional Classes

Uses go-if-class-* to define that the target element's class will be added conditionally. The value of the conditional attribute must be a boolean expression.

Example

Golang code snippet

bytes, err := template.RenderBytes(map[string]interface{}{
    "isFood": true,
    "isDrink": false,
    "name": "Blueberry Cheesecake",
    "description": "A delicious treat from the realm of gods and goddesses.",
})

HTML template snippet

<div class="menu-entry" go-if-class-food="isFood" go-if-class-drink="isDrink">
    <h1>{{go:name}}</h1>
    <p>{{go:description}}</p>
</div>

Output HTML

<div class="menu-entry food">
    <h1>Blueberry Cheesecake</h1>
    <p>A delicious treat from the realm of gods and goddesses.</p>
</div>
List Rendering

Uses the go-range attribute to define that the target element must be rendered n times, where n is the length of the specified range variable, under its original parent element.

Each entry on the RangeParams function will be accessible only to the target element and its children. If it does not contain a variable needed for one of the string interpolations inside the target element, the variable will be looked for on the EvaluatorParams passed to the Template#Render* function.

Example

Golang code snippet

bytes, err := template.RenderBytes(tplinator.EvaluatorParams{
    "userId": "412897373847523",
    "menuEntries": tplinator.RangeParams(
        tplinator.EvaluatorParams{
            "id": "399585827",
            "isFood": true,
            "isDrink": false,
            "favoriteWhat": "food",
            "name": "Blueberry Cheesecake",
            "description": "A delicious treat from the realm of gods and goddesses.",
        },
        tplinator.EvaluatorParams{
            "id": "518273743",
            "isFood": false,
            "isDrink": true,
            "favoriteWhat": "drink",
            "name": "Iced Coffee",
            "description": "The tears of the trees that lives on the summit of the Alps.",
        },
    ),
})

HTML template snippet

<div class="menu">
    <div class="menu-entry" go-range="menuEntries" go-if-class-food="isFood" go-if-class-drink="isDrink">
        <h1>{{go:name}}</h1>
        <p class="description">{{go:description}}</p>
        <form action="/user/{{go:userId}}/favorite?what={{go:favoriteWhat}}&id={{go:id}}" method="POST">
            <button type="submit">Add {{go:name}} to my favorites</button>
        </form>
    </div>
</div>

Output HTML

<div class="menu">
    <div class="menu-entry food">
        <h1>Blueberry Cheesecake</h1>
        <p class="description">A delicious treat from the realm of gods and goddesses.</p>
        <form action="/user/412897373847523/favorite?what=food&id=399585827" method="POST">
            <button type="submit">Add Blueberry Cheesecake to my favorites</button>
        </form>
    </div>
    <div class="menu-entry drink">
        <h1>Iced Coffee</h1>
        <p class="description">The tears of the trees that lives on the summit of the Alps.</p>
        <form action="/user/412897373847523/favorite?what=drink&id=518273743" method="POST">
            <button type="submit">Add Iced Coffee to my favorites</button>
        </form>
    </div>
</div>

Contributions

This is Go package is currently highly experimental. Contributions from y'all would be much appreciated.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConditionalClassExtensionNodeProcessor

func ConditionalClassExtensionNodeProcessor(node *Node)

func ConditionalExtensionNodeProcessor

func ConditionalExtensionNodeProcessor(node *Node)

func RangeExtensionNodeProcessor

func RangeExtensionNodeProcessor(node *Node)

func StringInterpolationNodeProcessor

func StringInterpolationNodeProcessor(node *Node)

func TryEvaluateBoolUsingContext

func TryEvaluateBoolUsingContext(ecs EvaluatorContextSource, evaluator Evaluator, inputStr string) (bool, bool, error)

func TryEvaluateStringUsingContext

func TryEvaluateStringUsingContext(ecs EvaluatorContextSource, evaluator Evaluator, inputStr string) (bool, string, error)

func TryEvaluateUsingContext

func TryEvaluateUsingContext(ecs EvaluatorContextSource, evaluator Evaluator, inputStr string) (bool, interface{}, error)

Types

type AttrStringInterpExtension

type AttrStringInterpExtension struct {
	// contains filtered or unexported fields
}

func (AttrStringInterpExtension) Apply

func (asie AttrStringInterpExtension) Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

type Attribute

type Attribute struct {
	Key     string
	Value   string
	KeyOnly bool
}

func (Attribute) String

func (a Attribute) String() string

type ConditionalClassExtension

type ConditionalClassExtension struct {
	// contains filtered or unexported fields
}

func (*ConditionalClassExtension) Apply

func (ce *ConditionalClassExtension) Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

type ConditionalExtension

type ConditionalExtension struct {
	// contains filtered or unexported fields
}

func (*ConditionalExtension) Apply

func (ce *ConditionalExtension) Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

type DefaultExtensionDependencies

type DefaultExtensionDependencies struct {
	// contains filtered or unexported fields
}

func (*DefaultExtensionDependencies) Get

func (ed *DefaultExtensionDependencies) Get(dependencyKey DependencyKey) interface{}

type DependencyKey

type DependencyKey string
const (
	EvaluatorExtDepKey DependencyKey = "evaluator"
)

type Evaluator

type Evaluator interface {
	EvaluateBool(input string, params EvaluatorParams) (bool, error)
	EvaluateString(input string, params EvaluatorParams) (string, error)
	Evaluate(input string, params EvaluatorParams) (interface{}, error)
}

type EvaluatorContextSource

type EvaluatorContextSource interface {
	GetContextParams() []EvaluatorParams
	SetParentEvaluatorContextSource(ecs EvaluatorContextSource)
}

type EvaluatorParams

type EvaluatorParams map[string]interface{}

type Extension

type Extension interface {
	Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)
}

type ExtensionDependencies

type ExtensionDependencies interface {
	Get(dependencyKey DependencyKey) interface{}
}

func NewDefaultExtensionDependencies

func NewDefaultExtensionDependencies() ExtensionDependencies

type Node

type Node struct {
	Data string
	Type html.NodeType
	// contains filtered or unexported fields
}

func CopyNode

func CopyNode(node *Node) *Node

func CreateNode

func CreateNode(
	nodeType html.NodeType, data string,
	attributes []html.Attribute, isSelfClosing bool,
) *Node

func ParseNodes

func ParseNodes(rdr io.Reader, opts ...ParserOptionFunc) ([]*Node, error)

func (*Node) AddAttribute

func (n *Node) AddAttribute(key, value string)

func (*Node) AddExtension

func (n *Node) AddExtension(extension Extension)

func (*Node) AppendChild

func (n *Node) AppendChild(node *Node)

func (*Node) ApplyExtensions

func (n *Node) ApplyExtensions(dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

func (Node) Attributes

func (n Node) Attributes() []Attribute

func (Node) Children

func (n Node) Children(nodeFunc func(int, *Node) bool)

func (Node) ContextParams

func (n Node) ContextParams() EvaluatorParams

func (Node) FirstChild

func (n Node) FirstChild() *Node

func (*Node) GetContextParams

func (n *Node) GetContextParams() []EvaluatorParams

func (Node) HasAttribute

func (n Node) HasAttribute(key string) (bool, int, string)

func (Node) HasAttributes

func (n Node) HasAttributes(testFunc func(Attribute) bool) []Attribute

func (*Node) Insert

func (n *Node) Insert(newChildNode *Node, beforeChildNode *Node)

func (Node) LastChild

func (n Node) LastChild() *Node

func (Node) NextSibling

func (n Node) NextSibling() *Node

func (Node) NextSiblings

func (n Node) NextSiblings(nodeFunc func(*Node) bool)

func (Node) Parent

func (n Node) Parent() *Node

func (Node) PreviousSibling

func (n Node) PreviousSibling() *Node

func (*Node) RemoveAttribute

func (n *Node) RemoveAttribute(key string)

func (*Node) RemoveChild

func (n *Node) RemoveChild(child *Node)

func (*Node) ReplaceAttribute

func (n *Node) ReplaceAttribute(key string, value string)

func (*Node) SetContextParams

func (n *Node) SetContextParams(contextParams EvaluatorParams)

func (*Node) SetParentEvaluatorContextSource

func (n *Node) SetParentEvaluatorContextSource(ecs EvaluatorContextSource)

func (Node) Tags

func (n Node) Tags() (string, string)

type NodeProcessorFunc

type NodeProcessorFunc func(*Node)

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

type ParserOptionFunc

type ParserOptionFunc func(*Parser)

func NodeProcessorsParserOption

func NodeProcessorsParserOption(npfs ...NodeProcessorFunc) ParserOptionFunc

type RangeEvaluatorParams

type RangeEvaluatorParams []EvaluatorParams

func RangeParams

func RangeParams(params ...EvaluatorParams) RangeEvaluatorParams

type RangeExtension

type RangeExtension struct {
	// contains filtered or unexported fields
}

func (*RangeExtension) Apply

func (re *RangeExtension) Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

type Template

type Template struct {
	// contains filtered or unexported fields
}

func CreateTemplateFromReader

func CreateTemplateFromReader(reader io.Reader, parserOptions ...ParserOptionFunc) (*Template, error)

func Tplinate

func Tplinate(tplReader io.Reader, parserOptions ...ParserOptionFunc) (*Template, error)
Example
package main

import (
	"fmt"
	"log"
	"strings"

	"github.com/bmdelacruz/tplinator"
	"github.com/yosssi/gohtml"
)

func main() {
	sampleHtml := `
	<!doctype html>
	<html>
	<head>
		<title>Hello, world!</title>
	</head>
	<body>
		<form action="/test/{{go:uid}}" method="POST">
			<input type="hidden" name="secret" value="{{go:secret}}"/>
			<input type="hidden" name="confcode" value="{{go:confcode}}"/>
		</form>
		<div class="container">
			<h1 go-if="!shouldBeRendered">shouldBeRendered is equal to false</h1>
			<h2>shouldBeRendered is equal to true</h2>
			<div class="col-sm-4" go-if="shouldBeRendered">
				<h3>shouldBeRendered is equal to true</h3>
				<h4>Username: {{go:username}}</h4>
			</div>
			<ul>
				<li go-range="indexes">{{go:index}}</li>
			</ul>
		</div>
	</body>
	</html>
	`

	tpl, err := tplinator.Tplinate(strings.NewReader(sampleHtml))
	if err != nil {
		log.Fatal(err)
	}

	docBytes, err := tpl.RenderBytes(map[string]interface{}{
		"shouldBeRendered": true,

		"username": "bryanmdlx",
		"uid":      "28473664853",
		"secret":   "hImydjwKwixFa9yv08wRDw",
		"confcode": "Y3g1tT3sH-aHQ_rMJOSB7A",

		"indexes": tplinator.RangeParams(
			tplinator.EvaluatorParams{"index": "1"},
			tplinator.EvaluatorParams{"index": "2"},
			tplinator.EvaluatorParams{"index": "3"},
			tplinator.EvaluatorParams{"index": "4"},
			tplinator.EvaluatorParams{"index": "5"},
			tplinator.EvaluatorParams{"index": "6"},
		),
	})
	if err != nil {
		log.Fatal(err)
	}

	gohtml.Condense = true
	fmt.Printf("%s\n", gohtml.FormatBytes(docBytes))

}
Output:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello, world!</title>
  </head>
  <body>
    <form action="/test/28473664853" method="POST">
      <input type="hidden" name="secret" value="hImydjwKwixFa9yv08wRDw"/>
      <input type="hidden" name="confcode" value="Y3g1tT3sH-aHQ_rMJOSB7A"/>
    </form>
    <div class="container">
      <h2>shouldBeRendered is equal to true</h2>
      <div class="col-sm-4">
        <h3>shouldBeRendered is equal to true</h3>
        <h4>Username: bryanmdlx</h4>
      </div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
      </ul>
    </div>
  </body>
</html>

func (*Template) AddExtensionDependencies

func (tpl *Template) AddExtensionDependencies(extDeps ...ExtensionDependencies)

func (*Template) Render

func (tpl *Template) Render(params EvaluatorParams, writerFunc func(string)) error

func (*Template) RenderBytes

func (tpl *Template) RenderBytes(params EvaluatorParams) ([]byte, error)

func (*Template) RenderString

func (tpl *Template) RenderString(params EvaluatorParams) (string, error)

type TextStringInterpExtension

type TextStringInterpExtension struct {
	// contains filtered or unexported fields
}

func (TextStringInterpExtension) Apply

func (tsie TextStringInterpExtension) Apply(node *Node, dependencies ExtensionDependencies, params EvaluatorParams) (*Node, []*Node, error)

Jump to

Keyboard shortcuts

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