diff --git a/README.md b/README.md
index 773f233ba103bda5d5778861851358e480de6e0d..a04c9de3c4491c7dab366e9c6337e95d93a92077 100644
--- a/README.md
+++ b/README.md
@@ -158,6 +158,35 @@ Pages
})
```
+## Special filters
+
+- first (gets first N posts)
+- last (gets last N posts)
+- random (gets random N posts)
+
+```html
+
+{{ range first 10 .Pages }}
+ {{ if and (eq .Type "post") (not .Draft) }}
+
{{ .Title }}
+ {{ end }}
+{{ end }}
+
+
+{{ range last 10 .Pages }}
+ {{ if and (eq .Type "post") (not .Draft) }}
+ {{ .Title }}
+ {{ end }}
+{{ end }}
+
+
+{{ range random 10 .Pages }}
+ {{ if and (eq .Type "post") (not .Draft) }}
+ {{ .Title }}
+ {{ end }}
+{{ end }}
+```
+
## License
[jbmafp](https://github.com/mitjafelicijan/jbmafp) was written by [Mitja
diff --git a/main.go b/main.go
index 8440286edd9a3fd1340ac35d44b50789ae3abfe0..2824041e174ddd7d5d1ea1597f314313d4f56abf 100644
--- a/main.go
+++ b/main.go
@@ -5,10 +5,12 @@ "bytes"
"fmt"
"html/template"
"log"
+ "math/rand"
"net/http"
"os"
"path"
"path/filepath"
+ "reflect"
"sort"
"strings"
"time"
@@ -86,6 +88,50 @@ var EmbedTemplatePost string
//go:embed "files/index.xml"
var EmbedTemplateFeed string
+
+// firstN returns the first n items of a slice.
+func firstN(n int, items interface{}) interface{} {
+ v := reflect.ValueOf(items)
+ if v.Kind() != reflect.Slice {
+ panic("firstN: not a slice")
+ }
+ if v.Len() < n {
+ return items
+ }
+ return v.Slice(0, n).Interface()
+}
+
+// lastN returns the last n items of any slice.
+func lastN(n int, items interface{}) interface{} {
+ v := reflect.ValueOf(items)
+ if v.Kind() != reflect.Slice {
+ panic("lastN: not a slice")
+ }
+ l := v.Len()
+ if l < n {
+ return items
+ }
+ return v.Slice(l-n, l).Interface()
+}
+
+// randomN returns n random items of any slice.
+func randomN(n int, items interface{}) interface{} {
+ v := reflect.ValueOf(items)
+ if v.Kind() != reflect.Slice {
+ panic("randomN: not a slice")
+ }
+ l := v.Len()
+ if l < n {
+ return items
+ }
+ rand.Seed(time.Now().UnixNano())
+ indices := rand.Perm(l)[:n]
+ result := reflect.MakeSlice(v.Type(), n, n)
+ for i, idx := range indices {
+ result.Index(i).Set(v.Index(idx))
+ }
+ return result.Interface()
+}
// Function to clean HTML tags using bluemonday.
func cleanHTMLTags(htmlString string) string {
@@ -284,7 +330,11 @@ templates := includeTemplateList(projectRoot)
templates = append([]string{templatePathname}, templates...)
templates = append([]string{baseTemplatePathname}, templates...)
- t, err := template.ParseFiles(templates...)
+ t, err := template.New("base.html").Funcs(template.FuncMap{
+ "first": firstN,
+ "last": lastN,
+ "random": randomN,
+ }).ParseFiles(templates...)
if err != nil {
panic(err)
}
@@ -335,7 +385,11 @@ templates := includeTemplateList(projectRoot)
templates = append([]string{templatePathname}, templates...)
templates = append([]string{baseTemplatePathname}, templates...)
- t, err := template.ParseFiles(templates...)
+ t, err := template.New("base.html").Funcs(template.FuncMap{
+ "first": firstN,
+ "last": lastN,
+ "random": randomN,
+ }).ParseFiles(templates...)
if err != nil {
panic(err)
}