Skip to content

Commit

Permalink
enhancement: crop long post on initial page
Browse files Browse the repository at this point in the history
  • Loading branch information
goenning committed Mar 28, 2021
1 parent b4a1f47 commit f799392
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 84 deletions.
18 changes: 0 additions & 18 deletions app/pkg/markdown/markdown.go
Expand Up @@ -18,24 +18,6 @@ var mdExtns = 0 |
blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
blackfriday.EXTENSION_HARD_LINE_BREAK

var simpleHTMLExtensions = 0 |
blackfriday.HTML_USE_XHTML |
blackfriday.HTML_USE_SMARTYPANTS |
blackfriday.HTML_SMARTYPANTS_FRACTIONS |
blackfriday.HTML_SMARTYPANTS_DASHES |
blackfriday.HTML_SKIP_IMAGES |
blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

var simpleRenderer = SimpleRenderer(simpleHTMLExtensions)

// Simple turns a markdown into HTML using few rules
func Simple(input string) template.HTML {
sanitizedInput := html.EscapeString(input)
output := blackfriday.Markdown([]byte(sanitizedInput), simpleRenderer, mdExtns)

return template.HTML(strings.TrimSpace(string(output)))
}

var fullHTMLExtensions = 0 |
blackfriday.HTML_USE_XHTML |
blackfriday.HTML_USE_SMARTYPANTS |
Expand Down
33 changes: 0 additions & 33 deletions app/pkg/markdown/markdown_test.go
Expand Up @@ -78,36 +78,3 @@ How are you?`,
Expect(output).Equals(expected)
}
}

func TestSimpleMarkdown(t *testing.T) {
RegisterT(t)

for input, expected := range map[string]string{
"**Hello World**": `<p><strong>Hello World</strong></p>`,
"[My Link](http://example.com/)": `<p><a href="http://example.com/">My Link</a></p>`,
"![My Image](http://example.com/hello.jpg)": `<p></p>`,
"Go to http://example.com/hello.jpg": `<p>Go to <a href="http://example.com/hello.jpg">http://example.com/hello.jpg</a></p>`,
"~~Option 3~~": `<p><del>Option 3</del></p>`,
"# Hello World": `<p>Hello World</p>`,
"### Hello World": `<p>Hello World</p>`,
"Check this out: `HEEEY`": "<p>Check this out: <code>HEEEY</code></p>",
`-123
-456
-789`: `<p>-123<br />
-456<br />
-789</p>`,
`# Hello World
How are you?`: `<p>Hello World</p>
<p>How are you?</p>`,
`Hello World
How are you?`: `<p>Hello World</p>
<p>How are you?</p>`,
`Hello <b>Beautiful</b> World`: `<p>Hello &lt;b&gt;Beautiful&lt;/b&gt; World</p>`,
} {
output := markdown.Simple(input)
Expect(output).Equals(template.HTML(expected))
}
}
8 changes: 4 additions & 4 deletions app/tasks/tasks.go
Expand Up @@ -142,7 +142,7 @@ func NotifyAboutNewPost(post *models.Post) worker.Task {
"title": post.Title,
"tenantName": c.Tenant().Name,
"userName": c.User().Name,
"content": markdown.Simple(post.Description),
"content": markdown.Full(post.Description),
"postLink": linkWithText(fmt.Sprintf("#%d", post.Number), web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
"view": linkWithText("View it on your browser", web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
"change": linkWithText("change your notification settings", web.BaseURL(c), "/settings"),
Expand Down Expand Up @@ -202,7 +202,7 @@ func NotifyAboutNewComment(post *models.Post, comment *models.NewComment) worker
"title": post.Title,
"tenantName": c.Tenant().Name,
"userName": c.User().Name,
"content": markdown.Simple(comment.Content),
"content": markdown.Full(comment.Content),
"postLink": linkWithText(fmt.Sprintf("#%d", post.Number), web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
"view": linkWithText("View it on your browser", web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
"unsubscribe": linkWithText("unsubscribe from it", web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
Expand Down Expand Up @@ -273,7 +273,7 @@ func NotifyAboutStatusChange(post *models.Post, prevStatus enum.PostStatus) work
"title": post.Title,
"postLink": linkWithText(fmt.Sprintf("#%d", post.Number), web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
"tenantName": c.Tenant().Name,
"content": markdown.Simple(post.Response.Text),
"content": markdown.Full(post.Response.Text),
"status": post.Status.Name(),
"duplicate": duplicate,
"view": linkWithText("View it on your browser", web.BaseURL(c), "/posts/%d/%s", post.Number, post.Slug),
Expand Down Expand Up @@ -333,7 +333,7 @@ func NotifyAboutDeletedPost(post *models.Post) worker.Task {
props := dto.Props{
"title": post.Title,
"tenantName": c.Tenant().Name,
"content": markdown.Simple(post.Response.Text),
"content": markdown.Full(post.Response.Text),
"change": linkWithText("change your notification settings", web.BaseURL(c), "/settings"),
"logo": web.LogoURL(c),
}
Expand Down
2 changes: 1 addition & 1 deletion public/components/SignInModal.tsx
Expand Up @@ -41,7 +41,7 @@ export const SignInModal: React.StatelessComponent<SignInModalProps> = (props) =

return (
<Modal.Window isOpen={props.isOpen} onClose={closeModal}>
<Modal.Header>Sign in to raise your voice</Modal.Header>
<Modal.Header>Sign in to post and vote</Modal.Header>
<Modal.Content>{content}</Modal.Content>
<LegalFooter />
</Modal.Window>
Expand Down
10 changes: 6 additions & 4 deletions public/components/common/MultiLineText.tsx
@@ -1,17 +1,19 @@
import React from "react"
import { markdown } from "@fider/services"
import { markdown, truncate } from "@fider/services"

interface MultiLineTextProps {
className?: string
text?: string
style: "full" | "simple"
maxLength?: number
style: "full" | "plainText"
}

export const MultiLineText = (props: MultiLineTextProps) => {
if (!props.text) {
return <p />
}

const func = props.style === "full" ? markdown.full : markdown.simple
return <div className={`markdown-body ${props.className || ""}`} dangerouslySetInnerHTML={{ __html: func(props.text) }} />
const html = markdown[props.style](props.text)
const className = `markdown-body ${props.className || ""}`
return <div className={className} dangerouslySetInnerHTML={{ __html: props.maxLength ? truncate(html, props.maxLength) : html }} />
}
2 changes: 1 addition & 1 deletion public/pages/Home/components/ListPosts.tsx
Expand Up @@ -24,7 +24,7 @@ const ListPostItem = (props: { post: Post; user?: CurrentUser; tags: Tag[] }) =>
<a className="c-list-item-title" href={`/posts/${props.post.number}/${props.post.slug}`}>
{props.post.title}
</a>
<MultiLineText className="c-list-item-description" text={props.post.description} style="simple" />
<MultiLineText className="c-list-item-description" maxLength={300} text={props.post.description} style="plainText" />
<ShowPostResponse showUser={false} status={props.post.status} response={props.post.response} />
{props.tags.map((tag) => (
<ShowTag key={tag.id} size="tiny" tag={tag} />
Expand Down
2 changes: 1 addition & 1 deletion public/pages/MyNotifications/MyNotifications.page.tsx
Expand Up @@ -39,7 +39,7 @@ export default class MyNotificationsPage extends React.Component<MyNotifications
return (
<ListItem key={n.id}>
<a href={`/notifications/${n.id}`}>
<MultiLineText text={n.title} style="simple" />
<MultiLineText text={n.title} style="full" />
<span className="info">
<Moment date={n.createdAt} />
</span>
Expand Down
2 changes: 1 addition & 1 deletion public/pages/ShowPost/ShowPost.page.tsx
Expand Up @@ -121,7 +121,7 @@ export default class ShowPostPage extends React.Component<ShowPostPageProps, Sho
</Form>
) : (
<>
<MultiLineText className="description" text={this.props.post.description} style="simple" />
<MultiLineText className="description" text={this.props.post.description} style="full" />
{this.props.attachments.map((x) => (
<ImageViewer key={x} bkey={x} />
))}
Expand Down
2 changes: 1 addition & 1 deletion public/pages/ShowPost/components/ShowComment.tsx
Expand Up @@ -149,7 +149,7 @@ export const ShowComment = (props: ShowCommentProps) => {
</Form>
) : (
<>
<MultiLineText text={comment.content} style="simple" />
<MultiLineText text={comment.content} style="full" />
{comment.attachments && comment.attachments.map((x) => <ImageViewer key={x} bkey={x} />)}
</>
)}
Expand Down
25 changes: 13 additions & 12 deletions public/services/markdown.spec.ts
Expand Up @@ -4,51 +4,52 @@ const testCases = [
{
input: "Visit [GitHub](https://github.com) to learn more.",
expectedFull: '<p>Visit <a target="_blank" rel="noopener" href="https://github.com">GitHub</a> to learn more.</p>',
expectedSimple: '<p>Visit <a target="_blank" rel="noopener" href="https://github.com">GitHub</a> to learn more.</p>',
expectedPlainText: "Visit GitHub to learn more.",
},
{
input: "My Picture ![](http://demo.dev.fider.io:3000/images/100/28)",
expectedFull: '<p>My Picture <img alt="" src="http://demo.dev.fider.io:3000/images/100/28"></p>',
expectedSimple: "<p>My Picture </p>",
expectedFull: "<p>My Picture </p>",
expectedPlainText: "My Picture",
},
{
input: "# Hello World",
expectedFull: "<h1>Hello World</h1>",
expectedSimple: "<p>Hello World</p>",
expectedPlainText: "Hello World",
},
{
input: "Hello <b>Beautiful</b> World",
expectedFull: "<p>Hello &lt;b&gt;Beautiful&lt;/b&gt; World</p>",
expectedSimple: "<p>Hello &lt;b&gt;Beautiful&lt;/b&gt; World</p>",
expectedPlainText: "Hello &lt;b&gt;Beautiful&lt;/b&gt; World",
},
{
input: `[Uh oh...]("onerror="alert('XSS'))`,
expectedFull: '<p><a target="_blank" rel="noopener" href="">Uh oh...</a></p>',
expectedSimple: '<p><a target="_blank" rel="noopener" href="">Uh oh...</a></p>',
expectedPlainText: "Uh oh...",
},
{
input: "~~Option 3~~",
expectedFull: "<p><del>Option 3</del></p>",
expectedSimple: "<p><del>Option 3</del></p>",
expectedPlainText: "Option 3",
},
{
input: "Check this out: `HEEEY`",
expectedFull: "<p>Check this out: <code>HEEEY</code></p>",
expectedSimple: "<p>Check this out: <code>HEEEY</code></p>",
expectedPlainText: "Check this out: HEEEY",
},
{
input: `# Hello World
How are you?`,
expectedFull: `<h1>Hello World</h1>
<p>How are you?</p>`,
expectedSimple: `<p>Hello World</p><p>How are you?</p>`,
expectedPlainText: "Hello World How are you?",
},
{
input: `-123
-456
-789`,
expectedFull: "<p>-123<br>-456<br>-789</p>",
expectedSimple: "<p>-123<br>-456<br>-789</p>",
expectedPlainText: "-123 -456 -789",
},
]

Expand All @@ -60,8 +61,8 @@ testCases.forEach((x) => {
})

testCases.forEach((x) => {
test(`Can parse markdown ${x.input} to ${x.expectedSimple} (simple mode)`, () => {
const result = markdown.simple(x.input)
expect(result).toEqual(x.expectedSimple)
test(`Can parse markdown ${x.input} to ${x.expectedPlainText} (plain text)`, () => {
const result = markdown.plainText(x.input)
expect(result).toEqual(x.expectedPlainText)
})
})
24 changes: 17 additions & 7 deletions public/services/markdown.ts
Expand Up @@ -23,14 +23,24 @@ const link = (href: string, title: string, text: string) => {
return `<a href="${href}"${titleAttr} rel="noopener" target="_blank">${text}</a>`
}

const simpleRenderer = new marked.Renderer()
simpleRenderer.heading = (_text, _level, raw) => `<p>${raw}</p>`
simpleRenderer.image = () => ""
simpleRenderer.link = link

const fullRenderer = new marked.Renderer()
fullRenderer.image = () => ""
fullRenderer.link = link

const plainTextRenderer = new marked.Renderer()
plainTextRenderer.link = (_href, _title, text) => text
plainTextRenderer.image = (_href, _title, _text) => ""
plainTextRenderer.br = () => " "
plainTextRenderer.strong = (text) => text
plainTextRenderer.list = (body) => body
plainTextRenderer.listitem = (text) => `${text} `
plainTextRenderer.heading = (text) => text
plainTextRenderer.paragraph = (text) => ` ${text} `
plainTextRenderer.code = (code) => code
plainTextRenderer.codespan = (code) => code
plainTextRenderer.html = (html) => html
plainTextRenderer.del = (text) => text

const entities: { [key: string]: string } = {
"<": "&lt;",
">": "&gt;",
Expand All @@ -43,6 +53,6 @@ export const full = (input: string): string => {
return sanitize(marked(encodeHTML(input), { renderer: fullRenderer }).trim())
}

export const simple = (input: string): string => {
return sanitize(marked(encodeHTML(input), { renderer: simpleRenderer }).trim())
export const plainText = (input: string): string => {
return sanitize(marked(encodeHTML(input), { renderer: plainTextRenderer }).trim())
}
2 changes: 1 addition & 1 deletion public/services/utils.ts
Expand Up @@ -138,7 +138,7 @@ export const uploadedImageURL = (bkey: string | undefined, size?: number): strin
}

export const truncate = (input: string, maxLength: number): string => {
if (input && input.length > 1000) {
if (input && input.length > maxLength) {
return `${input.substr(0, maxLength)}...`
}
return input
Expand Down

0 comments on commit f799392

Please sign in to comment.