diff options
| -rw-r--r-- | dom/css_class.go | 4 | ||||
| -rw-r--r-- | dom/html.go | 29 | ||||
| -rw-r--r-- | markdown/ast.go | 5 | ||||
| -rw-r--r-- | markdown/ast_code.go | 12 | ||||
| -rw-r--r-- | markdown/ast_external.go | 19 | ||||
| -rw-r--r-- | markdown/ast_external_test.go | 29 | ||||
| -rw-r--r-- | markdown/ast_heading.go (renamed from markdown/ast_header.go) | 9 | ||||
| -rw-r--r-- | markdown/ast_list.go | 13 | ||||
| -rw-r--r-- | markdown/ast_modifier.go | 4 | ||||
| -rw-r--r-- | markdown/ast_paragraph.go | 8 | ||||
| -rw-r--r-- | markdown/ast_paragraph_test.go | 9 | ||||
| -rw-r--r-- | markdown/ast_quote.go | 19 | ||||
| -rw-r--r-- | markdown/ast_test.go | 9 |
13 files changed, 89 insertions, 80 deletions
diff --git a/dom/css_class.go b/dom/css_class.go index 633869e..998dd50 100644 --- a/dom/css_class.go +++ b/dom/css_class.go @@ -1,5 +1,7 @@ package dom +import "strings" + type ClassList map[string]struct{} func (cl ClassList) set(e Element) Element { @@ -10,7 +12,7 @@ func (cl ClassList) set(e Element) Element { for k := range cl { classes += k + " " } - classes = classes[:len(cl)-1] + classes = strings.TrimSpace(classes) return e.SetAttribute("class", classes) } diff --git a/dom/html.go b/dom/html.go index 360a33b..a7dc434 100644 --- a/dom/html.go +++ b/dom/html.go @@ -2,7 +2,6 @@ package dom import ( "fmt" - "html" "html/template" ) @@ -25,12 +24,10 @@ type Element interface { ClassList() ClassList } -type LiteralElement struct { - Content string -} +type LiteralElement template.HTML func (e LiteralElement) Render() template.HTML { - return template.HTML(html.EscapeString(e.Content)) + return template.HTML(e) } func (LiteralElement) HasAttribute(string) bool { @@ -49,8 +46,8 @@ func (e LiteralElement) ClassList() ClassList { return nil } -func NewLiteralElement(s string) LiteralElement { - return LiteralElement{s} +func NewLiteralElement(s template.HTML) LiteralElement { + return LiteralElement(s) } type VoidElement struct { @@ -60,7 +57,7 @@ type VoidElement struct { } func (e VoidElement) Render() template.HTML { - e = e.cl.set(e).(VoidElement) + e.cl.set(e) return render(e.Tag, e.attributes, true) } @@ -88,7 +85,7 @@ func NewVoidElement(tag string) VoidElement { } func NewImg(src, alt string) Element { - return NewVoidElement("img").SetAttribute("src", src).SetAttribute("alt", alt) + return NewVoidElement("img").SetAttribute("alt", alt).SetAttribute("src", src) } type ContentElement struct { @@ -97,7 +94,7 @@ type ContentElement struct { } func (e ContentElement) Render() template.HTML { - e = e.cl.set(e).(ContentElement) + e.cl.set(e) base := render(e.Tag, e.attributes, false) for _, el := range e.Contents { base += el.Render() @@ -109,6 +106,14 @@ func NewContentElement(tag string, contents []Element) ContentElement { return ContentElement{NewVoidElement(tag), contents} } -func NewParagraph(content string) Element { - return NewContentElement("p", []Element{NewLiteralElement(content)}) +func NewLiteralContentElement(tag string, content template.HTML) Element { + return NewContentElement(tag, []Element{NewLiteralElement(content)}) +} + +func NewParagraph(content template.HTML) Element { + return NewLiteralContentElement("p", content) +} + +func NewHeading(level uint, content template.HTML) Element { + return NewLiteralContentElement(fmt.Sprintf("h%d", level), content) } diff --git a/markdown/ast.go b/markdown/ast.go index 9c9816e..2e073ee 100644 --- a/markdown/ast.go +++ b/markdown/ast.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "html/template" - "strings" ) var ErrUnkownLexType = errors.New("unkown lex type") @@ -107,7 +106,3 @@ func getBlock(lxs *lexers, newLine bool) (block, *ParseError) { } return b, err } - -func trimSpace(s template.HTML) template.HTML { - return template.HTML(strings.TrimSpace(string(s))) -} diff --git a/markdown/ast_code.go b/markdown/ast_code.go index 6980f32..c83a984 100644 --- a/markdown/ast_code.go +++ b/markdown/ast_code.go @@ -2,8 +2,10 @@ package markdown import ( "errors" - "fmt" + "html" "html/template" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var ( @@ -26,11 +28,15 @@ type astCode struct { } func (a *astCode) Eval(_ *Option) (template.HTML, *ParseError) { + content := template.HTML(html.EscapeString(a.content)) switch a.codeType { case codeOneLine: - return template.HTML(fmt.Sprintf("<code>%s</code>", template.HTMLEscapeString(a.content))), nil + return dom.NewLiteralContentElement("code", content).Render(), nil case codeMultiLine: - return template.HTML(fmt.Sprintf("<pre><code>%s</code></pre>", template.HTMLEscapeString(a.content))), nil + pre := dom.NewContentElement("pre", make([]dom.Element, 1)) + code := dom.NewContentElement("code", []dom.Element{dom.NewLiteralElement(content)}) + pre.Contents[0] = code + return pre.Render(), nil default: return "", &ParseError{lxs: lexers{}, internal: ErrUnknownCodeType} } diff --git a/markdown/ast_external.go b/markdown/ast_external.go index 8adeea1..4a1024a 100644 --- a/markdown/ast_external.go +++ b/markdown/ast_external.go @@ -1,9 +1,10 @@ package markdown import ( - "fmt" "html/template" "regexp" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var ExternalLink = regexp.MustCompile(`https?://`) @@ -31,10 +32,12 @@ func (a *astLink) Eval(opt *Option) (template.HTML, *ParseError) { } func RenderLink(content, href string) template.HTML { - if !ExternalLink.Match([]byte(href)) { - return template.HTML(fmt.Sprintf(`<a href="%s">%s</a>`, href, content)) + anchor := dom.NewLiteralContentElement("a", template.HTML(content)) + anchor.SetAttribute("href", href) + if ExternalLink.MatchString(href) { + anchor.SetAttribute("target", "_blank").SetAttribute("rel", "noreferer") } - return template.HTML(fmt.Sprintf(`<a href="%s" target="_blank" rel="noreferer">%s</a>`, href, content)) + return anchor.Render() } type astImage struct { @@ -53,8 +56,10 @@ func (a *astImage) Eval(opt *Option) (template.HTML, *ParseError) { return "", err } src = template.HTML(opt.ImageSource(string(src))) + img := dom.NewImg(string(src), string(alt)) + figure := dom.NewContentElement("figure", []dom.Element{img}) if a.source == nil { - return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"></figure>`, alt, src)), nil + return figure.Render(), nil } var s template.HTML for _, c := range a.source { @@ -65,7 +70,9 @@ func (a *astImage) Eval(opt *Option) (template.HTML, *ParseError) { s += ct + " " } s = s[:len(s)-1] - return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"><figcaption>%s</figcaption></figure>`, alt, src, s)), nil + figcaption := dom.NewLiteralContentElement("figcaption", s) + figure.Contents = append(figure.Contents, figcaption) + return figure.Render(), nil } func external(lxs *lexers) (block, *ParseError) { diff --git a/markdown/ast_external_test.go b/markdown/ast_external_test.go index 514cc89..c31c233 100644 --- a/markdown/ast_external_test.go +++ b/markdown/ast_external_test.go @@ -3,51 +3,34 @@ package markdown import "testing" func TestExternal(t *testing.T) { - lxs := lex("[content](href)") - tree, err := ast(lxs) - if err != nil { - t.Fatal(err) - } - got, err := tree.Eval(nil) + got, err := Parse("[content](href)", nil) if err != nil { t.Fatal(err) } if string(got) != `<p><a href="href">content</a></p>` { t.Errorf("invalid value, got %s", got) - t.Logf("lexer %s", lxs.String()) } - lxs = lex("") - tree, err = ast(lxs) + got, err = Parse("", nil) if err != nil { - t.Logf("lexer %s", lxs.String()) t.Fatal(err) } - got, err = tree.Eval(nil) - if err != nil { - t.Fatal(err) - } - if string(got) != `<figure><img alt="image alt" src="image src"></figure>` { + if string(got) != `<figure><img alt="image alt" src="image src" /></figure>` { t.Errorf("invalid value, got %s", got) } - lxs = lex(` + got, err = Parse(` Avant la source  source 1 source 2 Hors de la source -`) - tree, err = ast(lxs) - if err != nil { - t.Fatal(err) - } - got, err = tree.Eval(nil) +`, nil) if err != nil { t.Fatal(err) } - if string(got) != `<p>Avant la source</p><figure><img alt="image alt" src="image src"><figcaption>source 1 source 2</figcaption></figure><p>Hors de la source</p>` { + if string(got) != `<p>Avant la source</p><figure><img alt="image alt" src="image src" /><figcaption>source 1 source 2</figcaption></figure><p>Hors de la source</p>` { t.Errorf("invalid value, got %s", got) } diff --git a/markdown/ast_header.go b/markdown/ast_heading.go index 716a4a6..5ad7adb 100644 --- a/markdown/ast_header.go +++ b/markdown/ast_heading.go @@ -2,8 +2,10 @@ package markdown import ( "errors" - "fmt" "html/template" + "strings" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var ErrInvalidHeader = errors.New("invalid header") @@ -22,7 +24,10 @@ func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) { if err != nil { return "", err } - return template.HTML(fmt.Sprintf("<h%d>%s</h%d>", a.level, trimSpace(content), a.level)), nil + return dom.NewHeading( + a.level, + template.HTML(strings.TrimSpace(string(content))), + ).Render(), nil } func header(lxs *lexers) (*astHeader, *ParseError) { diff --git a/markdown/ast_list.go b/markdown/ast_list.go index b82df67..b07f013 100644 --- a/markdown/ast_list.go +++ b/markdown/ast_list.go @@ -1,9 +1,11 @@ package markdown import ( - "fmt" "html/template" "regexp" + "strings" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var regexOrdered = regexp.MustCompile(`\d+\.`) @@ -21,15 +23,18 @@ type astList struct { } func (a *astList) Eval(opt *Option) (template.HTML, *ParseError) { - var content template.HTML + list := dom.NewContentElement(string(a.tag), make([]dom.Element, 0)) for _, c := range a.content { ct, err := c.Eval(opt) if err != nil { return "", err } - content += template.HTML(fmt.Sprintf("<li>%s</li>", trimSpace(ct))) + list.Contents = append(list.Contents, dom.NewLiteralContentElement( + "li", + template.HTML(strings.TrimSpace(string(ct))), + )) } - return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil + return list.Render(), nil } func list(lxs *lexers) (block, *ParseError) { diff --git a/markdown/ast_modifier.go b/markdown/ast_modifier.go index 909d25e..635fbc0 100644 --- a/markdown/ast_modifier.go +++ b/markdown/ast_modifier.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "html/template" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var ( @@ -38,7 +40,7 @@ func (a *astModifier) Eval(opt *Option) (template.HTML, *ParseError) { if a.super { return content, nil } - return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil + return dom.NewLiteralContentElement(string(a.tag), content).Render(), nil } func (a *astModifier) String() string { diff --git a/markdown/ast_paragraph.go b/markdown/ast_paragraph.go index a6417e2..b945741 100644 --- a/markdown/ast_paragraph.go +++ b/markdown/ast_paragraph.go @@ -2,8 +2,10 @@ package markdown import ( "errors" - "fmt" "html/template" + "strings" + + "git.anhgelus.world/anhgelus/small-web/dom" ) var ( @@ -27,7 +29,9 @@ func (a *astParagraph) Eval(opt *Option) (template.HTML, *ParseError) { if a.oneLine { return content, nil } - return template.HTML(fmt.Sprintf("<p>%s</p>", trimSpace(content))), nil + return dom.NewParagraph( + template.HTML(strings.TrimSpace(string(content))), + ).Render(), nil } func paragraph(lxs *lexers, oneLine bool) (*astParagraph, *ParseError) { diff --git a/markdown/ast_paragraph_test.go b/markdown/ast_paragraph_test.go index 9155a9b..46dd714 100644 --- a/markdown/ast_paragraph_test.go +++ b/markdown/ast_paragraph_test.go @@ -3,18 +3,11 @@ package markdown import "testing" func TestParagraph(t *testing.T) { - content := "bonsoir" - lxs := lex(content) - tree, err := ast(lxs) - if err != nil { - t.Fatal(err) - } - c, err := tree.Eval(nil) + c, err := Parse("bonsoir", nil) if err != nil { t.Fatal(err) } if c != "<p>bonsoir</p>" { t.Errorf("failed, got %s", c) - t.Logf("lxs: %s\ntree: %s", lxs, tree) } } diff --git a/markdown/ast_quote.go b/markdown/ast_quote.go index fa3a878..96669c5 100644 --- a/markdown/ast_quote.go +++ b/markdown/ast_quote.go @@ -1,9 +1,10 @@ package markdown import ( - "fmt" "html/template" "strings" + + "git.anhgelus.world/anhgelus/small-web/dom" ) type astQuote struct { @@ -12,15 +13,18 @@ type astQuote struct { } func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) { - var quote template.HTML + var quoteContent template.HTML for _, c := range a.quote { ct, err := c.Eval(opt) if err != nil { return "", err } - quote += ct + quoteContent += ct } - quote = template.HTML(fmt.Sprintf("<blockquote>%s</blockquote>", trimSpace(quote))) + blockquote := dom.NewLiteralContentElement( + "blockquote", + template.HTML(strings.TrimSpace(string(quoteContent))), + ) var source template.HTML for _, c := range a.source { ct, err := c.Eval(opt) @@ -30,10 +34,13 @@ func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) { source += ct } source = template.HTML(strings.TrimSpace(string(source))) + quote := dom.NewContentElement("div", make([]dom.Element, 0)) + quote.ClassList().Add("quote") + quote.Contents = append(quote.Contents, blockquote) if len(source) > 0 { - return template.HTML(fmt.Sprintf(`<div class="quote">%s<p>%s</p></div>`, quote, source)), nil + quote.Contents = append(quote.Contents, dom.NewParagraph(source)) } - return template.HTML(fmt.Sprintf(`<div class="quote">%s</div>`, quote)), nil + return quote.Render(), nil } func quote(lxs *lexers) (*astQuote, *ParseError) { diff --git a/markdown/ast_test.go b/markdown/ast_test.go index 45eb49d..8f701f4 100644 --- a/markdown/ast_test.go +++ b/markdown/ast_test.go @@ -40,18 +40,13 @@ var parsed = ` <ol><li>et maintenant</li><li>elle l'est</li></ol> <ul><li>hehe</li></ul> <figure> -<img alt="Ceci est ma pfp :3" src="https://cdn.anhgelus.world/pfp.jpg"> +<img alt="Ceci est ma pfp :3" src="https://cdn.anhgelus.world/pfp.jpg" /> <figcaption> <a href="https://now.anhgelus.world/" target="_blank" rel="noreferer">Ma pfp</a> hehe :D Elle est <b>magnifique</b>, n'est-ce pas ?</figcaption> </figure> ` func TestAst(t *testing.T) { - lxs := lex(raw) - tree, err := ast(lxs) - if err != nil { - t.Fatal(err) - } - res, err := tree.Eval(nil) + res, err := Parse(raw, nil) if err != nil { t.Fatal(err) } |
