github.com/wanliu/go-oauth2-server@v0.0.0-20180817021415-f928fa1580df/web/render.go (about)

     1  package web
     2  
     3  import (
     4  	"fmt"
     5  	// "html/template"
     6  	"net/http"
     7  	"path/filepath"
     8  
     9  	"github.com/arschles/go-bindata-html-template"
    10  
    11  	"github.com/oxtoacart/bpool"
    12  )
    13  
    14  //go:generate go-bindata -pkg web includes layouts
    15  
    16  var (
    17  	templates map[string]*template.Template
    18  	bufpool   *bpool.BufferPool
    19  	loaded    = false
    20  )
    21  
    22  func raw(x string) interface{} { return template.HTML(x) }
    23  
    24  // renderTemplate is a wrapper around template.ExecuteTemplate.
    25  // It writes into a bytes.Buffer before writing to the http.ResponseWriter to catch
    26  // any errors resulting from populating the template.
    27  func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
    28  	loadTemplates()
    29  
    30  	// Ensure the template exists in the map.
    31  	tmpl, ok := templates[name]
    32  	if !ok {
    33  		return fmt.Errorf("The template %s does not exist", name)
    34  	}
    35  
    36  	// Create a buffer to temporarily write to and check if any errors were encountered.
    37  	buf := bufpool.Get()
    38  	defer bufpool.Put(buf)
    39  
    40  	err := tmpl.ExecuteTemplate(buf, "base", data)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	// The X-Frame-Options HTTP response header can be used to indicate whether
    46  	// or not a browser should be allowed to render a page in a <frame>,
    47  	// <iframe> or <object> . Sites can use this to avoid clickjacking attacks,
    48  	// by ensuring that their content is not embedded into other sites.
    49  	w.Header().Set("X-Frame-Options", "deny")
    50  	// Set the header and write the buffer to the http.ResponseWriter
    51  	w.Header().Set("Content-Type", "text/html; charset=utf-8")
    52  	buf.WriteTo(w)
    53  	return nil
    54  }
    55  
    56  func loadTemplates() {
    57  	if loaded {
    58  		return
    59  	}
    60  
    61  	templates = make(map[string]*template.Template)
    62  
    63  	bufpool = bpool.NewBufferPool(64)
    64  
    65  	layoutTemplates := map[string][]string{
    66  		"layouts/index.html": {
    67  			"includes/index.html",
    68  		},
    69  		"layouts/outside.html": {
    70  			"includes/register.html",
    71  			"includes/login.html",
    72  		},
    73  		"layouts/inside.html": {
    74  			"includes/authorize.html",
    75  			"includes/account.html",
    76  		},
    77  		"layouts/profile.html": {
    78  			"includes/clients.html",
    79  			"includes/new_client.html",
    80  			"includes/client_detail.html",
    81  		},
    82  	}
    83  
    84  	funcMap := template.FuncMap{
    85  		"raw": raw,
    86  	}
    87  
    88  	for layout, includes := range layoutTemplates {
    89  		for _, include := range includes {
    90  			files := []string{include, layout}
    91  
    92  			templates[filepath.Base(include)] = template.Must(template.New("", Asset).Funcs(funcMap).ParseFiles(files...))
    93  		}
    94  	}
    95  
    96  	loaded = true
    97  }