mirror of https://github.com/go-gitea/gitea.git
parent
f94ee4fd3c
commit
ba921fd903
|
@ -4,6 +4,7 @@
|
||||||
package markdown
|
package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
|
@ -29,9 +30,7 @@ func (n *Details) Kind() ast.NodeKind {
|
||||||
|
|
||||||
// NewDetails returns a new Paragraph node.
|
// NewDetails returns a new Paragraph node.
|
||||||
func NewDetails() *Details {
|
func NewDetails() *Details {
|
||||||
return &Details{
|
return &Details{}
|
||||||
BaseBlock: ast.BaseBlock{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summary is a block that contains the summary of details block
|
// Summary is a block that contains the summary of details block
|
||||||
|
@ -54,9 +53,7 @@ func (n *Summary) Kind() ast.NodeKind {
|
||||||
|
|
||||||
// NewSummary returns a new Summary node.
|
// NewSummary returns a new Summary node.
|
||||||
func NewSummary() *Summary {
|
func NewSummary() *Summary {
|
||||||
return &Summary{
|
return &Summary{}
|
||||||
BaseBlock: ast.BaseBlock{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox
|
// TaskCheckBoxListItem is a block that represents a list item of a markdown block with a checkbox
|
||||||
|
@ -95,29 +92,6 @@ type Icon struct {
|
||||||
Name []byte
|
Name []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump implements Node.Dump .
|
|
||||||
func (n *Icon) Dump(source []byte, level int) {
|
|
||||||
m := map[string]string{}
|
|
||||||
m["Name"] = string(n.Name)
|
|
||||||
ast.DumpHelper(n, source, level, m, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KindIcon is the NodeKind for Icon
|
|
||||||
var KindIcon = ast.NewNodeKind("Icon")
|
|
||||||
|
|
||||||
// Kind implements Node.Kind.
|
|
||||||
func (n *Icon) Kind() ast.NodeKind {
|
|
||||||
return KindIcon
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewIcon returns a new Paragraph node.
|
|
||||||
func NewIcon(name string) *Icon {
|
|
||||||
return &Icon{
|
|
||||||
BaseInline: ast.BaseInline{},
|
|
||||||
Name: []byte(name),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColorPreview is an inline for a color preview
|
// ColorPreview is an inline for a color preview
|
||||||
type ColorPreview struct {
|
type ColorPreview struct {
|
||||||
ast.BaseInline
|
ast.BaseInline
|
||||||
|
@ -175,3 +149,24 @@ func NewAttention(attentionType string) *Attention {
|
||||||
AttentionType: attentionType,
|
AttentionType: attentionType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var KindRawHTML = ast.NewNodeKind("RawHTML")
|
||||||
|
|
||||||
|
type RawHTML struct {
|
||||||
|
ast.BaseBlock
|
||||||
|
rawHTML template.HTML
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *RawHTML) Dump(source []byte, level int) {
|
||||||
|
m := map[string]string{}
|
||||||
|
m["RawHTML"] = string(n.rawHTML)
|
||||||
|
ast.DumpHelper(n, source, level, m, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *RawHTML) Kind() ast.NodeKind {
|
||||||
|
return KindRawHTML
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRawHTML(rawHTML template.HTML) *RawHTML {
|
||||||
|
return &RawHTML{rawHTML: rawHTML}
|
||||||
|
}
|
||||||
|
|
|
@ -4,23 +4,22 @@
|
||||||
package markdown
|
package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/htmlutil"
|
||||||
|
"code.gitea.io/gitea/modules/svg"
|
||||||
|
|
||||||
"github.com/yuin/goldmark/ast"
|
"github.com/yuin/goldmark/ast"
|
||||||
east "github.com/yuin/goldmark/extension/ast"
|
east "github.com/yuin/goldmark/extension/ast"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func nodeToTable(meta *yaml.Node) ast.Node {
|
func nodeToTable(meta *yaml.Node) ast.Node {
|
||||||
for {
|
for meta != nil && meta.Kind == yaml.DocumentNode {
|
||||||
if meta == nil {
|
meta = meta.Content[0]
|
||||||
return nil
|
}
|
||||||
}
|
if meta == nil {
|
||||||
switch meta.Kind {
|
return nil
|
||||||
case yaml.DocumentNode:
|
|
||||||
meta = meta.Content[0]
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
switch meta.Kind {
|
switch meta.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
|
@ -72,12 +71,28 @@ func sequenceNodeToTable(meta *yaml.Node) ast.Node {
|
||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeToDetails(meta *yaml.Node, icon string) ast.Node {
|
func nodeToDetails(g *ASTTransformer, meta *yaml.Node) ast.Node {
|
||||||
|
for meta != nil && meta.Kind == yaml.DocumentNode {
|
||||||
|
meta = meta.Content[0]
|
||||||
|
}
|
||||||
|
if meta == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if meta.Kind != yaml.MappingNode {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var keys []string
|
||||||
|
for i := 0; i < len(meta.Content); i += 2 {
|
||||||
|
if meta.Content[i].Kind == yaml.ScalarNode {
|
||||||
|
keys = append(keys, meta.Content[i].Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
details := NewDetails()
|
details := NewDetails()
|
||||||
|
details.SetAttributeString(g.renderInternal.SafeAttr("class"), g.renderInternal.SafeValue("frontmatter-content"))
|
||||||
summary := NewSummary()
|
summary := NewSummary()
|
||||||
summary.AppendChild(summary, NewIcon(icon))
|
summaryInnerHTML := htmlutil.HTMLFormat("%s %s", svg.RenderHTML("octicon-table", 12), strings.Join(keys, ", "))
|
||||||
|
summary.AppendChild(summary, NewRawHTML(summaryInnerHTML))
|
||||||
details.AppendChild(details, summary)
|
details.AppendChild(details, summary)
|
||||||
details.AppendChild(details, nodeToTable(meta))
|
details.AppendChild(details, nodeToTable(meta))
|
||||||
|
|
||||||
return details
|
return details
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,6 @@ package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
|
@ -51,7 +48,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
||||||
|
|
||||||
tocList := make([]Header, 0, 20)
|
tocList := make([]Header, 0, 20)
|
||||||
if rc.yamlNode != nil {
|
if rc.yamlNode != nil {
|
||||||
metaNode := rc.toMetaNode()
|
metaNode := rc.toMetaNode(g)
|
||||||
if metaNode != nil {
|
if metaNode != nil {
|
||||||
node.InsertBefore(node, firstChild, metaNode)
|
node.InsertBefore(node, firstChild, metaNode)
|
||||||
}
|
}
|
||||||
|
@ -112,11 +109,6 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is copied from old code, which is quite doubtful whether it is correct
|
|
||||||
var reValidIconName = sync.OnceValue(func() *regexp.Regexp {
|
|
||||||
return regexp.MustCompile(`^[-\w]+$`) // old: regexp.MustCompile("^[a-z ]+$")
|
|
||||||
})
|
|
||||||
|
|
||||||
// NewHTMLRenderer creates a HTMLRenderer to render in the gitea form.
|
// NewHTMLRenderer creates a HTMLRenderer to render in the gitea form.
|
||||||
func NewHTMLRenderer(renderInternal *internal.RenderInternal, opts ...html.Option) renderer.NodeRenderer {
|
func NewHTMLRenderer(renderInternal *internal.RenderInternal, opts ...html.Option) renderer.NodeRenderer {
|
||||||
r := &HTMLRenderer{
|
r := &HTMLRenderer{
|
||||||
|
@ -141,11 +133,11 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
||||||
reg.Register(ast.KindDocument, r.renderDocument)
|
reg.Register(ast.KindDocument, r.renderDocument)
|
||||||
reg.Register(KindDetails, r.renderDetails)
|
reg.Register(KindDetails, r.renderDetails)
|
||||||
reg.Register(KindSummary, r.renderSummary)
|
reg.Register(KindSummary, r.renderSummary)
|
||||||
reg.Register(KindIcon, r.renderIcon)
|
|
||||||
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
|
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
|
||||||
reg.Register(KindAttention, r.renderAttention)
|
reg.Register(KindAttention, r.renderAttention)
|
||||||
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
|
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
|
||||||
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
|
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
|
||||||
|
reg.Register(KindRawHTML, r.renderRawHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
|
@ -207,30 +199,14 @@ func (r *HTMLRenderer) renderSummary(w util.BufWriter, source []byte, node ast.N
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *HTMLRenderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if !entering {
|
if !entering {
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
n := node.(*RawHTML)
|
||||||
n := node.(*Icon)
|
_, err := w.WriteString(string(r.renderInternal.ProtectSafeAttrs(n.rawHTML)))
|
||||||
|
|
||||||
name := strings.TrimSpace(strings.ToLower(string(n.Name)))
|
|
||||||
|
|
||||||
if len(name) == 0 {
|
|
||||||
// skip this
|
|
||||||
return ast.WalkContinue, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reValidIconName().MatchString(name) {
|
|
||||||
// skip this
|
|
||||||
return ast.WalkContinue, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: the "icon xxx" is from Fomantic UI, it's really questionable whether it still works correctly
|
|
||||||
err := r.renderInternal.FormatWithSafeAttrs(w, `<i class="icon %s"></i>`, name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ast.WalkStop, err
|
return ast.WalkStop, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,11 +184,7 @@ func render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
|
||||||
// Preserve original length.
|
// Preserve original length.
|
||||||
bufWithMetadataLength := len(buf)
|
bufWithMetadataLength := len(buf)
|
||||||
|
|
||||||
rc := &RenderConfig{
|
rc := &RenderConfig{Meta: markup.RenderMetaAsDetails}
|
||||||
Meta: markup.RenderMetaAsDetails,
|
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
|
||||||
}
|
|
||||||
buf, _ = ExtractMetadataBytes(buf, rc)
|
buf, _ = ExtractMetadataBytes(buf, rc)
|
||||||
|
|
||||||
metaLength := bufWithMetadataLength - len(buf)
|
metaLength := bufWithMetadataLength - len(buf)
|
||||||
|
|
|
@ -383,18 +383,74 @@ func TestColorPreview(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTaskList(t *testing.T) {
|
func TestMarkdownFrontmatter(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
testcase string
|
name string
|
||||||
|
input string
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
"MapInFrontmatter",
|
||||||
|
`---
|
||||||
|
key1: val1
|
||||||
|
key2: val2
|
||||||
|
---
|
||||||
|
test
|
||||||
|
`,
|
||||||
|
`<details class="frontmatter-content"><summary><span>octicon-table(12/)</span> key1, key2</summary><table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>key1</th>
|
||||||
|
<th>key2</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>val1</td>
|
||||||
|
<td>val2</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</details><p>test</p>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"ListInFrontmatter",
|
||||||
|
`---
|
||||||
|
- item1
|
||||||
|
- item2
|
||||||
|
---
|
||||||
|
test
|
||||||
|
`,
|
||||||
|
`- item1
|
||||||
|
- item2
|
||||||
|
|
||||||
|
<p>test</p>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"StringInFrontmatter",
|
||||||
|
`---
|
||||||
|
anything
|
||||||
|
---
|
||||||
|
test
|
||||||
|
`,
|
||||||
|
`anything
|
||||||
|
|
||||||
|
<p>test</p>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// data-source-position should take into account YAML frontmatter.
|
// data-source-position should take into account YAML frontmatter.
|
||||||
|
"ListAfterFrontmatter",
|
||||||
`---
|
`---
|
||||||
foo: bar
|
foo: bar
|
||||||
---
|
---
|
||||||
- [ ] task 1`,
|
- [ ] task 1`,
|
||||||
`<details><summary><i class="icon table"></i></summary><table>
|
`<details class="frontmatter-content"><summary><span>octicon-table(12/)</span> foo</summary><table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>foo</th>
|
<th>foo</th>
|
||||||
|
@ -414,9 +470,9 @@ foo: bar
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testcases {
|
for _, test := range testcases {
|
||||||
res, err := markdown.RenderString(markup.NewTestRenderContext(), test.testcase)
|
res, err := markdown.RenderString(markup.NewTestRenderContext(), test.input)
|
||||||
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
|
assert.NoError(t, err, "Unexpected error in testcase: %q", test.name)
|
||||||
assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase)
|
assert.Equal(t, test.expected, string(res), "Unexpected result in testcase %q", test.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
// RenderConfig represents rendering configuration for this file
|
// RenderConfig represents rendering configuration for this file
|
||||||
type RenderConfig struct {
|
type RenderConfig struct {
|
||||||
Meta markup.RenderMetaMode
|
Meta markup.RenderMetaMode
|
||||||
Icon string
|
|
||||||
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
|
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
|
||||||
Lang string
|
Lang string
|
||||||
yamlNode *yaml.Node
|
yamlNode *yaml.Node
|
||||||
|
@ -74,7 +73,7 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
|
||||||
|
|
||||||
type yamlRenderConfig struct {
|
type yamlRenderConfig struct {
|
||||||
Meta *string `yaml:"meta"`
|
Meta *string `yaml:"meta"`
|
||||||
Icon *string `yaml:"details_icon"`
|
Icon *string `yaml:"details_icon"` // deprecated, because there is no font icon, so no custom icon
|
||||||
TOC *string `yaml:"include_toc"`
|
TOC *string `yaml:"include_toc"`
|
||||||
Lang *string `yaml:"lang"`
|
Lang *string `yaml:"lang"`
|
||||||
}
|
}
|
||||||
|
@ -96,10 +95,6 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
|
||||||
rc.Meta = renderMetaModeFromString(*cfg.Gitea.Meta)
|
rc.Meta = renderMetaModeFromString(*cfg.Gitea.Meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Gitea.Icon != nil {
|
|
||||||
rc.Icon = strings.TrimSpace(strings.ToLower(*cfg.Gitea.Icon))
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Gitea.Lang != nil && *cfg.Gitea.Lang != "" {
|
if cfg.Gitea.Lang != nil && *cfg.Gitea.Lang != "" {
|
||||||
rc.Lang = *cfg.Gitea.Lang
|
rc.Lang = *cfg.Gitea.Lang
|
||||||
}
|
}
|
||||||
|
@ -111,7 +106,7 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RenderConfig) toMetaNode() ast.Node {
|
func (rc *RenderConfig) toMetaNode(g *ASTTransformer) ast.Node {
|
||||||
if rc.yamlNode == nil {
|
if rc.yamlNode == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -119,7 +114,7 @@ func (rc *RenderConfig) toMetaNode() ast.Node {
|
||||||
case markup.RenderMetaAsTable:
|
case markup.RenderMetaAsTable:
|
||||||
return nodeToTable(rc.yamlNode)
|
return nodeToTable(rc.yamlNode)
|
||||||
case markup.RenderMetaAsDetails:
|
case markup.RenderMetaAsDetails:
|
||||||
return nodeToDetails(rc.yamlNode, rc.Icon)
|
return nodeToDetails(g, rc.yamlNode)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,42 +21,36 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
{
|
{
|
||||||
"empty", &RenderConfig{
|
"empty", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "",
|
}, "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lang", &RenderConfig{
|
"lang", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "test",
|
Lang: "test",
|
||||||
}, "lang: test",
|
}, "lang: test",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metatable", &RenderConfig{
|
"metatable", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "gitea: table",
|
}, "gitea: table",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metanone", &RenderConfig{
|
"metanone", &RenderConfig{
|
||||||
Meta: "none",
|
Meta: "none",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "gitea: none",
|
}, "gitea: none",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metadetails", &RenderConfig{
|
"metadetails", &RenderConfig{
|
||||||
Meta: "details",
|
Meta: "details",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "gitea: details",
|
}, "gitea: details",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"metawrong", &RenderConfig{
|
"metawrong", &RenderConfig{
|
||||||
Meta: "details",
|
Meta: "details",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "gitea: wrong",
|
}, "gitea: wrong",
|
||||||
},
|
},
|
||||||
|
@ -64,7 +58,6 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
"toc", &RenderConfig{
|
"toc", &RenderConfig{
|
||||||
TOC: "true",
|
TOC: "true",
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "include_toc: true",
|
}, "include_toc: true",
|
||||||
},
|
},
|
||||||
|
@ -72,14 +65,12 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
"tocfalse", &RenderConfig{
|
"tocfalse", &RenderConfig{
|
||||||
TOC: "false",
|
TOC: "false",
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}, "include_toc: false",
|
}, "include_toc: false",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"toclang", &RenderConfig{
|
"toclang", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
TOC: "true",
|
TOC: "true",
|
||||||
Lang: "testlang",
|
Lang: "testlang",
|
||||||
}, `
|
}, `
|
||||||
|
@ -90,7 +81,6 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
{
|
{
|
||||||
"complexlang", &RenderConfig{
|
"complexlang", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "testlang",
|
Lang: "testlang",
|
||||||
}, `
|
}, `
|
||||||
gitea:
|
gitea:
|
||||||
|
@ -100,7 +90,6 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
{
|
{
|
||||||
"complexlang2", &RenderConfig{
|
"complexlang2", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "testlang",
|
Lang: "testlang",
|
||||||
}, `
|
}, `
|
||||||
lang: notright
|
lang: notright
|
||||||
|
@ -111,7 +100,6 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
{
|
{
|
||||||
"complexlang", &RenderConfig{
|
"complexlang", &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "testlang",
|
Lang: "testlang",
|
||||||
}, `
|
}, `
|
||||||
gitea:
|
gitea:
|
||||||
|
@ -123,7 +111,6 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
Lang: "two",
|
Lang: "two",
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
TOC: "true",
|
TOC: "true",
|
||||||
Icon: "smiley",
|
|
||||||
}, `
|
}, `
|
||||||
lang: one
|
lang: one
|
||||||
include_toc: true
|
include_toc: true
|
||||||
|
@ -139,14 +126,12 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := &RenderConfig{
|
got := &RenderConfig{
|
||||||
Meta: "table",
|
Meta: "table",
|
||||||
Icon: "table",
|
|
||||||
Lang: "",
|
Lang: "",
|
||||||
}
|
}
|
||||||
err := yaml.Unmarshal([]byte(strings.ReplaceAll(tt.args, "\t", " ")), got)
|
err := yaml.Unmarshal([]byte(strings.ReplaceAll(tt.args, "\t", " ")), got)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, tt.expected.Meta, got.Meta)
|
assert.Equal(t, tt.expected.Meta, got.Meta)
|
||||||
assert.Equal(t, tt.expected.Icon, got.Icon)
|
|
||||||
assert.Equal(t, tt.expected.Lang, got.Lang)
|
assert.Equal(t, tt.expected.Lang, got.Lang)
|
||||||
assert.Equal(t, tt.expected.TOC, got.TOC)
|
assert.Equal(t, tt.expected.TOC, got.TOC)
|
||||||
})
|
})
|
||||||
|
|
|
@ -511,6 +511,18 @@
|
||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.markup details.frontmatter-content summary {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markup details.frontmatter-content svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
.file-revisions-btn {
|
.file-revisions-btn {
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
|
|
Loading…
Reference in New Issue