mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Refactor some Str2html code (#29397)
This PR touches the most interesting part of the "template refactoring".
1. Unclear variable type. Especially for "web/feed/convert.go":
sometimes it uses text, sometimes it uses HTML.
2. Assign text content to "RenderedContent" field, for example: `
project.RenderedContent = project.Description` in web/org/projects.go
3. Assign rendered content to text field, for example: `r.Note =
rendered content` in web/repo/release.go
4. (possible) Incorrectly calling `{{Str2html
.PackageDescriptor.Metadata.ReleaseNotes}}` in
package/content/nuget.tmpl, I guess the name Str2html misleads
developers to use it to "render string to html", but it only sanitizes.
if ReleaseNotes really contains HTML, then this is not a problem.
			
			
This commit is contained in:
		@@ -8,6 +8,7 @@ package issues
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"unicode/utf8"
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,8 +260,8 @@ type Comment struct {
 | 
				
			|||||||
	CommitID        int64
 | 
						CommitID        int64
 | 
				
			||||||
	Line            int64 // - previous line / + proposed line
 | 
						Line            int64 // - previous line / + proposed line
 | 
				
			||||||
	TreePath        string
 | 
						TreePath        string
 | 
				
			||||||
	Content         string `xorm:"LONGTEXT"`
 | 
						Content         string        `xorm:"LONGTEXT"`
 | 
				
			||||||
	RenderedContent string `xorm:"-"`
 | 
						RenderedContent template.HTML `xorm:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Path represents the 4 lines of code cemented by this comment
 | 
						// Path represents the 4 lines of code cemented by this comment
 | 
				
			||||||
	Patch       string `xorm:"-"`
 | 
						Patch       string `xorm:"-"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package issues
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"slices"
 | 
						"slices"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -105,7 +106,7 @@ type Issue struct {
 | 
				
			|||||||
	OriginalAuthorID int64                  `xorm:"index"`
 | 
						OriginalAuthorID int64                  `xorm:"index"`
 | 
				
			||||||
	Title            string                 `xorm:"name"`
 | 
						Title            string                 `xorm:"name"`
 | 
				
			||||||
	Content          string                 `xorm:"LONGTEXT"`
 | 
						Content          string                 `xorm:"LONGTEXT"`
 | 
				
			||||||
	RenderedContent  string                 `xorm:"-"`
 | 
						RenderedContent  template.HTML          `xorm:"-"`
 | 
				
			||||||
	Labels           []*Label               `xorm:"-"`
 | 
						Labels           []*Label               `xorm:"-"`
 | 
				
			||||||
	MilestoneID      int64                  `xorm:"INDEX"`
 | 
						MilestoneID      int64                  `xorm:"INDEX"`
 | 
				
			||||||
	Milestone        *Milestone             `xorm:"-"`
 | 
						Milestone        *Milestone             `xorm:"-"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package issues
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
@@ -47,8 +48,8 @@ type Milestone struct {
 | 
				
			|||||||
	RepoID          int64                  `xorm:"INDEX"`
 | 
						RepoID          int64                  `xorm:"INDEX"`
 | 
				
			||||||
	Repo            *repo_model.Repository `xorm:"-"`
 | 
						Repo            *repo_model.Repository `xorm:"-"`
 | 
				
			||||||
	Name            string
 | 
						Name            string
 | 
				
			||||||
	Content         string `xorm:"TEXT"`
 | 
						Content         string        `xorm:"TEXT"`
 | 
				
			||||||
	RenderedContent string `xorm:"-"`
 | 
						RenderedContent template.HTML `xorm:"-"`
 | 
				
			||||||
	IsClosed        bool
 | 
						IsClosed        bool
 | 
				
			||||||
	NumIssues       int
 | 
						NumIssues       int
 | 
				
			||||||
	NumClosedIssues int
 | 
						NumClosedIssues int
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package project
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
@@ -100,7 +101,7 @@ type Project struct {
 | 
				
			|||||||
	CardType    CardType
 | 
						CardType    CardType
 | 
				
			||||||
	Type        Type
 | 
						Type        Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RenderedContent string `xorm:"-"`
 | 
						RenderedContent template.HTML `xorm:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CreatedUnix    timeutil.TimeStamp `xorm:"INDEX created"`
 | 
						CreatedUnix    timeutil.TimeStamp `xorm:"INDEX created"`
 | 
				
			||||||
	UpdatedUnix    timeutil.TimeStamp `xorm:"INDEX updated"`
 | 
						UpdatedUnix    timeutil.TimeStamp `xorm:"INDEX updated"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package repo
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -80,7 +81,7 @@ type Release struct {
 | 
				
			|||||||
	NumCommits       int64
 | 
						NumCommits       int64
 | 
				
			||||||
	NumCommitsBehind int64              `xorm:"-"`
 | 
						NumCommitsBehind int64              `xorm:"-"`
 | 
				
			||||||
	Note             string             `xorm:"TEXT"`
 | 
						Note             string             `xorm:"TEXT"`
 | 
				
			||||||
	RenderedNote     string             `xorm:"-"`
 | 
						RenderedNote     template.HTML      `xorm:"-"`
 | 
				
			||||||
	IsDraft          bool               `xorm:"NOT NULL DEFAULT false"`
 | 
						IsDraft          bool               `xorm:"NOT NULL DEFAULT false"`
 | 
				
			||||||
	IsPrerelease     bool               `xorm:"NOT NULL DEFAULT false"`
 | 
						IsPrerelease     bool               `xorm:"NOT NULL DEFAULT false"`
 | 
				
			||||||
	IsTag            bool               `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
 | 
						IsTag            bool               `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -397,7 +397,7 @@ func TestRender_ShortLinks(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
		buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
							buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
				
			||||||
			Ctx: git.DefaultContext,
 | 
								Ctx: git.DefaultContext,
 | 
				
			||||||
			Links: markup.Links{
 | 
								Links: markup.Links{
 | 
				
			||||||
@@ -407,7 +407,7 @@ func TestRender_ShortLinks(t *testing.T) {
 | 
				
			|||||||
			IsWiki: true,
 | 
								IsWiki: true,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mediatree := util.URLJoin(markup.TestRepoURL, "media", "master")
 | 
						mediatree := util.URLJoin(markup.TestRepoURL, "media", "master")
 | 
				
			||||||
@@ -510,7 +510,7 @@ func TestRender_RelativeImages(t *testing.T) {
 | 
				
			|||||||
			Metas: localMetas,
 | 
								Metas: localMetas,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
		buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
							buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
				
			||||||
			Ctx: git.DefaultContext,
 | 
								Ctx: git.DefaultContext,
 | 
				
			||||||
			Links: markup.Links{
 | 
								Links: markup.Links{
 | 
				
			||||||
@@ -520,7 +520,7 @@ func TestRender_RelativeImages(t *testing.T) {
 | 
				
			|||||||
			IsWiki: true,
 | 
								IsWiki: true,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw")
 | 
						rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package markdown
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -262,12 +263,12 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RenderString renders Markdown string to HTML with all specific handling stuff and return string
 | 
					// RenderString renders Markdown string to HTML with all specific handling stuff and return string
 | 
				
			||||||
func RenderString(ctx *markup.RenderContext, content string) (string, error) {
 | 
					func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) {
 | 
				
			||||||
	var buf strings.Builder
 | 
						var buf strings.Builder
 | 
				
			||||||
	if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
 | 
						if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return buf.String(), nil
 | 
						return template.HTML(buf.String()), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RenderRaw renders Markdown to HTML without handling special links.
 | 
					// RenderRaw renders Markdown to HTML without handling special links.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ package markdown_test
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
@@ -56,7 +57,7 @@ func TestRender_StandardLinks(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
							buffer, err = markdown.RenderString(&markup.RenderContext{
 | 
				
			||||||
			Ctx: git.DefaultContext,
 | 
								Ctx: git.DefaultContext,
 | 
				
			||||||
@@ -66,7 +67,7 @@ func TestRender_StandardLinks(t *testing.T) {
 | 
				
			|||||||
			IsWiki: true,
 | 
								IsWiki: true,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	googleRendered := `<p><a href="https://google.com/" rel="nofollow">https://google.com/</a></p>`
 | 
						googleRendered := `<p><a href="https://google.com/" rel="nofollow">https://google.com/</a></p>`
 | 
				
			||||||
@@ -90,7 +91,7 @@ func TestRender_Images(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	url := "../../.images/src/02/train.jpg"
 | 
						url := "../../.images/src/02/train.jpg"
 | 
				
			||||||
@@ -299,7 +300,7 @@ func TestTotal_RenderWiki(t *testing.T) {
 | 
				
			|||||||
			IsWiki: true,
 | 
								IsWiki: true,
 | 
				
			||||||
		}, sameCases[i])
 | 
							}, sameCases[i])
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, answers[i], line)
 | 
							assert.Equal(t, template.HTML(answers[i]), line)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testCases := []string{
 | 
						testCases := []string{
 | 
				
			||||||
@@ -324,7 +325,7 @@ func TestTotal_RenderWiki(t *testing.T) {
 | 
				
			|||||||
			IsWiki: true,
 | 
								IsWiki: true,
 | 
				
			||||||
		}, testCases[i])
 | 
							}, testCases[i])
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, testCases[i+1], line)
 | 
							assert.Equal(t, template.HTML(testCases[i+1]), line)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -343,7 +344,7 @@ func TestTotal_RenderString(t *testing.T) {
 | 
				
			|||||||
			Metas: localMetas,
 | 
								Metas: localMetas,
 | 
				
			||||||
		}, sameCases[i])
 | 
							}, sameCases[i])
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, answers[i], line)
 | 
							assert.Equal(t, template.HTML(answers[i]), line)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testCases := []string{}
 | 
						testCases := []string{}
 | 
				
			||||||
