mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-23 23:03:34 +01:00
Make link last commit massages in repository home page and commit tables (#8006)
* Make link last commit massages in repository home page and commit tables * Use RenderCommitMessageLink instead surround with a * deleted __debug_bin file * Exclude email to link from latest commit title * Exclude email processor from commit table Co-Authored-By: mrsdizzie <info@mrsdizzie.com> * Add class parameter to a html element creator functions. Make links underline dashed that are not commit * fix tests * Show dashed underline when also not hovered
This commit is contained in:
parent
7eacdcf39a
commit
7e17424c7e
7 changed files with 154 additions and 38 deletions
|
@ -211,6 +211,40 @@ func RenderCommitMessage(
|
||||||
return ctx.postProcess(rawHTML)
|
return ctx.postProcess(rawHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commitMessageSubjectProcessors = []processor{
|
||||||
|
fullIssuePatternProcessor,
|
||||||
|
fullSha1PatternProcessor,
|
||||||
|
linkProcessor,
|
||||||
|
mentionProcessor,
|
||||||
|
issueIndexPatternProcessor,
|
||||||
|
crossReferenceIssueIndexPatternProcessor,
|
||||||
|
sha1CurrentPatternProcessor,
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderCommitMessageSubject will use the same logic as PostProcess and
|
||||||
|
// RenderCommitMessage, but will disable the shortLinkProcessor and
|
||||||
|
// emailAddressProcessor, will add a defaultLinkProcessor if defaultLink is set,
|
||||||
|
// which changes every text node into a link to the passed default link.
|
||||||
|
func RenderCommitMessageSubject(
|
||||||
|
rawHTML []byte,
|
||||||
|
urlPrefix, defaultLink string,
|
||||||
|
metas map[string]string,
|
||||||
|
) ([]byte, error) {
|
||||||
|
ctx := &postProcessCtx{
|
||||||
|
metas: metas,
|
||||||
|
urlPrefix: urlPrefix,
|
||||||
|
procs: commitMessageSubjectProcessors,
|
||||||
|
}
|
||||||
|
if defaultLink != "" {
|
||||||
|
// we don't have to fear data races, because being
|
||||||
|
// commitMessageSubjectProcessors of fixed len and cap, every time we
|
||||||
|
// append something to it the slice is realloc+copied, so append always
|
||||||
|
// generates the slice ex-novo.
|
||||||
|
ctx.procs = append(ctx.procs, genDefaultLinkProcessor(defaultLink))
|
||||||
|
}
|
||||||
|
return ctx.postProcess(rawHTML)
|
||||||
|
}
|
||||||
|
|
||||||
// RenderDescriptionHTML will use similar logic as PostProcess, but will
|
// RenderDescriptionHTML will use similar logic as PostProcess, but will
|
||||||
// use a single special linkProcessor.
|
// use a single special linkProcessor.
|
||||||
func RenderDescriptionHTML(
|
func RenderDescriptionHTML(
|
||||||
|
@ -296,12 +330,17 @@ func (ctx *postProcessCtx) textNode(node *html.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createLink(href, content string) *html.Node {
|
func createLink(href, content, class string) *html.Node {
|
||||||
a := &html.Node{
|
a := &html.Node{
|
||||||
Type: html.ElementNode,
|
Type: html.ElementNode,
|
||||||
Data: atom.A.String(),
|
Data: atom.A.String(),
|
||||||
Attr: []html.Attribute{{Key: "href", Val: href}},
|
Attr: []html.Attribute{{Key: "href", Val: href}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if class != "" {
|
||||||
|
a.Attr = append(a.Attr, html.Attribute{Key: "class", Val: class})
|
||||||
|
}
|
||||||
|
|
||||||
text := &html.Node{
|
text := &html.Node{
|
||||||
Type: html.TextNode,
|
Type: html.TextNode,
|
||||||
Data: content,
|
Data: content,
|
||||||
|
@ -311,12 +350,17 @@ func createLink(href, content string) *html.Node {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCodeLink(href, content string) *html.Node {
|
func createCodeLink(href, content, class string) *html.Node {
|
||||||
a := &html.Node{
|
a := &html.Node{
|
||||||
Type: html.ElementNode,
|
Type: html.ElementNode,
|
||||||
Data: atom.A.String(),
|
Data: atom.A.String(),
|
||||||
Attr: []html.Attribute{{Key: "href", Val: href}},
|
Attr: []html.Attribute{{Key: "href", Val: href}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if class != "" {
|
||||||
|
a.Attr = append(a.Attr, html.Attribute{Key: "class", Val: class})
|
||||||
|
}
|
||||||
|
|
||||||
text := &html.Node{
|
text := &html.Node{
|
||||||
Type: html.TextNode,
|
Type: html.TextNode,
|
||||||
Data: content,
|
Data: content,
|
||||||
|
@ -364,7 +408,7 @@ func mentionProcessor(_ *postProcessCtx, node *html.Node) {
|
||||||
}
|
}
|
||||||
// Replace the mention with a link to the specified user.
|
// Replace the mention with a link to the specified user.
|
||||||
mention := node.Data[m[2]:m[3]]
|
mention := node.Data[m[2]:m[3]]
|
||||||
replaceContent(node, m[2], m[3], createLink(util.URLJoin(setting.AppURL, mention[1:]), mention))
|
replaceContent(node, m[2], m[3], createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func shortLinkProcessor(ctx *postProcessCtx, node *html.Node) {
|
func shortLinkProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
|
@ -541,11 +585,11 @@ func fullIssuePatternProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
if matchOrg == ctx.metas["user"] && matchRepo == ctx.metas["repo"] {
|
if matchOrg == ctx.metas["user"] && matchRepo == ctx.metas["repo"] {
|
||||||
// TODO if m[4]:m[5] is not nil, then link is to a comment,
|
// TODO if m[4]:m[5] is not nil, then link is to a comment,
|
||||||
// and we should indicate that in the text somehow
|
// and we should indicate that in the text somehow
|
||||||
replaceContent(node, m[0], m[1], createLink(link, id))
|
replaceContent(node, m[0], m[1], createLink(link, id, "issue"))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
orgRepoID := matchOrg + "/" + matchRepo + id
|
orgRepoID := matchOrg + "/" + matchRepo + id
|
||||||
replaceContent(node, m[0], m[1], createLink(link, orgRepoID))
|
replaceContent(node, m[0], m[1], createLink(link, orgRepoID, "issue"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,9 +617,9 @@ func issueIndexPatternProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
} else {
|
} else {
|
||||||
ctx.metas["index"] = id[1:]
|
ctx.metas["index"] = id[1:]
|
||||||
}
|
}
|
||||||
link = createLink(com.Expand(ctx.metas["format"], ctx.metas), id)
|
link = createLink(com.Expand(ctx.metas["format"], ctx.metas), id, "issue")
|
||||||
} else {
|
} else {
|
||||||
link = createLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "issues", id[1:]), id)
|
link = createLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "issues", id[1:]), id, "issue")
|
||||||
}
|
}
|
||||||
replaceContent(node, match[2], match[3], link)
|
replaceContent(node, match[2], match[3], link)
|
||||||
}
|
}
|
||||||
|
@ -591,7 +635,7 @@ func crossReferenceIssueIndexPatternProcessor(ctx *postProcessCtx, node *html.No
|
||||||
repo, issue := parts[0], parts[1]
|
repo, issue := parts[0], parts[1]
|
||||||
|
|
||||||
replaceContent(node, m[2], m[3],
|
replaceContent(node, m[2], m[3],
|
||||||
createLink(util.URLJoin(setting.AppURL, repo, "issues", issue), ref))
|
createLink(util.URLJoin(setting.AppURL, repo, "issues", issue), ref, issue))
|
||||||
}
|
}
|
||||||
|
|
||||||
// fullSha1PatternProcessor renders SHA containing URLs
|
// fullSha1PatternProcessor renders SHA containing URLs
|
||||||
|
@ -642,7 +686,7 @@ func fullSha1PatternProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
text += " (" + hash + ")"
|
text += " (" + hash + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceContent(node, start, end, createCodeLink(urlFull, text))
|
replaceContent(node, start, end, createCodeLink(urlFull, text, "commit"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that
|
// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that
|
||||||
|
@ -672,7 +716,7 @@ func sha1CurrentPatternProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceContent(node, m[2], m[3],
|
replaceContent(node, m[2], m[3],
|
||||||
createCodeLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "commit", hash), base.ShortSha(hash)))
|
createCodeLink(util.URLJoin(setting.AppURL, ctx.metas["user"], ctx.metas["repo"], "commit", hash), base.ShortSha(hash), "commit"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// emailAddressProcessor replaces raw email addresses with a mailto: link.
|
// emailAddressProcessor replaces raw email addresses with a mailto: link.
|
||||||
|
@ -682,7 +726,7 @@ func emailAddressProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mail := node.Data[m[2]:m[3]]
|
mail := node.Data[m[2]:m[3]]
|
||||||
replaceContent(node, m[2], m[3], createLink("mailto:"+mail, mail))
|
replaceContent(node, m[2], m[3], createLink("mailto:"+mail, mail, "mailto"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkProcessor creates links for any HTTP or HTTPS URL not captured by
|
// linkProcessor creates links for any HTTP or HTTPS URL not captured by
|
||||||
|
@ -693,7 +737,7 @@ func linkProcessor(ctx *postProcessCtx, node *html.Node) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uri := node.Data[m[0]:m[1]]
|
uri := node.Data[m[0]:m[1]]
|
||||||
replaceContent(node, m[0], m[1], createLink(uri, uri))
|
replaceContent(node, m[0], m[1], createLink(uri, uri, "link"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func genDefaultLinkProcessor(defaultLink string) processor {
|
func genDefaultLinkProcessor(defaultLink string) processor {
|
||||||
|
@ -707,7 +751,10 @@ func genDefaultLinkProcessor(defaultLink string) processor {
|
||||||
node.Type = html.ElementNode
|
node.Type = html.ElementNode
|
||||||
node.Data = "a"
|
node.Data = "a"
|
||||||
node.DataAtom = atom.A
|
node.DataAtom = atom.A
|
||||||
node.Attr = []html.Attribute{{Key: "href", Val: defaultLink}}
|
node.Attr = []html.Attribute{
|
||||||
|
{Key: "href", Val: defaultLink},
|
||||||
|
{Key: "class", Val: "default-link"},
|
||||||
|
}
|
||||||
node.FirstChild, node.LastChild = ch, ch
|
node.FirstChild, node.LastChild = ch, ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,22 @@ const Repo = "gogits/gogs"
|
||||||
const AppSubURL = AppURL + Repo + "/"
|
const AppSubURL = AppURL + Repo + "/"
|
||||||
|
|
||||||
// alphanumLink an HTML link to an alphanumeric-style issue
|
// alphanumLink an HTML link to an alphanumeric-style issue
|
||||||
func alphanumIssueLink(baseURL string, name string) string {
|
func alphanumIssueLink(baseURL, class, name string) string {
|
||||||
return link(util.URLJoin(baseURL, name), name)
|
return link(util.URLJoin(baseURL, name), class, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// numericLink an HTML to a numeric-style issue
|
// numericLink an HTML to a numeric-style issue
|
||||||
func numericIssueLink(baseURL string, index int) string {
|
func numericIssueLink(baseURL, class string, index int) string {
|
||||||
return link(util.URLJoin(baseURL, strconv.Itoa(index)), fmt.Sprintf("#%d", index))
|
return link(util.URLJoin(baseURL, strconv.Itoa(index)), class, fmt.Sprintf("#%d", index))
|
||||||
}
|
}
|
||||||
|
|
||||||
// link an HTML link
|
// link an HTML link
|
||||||
func link(href, contents string) string {
|
func link(href, class, contents string) string {
|
||||||
return fmt.Sprintf("<a href=\"%s\">%s</a>", href, contents)
|
if class != "" {
|
||||||
|
class = " class=\"" + class + "\""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("<a href=\"%s\"%s>%s</a>", href, class, contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
var numericMetas = map[string]string{
|
var numericMetas = map[string]string{
|
||||||
|
@ -89,13 +93,13 @@ func TestRender_IssueIndexPattern2(t *testing.T) {
|
||||||
test := func(s, expectedFmt string, indices ...int) {
|
test := func(s, expectedFmt string, indices ...int) {
|
||||||
links := make([]interface{}, len(indices))
|
links := make([]interface{}, len(indices))
|
||||||
for i, index := range indices {
|
for i, index := range indices {
|
||||||
links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), index)
|
links[i] = numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), "issue", index)
|
||||||
}
|
}
|
||||||
expectedNil := fmt.Sprintf(expectedFmt, links...)
|
expectedNil := fmt.Sprintf(expectedFmt, links...)
|
||||||
testRenderIssueIndexPattern(t, s, expectedNil, &postProcessCtx{metas: localMetas})
|
testRenderIssueIndexPattern(t, s, expectedNil, &postProcessCtx{metas: localMetas})
|
||||||
|
|
||||||
for i, index := range indices {
|
for i, index := range indices {
|
||||||
links[i] = numericIssueLink("https://someurl.com/someUser/someRepo/", index)
|
links[i] = numericIssueLink("https://someurl.com/someUser/someRepo/", "issue", index)
|
||||||
}
|
}
|
||||||
expectedNum := fmt.Sprintf(expectedFmt, links...)
|
expectedNum := fmt.Sprintf(expectedFmt, links...)
|
||||||
testRenderIssueIndexPattern(t, s, expectedNum, &postProcessCtx{metas: numericMetas})
|
testRenderIssueIndexPattern(t, s, expectedNum, &postProcessCtx{metas: numericMetas})
|
||||||
|
@ -158,7 +162,7 @@ func TestRender_IssueIndexPattern4(t *testing.T) {
|
||||||
test := func(s, expectedFmt string, names ...string) {
|
test := func(s, expectedFmt string, names ...string) {
|
||||||
links := make([]interface{}, len(names))
|
links := make([]interface{}, len(names))
|
||||||
for i, name := range names {
|
for i, name := range names {
|
||||||
links[i] = alphanumIssueLink("https://someurl.com/someUser/someRepo/", name)
|
links[i] = alphanumIssueLink("https://someurl.com/someUser/someRepo/", "issue", name)
|
||||||
}
|
}
|
||||||
expected := fmt.Sprintf(expectedFmt, links...)
|
expected := fmt.Sprintf(expectedFmt, links...)
|
||||||
testRenderIssueIndexPattern(t, s, expected, &postProcessCtx{metas: alphanumericMetas})
|
testRenderIssueIndexPattern(t, s, expected, &postProcessCtx{metas: alphanumericMetas})
|
||||||
|
@ -197,17 +201,17 @@ func TestRender_AutoLink(t *testing.T) {
|
||||||
|
|
||||||
// render valid issue URLs
|
// render valid issue URLs
|
||||||
test(util.URLJoin(setting.AppSubURL, "issues", "3333"),
|
test(util.URLJoin(setting.AppSubURL, "issues", "3333"),
|
||||||
numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), 3333))
|
numericIssueLink(util.URLJoin(setting.AppSubURL, "issues"), "issue", 3333))
|
||||||
|
|
||||||
// render valid commit URLs
|
// render valid commit URLs
|
||||||
tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
|
tmp := util.URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
|
||||||
test(tmp, "<a href=\""+tmp+"\"><code class=\"nohighlight\">d8a994ef24</code></a>")
|
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24</code></a>")
|
||||||
tmp += "#diff-2"
|
tmp += "#diff-2"
|
||||||
test(tmp, "<a href=\""+tmp+"\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>")
|
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>")
|
||||||
|
|
||||||
// render other commit URLs
|
// render other commit URLs
|
||||||
tmp = "https://external-link.gitea.io/go-gitea/gitea/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2"
|
tmp = "https://external-link.gitea.io/go-gitea/gitea/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2"
|
||||||
test(tmp, "<a href=\""+tmp+"\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>")
|
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRender_FullIssueURLs(t *testing.T) {
|
func TestRender_FullIssueURLs(t *testing.T) {
|
||||||
|
@ -228,11 +232,11 @@ func TestRender_FullIssueURLs(t *testing.T) {
|
||||||
test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
|
test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
|
||||||
"Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
|
"Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
|
||||||
test("Look here http://localhost:3000/person/repo/issues/4",
|
test("Look here http://localhost:3000/person/repo/issues/4",
|
||||||
`Look here <a href="http://localhost:3000/person/repo/issues/4">person/repo#4</a>`)
|
`Look here <a href="http://localhost:3000/person/repo/issues/4" class="issue">person/repo#4</a>`)
|
||||||
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
|
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
|
||||||
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234">person/repo#4</a>`)
|
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="issue">person/repo#4</a>`)
|
||||||
test("http://localhost:3000/gogits/gogs/issues/4",
|
test("http://localhost:3000/gogits/gogs/issues/4",
|
||||||
`<a href="http://localhost:3000/gogits/gogs/issues/4">#4</a>`)
|
`<a href="http://localhost:3000/gogits/gogs/issues/4" class="issue">#4</a>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegExp_issueNumericPattern(t *testing.T) {
|
func TestRegExp_issueNumericPattern(t *testing.T) {
|
||||||
|
|
|
@ -118,13 +118,14 @@ func NewFuncMap() []template.FuncMap {
|
||||||
"EscapePound": func(str string) string {
|
"EscapePound": func(str string) string {
|
||||||
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
|
return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
|
||||||
},
|
},
|
||||||
"PathEscapeSegments": util.PathEscapeSegments,
|
"PathEscapeSegments": util.PathEscapeSegments,
|
||||||
"URLJoin": util.URLJoin,
|
"URLJoin": util.URLJoin,
|
||||||
"RenderCommitMessage": RenderCommitMessage,
|
"RenderCommitMessage": RenderCommitMessage,
|
||||||
"RenderCommitMessageLink": RenderCommitMessageLink,
|
"RenderCommitMessageLink": RenderCommitMessageLink,
|
||||||
"RenderCommitBody": RenderCommitBody,
|
"RenderCommitMessageLinkSubject": RenderCommitMessageLinkSubject,
|
||||||
"RenderNote": RenderNote,
|
"RenderCommitBody": RenderCommitBody,
|
||||||
"IsMultilineCommitMessage": IsMultilineCommitMessage,
|
"RenderNote": RenderNote,
|
||||||
|
"IsMultilineCommitMessage": IsMultilineCommitMessage,
|
||||||
"ThemeColorMetaTag": func() string {
|
"ThemeColorMetaTag": func() string {
|
||||||
return setting.UI.ThemeColorMetaTag
|
return setting.UI.ThemeColorMetaTag
|
||||||
},
|
},
|
||||||
|
@ -322,6 +323,24 @@ func RenderCommitMessageLink(msg, urlPrefix, urlDefault string, metas map[string
|
||||||
return template.HTML(msgLines[0])
|
return template.HTML(msgLines[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenderCommitMessageLinkSubject renders commit message as a XXS-safe link to
|
||||||
|
// the provided default url, handling for special links without email to links.
|
||||||
|
func RenderCommitMessageLinkSubject(msg, urlPrefix, urlDefault string, metas map[string]string) template.HTML {
|
||||||
|
cleanMsg := template.HTMLEscapeString(msg)
|
||||||
|
// we can safely assume that it will not return any error, since there
|
||||||
|
// shouldn't be any special HTML.
|
||||||
|
fullMessage, err := markup.RenderCommitMessageSubject([]byte(cleanMsg), urlPrefix, urlDefault, metas)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RenderCommitMessageSubject: %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
msgLines := strings.Split(strings.TrimSpace(string(fullMessage)), "\n")
|
||||||
|
if len(msgLines) == 0 {
|
||||||
|
return template.HTML("")
|
||||||
|
}
|
||||||
|
return template.HTML(msgLines[0])
|
||||||
|
}
|
||||||
|
|
||||||
// RenderCommitBody extracts the body of a commit message without its title.
|
// RenderCommitBody extracts the body of a commit message without its title.
|
||||||
func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.HTML {
|
func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.HTML {
|
||||||
cleanMsg := template.HTMLEscapeString(msg)
|
cleanMsg := template.HTMLEscapeString(msg)
|
||||||
|
|
|
@ -466,6 +466,10 @@ footer .ui.left,footer .ui.right{line-height:40px}
|
||||||
}
|
}
|
||||||
.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}
|
.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}
|
||||||
.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}
|
.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}
|
||||||
|
.repository.file.list #repo-files-table thead .commit-summary a{text-decoration:underline;-webkit-text-decoration-style:dashed;text-decoration-style:dashed}
|
||||||
|
.repository.file.list #repo-files-table thead .commit-summary a:hover{-webkit-text-decoration-style:solid;text-decoration-style:solid}
|
||||||
|
.repository.file.list #repo-files-table thead .commit-summary a.default-link{text-decoration:none}
|
||||||
|
.repository.file.list #repo-files-table thead .commit-summary a.default-link:hover{text-decoration:underline;-webkit-text-decoration-style:solid;text-decoration-style:solid}
|
||||||
.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}
|
.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}
|
||||||
.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}
|
.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}
|
||||||
.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}
|
.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}
|
||||||
|
@ -829,6 +833,10 @@ footer .ui.left,footer .ui.right{line-height:40px}
|
||||||
.stats-table .table-cell.tiny{height:.5em}
|
.stats-table .table-cell.tiny{height:.5em}
|
||||||
tbody.commit-list{vertical-align:baseline}
|
tbody.commit-list{vertical-align:baseline}
|
||||||
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
|
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
|
||||||
|
.commit-list .commit-summary a{text-decoration:underline;-webkit-text-decoration-style:dashed;text-decoration-style:dashed}
|
||||||
|
.commit-list .commit-summary a:hover{-webkit-text-decoration-style:solid;text-decoration-style:solid}
|
||||||
|
.commit-list .commit-summary a.default-link{text-decoration:none}
|
||||||
|
.commit-list .commit-summary a.default-link:hover{text-decoration:underline;-webkit-text-decoration-style:solid;text-decoration-style:solid}
|
||||||
.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
|
.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
|
||||||
.commit-body{white-space:pre-wrap}
|
.commit-body{white-space:pre-wrap}
|
||||||
.git-notes.top{text-align:left}
|
.git-notes.top{text-align:left}
|
||||||
|
|
|
@ -277,6 +277,24 @@
|
||||||
.ui.avatar {
|
.ui.avatar {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commit-summary a {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-style: dashed;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.default-link {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-style: solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody {
|
tbody {
|
||||||
|
@ -2188,6 +2206,24 @@ tbody.commit-list {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commit-list .commit-summary a {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-style: dashed;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.default-link {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-style: solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.commit-list .commit-status-link {
|
.commit-list .commit-status-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
|
@ -71,7 +71,8 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="message">
|
<td class="message">
|
||||||
<span class="message-wrapper">
|
<span class="message-wrapper">
|
||||||
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessage .Message $.RepoLink $.Repository.ComposeMetas}}</span>
|
{{ $commitLink:= printf "%s/%s/%s/commit/%s" AppSubUrl $.Username $.Reponame .ID }}
|
||||||
|
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject .Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span>
|
||||||
</span>
|
</span>
|
||||||
{{if IsMultilineCommitMessage .Message}}
|
{{if IsMultilineCommitMessage .Message}}
|
||||||
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
|
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</a>
|
</a>
|
||||||
{{template "repo/commit_status" .LatestCommitStatus}}
|
{{template "repo/commit_status" .LatestCommitStatus}}
|
||||||
<span class="grey has-emoji commit-summary" title="{{.LatestCommit.Summary}}">{{RenderCommitMessage .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}
|
{{ $commitLink:= printf "%s/commit/%s" .RepoLink .LatestCommit.ID }}
|
||||||
|
<span class="grey has-emoji commit-summary" title="{{.LatestCommit.Summary}}">{{RenderCommitMessageLinkSubject .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}
|
||||||
{{if IsMultilineCommitMessage .LatestCommit.Message}}
|
{{if IsMultilineCommitMessage .LatestCommit.Message}}
|
||||||
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
|
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
|
||||||
<pre class="commit-body" style="display: none;">{{RenderCommitBody .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre>
|
<pre class="commit-body" style="display: none;">{{RenderCommitBody .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre>
|
||||||
|
|
Loading…
Reference in a new issue