aboutsummaryrefslogtreecommitdiffstats
path: root/modules/markup
diff options
context:
space:
mode:
Diffstat (limited to 'modules/markup')
-rw-r--r--modules/markup/html.go9
-rw-r--r--modules/markup/html_commit.go2
-rw-r--r--modules/markup/html_link.go4
-rw-r--r--modules/markup/html_node.go10
-rw-r--r--modules/markup/markdown/markdown.go5
-rw-r--r--modules/markup/markdown/markdown_test.go21
-rw-r--r--modules/markup/markdown/math/block_renderer.go2
-rw-r--r--modules/markup/markdown/meta_test.go8
-rw-r--r--modules/markup/markdown/transform_heading.go2
-rw-r--r--modules/markup/sanitizer_default.go2
10 files changed, 35 insertions, 30 deletions
diff --git a/modules/markup/html.go b/modules/markup/html.go
index e8391341d9..51afd4be00 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"regexp"
+ "slices"
"strings"
"sync"
@@ -109,13 +110,7 @@ func CustomLinkURLSchemes(schemes []string) {
if !validScheme.MatchString(s) {
continue
}
- without := false
- for _, sna := range xurls.SchemesNoAuthority {
- if s == sna {
- without = true
- break
- }
- }
+ without := slices.Contains(xurls.SchemesNoAuthority, s)
if without {
s += ":"
} else {
diff --git a/modules/markup/html_commit.go b/modules/markup/html_commit.go
index 967c327f36..fe7a034967 100644
--- a/modules/markup/html_commit.go
+++ b/modules/markup/html_commit.go
@@ -62,7 +62,7 @@ func anyHashPatternExtract(s string) (ret anyHashPatternResult, ok bool) {
// if url ends in '.', it's very likely that it is not part of the actual url but used to finish a sentence.
ret.PosEnd--
ret.FullURL = ret.FullURL[:len(ret.FullURL)-1]
- for i := 0; i < len(m); i++ {
+ for i := range m {
m[i] = min(m[i], ret.PosEnd)
}
}
diff --git a/modules/markup/html_link.go b/modules/markup/html_link.go
index 1ea0b14028..43faef1681 100644
--- a/modules/markup/html_link.go
+++ b/modules/markup/html_link.go
@@ -31,8 +31,8 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
// It makes page handling terrible, but we prefer GitHub syntax
// And fall back to MediaWiki only when it is obvious from the look
// Of text and link contents
- sl := strings.Split(content, "|")
- for _, v := range sl {
+ sl := strings.SplitSeq(content, "|")
+ for v := range sl {
if equalPos := strings.IndexByte(v, '='); equalPos == -1 {
// There is no equal in this argument; this is a mandatory arg
if props["name"] == "" {
diff --git a/modules/markup/html_node.go b/modules/markup/html_node.go
index f67437465c..4eb78fdd2b 100644
--- a/modules/markup/html_node.go
+++ b/modules/markup/html_node.go
@@ -63,8 +63,11 @@ func processNodeA(ctx *RenderContext, node *html.Node) {
func visitNodeImg(ctx *RenderContext, img *html.Node) (next *html.Node) {
next = img.NextSibling
+ attrSrc, hasLazy := "", false
for i, imgAttr := range img.Attr {
+ hasLazy = hasLazy || imgAttr.Key == "loading" && imgAttr.Val == "lazy"
if imgAttr.Key != "src" {
+ attrSrc = imgAttr.Val
continue
}
@@ -72,8 +75,8 @@ func visitNodeImg(ctx *RenderContext, img *html.Node) (next *html.Node) {
isLinkable := imgSrcOrigin != "" && !strings.HasPrefix(imgSrcOrigin, "data:")
// By default, the "<img>" tag should also be clickable,
- // because frontend use `<img>` to paste the re-scaled image into the markdown,
- // so it must match the default markdown image behavior.
+ // because frontend uses `<img>` to paste the re-scaled image into the Markdown,
+ // so it must match the default Markdown image behavior.
cnt := 0
for p := img.Parent; isLinkable && p != nil && cnt < 2; p = p.Parent {
if hasParentAnchor := p.Type == html.ElementNode && p.Data == "a"; hasParentAnchor {
@@ -98,6 +101,9 @@ func visitNodeImg(ctx *RenderContext, img *html.Node) (next *html.Node) {
imgAttr.Val = camoHandleLink(imgAttr.Val)
img.Attr[i] = imgAttr
}
+ if !RenderBehaviorForTesting.DisableAdditionalAttributes && !hasLazy && !strings.HasPrefix(attrSrc, "data:") {
+ img.Attr = append(img.Attr, html.Attribute{Key: "loading", Val: "lazy"})
+ }
return next
}
diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go
index 79df547c2c..3b788432ba 100644
--- a/modules/markup/markdown/markdown.go
+++ b/modules/markup/markdown/markdown.go
@@ -182,10 +182,7 @@ func render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
rc := &RenderConfig{Meta: markup.RenderMetaAsDetails}
buf, _ = ExtractMetadataBytes(buf, rc)
- metaLength := bufWithMetadataLength - len(buf)
- if metaLength < 0 {
- metaLength = 0
- }
+ metaLength := max(bufWithMetadataLength-len(buf), 0)
rc.metaLength = metaLength
pc.Set(renderConfigKey, rc)
diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go
index 99f590c950..4eb01bcc2d 100644
--- a/modules/markup/markdown/markdown_test.go
+++ b/modules/markup/markdown/markdown_test.go
@@ -47,7 +47,7 @@ func TestRender_StandardLinks(t *testing.T) {
func TestRender_Images(t *testing.T) {
setting.AppURL = AppURL
- test := func(input, expected string) {
+ render := func(input, expected string) {
buffer, err := markdown.RenderString(markup.NewTestRenderContext(FullURL), input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
@@ -59,27 +59,32 @@ func TestRender_Images(t *testing.T) {
result := util.URLJoin(FullURL, url)
// hint: With Markdown v2.5.2, there is a new syntax: [link](URL){:target="_blank"} , but we do not support it now
- test(
+ render(
"!["+title+"]("+url+")",
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
- test(
+ render(
"[["+title+"|"+url+"]]",
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
- test(
+ render(
"[!["+title+"]("+url+")]("+href+")",
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
- test(
+ render(
"!["+title+"]("+url+")",
`<p><a href="`+result+`" target="_blank" rel="nofollow noopener"><img src="`+result+`" alt="`+title+`"/></a></p>`)
- test(
+ render(
"[["+title+"|"+url+"]]",
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
- test(
+ render(
"[!["+title+"]("+url+")]("+href+")",
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
+
+ defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, false)()
+ render(
+ "<a><img src='a.jpg'></a>", // by the way, empty "a" tag will be removed
+ `<p dir="auto"><img src="http://localhost:3000/user13/repo11/a.jpg" loading="lazy"/></p>`)
}
func TestTotal_RenderString(t *testing.T) {
@@ -252,7 +257,7 @@ This PR has been generated by [Renovate Bot](https://github.com/renovatebot/reno
return username == "r-lyeh"
},
})
- for i := 0; i < len(sameCases); i++ {
+ for i := range sameCases {
line, err := markdown.RenderString(markup.NewTestRenderContext(localMetas), sameCases[i])
assert.NoError(t, err)
assert.Equal(t, testAnswers[i], string(line))
diff --git a/modules/markup/markdown/math/block_renderer.go b/modules/markup/markdown/math/block_renderer.go
index 412e4d0dee..427ed842ec 100644
--- a/modules/markup/markdown/math/block_renderer.go
+++ b/modules/markup/markdown/math/block_renderer.go
@@ -42,7 +42,7 @@ func (r *BlockRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
func (r *BlockRenderer) writeLines(w util.BufWriter, source []byte, n gast.Node) {
l := n.Lines().Len()
- for i := 0; i < l; i++ {
+ for i := range l {
line := n.Lines().At(i)
_, _ = w.Write(util.EscapeHTML(line.Value(source)))
}
diff --git a/modules/markup/markdown/meta_test.go b/modules/markup/markdown/meta_test.go
index 3f74adeaef..283d289d48 100644
--- a/modules/markup/markdown/meta_test.go
+++ b/modules/markup/markdown/meta_test.go
@@ -60,7 +60,7 @@ func TestExtractMetadata(t *testing.T) {
func TestExtractMetadataBytes(t *testing.T) {
t.Run("ValidFrontAndBody", func(t *testing.T) {
var meta IssueTemplate
- body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)), &meta)
+ body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
assert.NoError(t, err)
assert.Equal(t, bodyTest, string(body))
assert.Equal(t, metaTest, meta)
@@ -69,19 +69,19 @@ func TestExtractMetadataBytes(t *testing.T) {
t.Run("NoFirstSeparator", func(t *testing.T) {
var meta IssueTemplate
- _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest)), &meta)
+ _, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoLastSeparator", func(t *testing.T) {
var meta IssueTemplate
- _, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest)), &meta)
+ _, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoBody", func(t *testing.T) {
var meta IssueTemplate
- body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest)), &meta)
+ body, err := ExtractMetadataBytes(fmt.Appendf(nil, "%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
assert.NoError(t, err)
assert.Empty(t, string(body))
assert.Equal(t, metaTest, meta)
diff --git a/modules/markup/markdown/transform_heading.go b/modules/markup/markdown/transform_heading.go
index 5f8a12794d..cac3cd6617 100644
--- a/modules/markup/markdown/transform_heading.go
+++ b/modules/markup/markdown/transform_heading.go
@@ -16,7 +16,7 @@ import (
func (g *ASTTransformer) transformHeading(_ *markup.RenderContext, v *ast.Heading, reader text.Reader, tocList *[]Header) {
for _, attr := range v.Attributes() {
if _, ok := attr.Value.([]byte); !ok {
- v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value)))
+ v.SetAttribute(attr.Name, fmt.Appendf(nil, "%v", attr.Value))
}
}
txt := v.Text(reader.Source()) //nolint:staticcheck
diff --git a/modules/markup/sanitizer_default.go b/modules/markup/sanitizer_default.go
index 14161eb533..9288be3b28 100644
--- a/modules/markup/sanitizer_default.go
+++ b/modules/markup/sanitizer_default.go
@@ -52,6 +52,8 @@ func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy {
policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
+ policy.AllowAttrs("loading").OnElements("img")
+
// Allow generally safe attributes (reference: https://github.com/jch/html-pipeline)
generalSafeAttrs := []string{
"abbr", "accept", "accept-charset",