mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-22 21:42:50 +02:00
markup/goldmark: Add removeSurroundingParagraph for Markdown images
* Removes any surrounding paragraph nodes * And transfers any attributes from the surrounding paragraph down to the image node * Adds IsBlock and Ordinal (zero based) field to the image context passed to the image render hooks IsBlock is set to true if `wrapStandAloneImageWithinParagraph = false` and the image's parent node has only one child. Closes #8362 Fixes #10492 Fixes #10494 Fixes #10501
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/gohugoio/hugo/common/types/hstring"
|
||||
"github.com/gohugoio/hugo/markup/converter/hooks"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/images"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
|
||||
"github.com/gohugoio/hugo/markup/internal/attributes"
|
||||
|
||||
@@ -52,16 +53,13 @@ type linkContext struct {
|
||||
title string
|
||||
text hstring.RenderedString
|
||||
plainText string
|
||||
*attributes.AttributesHolder
|
||||
}
|
||||
|
||||
func (ctx linkContext) Destination() string {
|
||||
return ctx.destination
|
||||
}
|
||||
|
||||
func (ctx linkContext) Resolved() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ctx linkContext) Page() any {
|
||||
return ctx.page
|
||||
}
|
||||
@@ -78,6 +76,20 @@ func (ctx linkContext) Title() string {
|
||||
return ctx.title
|
||||
}
|
||||
|
||||
type imageLinkContext struct {
|
||||
linkContext
|
||||
ordinal int
|
||||
isBlock bool
|
||||
}
|
||||
|
||||
func (ctx imageLinkContext) IsBlock() bool {
|
||||
return ctx.isBlock
|
||||
}
|
||||
|
||||
func (ctx imageLinkContext) Ordinal() int {
|
||||
return ctx.ordinal
|
||||
}
|
||||
|
||||
type headingContext struct {
|
||||
page any
|
||||
level int
|
||||
@@ -151,14 +163,36 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
|
||||
text := ctx.Buffer.Bytes()[pos:]
|
||||
ctx.Buffer.Truncate(pos)
|
||||
|
||||
var (
|
||||
isBlock bool
|
||||
ordinal int
|
||||
)
|
||||
if b, ok := n.AttributeString(images.AttrIsBlock); ok && b.(bool) {
|
||||
isBlock = true
|
||||
}
|
||||
if n, ok := n.AttributeString(images.AttrOrdinal); ok {
|
||||
ordinal = n.(int)
|
||||
}
|
||||
|
||||
// We use the attributes to signal from the parser whether the image is in
|
||||
// a block context or not.
|
||||
// We may find a better way to do that, but for now, we'll need to remove any
|
||||
// internal attributes before rendering.
|
||||
attrs := r.filterInternalAttributes(n.Attributes())
|
||||
|
||||
err := lr.RenderLink(
|
||||
w,
|
||||
linkContext{
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: string(n.Destination),
|
||||
title: string(n.Title),
|
||||
text: hstring.RenderedString(text),
|
||||
plainText: string(n.Text(source)),
|
||||
imageLinkContext{
|
||||
linkContext: linkContext{
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: string(n.Destination),
|
||||
title: string(n.Title),
|
||||
text: hstring.RenderedString(text),
|
||||
plainText: string(n.Text(source)),
|
||||
AttributesHolder: attributes.New(attrs, attributes.AttributesOwnerGeneral),
|
||||
},
|
||||
ordinal: ordinal,
|
||||
isBlock: isBlock,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -167,6 +201,17 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
|
||||
return ast.WalkContinue, err
|
||||
}
|
||||
|
||||
func (r *hookedRenderer) filterInternalAttributes(attrs []ast.Attribute) []ast.Attribute {
|
||||
n := 0
|
||||
for _, x := range attrs {
|
||||
if !bytes.HasPrefix(x.Name, []byte(internalAttrPrefix)) {
|
||||
attrs[n] = x
|
||||
n++
|
||||
}
|
||||
}
|
||||
return attrs[:n]
|
||||
}
|
||||
|
||||
// Fall back to the default Goldmark render funcs. Method below borrowed from:
|
||||
// https://github.com/yuin/goldmark/blob/b611cd333a492416b56aa8d94b04a67bf0096ab2/renderer/html/html.go#L404
|
||||
func (r *hookedRenderer) renderImageDefault(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||
@@ -186,6 +231,10 @@ func (r *hookedRenderer) renderImageDefault(w util.BufWriter, source []byte, nod
|
||||
r.Writer.Write(w, n.Title)
|
||||
_ = w.WriteByte('"')
|
||||
}
|
||||
if n.Attributes() != nil {
|
||||
attrs := r.filterInternalAttributes(n.Attributes())
|
||||
attributes.RenderASTAttributes(w, attrs...)
|
||||
}
|
||||
if r.XHTML {
|
||||
_, _ = w.WriteString(" />")
|
||||
} else {
|
||||
@@ -224,11 +273,12 @@ func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.No
|
||||
err := lr.RenderLink(
|
||||
w,
|
||||
linkContext{
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: string(n.Destination),
|
||||
title: string(n.Title),
|
||||
text: hstring.RenderedString(text),
|
||||
plainText: string(n.Text(source)),
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: string(n.Destination),
|
||||
title: string(n.Title),
|
||||
text: hstring.RenderedString(text),
|
||||
plainText: string(n.Text(source)),
|
||||
AttributesHolder: attributes.Empty,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -292,10 +342,11 @@ func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node as
|
||||
err := lr.RenderLink(
|
||||
w,
|
||||
linkContext{
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: url,
|
||||
text: hstring.RenderedString(label),
|
||||
plainText: label,
|
||||
page: ctx.DocumentContext().Document,
|
||||
destination: url,
|
||||
text: hstring.RenderedString(label),
|
||||
plainText: label,
|
||||
AttributesHolder: attributes.Empty,
|
||||
},
|
||||
)
|
||||
|
||||
|
Reference in New Issue
Block a user