1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-27 09:34:41 +01:00
gojekyll/dynamic_page.go

151 lines
4.0 KiB
Go
Raw Normal View History

package gojekyll
import (
"bytes"
"io"
"io/ioutil"
"path/filepath"
"regexp"
2017-06-17 02:11:52 +02:00
"github.com/osteele/gojekyll/helpers"
"github.com/russross/blackfriday"
yaml "gopkg.in/yaml.v2"
)
// DynamicPage is a static page, that includes frontmatter.
type DynamicPage struct {
pageFields
Content []byte
}
// Static returns a bool indicating that the page is a not static page.
2017-06-19 04:26:49 +02:00
func (page *DynamicPage) Static() bool { return false }
// NewDynamicPage reads the front matter from a file to create a new DynamicPage.
func NewDynamicPage(fields pageFields) (p *DynamicPage, err error) {
2017-06-17 02:06:55 +02:00
data, err := ioutil.ReadFile(filepath.Join(fields.site.Source, fields.relpath))
if err != nil {
return
}
2017-06-17 02:49:28 +02:00
// Replace Windows linefeeds. This allows regular expressions to work.
data = bytes.Replace(data, []byte("\r\n"), []byte("\n"), -1)
frontMatter, err := readFrontMatter(&data)
if err != nil {
return
}
fields.frontMatter = MergeVariableMaps(fields.frontMatter, frontMatter)
return &DynamicPage{
pageFields: fields,
Content: data,
}, nil
}
func readFrontMatter(sourcePtr *[]byte) (frontMatter VariableMap, err error) {
var (
source = *sourcePtr
start = 0
)
if match := frontMatterMatcher.FindSubmatchIndex(source); match != nil {
start = match[1]
if err = yaml.Unmarshal(source[match[2]:match[3]], &frontMatter); err != nil {
return
}
} else if match := emptyFontMatterMatcher.FindSubmatchIndex(source); match != nil {
start = match[1]
}
// This fixes the line numbers for template errors
2017-06-17 02:06:55 +02:00
// TODO find a less hack-ey solution
*sourcePtr = append(
regexp.MustCompile(`[^\n\r]+`).ReplaceAllLiteral(source[:start], []byte{}),
source[start:]...)
return
}
// TemplateObject returns the attributes of the template page object.
2017-06-19 04:26:49 +02:00
func (page *DynamicPage) TemplateObject() VariableMap {
var (
2017-06-19 04:26:49 +02:00
relpath = page.relpath
2017-06-17 02:06:55 +02:00
ext = filepath.Ext(relpath)
2017-06-19 04:26:49 +02:00
root = helpers.PathWithoutExtension(page.relpath)
2017-06-17 02:06:55 +02:00
base = filepath.Base(root)
)
data := VariableMap{
2017-06-17 02:06:55 +02:00
"path": relpath,
2017-06-19 04:26:49 +02:00
"url": page.Permalink(),
// TODO content output
// not documented, but present in both collection and non-collection pages
2017-06-19 04:26:49 +02:00
"permalink": page.Permalink(),
// TODO only in non-collection pages:
// TODO dir
// TODO name
// TODO next previous
// TODO Documented as present in all pages, but de facto only defined for collection pages
"id": base,
"title": base, // TODO capitalize
// TODO date (of the collection?) 2017-06-15 07:44:21 -0400
// TODO excerpt category? categories tags
// TODO slug
// TODO Only present in collection pages https://jekyllrb.com/docs/collections/#documents
2017-06-19 04:26:49 +02:00
"relative_path": page.Path(),
// TODO collection(name)
// TODO undocumented; only present in collection pages:
"ext": ext,
}
2017-06-19 04:26:49 +02:00
for k, v := range page.frontMatter {
switch k {
// doc implies these aren't present, but they appear to be present in a collection page:
// case "layout", "published":
case "permalink":
// omit this, in order to use the value above
default:
data[k] = v
}
}
return data
}
// TemplateVariables returns the local variables for template evaluation
2017-06-19 04:26:49 +02:00
func (page *DynamicPage) TemplateVariables() VariableMap {
return VariableMap{
2017-06-19 04:26:49 +02:00
"page": page.TemplateObject(),
"site": page.site.Variables,
}
}
// DebugVariables returns a map that's useful to present during diagnostics.
// For a dynamic page, this is the local variable map that is used for template evaluation.
2017-06-19 04:26:49 +02:00
func (page *DynamicPage) DebugVariables() VariableMap {
return page.TemplateVariables()
}
// Write applies Liquid and Markdown, as appropriate.
2017-06-19 04:26:49 +02:00
func (page *DynamicPage) Write(w io.Writer) (err error) {
body, err := page.site.LiquidEngine().ParseAndRender(page.Content, page.TemplateVariables())
if err != nil {
2017-06-19 04:26:49 +02:00
return helpers.PathError(err, "Liquid Error", page.Source())
}
2017-06-19 04:26:49 +02:00
if page.IsMarkdown() {
body = blackfriday.MarkdownCommon(body)
2017-06-19 04:26:49 +02:00
body, err = page.applyLayout(page.frontMatter, body)
if err != nil {
return
}
}
2017-06-19 04:26:49 +02:00
if page.Site().IsSassPath(page.relpath) {
return page.writeSass(w, body)
}
_, err = w.Write(body)
return
}