Add support for index in each tags
It was requested that the current index could be accessed in the each tag.
This commit is contained in:
parent
3795a77354
commit
d7a0ab3b38
10
README.md
10
README.md
|
@ -86,6 +86,16 @@ If you need to print out a block of text for each item in a collection, use the
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
Within the context of the **each** block, the scope changes to the current item. So, in the example above, `Name` would refer to a property in the `Customer` class.
|
Within the context of the **each** block, the scope changes to the current item. So, in the example above, `Name` would refer to a property in the `Customer` class.
|
||||||
|
|
||||||
|
Additionally, you can access the current index into the collection being enumerated using the **index** tag.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{{#each Items}}
|
||||||
|
<li class="list-item{{#index}}" value="{{Value}}">{{Description}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
This will build an HTML list, building a list of items with `Description` and `Value` properties. Additionally, the `index` tag is used to create a CSS class with increasing numbers.
|
||||||
|
|
||||||
## The 'with' tag
|
## The 'with' tag
|
||||||
Within a block of text, you may refer to a same top-level placeholder over and over. You can cut down the amount of text by using the **with** tag.
|
Within a block of text, you may refer to a same top-level placeholder over and over. You can cut down the amount of text by using the **with** tag.
|
||||||
|
|
|
@ -990,6 +990,20 @@ Last";
|
||||||
Assert.AreEqual("Before123After", result, "The wrong text was generated.");
|
Assert.AreEqual("Before123After", result, "The wrong text was generated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We can use the index tag to get the current iteration.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_Each_Index_PrintsIndexOfItem()
|
||||||
|
{
|
||||||
|
FormatCompiler parser = new FormatCompiler();
|
||||||
|
const string format = "<ul>{{#each this}}<li value=\"{{this}}\">Item {{#index}}</li>{{/each}}</ul>";
|
||||||
|
Generator generator = parser.Compile(format);
|
||||||
|
string result = generator.Render(new int[] { 1, 2, 3 });
|
||||||
|
const string expected = @"<ul><li value=""1"">Item 0</li><li value=""2"">Item 1</li><li value=""3"">Item 2</li></ul>";
|
||||||
|
Assert.AreEqual(expected, result, "The wrong text was generated.");
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region With
|
#region With
|
||||||
|
@ -1038,7 +1052,7 @@ Last";
|
||||||
return new TagParameter[] { new TagParameter("param") { IsRequired = false, DefaultValue = 123 } };
|
return new TagParameter[] { new TagParameter("param") { IsRequired = false, DefaultValue = 123 } };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void GetText(TextWriter writer, Dictionary<string, object> arguments)
|
public override void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||||
{
|
{
|
||||||
writer.Write(arguments["param"]);
|
writer.Write(arguments["param"]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||||
//
|
//
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
[assembly: AssemblyVersion("0.1.1.0")]
|
[assembly: AssemblyVersion("0.1.2.0")]
|
||||||
[assembly: AssemblyFileVersion("0.1.1.0")]
|
[assembly: AssemblyFileVersion("0.1.2.0")]
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace Mustache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
||||||
IEnumerable<NestedContext> contexts = _definition.GetChildContext(writer, scope, arguments);
|
IEnumerable<NestedContext> contexts = _definition.GetChildContext(writer, scope, arguments);
|
||||||
|
@ -93,7 +93,7 @@ namespace Mustache
|
||||||
{
|
{
|
||||||
foreach (IGenerator generator in generators)
|
foreach (IGenerator generator in generators)
|
||||||
{
|
{
|
||||||
generator.GetText(context.KeyScope ?? scope, context.Writer ?? writer);
|
generator.GetText(context.KeyScope ?? scope, context.Writer ?? writer, context.Data);
|
||||||
if (context.WriterNeedsConsidated)
|
if (context.WriterNeedsConsidated)
|
||||||
{
|
{
|
||||||
writer.Write(_definition.ConsolidateWriter(context.Writer ?? writer, arguments));
|
writer.Write(_definition.ConsolidateWriter(context.Writer ?? writer, arguments));
|
||||||
|
|
|
@ -54,9 +54,11 @@ namespace Mustache
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
int index = 0;
|
||||||
foreach (object item in enumerable)
|
foreach (object item in enumerable)
|
||||||
{
|
{
|
||||||
yield return new NestedContext() { KeyScope = scope.CreateChildScope(item), Writer = writer };
|
yield return new NestedContext() { KeyScope = scope.CreateChildScope(item), Writer = writer, Data = index };
|
||||||
|
++index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ namespace Mustache
|
||||||
/// <returns>The name of the tags that are in scope.</returns>
|
/// <returns>The name of the tags that are in scope.</returns>
|
||||||
protected override IEnumerable<string> GetChildTags()
|
protected override IEnumerable<string> GetChildTags()
|
||||||
{
|
{
|
||||||
return new string[] { };
|
return new string[] { "index" };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -33,6 +33,8 @@ namespace Mustache
|
||||||
_tagLookup.Add(elseDefinition.Name, elseDefinition);
|
_tagLookup.Add(elseDefinition.Name, elseDefinition);
|
||||||
EachTagDefinition eachDefinition = new EachTagDefinition();
|
EachTagDefinition eachDefinition = new EachTagDefinition();
|
||||||
_tagLookup.Add(eachDefinition.Name, eachDefinition);
|
_tagLookup.Add(eachDefinition.Name, eachDefinition);
|
||||||
|
IndexTagDefinition indexDefinition = new IndexTagDefinition();
|
||||||
|
_tagLookup.Add(indexDefinition.Name, indexDefinition);
|
||||||
WithTagDefinition withDefinition = new WithTagDefinition();
|
WithTagDefinition withDefinition = new WithTagDefinition();
|
||||||
_tagLookup.Add(withDefinition.Name, withDefinition);
|
_tagLookup.Add(withDefinition.Name, withDefinition);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace Mustache
|
||||||
scope.KeyNotFound += handler;
|
scope.KeyNotFound += handler;
|
||||||
}
|
}
|
||||||
StringWriter writer = new StringWriter(provider);
|
StringWriter writer = new StringWriter(provider);
|
||||||
_generator.GetText(scope, writer);
|
_generator.GetText(scope, writer, null);
|
||||||
return writer.ToString();
|
return writer.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scope">The current lexical scope of the keys.</param>
|
/// <param name="scope">The current lexical scope of the keys.</param>
|
||||||
/// <param name="writer">The text writer to send all text to.</param>
|
/// <param name="writer">The text writer to send all text to.</param>
|
||||||
|
/// <param name="contextData">The data associated to the context.</param>
|
||||||
/// <returns>The generated text.</returns>
|
/// <returns>The generated text.</returns>
|
||||||
void GetText(KeyScope scope, TextWriter writer);
|
void GetText(KeyScope scope, TextWriter writer, object contextData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a tag that outputs the current index within an each loop.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class IndexTagDefinition : InlineTagDefinition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of an IndexTagDefinition.
|
||||||
|
/// </summary>
|
||||||
|
public IndexTagDefinition()
|
||||||
|
: base("index")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the tag only exists within the scope of its parent.
|
||||||
|
/// </summary>
|
||||||
|
protected override bool GetIsContextSensitive()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text to output.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The writer to write the output to.</param>
|
||||||
|
/// <param name="arguments">The arguments passed to the tag.</param>
|
||||||
|
/// <param name="contextData">Extra data passed along with the context.</param>
|
||||||
|
public override void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||||
|
{
|
||||||
|
int index = (int)contextData;
|
||||||
|
writer.Write(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,10 +23,10 @@ namespace Mustache
|
||||||
_arguments = arguments;
|
_arguments = arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
||||||
_definition.GetText(writer, arguments);
|
_definition.GetText(writer, arguments, contextData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Mustache
|
||||||
return formatBuilder.ToString();
|
return formatBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||||
{
|
{
|
||||||
object value = scope.Find(_key);
|
object value = scope.Find(_key);
|
||||||
writer.Write(_format, value);
|
writer.Write(_format, value);
|
||||||
|
|
|
@ -45,5 +45,10 @@ namespace Mustache
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets data associated with the context.
|
||||||
|
/// </summary>
|
||||||
|
public object Data { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,6 @@ using System.Runtime.CompilerServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.1.1.0")]
|
[assembly: AssemblyVersion("0.1.2.0")]
|
||||||
[assembly: AssemblyFileVersion("0.1.1.0")]
|
[assembly: AssemblyFileVersion("0.1.2.0")]
|
||||||
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
|
@ -46,7 +46,7 @@ namespace Mustache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||||
{
|
{
|
||||||
writer.Write(Value);
|
writer.Write(Value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,8 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="writer">The text writer to write to.</param>
|
/// <param name="writer">The text writer to write to.</param>
|
||||||
/// <param name="arguments">The arguments passed to the tag.</param>
|
/// <param name="arguments">The arguments passed to the tag.</param>
|
||||||
public virtual void GetText(TextWriter writer, Dictionary<string, object> arguments)
|
/// <param name="contextData">The data associated to the context.</param>
|
||||||
|
public virtual void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
<Compile Include="ContentTagDefinition.cs" />
|
<Compile Include="ContentTagDefinition.cs" />
|
||||||
<Compile Include="Context.cs" />
|
<Compile Include="Context.cs" />
|
||||||
<Compile Include="ContextParameter.cs" />
|
<Compile Include="ContextParameter.cs" />
|
||||||
|
<Compile Include="IndexTagDefinition.cs" />
|
||||||
<Compile Include="KeyFoundEventArgs.cs" />
|
<Compile Include="KeyFoundEventArgs.cs" />
|
||||||
<Compile Include="InlineTagDefinition.cs" />
|
<Compile Include="InlineTagDefinition.cs" />
|
||||||
<Compile Include="EachTagDefinition.cs" />
|
<Compile Include="EachTagDefinition.cs" />
|
||||||
|
|
Loading…
Reference in New Issue