package html
import (
"bytes"
"fmt"
"github.com/dlclark/regexp2"
"github.com/fthvgb1/wp-go/helper/slice"
strings2 "github.com/fthvgb1/wp-go/helper/strings"
"html/template"
"regexp"
"strings"
)
var entitlesMap = map[int][]string{
EntCompat: {"&", """, "<", ">"},
EntQuotes: {"&", """, "'", "<", ">"},
EntNoQuotes: {"&", "<", ">"},
EntSpace: {" "},
}
var unEntitlesMap = map[int][]string{
EntCompat: {"&", "\"", "<", ">"},
EntQuotes: {"&", "\"", "'", "<", ">"},
EntNoQuotes: {"&", "<", ">"},
EntSpace: {" "},
}
const (
EntCompat = 1
EntQuotes = 2
EntNoQuotes = 4
EntSpace = 8
)
func SpecialChars(text string, flag ...int) string {
flags := EntQuotes
if len(flag) > 0 {
flags = flag[0]
}
r, ok := unEntitlesMap[flags]
e := entitlesMap[flags]
if !ok {
r = unEntitlesMap[EntCompat]
e = entitlesMap[EntCompat]
}
if flags&EntSpace == EntSpace {
r = append(r, unEntitlesMap[EntSpace]...)
e = append(e, entitlesMap[EntSpace]...)
}
for i, entitle := range r {
text = strings.Replace(text, entitle, e[i], -1)
}
return text
}
func SpecialCharsDecode(text string, flag ...int) string {
flags := EntQuotes
if len(flag) > 0 {
flags = flag[0]
}
r, ok := entitlesMap[flags]
u := unEntitlesMap[flags]
if !ok {
r = entitlesMap[EntCompat]
u = unEntitlesMap[EntCompat]
}
if flags&EntSpace == EntSpace {
r = append(r, entitlesMap[EntSpace]...)
u = append(u, unEntitlesMap[EntSpace]...)
}
for i, entitle := range r {
text = strings.Replace(text, entitle, u[i], -1)
}
return text
}
var allHtmlTag = regexp.MustCompile("?.*>")
func StripTags(str, allowable string) string {
html := ""
if allowable == "" {
return allHtmlTag.ReplaceAllString(str, "")
}
r := strings.Split(allowable, ">")
re := ""
for _, reg := range r {
if reg == "" {
continue
}
tag := strings.TrimLeft(reg, "<")
ree := fmt.Sprintf(`%s|\/%s`, tag, tag)
re = fmt.Sprintf("%s|%s", re, ree)
}
ree := strings.Trim(re, "|")
reg := fmt.Sprintf("<(?!%s).*?>", ree)
compile, err := regexp2.Compile(reg, regexp2.IgnoreCase)
if err != nil {
return str
}
html, err = compile.Replace(str, "", 0, -1)
if err != nil {
return str
}
return html
}
var tag = regexp.MustCompile(`(?is:<(.*?)>)`) //使用忽略大小写和包含换行符模式
func StripTagsX(str, allowable string) string {
if allowable == "" {
return allHtmlTag.ReplaceAllString(str, "")
}
tags := tag.ReplaceAllString(allowable, "$1|")
or := strings.TrimRight(tags, "|")
reg := fmt.Sprintf(`<(/?(%s).*?)>`, or)
regx := fmt.Sprintf(`\{\[(/?(%s).*?)\]\}`, or)
cp, err := regexp.Compile(reg)
if err != nil {
return str
}
rep := cp.ReplaceAllString(str, "{[$1]}")
tmp := tag.ReplaceAllString(rep, "")
rex, err := regexp.Compile(regx)
if err != nil {
return str
}
html := rex.ReplaceAllString(tmp, "<$1>")
return html
}
var selfCloseTags = map[string]string{"area": "", "base": "", "basefont": "", "br": "", "col": "", "command": "", "fecolormatrix": "", "embed": "", "frame": "", "hr": "", "img": "", "input": "", "isindex": "", "link": "", "fecomposite": "", "fefuncr": "", "fefuncg": "", "fefuncb": "", "fefunca": "", "meta": "", "param": "", "!doctype": "", "source": "", "track": "", "wbr": ""}
func CloseTag(str string) string {
tags := tag.FindAllString(str, -1)
if len(tags) < 1 {
return str
}
var tagss = make([]string, 0, len(tags))
for _, s := range tags {
ss := strings.Split(s, " ")
sss := strings2.Replace(ss[0], map[string]string{
"\\": "",
"\n": "",
"\\/": "/",
})
if strings.Contains(sss, "' {
sss = fmt.Sprintf("%s>", sss)
}
if _, ok := selfCloseTags[strings.Trim(strings.ToLower(sss), "\\/<>")]; ok {
continue
}
tagss = append(tagss, sss)
}
r := slice.Map(slice.Reverse(UnClosedTag(tagss)), func(s string) string {
return fmt.Sprintf("%s>", strings.Trim(s, "<>"))
})
return strings.Join(r, "")
}
func UnClosedTag(s []string) []string {
i := 0
for {
if len(s[i:]) < 2 {
return s
}
l := s[i]
r := fmt.Sprintf(`%s>`, strings.Trim(l, "<>"))
if s[i+1] == r {
if len(s[i+1:]) > 1 {
ss := s[:i]
s = append(ss, s[i+2:]...)
} else {
s = s[:i]
}
i = 0
continue
}
i++
}
}
func RenderedHtml(t *template.Template, data map[string]any) (r string, err error) {
var buf bytes.Buffer
err = t.Execute(&buf, data)
if err != nil {
return
}
r = buf.String()
return
}