From 80dae5f8269bbb9d8408e89ca564e7e77e4416f6 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 10:37:30 +0000 Subject: [PATCH 01/15] Add color preview to markdown Signed-off-by: Yarden Shoham --- modules/markup/markdown/ast.go | 36 +++++++++++++++++++++++++++++ modules/markup/markdown/goldmark.go | 24 +++++++++++++++++++ modules/markup/sanitizer.go | 8 +++++-- web_src/less/_base.less | 16 +++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/modules/markup/markdown/ast.go b/modules/markup/markdown/ast.go index 5191d94cdd85a..c82d5e5e73396 100644 --- a/modules/markup/markdown/ast.go +++ b/modules/markup/markdown/ast.go @@ -144,3 +144,39 @@ func IsIcon(node ast.Node) bool { _, ok := node.(*Icon) return ok } + +// ColorPreview is an inline for a color preview +type ColorPreview struct { + ast.BaseInline + Color []byte +} + +// Dump implements Node.Dump. +func (n *ColorPreview) Dump(source []byte, level int) { + m := map[string]string{} + m["Color"] = string(n.Color) + ast.DumpHelper(n, source, level, m, nil) +} + +// KindColorPreview is the NodeKind for ColorPreview +var KindColorPreview = ast.NewNodeKind("ColorPreview") + +// Kind implements Node.Kind. +func (n *ColorPreview) Kind() ast.NodeKind { + return KindColorPreview +} + +// NewColorPreview returns a new Span node. +func NewColorPreview(color []byte) *ColorPreview { + return &ColorPreview{ + BaseInline: ast.BaseInline{}, + Color: color, + } +} + +// IsColorPreview returns true if the given node implements the ColorPreview interface, +// otherwise false. +func IsColorPreview(node ast.Node) bool { + _, ok := node.(*ColorPreview) + return ok +} diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 8417019ddbad7..38438b5604e60 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -27,6 +27,8 @@ import ( var byteMailto = []byte("mailto:") +var cssColorRegex = regexp.MustCompile(`(?i)(#(?:[0-9a-f]{2}){2,4}$|(#[0-9a-f]{3}$)|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))$`) + // ASTTransformer is a default transformer of the goldmark tree. type ASTTransformer struct{} @@ -178,6 +180,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInDocuments) } } + case *ast.CodeSpan: + colorContent := n.Text(reader.Source()) + if cssColorRegex.Match(colorContent) { + v.Parent().InsertAfter(v.Parent(), v, NewColorPreview(colorContent)) + } } return ast.WalkContinue, nil }) @@ -266,6 +273,7 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindDetails, r.renderDetails) reg.Register(KindSummary, r.renderSummary) reg.Register(KindIcon, r.renderIcon) + reg.Register(KindColorPreview, r.renderColorPreview) reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem) reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox) } @@ -356,6 +364,22 @@ func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node return ast.WalkContinue, nil } +func (r *HTMLRenderer) renderColorPreview(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + var err error + n := node.(*ColorPreview) + if entering { + _, err = w.WriteString(fmt.Sprintf(``, string(n.Color))) + } else { + _, err = w.WriteString("") + } + + if err != nil { + return ast.WalkStop, err + } + + return ast.WalkContinue, nil +} + func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { n := node.(*TaskCheckBoxListItem) if entering { diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 807a8a7892b3d..4d0df289154ab 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -55,6 +55,10 @@ func createDefaultPolicy() *bluemonday.Policy { // For JS code copy and Mermaid loading state policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-block( is-loading)?$`)).OnElements("pre") + // For color preview + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^repo-icon rounded$`)).OnElements("span") + policy.AllowAttrs("class").Matching(regexp.MustCompile("^color-preview$")).OnElements("code") + // For Chroma markdown plugin policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(chroma )?language-[\w-]+( display)?( is-loading)?$`)).OnElements("code") @@ -88,8 +92,8 @@ func createDefaultPolicy() *bluemonday.Policy { // Allow 'style' attribute on text elements. policy.AllowAttrs("style").OnElements("span", "p") - // Allow 'color' property for the style attribute on text elements. - policy.AllowStyles("color").OnElements("span", "p") + // Allow 'color' and 'background-color' properties for the style attribute on text elements. + policy.AllowStyles("color", "background-color").OnElements("span", "p") // Allow generally safe attributes generalSafeAttrs := []string{ diff --git a/web_src/less/_base.less b/web_src/less/_base.less index bfc6e0cf96cbf..f66ad969a4a25 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1371,6 +1371,22 @@ a.ui.card:hover, border-color: var(--color-secondary); } +.color-preview { + padding-left: 0 !important; + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; + span { + height: 7px; + width: 7px; + } +} + +code:has(+ .color-preview) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + padding-right: 0.2em; +} + footer { background-color: var(--color-footer); border-top: 1px solid var(--color-secondary); From df33f5851e49ed8a60c00a2032c89fb6e94ff7ea Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 10:46:18 +0000 Subject: [PATCH 02/15] Lint --- web_src/less/_base.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index f66ad969a4a25..a6eca975f5777 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1384,7 +1384,7 @@ a.ui.card:hover, code:has(+ .color-preview) { border-top-right-radius: 0; border-bottom-right-radius: 0; - padding-right: 0.2em; + padding-right: .2em; } footer { From 7fdc6831e8bee8f732b4c32af9c234ccfbecf37c Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 11:26:16 +0000 Subject: [PATCH 03/15] Simplify code --- modules/markup/markdown/goldmark.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 38438b5604e60..8287a65321126 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -368,9 +368,7 @@ func (r *HTMLRenderer) renderColorPreview(w util.BufWriter, source []byte, node var err error n := node.(*ColorPreview) if entering { - _, err = w.WriteString(fmt.Sprintf(``, string(n.Color))) - } else { - _, err = w.WriteString("") + _, err = w.WriteString(fmt.Sprintf(``, string(n.Color))) } if err != nil { From 705f92be798f1d0c54451392ad5a1385ba448aa7 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 18:10:58 +0000 Subject: [PATCH 04/15] Override renderCodeSpan --- modules/markup/markdown/goldmark.go | 50 ++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 8287a65321126..ddaf0c9bd67f7 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -183,7 +183,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa case *ast.CodeSpan: colorContent := n.Text(reader.Source()) if cssColorRegex.Match(colorContent) { - v.Parent().InsertAfter(v.Parent(), v, NewColorPreview(colorContent)) + v.AppendChild(v, NewColorPreview(colorContent)) } } return ast.WalkContinue, nil @@ -273,11 +273,43 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindDetails, r.renderDetails) reg.Register(KindSummary, r.renderSummary) reg.Register(KindIcon, r.renderIcon) - reg.Register(KindColorPreview, r.renderColorPreview) + reg.Register(ast.KindCodeSpan, r.renderCodeSpan) reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem) reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox) } +// renderCodeSpan renders CodeSpan elements (like goldmark upstream does) but also renders ColorPreview elements. +// See #21474 for reference +func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if n.Attributes() != nil { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("") + } + for c := n.FirstChild(); c != nil; c = c.NextSibling() { + switch v := c.(type) { + case *ast.Text: + segment := v.Segment + value := segment.Value(source) + if bytes.HasSuffix(value, []byte("\n")) { + r.Writer.RawWrite(w, value[:len(value)-1]) + r.Writer.RawWrite(w, []byte(" ")) + } else { + r.Writer.RawWrite(w, value) + } + case *ColorPreview: + _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) + } + } + return ast.WalkSkipChildren, nil + } + _, _ = w.WriteString("") + return ast.WalkContinue, nil +} + func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { n := node.(*ast.Document) @@ -364,20 +396,6 @@ func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node return ast.WalkContinue, nil } -func (r *HTMLRenderer) renderColorPreview(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { - var err error - n := node.(*ColorPreview) - if entering { - _, err = w.WriteString(fmt.Sprintf(``, string(n.Color))) - } - - if err != nil { - return ast.WalkStop, err - } - - return ast.WalkContinue, nil -} - func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { n := node.(*TaskCheckBoxListItem) if entering { From c43063faf6687baecd6043648940d2b5ff0b546c Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 18:11:17 +0000 Subject: [PATCH 05/15] continued --- modules/markup/sanitizer.go | 3 +-- web_src/less/_base.less | 18 +++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 4d0df289154ab..0762dab71496b 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -56,8 +56,7 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-block( is-loading)?$`)).OnElements("pre") // For color preview - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^repo-icon rounded$`)).OnElements("span") - policy.AllowAttrs("class").Matching(regexp.MustCompile("^color-preview$")).OnElements("code") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^repo-icon rounded color-preview$`)).OnElements("span") // For Chroma markdown plugin policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(chroma )?language-[\w-]+( display)?( is-loading)?$`)).OnElements("code") diff --git a/web_src/less/_base.less b/web_src/less/_base.less index a6eca975f5777..9bb0540d752e1 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1372,19 +1372,11 @@ a.ui.card:hover, } .color-preview { - padding-left: 0 !important; - border-top-left-radius: 0 !important; - border-bottom-left-radius: 0 !important; - span { - height: 7px; - width: 7px; - } -} - -code:has(+ .color-preview) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - padding-right: .2em; + border-style: solid; + border-color: var(--color-secondary-dark-8); + margin-left: .2em; + height: 7px; + width: 7px; } footer { From 1dfc0bdf1f1b3321be7a8a11425cb5bf67dde3d3 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 18:21:58 +0000 Subject: [PATCH 06/15] Style --- web_src/less/_base.less | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index 9bb0540d752e1..cb515adc42e93 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1372,9 +1372,7 @@ a.ui.card:hover, } .color-preview { - border-style: solid; - border-color: var(--color-secondary-dark-8); - margin-left: .2em; + margin-left: .4em; height: 7px; width: 7px; } From 488ff92584a6eb3da3b6532e807abe7e09f2bb2d Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Mon, 17 Oct 2022 18:33:19 +0000 Subject: [PATCH 07/15] Credit Co-authored-by: KN4CK3R From 46f3a297ef1ead4e4a50ab4ea71b186aeed30ede Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Tue, 18 Oct 2022 17:14:26 +0000 Subject: [PATCH 08/15] Add tests --- modules/markup/markdown/markdown_test.go | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 49ed3d75d6c09..6b9483ed35203 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -429,6 +429,55 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) { assert.Equal(t, expected, res) } +func TestColorPreview(t *testing.T) { + const nl = "\n" + positiveTests := []struct { + testcase string + expected string + }{ + { // hex + "`#FF0000`", + `

