/// <summary> /// Renders the content of a block helper. /// </summary> /// <param name="children">The children of the helper block.</param> /// <param name="context">The render context.</param> /// <param name="data">The new data model.</param> /// <returns>The string content of the result.</returns> private string RenderHelperChildren(IEnumerable<SyntaxTreeNode> children, RenderContext context, object data) { RenderContext targetContext = context; RenderContextScope scope = null; if (data != null) { scope = context.BeginScope(data); targetContext = scope.ScopeContext; } using (var writer = new StringWriter()) { var renderer = new RenderingParserVisitor(writer, targetContext, context.ModelMetadataProvider); foreach (var node in children) { node.Accept(renderer); } if (scope != null) { scope.Dispose(); } return writer.GetStringBuilder().ToString(); } }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); var elseChildren = new List<SyntaxTreeNode>(); // Determine if there is an alternate {{else}} block which denotes content to display when predicate is false. var elseNode = children.Find(n => n.IsBlock && (((Block)n).Name == "else" || ((Block)n).Name == "^")); if (elseNode != null) { int elseIndex = children.IndexOf(elseNode); elseChildren = children.Skip(elseIndex + 1).ToList(); children = children.Take(elseIndex).ToList(); } if (!IsTruthy(arguments[0])) { RenderChildren(children, context); } else if (elseChildren.Count > 0) { RenderChildren(elseChildren, context); } }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { if (context.Service == null) { // No service, can't do anything. return; } var span = block.Children.FirstOrDefault(c => !c.IsBlock && ((Span)c).Kind == SpanKind.Expression) as Span; if (span == null) { // Malformed tag? return; } string name = span.Content; object model = arguments.FirstOrDefault(); if (model != null) { using (var scope = context.BeginScope(model)) { Write(scope.ScopeContext, writer, new SafeString(context.Service.RunPartial(name, scope.ScopeContext))); } } else { Write(context, writer, new SafeString(context.Service.RunPartial(name, context))); } }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { var enumerable = arguments[0]; if (!(enumerable is IEnumerable)) { enumerable = new object[] { enumerable }; } var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); var elseChildren = new List<SyntaxTreeNode>(); // Determine if there is an alternate {{else}} block which denotes content to display when there are no items. var elseNode = children.Find(n => n.IsBlock && (((Block)n).Name == "else" || ((Block)n).Name == "^")); if (elseNode != null) { int elseIndex = children.IndexOf(elseNode); elseChildren = children.Skip(elseIndex + 1).ToList(); children = children.Take(elseIndex).ToList(); } RenderEnumerable((IEnumerable)enumerable, context, children, elseChildren); }
/// <summary> /// Creates a child <see cref="RenderContext"/> based on the parent context provided. /// </summary> /// <param name="parent">The parent render context.</param> /// <param name="model">The child model.</param> /// <returns>The parent render context.</returns> public static RenderContext CreateRenderContext(RenderContext parent, object model = null) { if (parent == null) { throw new ArgumentNullException("parent"); } model = model ?? parent.TemplateData.Model; var context = new RenderContext(parent.Visitor, parent) { TemplateData = new TemplateData() { Model = model, ModelMetadata = (model == null) ? null : parent.ModelMetadataProvider.GetMetadataForType(() => model, model.GetType()) }, ModelMetadataProvider = parent.ModelMetadataProvider, Service = parent.Service }; // Set the root context context.RootRenderContext = parent.RootRenderContext ?? parent; return context; }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { if (context.Service == null) { // There is nothing we can do, no service has been assigned. return; } var options = new HelperOptions() { Arguments = arguments, Parameters = maps, RenderContext = context }; if (block.Type == BlockType.Tag) { var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); options.Render = (data) => RenderHelperChildren(children, context, data); } string result = context.Service.RunHelper(block.Name, options); Write(context, writer, new SafeString(result)); }
/// <summary> /// Renders the enumerable content. /// </summary> /// <param name="enumerable">The enumerable instance.</param> /// <param name="context">The render context.</param> /// <param name="children">The child block to render for each item.</param> /// <param name="alternateChildren">Alternative content to render when no content is available.</param> protected internal void RenderEnumerable(IEnumerable enumerable, RenderContext context, IEnumerable<SyntaxTreeNode> children, IEnumerable<SyntaxTreeNode> alternateChildren = null) { int index = 0; bool hasItems = false; var dict = enumerable as IDictionary; if (dict != null) { int maxIndex = dict.Count - 1; foreach (var key in dict.Keys) { hasItems = true; var item = dict[key]; using (var scope = context.BeginScope(item)) { scope.ScopeContext.SetVariable("first", (index == 0)); scope.ScopeContext.SetVariable("last", (index == maxIndex)); scope.ScopeContext.SetVariable("index", index); scope.ScopeContext.SetVariable("key", key); foreach (var child in children) { RenderChild(child, scope.ScopeContext); } } index++; } } else { var array = (enumerable is Array) ? (object[])enumerable : (((IEnumerable)enumerable).Cast<object>().ToArray()); int maxIndex = array.Length - 1; for (index = 0; index <= maxIndex; index++) { hasItems = true; var item = array[index]; using (var scope = context.BeginScope(item)) { scope.ScopeContext.SetVariable("first", (index == 0)); scope.ScopeContext.SetVariable("last", (index == maxIndex)); scope.ScopeContext.SetVariable("index", index); foreach (var child in children) { RenderChild(child, scope.ScopeContext); } } } } if (!hasItems && alternateChildren != null && alternateChildren.Any()) { RenderChildren(alternateChildren, context); } }
/// <inheritdoc /> public override void Render(Span target, RenderContext context, TextWriter writer) { if (target.Collapsed) { // Span is collapsed, so do not render. return; } string content = target == null || target.Content == null ? string.Empty : target.Content; Write(context, writer, new SafeString(content)); }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { string name = block.Name; var children = block.Children.ToList(); // Get the TagElement block. var tagElement = (Block)children[0]; // Determine if the block prefix symbol (either # or ^) is a caret. bool isNegatedSection = tagElement.Children.Cast<Span>().Where(s => s.Kind == SpanKind.MetaCode).ToArray()[1].Content == "^"; children.RemoveAt(0); children.RemoveAt(children.Count - 1); if (string.IsNullOrEmpty(name)) { // Nothing we can do. return; } object value = context.ResolveValue(name, false); if (value == null && !isNegatedSection) { // No value, nothing we can do :-( return; } if ((value is IEnumerable) && !(value is string) && !isNegatedSection) { RenderEnumerable((IEnumerable)value, context, children, null); } else { bool isTruthy = IsTruthy(value); // Treat this as a conditional block. if (isTruthy != isNegatedSection) { if (isTruthy) { // Create a scope around the value. using (var scope = context.BeginScope(value)) { RenderChildren(children, context); } } else { RenderChildren(children, context); } } } }
/// <summary> /// Creates a <see cref="RenderContext"/> using the renderer provided. /// </summary> /// <param name="renderer">The renderering parser visitor.</param> /// <param name="model">The model.</param> /// <returns>The render context.</returns> public static RenderContext CreateRenderContext(RenderingParserVisitor renderer, object model = null) { if (renderer == null) { throw new ArgumentNullException("renderer"); } var context = new RenderContext(renderer) { TemplateData = new TemplateData() { Model = model, ModelMetadata = (model == null) ? null : renderer.ModelMetadataProvider.GetMetadataForType(() => model, model.GetType()) }, ModelMetadataProvider = renderer.ModelMetadataProvider, Service = renderer.Service }; return context; }
/// <inheritdoc /> public override void Render(Block target, RenderContext context, TextWriter writer) { // 1. Figure out branching blocks. // 2. For each branching block (first to last), resolve conditional argument. var blocks = ParseConditionalBlocks(target); foreach (var block in blocks) { var arguments = GetArgumentsAndMappedParameters(block.Item1, context); if (block.Item1.Name == "if" || block.Item1.Name == "elseif") { if (IsTruthy(arguments.Item1[0])) { RenderChildren(block.Item2, context); break; } } else { RenderChildren(block.Item2, context); break; } } }
/// <inheritdoc /> public override void Render(Span target, RenderContext context, TextWriter writer) { object value = context.ResolveValue(target); Write(context, writer, value); }
/// <summary> /// Resolves the value for the given expression. /// </summary> /// <param name="context">The render context.</param> /// <param name="templateData">The template data.</param> /// <param name="expression">The expression.</param> /// <param name="isVariableLookup">True if this is a variable lookup, otherwise false.</param> /// <returns>The resolved value.</returns> public static object ResolveValue(RenderContext context, TemplateData templateData, string expression, bool isVariableLookup) { if (isVariableLookup && !string.IsNullOrEmpty(expression) && !expression.StartsWith("root.")) { return context.GetVariable(expression); } if (isVariableLookup && !string.IsNullOrEmpty(expression) && expression.StartsWith("root.")) { context = context.RootRenderContext ?? context; templateData = context.TemplateData; expression = expression.Substring(5); } var modelMetadata = ExpressionMetadataProvider.FromStringExpression(expression, templateData, context.ModelMetadataProvider); if (modelMetadata == null) { return null; } return modelMetadata.Model; }
/// <summary> /// Initializes a new instance of the <see cref="RenderContext"/> class. /// </summary> /// <param name="visitor">The visitor.</param> /// <param name="parentRenderContext">The parent render context.</param> public RenderContext(ParserVisitor<RenderContext> visitor, RenderContext parentRenderContext = null) { ParentRenderContext = parentRenderContext; Visitor = visitor; }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary <string, object> maps, RenderContext context, TextWriter writer) { if (context.Service == null) { // No service, can't do anything. return; } var span = block.Children.FirstOrDefault(c => !c.IsBlock && ((Span)c).Kind == SpanKind.Expression) as Span; if (span == null) { // Malformed tag? return; } string name = span.Content; object model = arguments.FirstOrDefault(); if (model != null) { using (var scope = context.BeginScope(model)) { Write(scope.ScopeContext, writer, new SafeString(context.Service.RunPartial(name, scope.ScopeContext))); } } else { Write(context, writer, new SafeString(context.Service.RunPartial(name, context))); } }
/// <inheritdoc /> public string RunPartial(string name, RenderContext context) { Func<RenderContext, string> func; if (_partials.TryGetValue(name, out func)) { return func(context); } throw new ArgumentException("No partial template called '" + name + "' has been compiled."); }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { }
/// <summary> /// Runs a pre-compiled partial template. /// </summary> /// <param name="name">The name of the partial template.</param> /// <param name="context">The render context.</param> /// <returns>The template result.</returns> public static string RunPartial(string name, RenderContext context) { return _handlebarsService.Value.RunPartial(name, context); }
/// <summary> /// Initialises a new instance of <see cref="RenderContextScope"/> /// </summary> /// <param name="scopeContext">The scoped context.</param> /// <param name="action">The dispose action.</param> public RenderContextScope(RenderContext scopeContext, Action action) : base(action) { ScopeContext = scopeContext; }