| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // Copyright 2024 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package markup
-
- import (
- "strings"
-
- "code.gitea.io/gitea/modules/emoji"
- "code.gitea.io/gitea/modules/setting"
-
- "golang.org/x/net/html"
- "golang.org/x/net/html/atom"
- )
-
- func createEmoji(ctx *RenderContext, content, name string) *html.Node {
- span := &html.Node{
- Type: html.ElementNode,
- Data: atom.Span.String(),
- Attr: []html.Attribute{},
- }
- span.Attr = append(span.Attr, ctx.RenderInternal.NodeSafeAttr("class", "emoji"))
- if name != "" {
- span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: name})
- }
-
- text := &html.Node{
- Type: html.TextNode,
- Data: content,
- }
-
- span.AppendChild(text)
- return span
- }
-
- func createCustomEmoji(ctx *RenderContext, alias string) *html.Node {
- span := &html.Node{
- Type: html.ElementNode,
- Data: atom.Span.String(),
- Attr: []html.Attribute{},
- }
- span.Attr = append(span.Attr, ctx.RenderInternal.NodeSafeAttr("class", "emoji"))
- span.Attr = append(span.Attr, html.Attribute{Key: "aria-label", Val: alias})
-
- img := &html.Node{
- Type: html.ElementNode,
- DataAtom: atom.Img,
- Data: "img",
- Attr: []html.Attribute{},
- }
- 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
- }
-
- // emojiShortCodeProcessor for rendering text like :smile: into emoji
- func emojiShortCodeProcessor(ctx *RenderContext, node *html.Node) {
- start := 0
- next := node.NextSibling
- for node != nil && node != next && start < len(node.Data) {
- m := globalVars().emojiShortCodeRegex.FindStringSubmatchIndex(node.Data[start:])
- if m == nil {
- return
- }
- m[0] += start
- m[1] += start
-
- start = m[1]
-
- alias := node.Data[m[0]:m[1]]
- alias = strings.ReplaceAll(alias, ":", "")
- converted := emoji.FromAlias(alias)
- if converted == nil {
- // check if this is a custom reaction
- if _, exist := setting.UI.CustomEmojisMap[alias]; exist {
- replaceContent(node, m[0], m[1], createCustomEmoji(ctx, alias))
- node = node.NextSibling.NextSibling
- start = 0
- continue
- }
- continue
- }
-
- replaceContent(node, m[0], m[1], createEmoji(ctx, converted.Emoji, converted.Description))
- node = node.NextSibling.NextSibling
- start = 0
- }
- }
-
- // emoji processor to match emoji and add emoji class
- func emojiProcessor(ctx *RenderContext, node *html.Node) {
- start := 0
- next := node.NextSibling
- for node != nil && node != next && start < len(node.Data) {
- m := emoji.FindEmojiSubmatchIndex(node.Data[start:])
- if m == nil {
- return
- }
- m[0] += start
- m[1] += start
-
- codepoint := node.Data[m[0]:m[1]]
- start = m[1]
- val := emoji.FromCode(codepoint)
- if val != nil {
- replaceContent(node, m[0], m[1], createEmoji(ctx, codepoint, val.Description))
- node = node.NextSibling.NextSibling
- start = 0
- }
- }
- }
|