2016-05-30 16:08:09 +02:00
package markdown
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"fmt"
"github.com/kataras/iris/config"
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
)
// Supports RAW markdown only, no context binding or layout, to use dynamic markdown with other template engine use the context.Markdown/MarkdownString
2016-06-03 04:11:50 +02:00
2016-05-30 16:08:09 +02:00
type (
2016-06-03 04:11:50 +02:00
// Engine the jade engine
2016-05-30 16:08:09 +02:00
Engine struct {
Config * config . Template
templateCache map [ string ] [ ] byte
mu sync . Mutex
}
)
// New creates and returns a Pongo template engine
func New ( c config . Template ) * Engine {
return & Engine { Config : & c , templateCache : make ( map [ string ] [ ] byte ) }
}
2016-06-03 04:11:50 +02:00
// BuildTemplates builds the templates
2016-05-30 16:08:09 +02:00
func ( e * Engine ) BuildTemplates ( ) error {
if e . Config . Asset == nil || e . Config . AssetNames == nil {
return e . buildFromDir ( )
}
return e . buildFromAsset ( )
}
func ( e * Engine ) buildFromDir ( ) ( templateErr error ) {
if e . Config . Directory == "" {
return nil //we don't return fill error here(yet)
}
dir := e . Config . Directory
// Walk the supplied directory and compile any files that match our extension list.
filepath . Walk ( dir , func ( path string , info os . FileInfo , err error ) error {
if info == nil || info . IsDir ( ) {
return nil
}
rel , err := filepath . Rel ( dir , path )
if err != nil {
return err
}
ext := ""
if strings . Index ( rel , "." ) != - 1 {
ext = filepath . Ext ( rel )
}
for _ , extension := range e . Config . Extensions {
if ext == extension {
buf , err := ioutil . ReadFile ( path )
if err != nil {
templateErr = err
break
}
buf = blackfriday . MarkdownCommon ( buf )
if e . Config . Markdown . Sanitize {
buf = bluemonday . UGCPolicy ( ) . SanitizeBytes ( buf )
}
if err != nil {
templateErr = err
break
}
name := filepath . ToSlash ( rel )
e . templateCache [ name ] = buf
break
}
}
return nil
} )
return nil
}
func ( e * Engine ) buildFromAsset ( ) error {
var templateErr error
dir := e . Config . Directory
for _ , path := range e . Config . AssetNames ( ) {
if ! strings . HasPrefix ( path , dir ) {
continue
}
rel , err := filepath . Rel ( dir , path )
if err != nil {
panic ( err )
}
ext := ""
if strings . Index ( rel , "." ) != - 1 {
ext = "." + strings . Join ( strings . Split ( rel , "." ) [ 1 : ] , "." )
}
for _ , extension := range e . Config . Extensions {
if ext == extension {
buf , err := e . Config . Asset ( path )
if err != nil {
templateErr = err
break
}
b := blackfriday . MarkdownCommon ( buf )
if e . Config . Markdown . Sanitize {
b = bluemonday . UGCPolicy ( ) . SanitizeBytes ( b )
}
name := filepath . ToSlash ( rel )
e . templateCache [ name ] = b
break
}
}
}
return templateErr
}
func ( e * Engine ) fromCache ( relativeName string ) [ ] byte {
e . mu . Lock ( )
tmpl , ok := e . templateCache [ relativeName ]
if ok {
e . mu . Unlock ( ) // defer is slow
return tmpl
}
e . mu . Unlock ( ) // defer is slow
return nil
}
2016-06-03 04:11:50 +02:00
// ExecuteWriter executes a templates and write its results to the out writer
// layout here is useless
2016-05-30 16:08:09 +02:00
func ( e * Engine ) ExecuteWriter ( out io . Writer , name string , binding interface { } , layout string ) error {
if tmpl := e . fromCache ( name ) ; tmpl != nil {
_ , err := out . Write ( tmpl )
return err
}
return fmt . Errorf ( "[IRIS TEMPLATES] Template with name %s doesn't exists in the dir %s" , name , e . Config . Directory )
}