@@ -356,7 +357,7 @@ func TestTotal_RenderString(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, testCases[i])
 | 
							}, testCases[i])
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, testCases[i+1], line)
 | 
							assert.Equal(t, template.HTML(testCases[i+1]), line)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -423,7 +424,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) {
 | 
				
			|||||||
`
 | 
					`
 | 
				
			||||||
	res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
 | 
						res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, expected, res)
 | 
						assert.Equal(t, template.HTML(expected), res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestColorPreview(t *testing.T) {
 | 
					func TestColorPreview(t *testing.T) {
 | 
				
			||||||
@@ -457,7 +458,7 @@ func TestColorPreview(t *testing.T) {
 | 
				
			|||||||
	for _, test := range positiveTests {
 | 
						for _, test := range positiveTests {
 | 
				
			||||||
		res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
							res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
				
			||||||
		assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
							assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -524,7 +525,7 @@ func TestMathBlock(t *testing.T) {
 | 
				
			|||||||
	for _, test := range testcases {
 | 
						for _, test := range testcases {
 | 
				
			||||||
		res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
							res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
				
			||||||
		assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
							assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -562,12 +563,12 @@ foo: bar
 | 
				
			|||||||
	for _, test := range testcases {
 | 
						for _, test := range testcases {
 | 
				
			||||||
		res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
							res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
				
			||||||
		assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
							assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRenderLinks(t *testing.T) {
 | 
					func TestRenderLinks(t *testing.T) {
 | 
				
			||||||
	input := `  space @mention-user  
 | 
						input := `  space @mention-user${SPACE}${SPACE}
 | 
				
			||||||
/just/a/path.bin
 | 
					/just/a/path.bin
 | 
				
			||||||
https://example.com/file.bin
 | 
					https://example.com/file.bin
 | 
				
			||||||
[local link](file.bin)
 | 
					[local link](file.bin)
 | 
				
			||||||
@@ -588,8 +589,9 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
 | 
				
			|||||||
mail@domain.com
 | 
					mail@domain.com
 | 
				
			||||||
@mention-user test
 | 
					@mention-user test
 | 
				
			||||||
#123
 | 
					#123
 | 
				
			||||||
  space  
 | 
					  space${SPACE}${SPACE}
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
						input = strings.ReplaceAll(input, "${SPACE}", " ") // replace ${SPACE} with " ", to avoid some editor's auto-trimming
 | 
				
			||||||
	cases := []struct {
 | 
						cases := []struct {
 | 
				
			||||||
		Links    markup.Links
 | 
							Links    markup.Links
 | 
				
			||||||
		IsWiki   bool
 | 
							IsWiki   bool
 | 
				
			||||||
@@ -952,6 +954,6 @@ space</p>
 | 
				
			|||||||
	for i, c := range cases {
 | 
						for i, c := range cases {
 | 
				
			||||||
		result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input)
 | 
							result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %v", i)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %v", i)
 | 
				
			||||||
		assert.Equal(t, c.Expected, result, "Unexpected result in testcase %v", i)
 | 
							assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -208,7 +208,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("RenderString: %v", err)
 | 
							log.Error("RenderString: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return template.HTML(output)
 | 
						return output
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML {
 | 
					func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
package templates
 | 
					package templates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
@@ -17,6 +19,19 @@ func NewStringUtils() *StringUtils {
 | 
				
			|||||||
	return &stringUtils
 | 
						return &stringUtils
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (su *StringUtils) ToString(v any) string {
 | 
				
			||||||
 | 
						switch v := v.(type) {
 | 
				
			||||||
 | 
						case string:
 | 
				
			||||||
 | 
							return v
 | 
				
			||||||
 | 
						case template.HTML:
 | 
				
			||||||
 | 
							return string(v)
 | 
				
			||||||
 | 
						case fmt.Stringer:
 | 
				
			||||||
 | 
							return v.String()
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Sprint(v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (su *StringUtils) HasPrefix(s, prefix string) bool {
 | 
					func (su *StringUtils) HasPrefix(s, prefix string) bool {
 | 
				
			||||||
	return strings.HasPrefix(s, prefix)
 | 
						return strings.HasPrefix(s, prefix)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ func toReleaseLink(ctx *context.Context, act *activities_model.Action) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// renderMarkdown creates a minimal markdown render context from an action.
 | 
					// renderMarkdown creates a minimal markdown render context from an action.
 | 
				
			||||||
// If rendering fails, the original markdown text is returned
 | 
					// If rendering fails, the original markdown text is returned
 | 
				
			||||||
func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) string {
 | 
					func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) template.HTML {
 | 
				
			||||||
	markdownCtx := &markup.RenderContext{
 | 
						markdownCtx := &markup.RenderContext{
 | 
				
			||||||
		Ctx: ctx,
 | 
							Ctx: ctx,
 | 
				
			||||||
		Links: markup.Links{
 | 
							Links: markup.Links{
 | 
				
			||||||
@@ -64,7 +64,7 @@ func renderMarkdown(ctx *context.Context, act *activities_model.Action, content
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	markdown, err := markdown.RenderString(markdownCtx, content)
 | 
						markdown, err := markdown.RenderString(markdownCtx, content)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return content
 | 
							return templates.Str2html(content) // old code did so: use Str2html to render in tmpl
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return markdown
 | 
						return markdown
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -74,7 +74,11 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
 | 
				
			|||||||
	for _, act := range actions {
 | 
						for _, act := range actions {
 | 
				
			||||||
		act.LoadActUser(ctx)
 | 
							act.LoadActUser(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var content, desc, title string
 | 
							// TODO: the code seems quite strange (maybe not right)
 | 
				
			||||||
 | 
							// sometimes it uses text content but sometimes it uses HTML content
 | 
				
			||||||
 | 
							// it should clearly defines which kind of content it should use for the feed items: plan text or rich HTML
 | 
				
			||||||
 | 
							var title, desc string
 | 
				
			||||||
 | 
							var content template.HTML
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)}
 | 
							link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,7 +232,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
 | 
				
			|||||||
				desc = act.GetIssueTitle(ctx)
 | 
									desc = act.GetIssueTitle(ctx)
 | 
				
			||||||
				comment := act.GetIssueInfos()[1]
 | 
									comment := act.GetIssueInfos()[1]
 | 
				
			||||||
				if len(comment) != 0 {
 | 
									if len(comment) != 0 {
 | 
				
			||||||
					desc += "\n\n" + renderMarkdown(ctx, act, comment)
 | 
										desc += "\n\n" + string(renderMarkdown(ctx, act, comment))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest:
 | 
								case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest:
 | 
				
			||||||
				desc = act.GetIssueInfos()[1]
 | 
									desc = act.GetIssueInfos()[1]
 | 
				
			||||||
@@ -239,7 +243,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if len(content) == 0 {
 | 
							if len(content) == 0 {
 | 
				
			||||||
			content = desc
 | 
								content = templates.Str2html(desc)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		items = append(items, &feeds.Item{
 | 
							items = append(items, &feeds.Item{
 | 
				
			||||||
@@ -253,7 +257,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			Id:      fmt.Sprintf("%v: %v", strconv.FormatInt(act.ID, 10), link.Href),
 | 
								Id:      fmt.Sprintf("%v: %v", strconv.FormatInt(act.ID, 10), link.Href),
 | 
				
			||||||
			Created: act.CreatedUnix.AsTime(),
 | 
								Created: act.CreatedUnix.AsTime(),
 | 
				
			||||||
			Content: content,
 | 
								Content: string(content),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return items, err
 | 
						return items, err
 | 
				
			||||||
@@ -282,7 +286,8 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, i
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var title, content string
 | 
							var title string
 | 
				
			||||||
 | 
							var content template.HTML
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if rel.IsTag {
 | 
							if rel.IsTag {
 | 
				
			||||||
			title = rel.TagName
 | 
								title = rel.TagName
 | 
				
			||||||
@@ -311,7 +316,7 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, i
 | 
				
			|||||||
				Email: rel.Publisher.GetEmail(),
 | 
									Email: rel.Publisher.GetEmail(),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Id:      fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href),
 | 
								Id:      fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href),
 | 
				
			||||||
			Content: content,
 | 
								Content: string(content),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@ func showUserFeed(ctx *context.Context, formatType string) {
 | 
				
			|||||||
	feed := &feeds.Feed{
 | 
						feed := &feeds.Feed{
 | 
				
			||||||
		Title:       ctx.Locale.TrString("home.feed_of", ctx.ContextUser.DisplayName()),
 | 
							Title:       ctx.Locale.TrString("home.feed_of", ctx.ContextUser.DisplayName()),
 | 
				
			||||||
		Link:        &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
 | 
							Link:        &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
 | 
				
			||||||
		Description: ctxUserDescription,
 | 
							Description: string(ctxUserDescription),
 | 
				
			||||||
		Created:     time.Now(),
 | 
							Created:     time.Now(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/json"
 | 
						"code.gitea.io/gitea/modules/json"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/templates"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web"
 | 
						"code.gitea.io/gitea/modules/web"
 | 
				
			||||||
	shared_user "code.gitea.io/gitea/routers/web/shared/user"
 | 
						shared_user "code.gitea.io/gitea/routers/web/shared/user"
 | 
				
			||||||
@@ -104,7 +105,7 @@ func Projects(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, project := range projects {
 | 
						for _, project := range projects {
 | 
				
			||||||
		project.RenderedContent = project.Description
 | 
							project.RenderedContent = templates.Str2html(project.Description) // FIXME: is it right? why not render?
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = shared_user.LoadHeaderCount(ctx)
 | 
						err = shared_user.LoadHeaderCount(ctx)
 | 
				
			||||||
@@ -395,7 +396,7 @@ func ViewProject(ctx *context.Context) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	project.RenderedContent = project.Description
 | 
						project.RenderedContent = templates.Str2html(project.Description) // FIXME: is it right? why not render?
 | 
				
			||||||
	ctx.Data["LinkedPRs"] = linkedPrsMap
 | 
						ctx.Data["LinkedPRs"] = linkedPrsMap
 | 
				
			||||||
	ctx.Data["PageIsViewProjects"] = true
 | 
						ctx.Data["PageIsViewProjects"] = true
 | 
				
			||||||
	ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
 | 
						ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ import (
 | 
				
			|||||||
	repo_module "code.gitea.io/gitea/modules/repository"
 | 
						repo_module "code.gitea.io/gitea/modules/repository"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/templates"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/templates/vars"
 | 
						"code.gitea.io/gitea/modules/templates/vars"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
						"code.gitea.io/gitea/modules/timeutil"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
@@ -1760,7 +1761,7 @@ func ViewIssue(ctx *context.Context) {
 | 
				
			|||||||
				// so "|" is used as delimeter to mark the new format
 | 
									// so "|" is used as delimeter to mark the new format
 | 
				
			||||||
				if comment.Content[0] != '|' {
 | 
									if comment.Content[0] != '|' {
 | 
				
			||||||
					// handle old time comments that have formatted text stored
 | 
										// handle old time comments that have formatted text stored
 | 
				
			||||||
					comment.RenderedContent = comment.Content
 | 
										comment.RenderedContent = templates.Str2html(comment.Content)
 | 
				
			||||||
					comment.Content = ""
 | 
										comment.Content = ""
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					// else it's just a duration in seconds to pass on to the frontend
 | 
										// else it's just a duration in seconds to pass on to the frontend
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,7 +113,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
 | 
				
			|||||||
			cacheUsers[r.PublisherID] = r.Publisher
 | 
								cacheUsers[r.PublisherID] = r.Publisher
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		r.Note, err = markdown.RenderString(&markup.RenderContext{
 | 
							r.RenderedNote, err = markdown.RenderString(&markup.RenderContext{
 | 
				
			||||||
			Links: markup.Links{
 | 
								Links: markup.Links{
 | 
				
			||||||
				Base: ctx.Repo.RepoLink,
 | 
									Base: ctx.Repo.RepoLink,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
		{{.locale.Tr "mail.release.note"}}<br>
 | 
							{{.locale.Tr "mail.release.note"}}<br>
 | 
				
			||||||
		{{- if eq .Release.RenderedNote ""}}
 | 
							{{- if eq .Release.RenderedNote ""}}
 | 
				
			||||||
		{{else}}
 | 
							{{else}}
 | 
				
			||||||
			{{.Release.RenderedNote | Str2html}}
 | 
								{{.Release.RenderedNote}}
 | 
				
			||||||
		{{end -}}
 | 
							{{end -}}
 | 
				
			||||||
	</p>
 | 
						</p>
 | 
				
			||||||
	<br><br>
 | 
						<br><br>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@
 | 
				
			|||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
			</span>
 | 
								</span>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		{{if .RenderedDescription}}<div class="render-content markup">{{.RenderedDescription | Str2html}}</div>{{end}}
 | 
							{{if .RenderedDescription}}<div class="render-content markup">{{.RenderedDescription}}</div>{{end}}
 | 
				
			||||||
		<div class="text light meta gt-mt-2">
 | 
							<div class="text light meta gt-mt-2">
 | 
				
			||||||
			{{if .Org.Location}}<div class="flex-text-block">{{svg "octicon-location"}} <span>{{.Org.Location}}</span></div>{{end}}
 | 
								{{if .Org.Location}}<div class="flex-text-block">{{svg "octicon-location"}} <span>{{.Org.Location}}</span></div>{{end}}
 | 
				
			||||||
			{{if .Org.Website}}<div class="flex-text-block">{{svg "octicon-link"}} <a class="muted" target="_blank" rel="noopener noreferrer me" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}}
 | 
								{{if .Org.Website}}<div class="flex-text-block">{{svg "octicon-link"}} <a class="muted" target="_blank" rel="noopener noreferrer me" href="{{.Org.Website}}">{{.Org.Website}}</a></div>{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
		<div class="ui mobile reversed stackable grid">
 | 
							<div class="ui mobile reversed stackable grid">
 | 
				
			||||||
			<div class="ui {{if .ShowMemberAndTeamTab}}eleven wide{{end}} column">
 | 
								<div class="ui {{if .ShowMemberAndTeamTab}}eleven wide{{end}} column">
 | 
				
			||||||
				{{if .ProfileReadme}}
 | 
									{{if .ProfileReadme}}
 | 
				
			||||||
					<div id="readme_profile" class="markup">{{.ProfileReadme | Str2html}}</div>
 | 
										<div id="readme_profile" class="markup">{{.ProfileReadme}}</div>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				{{template "explore/repo_search" .}}
 | 
									{{template "explore/repo_search" .}}
 | 
				
			||||||
				{{template "explore/repo_list" .}}
 | 
									{{template "explore/repo_list" .}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@
 | 
				
			|||||||
		<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.about"}}</h4>
 | 
							<h4 class="ui top attached header">{{ctx.Locale.Tr "packages.about"}}</h4>
 | 
				
			||||||
		<div class="ui attached segment">
 | 
							<div class="ui attached segment">
 | 
				
			||||||
			{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}}
 | 
								{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}}
 | 
				
			||||||
			{{if .PackageDescriptor.Metadata.ReleaseNotes}}{{Str2html .PackageDescriptor.Metadata.ReleaseNotes}}{{end}}
 | 
								{{if .PackageDescriptor.Metadata.ReleaseNotes}}{{.PackageDescriptor.Metadata.ReleaseNotes}}{{end}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	{{end}}
 | 
						{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,7 +75,7 @@
 | 
				
			|||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			{{if .Description}}
 | 
								{{if .Description}}
 | 
				
			||||||
			<div class="content">
 | 
								<div class="content">
 | 
				
			||||||
				{{.RenderedContent|Str2html}}
 | 
									{{.RenderedContent}}
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</li>
 | 
							</li>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
		{{end}}
 | 
							{{end}}
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<div class="content">{{$.Project.RenderedContent|Str2html}}</div>
 | 
						<div class="content">{{$.Project.RenderedContent}}</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<div class="divider"></div>
 | 
						<div class="divider"></div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@
 | 
				
			|||||||
		<div class="ui attached segment comment-body">
 | 
							<div class="ui attached segment comment-body">
 | 
				
			||||||
			<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
								<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
				
			||||||
			{{if .RenderedContent}}
 | 
								{{if .RenderedContent}}
 | 
				
			||||||
				{{.RenderedContent|Str2html}}
 | 
									{{.RenderedContent}}
 | 
				
			||||||
			{{else}}
 | 
								{{else}}
 | 
				
			||||||
				<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
									<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		{{if .Milestone.RenderedContent}}
 | 
							{{if .Milestone.RenderedContent}}
 | 
				
			||||||
		<div class="markup content gt-mb-4">
 | 
							<div class="markup content gt-mb-4">
 | 
				
			||||||
				{{.Milestone.RenderedContent|Str2html}}
 | 
									{{.Milestone.RenderedContent}}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		{{end}}
 | 
							{{end}}
 | 
				
			||||||
		<div class="gt-df gt-fc gt-gap-3">
 | 
							<div class="gt-df gt-fc gt-gap-3">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,7 @@
 | 
				
			|||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					{{if .Content}}
 | 
										{{if .Content}}
 | 
				
			||||||
						<div class="markup content">
 | 
											<div class="markup content">
 | 
				
			||||||
							{{.RenderedContent|Str2html}}
 | 
												{{.RenderedContent}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
				</li>
 | 
									</li>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@
 | 
				
			|||||||
					<div class="ui attached segment comment-body" role="article">
 | 
										<div class="ui attached segment comment-body" role="article">
 | 
				
			||||||
						<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission $.IsIssuePoster}}data-can-edit="true"{{end}}>
 | 
											<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission $.IsIssuePoster}}data-can-edit="true"{{end}}>
 | 
				
			||||||
							{{if .Issue.RenderedContent}}
 | 
												{{if .Issue.RenderedContent}}
 | 
				
			||||||
								{{.Issue.RenderedContent|Str2html}}
 | 
													{{.Issue.RenderedContent}}
 | 
				
			||||||
							{{else}}
 | 
												{{else}}
 | 
				
			||||||
								<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
													<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
			<div class="gt-f1 gt-p-3">
 | 
								<div class="gt-f1 gt-p-3">
 | 
				
			||||||
				<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}" title="{{ctx.Locale.Tr "repo.issues.attachment.open_tab" .Name}}">
 | 
									<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}" title="{{ctx.Locale.Tr "repo.issues.attachment.open_tab" .Name}}">
 | 
				
			||||||
					{{if FilenameIsImage .Name}}
 | 
										{{if FilenameIsImage .Name}}
 | 
				
			||||||
						{{if not (StringUtils.Contains $.Content .UUID)}}
 | 
											{{if not (StringUtils.Contains (StringUtils.ToString $.Content) .UUID)}}
 | 
				
			||||||
							{{$hasThumbnails = true}}
 | 
												{{$hasThumbnails = true}}
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{svg "octicon-file"}}
 | 
											{{svg "octicon-file"}}
 | 
				
			||||||
@@ -29,7 +29,7 @@
 | 
				
			|||||||
		<div class="ui small thumbnails">
 | 
							<div class="ui small thumbnails">
 | 
				
			||||||
			{{- range .Attachments -}}
 | 
								{{- range .Attachments -}}
 | 
				
			||||||
				{{if FilenameIsImage .Name}}
 | 
									{{if FilenameIsImage .Name}}
 | 
				
			||||||
					{{if not (StringUtils.Contains $.Content .UUID)}}
 | 
										{{if not (StringUtils.Contains (StringUtils.ToString $.Content) .UUID)}}
 | 
				
			||||||
					<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}">
 | 
										<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}">
 | 
				
			||||||
						<img alt="{{.Name}}" src="{{.DownloadURL}}" title="{{ctx.Locale.Tr "repo.issues.attachment.open_tab" .Name}}">
 | 
											<img alt="{{.Name}}" src="{{.DownloadURL}}" title="{{ctx.Locale.Tr "repo.issues.attachment.open_tab" .Name}}">
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@
 | 
				
			|||||||
					<div class="ui attached segment comment-body" role="article">
 | 
										<div class="ui attached segment comment-body" role="article">
 | 
				
			||||||
						<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
											<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
				
			||||||
							{{if .RenderedContent}}
 | 
												{{if .RenderedContent}}
 | 
				
			||||||
								{{.RenderedContent|Str2html}}
 | 
													{{.RenderedContent}}
 | 
				
			||||||
							{{else}}
 | 
												{{else}}
 | 
				
			||||||
								<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
													<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
@@ -432,7 +432,7 @@
 | 
				
			|||||||
						<div class="ui attached segment comment-body">
 | 
											<div class="ui attached segment comment-body">
 | 
				
			||||||
							<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
												<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
				
			||||||
								{{if .RenderedContent}}
 | 
													{{if .RenderedContent}}
 | 
				
			||||||
									{{.RenderedContent|Str2html}}
 | 
														{{.RenderedContent}}
 | 
				
			||||||
								{{else}}
 | 
													{{else}}
 | 
				
			||||||
									<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
														<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
								{{end}}
 | 
													{{end}}
 | 
				
			||||||
@@ -631,7 +631,7 @@
 | 
				
			|||||||
							<div class="ui attached segment">
 | 
												<div class="ui attached segment">
 | 
				
			||||||
								<div class="render-content markup">
 | 
													<div class="render-content markup">
 | 
				
			||||||
									{{if .RenderedContent}}
 | 
														{{if .RenderedContent}}
 | 
				
			||||||
										{{.RenderedContent|Str2html}}
 | 
															{{.RenderedContent}}
 | 
				
			||||||
									{{else}}
 | 
														{{else}}
 | 
				
			||||||
										<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
															<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
									{{end}}
 | 
														{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,7 +87,7 @@
 | 
				
			|||||||
						<div class="text comment-content">
 | 
											<div class="text comment-content">
 | 
				
			||||||
							<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
												<div class="render-content markup" {{if or $.Permission.IsAdmin $.HasIssuesOrPullsWritePermission (and $.IsSigned (eq $.SignedUserID .PosterID))}}data-can-edit="true"{{end}}>
 | 
				
			||||||
							{{if .RenderedContent}}
 | 
												{{if .RenderedContent}}
 | 
				
			||||||
								{{.RenderedContent|Str2html}}
 | 
													{{.RenderedContent}}
 | 
				
			||||||
							{{else}}
 | 
												{{else}}
 | 
				
			||||||
								<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
													<span class="no-content">{{ctx.Locale.Tr "repo.issues.no_content"}}</span>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</p>
 | 
											</p>
 | 
				
			||||||
						<div class="markup desc">
 | 
											<div class="markup desc">
 | 
				
			||||||
							{{Str2html $release.Note}}
 | 
												{{$release.RenderedNote}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
						<div class="divider"></div>
 | 
											<div class="divider"></div>
 | 
				
			||||||
						<details class="download" {{if eq $idx 0}}open{{end}}>
 | 
											<details class="download" {{if eq $idx 0}}open{{end}}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,7 @@
 | 
				
			|||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
			{{if $.RenderedDescription}}
 | 
								{{if $.RenderedDescription}}
 | 
				
			||||||
				<li>
 | 
									<li>
 | 
				
			||||||
					<div class="render-content markup">{{$.RenderedDescription|Str2html}}</div>
 | 
										<div class="render-content markup">{{$.RenderedDescription}}</div>
 | 
				
			||||||
				</li>
 | 
									</li>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
			{{range .OpenIDs}}
 | 
								{{range .OpenIDs}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,7 +141,7 @@
 | 
				
			|||||||
							</div>
 | 
												</div>
 | 
				
			||||||
							{{if .Content}}
 | 
												{{if .Content}}
 | 
				
			||||||
								<div class="markup content">
 | 
													<div class="markup content">
 | 
				
			||||||
									{{.RenderedContent|Str2html}}
 | 
														{{.RenderedContent}}
 | 
				
			||||||
								</div>
 | 
													</div>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</li>
 | 
											</li>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@
 | 
				
			|||||||
				{{else if eq .TabName "followers"}}
 | 
									{{else if eq .TabName "followers"}}
 | 
				
			||||||
					{{template "repo/user_cards" .}}
 | 
										{{template "repo/user_cards" .}}
 | 
				
			||||||
				{{else if eq .TabName "overview"}}
 | 
									{{else if eq .TabName "overview"}}
 | 
				
			||||||
					<div id="readme_profile" class="markup">{{.ProfileReadme | Str2html}}</div>
 | 
										<div id="readme_profile" class="markup">{{.ProfileReadme}}</div>
 | 
				
			||||||
				{{else}}
 | 
									{{else}}
 | 
				
			||||||
					{{template "explore/repo_search" .}}
 | 
										{{template "explore/repo_search" .}}
 | 
				
			||||||
					{{template "explore/repo_list" .}}
 | 
										{{template "explore/repo_list" .}}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user