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("") br.WriteString("") } if len(table.Body) > 0 { br.WriteString("") for _, cell := range table.Body { br.WriteString("") for _, text := range cell { br.WriteString("") } br.WriteString("") } br.WriteString("") } br.WriteString("
") br.WriteString(text.Html()) br.WriteString("
") br.WriteString(text.Html()) 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("") 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 }