Direct support for HTML formatting
This commit is contained in:
parent
929764e58a
commit
bb1b6cc936
Binary file not shown.
17
README.md
17
README.md
|
@ -37,7 +37,7 @@ Introducing [handlebars.js](http://handlebarsjs.com/)... If you've needed to gen
|
||||||
Most of the lines in the previous example will never appear in the final output. This allows you to use **mustache#** to write templates for normal text, not just HTML/XML.
|
Most of the lines in the previous example will never appear in the final output. This allows you to use **mustache#** to write templates for normal text, not just HTML/XML.
|
||||||
|
|
||||||
## Placeholders
|
## Placeholders
|
||||||
The placeholders can be any valid identifier. These map to the property names in your classes.
|
The placeholders can be any valid identifier. These map to the property names in your classes (or `Dictionary` keys).
|
||||||
|
|
||||||
### Formatting Placeholders
|
### Formatting Placeholders
|
||||||
Each format item takes the following form and consists of the following components:
|
Each format item takes the following form and consists of the following components:
|
||||||
|
@ -216,6 +216,21 @@ Here's an example of a tag that will join the items of a collection:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## HTML Support
|
||||||
|
**mustache#** was not originally designed to exclusively generate HTML. However, it is by far the most common use of **mustache#**. For that reason, there is a separate `HtmlFormatCompiler` class that will automatically configure the code to work with HTML documents. Particularly, this class will eliminate most newlines and escape any special HTML characters that might appear within the substituted values.
|
||||||
|
|
||||||
|
If you really need to embed HTML values, you can wrap placeholders in triple quotes rather than double quotes.
|
||||||
|
|
||||||
|
HtmlFormatCompiler compiler = new HtmlFormatCompiler();
|
||||||
|
const string format = @"<html><body>{{escaped}} and {{{unescaped}}}</body></html>";
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
string result = generator.Render(new
|
||||||
|
{
|
||||||
|
escaped = "<b>Awesome</b>",
|
||||||
|
unescaped = "<i>sweet</i>"
|
||||||
|
});
|
||||||
|
// Generates <html><body><b>Awesome</b> and <i>sweet</i></body></html>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
This is free and unencumbered software released into the public domain.
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace Mustache.Test
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class HtmlFormatCompilerTester
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void ShouldEscapeValueContainingHTMLCharacters()
|
||||||
|
{
|
||||||
|
HtmlFormatCompiler compiler = new HtmlFormatCompiler();
|
||||||
|
var generator = compiler.Compile("<html><body>Hello, {{Name}}!!!</body></html>");
|
||||||
|
string html = generator.Render(new
|
||||||
|
{
|
||||||
|
Name = "John \"The Man\" Standford"
|
||||||
|
});
|
||||||
|
Assert.AreEqual("<html><body>Hello, John "The Man" Standford!!!</body></html>", html);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ShouldIgnoreHTMLCharactersInsideTripleCurlyBraces()
|
||||||
|
{
|
||||||
|
HtmlFormatCompiler compiler = new HtmlFormatCompiler();
|
||||||
|
var generator = compiler.Compile("<html><body>Hello, {{{Name}}}!!!</body></html>");
|
||||||
|
string html = generator.Render(new
|
||||||
|
{
|
||||||
|
Name = "John \"The Man\" Standford"
|
||||||
|
});
|
||||||
|
Assert.AreEqual("<html><body>Hello, John \"The Man\" Standford!!!</body></html>", html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,6 +50,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="FormatCompilerTester.cs" />
|
<Compile Include="FormatCompilerTester.cs" />
|
||||||
|
<Compile Include="HtmlFormatCompilerTester.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="UpcastDictionaryTester.cs" />
|
<Compile Include="UpcastDictionaryTester.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace Mustache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(Scope keyScope, TextWriter writer, Scope contextScope)
|
void IGenerator.GetText(TextWriter writer, Scope keyScope, Scope contextScope, Action<Substitution> postProcessor)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> arguments = _arguments.GetArguments(keyScope, contextScope);
|
Dictionary<string, object> arguments = _arguments.GetArguments(keyScope, contextScope);
|
||||||
IEnumerable<NestedContext> contexts = _definition.GetChildContext(writer, keyScope, arguments, contextScope);
|
IEnumerable<NestedContext> contexts = _definition.GetChildContext(writer, keyScope, arguments, contextScope);
|
||||||
|
@ -80,7 +80,7 @@ namespace Mustache
|
||||||
{
|
{
|
||||||
foreach (IGenerator generator in generators)
|
foreach (IGenerator generator in generators)
|
||||||
{
|
{
|
||||||
generator.GetText(context.KeyScope ?? keyScope, context.Writer ?? writer, context.ContextScope);
|
generator.GetText(context.Writer ?? writer, context.KeyScope ?? keyScope, context.ContextScope, postProcessor);
|
||||||
if (context.WriterNeedsConsidated)
|
if (context.WriterNeedsConsidated)
|
||||||
{
|
{
|
||||||
writer.Write(_definition.ConsolidateWriter(context.Writer ?? writer, arguments));
|
writer.Write(_definition.ConsolidateWriter(context.Writer ?? writer, arguments));
|
||||||
|
|
|
@ -60,6 +60,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RemoveNewLines { get; set; }
|
public bool RemoveNewLines { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the compiler searches for tags using triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool AreExtensionTagsAllowed { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the given tag definition with the parser.
|
/// Registers the given tag definition with the parser.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -129,7 +134,13 @@ namespace Mustache
|
||||||
matches.Add(getTagRegex(childDefinition));
|
matches.Add(getTagRegex(childDefinition));
|
||||||
}
|
}
|
||||||
matches.Add(getUnknownTagRegex());
|
matches.Add(getUnknownTagRegex());
|
||||||
string match = "{{(" + String.Join("|", matches) + ")}}";
|
string combined = String.Join("|", matches);
|
||||||
|
string match = "{{(?<match>" + combined + ")}}";
|
||||||
|
if (AreExtensionTagsAllowed)
|
||||||
|
{
|
||||||
|
string tripleMatch = "{{{(?<extension>" + combined + ")}}}";
|
||||||
|
match = "(?:" + match + ")|(?:" + tripleMatch + ")";
|
||||||
|
}
|
||||||
regex = new Regex(match);
|
regex = new Regex(match);
|
||||||
_regexLookup.Add(definition.Name, regex);
|
_regexLookup.Add(definition.Name, regex);
|
||||||
}
|
}
|
||||||
|
@ -176,7 +187,7 @@ namespace Mustache
|
||||||
return regexBuilder.ToString();
|
return regexBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getUnknownTagRegex()
|
private static string getUnknownTagRegex()
|
||||||
{
|
{
|
||||||
return @"(?<unknown>(#.*?))";
|
return @"(?<unknown>(#.*?))";
|
||||||
}
|
}
|
||||||
|
@ -207,32 +218,35 @@ namespace Mustache
|
||||||
{
|
{
|
||||||
generator.AddGenerator(new StaticGenerator(leading, RemoveNewLines));
|
generator.AddGenerator(new StaticGenerator(leading, RemoveNewLines));
|
||||||
formatIndex = match.Index + match.Length;
|
formatIndex = match.Index + match.Length;
|
||||||
|
bool isExtension = match.Groups["extension"].Success;
|
||||||
string key = match.Groups["key"].Value;
|
string key = match.Groups["key"].Value;
|
||||||
string alignment = match.Groups["alignment"].Value;
|
string alignment = match.Groups["alignment"].Value;
|
||||||
string formatting = match.Groups["format"].Value;
|
string formatting = match.Groups["format"].Value;
|
||||||
if (key.StartsWith("@"))
|
if (key.StartsWith("@"))
|
||||||
{
|
{
|
||||||
VariableFoundEventArgs args = new VariableFoundEventArgs(key.Substring(1), alignment, formatting, context.ToArray());
|
VariableFoundEventArgs args = new VariableFoundEventArgs(key.Substring(1), alignment, formatting, isExtension, context.ToArray());
|
||||||
if (VariableFound != null)
|
if (VariableFound != null)
|
||||||
{
|
{
|
||||||
VariableFound(this, args);
|
VariableFound(this, args);
|
||||||
key = "@" + args.Name;
|
key = "@" + args.Name;
|
||||||
alignment = args.Alignment;
|
alignment = args.Alignment;
|
||||||
formatting = args.Formatting;
|
formatting = args.Formatting;
|
||||||
|
isExtension = args.IsExtension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(key, alignment, formatting, context.ToArray());
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(key, alignment, formatting, isExtension, context.ToArray());
|
||||||
if (PlaceholderFound != null)
|
if (PlaceholderFound != null)
|
||||||
{
|
{
|
||||||
PlaceholderFound(this, args);
|
PlaceholderFound(this, args);
|
||||||
key = args.Key;
|
key = args.Key;
|
||||||
alignment = args.Alignment;
|
alignment = args.Alignment;
|
||||||
formatting = args.Formatting;
|
formatting = args.Formatting;
|
||||||
|
isExtension = args.IsExtension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyGenerator keyGenerator = new KeyGenerator(key, alignment, formatting);
|
KeyGenerator keyGenerator = new KeyGenerator(key, alignment, formatting, isExtension);
|
||||||
generator.AddGenerator(keyGenerator);
|
generator.AddGenerator(keyGenerator);
|
||||||
}
|
}
|
||||||
else if (match.Groups["open"].Success)
|
else if (match.Groups["open"].Success)
|
||||||
|
@ -347,7 +361,7 @@ namespace Mustache
|
||||||
if (placeholder.StartsWith("@"))
|
if (placeholder.StartsWith("@"))
|
||||||
{
|
{
|
||||||
string variableName = placeholder.Substring(1);
|
string variableName = placeholder.Substring(1);
|
||||||
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, context.ToArray());
|
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, false, context.ToArray());
|
||||||
if (VariableFound != null)
|
if (VariableFound != null)
|
||||||
{
|
{
|
||||||
VariableFound(this, args);
|
VariableFound(this, args);
|
||||||
|
@ -371,7 +385,7 @@ namespace Mustache
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string placeholderName = placeholder;
|
string placeholderName = placeholder;
|
||||||
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, context.ToArray());
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, false, context.ToArray());
|
||||||
if (PlaceholderFound != null)
|
if (PlaceholderFound != null)
|
||||||
{
|
{
|
||||||
PlaceholderFound(this, args);
|
PlaceholderFound(this, args);
|
||||||
|
|
|
@ -54,6 +54,11 @@ namespace Mustache
|
||||||
remove { _valueRequestedHandlers.Remove(value); }
|
remove { _valueRequestedHandlers.Remove(value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a tag is replaced by its text.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<TagFormattedEventArgs> TagFormatted;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the text that is generated for the given object.
|
/// Gets the text that is generated for the given object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -98,8 +103,19 @@ namespace Mustache
|
||||||
contextScope.ValueRequested += handler;
|
contextScope.ValueRequested += handler;
|
||||||
}
|
}
|
||||||
StringWriter writer = new StringWriter(provider);
|
StringWriter writer = new StringWriter(provider);
|
||||||
_generator.GetText(keyScope, writer, contextScope);
|
_generator.GetText(writer, keyScope, contextScope, postProcess);
|
||||||
return writer.ToString();
|
return writer.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void postProcess(Substitution substitution)
|
||||||
|
{
|
||||||
|
if (TagFormatted == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TagFormattedEventArgs args = new TagFormattedEventArgs(substitution.Key, substitution.Substitute, substitution.IsExtension);
|
||||||
|
TagFormatted(this, args);
|
||||||
|
substitution.Substitute = args.Substitute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public sealed class HtmlFormatCompiler
|
||||||
|
{
|
||||||
|
private readonly FormatCompiler compiler;
|
||||||
|
|
||||||
|
public HtmlFormatCompiler()
|
||||||
|
{
|
||||||
|
compiler = new FormatCompiler();
|
||||||
|
compiler.AreExtensionTagsAllowed = true;
|
||||||
|
compiler.RemoveNewLines = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a placeholder is found in the template.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<PlaceholderFoundEventArgs> PlaceholderFound
|
||||||
|
{
|
||||||
|
add { compiler.PlaceholderFound += value; }
|
||||||
|
remove { compiler.PlaceholderFound -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a variable is found in the template.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<VariableFoundEventArgs> VariableFound
|
||||||
|
{
|
||||||
|
add { compiler.VariableFound += value; }
|
||||||
|
remove { compiler.VariableFound -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the given tag definition with the parser.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="definition">The tag definition to register.</param>
|
||||||
|
/// <param name="isTopLevel">Specifies whether the tag is immediately in scope.</param>
|
||||||
|
public void RegisterTag(TagDefinition definition, bool isTopLevel)
|
||||||
|
{
|
||||||
|
compiler.RegisterTag(definition, isTopLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a text generator based on the given format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">The format to parse.</param>
|
||||||
|
/// <returns>The text generator.</returns>
|
||||||
|
public Generator Compile(string format)
|
||||||
|
{
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
generator.TagFormatted += escapeInvalidHtml;
|
||||||
|
return generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void escapeInvalidHtml(object sender, TagFormattedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.IsExtension)
|
||||||
|
{
|
||||||
|
// Do not escape text within triple curly braces
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.Substitute = SecurityElement.Escape(e.Substitute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,11 @@ namespace Mustache
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates the text when applying the format plan.
|
/// Generates the text when applying the format plan.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyScope">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="keyScope">The current lexical scope of the keys.</param>
|
||||||
/// <param name="contextScope">The data associated to the context.</param>
|
/// <param name="contextScope">The data associated to the context.</param>
|
||||||
|
/// <param name="postProcessor">A function to apply after a substitution is made.</param>
|
||||||
/// <returns>The generated text.</returns>
|
/// <returns>The generated text.</returns>
|
||||||
void GetText(Scope keyScope, TextWriter writer, Scope contextScope);
|
void GetText(TextWriter writer, Scope keyScope, Scope contextScope, Action<Substitution> postProcessor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Mustache
|
||||||
_arguments = arguments;
|
_arguments = arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(Scope scope, TextWriter writer, Scope context)
|
void IGenerator.GetText(TextWriter writer, Scope scope, Scope context, Action<Substitution> postProcessor)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> arguments;
|
Dictionary<string, object> arguments;
|
||||||
if (_definition.IsSetter)
|
if (_definition.IsSetter)
|
||||||
|
|
|
@ -11,7 +11,8 @@ namespace Mustache
|
||||||
/// Initializes a new instance of a KeyFoundEventArgs.
|
/// Initializes a new instance of a KeyFoundEventArgs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The fully-qualified key.</param>
|
/// <param name="key">The fully-qualified key.</param>
|
||||||
internal KeyFoundEventArgs(string key, object value)
|
/// <param name="isExtension">Specifies whether the key was found within triple curly braces.</param>
|
||||||
|
internal KeyFoundEventArgs(string key, object value, bool isExtension)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
Substitute = value;
|
Substitute = value;
|
||||||
|
@ -22,6 +23,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; private set; }
|
public string Key { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the key appeared within triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExtension { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the object to use as the substitute.
|
/// Gets or sets the object to use as the substitute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Mustache
|
||||||
private readonly string _key;
|
private readonly string _key;
|
||||||
private readonly string _format;
|
private readonly string _format;
|
||||||
private readonly bool _isVariable;
|
private readonly bool _isVariable;
|
||||||
|
private readonly bool _isExtension;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of a KeyGenerator.
|
/// Initializes a new instance of a KeyGenerator.
|
||||||
|
@ -19,7 +20,8 @@ namespace Mustache
|
||||||
/// <param name="key">The key to substitute with its value.</param>
|
/// <param name="key">The key to substitute with its value.</param>
|
||||||
/// <param name="alignment">The alignment specifier.</param>
|
/// <param name="alignment">The alignment specifier.</param>
|
||||||
/// <param name="formatting">The format specifier.</param>
|
/// <param name="formatting">The format specifier.</param>
|
||||||
public KeyGenerator(string key, string alignment, string formatting)
|
/// <param name="isExtension">Specifies whether the key was found within triple curly braces.</param>
|
||||||
|
public KeyGenerator(string key, string alignment, string formatting, bool isExtension)
|
||||||
{
|
{
|
||||||
if (key.StartsWith("@"))
|
if (key.StartsWith("@"))
|
||||||
{
|
{
|
||||||
|
@ -32,6 +34,7 @@ namespace Mustache
|
||||||
_isVariable = false;
|
_isVariable = false;
|
||||||
}
|
}
|
||||||
_format = getFormat(alignment, formatting);
|
_format = getFormat(alignment, formatting);
|
||||||
|
_isExtension = isExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getFormat(string alignment, string formatting)
|
private static string getFormat(string alignment, string formatting)
|
||||||
|
@ -52,10 +55,18 @@ namespace Mustache
|
||||||
return formatBuilder.ToString();
|
return formatBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(Scope scope, TextWriter writer, Scope context)
|
void IGenerator.GetText(TextWriter writer, Scope scope, Scope context, Action<Substitution> postProcessor)
|
||||||
{
|
{
|
||||||
object value = _isVariable ? context.Find(_key) : scope.Find(_key);
|
object value = _isVariable ? context.Find(_key, _isExtension) : scope.Find(_key, _isExtension);
|
||||||
writer.Write(_format, value);
|
string result = String.Format(writer.FormatProvider, _format, value);
|
||||||
|
Substitution substitution = new Substitution()
|
||||||
|
{
|
||||||
|
Key = _key,
|
||||||
|
Substitute = result,
|
||||||
|
IsExtension = _isExtension
|
||||||
|
};
|
||||||
|
postProcessor(substitution);
|
||||||
|
writer.Write(substitution.Substitute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,12 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The fully-qualified key.</param>
|
/// <param name="key">The fully-qualified key.</param>
|
||||||
/// <param name="missingMember">The part of the key that could not be found.</param>
|
/// <param name="missingMember">The part of the key that could not be found.</param>
|
||||||
internal KeyNotFoundEventArgs(string key, string missingMember)
|
/// <param name="isExtension">Specifies whether the key appears within triple curly braces.</param>
|
||||||
|
internal KeyNotFoundEventArgs(string key, string missingMember, bool isExtension)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
MissingMember = missingMember;
|
MissingMember = missingMember;
|
||||||
|
IsExtension = isExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -28,6 +30,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string MissingMember { get; private set; }
|
public string MissingMember { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the key appeared within triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExtension { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether to use the substitute.
|
/// Gets or sets whether to use the substitute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Mustache
|
||||||
|
|
||||||
public object GetValue(Scope keyScope, Scope contextScope)
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
{
|
{
|
||||||
return keyScope.Find(name);
|
return keyScope.Find(name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ namespace Mustache
|
||||||
/// <param name="key">The key that was found.</param>
|
/// <param name="key">The key that was found.</param>
|
||||||
/// <param name="alignment">The alignment that will be applied to the substitute value.</param>
|
/// <param name="alignment">The alignment that will be applied to the substitute value.</param>
|
||||||
/// <param name="formatting">The formatting that will be applied to the substitute value.</param>
|
/// <param name="formatting">The formatting that will be applied to the substitute value.</param>
|
||||||
|
/// <param name="isExtension">Indicates whether the placeholder was found within triple curly braces.</param>
|
||||||
/// <param name="context">The context where the placeholder was found.</param>
|
/// <param name="context">The context where the placeholder was found.</param>
|
||||||
internal PlaceholderFoundEventArgs(string key, string alignment, string formatting, Context[] context)
|
internal PlaceholderFoundEventArgs(string key, string alignment, string formatting, bool isExtension, Context[] context)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
Alignment = alignment;
|
Alignment = alignment;
|
||||||
|
@ -38,6 +39,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Formatting { get; set; }
|
public string Formatting { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the placeholder was found within triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExtension { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the context where the placeholder was found.
|
/// Gets the context where the placeholder was found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -14,6 +14,6 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: CLSCompliant(true)]
|
[assembly: CLSCompliant(true)]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: Guid("e5a4263d-d450-4d85-a4d5-44c0a2822668")]
|
[assembly: Guid("e5a4263d-d450-4d85-a4d5-44c0a2822668")]
|
||||||
[assembly: AssemblyVersion("0.2.8.2")]
|
[assembly: AssemblyVersion("0.2.9.0")]
|
||||||
[assembly: AssemblyFileVersion("0.2.8.2")]
|
[assembly: AssemblyFileVersion("0.2.9.0")]
|
||||||
[assembly: InternalsVisibleTo("mustache-sharp.test,PublicKey=0024000004800000940000000602000000240000525341310004000001000100755df5a2b24c568812aae0eb194d08a4e3cba960673bcc07a7d446acf52f3f56ae2155b37b8d547bc5d8c562823bd592d1312bef9ad4740a8bb503d0095c31419f9d190882a2fa46090412bf15b13ca0057ba533c85a853333132ec8b70cf19655ef961b06d1c3fc35b3f68680420562be741456cb7a18bd5ab0fa779f8d47b1")]
|
[assembly: InternalsVisibleTo("mustache-sharp.test,PublicKey=0024000004800000940000000602000000240000525341310004000001000100755df5a2b24c568812aae0eb194d08a4e3cba960673bcc07a7d446acf52f3f56ae2155b37b8d547bc5d8c562823bd592d1312bef9ad4740a8bb503d0095c31419f9d190882a2fa46090412bf15b13ca0057ba533c85a853333132ec8b70cf19655ef961b06d1c3fc35b3f68680420562be741456cb7a18bd5ab0fa779f8d47b1")]
|
|
@ -76,17 +76,18 @@ namespace Mustache
|
||||||
/// Attempts to find the value associated with the key with given name.
|
/// Attempts to find the value associated with the key with given name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the key.</param>
|
/// <param name="name">The name of the key.</param>
|
||||||
|
/// <param name="isExtension">Specifies whether the key appeared within triple curly braces.</param>
|
||||||
/// <returns>The value associated with the key with the given name.</returns>
|
/// <returns>The value associated with the key with the given name.</returns>
|
||||||
/// <exception cref="System.Collections.Generic.KeyNotFoundException">A key with the given name could not be found.</exception>
|
/// <exception cref="System.Collections.Generic.KeyNotFoundException">A key with the given name could not be found.</exception>
|
||||||
internal object Find(string name)
|
internal object Find(string name, bool isExtension)
|
||||||
{
|
{
|
||||||
SearchResults results = tryFind(name);
|
SearchResults results = tryFind(name);
|
||||||
if (results.Found)
|
if (results.Found)
|
||||||
{
|
{
|
||||||
return onKeyFound(name, results.Value);
|
return onKeyFound(name, results.Value, isExtension);
|
||||||
}
|
}
|
||||||
object value;
|
object value;
|
||||||
if (onKeyNotFound(name, results.Member, out value))
|
if (onKeyNotFound(name, results.Member, isExtension, out value))
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -94,25 +95,25 @@ namespace Mustache
|
||||||
throw new KeyNotFoundException(message);
|
throw new KeyNotFoundException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object onKeyFound(string name, object value)
|
private object onKeyFound(string name, object value, bool isExtension)
|
||||||
{
|
{
|
||||||
if (KeyFound == null)
|
if (KeyFound == null)
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
KeyFoundEventArgs args = new KeyFoundEventArgs(name, value);
|
KeyFoundEventArgs args = new KeyFoundEventArgs(name, value, isExtension);
|
||||||
KeyFound(this, args);
|
KeyFound(this, args);
|
||||||
return args.Substitute;
|
return args.Substitute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool onKeyNotFound(string name, string member, out object value)
|
private bool onKeyNotFound(string name, string member, bool isExtension, out object value)
|
||||||
{
|
{
|
||||||
if (KeyNotFound == null)
|
if (KeyNotFound == null)
|
||||||
{
|
{
|
||||||
value = null;
|
value = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
KeyNotFoundEventArgs args = new KeyNotFoundEventArgs(name, member);
|
KeyNotFoundEventArgs args = new KeyNotFoundEventArgs(name, member, isExtension);
|
||||||
KeyNotFound(this, args);
|
KeyNotFound(this, args);
|
||||||
if (!args.Handled)
|
if (!args.Handled)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace Mustache
|
||||||
get { return value; }
|
get { return value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGenerator.GetText(Scope scope, TextWriter writer, Scope context)
|
void IGenerator.GetText(TextWriter writer, Scope scope, Scope context, Action<Substitution> postProcessor)
|
||||||
{
|
{
|
||||||
writer.Write(Value);
|
writer.Write(Value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
internal class Substitution
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
public string Substitute { get; set; }
|
||||||
|
|
||||||
|
public bool IsExtension { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the information about a tag that's been converted to text.
|
||||||
|
/// </summary>
|
||||||
|
public class TagFormattedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of a TagFormattedEventArgs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The fully-qualified key.</param>
|
||||||
|
/// <param name="value">The formatted value being extended.</param>
|
||||||
|
/// <param name="isExtension">Specifies whether the key was found within triple curly braces.</param>
|
||||||
|
internal TagFormattedEventArgs(string key, string value, bool isExtension)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Substitute = value;
|
||||||
|
IsExtension = isExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the fully-qualified key.
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the key appeared within triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExtension { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the object to use as the substitute.
|
||||||
|
/// </summary>
|
||||||
|
public string Substitute { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ namespace Mustache
|
||||||
|
|
||||||
public object GetValue(Scope keyScope, Scope contextScope)
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
{
|
{
|
||||||
return contextScope.Find(name);
|
return contextScope.Find(name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,14 @@ namespace Mustache
|
||||||
/// <param name="key">The key that was found.</param>
|
/// <param name="key">The key that was found.</param>
|
||||||
/// <param name="alignment">The alignment that will be applied to the substitute value.</param>
|
/// <param name="alignment">The alignment that will be applied to the substitute value.</param>
|
||||||
/// <param name="formatting">The formatting that will be applied to the substitute value.</param>
|
/// <param name="formatting">The formatting that will be applied to the substitute value.</param>
|
||||||
|
/// <param name="isExtension">Specifies whether the variable was found within triple curly braces.</param>
|
||||||
/// <param name="context">The context where the placeholder was found.</param>
|
/// <param name="context">The context where the placeholder was found.</param>
|
||||||
internal VariableFoundEventArgs(string name, string alignment, string formatting, Context[] context)
|
internal VariableFoundEventArgs(string name, string alignment, string formatting, bool isExtension, Context[] context)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Alignment = alignment;
|
Alignment = alignment;
|
||||||
Formatting = formatting;
|
Formatting = formatting;
|
||||||
|
IsExtension = isExtension;
|
||||||
Context = context;
|
Context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +40,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Formatting { get; set; }
|
public string Formatting { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether variable was found within triple curly braces.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExtension { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the context where the placeholder was found.
|
/// Gets the context where the placeholder was found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -46,6 +46,9 @@
|
||||||
<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="Substitution.cs" />
|
||||||
|
<Compile Include="TagFormattedEventArgs.cs" />
|
||||||
|
<Compile Include="HtmlFormatCompiler.cs" />
|
||||||
<Compile Include="IArgument.cs" />
|
<Compile Include="IArgument.cs" />
|
||||||
<Compile Include="NumberArgument.cs" />
|
<Compile Include="NumberArgument.cs" />
|
||||||
<Compile Include="PlaceholderArgument.cs" />
|
<Compile Include="PlaceholderArgument.cs" />
|
||||||
|
|
Loading…
Reference in New Issue