mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Add custom emoji support (#16004)
This commit is contained in:
@@ -6,7 +6,6 @@ package markup
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
@@ -66,7 +65,7 @@ var (
|
||||
blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`)
|
||||
|
||||
// EmojiShortCodeRegex find emoji by alias like :smile:
|
||||
EmojiShortCodeRegex = regexp.MustCompile(`\:[\w\+\-]+\:{1}`)
|
||||
EmojiShortCodeRegex = regexp.MustCompile(`:[\w\+\-]+:`)
|
||||
)
|
||||
|
||||
// CSS class for action keywords (e.g. "closes: #1")
|
||||
@@ -460,17 +459,14 @@ func createEmoji(content, class, name string) *html.Node {
|
||||
return span
|
||||
}
|
||||
|
||||
func createCustomEmoji(alias, class string) *html.Node {
|
||||
|
||||
func createCustomEmoji(alias string) *html.Node {
|
||||
span := &html.Node{
|
||||
Type: html.ElementNode,
|
||||
Data: atom.Span.String(),
|
||||
Attr: []html.Attribute{},
|
||||
}
|
||||
if class != "" {
|
||||
span.Attr = append(span.Attr, html.Attribute{Key: "class", Val: class})
|
||||
span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: alias})
|
||||
}
|
||||
span.Attr = append(span.Attr, html.Attribute{Key: "class", Val: "emoji"})
|
||||
span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: alias})
|
||||
|
||||
img := &html.Node{
|
||||
Type: html.ElementNode,
|
||||
@@ -478,10 +474,8 @@ func createCustomEmoji(alias, class string) *html.Node {
|
||||
Data: "img",
|
||||
Attr: []html.Attribute{},
|
||||
}
|
||||
if class != "" {
|
||||
img.Attr = append(img.Attr, html.Attribute{Key: "alt", Val: fmt.Sprintf(`:%s:`, alias)})
|
||||
img.Attr = append(img.Attr, html.Attribute{Key: "src", Val: fmt.Sprintf(`%s/assets/img/emoji/%s.png`, setting.StaticURLPrefix, alias)})
|
||||
}
|
||||
img.Attr = append(img.Attr, html.Attribute{Key: "alt", Val: ":" + alias + ":"})
|
||||
img.Attr = append(img.Attr, html.Attribute{Key: "src", Val: setting.StaticURLPrefix + "/assets/img/emoji/" + alias + ".png"})
|
||||
|
||||
span.AppendChild(img)
|
||||
return span
|
||||
@@ -948,9 +942,8 @@ func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) {
|
||||
converted := emoji.FromAlias(alias)
|
||||
if converted == nil {
|
||||
// check if this is a custom reaction
|
||||
s := strings.Join(setting.UI.Reactions, " ") + "gitea"
|
||||
if strings.Contains(s, alias) {
|
||||
replaceContent(node, m[0], m[1], createCustomEmoji(alias, "emoji"))
|
||||
if _, exist := setting.UI.CustomEmojisMap[alias]; exist {
|
||||
replaceContent(node, m[0], m[1], createCustomEmoji(alias))
|
||||
node = node.NextSibling.NextSibling
|
||||
start = 0
|
||||
continue
|
||||
|
@@ -284,7 +284,18 @@ func TestRender_emoji(t *testing.T) {
|
||||
test(
|
||||
":gitea:",
|
||||
`<p><span class="emoji" aria-label="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`)
|
||||
|
||||
test(
|
||||
":custom-emoji:",
|
||||
`<p>:custom-emoji:</p>`)
|
||||
setting.UI.CustomEmojisMap["custom-emoji"] = ":custom-emoji:"
|
||||
test(
|
||||
":custom-emoji:",
|
||||
`<p><span class="emoji" aria-label="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span></p>`)
|
||||
test(
|
||||
"这是字符:1::+1: some🐊 \U0001f44d:custom-emoji: :gitea:",
|
||||
`<p>这是字符:1:<span class="emoji" aria-label="thumbs up">👍</span> some<span class="emoji" aria-label="crocodile">🐊</span> `+
|
||||
`<span class="emoji" aria-label="thumbs up">👍</span><span class="emoji" aria-label="custom-emoji"><img alt=":custom-emoji:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/custom-emoji.png"/></span> `+
|
||||
`<span class="emoji" aria-label="gitea"><img alt=":gitea:" src="`+setting.StaticURLPrefix+`/assets/img/emoji/gitea.png"/></span></p>`)
|
||||
test(
|
||||
"Some text with 😄 in the middle",
|
||||
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span> in the middle</p>`)
|
||||
|
@@ -208,7 +208,9 @@ var (
|
||||
DefaultTheme string
|
||||
Themes []string
|
||||
Reactions []string
|
||||
ReactionsMap map[string]bool
|
||||
ReactionsMap map[string]bool `ini:"-"`
|
||||
CustomEmojis []string
|
||||
CustomEmojisMap map[string]string `ini:"-"`
|
||||
SearchRepoDescription bool
|
||||
UseServiceWorker bool
|
||||
|
||||
@@ -256,6 +258,8 @@ var (
|
||||
DefaultTheme: `gitea`,
|
||||
Themes: []string{`gitea`, `arc-green`},
|
||||
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
|
||||
CustomEmojis: []string{`gitea`},
|
||||
CustomEmojisMap: map[string]string{"gitea": ":gitea:"},
|
||||
Notification: struct {
|
||||
MinTimeout time.Duration
|
||||
TimeoutStep time.Duration
|
||||
@@ -983,6 +987,10 @@ func NewContext() {
|
||||
for _, reaction := range UI.Reactions {
|
||||
UI.ReactionsMap[reaction] = true
|
||||
}
|
||||
UI.CustomEmojisMap = make(map[string]string)
|
||||
for _, emoji := range UI.CustomEmojis {
|
||||
UI.CustomEmojisMap[emoji] = ":" + emoji + ":"
|
||||
}
|
||||
}
|
||||
|
||||
func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
|
||||
|
@@ -18,6 +18,7 @@ type GeneralRepoSettings struct {
|
||||
type GeneralUISettings struct {
|
||||
DefaultTheme string `json:"default_theme"`
|
||||
AllowedReactions []string `json:"allowed_reactions"`
|
||||
CustomEmojis []string `json:"custom_emojis"`
|
||||
}
|
||||
|
||||
// GeneralAPISettings contains global api settings exposed by it
|
||||
|
@@ -90,6 +90,9 @@ func NewFuncMap() []template.FuncMap {
|
||||
"AllowedReactions": func() []string {
|
||||
return setting.UI.Reactions
|
||||
},
|
||||
"CustomEmojis": func() map[string]string {
|
||||
return setting.UI.CustomEmojisMap
|
||||
},
|
||||
"Safe": Safe,
|
||||
"SafeJS": SafeJS,
|
||||
"JSEscape": JSEscape,
|
||||
|
Reference in New Issue
Block a user