ソースを参照

优化元素接口

fancl 2 年 前
コミット
d0e13db493
2 ファイル変更155 行追加99 行削除
  1. 152 77
      pgenr.go
  2. 3 22
      theme/default.go

+ 152 - 77
pgenr.go

@@ -1,9 +1,10 @@
 package pgenr
 
 import (
+	"bytes"
 	"golang.org/x/net/html/atom"
 	"html"
-	"strings"
+	"sync"
 )
 
 const (
@@ -11,7 +12,28 @@ const (
 	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
+	}
+
 	TextOption func(t *Text)
 
 	ButtonOption func(btn *Button)
@@ -32,37 +54,85 @@ type (
 	}
 
 	Entry struct {
-		Title *Text
-		Items map[string]*Text
+		Title Element
+		Items map[string]Element
 	}
 
 	Action struct {
-		Instructions *Text
+		Instructions Element
 		Button       *Button
 		InviteCode   string
 	}
 
 	Table struct {
-		Title  *Text
-		Header []*Text
-		Body   [][]*Text
+		Title  Element
+		Header []Element
+		Body   [][]Element
 	}
 
 	Page struct {
 		Title     string
 		Head      string
-		Intros    []*Text
+		Intros    []Element
 		Entries   []*Entry
 		Actions   []*Action
 		Tables    []*Table
-		Outros    []*Text
+		Outros    []Element
 		Copyright 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("<div class='action-block'>")
+	if a.InviteCode != "" {
+		br.WriteString("<span class='invite-code'>")
+		br.WriteString(html.EscapeString(a.InviteCode))
+		br.WriteString("</span>")
+	}
+	if a.Button != nil {
+		br.WriteString(a.Button.String())
+	}
+	br.WriteString("</div>")
+	return br.String()
+}
+
+func (e *Entry) Html() string {
+	return e.String()
+}
+
+func (e *Entry) String() string {
+	br := getBuffer()
+	defer releaseBuffer(br)
+	br.WriteString("<div class='grid'>")
+	if e.Title != nil {
+		br.WriteString(e.Title.Html())
+	}
+	for k, v := range e.Items {
+		br.WriteString("<div class='row'>")
+		br.WriteString("<div class='preview-label'>")
+		br.WriteString(k)
+		br.WriteString("</div>")
+		br.WriteString("<div class='preview-value'>")
+		br.WriteString(v.Html())
+		br.WriteString("</div>")
+		br.WriteString("</div>")
+	}
+	br.WriteString("</div>")
+	return br.String()
+}
+
 func (e *Entry) AddItem(label string, txt *Text) *Entry {
 	if e.Items == nil {
-		e.Items = make(map[string]*Text)
+		e.Items = make(map[string]Element)
 	}
 	e.Items[label] = txt
 	return e
@@ -126,10 +196,10 @@ func (page *Page) Escape() {
 func NewPage(title string) *Page {
 	return &Page{
 		Title:   title,
-		Intros:  make([]*Text, 0),
+		Intros:  make([]Element, 0),
 		Entries: make([]*Entry, 0),
 		Actions: make([]*Action, 0),
-		Outros:  make([]*Text, 0),
+		Outros:  make([]Element, 0),
 		Tables:  make([]*Table, 0),
 	}
 }
@@ -137,7 +207,7 @@ func NewPage(title string) *Page {
 func NewEntry(title string) *Entry {
 	return &Entry{
 		Title: NewText(title, WithTextTag(atom.P)),
-		Items: make(map[string]*Text),
+		Items: make(map[string]Element),
 	}
 }
 
@@ -165,89 +235,94 @@ func WithTextColor(color string) TextOption {
 	}
 }
 
+func (button *Button) Html() string {
+	return button.String()
+}
+
 func (button *Button) String() string {
-	var (
-		sb strings.Builder
-	)
+	br := getBuffer()
+	defer releaseBuffer(br)
 	if button.Style == nil {
 		button.Style = make(map[string]string)
 	}
 	if button.Color != "" {
 		button.Style["color"] = button.Color
 	}
-	sb.WriteString("<a class='button'")
+	br.WriteString("<a class='button'")
 	if button.Url != "" {
-		sb.WriteString(" href='" + button.Url + "'")
+		br.WriteString(" href='" + button.Url + "'")
 	}
 	if len(button.Style) > 0 {
-		sb.WriteString(" style='")
+		br.WriteString(" style='")
 		for k, v := range button.Style {
-			sb.WriteString(k)
-			sb.WriteString(":")
-			sb.WriteString(v)
-			sb.WriteString(";")
+			br.WriteString(k)
+			br.WriteString(":")
+			br.WriteString(v)
+			br.WriteString(";")
 		}
-		sb.WriteString("'")
+		br.WriteString("'")
 	}
-	sb.WriteString(">")
-	sb.WriteString(html.EscapeString(button.Text))
-	sb.WriteString("</a>")
-	return sb.String()
+	br.WriteString(">")
+	br.WriteString(html.EscapeString(button.Text))
+	br.WriteString("</a>")
+	return br.String()
 }
 
-func (table *Table) SetHead(header ...*Text) {
-	table.Header = header
+func (table *Table) SetHead(elements ...Element) {
+	table.Header = elements
 }
 
-func (table *Table) AddCell(texts ...*Text) {
+func (table *Table) AddCell(elements ...Element) {
 	if table.Body == nil {
-		table.Body = make([][]*Text, 0)
+		table.Body = make([][]Element, 0)
 	}
-	table.Body = append(table.Body, texts)
+	table.Body = append(table.Body, elements)
 }
 
 func (table *Table) String() string {
-	var (
-		sb strings.Builder
-	)
-	sb.WriteString("<div class='table-wrapper'>")
+	br := getBuffer()
+	defer releaseBuffer(br)
+	br.WriteString("<div class='table-wrapper'>")
 	if table.Title != nil {
-		sb.WriteString("<div class='table-title'>")
-		sb.WriteString(table.Title.String())
-		sb.WriteString("</div>")
+		br.WriteString("<div class='table-title'>")
+		br.WriteString(table.Title.Html())
+		br.WriteString("</div>")
 	}
-	sb.WriteString("<table class='table'>")
+	br.WriteString("<table class='table'>")
 
 	if len(table.Header) > 0 {
-		sb.WriteString("<thead><tr>")
+		br.WriteString("<thead><tr>")
 		for _, text := range table.Header {
-			sb.WriteString("<th>")
-			sb.WriteString(text.String())
-			sb.WriteString("</th>")
+			br.WriteString("<th>")
+			br.WriteString(text.Html())
+			br.WriteString("</th>")
 		}
-		sb.WriteString("</tr></thead>")
+		br.WriteString("</tr></thead>")
 	}
 	if len(table.Body) > 0 {
-		sb.WriteString("<tbody>")
+		br.WriteString("<tbody>")
 		for _, cell := range table.Body {
-			sb.WriteString("<tr>")
+			br.WriteString("<tr>")
 			for _, text := range cell {
-				sb.WriteString("<td>")
-				sb.WriteString(text.String())
-				sb.WriteString("</td>")
+				br.WriteString("<td>")
+				br.WriteString(text.Html())
+				br.WriteString("</td>")
 			}
-			sb.WriteString("</tr>")
+			br.WriteString("</tr>")
 		}
-		sb.WriteString("</tbody>")
+		br.WriteString("</tbody>")
 	}
-	sb.WriteString("</table></div>")
-	return sb.String()
+	br.WriteString("</table></div>")
+	return br.String()
+}
+
+func (text *Text) Html() string {
+	return text.String()
 }
 
 func (text *Text) String() string {
-	var (
-		sb strings.Builder
-	)
+	br := getBuffer()
+	defer releaseBuffer(br)
 	if text.Style == nil {
 		text.Style = make(map[string]string)
 	}
@@ -257,29 +332,29 @@ func (text *Text) String() string {
 	if text.Tag == 0 {
 		text.Tag = atom.Span
 	}
-	sb.WriteString("<")
-	sb.WriteString(text.Tag.String())
+	br.WriteString("<")
+	br.WriteString(text.Tag.String())
 	if text.Theme != "" {
-		sb.WriteString(" class='text-")
-		sb.WriteString(text.Theme)
-		sb.WriteString("'")
+		br.WriteString(" class='text-")
+		br.WriteString(text.Theme)
+		br.WriteString("'")
 	}
 	if len(text.Style) > 0 {
-		sb.WriteString(" style='")
+		br.WriteString(" style='")
 		for k, v := range text.Style {
-			sb.WriteString(k)
-			sb.WriteString(":")
-			sb.WriteString(v)
-			sb.WriteString(";")
+			br.WriteString(k)
+			br.WriteString(":")
+			br.WriteString(v)
+			br.WriteString(";")
 		}
-		sb.WriteString("'")
+		br.WriteString("'")
 	}
-	sb.WriteString(">")
-	sb.WriteString(html.EscapeString(text.Content))
-	sb.WriteString("</")
-	sb.WriteString(text.Tag.String())
-	sb.WriteString(">")
-	return sb.String()
+	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 {
@@ -301,8 +376,8 @@ func NewText(s string, opts ...TextOption) *Text {
 func NewTable(title *Text) *Table {
 	table := &Table{
 		Title:  title,
-		Header: make([]*Text, 0),
-		Body:   make([][]*Text, 0),
+		Header: make([]Element, 0),
+		Body:   make([][]Element, 0),
 	}
 	return table
 }

+ 3 - 22
theme/default.go

@@ -35,7 +35,7 @@ func (theme *Default) Template() string {
 
     .container {
       max-width: 560px;
-      height: 100%;
+      min-height: 100%;
       margin: 0 auto;
       background-color: white;
     }
@@ -200,33 +200,14 @@ func (theme *Default) Template() string {
 		{{ with .Page.Actions }}
 			{{ if gt (len .) 0 }}
 				{{ range $action := . }}
-					{{ if $action.Instructions }}
-						{{ $action.Instructions }}
-					{{ end }}
-					{{ if $action.InviteCode }}
-						<div class="action-block"><span class="invite-code">{{ $action.InviteCode }}</span></div>
-					{{ else if $action.Button }}
-						<div class="action-block">{{ $action.Button }}</div>
-					{{ end }}
+					{{ $action }}
 				{{ end }}
 			{{ end }}
 		{{ end }}
 		{{ with .Page.Entries }}
 			{{ if gt (len .) 0 }}
 				{{ range $entry := . }}
-				<div class="grid">
-					{{if $entry.Title }}<h4>{{ $entry.Title }}</h4>{{ end }}
-					{{ with $entry.Items }}
-						{{ if gt (len .) 0 }}
-						  {{ range $label,$value := . }}
-							<div class="row">
-							  <div class="preview-label">{{ $label }}</div>
-							  <div class="preview-value">{{ $value }}</div>
-						    </div>
-						  {{ end }}
-						{{ end }}
-					{{ end }}
-				</div>
+					{{ $entry }}
 				{{ end }}
 			{{ end }}
 		{{ end }}