1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
package pongo2
type tagIncludeNode struct {
tpl *Template
filenameEvaluator IEvaluator
lazy bool
only bool
filename string
withPairs map[string]IEvaluator
ifExists bool
}
func (node *tagIncludeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
// Building the context for the template
includeCtx := make(Context)
// Fill the context with all data from the parent
if !node.only {
includeCtx.Update(ctx.Public)
includeCtx.Update(ctx.Private)
}
// Put all custom with-pairs into the context
for key, value := range node.withPairs {
val, err := value.Evaluate(ctx)
if err != nil {
return err
}
includeCtx[key] = val
}
// Execute the template
if node.lazy {
// Evaluate the filename
filename, err := node.filenameEvaluator.Evaluate(ctx)
if err != nil {
return err
}
if filename.String() == "" {
return ctx.Error("Filename for 'include'-tag evaluated to an empty string.", nil)
}
// Get include-filename
includedFilename := ctx.template.set.resolveFilename(ctx.template, filename.String())
includedTpl, err2 := ctx.template.set.FromFile(includedFilename)
if err2 != nil {
// if this is ReadFile error, and "if_exists" flag is enabled
if node.ifExists && err2.(*Error).Sender == "fromfile" {
return nil
}
return err2.(*Error)
}
err2 = includedTpl.ExecuteWriter(includeCtx, writer)
if err2 != nil {
return err2.(*Error)
}
return nil
}
// Template is already parsed with static filename
err := node.tpl.ExecuteWriter(includeCtx, writer)
if err != nil {
return err.(*Error)
}
return nil
}
type tagIncludeEmptyNode struct{}
func (node *tagIncludeEmptyNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
return nil
}
func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
includeNode := &tagIncludeNode{
withPairs: make(map[string]IEvaluator),
}
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
// prepared, static template
// "if_exists" flag
ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
// Get include-filename
includedFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
// Parse the parent
includeNode.filename = includedFilename
includedTpl, err := doc.template.set.FromFile(includedFilename)
if err != nil {
// if this is ReadFile error, and "if_exists" token presents we should create and empty node
if err.(*Error).Sender == "fromfile" && ifExists {
return &tagIncludeEmptyNode{}, nil
}
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
}
includeNode.tpl = includedTpl
} else {
// No String, then the user wants to use lazy-evaluation (slower, but possible)
filenameEvaluator, err := arguments.ParseExpression()
if err != nil {
return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
}
includeNode.filenameEvaluator = filenameEvaluator
includeNode.lazy = true
includeNode.ifExists = arguments.Match(TokenIdentifier, "if_exists") != nil // "if_exists" flag
}
// After having parsed the filename we're gonna parse the with+only options
if arguments.Match(TokenIdentifier, "with") != nil {
for arguments.Remaining() > 0 {
// We have at least one key=expr pair (because of starting "with")
keyToken := arguments.MatchType(TokenIdentifier)
if keyToken == nil {
return nil, arguments.Error("Expected an identifier", nil)
}
if arguments.Match(TokenSymbol, "=") == nil {
return nil, arguments.Error("Expected '='.", nil)
}
valueExpr, err := arguments.ParseExpression()
if err != nil {
return nil, err.updateFromTokenIfNeeded(doc.template, keyToken)
}
includeNode.withPairs[keyToken.Val] = valueExpr
// Only?
if arguments.Match(TokenIdentifier, "only") != nil {
includeNode.only = true
break // stop parsing arguments because it's the last option
}
}
}
if arguments.Remaining() > 0 {
return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
}
return includeNode, nil
}
func init() {
RegisterTag("include", tagIncludeParser)
}
|