#FF0000

` + nl, + }, + { // rgb + "`rgb(16, 32, 64)`", + `

rgb(16, 32, 64)

` + nl, + }, + { // short hex + "This is the color white `#000`", + `

This is the color white #000

` + nl, + }, + { // hsl + "HSL stands for hue, saturation, and lightness. An example: `hsl(0, 100%, 50%)`.", + `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, + }, + } + + for _, test := range positiveTests { + res, err := RenderString(&markup.RenderContext{}, test.testcase) + assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) + assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + + } + + negativeTests := []string{ + // not a color code + "`FF0000`", + // inside a code block + "```javascript" + nl + `const red = "#FF0000";` + nl + "```", + // no backticks + "rgb(166, 32, 64)", + // typo + "hsI(0, 100%, 50%)", + } + + for _, test := range negativeTests { + res, err := RenderString(&markup.RenderContext{}, test) + assert.NoError(t, err, "Unexpected error in testcase: %q", test) + assert.NotContains(t, res, ` Date: Tue, 18 Oct 2022 18:02:03 +0000 Subject: [PATCH 09/15] Simplify CSS color check Had some false positives with regex --- modules/markup/markdown/goldmark.go | 5 ++--- modules/markup/markdown/markdown_test.go | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index ddaf0c9bd67f7..70c48b4d6d15f 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" giteautil "code.gitea.io/gitea/modules/util" + "github.com/microcosm-cc/bluemonday/css" "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" "github.com/yuin/goldmark/parser" @@ -27,8 +28,6 @@ import ( var byteMailto = []byte("mailto:") -var cssColorRegex = regexp.MustCompile(`(?i)(#(?:[0-9a-f]{2}){2,4}$|(#[0-9a-f]{3}$)|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))$`) - // ASTTransformer is a default transformer of the goldmark tree. type ASTTransformer struct{} @@ -182,7 +181,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa } case *ast.CodeSpan: colorContent := n.Text(reader.Source()) - if cssColorRegex.Match(colorContent) { + if css.ColorHandler(strings.ToLower(string(colorContent))) { v.AppendChild(v, NewColorPreview(colorContent)) } } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 6b9483ed35203..df8042d7fe814 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -451,6 +451,10 @@ func TestColorPreview(t *testing.T) { "HSL stands for hue, saturation, and lightness. An example: `hsl(0, 100%, 50%)`.", `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, }, + { // uppercase hsl + "HSL stands for hue, saturation, and lightness. An example: `HSL(0, 100%, 50%)`.", + `

HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%).

