mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
adding support for shortcodes with opening and closing tags
This commit is contained in:
parent
db29f57cc4
commit
a45de56db1
1 changed files with 106 additions and 16 deletions
|
@ -17,6 +17,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/hugo/template/bundle"
|
"github.com/spf13/hugo/template/bundle"
|
||||||
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
@ -32,26 +33,85 @@ type Shortcode struct {
|
||||||
|
|
||||||
type ShortcodeWithPage struct {
|
type ShortcodeWithPage struct {
|
||||||
Params interface{}
|
Params interface{}
|
||||||
|
Inner template.HTML
|
||||||
Page *Page
|
Page *Page
|
||||||
}
|
}
|
||||||
|
|
||||||
type Shortcodes map[string]ShortcodeFunc
|
type Shortcodes map[string]ShortcodeFunc
|
||||||
|
|
||||||
func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string {
|
func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string {
|
||||||
posStart := strings.Index(stringToParse, "{{%")
|
leadStart := strings.Index(stringToParse, `{{%`)
|
||||||
if posStart > 0 {
|
if leadStart >= 0 {
|
||||||
posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart
|
leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart
|
||||||
if posEnd > posStart {
|
if leadEnd > leadStart {
|
||||||
name, par := SplitParams(stringToParse[posStart+3 : posEnd])
|
name, par := SplitParams(stringToParse[leadStart+3 : leadEnd])
|
||||||
|
tmpl := GetTemplate(name, t)
|
||||||
|
if tmpl == nil {
|
||||||
|
return stringToParse
|
||||||
|
}
|
||||||
params := Tokenize(par)
|
params := Tokenize(par)
|
||||||
|
// Always look for closing tag.
|
||||||
|
endStart, endEnd := FindEnd(stringToParse[leadEnd:], name)
|
||||||
var data = &ShortcodeWithPage{Params: params, Page: p}
|
var data = &ShortcodeWithPage{Params: params, Page: p}
|
||||||
newString := stringToParse[:posStart] + ShortcodeRender(name, data, t) + ShortcodesHandle(stringToParse[posEnd+3:], p, t)
|
if endStart > 0 {
|
||||||
return newString
|
s := stringToParse[leadEnd+3 : leadEnd+endStart]
|
||||||
|
data.Inner = template.HTML(CleanP(ShortcodesHandle(s, p, t)))
|
||||||
|
remainder := CleanP(stringToParse[leadEnd+endEnd:])
|
||||||
|
|
||||||
|
return CleanP(stringToParse[:leadStart]) +
|
||||||
|
ShortcodeRender(tmpl, data) +
|
||||||
|
CleanP(ShortcodesHandle(remainder, p, t))
|
||||||
|
}
|
||||||
|
return CleanP(stringToParse[:leadStart]) +
|
||||||
|
ShortcodeRender(tmpl, data) +
|
||||||
|
CleanP(ShortcodesHandle(stringToParse[leadEnd+3:], p,
|
||||||
|
t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stringToParse
|
return stringToParse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up odd behavior when closing tag is on first line
|
||||||
|
// or opening tag is on the last line due to extra line in markdown file
|
||||||
|
func CleanP(str string) string {
|
||||||
|
if strings.HasSuffix(strings.TrimSpace(str), "<p>") {
|
||||||
|
idx := strings.LastIndex(str, "<p>")
|
||||||
|
str = str[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(strings.TrimSpace(str), "</p>") {
|
||||||
|
str = str[strings.Index(str, "</p>")+5:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindEnd(str string, name string) (int, int) {
|
||||||
|
var endPos int
|
||||||
|
var startPos int
|
||||||
|
var try []string
|
||||||
|
|
||||||
|
try = append(try, "{{% /"+name+" %}}")
|
||||||
|
try = append(try, "{{% /"+name+"%}}")
|
||||||
|
try = append(try, "{{%/"+name+"%}}")
|
||||||
|
try = append(try, "{{%/"+name+" %}}")
|
||||||
|
|
||||||
|
lowest := len(str)
|
||||||
|
for _, x := range try {
|
||||||
|
start := strings.Index(str, x)
|
||||||
|
if start < lowest && start > 0 {
|
||||||
|
startPos = start
|
||||||
|
endPos = startPos + len(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return startPos, endPos
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTemplate(name string, t bundle.Template) *template.Template {
|
||||||
|
return t.Lookup("shortcodes/" + name + ".html")
|
||||||
|
}
|
||||||
|
|
||||||
func StripShortcodes(stringToParse string) string {
|
func StripShortcodes(stringToParse string) string {
|
||||||
posStart := strings.Index(stringToParse, "{{%")
|
posStart := strings.Index(stringToParse, "{{%")
|
||||||
if posStart > 0 {
|
if posStart > 0 {
|
||||||
|
@ -67,6 +127,12 @@ func StripShortcodes(stringToParse string) string {
|
||||||
func Tokenize(in string) interface{} {
|
func Tokenize(in string) interface{} {
|
||||||
first := strings.Fields(in)
|
first := strings.Fields(in)
|
||||||
var final = make([]string, 0)
|
var final = make([]string, 0)
|
||||||
|
|
||||||
|
// if don't need to parse, don't parse.
|
||||||
|
if strings.Index(in, " ") < 0 && strings.Index(in, "=") < 1 {
|
||||||
|
return append(final, in)
|
||||||
|
}
|
||||||
|
|
||||||
var keys = make([]string, 0)
|
var keys = make([]string, 0)
|
||||||
inQuote := false
|
inQuote := false
|
||||||
start := 0
|
start := 0
|
||||||
|
@ -81,18 +147,38 @@ func Tokenize(in string) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(v, "“") && !inQuote {
|
// Adjusted to handle htmlencoded and non htmlencoded input
|
||||||
|
if !strings.HasPrefix(v, "“") && !strings.HasPrefix(v, "\"") && !inQuote {
|
||||||
final = append(final, v)
|
final = append(final, v)
|
||||||
} else if inQuote && strings.HasSuffix(v, "”") && !strings.HasSuffix(v, "\\\"") {
|
} else if inQuote && (strings.HasSuffix(v, "”") ||
|
||||||
|
strings.HasSuffix(v, "\"")) && !strings.HasSuffix(v, "\\\"") {
|
||||||
|
if strings.HasSuffix(v, "\"") {
|
||||||
|
first[i] = v[:len(v)-1]
|
||||||
|
} else {
|
||||||
first[i] = v[:len(v)-7]
|
first[i] = v[:len(v)-7]
|
||||||
|
}
|
||||||
final = append(final, strings.Join(first[start:i+1], " "))
|
final = append(final, strings.Join(first[start:i+1], " "))
|
||||||
inQuote = false
|
inQuote = false
|
||||||
} else if strings.HasPrefix(v, "“") && !inQuote {
|
} else if (strings.HasPrefix(v, "“") ||
|
||||||
if strings.HasSuffix(v, "”") {
|
strings.HasPrefix(v, "\"")) && !inQuote {
|
||||||
|
if strings.HasSuffix(v, "”") || strings.HasSuffix(v,
|
||||||
|
"\"") {
|
||||||
|
if strings.HasSuffix(v, "\"") {
|
||||||
|
if len(v) > 1 {
|
||||||
|
final = append(final, v[1:len(v)-1])
|
||||||
|
} else {
|
||||||
|
final = append(final, "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
final = append(final, v[7:len(v)-7])
|
final = append(final, v[7:len(v)-7])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
start = i
|
start = i
|
||||||
|
if strings.HasPrefix(v, "\"") {
|
||||||
|
first[i] = v[1:]
|
||||||
|
} else {
|
||||||
first[i] = v[7:]
|
first[i] = v[7:]
|
||||||
|
}
|
||||||
inQuote = true
|
inQuote = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +189,10 @@ func Tokenize(in string) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(keys) > 0 && (len(keys) != len(final)) {
|
||||||
|
panic("keys and final different lengths")
|
||||||
|
}
|
||||||
|
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
var m = make(map[string]string)
|
var m = make(map[string]string)
|
||||||
for i, k := range keys {
|
for i, k := range keys {
|
||||||
|
@ -124,8 +214,8 @@ func SplitParams(in string) (name string, par2 string) {
|
||||||
return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:])
|
return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShortcodeRender(name string, data *ShortcodeWithPage, t bundle.Template) string {
|
func ShortcodeRender(tmpl *template.Template, data *ShortcodeWithPage) string {
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
t.ExecuteTemplate(buffer, "shortcodes/"+name+".html", data)
|
tmpl.Execute(buffer, data)
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue