replace zxq.co/ripple/hanayo
This commit is contained in:
256
vendor/github.com/frustra/bbcode/compiler.go
generated
vendored
Normal file
256
vendor/github.com/frustra/bbcode/compiler.go
generated
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
// Copyright 2015 Frustra. All rights reserved.
|
||||
// Use of this source code is governed by the MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bbcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TagCompilerFunc func(*BBCodeNode) (*HTMLTag, bool)
|
||||
|
||||
type Compiler struct {
|
||||
tagCompilers map[string]TagCompilerFunc
|
||||
defaultCompiler TagCompilerFunc
|
||||
AutoCloseTags bool
|
||||
IgnoreUnmatchedClosingTags bool
|
||||
}
|
||||
|
||||
func NewCompiler(autoCloseTags, ignoreUnmatchedClosingTags bool) Compiler {
|
||||
compiler := Compiler{make(map[string]TagCompilerFunc), DefaultTagCompiler, autoCloseTags, ignoreUnmatchedClosingTags}
|
||||
|
||||
for tag, compilerFunc := range DefaultTagCompilers {
|
||||
compiler.SetTag(tag, compilerFunc)
|
||||
}
|
||||
return compiler
|
||||
}
|
||||
|
||||
func (c Compiler) Compile(str string) string {
|
||||
tokens := Lex(str)
|
||||
tree := Parse(tokens)
|
||||
return c.CompileTree(tree).String()
|
||||
}
|
||||
|
||||
func (c Compiler) SetDefault(compiler TagCompilerFunc) {
|
||||
if compiler == nil {
|
||||
panic("Default tag compiler can't be nil")
|
||||
} else {
|
||||
c.defaultCompiler = compiler
|
||||
}
|
||||
}
|
||||
|
||||
func (c Compiler) SetTag(tag string, compiler TagCompilerFunc) {
|
||||
if compiler == nil {
|
||||
delete(c.tagCompilers, tag)
|
||||
} else {
|
||||
c.tagCompilers[tag] = compiler
|
||||
}
|
||||
}
|
||||
|
||||
// CompileTree transforms BBCodeNode into an HTML tag.
|
||||
func (c Compiler) CompileTree(node *BBCodeNode) *HTMLTag {
|
||||
var out = NewHTMLTag("")
|
||||
if node.ID == TEXT {
|
||||
out.Value = node.Value.(string)
|
||||
InsertNewlines(out)
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(c.CompileTree(child))
|
||||
}
|
||||
} else if node.ID == CLOSING_TAG {
|
||||
if !c.IgnoreUnmatchedClosingTags {
|
||||
out.Value = node.Value.(BBClosingTag).Raw
|
||||
InsertNewlines(out)
|
||||
}
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(c.CompileTree(child))
|
||||
}
|
||||
} else if node.ClosingTag == nil && !c.AutoCloseTags {
|
||||
out.Value = node.Value.(BBOpeningTag).Raw
|
||||
InsertNewlines(out)
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(c.CompileTree(child))
|
||||
}
|
||||
} else {
|
||||
in := node.GetOpeningTag()
|
||||
|
||||
compileFunc, ok := c.tagCompilers[in.Name]
|
||||
if !ok {
|
||||
compileFunc = c.defaultCompiler
|
||||
}
|
||||
var appendExpr bool
|
||||
node.Compiler = &c
|
||||
out, appendExpr = compileFunc(node)
|
||||
if appendExpr {
|
||||
if len(node.Children) == 0 {
|
||||
out.AppendChild(NewHTMLTag(""))
|
||||
} else {
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(c.CompileTree(child))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func CompileText(in *BBCodeNode) string {
|
||||
out := ""
|
||||
if in.ID == TEXT {
|
||||
out = in.Value.(string)
|
||||
}
|
||||
for _, child := range in.Children {
|
||||
out += CompileText(child)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func CompileRaw(in *BBCodeNode) *HTMLTag {
|
||||
out := NewHTMLTag("")
|
||||
if in.ID == TEXT {
|
||||
out.Value = in.Value.(string)
|
||||
} else if in.ID == CLOSING_TAG {
|
||||
out.Value = in.Value.(BBClosingTag).Raw
|
||||
} else {
|
||||
out.Value = in.Value.(BBOpeningTag).Raw
|
||||
}
|
||||
for _, child := range in.Children {
|
||||
out.AppendChild(CompileRaw(child))
|
||||
}
|
||||
if in.ID == OPENING_TAG && in.ClosingTag != nil {
|
||||
tag := NewHTMLTag(in.ClosingTag.Raw)
|
||||
out.AppendChild(tag)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var DefaultTagCompilers map[string]TagCompilerFunc
|
||||
var DefaultTagCompiler TagCompilerFunc
|
||||
|
||||
func init() {
|
||||
DefaultTagCompiler = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag(node.GetOpeningTag().Raw)
|
||||
InsertNewlines(out)
|
||||
if len(node.Children) == 0 {
|
||||
out.AppendChild(NewHTMLTag(""))
|
||||
} else {
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(node.Compiler.CompileTree(child))
|
||||
}
|
||||
}
|
||||
if node.ClosingTag != nil {
|
||||
tag := NewHTMLTag(node.ClosingTag.Raw)
|
||||
InsertNewlines(tag)
|
||||
out.AppendChild(tag)
|
||||
}
|
||||
return out, false
|
||||
}
|
||||
|
||||
DefaultTagCompilers = make(map[string]TagCompilerFunc)
|
||||
DefaultTagCompilers["url"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "a"
|
||||
value := node.GetOpeningTag().Value
|
||||
if value == "" {
|
||||
text := CompileText(node)
|
||||
if len(text) > 0 {
|
||||
out.Attrs["href"] = ValidURL(text)
|
||||
}
|
||||
} else {
|
||||
out.Attrs["href"] = ValidURL(value)
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
DefaultTagCompilers["img"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "img"
|
||||
value := node.GetOpeningTag().Value
|
||||
if value == "" {
|
||||
out.Attrs["src"] = ValidURL(CompileText(node))
|
||||
} else {
|
||||
out.Attrs["src"] = ValidURL(value)
|
||||
text := CompileText(node)
|
||||
if len(text) > 0 {
|
||||
out.Attrs["alt"] = text
|
||||
out.Attrs["title"] = out.Attrs["alt"]
|
||||
}
|
||||
}
|
||||
return out, false
|
||||
}
|
||||
|
||||
DefaultTagCompilers["center"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "div"
|
||||
out.Attrs["style"] = "text-align: center;"
|
||||
return out, true
|
||||
}
|
||||
|
||||
DefaultTagCompilers["color"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "span"
|
||||
sanitize := func(r rune) rune {
|
||||
if r == '#' || r == ',' || r == '.' || r == '(' || r == ')' || r == '%' {
|
||||
return r
|
||||
} else if r >= '0' && r <= '9' {
|
||||
return r
|
||||
} else if r >= 'a' && r <= 'z' {
|
||||
return r
|
||||
} else if r >= 'A' && r <= 'Z' {
|
||||
return r
|
||||
}
|
||||
return -1
|
||||
}
|
||||
color := strings.Map(sanitize, node.GetOpeningTag().Value)
|
||||
out.Attrs["style"] = "color: " + color + ";"
|
||||
return out, true
|
||||
}
|
||||
|
||||
DefaultTagCompilers["size"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "span"
|
||||
if size, err := strconv.Atoi(node.GetOpeningTag().Value); err == nil {
|
||||
out.Attrs["class"] = fmt.Sprintf("size%d", size)
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
DefaultTagCompilers["quote"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "blockquote"
|
||||
who := ""
|
||||
in := node.GetOpeningTag()
|
||||
if name, ok := in.Args["name"]; ok && name != "" {
|
||||
who = name
|
||||
} else {
|
||||
who = in.Value
|
||||
}
|
||||
cite := NewHTMLTag("")
|
||||
cite.Name = "cite"
|
||||
if who != "" {
|
||||
cite.AppendChild(NewHTMLTag(who + " said:"))
|
||||
} else {
|
||||
cite.AppendChild(NewHTMLTag("Quote"))
|
||||
}
|
||||
return out.AppendChild(cite), true
|
||||
}
|
||||
|
||||
DefaultTagCompilers["code"] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = "pre"
|
||||
for _, child := range node.Children {
|
||||
out.AppendChild(CompileRaw(child))
|
||||
}
|
||||
return out, false
|
||||
}
|
||||
|
||||
for _, tag := range []string{"i", "b", "u", "s"} {
|
||||
DefaultTagCompilers[tag] = func(node *BBCodeNode) (*HTMLTag, bool) {
|
||||
out := NewHTMLTag("")
|
||||
out.Name = node.GetOpeningTag().Name
|
||||
return out, true
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user