` + nl, + }, } for _, test := range positiveTests { @@ -468,7 +472,9 @@ func TestColorPreview(t *testing.T) { // no backticks "rgb(166, 32, 64)", // typo - "hsI(0, 100%, 50%)", + "`hsI(0, 100%, 50%)`", + // looks like a color but not really + "`hsl(40, 60, 80)`", } for _, test := range negativeTests { From a73a77407876e9e4a0b67cb8d094aaf21fe6709b Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 19 Oct 2022 10:49:15 +0300 Subject: [PATCH 10/15] Update web_src/less/_base.less Co-authored-by: silverwind --- web_src/less/_base.less | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index cb515adc42e93..8e96f7ca4cc08 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1373,8 +1373,9 @@ a.ui.card:hover, .color-preview { margin-left: .4em; - height: 7px; - width: 7px; + height: .67em; + width: .67em; + border-radius: .15em; } footer { From b9c4e62f6a27b1e415870a4571d052d8a509cd28 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 19 Oct 2022 10:49:33 +0300 Subject: [PATCH 11/15] Update modules/markup/markdown/goldmark.go Co-authored-by: silverwind --- modules/markup/markdown/goldmark.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 70c48b4d6d15f..aa7629c737a48 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -300,7 +300,7 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod r.Writer.RawWrite(w, value) } case *ColorPreview: - _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) + _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) } } return ast.WalkSkipChildren, nil From 64b8a089d81c2b5a2277068f859b6f4e41c43065 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 19 Oct 2022 07:56:49 +0000 Subject: [PATCH 12/15] Use dib class --- modules/markup/markdown/markdown_test.go | 10 +++++----- modules/markup/sanitizer.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index df8042d7fe814..7bf798ae7a9fe 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -437,23 +437,23 @@ func TestColorPreview(t *testing.T) { }{ { // hex "`#FF0000`", - `

