mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	Add context when rendering labels or emojis (#23281)
This branch continues the work of #23092 and attempts to rid the codebase of any `nil` contexts when using a `RenderContext`. Anything that renders markdown or does post processing may call `markup.sha1CurrentPatternProcessor()`, and this runs `git.OpenRepository()`, which needs a context. It will panic if the context is `nil`. This branch attempts to _always_ include a context when creating a `RenderContext` to prevent future crashes. Co-authored-by: Kyle D <kdumontnu@gmail.com>
This commit is contained in:
		| @@ -11,6 +11,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/markup" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -229,7 +230,10 @@ John Doe	john@doe.com	This,note,had,a,lot,of,commas,to,test,delimiters`, | ||||
| 	} | ||||
|  | ||||
| 	for n, c := range cases { | ||||
| 		delimiter := determineDelimiter(&markup.RenderContext{RelativePath: c.filename}, []byte(decodeSlashes(t, c.csv))) | ||||
| 		delimiter := determineDelimiter(&markup.RenderContext{ | ||||
| 			Ctx:          git.DefaultContext, | ||||
| 			RelativePath: c.filename, | ||||
| 		}, []byte(decodeSlashes(t, c.csv))) | ||||
| 		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/markup" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -23,7 +24,8 @@ func TestRenderConsole(t *testing.T) { | ||||
| 		canRender := render.CanRender("test", strings.NewReader(k)) | ||||
| 		assert.True(t, canRender) | ||||
|  | ||||
| 		err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf) | ||||
| 		err := render.Render(&markup.RenderContext{Ctx: git.DefaultContext}, | ||||
| 			strings.NewReader(k), &buf) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.EqualValues(t, v, buf.String()) | ||||
| 	} | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/markup" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -23,7 +24,8 @@ func TestRenderCSV(t *testing.T) { | ||||
|  | ||||
| 	for k, v := range kases { | ||||
| 		var buf strings.Builder | ||||
| 		err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf) | ||||
| 		err := render.Render(&markup.RenderContext{Ctx: git.DefaultContext}, | ||||
| 			strings.NewReader(k), &buf) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.EqualValues(t, v, buf.String()) | ||||
| 	} | ||||
|   | ||||
| @@ -291,9 +291,10 @@ func RenderDescriptionHTML( | ||||
| // RenderEmoji for when we want to just process emoji and shortcodes | ||||
| // in various places it isn't already run through the normal markdown processor | ||||
| func RenderEmoji( | ||||
| 	ctx *RenderContext, | ||||
| 	content string, | ||||
| ) (string, error) { | ||||
| 	return renderProcessString(&RenderContext{}, emojiProcessors, content) | ||||
| 	return renderProcessString(ctx, emojiProcessors, content) | ||||
| } | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
|  | ||||
| @@ -70,8 +71,13 @@ var localMetas = map[string]string{ | ||||
| func TestRender_IssueIndexPattern(t *testing.T) { | ||||
| 	// numeric: render inputs without valid mentions | ||||
| 	test := func(s string) { | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{}) | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{Metas: numericMetas}) | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{ | ||||
| 			Ctx: git.DefaultContext, | ||||
| 		}) | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: numericMetas, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// should not render anything when there are no mentions | ||||
| @@ -119,7 +125,10 @@ func TestRender_IssueIndexPattern2(t *testing.T) { | ||||
| 			links[i] = numericIssueLink(util.URLJoin(TestRepoURL, path), "ref-issue", index, marker) | ||||
| 		} | ||||
| 		expectedNil := fmt.Sprintf(expectedFmt, links...) | ||||
| 		testRenderIssueIndexPattern(t, s, expectedNil, &RenderContext{Metas: localMetas}) | ||||
| 		testRenderIssueIndexPattern(t, s, expectedNil, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: localMetas, | ||||
| 		}) | ||||
|  | ||||
| 		class := "ref-issue" | ||||
| 		if isExternal { | ||||
| @@ -130,7 +139,10 @@ func TestRender_IssueIndexPattern2(t *testing.T) { | ||||
| 			links[i] = numericIssueLink(prefix, class, index, marker) | ||||
| 		} | ||||
| 		expectedNum := fmt.Sprintf(expectedFmt, links...) | ||||
| 		testRenderIssueIndexPattern(t, s, expectedNum, &RenderContext{Metas: numericMetas}) | ||||
| 		testRenderIssueIndexPattern(t, s, expectedNum, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: numericMetas, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	// should render freestanding mentions | ||||
| @@ -164,7 +176,10 @@ func TestRender_IssueIndexPattern3(t *testing.T) { | ||||
|  | ||||
| 	// alphanumeric: render inputs without valid mentions | ||||
| 	test := func(s string) { | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{Metas: alphanumericMetas}) | ||||
| 		testRenderIssueIndexPattern(t, s, s, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: alphanumericMetas, | ||||
| 		}) | ||||
| 	} | ||||
| 	test("") | ||||
| 	test("this is a test") | ||||
| @@ -194,7 +209,10 @@ func TestRender_IssueIndexPattern4(t *testing.T) { | ||||
| 			links[i] = externalIssueLink("https://someurl.com/someUser/someRepo/", "ref-issue ref-external-issue", name) | ||||
| 		} | ||||
| 		expected := fmt.Sprintf(expectedFmt, links...) | ||||
| 		testRenderIssueIndexPattern(t, s, expected, &RenderContext{Metas: alphanumericMetas}) | ||||
| 		testRenderIssueIndexPattern(t, s, expected, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: alphanumericMetas, | ||||
| 		}) | ||||
| 	} | ||||
| 	test("OTT-1234 test", "%s test", "OTT-1234") | ||||
| 	test("test T-12 issue", "test %s issue", "T-12") | ||||
| @@ -214,7 +232,10 @@ func TestRender_IssueIndexPattern5(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		expected := fmt.Sprintf(expectedFmt, links...) | ||||
| 		testRenderIssueIndexPattern(t, s, expected, &RenderContext{Metas: metas}) | ||||
| 		testRenderIssueIndexPattern(t, s, expected, &RenderContext{ | ||||
| 			Ctx:   git.DefaultContext, | ||||
| 			Metas: metas, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	test("abc ISSUE-123 def", "abc %s def", | ||||
| @@ -235,7 +256,10 @@ func TestRender_IssueIndexPattern5(t *testing.T) { | ||||
| 		[]string{"ISSUE-123"}, | ||||
| 	) | ||||
|  | ||||
| 	testRenderIssueIndexPattern(t, "will not match", "will not match", &RenderContext{Metas: regexpMetas}) | ||||
| 	testRenderIssueIndexPattern(t, "will not match", "will not match", &RenderContext{ | ||||
| 		Ctx:   git.DefaultContext, | ||||
| 		Metas: regexpMetas, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) { | ||||
| @@ -255,6 +279,7 @@ func TestRender_AutoLink(t *testing.T) { | ||||
| 	test := func(input, expected string) { | ||||
| 		var buffer strings.Builder | ||||
| 		err := PostProcess(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: TestRepoURL, | ||||
| 			Metas:     localMetas, | ||||
| 		}, strings.NewReader(input), &buffer) | ||||
| @@ -263,6 +288,7 @@ func TestRender_AutoLink(t *testing.T) { | ||||
|  | ||||
| 		buffer.Reset() | ||||
| 		err = PostProcess(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: TestRepoURL, | ||||
| 			Metas:     localMetas, | ||||
| 			IsWiki:    true, | ||||
| @@ -292,6 +318,7 @@ func TestRender_FullIssueURLs(t *testing.T) { | ||||
| 	test := func(input, expected string) { | ||||
| 		var result strings.Builder | ||||
| 		err := postProcess(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: TestRepoURL, | ||||
| 			Metas:     localMetas, | ||||
| 		}, []processor{fullIssuePatternProcessor}, strings.NewReader(input), &result) | ||||
|   | ||||
| @@ -91,6 +91,7 @@ func TestRender_CrossReferences(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&RenderContext{ | ||||
| 			Ctx:          git.DefaultContext, | ||||
| 			RelativePath: "a.md", | ||||
| 			URLPrefix:    setting.AppSubURL, | ||||
| 			Metas:        localMetas, | ||||
| @@ -135,6 +136,7 @@ func TestRender_links(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&RenderContext{ | ||||
| 			Ctx:          git.DefaultContext, | ||||
| 			RelativePath: "a.md", | ||||
| 			URLPrefix:    TestRepoURL, | ||||
| 		}, input) | ||||
| @@ -234,6 +236,7 @@ func TestRender_email(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		res, err := RenderString(&RenderContext{ | ||||
| 			Ctx:          git.DefaultContext, | ||||
| 			RelativePath: "a.md", | ||||
| 			URLPrefix:    TestRepoURL, | ||||
| 		}, input) | ||||
| @@ -292,6 +295,7 @@ func TestRender_emoji(t *testing.T) { | ||||
| 	test := func(input, expected string) { | ||||
| 		expected = strings.ReplaceAll(expected, "&", "&") | ||||
| 		buffer, err := RenderString(&RenderContext{ | ||||
| 			Ctx:          git.DefaultContext, | ||||
| 			RelativePath: "a.md", | ||||
| 			URLPrefix:    TestRepoURL, | ||||
| 		}, input) | ||||
| @@ -355,11 +359,13 @@ func TestRender_ShortLinks(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected, expectedWiki string) { | ||||
| 		buffer, err := markdown.RenderString(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: tree, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) | ||||
| 		buffer, err = markdown.RenderString(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: TestRepoURL, | ||||
| 			Metas:     localMetas, | ||||
| 			IsWiki:    true, | ||||
| @@ -461,12 +467,14 @@ func TestRender_RelativeImages(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected, expectedWiki string) { | ||||
| 		buffer, err := markdown.RenderString(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: tree, | ||||
| 			Metas:     localMetas, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) | ||||
| 		buffer, err = markdown.RenderString(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: TestRepoURL, | ||||
| 			Metas:     localMetas, | ||||
| 			IsWiki:    true, | ||||
| @@ -501,6 +509,7 @@ func Test_ParseClusterFuzz(t *testing.T) { | ||||
|  | ||||
| 	var res strings.Builder | ||||
| 	err := PostProcess(&RenderContext{ | ||||
| 		Ctx:       git.DefaultContext, | ||||
| 		URLPrefix: "https://example.com", | ||||
| 		Metas:     localMetas, | ||||
| 	}, strings.NewReader(data), &res) | ||||
| @@ -511,6 +520,7 @@ func Test_ParseClusterFuzz(t *testing.T) { | ||||
|  | ||||
| 	res.Reset() | ||||
| 	err = PostProcess(&RenderContext{ | ||||
| 		Ctx:       git.DefaultContext, | ||||
| 		URLPrefix: "https://example.com", | ||||
| 		Metas:     localMetas, | ||||
| 	}, strings.NewReader(data), &res) | ||||
| @@ -531,6 +541,7 @@ func TestIssue16020(t *testing.T) { | ||||
|  | ||||
| 	var res strings.Builder | ||||
| 	err := PostProcess(&RenderContext{ | ||||
| 		Ctx:       git.DefaultContext, | ||||
| 		URLPrefix: "https://example.com", | ||||
| 		Metas:     localMetas, | ||||
| 	}, strings.NewReader(data), &res) | ||||
| @@ -547,6 +558,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		var res strings.Builder | ||||
| 		err := PostProcess(&RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: "https://example.com", | ||||
| 			Metas:     localMetas, | ||||
| 		}, strings.NewReader(data), &res) | ||||
| @@ -557,6 +569,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) { | ||||
| func TestFuzz(t *testing.T) { | ||||
| 	s := "t/l/issues/8#/../../a" | ||||
| 	renderContext := RenderContext{ | ||||
| 		Ctx:       git.DefaultContext, | ||||
| 		URLPrefix: "https://example.com/go-gitea/gitea", | ||||
| 		Metas: map[string]string{ | ||||
| 			"user": "go-gitea", | ||||
| @@ -574,6 +587,7 @@ func TestIssue18471(t *testing.T) { | ||||
|  | ||||
| 	var res strings.Builder | ||||
| 	err := PostProcess(&RenderContext{ | ||||
| 		Ctx:       git.DefaultContext, | ||||
| 		URLPrefix: "https://example.com", | ||||
| 		Metas:     localMetas, | ||||
| 	}, strings.NewReader(data), &res) | ||||
|   | ||||
| @@ -52,12 +52,14 @@ func TestRender_StandardLinks(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected, expectedWiki string) { | ||||
| 		buffer, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) | ||||
|  | ||||
| 		buffer, err = RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 			IsWiki:    true, | ||||
| 		}, input) | ||||
| @@ -81,6 +83,7 @@ func TestRender_Images(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| @@ -311,6 +314,7 @@ func TestTotal_RenderWiki(t *testing.T) { | ||||
|  | ||||
| 	for i := 0; i < len(testCases); i += 2 { | ||||
| 		line, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: AppSubURL, | ||||
| 			IsWiki:    true, | ||||
| 		}, testCases[i]) | ||||
| @@ -339,6 +343,7 @@ func TestTotal_RenderString(t *testing.T) { | ||||
|  | ||||
| 	for i := 0; i < len(testCases); i += 2 { | ||||
| 		line, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: AppSubURL, | ||||
| 		}, testCases[i]) | ||||
| 		assert.NoError(t, err) | ||||
| @@ -348,17 +353,17 @@ func TestTotal_RenderString(t *testing.T) { | ||||
|  | ||||
| func TestRender_RenderParagraphs(t *testing.T) { | ||||
| 	test := func(t *testing.T, str string, cnt int) { | ||||
| 		res, err := RenderRawString(&markup.RenderContext{}, str) | ||||
| 		res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, str) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for unix should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res) | ||||
|  | ||||
| 		mac := strings.ReplaceAll(str, "\n", "\r") | ||||
| 		res, err = RenderRawString(&markup.RenderContext{}, mac) | ||||
| 		res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, mac) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for mac should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res) | ||||
|  | ||||
| 		dos := strings.ReplaceAll(str, "\n", "\r\n") | ||||
| 		res, err = RenderRawString(&markup.RenderContext{}, dos) | ||||
| 		res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, dos) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for windows should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res) | ||||
| 	} | ||||
| @@ -386,7 +391,7 @@ func TestMarkdownRenderRaw(t *testing.T) { | ||||
|  | ||||
| 	for _, testcase := range testcases { | ||||
| 		log.Info("Test markdown render error with fuzzy data: %x, the following errors can be recovered", testcase) | ||||
| 		_, err := RenderRawString(&markup.RenderContext{}, string(testcase)) | ||||
| 		_, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, string(testcase)) | ||||
| 		assert.NoError(t, err) | ||||
| 	} | ||||
| } | ||||
| @@ -398,7 +403,7 @@ func TestRenderSiblingImages_Issue12925(t *testing.T) { | ||||
| 	expected := `<p><a href="/image1" target="_blank" rel="nofollow noopener"><img src="/image1" alt="image1"></a><br> | ||||
| <a href="/image2" target="_blank" rel="nofollow noopener"><img src="/image2" alt="image2"></a></p> | ||||
| ` | ||||
| 	res, err := RenderRawString(&markup.RenderContext{}, testcase) | ||||
| 	res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, expected, res) | ||||
| } | ||||
| @@ -407,7 +412,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) { | ||||
| 	testcase := `[Link with emoji :moon: in text](https://gitea.io)` | ||||
| 	expected := `<p><a href="https://gitea.io" rel="nofollow">Link with emoji <span class="emoji" aria-label="waxing gibbous moon">🌔</span> in text</a></p> | ||||
| ` | ||||
| 	res, err := RenderString(&markup.RenderContext{}, testcase) | ||||
| 	res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, expected, res) | ||||
| } | ||||
| @@ -441,7 +446,7 @@ func TestColorPreview(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range positiveTests { | ||||
| 		res, err := RenderString(&markup.RenderContext{}, test.testcase) | ||||
| 		res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, 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) | ||||
|  | ||||
| @@ -461,7 +466,7 @@ func TestColorPreview(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range negativeTests { | ||||
| 		res, err := RenderString(&markup.RenderContext{}, test) | ||||
| 		res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test) | ||||
| 		assert.NoError(t, err, "Unexpected error in testcase: %q", test) | ||||
| 		assert.NotContains(t, res, `<span class="color-preview" style="background-color: `, "Unexpected result in testcase %q", test) | ||||
| 	} | ||||
| @@ -508,7 +513,7 @@ func TestMathBlock(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range testcases { | ||||
| 		res, err := RenderString(&markup.RenderContext{}, test.testcase) | ||||
| 		res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, 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) | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/markup" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| @@ -26,6 +27,7 @@ func TestRender_StandardLinks(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| @@ -46,6 +48,7 @@ func TestRender_Images(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
| @@ -65,6 +68,7 @@ func TestRender_Source(t *testing.T) { | ||||
|  | ||||
| 	test := func(input, expected string) { | ||||
| 		buffer, err := RenderString(&markup.RenderContext{ | ||||
| 			Ctx:       git.DefaultContext, | ||||
| 			URLPrefix: setting.AppSubURL, | ||||
| 		}, input) | ||||
| 		assert.NoError(t, err) | ||||
|   | ||||
| @@ -385,10 +385,10 @@ func NewFuncMap() []template.FuncMap { | ||||
| 			// the table is NOT sorted with this header | ||||
| 			return "" | ||||
| 		}, | ||||
| 		"RenderLabel": func(label *issues_model.Label) template.HTML { | ||||
| 			return template.HTML(RenderLabel(label)) | ||||
| 		"RenderLabel": func(ctx context.Context, label *issues_model.Label) template.HTML { | ||||
| 			return template.HTML(RenderLabel(ctx, label)) | ||||
| 		}, | ||||
| 		"RenderLabels": func(labels []*issues_model.Label, repoLink string) template.HTML { | ||||
| 		"RenderLabels": func(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML { | ||||
| 			htmlCode := `<span class="labels-list">` | ||||
| 			for _, label := range labels { | ||||
| 				// Protect against nil value in labels - shouldn't happen but would cause a panic if so | ||||
| @@ -396,7 +396,7 @@ func NewFuncMap() []template.FuncMap { | ||||
| 					continue | ||||
| 				} | ||||
| 				htmlCode += fmt.Sprintf("<a href='%s/issues?labels=%d'>%s</a> ", | ||||
| 					repoLink, label.ID, RenderLabel(label)) | ||||
| 					repoLink, label.ID, RenderLabel(ctx, label)) | ||||
| 			} | ||||
| 			htmlCode += "</span>" | ||||
| 			return template.HTML(htmlCode) | ||||
| @@ -808,7 +808,7 @@ func RenderIssueTitle(ctx context.Context, text, urlPrefix string, metas map[str | ||||
| } | ||||
|  | ||||
| // RenderLabel renders a label | ||||
| func RenderLabel(label *issues_model.Label) string { | ||||
| func RenderLabel(ctx context.Context, label *issues_model.Label) string { | ||||
| 	labelScope := label.ExclusiveScope() | ||||
|  | ||||
| 	textColor := "#111" | ||||
| @@ -821,12 +821,12 @@ func RenderLabel(label *issues_model.Label) string { | ||||
| 	if labelScope == "" { | ||||
| 		// Regular label | ||||
| 		return fmt.Sprintf("<div class='ui label' style='color: %s !important; background-color: %s !important' title='%s'>%s</div>", | ||||
| 			textColor, label.Color, description, RenderEmoji(label.Name)) | ||||
| 			textColor, label.Color, description, RenderEmoji(ctx, label.Name)) | ||||
| 	} | ||||
|  | ||||
| 	// Scoped label | ||||
| 	scopeText := RenderEmoji(labelScope) | ||||
| 	itemText := RenderEmoji(label.Name[len(labelScope)+1:]) | ||||
| 	scopeText := RenderEmoji(ctx, labelScope) | ||||
| 	itemText := RenderEmoji(ctx, label.Name[len(labelScope)+1:]) | ||||
|  | ||||
| 	itemColor := label.Color | ||||
| 	scopeColor := label.Color | ||||
| @@ -869,8 +869,9 @@ func RenderLabel(label *issues_model.Label) string { | ||||
| } | ||||
|  | ||||
| // RenderEmoji renders html text with emoji post processors | ||||
| func RenderEmoji(text string) template.HTML { | ||||
| 	renderedText, err := markup.RenderEmoji(template.HTMLEscapeString(text)) | ||||
| func RenderEmoji(ctx context.Context, text string) template.HTML { | ||||
| 	renderedText, err := markup.RenderEmoji(&markup.RenderContext{Ctx: ctx}, | ||||
| 		template.HTMLEscapeString(text)) | ||||
| 	if err != nil { | ||||
| 		log.Error("RenderEmoji: %v", err) | ||||
| 		return template.HTML("") | ||||
|   | ||||
| @@ -234,7 +234,7 @@ | ||||
| 						{{if or .Labels .Assignees}} | ||||
| 						<div class="extra content labels-list gt-p-0 gt-pt-2"> | ||||
| 							{{range .Labels}} | ||||
| 								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel .}}</a> | ||||
| 								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel $.Context .}}</a> | ||||
| 							{{end}} | ||||
| 							<div class="right floated"> | ||||
| 								{{range .Assignees}} | ||||
|   | ||||
| @@ -129,7 +129,7 @@ | ||||
| 						<span class="ui green label">{{$.locale.Tr "repo.activity.published_release_label"}}</span> | ||||
| 						{{.TagName}} | ||||
| 						{{if not .IsTag}} | ||||
| 							<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a> | ||||
| 							<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{end}} | ||||
| 						{{TimeSinceUnix .CreatedUnix $.locale}} | ||||
| 					</p> | ||||
| @@ -149,7 +149,7 @@ | ||||
| 				{{range .Activity.MergedPRs}} | ||||
| 					<p class="desc"> | ||||
| 						<span class="ui purple label">{{$.locale.Tr "repo.activity.merged_prs_label"}}</span> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{TimeSinceUnix .MergedUnix $.locale}} | ||||
| 					</p> | ||||
| 				{{end}} | ||||
| @@ -168,7 +168,7 @@ | ||||
| 				{{range .Activity.OpenedPRs}} | ||||
| 					<p class="desc"> | ||||
| 						<span class="ui green label">{{$.locale.Tr "repo.activity.opened_prs_label"}}</span> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{TimeSinceUnix .Issue.CreatedUnix $.locale}} | ||||
| 					</p> | ||||
| 				{{end}} | ||||
| @@ -187,7 +187,7 @@ | ||||
| 				{{range .Activity.ClosedIssues}} | ||||
| 					<p class="desc"> | ||||
| 						<span class="ui red label">{{$.locale.Tr "repo.activity.closed_issue_label"}}</span> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{TimeSinceUnix .ClosedUnix $.locale}} | ||||
| 					</p> | ||||
| 				{{end}} | ||||
| @@ -206,7 +206,7 @@ | ||||
| 				{{range .Activity.OpenedIssues}} | ||||
| 					<p class="desc"> | ||||
| 						<span class="ui green label">{{$.locale.Tr "repo.activity.new_issue_label"}}</span> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a> | ||||
| 						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{TimeSinceUnix .CreatedUnix $.locale}} | ||||
| 					</p> | ||||
| 				{{end}} | ||||
| @@ -227,9 +227,9 @@ | ||||
| 						<span class="ui green label">{{$.locale.Tr "repo.activity.unresolved_conv_label"}}</span> | ||||
| 						#{{.Index}} | ||||
| 						{{if .IsPull}} | ||||
| 						<a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Title | RenderEmoji}}</a> | ||||
| 						<a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{else}} | ||||
| 						<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a> | ||||
| 						<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a> | ||||
| 						{{end}} | ||||
| 						{{TimeSinceUnix .UpdatedUnix $.locale}} | ||||
| 					</p> | ||||
|   | ||||
| @@ -61,7 +61,7 @@ | ||||
| 						<td class="message"> | ||||
| 							<span class="message-wrapper"> | ||||
| 							{{if $.PageIsWiki}} | ||||
| 								<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji}}</span> | ||||
| 								<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span> | ||||
| 							{{else}} | ||||
| 								{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} | ||||
| 								<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitRepoLink $commitLink $.Repository.ComposeMetas}}</span> | ||||
|   | ||||
| @@ -3,5 +3,5 @@ | ||||
| 	id="label_{{.label.ID}}" | ||||
| 	href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}"{{/* FIXME: use .root.Issue.Link or create .root.Link */}} | ||||
| > | ||||
| 	{{RenderLabel .label}} | ||||
| 	{{RenderLabel $.Context .label}} | ||||
| </a> | ||||
|   | ||||
| @@ -31,8 +31,8 @@ | ||||
| 			<li class="item"> | ||||
| 			<div class="ui grid middle aligned"> | ||||
| 				<div class="nine wide column"> | ||||
| 					{{RenderLabel .}} | ||||
| 					{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}} | ||||
| 					{{RenderLabel $.Context .}} | ||||
| 					{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}} | ||||
| 				</div> | ||||
| 				<div class="four wide column"> | ||||
| 					{{if $.PageIsOrgSettingsLabels}} | ||||
| @@ -70,8 +70,8 @@ | ||||
| 					<li class="item"> | ||||
| 					<div class="ui grid middle aligned"> | ||||
| 						<div class="nine wide column"> | ||||
| 							{{RenderLabel .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}} | ||||
| 							{{RenderLabel $.Context .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}} | ||||
| 						</div> | ||||
| 						<div class="four wide column"> | ||||
| 							<a class="ui left open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.locale.Tr "repo.issues.label_open_issues" .NumOpenRepoIssues}}</a> | ||||
|   | ||||
| @@ -57,7 +57,7 @@ | ||||
| 									<div class="ui divider"></div> | ||||
| 								{{end}} | ||||
| 								{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel .}}</a> | ||||
| 								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}}</a> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 					</div> | ||||
| @@ -232,7 +232,7 @@ | ||||
| 								{{end}} | ||||
| 								{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 								<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels"> | ||||
| 									{{if contain $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel .}} | ||||
| 									{{if contain $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}} | ||||
| 								</div> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
|   | ||||
| @@ -58,7 +58,7 @@ | ||||
| 							<span class="info">{{.locale.Tr "repo.issues.filter_label_exclude" | Safe}}</span> | ||||
| 							<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_label_no_select"}}</a> | ||||
| 							{{range .Labels}} | ||||
| 								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel .}}</a> | ||||
| 								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel $.Context .}}</a> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 					</div> | ||||
| @@ -162,7 +162,7 @@ | ||||
| 						<div class="menu"> | ||||
| 							{{range .Labels}} | ||||
| 								<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels"> | ||||
| 									{{if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel .}} | ||||
| 									{{if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel $.Context .}} | ||||
| 								</div> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
|   | ||||
| @@ -60,8 +60,8 @@ | ||||
| 								<div class="ui divider"></div> | ||||
| 							{{end}} | ||||
| 							{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a> | ||||
| 							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a> | ||||
| 						{{end}} | ||||
|  | ||||
| 						<div class="ui divider"></div> | ||||
| @@ -72,8 +72,8 @@ | ||||
| 								<div class="ui divider"></div> | ||||
| 							{{end}} | ||||
| 							{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a> | ||||
| 							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}} | ||||
| 							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a> | ||||
| 						{{end}} | ||||
| 					{{else}} | ||||
| 						<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div> | ||||
|   | ||||
| @@ -180,11 +180,11 @@ | ||||
| 					<span class="text grey muted-links"> | ||||
| 						{{template "shared/user/authorlink" .Poster}} | ||||
| 						{{if and .AddedLabels (not .RemovedLabels)}} | ||||
| 							{{$.locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels .AddedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 							{{$.locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 						{{else if and (not .AddedLabels) .RemovedLabels}} | ||||
| 							{{$.locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels .RemovedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 							{{$.locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 						{{else}} | ||||
| 							{{$.locale.Tr "repo.issues.add_remove_labels" (RenderLabels .AddedLabels $.RepoLink) (RenderLabels .RemovedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 							{{$.locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}} | ||||
| 						{{end}} | ||||
| 					</span> | ||||
| 				</div> | ||||
| @@ -231,7 +231,7 @@ | ||||
| 				{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .Poster}} | ||||
| 				<span class="text grey muted-links"> | ||||
| 					{{template "shared/user/authorlink" .Poster}} | ||||
| 					{{$.locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji) (.NewTitle|RenderEmoji) $createdStr | Safe}} | ||||
| 					{{$.locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji $.Context) (.NewTitle|RenderEmoji $.Context) $createdStr | Safe}} | ||||
| 				</span> | ||||
| 			</div> | ||||
| 		{{else if eq .Type 11}} | ||||
|   | ||||
| @@ -130,8 +130,8 @@ | ||||
| 							<div class="ui divider"></div> | ||||
| 						{{end}} | ||||
| 						{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}} | ||||
| 						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a> | ||||
| 						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}} | ||||
| 						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a> | ||||
| 					{{end}} | ||||
| 					<div class="ui divider"></div> | ||||
| 					{{$previousExclusiveScope := "_no_scope"}} | ||||
| @@ -141,8 +141,8 @@ | ||||
| 							<div class="ui divider"></div> | ||||
| 						{{end}} | ||||
| 						{{$previousExclusiveScope = $exclusiveScope}} | ||||
| 						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}} | ||||
| 						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a> | ||||
| 						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}} | ||||
| 						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a> | ||||
| 					{{end}} | ||||
| 				{{else}} | ||||
| 					<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div> | ||||
| @@ -487,8 +487,8 @@ | ||||
| 						{{range .BlockingDependencies}} | ||||
| 							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb"> | ||||
| 								<div class="item-left gt-df gt-jc gt-fc gt-f1"> | ||||
| 									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}"> | ||||
| 										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}} | ||||
| 									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}"> | ||||
| 										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}} | ||||
| 									</a> | ||||
| 									<div class="text small"> | ||||
| 										{{.Repository.OwnerName}}/{{.Repository.Name}} | ||||
| @@ -514,8 +514,8 @@ | ||||
| 						{{range .BlockedByDependencies}} | ||||
| 							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb"> | ||||
| 								<div class="item-left gt-df gt-jc gt-fc gt-f1"> | ||||
| 									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}"> | ||||
| 										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}} | ||||
| 									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}"> | ||||
| 										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}} | ||||
| 									</a> | ||||
| 									<div class="text small"> | ||||
| 										{{.Repository.OwnerName}}/{{.Repository.Name}} | ||||
|   | ||||
| @@ -245,7 +245,7 @@ | ||||
| 						{{if or .Labels .Assignees}} | ||||
| 						<div class="extra content labels-list gt-p-0 gt-pt-2"> | ||||
| 							{{range .Labels}} | ||||
| 								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel .}}</a> | ||||
| 								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel $.Context .}}</a> | ||||
| 							{{end}} | ||||
| 							<div class="right floated"> | ||||
| 								{{range .Assignees}} | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| 							<td class="message"> | ||||
| 								<span class="truncate"> | ||||
| 									<a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary | RenderEmojiPlain}}"> | ||||
| 										{{.Summary | RenderEmoji}} | ||||
| 										{{.Summary | RenderEmoji $.Context}} | ||||
| 									</a> | ||||
| 								</span> | ||||
| 							</td> | ||||
|   | ||||
| @@ -34,7 +34,7 @@ | ||||
| 			</div> | ||||
| 			<div class="issue-item-main gt-f1 gt-fc gt-df"> | ||||
| 				<div class="issue-item-top-row"> | ||||
| 					<a class="title gt-tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a> | ||||
| 					<a class="title gt-tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji $.Context .Title | RenderCodeBlock}}</a> | ||||
| 					{{if .IsPull}} | ||||
| 						{{if (index $.CommitStatuses .PullRequest.ID)}} | ||||
| 							{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}} | ||||
| @@ -42,7 +42,7 @@ | ||||
| 					{{end}} | ||||
| 					<span class="labels-list gt-ml-2"> | ||||
| 						{{range .Labels}} | ||||
| 							<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel .}}</a> | ||||
| 							<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel $.Context .}}</a> | ||||
| 						{{end}} | ||||
| 					</span> | ||||
| 				</div> | ||||
|   | ||||
| @@ -72,7 +72,7 @@ | ||||
| 							{{$index := index .GetIssueInfos 0}} | ||||
| 							{{$.locale.Tr "action.comment_pull" ((printf "%s/pulls/%s" .GetRepoLink $index) |Escape) $index (.ShortRepoPath|Escape) | Str2html}} | ||||
| 						{{else if eq .GetOpType 24}} | ||||
| 							{{$linkText := .Content | RenderEmoji}} | ||||
| 							{{$linkText := .Content | RenderEmoji $.Context}} | ||||
| 							{{$.locale.Tr "action.publish_release" (.GetRepoLink|Escape) ((printf "%s/releases/tag/%s" .GetRepoLink .GetTag)|Escape) (.ShortRepoPath|Escape) $linkText | Str2html}} | ||||
| 						{{else if eq .GetOpType 25}} | ||||
| 							{{$index := index .GetIssueInfos 0}} | ||||
| @@ -99,20 +99,20 @@ | ||||
| 							</ul> | ||||
| 						</div> | ||||
| 					{{else if eq .GetOpType 6}} | ||||
| 						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji | RenderCodeBlock}}</span> | ||||
| 						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span> | ||||
| 					{{else if eq .GetOpType 7}} | ||||
| 						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji | RenderCodeBlock}}</span> | ||||
| 						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span> | ||||
| 					{{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22) (eq .GetOpType 23)}} | ||||
| 						<a href="{{.GetCommentLink}}" class="text truncate issue title">{{.GetIssueTitle | RenderEmoji | RenderCodeBlock}}</a> | ||||
| 						<a href="{{.GetCommentLink}}" class="text truncate issue title">{{.GetIssueTitle | RenderEmoji $.Context | RenderCodeBlock}}</a> | ||||
| 						{{$comment := index .GetIssueInfos 1}} | ||||
| 						{{if gt (len $comment) 0}}<p class="text light grey">{{$comment | RenderEmoji}}</p>{{end}} | ||||
| 						{{if gt (len $comment) 0}}<p class="text light grey">{{$comment | RenderEmoji $.Context}}</p>{{end}} | ||||
| 					{{else if eq .GetOpType 11}} | ||||
| 						<p class="text light grey">{{index .GetIssueInfos 1}}</p> | ||||
| 					{{else if or (eq .GetOpType 12) (eq .GetOpType 13) (eq .GetOpType 14) (eq .GetOpType 15)}} | ||||
| 						<span class="text truncate issue title">{{.GetIssueTitle | RenderEmoji | RenderCodeBlock}}</span> | ||||
| 						<span class="text truncate issue title">{{.GetIssueTitle | RenderEmoji $.Context | RenderCodeBlock}}</span> | ||||
| 					{{else if eq .GetOpType 25}} | ||||
| 					<p class="text light grey">{{$.locale.Tr "action.review_dismissed_reason"}}</p> | ||||
| 						<p class="text light grey">{{index .GetIssueInfos 2 | RenderEmoji}}</p> | ||||
| 						<p class="text light grey">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</p> | ||||
| 					{{end}} | ||||
| 					<p class="text italic light grey">{{TimeSince .GetCreate $.locale}}</p> | ||||
| 				</div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user