Don't require !embed, use placeholders in previews
This commit is contained in:
parent
f1ccbc53d7
commit
4d9ef5917e
Binary file not shown.
|
@ -14,55 +14,55 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
REEmbedTag = regexp.MustCompile(`^!embed\((?P<url>.+?)\)`)
|
|
||||||
|
|
||||||
// TODO: Timestamped youtube embeds
|
// TODO: Timestamped youtube embeds
|
||||||
REYoutubeLong = regexp.MustCompile(`^https://www\.youtube\.com/watch?.*v=(?P<vid>[a-zA-Z0-9_-]{11})`)
|
REYoutubeLong = regexp.MustCompile(`^https://www\.youtube\.com/watch?.*v=(?P<vid>[a-zA-Z0-9_-]{11})`)
|
||||||
REYoutubeShort = regexp.MustCompile(`^https://youtu\.be/(?P<vid>[a-zA-Z0-9_-]{11})`)
|
REYoutubeShort = regexp.MustCompile(`^https://youtu\.be/(?P<vid>[a-zA-Z0-9_-]{11})`)
|
||||||
REVimeo = regexp.MustCompile(`^https://vimeo\.com/(?P<vid>\d+)`)
|
REVimeo = regexp.MustCompile(`^https://vimeo\.com/(?P<vid>\d+)`)
|
||||||
|
// TODO: Twitch VODs / clips
|
||||||
|
// TODO: Desmos
|
||||||
|
// TODO: Tweets
|
||||||
)
|
)
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
// Parser and delimiters
|
// Parser and delimiters
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
type embedParser struct{}
|
type embedParser struct {
|
||||||
|
Preview bool
|
||||||
func NewEmbedParser() parser.BlockParser {
|
|
||||||
return embedParser{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ parser.BlockParser = embedParser{}
|
||||||
|
|
||||||
func (s embedParser) Trigger() []byte {
|
func (s embedParser) Trigger() []byte {
|
||||||
return []byte{'!'}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s embedParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
|
func (s embedParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
|
||||||
restOfLine, _ := reader.PeekLine()
|
restOfLine, _ := reader.PeekLine()
|
||||||
urlMatch := REEmbedTag.FindSubmatch(restOfLine)
|
|
||||||
if urlMatch == nil {
|
|
||||||
return nil, parser.NoChildren
|
|
||||||
}
|
|
||||||
url := urlMatch[REEmbedTag.SubexpIndex("url")]
|
|
||||||
|
|
||||||
html := ""
|
html := ""
|
||||||
if ytLongMatch := extract(REYoutubeLong, url, "vid"); ytLongMatch != nil {
|
var match []byte
|
||||||
html = makeYoutubeEmbed(string(ytLongMatch))
|
if ytLongMatch := extract(REYoutubeLong, restOfLine, "vid"); ytLongMatch != nil {
|
||||||
} else if ytShortMatch := extract(REYoutubeShort, url, "vid"); ytShortMatch != nil {
|
match = ytLongMatch
|
||||||
html = makeYoutubeEmbed(string(ytShortMatch))
|
html = makeYoutubeEmbed(string(ytLongMatch), s.Preview)
|
||||||
} else if vimeoMatch := extract(REVimeo, url, "vid"); vimeoMatch != nil {
|
} else if ytShortMatch := extract(REYoutubeShort, restOfLine, "vid"); ytShortMatch != nil {
|
||||||
html = `
|
match = ytShortMatch
|
||||||
|
html = makeYoutubeEmbed(string(ytShortMatch), s.Preview)
|
||||||
|
} else if vimeoMatch := extract(REVimeo, restOfLine, "vid"); vimeoMatch != nil {
|
||||||
|
match = vimeoMatch
|
||||||
|
html = s.previewOrLegitEmbed("Vimeo", `
|
||||||
<div class="mw6">
|
<div class="mw6">
|
||||||
<div class="aspect-ratio aspect-ratio--16x9">
|
<div class="aspect-ratio aspect-ratio--16x9">
|
||||||
<iframe class="aspect-ratio--object" src="https://player.vimeo.com/video/`+string(vimeoMatch)+`" frameborder="0" allow="fullscreen; picture-in-picture" allowfullscreen></iframe>
|
<iframe class="aspect-ratio--object" src="https://player.vimeo.com/video/`+string(vimeoMatch)+`" frameborder="0" allow="fullscreen; picture-in-picture" allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if html == "" {
|
if html == "" {
|
||||||
return nil, parser.NoChildren
|
return nil, parser.NoChildren
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Advance(len(urlMatch[0]))
|
reader.Advance(len(match))
|
||||||
return NewEmbed(html), parser.NoChildren
|
return NewEmbed(html), parser.NoChildren
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,22 @@ func (s embedParser) CanAcceptIndentedLine() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s embedParser) previewOrLegitEmbed(name string, legitHtml string) string {
|
||||||
|
if s.Preview {
|
||||||
|
return `
|
||||||
|
<div class="mw6">
|
||||||
|
<div class="aspect-ratio aspect-ratio--16x9">
|
||||||
|
<div class="aspect-ratio--object ba b--dimmest bg-light-gray i black flex items-center justify-center">
|
||||||
|
` + name + ` embed
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
return legitHtml
|
||||||
|
}
|
||||||
|
|
||||||
func extract(re *regexp.Regexp, src []byte, subexpName string) []byte {
|
func extract(re *regexp.Regexp, src []byte, subexpName string) []byte {
|
||||||
m := re.FindSubmatch(src)
|
m := re.FindSubmatch(src)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
|
@ -88,13 +104,22 @@ func extract(re *regexp.Regexp, src []byte, subexpName string) []byte {
|
||||||
return m[re.SubexpIndex(subexpName)]
|
return m[re.SubexpIndex(subexpName)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeYoutubeEmbed(vid string) string {
|
func makeYoutubeEmbed(vid string, preview bool) string {
|
||||||
|
if preview {
|
||||||
|
return `
|
||||||
|
<div class="mw6">
|
||||||
|
<img src="https://img.youtube.com/vi/` + vid + `/hqdefault.jpg">
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
} else {
|
||||||
return `
|
return `
|
||||||
<div class="mw6">
|
<div class="mw6">
|
||||||
<div class="aspect-ratio aspect-ratio--16x9">
|
<div class="aspect-ratio aspect-ratio--16x9">
|
||||||
<iframe class="aspect-ratio--object" src="https://www.youtube-nocookie.com/embed/` + vid + `" frameborder="0" allowfullscreen></iframe>
|
<iframe class="aspect-ratio--object" src="https://www.youtube-nocookie.com/embed/` + vid + `" frameborder="0" allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
@ -155,11 +180,13 @@ func (r *EmbedHTMLRenderer) renderEmbed(w util.BufWriter, source []byte, n gast.
|
||||||
// Extension
|
// Extension
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
type EmbedExtension struct{}
|
type EmbedExtension struct {
|
||||||
|
Preview bool
|
||||||
|
}
|
||||||
|
|
||||||
func (e EmbedExtension) Extend(m goldmark.Markdown) {
|
func (e EmbedExtension) Extend(m goldmark.Markdown) {
|
||||||
m.Parser().AddOptions(parser.WithBlockParsers(
|
m.Parser().AddOptions(parser.WithBlockParsers(
|
||||||
util.Prioritized(NewEmbedParser(), 500),
|
util.Prioritized(embedParser{Preview: e.Preview}, 500),
|
||||||
))
|
))
|
||||||
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
||||||
util.Prioritized(NewEmbedHTMLRenderer(), 500),
|
util.Prioritized(NewEmbedHTMLRenderer(), 500),
|
||||||
|
|
|
@ -90,11 +90,31 @@ func tokenizeBBCode(input string) []token {
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
var md = goldmark.New(
|
var previewMarkdown = goldmark.New(
|
||||||
goldmark.WithExtensions(extension.GFM, SpoilerExtension{}, EmbedExtension{}, bTag{}),
|
goldmark.WithExtensions(
|
||||||
|
extension.GFM,
|
||||||
|
SpoilerExtension{},
|
||||||
|
EmbedExtension{
|
||||||
|
Preview: true,
|
||||||
|
},
|
||||||
|
bTag{},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var realMarkdown = goldmark.New(
|
||||||
|
goldmark.WithExtensions(
|
||||||
|
extension.GFM,
|
||||||
|
SpoilerExtension{},
|
||||||
|
EmbedExtension{},
|
||||||
|
bTag{},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParsePostInput(source string) string {
|
func ParsePostInput(source string, preview bool) string {
|
||||||
|
md := realMarkdown
|
||||||
|
if preview {
|
||||||
|
md = previewMarkdown
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := md.Convert([]byte(source), &buf); err != nil {
|
if err := md.Convert([]byte(source), &buf); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -47,7 +47,7 @@ Mix 'em: [u][/i]wow.[/i][/u]
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func TestBBCodeParsing(t *testing.T) {
|
func TestBBCodeParsing(t *testing.T) {
|
||||||
res := ParsePostInput(`[b]ONE[/b] [i]TWO[/i]`)
|
res := ParsePostInput(`[b]ONE[/b] [i]TWO[/i]`, false)
|
||||||
fmt.Println(res)
|
fmt.Println(res)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
js.Global().Set("parseMarkdown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
js.Global().Set("parseMarkdown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||||
return parsing.ParsePostInput(args[0].String())
|
return parsing.ParsePostInput(args[0].String(), true)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
var done chan bool
|
var done chan bool
|
||||||
|
|
Loading…
Reference in New Issue