package pgenr
import (
"bytes"
"golang.org/x/net/html/atom"
"html"
"sync"
)
const (
TextThemeSuccess = "success"
TextThemeDanger = "danger"
)
var (
bufferPool sync.Pool
)
func getBuffer() *bytes.Buffer {
if v := bufferPool.Get(); v == nil {
return new(bytes.Buffer)
} else {
return v.(*bytes.Buffer)
}
}
func releaseBuffer(sb *bytes.Buffer) {
sb.Reset()
bufferPool.Put(sb)
}
type (
Element interface {
Html() string
}
Style map[string]string
TextOption func(t *Text)
ButtonOption func(btn *Button)
Text struct {
Tag atom.Atom
Content string
Theme string
Color string
Style Style
}
Button struct {
Url string
Text string
Color string
Style Style
}
Entry struct {
Title Element
Items map[string]Element
}
Action struct {
Instructions Element
Button *Button
InviteCode string
}
Table struct {
Title Element
Header []Element
Body [][]Element
}
Page struct {
Title string
Head string
Intros []Element
Entries []*Entry
Actions []*Action
Tables []*Table
Outros []Element
Copyright string
}
)
func (s Style) Css(name string, value string) {
s[name] = value
}
func (s Style) String() string {
br := getBuffer()
defer releaseBuffer(br)
for k, v := range s {
br.WriteString(k)
br.WriteString(":")
br.WriteString(v)
br.WriteString(";")
}
return br.String()
}
func (a *Action) Html() string {
return a.String()
}
func (a *Action) String() string {
br := getBuffer()
defer releaseBuffer(br)
if a.Instructions != nil {
br.WriteString(a.Instructions.Html())
}
br.WriteString("
")
if a.InviteCode != "" {
br.WriteString("")
br.WriteString(html.EscapeString(a.InviteCode))
br.WriteString("")
}
if a.Button != nil {
br.WriteString(a.Button.String())
}
br.WriteString("
")
return br.String()
}
func (e *Entry) Html() string {
return e.String()
}
func (e *Entry) String() string {
br := getBuffer()
defer releaseBuffer(br)
br.WriteString("")
if e.Title != nil {
br.WriteString(e.Title.Html())
}
for k, v := range e.Items {
br.WriteString("
")
br.WriteString("
")
br.WriteString(k)
br.WriteString("
")
br.WriteString("
")
br.WriteString(v.Html())
br.WriteString("
")
br.WriteString("
")
}
br.WriteString("
")
return br.String()
}
func (e *Entry) AddItem(label string, txt *Text) *Entry {
if e.Items == nil {
e.Items = make(map[string]Element)
}
e.Items[label] = txt
return e
}
func (page *Page) SetHead(s string) *Page {
page.Head = s
return page
}
func (page *Page) SetCopyright(s string) *Page {
page.Copyright = s
return page
}
func (page *Page) AddPlainIntro(s string) *Page {
page.Intros = append(page.Intros, NewText(s, WithTextTag(atom.P)))
return page
}
func (page *Page) AddIntro(t *Text) *Page {
page.Intros = append(page.Intros, t)
return page
}
func (page *Page) AddEntry(e *Entry) *Page {
page.Entries = append(page.Entries, e)
return page
}
func (page *Page) AddTable(t *Table) *Page {
page.Tables = append(page.Tables, t)
return page
}
func (page *Page) AddButtonAction(s string, btn *Button) *Page {
page.Actions = append(page.Actions, &Action{Instructions: NewText(s, WithTextTag(atom.P)), Button: btn})
return page
}
func (page *Page) AddInviteCodeAction(s string, code string) *Page {
page.Actions = append(page.Actions, &Action{Instructions: NewText(s, WithTextTag(atom.P)), InviteCode: code})
return page
}
func (page *Page) AddOutro(t *Text) *Page {
page.Outros = append(page.Outros, t)
return page
}
func (page *Page) AddPlainOutro(s string) *Page {
page.Outros = append(page.Outros, NewText(s, WithTextTag(atom.P)))
return page
}
func (page *Page) Escape() {
page.Head = html.EscapeString(page.Head)
page.Copyright = html.EscapeString(page.Copyright)
}
func NewPage(title string) *Page {
return &Page{
Title: title,
Intros: make([]Element, 0),
Entries: make([]*Entry, 0),
Actions: make([]*Action, 0),
Outros: make([]Element, 0),
Tables: make([]*Table, 0),
}
}
func NewEntry(title string) *Entry {
return &Entry{
Title: NewText(title, WithTextTag(atom.P)),
Items: make(map[string]Element),
}
}
func WithTextTheme(s string) TextOption {
return func(t *Text) {
t.Theme = s
}
}
func WithTextStyle(ms map[string]string) TextOption {
return func(t *Text) {
t.Style = ms
}
}
func WithTextTag(tag atom.Atom) TextOption {
return func(t *Text) {
t.Tag = tag
}
}
func WithTextColor(color string) TextOption {
return func(t *Text) {
t.Color = color
}
}
func (button *Button) Html() string {
return button.String()
}
func (button *Button) String() string {
br := getBuffer()
defer releaseBuffer(br)
if button.Style == nil {
button.Style = make(map[string]string)
}
if button.Color != "" {
button.Style["color"] = button.Color
}
br.WriteString(" 0 {
br.WriteString(" style='")
br.WriteString(button.Style.String())
br.WriteString("'")
}
br.WriteString(">")
br.WriteString(html.EscapeString(button.Text))
br.WriteString("")
return br.String()
}
func (table *Table) SetHead(elements ...Element) {
table.Header = elements
}
func (table *Table) AddCell(elements ...Element) {
if table.Body == nil {
table.Body = make([][]Element, 0)
}
table.Body = append(table.Body, elements)
}
func (table *Table) String() string {
br := getBuffer()
defer releaseBuffer(br)
br.WriteString("")
if table.Title != nil {
br.WriteString("
")
br.WriteString(table.Title.Html())
br.WriteString("
")
}
br.WriteString("
")
if len(table.Header) > 0 {
br.WriteString("")
br.WriteString("")
for _, text := range table.Header {
br.WriteString("")
br.WriteString(text.Html())
br.WriteString(" | ")
}
br.WriteString("
")
br.WriteString("")
}
if len(table.Body) > 0 {
br.WriteString("")
for _, cell := range table.Body {
br.WriteString("")
for _, text := range cell {
br.WriteString("")
br.WriteString(text.Html())
br.WriteString(" | ")
}
br.WriteString("
")
}
br.WriteString("")
}
br.WriteString("
")
br.WriteString("
")
return br.String()
}
func (text *Text) Html() string {
return text.String()
}
func (text *Text) String() string {
br := getBuffer()
defer releaseBuffer(br)
if text.Style == nil {
text.Style = make(map[string]string)
}
if text.Color != "" {
text.Style["color"] = text.Color
}
if text.Tag == 0 {
text.Tag = atom.Span
}
br.WriteString("<")
br.WriteString(text.Tag.String())
if text.Theme != "" {
br.WriteString(" class='text-")
br.WriteString(text.Theme)
br.WriteString("'")
}
if len(text.Style) > 0 {
br.WriteString(" style='")
br.WriteString(text.Style.String())
br.WriteString("'")
}
br.WriteString(">")
br.WriteString(html.EscapeString(text.Content))
br.WriteString("")
br.WriteString(text.Tag.String())
br.WriteString(">")
return br.String()
}
func NewButton(label, link string, opts ...ButtonOption) *Button {
btn := &Button{Text: label, Url: link}
for _, cb := range opts {
cb(btn)
}
return btn
}
func NewText(s string, opts ...TextOption) *Text {
txt := &Text{Content: s, Tag: atom.Span}
for _, cb := range opts {
cb(txt)
}
return txt
}
func NewTable(title *Text) *Table {
table := &Table{
Title: title,
Header: make([]Element, 0),
Body: make([][]Element, 0),
}
return table
}