diff --git a/helpers/content.go b/helpers/content.go
index a70fa6075..ee8356c22 100644
--- a/helpers/content.go
+++ b/helpers/content.go
@@ -35,10 +35,10 @@ import (
"sync"
)
-// Length of the summary that Hugo extracts from a content.
+// SummaryLength is the length of the summary that Hugo extracts from a content.
var SummaryLength = 70
-// Custom divider let's user define where summarization ends.
+// SummaryDivider denotes where content summarization should end. The default is "".
var SummaryDivider = []byte("")
// Blackfriday holds configuration values for Blackfriday rendering.
@@ -157,7 +157,7 @@ func BytesToHTML(b []byte) template.HTML {
return template.HTML(string(b))
}
-// GetHtmlRenderer creates a new Renderer with the given configuration.
+// GetHTMLRenderer creates a new Renderer with the given configuration.
func GetHTMLRenderer(defaultFlags int, ctx *RenderingContext) blackfriday.Renderer {
renderParameters := blackfriday.HtmlRendererParameters{
FootnoteAnchorPrefix: viper.GetString("FootnoteAnchorPrefix"),
@@ -237,7 +237,7 @@ func markdownRenderWithTOC(ctx *RenderingContext) []byte {
getMarkdownExtensions(ctx))
}
-// mmark
+// GetMmarkHtmlRenderer returns markdown html renderer.
func GetMmarkHtmlRenderer(defaultFlags int, ctx *RenderingContext) mmark.Renderer {
renderParameters := mmark.HtmlRendererParameters{
FootnoteAnchorPrefix: viper.GetString("FootnoteAnchorPrefix"),
@@ -259,6 +259,7 @@ func GetMmarkHtmlRenderer(defaultFlags int, ctx *RenderingContext) mmark.Rendere
}
}
+// GetMmarkExtensions returns markdown extensions.
func GetMmarkExtensions(ctx *RenderingContext) int {
flags := 0
flags |= mmark.EXTENSION_TABLES
@@ -283,17 +284,12 @@ func GetMmarkExtensions(ctx *RenderingContext) int {
return flags
}
+// MmarkRender renders markdowns.
func MmarkRender(ctx *RenderingContext) []byte {
return mmark.Parse(ctx.Content, GetMmarkHtmlRenderer(0, ctx),
GetMmarkExtensions(ctx)).Bytes()
}
-func MmarkRenderWithTOC(ctx *RenderingContext) []byte {
- return mmark.Parse(ctx.Content,
- GetMmarkHtmlRenderer(0, ctx),
- GetMmarkExtensions(ctx)).Bytes()
-}
-
// ExtractTOC extracts Table of Contents from content.
func ExtractTOC(content []byte) (newcontent []byte, toc []byte) {
origContent := make([]byte, len(content))
@@ -331,7 +327,7 @@ func ExtractTOC(content []byte) (newcontent []byte, toc []byte) {
}
// RenderingContext holds contextual information, like content and configuration,
-// for a given content renderin.g
+// for a given content rendering.
type RenderingContext struct {
Content []byte
PageFmt string
@@ -361,7 +357,7 @@ func RenderBytesWithTOC(ctx *RenderingContext) []byte {
case "asciidoc":
return []byte(GetAsciidocContent(ctx.Content))
case "mmark":
- return MmarkRenderWithTOC(ctx)
+ return MmarkRender(ctx)
case "rst":
return []byte(GetRstContent(ctx.Content))
}
@@ -403,17 +399,7 @@ func RemoveSummaryDivider(content []byte) []byte {
return bytes.Replace(content, SummaryDivider, []byte(""), -1)
}
-// TruncateWords takes content and an int and shortens down the number
-// of words in the content down to the number of int.
-func TruncateWords(s string, max int) string {
- words := strings.Fields(s)
- if max > len(words) {
- return strings.Join(words, " ")
- }
-
- return strings.Join(words[:max], " ")
-}
-
+// TruncateWordsByRune truncates words by runes.
func TruncateWordsByRune(words []string, max int) (string, bool) {
count := 0
for index, word := range words {
@@ -430,9 +416,8 @@ func TruncateWordsByRune(words []string, max int) (string, bool) {
if count >= max {
truncatedWords := append(words[:index], word[:ri])
return strings.Join(truncatedWords, " "), true
- } else {
- count++
}
+ count++
}
}
}
diff --git a/helpers/content_test.go b/helpers/content_test.go
index dfab5f980..ba7971605 100644
--- a/helpers/content_test.go
+++ b/helpers/content_test.go
@@ -14,10 +14,14 @@
package helpers
import (
+ "bytes"
"html/template"
+ "reflect"
"strings"
"testing"
+ "github.com/miekg/mmark"
+ "github.com/russross/blackfriday"
"github.com/stretchr/testify/assert"
)
@@ -33,6 +37,7 @@ func TestStripHTML(t *testing.T) {
{" strip br
", " strip br\n"},
{" strip br2
", " strip br2\n"},
{"This is a\nnewline", "This is a newline"},
+ {"No Tags", "No Tags"},
}
for i, d := range data {
output := StripHTML(d.input)
@@ -117,3 +122,293 @@ func TestTruncateWordsByRune(t *testing.T) {
}
}
}
+
+func TestGetHTMLRendererFlags(t *testing.T) {
+ ctx := &RenderingContext{}
+ renderer := GetHTMLRenderer(blackfriday.HTML_USE_XHTML, ctx)
+ flags := renderer.GetFlags()
+ if flags&blackfriday.HTML_USE_XHTML != blackfriday.HTML_USE_XHTML {
+ t.Errorf("Test flag: %d was not found amongs set flags:%d; Result: %d", blackfriday.HTML_USE_XHTML, flags, flags&blackfriday.HTML_USE_XHTML)
+ }
+}
+
+func TestGetHTMLRendererAllFlags(t *testing.T) {
+ type data struct {
+ testFlag int
+ }
+
+ allFlags := []data{
+ {blackfriday.HTML_USE_XHTML},
+ {blackfriday.HTML_FOOTNOTE_RETURN_LINKS},
+ {blackfriday.HTML_USE_SMARTYPANTS},
+ {blackfriday.HTML_SMARTYPANTS_ANGLED_QUOTES},
+ {blackfriday.HTML_SMARTYPANTS_FRACTIONS},
+ {blackfriday.HTML_HREF_TARGET_BLANK},
+ {blackfriday.HTML_SMARTYPANTS_DASHES},
+ {blackfriday.HTML_SMARTYPANTS_LATEX_DASHES},
+ }
+ defaultFlags := blackfriday.HTML_USE_XHTML
+ ctx := &RenderingContext{}
+ ctx.Config = ctx.getConfig()
+ ctx.Config.AngledQuotes = true
+ ctx.Config.Fractions = true
+ ctx.Config.HrefTargetBlank = true
+ ctx.Config.LatexDashes = true
+ ctx.Config.PlainIDAnchors = true
+ ctx.Config.SmartDashes = true
+ ctx.Config.Smartypants = true
+ ctx.Config.SourceRelativeLinksEval = true
+ renderer := GetHTMLRenderer(defaultFlags, ctx)
+ actualFlags := renderer.GetFlags()
+ var expectedFlags int
+ //OR-ing flags together...
+ for _, d := range allFlags {
+ expectedFlags |= d.testFlag
+ }
+ if expectedFlags != actualFlags {
+ t.Errorf("Expected flags (%d) did not equal actual (%d) flags.", expectedFlags, actualFlags)
+ }
+}
+
+func TestGetHTMLRendererAnchors(t *testing.T) {
+ ctx := &RenderingContext{}
+ ctx.DocumentID = "testid"
+ ctx.Config = ctx.getConfig()
+ ctx.Config.PlainIDAnchors = false
+
+ actualRenderer := GetHTMLRenderer(0, ctx)
+ headerBuffer := &bytes.Buffer{}
+ footnoteBuffer := &bytes.Buffer{}
+ expectedFootnoteHref := []byte("href=\"#fn:testid:href\"")
+ expectedHeaderID := []byte("
testContent
\n") + if !bytes.Equal(actualRenderedMarkdown, expectedRenderedMarkdown) { + t.Errorf("Actual rendered Markdown (%s) did not match expected markdown (%s)", actualRenderedMarkdown, expectedRenderedMarkdown) + } +} + +func TestGetMarkdownRendererWithTOC(t *testing.T) { + ctx := &RenderingContext{} + ctx.Content = []byte("testContent") + ctx.Config = ctx.getConfig() + actualRenderedMarkdown := markdownRenderWithTOC(ctx) + expectedRenderedMarkdown := []byte("\n\ntestContent
\n") + if !bytes.Equal(actualRenderedMarkdown, expectedRenderedMarkdown) { + t.Errorf("Actual rendered Markdown (%s) did not match expected markdown (%s)", actualRenderedMarkdown, expectedRenderedMarkdown) + } +} + +func TestGetMmarkExtensions(t *testing.T) { + //TODO: This is doing the same just with different marks... + type data struct { + testFlag int + } + ctx := &RenderingContext{} + ctx.Config = ctx.getConfig() + ctx.Config.Extensions = []string{"tables"} + ctx.Config.ExtensionsMask = []string{""} + allExtensions := []data{ + {mmark.EXTENSION_TABLES}, + {mmark.EXTENSION_FENCED_CODE}, + {mmark.EXTENSION_AUTOLINK}, + {mmark.EXTENSION_SPACE_HEADERS}, + {mmark.EXTENSION_CITATION}, + {mmark.EXTENSION_TITLEBLOCK_TOML}, + {mmark.EXTENSION_HEADER_IDS}, + {mmark.EXTENSION_AUTO_HEADER_IDS}, + {mmark.EXTENSION_UNIQUE_HEADER_IDS}, + {mmark.EXTENSION_FOOTNOTES}, + {mmark.EXTENSION_SHORT_REF}, + {mmark.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK}, + {mmark.EXTENSION_INCLUDE}, + } + + actualFlags := GetMmarkExtensions(ctx) + for _, e := range allExtensions { + if actualFlags&e.testFlag != e.testFlag { + t.Errorf("Flag %v was not found in the list of extensions.", e) + } + } +} + +func TestMmarkRender(t *testing.T) { + ctx := &RenderingContext{} + ctx.Content = []byte("testContent") + ctx.Config = ctx.getConfig() + actualRenderedMarkdown := MmarkRender(ctx) + expectedRenderedMarkdown := []byte("testContent
\n") + if !bytes.Equal(actualRenderedMarkdown, expectedRenderedMarkdown) { + t.Errorf("Actual rendered Markdown (%s) did not match expected markdown (%s)", actualRenderedMarkdown, expectedRenderedMarkdown) + } +} + +func TestExtractTOCNormalContent(t *testing.T) { + content := []byte("