#FF0000

` + nl, + `

#FF0000

` + nl, }, { // rgb "`rgb(16, 32, 64)`", - `

rgb(16, 32, 64)

` + nl, + `

rgb(16, 32, 64)

` + nl, }, { // short hex "This is the color white `#000`", - `

This is the color white #000

` + nl, + `

This is the color white #000

` + nl, }, { // hsl "HSL stands for hue, saturation, and lightness. An example: `hsl(0, 100%, 50%)`.", - `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, + `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, }, { // uppercase hsl "HSL stands for hue, saturation, and lightness. An example: `HSL(0, 100%, 50%)`.", - `

HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%).

` + nl, + `

HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%).

` + nl, }, } diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go index 0762dab71496b..cb2293c1c2637 100644 --- a/modules/markup/sanitizer.go +++ b/modules/markup/sanitizer.go @@ -56,7 +56,7 @@ func createDefaultPolicy() *bluemonday.Policy { policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-block( is-loading)?$`)).OnElements("pre") // For color preview - policy.AllowAttrs("class").Matching(regexp.MustCompile(`^repo-icon rounded color-preview$`)).OnElements("span") + policy.AllowAttrs("class").Matching(regexp.MustCompile(`^color-preview dib$`)).OnElements("span") // For Chroma markdown plugin policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(chroma )?language-[\w-]+( display)?( is-loading)?$`)).OnElements("code") From 56bfbf510e29c68cd020b0f61bb5c8937cb78653 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 19 Oct 2022 08:07:42 +0000 Subject: [PATCH 13/15] Use dib in negative tests --- modules/markup/markdown/markdown_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 7bf798ae7a9fe..da9d8b52b28fa 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -480,7 +480,7 @@ func TestColorPreview(t *testing.T) { for _, test := range negativeTests { res, err := RenderString(&markup.RenderContext{}, test) assert.NoError(t, err, "Unexpected error in testcase: %q", test) - assert.NotContains(t, res, ` Date: Fri, 21 Oct 2022 10:55:04 +0300 Subject: [PATCH 14/15] Update modules/markup/markdown/goldmark.go Co-authored-by: silverwind --- modules/markup/markdown/goldmark.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index aa7629c737a48..1a36681366193 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -300,7 +300,7 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod r.Writer.RawWrite(w, value) } case *ColorPreview: - _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) + _, _ = w.WriteString(fmt.Sprintf(``, string(v.Color))) } } return ast.WalkSkipChildren, nil From 001fc08e5a6c66410934181282361fc34cb9a007 Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Fri, 21 Oct 2022 07:59:48 +0000 Subject: [PATCH 15/15] Move dib into color-preview Signed-off-by: Yarden Shoham --- modules/markup/markdown/markdown_test.go | 12 ++++++------ modules/markup/sanitizer.go | 2 +- web_src/less/_base.less | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index da9d8b52b28fa..12c6288c24d12 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -437,23 +437,23 @@ func TestColorPreview(t *testing.T) { }{ { // hex "`#FF0000`", - `

#FF0000

` + nl, + `

#FF0000

` + nl, }, { // rgb "`rgb(16, 32, 64)`", - `

rgb(16, 32, 64)

` + nl, + `

rgb(16, 32, 64)

` + nl, }, { // short hex "This is the color white `#000`", - `

This is the color white #000

` + nl, + `

This is the color white #000

` + nl, }, { // hsl "HSL stands for hue, saturation, and lightness. An example: `hsl(0, 100%, 50%)`.", - `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, + `

HSL stands for hue, saturation, and lightness. An example: hsl(0, 100%, 50%).

` + nl, }, { // uppercase hsl "HSL stands for hue, saturation, and lightness. An example: `HSL(0, 100%, 50%)`.", - `

HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%).

` + nl, + `

HSL stands for hue, saturation, and lightness. An example: HSL(0, 100%, 50%).

` + nl, }, } @@ -480,7 +480,7 @@ func TestColorPreview(t *testing.T) { for _, test := range negativeTests { res, err := RenderString(&markup.RenderContext{}, test) assert.NoError(t, err, "Unexpected error in testcase: %q", test) - assert.NotContains(t, res, `