From 99d9cbbfd74aaaacafdc44776aad21c17a9f71ae Mon Sep 17 00:00:00 2001
From: Jim McDonald
Date: Mon, 1 Apr 2019 12:44:03 +0100
Subject: [PATCH 1/3] hugolib: Add parameter option for .Summary
Add the ability to have a `summary` page variable that overrides
the auto-generated summary. Logic for obtaining summary becomes:
* if summary divider is present in content use the text above it
* if summary variables is present in page metadata use that
* auto-generate summary from first _x_ words of the content
Fixes #5800
---
hugolib/page__meta.go | 5 ++++
hugolib/page__per_output.go | 13 +++++++++-
hugolib/page_test.go | 52 +++++++++++++++++++++++++++++++++++++
hugolib/rss_test.go | 3 +++
hugolib/site_test.go | 1 +
5 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/hugolib/page__meta.go b/hugolib/page__meta.go
index 9f5f369b3ad..a6b288be02c 100644
--- a/hugolib/page__meta.go
+++ b/hugolib/page__meta.go
@@ -63,6 +63,8 @@ type pageMeta struct {
title string
linkTitle string
+ summary string
+
resourcePath string
weight int
@@ -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
diff --git a/hugolib/page__per_output.go b/hugolib/page__per_output.go
index 05b35cc8703..96924c5afc5 100644
--- a/hugolib/page__per_output.go
+++ b/hugolib/page__per_output.go
@@ -128,6 +128,17 @@ 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()})
+ // Strip enclosing
+ html = []byte(strings.TrimSpace(string(html)))
+ html = []byte(strings.TrimPrefix(string(html), "
"))
+ html = []byte(strings.TrimSuffix(string(html), "
"))
+ cp.summary = helpers.BytesToHTML(html)
}
}
@@ -271,7 +282,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
}
diff --git a/hugolib/page_test.go b/hugolib/page_test.go
index 570d09ac657..595c5a0922d 100644
--- a/hugolib/page_test.go
+++ b/hugolib/page_test.go
@@ -45,6 +45,16 @@ 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
---
@@ -52,6 +62,16 @@ Summary Next Line
Some more text
+`
+
+ simplePageWithSummaryParameter = `---
+title: SimpleWithSummaryParameter
+summary: "Page with summary parameter and [a link](http://www.example.com/)"
+---
+
+Some text.
+
+Some more text.
`
simplePageWithSummaryDelimiterAndMarkdownThatCrossesBorder = `---
@@ -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 RST-compatibile so don't test for it
+ if ext != "rst" {
+ checkPageContent(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.
\n\n
Additional text.
\n\n
Further text.
\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) {
@@ -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, "
Some text.
\n\n
Some more text.
\n"), ext)
+ // Summary is not RST-compatibile so don't test for it
+ if ext != "rst" {
+ checkPageSummary(t, p, normalizeExpected(ext, "Page with summary parameter and a link"), 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) {
diff --git a/hugolib/rss_test.go b/hugolib/rss_test.go
index 683a737c59b..38f0f1effb3 100644
--- a/hugolib/rss_test.go
+++ b/hugolib/rss_test.go
@@ -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), "
Date: Thu, 4 Apr 2019 15:53:49 +0100
Subject: [PATCH 2/3] Do not include Asciidoc processor tests when using
Markdown source
---
hugolib/page_test.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/hugolib/page_test.go b/hugolib/page_test.go
index 595c5a0922d..a4131c86362 100644
--- a/hugolib/page_test.go
+++ b/hugolib/page_test.go
@@ -516,8 +516,8 @@ func TestPageSummary(t *testing.T) {
assertFunc := func(t *testing.T, ext string, pages page.Pages) {
p := pages[0]
checkPageTitle(t, p, "SimpleWithoutSummaryDelimiter")
- // Source is not RST-compatibile so don't test for it
- if ext != "rst" {
+ // Source is not Asciidoctor- or RST-compatibile so don't test them
+ if ext != "ad" && ext != "rst" {
checkPageContent(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.
\n\n
Additional text.
\n\n
Further text.
\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)
}
@@ -546,8 +546,8 @@ func TestPageWithSummaryParameter(t *testing.T) {
p := pages[0]
checkPageTitle(t, p, "SimpleWithSummaryParameter")
checkPageContent(t, p, normalizeExpected(ext, "
Some text.
\n\n
Some more text.
\n"), ext)
- // Summary is not RST-compatibile so don't test for it
- if ext != "rst" {
+ // 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 link"), ext)
}
checkPageType(t, p, "page")
From f9f657052cbc1012e83973e2fd97f62eac2a1177 Mon Sep 17 00:00:00 2001
From: Jim McDonald
Date: Thu, 4 Apr 2019 23:41:19 +0100
Subject: [PATCH 3/3] Add TrimShortHTML function
---
helpers/content.go | 21 +++++++++++++++++++++
helpers/content_test.go | 22 ++++++++++++++++++++++
hugolib/page__per_output.go | 5 +----
tpl/transform/transform.go | 16 ++--------------
4 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/helpers/content.go b/helpers/content.go
index be5090c211d..3892647bb29 100644
--- a/helpers/content.go
+++ b/helpers/content.go
@@ -42,6 +42,12 @@ import (
// SummaryDivider denotes where content summarization should end. The default is "".
var SummaryDivider = []byte("")
+var (
+ openingPTag = []byte("
")
+ closingPTag = []byte("
")
+ paragraphIndicator = []byte("
/
tags from HTML input in the situation
+// where said tags are the only
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'
}
diff --git a/helpers/content_test.go b/helpers/content_test.go
index 1dd4a2fb83b..709c811420c 100644
--- a/helpers/content_test.go
+++ b/helpers/content_test.go
@@ -29,6 +29,28 @@ import (
const tstHTMLContent = "