예제 #1
0
		/// <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();
			}
		}
예제 #2
0
		/// <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);
			}
		}
예제 #3
0
		/// <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)));
			}
		}
예제 #4
0
		/// <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);
		}
예제 #5
0
		/// <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;
		}
예제 #6
0
		/// <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));
		}
예제 #7
0
		/// <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);
			}
		}
예제 #8
0
		/// <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));
		}
예제 #9
0
		/// <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);
					}
				}
			}
		}
예제 #10
0
		/// <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;
		}
예제 #11
0
		/// <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;
				}
			}
		}
예제 #12
0
		/// <inheritdoc />
		public override void Render(Span target, RenderContext context, TextWriter writer)
		{
			object value = context.ResolveValue(target);

			Write(context, writer, value);
		}
예제 #13
0
		/// <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;
		}
예제 #14
0
		/// <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;
		}
예제 #15
0
        /// <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)));
            }
        }
예제 #16
0
		/// <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.");
		}
예제 #17
0
		/// <inheritdoc />
		protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { }
예제 #18
0
		/// <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);
		}
예제 #19
0
		/// <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;
		}