diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bba374..6c87fe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Master +### Enhancements + +- Added an optional second parameter to the `include` tag for passing a sub context to the included file. + [Yonas Kolb](https://github.com/yonaskolb) + [#394](https://github.com/stencilproject/Stencil/pull/214) + ### Bug Fixes - Fixed using quote as a filter parameter diff --git a/Sources/Include.swift b/Sources/Include.swift index cd9cc5c..560bb74 100644 --- a/Sources/Include.swift +++ b/Sources/Include.swift @@ -3,19 +3,21 @@ import PathKit class IncludeNode : NodeType { let templateName: Variable + let includeContext: String? class func parse(_ parser: TokenParser, token: Token) throws -> NodeType { let bits = token.components() - guard bits.count == 2 else { - throw TemplateSyntaxError("'include' tag takes one argument, the template file to be included") + guard bits.count == 2 || bits.count == 3 else { + throw TemplateSyntaxError("'include' tag requires one argument, the template file to be included. A second optional argument can be used to specify the context that will be passed to the included file") } - return IncludeNode(templateName: Variable(bits[1])) + return IncludeNode(templateName: Variable(bits[1]), includeContext: bits.count == 3 ? bits[2] : nil) } - init(templateName: Variable) { + init(templateName: Variable, includeContext: String? = nil) { self.templateName = templateName + self.includeContext = includeContext } func render(_ context: Context) throws -> String { @@ -25,7 +27,8 @@ class IncludeNode : NodeType { let template = try context.environment.loadTemplate(name: templateName) - return try context.push { + let subContext = includeContext.flatMap { context[$0] as? [String: Any] } + return try context.push(dictionary: subContext) { return try template.render(context) } } diff --git a/Tests/StencilTests/IncludeSpec.swift b/Tests/StencilTests/IncludeSpec.swift index 0297896..1ad004f 100644 --- a/Tests/StencilTests/IncludeSpec.swift +++ b/Tests/StencilTests/IncludeSpec.swift @@ -14,7 +14,7 @@ func testInclude() { let tokens: [Token] = [ .block(value: "include") ] let parser = TokenParser(tokens: tokens, environment: Environment()) - let error = TemplateSyntaxError("'include' tag takes one argument, the template file to be included") + let error = TemplateSyntaxError("'include' tag requires one argument, the template file to be included. A second optional argument can be used to specify the context that will be passed to the included file") try expect(try parser.parse()).toThrow(error) } @@ -56,6 +56,13 @@ func testInclude() { let value = try node.render(context) try expect(value) == "Hello World!" } + + $0.it("successfully passes context") { + let template = Template(templateString: "{% include \"test.html\" child %}") + let context = Context(dictionary: ["child": ["target": "World"]], environment: environment) + let value = try template.render(context) + try expect(value) == "Hello World!" + } } } } diff --git a/docs/builtins.rst b/docs/builtins.rst index 9d61eca..d4cc99a 100644 --- a/docs/builtins.rst +++ b/docs/builtins.rst @@ -260,6 +260,12 @@ You can include another template using the `include` tag. {% include "comment.html" %} +By default the included file gets passed the current context. You can pass a sub context by using an optional 2nd parameter as a lookup in the current context. + +.. code-block:: html+django + + {% include "comment.html" comment %} + The `include` tag requires you to provide a loader which will be used to lookup the template.