github.com/ruudk/buffalo@v0.11.0/render/template.go (about)

     1  package render
     2  
     3  import (
     4  	"html/template"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/pkg/errors"
    12  	"github.com/sirupsen/logrus"
    13  
    14  	// this blank import is here because dep doesn't
    15  	// handle transitive dependencies correctly
    16  	_ "github.com/russross/blackfriday"
    17  )
    18  
    19  type templateRenderer struct {
    20  	*Engine
    21  	contentType string
    22  	names       []string
    23  }
    24  
    25  func (s templateRenderer) ContentType() string {
    26  	return s.contentType
    27  }
    28  
    29  func (s templateRenderer) Render(w io.Writer, data Data) error {
    30  	var body template.HTML
    31  	var err error
    32  	for _, name := range s.names {
    33  		body, err = s.exec(name, data)
    34  		if err != nil {
    35  			return err
    36  		}
    37  		data["yield"] = body
    38  	}
    39  	w.Write([]byte(body))
    40  	return nil
    41  }
    42  
    43  func (s templateRenderer) partial(name string, dd Data) (template.HTML, error) {
    44  	d, f := filepath.Split(name)
    45  	name = filepath.Join(d, "_"+f)
    46  	return s.exec(name, dd)
    47  }
    48  
    49  func (s templateRenderer) exec(name string, data Data) (template.HTML, error) {
    50  	ct := strings.ToLower(s.contentType)
    51  	data["contentType"] = ct
    52  
    53  	if filepath.Ext(name) == "" {
    54  		switch {
    55  		case strings.Contains(ct, "html"):
    56  			name += ".html"
    57  		case strings.Contains(ct, "javascript"):
    58  			name += ".js"
    59  		case strings.Contains(ct, "markdown"):
    60  			name += ".md"
    61  		}
    62  	}
    63  
    64  	// Try to use localized version
    65  	templateName := name
    66  	if languages, ok := data["languages"].([]string); ok {
    67  		ll := len(languages)
    68  		if ll > 0 {
    69  			// Default language is the last in the list
    70  			defaultLanguage := languages[ll-1]
    71  			ext := filepath.Ext(name)
    72  			rawName := strings.TrimSuffix(name, ext)
    73  
    74  			for _, l := range languages {
    75  				var candidateName string
    76  				if l == defaultLanguage {
    77  					break
    78  				}
    79  				candidateName = rawName + "." + strings.ToLower(l) + ext
    80  				if s.TemplatesBox.Has(candidateName) {
    81  					// Replace name with the existing suffixed version
    82  					templateName = candidateName
    83  					break
    84  				}
    85  			}
    86  		}
    87  	}
    88  
    89  	source, err := s.TemplatesBox.MustBytes(templateName)
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  
    94  	helpers := map[string]interface{}{
    95  		"partial": s.partial,
    96  	}
    97  
    98  	helpers = s.addAssetsHelpers(helpers)
    99  
   100  	for k, v := range s.Helpers {
   101  		helpers[k] = v
   102  	}
   103  
   104  	body := string(source)
   105  	for _, ext := range s.exts(name) {
   106  		te, ok := s.TemplateEngines[ext]
   107  		if !ok {
   108  			logrus.Errorf("could not find a template engine for %s\n", ext)
   109  			continue
   110  		}
   111  		body, err = te(body, data, helpers)
   112  		if err != nil {
   113  			return "", errors.Wrap(err, name)
   114  		}
   115  	}
   116  
   117  	return template.HTML(body), nil
   118  }
   119  
   120  func (s templateRenderer) exts(name string) []string {
   121  	exts := []string{}
   122  	for {
   123  		ext := filepath.Ext(name)
   124  		if ext == "" {
   125  			break
   126  		}
   127  		name = strings.TrimSuffix(name, ext)
   128  		exts = append(exts, strings.ToLower(ext[1:]))
   129  	}
   130  	if len(exts) == 0 {
   131  		return []string{"html"}
   132  	}
   133  	sort.Sort(sort.Reverse(sort.StringSlice(exts)))
   134  	return exts
   135  }
   136  
   137  func (s templateRenderer) assetPath(file string) (string, error) {
   138  
   139  	if len(assetMap) == 0 || os.Getenv("GO_ENV") != "production" {
   140  		manifest, err := s.AssetsBox.MustString("manifest.json")
   141  
   142  		if err != nil {
   143  			manifest, err = s.AssetsBox.MustString("assets/manifest.json")
   144  			if err != nil {
   145  				return assetPathFor(file), nil
   146  			}
   147  		}
   148  
   149  		err = loadManifest(manifest)
   150  		if err != nil {
   151  			return assetPathFor(file), errors.Wrap(err, "your manifest.json is not correct")
   152  		}
   153  	}
   154  
   155  	return assetPathFor(file), nil
   156  }
   157  
   158  // Template renders the named files using the specified
   159  // content type and the github.com/gobuffalo/plush
   160  // package for templating. If more than 1 file is provided
   161  // the second file will be considered a "layout" file
   162  // and the first file will be the "content" file which will
   163  // be placed into the "layout" using "{{yield}}".
   164  func Template(c string, names ...string) Renderer {
   165  	e := New(Options{})
   166  	return e.Template(c, names...)
   167  }
   168  
   169  // Template renders the named files using the specified
   170  // content type and the github.com/gobuffalo/plush
   171  // package for templating. If more than 1 file is provided
   172  // the second file will be considered a "layout" file
   173  // and the first file will be the "content" file which will
   174  // be placed into the "layout" using "{{yield}}".
   175  func (e *Engine) Template(c string, names ...string) Renderer {
   176  	return templateRenderer{
   177  		Engine:      e,
   178  		contentType: c,
   179  		names:       names,
   180  	}
   181  }