Skip to content

Commit c5df0ce

Browse files
committed
fix
1 parent 6ed1b26 commit c5df0ce

File tree

8 files changed

+136
-109
lines changed

8 files changed

+136
-109
lines changed

modules/markup/markdown/ast.go

+25-29
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package markdown
55

66
import (
7+
"html/template"
78
"strconv"
89

910
"github.com/yuin/goldmark/ast"
@@ -29,14 +30,13 @@ func (n *Details) Kind() ast.NodeKind {
2930

3031
// NewDetails returns a new Paragraph node.
3132
func NewDetails() *Details {
32-
return &Details{
33-
BaseBlock: ast.BaseBlock{},
34-
}
33+
return &Details{}
3534
}
3635

3736
// Summary is a block that contains the summary of details block
3837
type Summary struct {
3938
ast.BaseBlock
39+
HTMLClass string
4040
}
4141

4242
// Dump implements Node.Dump .
@@ -54,9 +54,7 @@ func (n *Summary) Kind() ast.NodeKind {
5454

5555
// NewSummary returns a new Summary node.
5656
func NewSummary() *Summary {
57-
return &Summary{
58-
BaseBlock: ast.BaseBlock{},
59-
}
57+
return &Summary{}
6058
}
6159

6260
// TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox
@@ -95,29 +93,6 @@ type Icon struct {
9593
Name []byte
9694
}
9795

98-
// Dump implements Node.Dump .
99-
func (n *Icon) Dump(source []byte, level int) {
100-
m := map[string]string{}
101-
m["Name"] = string(n.Name)
102-
ast.DumpHelper(n, source, level, m, nil)
103-
}
104-
105-
// KindIcon is the NodeKind for Icon
106-
var KindIcon = ast.NewNodeKind("Icon")
107-
108-
// Kind implements Node.Kind.
109-
func (n *Icon) Kind() ast.NodeKind {
110-
return KindIcon
111-
}
112-
113-
// NewIcon returns a new Paragraph node.
114-
func NewIcon(name string) *Icon {
115-
return &Icon{
116-
BaseInline: ast.BaseInline{},
117-
Name: []byte(name),
118-
}
119-
}
120-
12196
// ColorPreview is an inline for a color preview
12297
type ColorPreview struct {
12398
ast.BaseInline
@@ -175,3 +150,24 @@ func NewAttention(attentionType string) *Attention {
175150
AttentionType: attentionType,
176151
}
177152
}
153+
154+
var KindRawHTML = ast.NewNodeKind("RawHTML")
155+
156+
type RawHTML struct {
157+
ast.BaseBlock
158+
rawHTML template.HTML
159+
}
160+
161+
func (n *RawHTML) Dump(source []byte, level int) {
162+
m := map[string]string{}
163+
m["RawHTML"] = string(n.rawHTML)
164+
ast.DumpHelper(n, source, level, m, nil)
165+
}
166+
167+
func (n *RawHTML) Kind() ast.NodeKind {
168+
return KindRawHTML
169+
}
170+
171+
func NewRawHTML(rawHTML template.HTML) *RawHTML {
172+
return &RawHTML{rawHTML: rawHTML}
173+
}

modules/markup/markdown/convertyaml.go

+27-14
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,20 @@
44
package markdown
55

66
import (
7+
"code.gitea.io/gitea/modules/htmlutil"
8+
"code.gitea.io/gitea/modules/svg"
79
"github.com/yuin/goldmark/ast"
810
east "github.com/yuin/goldmark/extension/ast"
911
"gopkg.in/yaml.v3"
12+
"strings"
1013
)
1114

1215
func nodeToTable(meta *yaml.Node) ast.Node {
13-
for {
14-
if meta == nil {
15-
return nil
16-
}
17-
switch meta.Kind {
18-
case yaml.DocumentNode:
19-
meta = meta.Content[0]
20-
continue
21-
default:
22-
}
23-
break
16+
for meta != nil && meta.Kind == yaml.DocumentNode {
17+
meta = meta.Content[0]
18+
}
19+
if meta == nil {
20+
return nil
2421
}
2522
switch meta.Kind {
2623
case yaml.MappingNode:
@@ -72,12 +69,28 @@ func sequenceNodeToTable(meta *yaml.Node) ast.Node {
7269
return table
7370
}
7471

75-
func nodeToDetails(meta *yaml.Node, icon string) ast.Node {
72+
func nodeToDetails(g *ASTTransformer, meta *yaml.Node) ast.Node {
73+
for meta != nil && meta.Kind == yaml.DocumentNode {
74+
meta = meta.Content[0]
75+
}
76+
if meta == nil {
77+
return nil
78+
}
79+
if meta.Kind != yaml.MappingNode {
80+
return nil
81+
}
82+
var keys []string
83+
for i := 0; i < len(meta.Content); i += 2 {
84+
if meta.Content[i].Kind == yaml.ScalarNode {
85+
keys = append(keys, meta.Content[i].Value)
86+
}
87+
}
7688
details := NewDetails()
89+
details.SetAttributeString(g.renderInternal.SafeAttr("class"), g.renderInternal.SafeValue("frontmatter-content"))
7790
summary := NewSummary()
78-
summary.AppendChild(summary, NewIcon(icon))
91+
summaryInnerHTML := htmlutil.HTMLFormat("%s %s", svg.RenderHTML("octicon-table", 12), strings.Join(keys, ", "))
92+
summary.AppendChild(summary, NewRawHTML(summaryInnerHTML))
7993
details.AppendChild(details, summary)
8094
details.AppendChild(details, nodeToTable(meta))
81-
8295
return details
8396
}

modules/markup/markdown/goldmark.go

+6-32
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@
44
package markdown
55

66
import (
7-
"fmt"
8-
"regexp"
9-
"strings"
10-
"sync"
11-
127
"code.gitea.io/gitea/modules/container"
138
"code.gitea.io/gitea/modules/markup"
149
"code.gitea.io/gitea/modules/markup/internal"
1510
"code.gitea.io/gitea/modules/setting"
16-
11+
"fmt"
1712
"github.com/yuin/goldmark/ast"
1813
east "github.com/yuin/goldmark/extension/ast"
1914
"github.com/yuin/goldmark/parser"
@@ -51,7 +46,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
5146

5247
tocList := make([]Header, 0, 20)
5348
if rc.yamlNode != nil {
54-
metaNode := rc.toMetaNode()
49+
metaNode := rc.toMetaNode(g)
5550
if metaNode != nil {
5651
node.InsertBefore(node, firstChild, metaNode)
5752
}
@@ -112,11 +107,6 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
112107
}
113108
}
114109

115-
// it is copied from old code, which is quite doubtful whether it is correct
116-
var reValidIconName = sync.OnceValue(func() *regexp.Regexp {
117-
return regexp.MustCompile(`^[-\w]+$`) // old: regexp.MustCompile("^[a-z ]+$")
118-
})
119-
120110
// NewHTMLRenderer creates a HTMLRenderer to render in the gitea form.
121111
func NewHTMLRenderer(renderInternal *internal.RenderInternal, opts ...html.Option) renderer.NodeRenderer {
122112
r := &HTMLRenderer{
@@ -141,11 +131,11 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
141131
reg.Register(ast.KindDocument, r.renderDocument)
142132
reg.Register(KindDetails, r.renderDetails)
143133
reg.Register(KindSummary, r.renderSummary)
144-
reg.Register(KindIcon, r.renderIcon)
145134
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
146135
reg.Register(KindAttention, r.renderAttention)
147136
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
148137
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
138+
reg.Register(KindRawHTML, r.renderRawHTML)
149139
}
150140

151141
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
@@ -207,30 +197,14 @@ func (r *HTMLRenderer) renderSummary(w util.BufWriter, source []byte, node ast.N
207197
return ast.WalkContinue, nil
208198
}
209199

210-
func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
200+
func (r *HTMLRenderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
211201
if !entering {
212202
return ast.WalkContinue, nil
213203
}
214-
215-
n := node.(*Icon)
216-
217-
name := strings.TrimSpace(strings.ToLower(string(n.Name)))
218-
219-
if len(name) == 0 {
220-
// skip this
221-
return ast.WalkContinue, nil
222-
}
223-
224-
if !reValidIconName().MatchString(name) {
225-
// skip this
226-
return ast.WalkContinue, nil
227-
}
228-
229-
// FIXME: the "icon xxx" is from Fomantic UI, it's really questionable whether it still works correctly
230-
err := r.renderInternal.FormatWithSafeAttrs(w, `<i class="icon %s"></i>`, name)
204+
n := node.(*RawHTML)
205+
_, err := w.WriteString(string(r.renderInternal.ProtectSafeAttrs(n.rawHTML)))
231206
if err != nil {
232207
return ast.WalkStop, err
233208
}
234-
235209
return ast.WalkContinue, nil
236210
}

modules/markup/markdown/markdown.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,7 @@ func render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
184184
// Preserve original length.
185185
bufWithMetadataLength := len(buf)
186186

187-
rc := &RenderConfig{
188-
Meta: markup.RenderMetaAsDetails,
189-
Icon: "table",
190-
Lang: "",
191-
}
187+
rc := &RenderConfig{Meta: markup.RenderMetaAsDetails}
192188
buf, _ = ExtractMetadataBytes(buf, rc)
193189

194190
metaLength := bufWithMetadataLength - len(buf)

modules/markup/markdown/markdown_test.go

+62-6
Original file line numberDiff line numberDiff line change
@@ -383,18 +383,74 @@ func TestColorPreview(t *testing.T) {
383383
}
384384
}
385385

386-
func TestTaskList(t *testing.T) {
386+
func TestMarkdownFrontmatter(t *testing.T) {
387387
testcases := []struct {
388-
testcase string
388+
name string
389+
input string
389390
expected string
390391
}{
392+
{
393+
"MapInFrontmatter",
394+
`---
395+
key1: val1
396+
key2: val2
397+
---
398+
test
399+
`,
400+
`<details class="frontmatter-content"><summary><span>octicon-table(12/)</span> key1, key2</summary><table>
401+
<thead>
402+
<tr>
403+
<th>key1</th>
404+
<th>key2</th>
405+
</tr>
406+
</thead>
407+
<tbody>
408+
<tr>
409+
<td>val1</td>
410+
<td>val2</td>
411+
</tr>
412+
</tbody>
413+
</table>
414+
</details><p>test</p>
415+
`,
416+
},
417+
418+
{
419+
"ListInFrontmatter",
420+
`---
421+
- item1
422+
- item2
423+
---
424+
test
425+
`,
426+
`- item1
427+
- item2
428+
429+
<p>test</p>
430+
`,
431+
},
432+
433+
{
434+
"StringInFrontmatter",
435+
`---
436+
anything
437+
---
438+
test
439+
`,
440+
`anything
441+
442+
<p>test</p>
443+
`,
444+
},
445+
391446
{
392447
// data-source-position should take into account YAML frontmatter.
448+
"ListAfterFrontmatter",
393449
`---
394450
foo: bar
395451
---
396452
- [ ] task 1`,
397-
`<details><summary><i class="icon table"></i></summary><table>
453+
`<details class="frontmatter-content"><summary><span>octicon-table(12/)</span> foo</summary><table>
398454
<thead>
399455
<tr>
400456
<th>foo</th>
@@ -414,9 +470,9 @@ foo: bar
414470
}
415471

416472
for _, test := range testcases {
417-
res, err := markdown.RenderString(markup.NewTestRenderContext(), test.testcase)
418-
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
419-
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
473+
res, err := markdown.RenderString(markup.NewTestRenderContext(), test.input)
474+
assert.NoError(t, err, "Unexpected error in testcase: %q", test.name)
475+
assert.Equal(t, test.expected, string(res), "Unexpected result in testcase %q", test.name)
420476
}
421477
}
422478

modules/markup/markdown/renderconfig.go

+3-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
// RenderConfig represents rendering configuration for this file
1717
type RenderConfig struct {
1818
Meta markup.RenderMetaMode
19-
Icon string
2019
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
2120
Lang string
2221
yamlNode *yaml.Node
@@ -74,7 +73,7 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
7473

7574
type yamlRenderConfig struct {
7675
Meta *string `yaml:"meta"`
77-
Icon *string `yaml:"details_icon"`
76+
Icon *string `yaml:"details_icon"` // deprecated, because there is no font icon, so no custom icon
7877
TOC *string `yaml:"include_toc"`
7978
Lang *string `yaml:"lang"`
8079
}
@@ -96,10 +95,6 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
9695
rc.Meta = renderMetaModeFromString(*cfg.Gitea.Meta)
9796
}
9897

99-
if cfg.Gitea.Icon != nil {
100-
rc.Icon = strings.TrimSpace(strings.ToLower(*cfg.Gitea.Icon))
101-
}
102-
10398
if cfg.Gitea.Lang != nil && *cfg.Gitea.Lang != "" {
10499
rc.Lang = *cfg.Gitea.Lang
105100
}
@@ -111,15 +106,15 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
111106
return nil
112107
}
113108

114-
func (rc *RenderConfig) toMetaNode() ast.Node {
109+
func (rc *RenderConfig) toMetaNode(g *ASTTransformer) ast.Node {
115110
if rc.yamlNode == nil {
116111
return nil
117112
}
118113
switch rc.Meta {
119114
case markup.RenderMetaAsTable:
120115
return nodeToTable(rc.yamlNode)
121116
case markup.RenderMetaAsDetails:
122-
return nodeToDetails(rc.yamlNode, rc.Icon)
117+
return nodeToDetails(g, rc.yamlNode)
123118
default:
124119
return nil
125120
}

0 commit comments

Comments
 (0)