diff --git a/README.md b/README.md index 3dfe0ab..c4b0e3b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ All additional filters/tags will be registered automatically. - Regulars - **[filesizeformat](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#filesizeformat)** (human-readable filesize; takes bytes as input) - **[slugify](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#slugify)** (creates a slug for a given input) + - **truncatesentences** (returns the first X sentences [like truncatechars/truncatewords]; please provide X as a parameter) - Markup - **markdown** (parses markdown text and outputs HTML; **hint**: use the **safe**-filter to make the output not being escaped) diff --git a/filters.go b/filters.go index 42d202f..e1404d2 100644 --- a/filters.go +++ b/filters.go @@ -3,6 +3,8 @@ package pongo2addons import ( "errors" "time" + "regexp" + "strings" "github.com/flosch/pongo2" @@ -12,9 +14,15 @@ import ( ) func init() { - pongo2.RegisterFilter("markdown", filterMarkdown) + // Regulars pongo2.RegisterFilter("slugify", filterSlugify) pongo2.RegisterFilter("filesizeformat", filterFilesizeformat) + pongo2.RegisterFilter("truncatesentences", filterTruncatesentences) + + // Markup + pongo2.RegisterFilter("markdown", filterMarkdown) + + // Humanize pongo2.RegisterFilter("timeuntil", filterTimeuntilTimesince) pongo2.RegisterFilter("timesince", filterTimeuntilTimesince) pongo2.RegisterFilter("naturaltime", filterTimeuntilTimesince) @@ -35,6 +43,17 @@ func filterFilesizeformat(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, return pongo2.AsValue(humanize.IBytes(uint64(in.Integer()))), nil } +var filterTruncatesentencesRe = regexp.MustCompile(`(?U:.*[\w]{3,}.*([\d][\.!?][\D]|[\D][\.!?][\s]|[\n$]))`) + +func filterTruncatesentences(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { + count := param.Integer() + if count <= 0 { + return pongo2.AsValue(""), nil + } + sentencens := filterTruncatesentencesRe.FindAllString(strings.TrimSpace(in.String()), -1) + return pongo2.AsValue(strings.TrimSpace(strings.Join(sentencens[:min(count, len(sentencens))], ""))), nil +} + func filterTimeuntilTimesince(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { basetime, is_time := in.Interface().(time.Time) if !is_time { diff --git a/filters_test.go b/filters_test.go index bb2e773..70fbbce 100644 --- a/filters_test.go +++ b/filters_test.go @@ -18,6 +18,9 @@ type TestSuite1 struct{} var _ = Suite(&TestSuite1{}) +// Taken from http://www.florian-schlachter.de/post/pongo2-10-rc1/ +const demoText = `This is a first sentencen with a 4.50 number. The second one is even more fun! Isn't it? Last sentence, okay.` + func (s *TestSuite1) TestFilters(c *C) { // Markdown c.Assert(pongo2.RenderTemplateString("{{ \"**test**\"|markdown|safe }}", nil), Equals, "

test

\n") @@ -70,4 +73,8 @@ func (s *TestSuite1) TestFilters(c *C) { // Ordinal c.Assert(pongo2.RenderTemplateString("{{ 1|ordinal }} {{ 2|ordinal }} {{ 3|ordinal }} {{ 18241|ordinal }}", nil), Equals, "1st 2nd 3rd 18241st") + + // Truncatesentences + c.Assert(pongo2.RenderTemplateString("{{ text|truncatesentences:3|safe }}", pongo2.Context{"text": demoText}), + Equals, "This is a first sentencen with a 4.50 number. The second one is even more fun! Isn't it?") } diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..008052c --- /dev/null +++ b/helpers.go @@ -0,0 +1,15 @@ +package pongo2addons + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func min(a, b int) int { + if a < b { + return a + } + return b +}