Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hugolib: Add parameter option for .Summary #5806

Merged
merged 3 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions helpers/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ import (
// SummaryDivider denotes where content summarization should end. The default is "<!--more-->".
var SummaryDivider = []byte("<!--more-->")

var (
openingPTag = []byte("<p>")
closingPTag = []byte("</p>")
paragraphIndicator = []byte("<p")
)

// ContentSpec provides functionality to render markdown content.
type ContentSpec struct {
BlackFriday *BlackFriday
Expand Down Expand Up @@ -580,6 +586,21 @@ func (c *ContentSpec) TruncateWordsToWholeSentence(s string) (string, bool) {
return strings.TrimSpace(s[:endIndex]), endIndex < len(s)
}

// TrimShortHTML removes the <p>/</p> tags from HTML input in the situation
// where said tags are the only <p> tags in the input and enclose the content
// of the input (whitespace excluded).
func (c *ContentSpec) TrimShortHTML(input []byte) []byte {
first := bytes.Index(input, paragraphIndicator)
last := bytes.LastIndex(input, paragraphIndicator)
if first == last {
input = bytes.TrimSpace(input)
input = bytes.TrimPrefix(input, openingPTag)
input = bytes.TrimSuffix(input, closingPTag)
input = bytes.TrimSpace(input)
}
return input
}

func isEndOfSentence(r rune) bool {
return r == '.' || r == '?' || r == '!' || r == '"' || r == '\n'
}
Expand Down
22 changes: 22 additions & 0 deletions helpers/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ import (

const tstHTMLContent = "<!DOCTYPE html><html><head><script src=\"http://two/foobar.js\"></script></head><body><nav><ul><li hugo-nav=\"section_0\"></li><li hugo-nav=\"section_1\"></li></ul></nav><article>content <a href=\"http://two/foobar\">foobar</a>. Follow up</article><p>This is some text.<br>And some more.</p></body></html>"

func TestTrimShortHTML(t *testing.T) {
tests := []struct {
input, output []byte
}{
{[]byte(""), []byte("")},
{[]byte("Plain text"), []byte("Plain text")},
{[]byte(" \t\n Whitespace text\n\n"), []byte("Whitespace text")},
{[]byte("<p>Simple paragraph</p>"), []byte("Simple paragraph")},
{[]byte("\n \n \t <p> \t Whitespace\nHTML \n\t </p>\n\t"), []byte("Whitespace\nHTML")},
{[]byte("<p>Multiple</p><p>paragraphs</p>"), []byte("<p>Multiple</p><p>paragraphs</p>")},
{[]byte("<p>Nested<p>paragraphs</p></p>"), []byte("<p>Nested<p>paragraphs</p></p>")},
}

c := newTestContentSpec()
for i, test := range tests {
output := c.TrimShortHTML(test.input)
if bytes.Compare(test.output, output) != 0 {
t.Errorf("Test %d failed. Expected %q got %q", i, test.output, output)
}
}
}

func TestStripHTML(t *testing.T) {
type test struct {
input, expected string
Expand Down
5 changes: 5 additions & 0 deletions hugolib/page__meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ type pageMeta struct {
title string
linkTitle string

summary string

resourcePath string

weight int
Expand Down Expand Up @@ -360,6 +362,9 @@ func (pm *pageMeta) setMetadata(p *pageState, frontmatter map[string]interface{}
case "linktitle":
pm.linkTitle = cast.ToString(v)
pm.params[loki] = pm.linkTitle
case "summary":
pm.summary = cast.ToString(v)
pm.params[loki] = pm.summary
case "description":
pm.description = cast.ToString(v)
pm.params[loki] = pm.description
Expand Down
10 changes: 9 additions & 1 deletion hugolib/page__per_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ func newPageContentOutput(p *pageState) func(f output.Format) (*pageContentOutpu
cp.summary = helpers.BytesToHTML(summary)
}
}
} else if cp.p.m.summary != "" {
html := cp.p.s.ContentSpec.RenderBytes(&helpers.RenderingContext{
Content: []byte(cp.p.m.summary), RenderTOC: false, PageFmt: cp.p.m.markup,
Cfg: p.Language(),
DocumentID: p.File().UniqueID(), DocumentName: p.File().Path(),
Config: cp.p.getRenderingConfig()})
html = cp.p.s.ContentSpec.TrimShortHTML(html)
cp.summary = helpers.BytesToHTML(html)
}
}

Expand Down Expand Up @@ -271,7 +279,7 @@ func (p *pageContentOutput) WordCount() int {
}

func (p *pageContentOutput) setAutoSummary() error {
if p.p.source.hasSummaryDivider {
if p.p.source.hasSummaryDivider || p.p.m.summary != "" {
return nil
}

Expand Down
52 changes: 52 additions & 0 deletions hugolib/page_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,33 @@ const (

simplePageRFC3339Date = "---\ntitle: RFC3339 Date\ndate: \"2013-05-17T16:59:30Z\"\n---\nrfc3339 content"

simplePageWithoutSummaryDelimiter = `---
title: SimpleWithoutSummaryDelimiter
---
[Lorem ipsum](https://lipsum.com/) dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Additional text.

Further text.
`

simplePageWithSummaryDelimiter = `---
title: Simple
---
Summary Next Line

<!--more-->
Some more text
`

simplePageWithSummaryParameter = `---
title: SimpleWithSummaryParameter
summary: "Page with summary parameter and [a link](http://www.example.com/)"
---

Some text.

Some more text.
`

simplePageWithSummaryDelimiterAndMarkdownThatCrossesBorder = `---
Expand Down Expand Up @@ -491,6 +511,22 @@ func TestCreateNewPage(t *testing.T) {
testAllMarkdownEnginesForPages(t, assertFunc, settings, simplePage)
}

func TestPageSummary(t *testing.T) {
t.Parallel()
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
p := pages[0]
checkPageTitle(t, p, "SimpleWithoutSummaryDelimiter")
// Source is not Asciidoctor- or RST-compatibile so don't test them
if ext != "ad" && ext != "rst" {
checkPageContent(t, p, normalizeExpected(ext, "<p><a href=\"https://lipsum.com/\">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n\n<p>Additional text.</p>\n\n<p>Further text.</p>\n"), ext)
checkPageSummary(t, p, normalizeExpected(ext, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Additional text."), ext)
}
checkPageType(t, p, "page")
}

testAllMarkdownEnginesForPages(t, assertFunc, nil, simplePageWithoutSummaryDelimiter)
}

func TestPageWithDelimiter(t *testing.T) {
t.Parallel()
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
Expand All @@ -504,6 +540,22 @@ func TestPageWithDelimiter(t *testing.T) {
testAllMarkdownEnginesForPages(t, assertFunc, nil, simplePageWithSummaryDelimiter)
}

func TestPageWithSummaryParameter(t *testing.T) {
t.Parallel()
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
p := pages[0]
checkPageTitle(t, p, "SimpleWithSummaryParameter")
checkPageContent(t, p, normalizeExpected(ext, "<p>Some text.</p>\n\n<p>Some more text.</p>\n"), ext)
// Summary is not Asciidoctor- or RST-compatibile so don't test them
if ext != "ad" && ext != "rst" {
checkPageSummary(t, p, normalizeExpected(ext, "Page with summary parameter and <a href=\"http://www.example.com/\">a link</a>"), ext)
}
checkPageType(t, p, "page")
}

testAllMarkdownEnginesForPages(t, assertFunc, nil, simplePageWithSummaryParameter)
}

// Issue #3854
// Also see https://github.com/gohugoio/hugo/issues/3977
func TestPageWithDateFields(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions hugolib/rss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func TestRSSOutput(t *testing.T) {
if c != rssLimit {
t.Errorf("incorrect RSS item count: expected %d, got %d", rssLimit, c)
}

// Encoded summary
th.assertFileContent(filepath.Join("public", rssURI), "<?xml", "description", "A &lt;em&gt;custom&lt;/em&gt; summary")
}

// Before Hugo 0.49 we set the pseudo page kind RSS on the page when output to RSS.
Expand Down
1 change: 1 addition & 0 deletions hugolib/site_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ date = "2012-01-01"
publishdate = "2012-01-01"
my_param = "baz"
my_date = 2010-05-27T07:32:00Z
summary = "A _custom_ summary"
categories = [ "hugo" ]
+++
Front Matter with Ordered Pages 4. This is longer content`
Expand Down
16 changes: 2 additions & 14 deletions tpl/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package transform

import (
"bytes"
"html"
"html/template"

Expand Down Expand Up @@ -91,12 +90,6 @@ func (ns *Namespace) HTMLUnescape(s interface{}) (string, error) {
return html.UnescapeString(ss), nil
}

var (
markdownTrimPrefix = []byte("<p>")
markdownTrimSuffix = []byte("</p>\n")
markdownParagraphIndicator = []byte("<p")
)

// Markdownify renders a given input from Markdown to HTML.
func (ns *Namespace) Markdownify(s interface{}) (template.HTML, error) {
ss, err := cast.ToStringE(s)
Expand All @@ -114,14 +107,9 @@ func (ns *Namespace) Markdownify(s interface{}) (template.HTML, error) {
)

// Strip if this is a short inline type of text.
first := bytes.Index(m, markdownParagraphIndicator)
last := bytes.LastIndex(m, markdownParagraphIndicator)
if first == last {
m = bytes.TrimPrefix(m, markdownTrimPrefix)
m = bytes.TrimSuffix(m, markdownTrimSuffix)
}
m = ns.deps.ContentSpec.TrimShortHTML(m)

return template.HTML(m), nil
return helpers.BytesToHTML(m), nil
}

// Plainify returns a copy of s with all HTML tags removed.
Expand Down