Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Łukasz Nowak
caddy
Commits
f2f7e682
Commit
f2f7e682
authored
May 09, 2015
by
Matt Holt
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #68 from abiosoft/master
Markdown: support for templates and metadata
parents
2743f978
2f5e2f39
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
650 additions
and
49 deletions
+650
-49
config/setup/markdown.go
config/setup/markdown.go
+23
-1
middleware/markdown/markdown.go
middleware/markdown/markdown.go
+41
-48
middleware/markdown/metadata.go
middleware/markdown/metadata.go
+239
-0
middleware/markdown/metadata_test.go
middleware/markdown/metadata_test.go
+165
-0
middleware/markdown/process.go
middleware/markdown/process.go
+182
-0
No files found.
config/setup/markdown.go
View file @
f2f7e682
...
...
@@ -2,6 +2,8 @@ package setup
import
(
"net/http"
"path"
"path/filepath"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/markdown"
...
...
@@ -33,7 +35,10 @@ func markdownParse(c *Controller) ([]markdown.Config, error) {
for
c
.
Next
()
{
md
:=
markdown
.
Config
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
Templates
:
make
(
map
[
string
]
string
),
StaticFiles
:
make
(
map
[
string
]
string
),
StaticDir
:
path
.
Join
(
c
.
Root
,
markdown
.
StaticDir
),
}
// Get the path scope
...
...
@@ -61,6 +66,23 @@ func markdownParse(c *Controller) ([]markdown.Config, error) {
return
mdconfigs
,
c
.
ArgErr
()
}
md
.
Scripts
=
append
(
md
.
Scripts
,
c
.
Val
())
case
"template"
:
tArgs
:=
c
.
RemainingArgs
()
switch
len
(
tArgs
)
{
case
0
:
return
mdconfigs
,
c
.
ArgErr
()
case
1
:
if
_
,
ok
:=
md
.
Templates
[
markdown
.
DefaultTemplate
];
ok
{
return
mdconfigs
,
c
.
Err
(
"only one default template is allowed, use alias."
)
}
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
0
])
md
.
Templates
[
markdown
.
DefaultTemplate
]
=
fpath
case
2
:
fpath
:=
filepath
.
Clean
(
c
.
Root
+
string
(
filepath
.
Separator
)
+
tArgs
[
1
])
md
.
Templates
[
tArgs
[
0
]]
=
fpath
default
:
return
mdconfigs
,
c
.
ArgErr
()
}
default
:
return
mdconfigs
,
c
.
Err
(
"Expected valid markdown configuration property"
)
}
...
...
middleware/markdown/markdown.go
View file @
f2f7e682
...
...
@@ -3,11 +3,9 @@
package
markdown
import
(
"bytes"
"io/ioutil"
"net/http"
"os"
"path"
"strings"
"github.com/mholt/caddy/middleware"
...
...
@@ -33,6 +31,16 @@ type Markdown struct {
IndexFiles
[]
string
}
// Helper function to check if a file is an index file
func
(
m
Markdown
)
IsIndexFile
(
file
string
)
bool
{
for
_
,
f
:=
range
m
.
IndexFiles
{
if
f
==
file
{
return
true
}
}
return
false
}
// Config stores markdown middleware configurations.
type
Config
struct
{
// Markdown renderer
...
...
@@ -49,6 +57,15 @@ type Config struct {
// List of JavaScript files to load for each markdown file
Scripts
[]
string
// Map of registered templates
Templates
map
[
string
]
string
// Map of request URL to static files generated
StaticFiles
map
[
string
]
string
// Directory to store static files
StaticDir
string
}
// ServeHTTP implements the http.Handler interface.
...
...
@@ -73,44 +90,37 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
return
http
.
StatusNotFound
,
nil
}
body
,
err
:=
ioutil
.
ReadAll
(
f
)
fs
,
err
:=
f
.
Stat
(
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
content
:=
blackfriday
.
Markdown
(
body
,
m
.
Renderer
,
0
)
var
scripts
,
styles
string
for
_
,
style
:=
range
m
.
Styles
{
styles
+=
strings
.
Replace
(
cssTemplate
,
"{{url}}"
,
style
,
1
)
+
"
\r\n
"
}
for
_
,
script
:=
range
m
.
Scripts
{
scripts
+=
strings
.
Replace
(
jsTemplate
,
"{{url}}"
,
script
,
1
)
+
"
\r\n
"
return
http
.
StatusNotFound
,
nil
}
//
Title is first line (length-limited), otherwise filename
title
:=
path
.
Base
(
fpath
)
newline
:=
bytes
.
Index
(
body
,
[]
byte
(
"
\n
"
))
if
newline
>
-
1
{
firstline
:=
body
[
:
newline
]
newTitle
:=
strings
.
TrimSpace
(
string
(
firstline
))
if
len
(
newTitle
)
>
1
{
if
len
(
newTitle
)
>
128
{
title
=
newTitle
[
:
128
]
}
else
{
title
=
newTitle
//
if static site is generated, attempt to use it
if
filepath
,
ok
:=
m
.
StaticFiles
[
fpath
];
ok
{
if
fs1
,
err
:=
os
.
Stat
(
filepath
);
err
==
nil
{
// if markdown has not been modified
// since static page generation,
// serve the static page
if
fs
.
ModTime
()
.
UnixNano
()
<
fs1
.
ModTime
()
.
UnixNano
()
{
if
html
,
err
:=
ioutil
.
ReadFile
(
filepath
);
err
==
nil
{
w
.
Write
(
html
)
return
http
.
StatusOK
,
nil
}
}
}
}
html
:=
htmlTemplate
html
=
strings
.
Replace
(
html
,
"{{title}}"
,
title
,
1
)
html
=
strings
.
Replace
(
html
,
"{{css}}"
,
styles
,
1
)
html
=
strings
.
Replace
(
html
,
"{{js}}"
,
scripts
,
1
)
html
=
strings
.
Replace
(
html
,
"{{body}}"
,
string
(
content
),
1
)
body
,
err
:=
ioutil
.
ReadAll
(
f
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
w
.
Write
([]
byte
(
html
))
html
,
err
:=
md
.
process
(
m
,
fpath
,
body
)
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
}
w
.
Write
(
html
)
return
http
.
StatusOK
,
nil
}
}
...
...
@@ -119,20 +129,3 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
// Didn't qualify to serve as markdown; pass-thru
return
md
.
Next
.
ServeHTTP
(
w
,
r
)
}
const
(
htmlTemplate
=
`<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="utf-8">
{{css}}
{{js}}
</head>
<body>
{{body}}
</body>
</html>`
cssTemplate
=
`<link rel="stylesheet" href="{{url}}">`
jsTemplate
=
`<script src="{{url}}"></script>`
)
middleware/markdown/metadata.go
0 → 100644
View file @
f2f7e682
package
markdown
import
(
"bufio"
"bytes"
"encoding/json"
"fmt"
"github.com/BurntSushi/toml"
"gopkg.in/yaml.v2"
)
var
(
parsers
=
[]
MetadataParser
{
&
JSONMetadataParser
{},
&
TOMLMetadataParser
{},
&
YAMLMetadataParser
{},
}
)
// Metadata stores a page's metadata
type
Metadata
struct
{
// Page title
Title
string
// Page template
Template
string
// Variables to be used with Template
Variables
map
[
string
]
interface
{}
}
// load loads parsed values in parsedMap into Metadata
func
(
m
*
Metadata
)
load
(
parsedMap
map
[
string
]
interface
{})
{
if
template
,
ok
:=
parsedMap
[
"title"
];
ok
{
m
.
Title
,
_
=
template
.
(
string
)
}
if
template
,
ok
:=
parsedMap
[
"template"
];
ok
{
m
.
Template
,
_
=
template
.
(
string
)
}
if
variables
,
ok
:=
parsedMap
[
"variables"
];
ok
{
m
.
Variables
,
_
=
variables
.
(
map
[
string
]
interface
{})
}
}
// MetadataParser is a an interface that must be satisfied by each parser
type
MetadataParser
interface
{
// Opening identifier
Opening
()
[]
byte
// Closing identifier
Closing
()
[]
byte
// Parse the metadata.
// Returns the remaining page contents (Markdown)
// after extracting metadata
Parse
([]
byte
)
([]
byte
,
error
)
// Parsed metadata.
// Should be called after a call to Parse returns no error
Metadata
()
Metadata
}
// JSONMetadataParser is the MetdataParser for JSON
type
JSONMetadataParser
struct
{
metadata
Metadata
}
// Parse the metadata
func
(
j
*
JSONMetadataParser
)
Parse
(
b
[]
byte
)
([]
byte
,
error
)
{
m
:=
make
(
map
[
string
]
interface
{})
// Read the preceding JSON object
decoder
:=
json
.
NewDecoder
(
bytes
.
NewReader
(
b
))
if
err
:=
decoder
.
Decode
(
&
m
);
err
!=
nil
{
return
b
,
err
}
j
.
metadata
.
load
(
m
)
// Retrieve remaining bytes after decoding
buf
:=
make
([]
byte
,
len
(
b
))
n
,
err
:=
decoder
.
Buffered
()
.
Read
(
buf
)
if
err
!=
nil
{
return
b
,
err
}
return
buf
[
:
n
],
nil
}
// Parsed metadata.
// Should be called after a call to Parse returns no error
func
(
j
*
JSONMetadataParser
)
Metadata
()
Metadata
{
return
j
.
metadata
}
// Opening returns the opening identifier JSON metadata
func
(
j
*
JSONMetadataParser
)
Opening
()
[]
byte
{
return
[]
byte
(
"{"
)
}
// Closing returns the closing identifier JSON metadata
func
(
j
*
JSONMetadataParser
)
Closing
()
[]
byte
{
return
[]
byte
(
"}"
)
}
// TOMLMetadataParser is the MetadataParser for TOML
type
TOMLMetadataParser
struct
{
metadata
Metadata
}
// Parse the metadata
func
(
t
*
TOMLMetadataParser
)
Parse
(
b
[]
byte
)
([]
byte
,
error
)
{
b
,
markdown
,
err
:=
extractMetadata
(
t
,
b
)
if
err
!=
nil
{
return
markdown
,
err
}
m
:=
make
(
map
[
string
]
interface
{})
if
err
:=
toml
.
Unmarshal
(
b
,
&
m
);
err
!=
nil
{
return
markdown
,
err
}
t
.
metadata
.
load
(
m
)
return
markdown
,
nil
}
// Parsed metadata.
// Should be called after a call to Parse returns no error
func
(
t
*
TOMLMetadataParser
)
Metadata
()
Metadata
{
return
t
.
metadata
}
// Opening returns the opening identifier TOML metadata
func
(
t
*
TOMLMetadataParser
)
Opening
()
[]
byte
{
return
[]
byte
(
"+++"
)
}
// Closing returns the closing identifier TOML metadata
func
(
t
*
TOMLMetadataParser
)
Closing
()
[]
byte
{
return
[]
byte
(
"+++"
)
}
// YAMLMetadataParser is the MetadataParser for YAML
type
YAMLMetadataParser
struct
{
metadata
Metadata
}
// Parse the metadata
func
(
y
*
YAMLMetadataParser
)
Parse
(
b
[]
byte
)
([]
byte
,
error
)
{
b
,
markdown
,
err
:=
extractMetadata
(
y
,
b
)
if
err
!=
nil
{
return
markdown
,
err
}
m
:=
make
(
map
[
string
]
interface
{})
if
err
:=
yaml
.
Unmarshal
(
b
,
&
m
);
err
!=
nil
{
return
markdown
,
err
}
y
.
metadata
.
load
(
m
)
return
markdown
,
nil
}
// Parsed metadata.
// Should be called after a call to Parse returns no error
func
(
y
*
YAMLMetadataParser
)
Metadata
()
Metadata
{
return
y
.
metadata
}
// Opening returns the opening identifier YAML metadata
func
(
y
*
YAMLMetadataParser
)
Opening
()
[]
byte
{
return
[]
byte
(
"---"
)
}
// Closing returns the closing identifier YAML metadata
func
(
y
*
YAMLMetadataParser
)
Closing
()
[]
byte
{
return
[]
byte
(
"---"
)
}
// extractMetadata extracts metadata content from a page.
// it returns the metadata, the remaining bytes (markdown),
// and an error if any.
// Useful for MetadataParser with defined identifiers (YAML, TOML)
func
extractMetadata
(
parser
MetadataParser
,
b
[]
byte
)
(
metadata
[]
byte
,
markdown
[]
byte
,
err
error
)
{
b
=
bytes
.
TrimSpace
(
b
)
reader
:=
bytes
.
NewBuffer
(
b
)
scanner
:=
bufio
.
NewScanner
(
reader
)
// Read first line
if
!
scanner
.
Scan
()
{
// if no line is read,
// assume metadata not present
return
nil
,
b
,
nil
}
line
:=
bytes
.
TrimSpace
(
scanner
.
Bytes
())
if
!
bytes
.
Equal
(
line
,
parser
.
Opening
())
{
return
nil
,
b
,
fmt
.
Errorf
(
"Wrong identifier"
)
}
// buffer for metadata contents
buf
:=
bytes
.
Buffer
{}
// Read remaining lines until closing identifier is found
for
scanner
.
Scan
()
{
line
:=
scanner
.
Bytes
()
// if closing identifier found
if
bytes
.
Equal
(
bytes
.
TrimSpace
(
line
),
parser
.
Closing
())
{
// get the scanner to return remaining bytes
scanner
.
Split
(
func
(
data
[]
byte
,
atEOF
bool
)
(
int
,
[]
byte
,
error
)
{
return
len
(
data
),
data
,
nil
})
// scan the remaining bytes
scanner
.
Scan
()
return
buf
.
Bytes
(),
scanner
.
Bytes
(),
nil
}
buf
.
Write
(
line
)
buf
.
WriteString
(
"
\r\n
"
)
}
// closing identifier not found
return
buf
.
Bytes
(),
nil
,
fmt
.
Errorf
(
"Metadata not closed. '%v' not found"
,
string
(
parser
.
Closing
()))
}
// findParser finds the parser using line that contains opening identifier
func
findParser
(
b
[]
byte
)
MetadataParser
{
var
line
[]
byte
// Read first line
if
_
,
err
:=
fmt
.
Fscanln
(
bytes
.
NewReader
(
b
),
&
line
);
err
!=
nil
{
return
nil
}
line
=
bytes
.
TrimSpace
(
line
)
for
_
,
parser
:=
range
parsers
{
if
bytes
.
Equal
(
parser
.
Opening
(),
line
)
{
return
parser
}
}
return
nil
}
middleware/markdown/metadata_test.go
0 → 100644
View file @
f2f7e682
package
markdown
import
(
"bytes"
"fmt"
"reflect"
"strings"
"testing"
)
var
TOML
=
[
4
]
string
{
`
title = "A title"
template = "default"
[variables]
name = "value"
`
,
`+++
title = "A title"
template = "default"
[variables]
name = "value"
+++
Page content
`
,
`+++
title = "A title"
template = "default"
[variables]
name = "value"
`
,
`title = "A title" template = "default" [variables] name = "value"`
,
}
var
YAML
=
[
4
]
string
{
`
title : A title
template : default
variables :
- name : value
`
,
`---
title : A title
template : default
variables :
- name : value
---
Page content
`
,
`---
title : A title
template : default
variables :
- name : value
`
,
`title : A title template : default variables : name : value`
,
}
var
JSON
=
[
4
]
string
{
`
"title" : "A title",
"template" : "default",
"variables" : {
"name" : "value"
}
`
,
`{
"title" : "A title",
"template" : "default",
"variables" : {
"name" : "value"
}
}
Page content
`
,
`
{
"title" : "A title",
"template" : "default",
"variables" : {
"name" : "value"
}
`
,
`
{{
"title" : "A title",
"template" : "default",
"variables" : {
"name" : "value"
}
}
`
,
}
func
check
(
t
*
testing
.
T
,
err
error
)
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
TestParsers
(
t
*
testing
.
T
)
{
expected
:=
Metadata
{
Title
:
"A title"
,
Template
:
"default"
,
Variables
:
map
[
string
]
interface
{}{
"name"
:
"value"
},
}
compare
:=
func
(
m
Metadata
)
bool
{
if
m
.
Title
!=
expected
.
Title
{
return
false
}
if
m
.
Template
!=
expected
.
Template
{
return
false
}
for
k
,
v
:=
range
m
.
Variables
{
if
v
!=
expected
.
Variables
[
k
]
{
return
false
}
}
return
true
}
data
:=
[]
struct
{
parser
MetadataParser
testData
[
4
]
string
name
string
}{
{
&
JSONMetadataParser
{},
JSON
,
"json"
},
{
&
YAMLMetadataParser
{},
YAML
,
"yaml"
},
{
&
TOMLMetadataParser
{},
TOML
,
"toml"
},
}
for
_
,
v
:=
range
data
{
// metadata without identifiers
if
_
,
err
:=
v
.
parser
.
Parse
([]
byte
(
v
.
testData
[
0
]));
err
==
nil
{
t
.
Fatalf
(
"Expected error for invalid metadata for %v"
,
v
.
name
)
}
// metadata with identifiers
md
,
err
:=
v
.
parser
.
Parse
([]
byte
(
v
.
testData
[
1
]))
check
(
t
,
err
)
if
!
compare
(
v
.
parser
.
Metadata
())
{
t
.
Fatalf
(
"Expected %v, found %v for %v"
,
expected
,
v
.
parser
.
Metadata
()
.
Variables
,
v
.
name
)
}
if
"Page content"
!=
strings
.
TrimSpace
(
string
(
md
))
{
t
.
Fatalf
(
"Expected %v, found %v for %v"
,
"Page content"
,
string
(
md
),
v
.
name
)
}
var
line
[]
byte
fmt
.
Fscanln
(
bytes
.
NewReader
([]
byte
(
v
.
testData
[
1
])),
&
line
)
if
parser
:=
findParser
(
line
);
parser
==
nil
{
t
.
Fatalf
(
"Parser must be found for %v"
,
v
.
name
)
}
else
{
if
reflect
.
TypeOf
(
parser
)
!=
reflect
.
TypeOf
(
v
.
parser
)
{
t
.
Fatalf
(
"parsers not equal. %v != %v"
,
reflect
.
TypeOf
(
parser
),
reflect
.
TypeOf
(
v
.
parser
))
}
}
// metadata without closing identifier
if
_
,
err
:=
v
.
parser
.
Parse
([]
byte
(
v
.
testData
[
2
]));
err
==
nil
{
t
.
Fatalf
(
"Expected error for missing closing identifier for %v"
,
v
.
name
)
}
// invalid metadata
if
md
,
err
=
v
.
parser
.
Parse
([]
byte
(
v
.
testData
[
3
]));
err
==
nil
{
t
.
Fatalf
(
"Expected error for invalid metadata for %v"
,
v
.
name
)
}
}
}
middleware/markdown/process.go
0 → 100644
View file @
f2f7e682
package
markdown
import
(
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/russross/blackfriday"
)
const
(
DefaultTemplate
=
"defaultTemplate"
StaticDir
=
".caddy_static"
)
// process processes the contents of a page.
// It parses the metadata (if any) and uses the template (if found)
func
(
md
Markdown
)
process
(
c
Config
,
requestPath
string
,
b
[]
byte
)
([]
byte
,
error
)
{
var
metadata
=
Metadata
{}
var
markdown
[]
byte
var
err
error
// find parser compatible with page contents
parser
:=
findParser
(
b
)
// if found, assume metadata present and parse.
if
parser
!=
nil
{
markdown
,
err
=
parser
.
Parse
(
b
)
if
err
!=
nil
{
return
nil
,
err
}
metadata
=
parser
.
Metadata
()
}
// if template is not specified, check if Default template is set
if
metadata
.
Template
==
""
{
if
_
,
ok
:=
c
.
Templates
[
DefaultTemplate
];
ok
{
metadata
.
Template
=
DefaultTemplate
}
}
// if template is set, load it
var
tmpl
[]
byte
if
metadata
.
Template
!=
""
{
if
t
,
ok
:=
c
.
Templates
[
metadata
.
Template
];
ok
{
tmpl
,
err
=
ioutil
.
ReadFile
(
t
)
}
if
err
!=
nil
{
return
nil
,
err
}
}
// process markdown
markdown
=
blackfriday
.
Markdown
(
markdown
,
c
.
Renderer
,
0
)
// set it as body for template
metadata
.
Variables
[
"markdown"
]
=
string
(
markdown
)
return
md
.
processTemplate
(
c
,
requestPath
,
tmpl
,
metadata
)
}
// processTemplate processes a template given a requestPath,
// template (tmpl) and metadata
func
(
md
Markdown
)
processTemplate
(
c
Config
,
requestPath
string
,
tmpl
[]
byte
,
metadata
Metadata
)
([]
byte
,
error
)
{
// if template is not specified,
// use the default template
if
tmpl
==
nil
{
tmpl
=
defaultTemplate
(
c
,
metadata
,
requestPath
)
}
// process the template
b
:=
&
bytes
.
Buffer
{}
t
,
err
:=
template
.
New
(
""
)
.
Parse
(
string
(
tmpl
))
if
err
!=
nil
{
return
nil
,
err
}
if
err
=
t
.
Execute
(
b
,
metadata
.
Variables
);
err
!=
nil
{
return
nil
,
err
}
// generate static page
if
err
=
md
.
generatePage
(
c
,
requestPath
,
b
.
Bytes
());
err
!=
nil
{
// if static page generation fails,
// nothing fatal, only log the error.
log
.
Println
(
err
)
}
return
b
.
Bytes
(),
nil
}
// generatePage generates a static html page from the markdown in content.
func
(
md
Markdown
)
generatePage
(
c
Config
,
requestPath
string
,
content
[]
byte
)
error
{
// should not happen,
// must be set on Markdown init.
if
c
.
StaticDir
==
""
{
return
fmt
.
Errorf
(
"Static directory not set"
)
}
// if static directory is not existing, create it
if
_
,
err
:=
os
.
Stat
(
c
.
StaticDir
);
err
!=
nil
{
err
:=
os
.
MkdirAll
(
c
.
StaticDir
,
os
.
FileMode
(
0755
))
if
err
!=
nil
{
return
err
}
}
filePath
:=
filepath
.
Join
(
c
.
StaticDir
,
requestPath
)
// If it is index file, use the directory instead
if
md
.
IsIndexFile
(
filepath
.
Base
(
requestPath
))
{
filePath
,
_
=
filepath
.
Split
(
filePath
)
}
// Create the directory in case it is not existing
if
err
:=
os
.
MkdirAll
(
filePath
,
os
.
FileMode
(
0755
));
err
!=
nil
{
return
err
}
// generate index.html file in the directory
filePath
=
filepath
.
Join
(
filePath
,
"index.html"
)
err
:=
ioutil
.
WriteFile
(
filePath
,
content
,
os
.
FileMode
(
0755
))
if
err
!=
nil
{
return
err
}
c
.
StaticFiles
[
requestPath
]
=
filePath
return
nil
}
// defaultTemplate constructs a default template.
func
defaultTemplate
(
c
Config
,
metadata
Metadata
,
requestPath
string
)
[]
byte
{
var
scripts
,
styles
bytes
.
Buffer
for
_
,
style
:=
range
c
.
Styles
{
styles
.
WriteString
(
strings
.
Replace
(
cssTemplate
,
"{{url}}"
,
style
,
1
))
styles
.
WriteString
(
"
\r\n
"
)
}
for
_
,
script
:=
range
c
.
Scripts
{
scripts
.
WriteString
(
strings
.
Replace
(
jsTemplate
,
"{{url}}"
,
script
,
1
))
scripts
.
WriteString
(
"
\r\n
"
)
}
// Title is first line (length-limited), otherwise filename
title
:=
metadata
.
Title
if
title
==
""
{
title
=
filepath
.
Base
(
requestPath
)
if
body
,
_
:=
metadata
.
Variables
[
"markdown"
]
.
([]
byte
);
len
(
body
)
>
128
{
title
=
string
(
body
[
:
128
])
}
else
if
len
(
body
)
>
0
{
title
=
string
(
body
)
}
}
html
:=
[]
byte
(
htmlTemplate
)
html
=
bytes
.
Replace
(
html
,
[]
byte
(
"{{title}}"
),
[]
byte
(
title
),
1
)
html
=
bytes
.
Replace
(
html
,
[]
byte
(
"{{css}}"
),
styles
.
Bytes
(),
1
)
html
=
bytes
.
Replace
(
html
,
[]
byte
(
"{{js}}"
),
scripts
.
Bytes
(),
1
)
return
html
}
const
(
htmlTemplate
=
`<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="utf-8">
{{css}}
{{js}}
</head>
<body>
{{.markdown}}
</body>
</html>`
cssTemplate
=
`<link rel="stylesheet" href="{{url}}">`
jsTemplate
=
`<script src="{{url}}"></script>`
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment