1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-29 08:56:23 -07:00
gochan/pkg/gctemplates/misc.go

86 lines
2.6 KiB
Go

package gctemplates
import (
"bytes"
"html/template"
"strings"
"github.com/gochan-org/gochan/pkg/gcutil"
x_html "golang.org/x/net/html"
)
// truncateHTML truncates a template.HTML string to a certain visible character limit and line limit
func truncateHTML(htmlText template.HTML, characterLimit, maxLines int) template.HTML {
if htmlText == "" {
return ""
}
node, err := x_html.Parse(strings.NewReader(string(htmlText)))
if err != nil {
gcutil.LogError(err).Send()
return template.HTML("Server error truncating HTML, failed to parse html")
}
buf := new(bytes.Buffer)
if node.Type == x_html.DocumentNode {
node = node.FirstChild.LastChild // FirstChild is <html>, has <head> and <body> children
}
truncateHTMLNodes(node, characterLimit, maxLines)
for node = node.FirstChild; node != nil; node = node.NextSibling {
// render all nodes inside body node
x_html.Render(buf, node)
}
return template.HTML(buf.String()) // skipcq: GSC-G203
}
func removeNextSiblings(node *x_html.Node) {
if node == nil {
return
}
removeNextSiblings(node.NextSibling)
node.Parent.RemoveChild(node)
}
func truncateHTMLNodes(node *x_html.Node, charactersLeft, linesLeft int) (charsLeft, lineLeft int) {
//Uses a depth first search to map nodes and remove the rest.
if node == nil {
return charactersLeft, linesLeft
}
//if either value is 0 or less, remove next siblings and self
if charactersLeft <= 0 || linesLeft <= 0 {
removeNextSiblings(node)
}
switch node.Type {
case x_html.ElementNode:
//This is a tag node. If tag node is br, reduce amount of lines by 1
if strings.ToLower(node.Data) == "br" {
linesLeft--
}
//Acts as normal node for the rest
fallthrough
case x_html.CommentNode:
fallthrough
case x_html.DoctypeNode:
fallthrough
case x_html.RawNode:
fallthrough
case x_html.ErrorNode:
fallthrough
case x_html.DocumentNode:
//None of the nodes directly contain text
//truncate children first
charactersLeft, linesLeft = truncateHTMLNodes(node.FirstChild, charactersLeft, linesLeft)
//Pass values to siblings (sibling code will immediately exit if no more chars allowed, and remove self)
return truncateHTMLNodes(node.NextSibling, charactersLeft, linesLeft)
case x_html.TextNode:
if len(node.Data) > charactersLeft {
node.Data = node.Data[0:charactersLeft-1] + "..."
}
charactersLeft -= len(node.Data)
return truncateHTMLNodes(node.NextSibling, charactersLeft, linesLeft)
}
gcutil.LogError(nil).
Interface("node", node).
Msg("Did not match any known node type, possible unhandled error?")
return charactersLeft, linesLeft
}