Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for DictionaryAttributePrefix and ModelExplorer property in liquid #5099

Merged
merged 32 commits into from
Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
007a648
Added support for DictionaryAttributePrefix in liquid as per comments…
ns8482e Dec 21, 2019
012c200
Added form block
ns8482e Dec 21, 2019
258f250
remove extra space
ns8482e Dec 21, 2019
a90c0a1
Added Support for Model expressions, possibly fixes #4426
ns8482e Dec 24, 2019
82c5b4a
Merge branch 'dev' of https://github.com/OrchardCMS/OrchardCore into …
ns8482e Jan 8, 2020
2902e2b
reverted to simplified type
ns8482e Jan 8, 2020
22c9ff2
created FastGetterProperty for getter
ns8482e Jan 8, 2020
6cd48e9
review feedback
ns8482e Feb 15, 2020
cb27e8e
Merge branch 'dev' of https://github.com/OrchardCMS/OrchardCore into …
ns8482e Feb 15, 2020
d162855
Added Liquid CRUD samples that use asp-for, asp-validation-for, asp-r…
ns8482e Feb 18, 2020
3f71acb
Merge branch 'dev' of https://github.com/OrchardCMS/OrchardCore into …
ns8482e Feb 18, 2020
c4d7fad
Updated document
ns8482e Feb 19, 2020
bd21669
docus for route-data
ns8482e Feb 19, 2020
cd0d8f6
Merge branch 'dev' into ns8482e/liquid-idictonary-support
sebastienros Mar 5, 2020
1935f0c
Update after merging dev
jtkech Mar 5, 2020
4cad1ec
Merge branch 'dev' of https://github.com/OrchardCMS/OrchardCore into …
ns8482e Mar 21, 2020
9fd64b8
Review feedback
ns8482e Mar 21, 2020
3d989e2
EOL
ns8482e Mar 21, 2020
dd9d68e
Update AdminMenu.cs
jtkech Mar 22, 2020
9785a97
Create TodoViewModel.cs
jtkech Mar 22, 2020
d542940
Update TodoModel.cs
jtkech Mar 22, 2020
154eb09
Update TodoController.cs
jtkech Mar 22, 2020
f54d7d6
Update Todo.Edit.liquid
jtkech Mar 22, 2020
0841c14
Update Todo.liquid
jtkech Mar 22, 2020
dc8448c
Update Edit.liquid
jtkech Mar 22, 2020
bee53d6
Update Index.liquid
jtkech Mar 22, 2020
cbebd49
Update LiquidViewTemplate.cs
jtkech Mar 22, 2020
899431c
Update LiquidTagHelperActivator.cs
jtkech Mar 22, 2020
728d2c7
Update StringExtensions.cs
jtkech Mar 22, 2020
7f95cb5
Update README.md
jtkech Mar 22, 2020
1c0a553
Update README.md
jtkech Mar 22, 2020
94167de
Update README.md
ns8482e Mar 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ static LiquidViewTemplate()
Factory.RegisterBlock<HelperBlock>("block");
Factory.RegisterBlock<NamedHelperBlock>("a");
Factory.RegisterBlock<NamedHelperBlock>("zone");
Factory.RegisterBlock<NamedHelperBlock>("form");
Factory.RegisterBlock<NamedHelperBlock>("scriptblock");

// Dynamic caching
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class LiquidTagHelperActivator
public static readonly LiquidTagHelperActivator None = new LiquidTagHelperActivator();

private readonly Func<ITagHelperFactory, ViewContext, ITagHelper> _activatorByFactory;
private readonly Dictionary<string, Action<ITagHelper, FluidValue>> _setters =
new Dictionary<string, Action<ITagHelper, FluidValue>>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Action<ITagHelper, ModelExpressionProvider, ViewDataDictionary<dynamic>, string, FluidValue>> _setters =
new Dictionary<string, Action<ITagHelper, ModelExpressionProvider, ViewDataDictionary<dynamic>, string, FluidValue>>(StringComparer.OrdinalIgnoreCase);

private readonly Func<ViewContext, ITagHelper> _activatorByService;
private readonly Action<object, object> _viewContextSetter;
Expand All @@ -46,9 +46,20 @@ public LiquidTagHelperActivator(Type type)
{
allNames.Add(htmlAttribute.Name.Substring(4).ToPascalCaseDash());
}
var dictonaryPrefix = htmlAttribute.DictionaryAttributePrefix;
if(dictonaryPrefix != null)
{
allNames.Add(dictonaryPrefix.ToPascalCaseDash());

if (dictonaryPrefix.StartsWith("asp-", StringComparison.Ordinal))
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
{
allNames.Add(dictonaryPrefix.Substring(4).ToPascalCaseDash());
}
}
}

var setter = MakeFastPropertySetter(type, property);
var getter = MakeFastPropertyGetter(type, property);

foreach (var propertyName in allNames)
{
Expand All @@ -58,7 +69,7 @@ public LiquidTagHelperActivator(Type type)
continue;
}

_setters.Add(propertyName, (h, v) =>
_setters.Add(propertyName, (h, mp, vd, k, v) =>
{
object value = null;

Expand All @@ -78,6 +89,24 @@ public LiquidTagHelperActivator(Type type)
{
value = v.IsNil() ? null : (bool?)Convert.ToBoolean(v.ToStringValue());
}
else if(property.PropertyType == typeof(IDictionary<string, string>))
{
IDictionary<string, string> dictValue = (IDictionary<string, string>) getter(h);
if(!string.IsNullOrWhiteSpace(k))
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
dictValue[k] = v.ToStringValue();
value = dictValue;
}
else if(property.PropertyType == typeof(IDictionary<string, object>))
{
IDictionary<string, object> dictValue = (IDictionary<string, object>) getter(h);
if(!string.IsNullOrWhiteSpace(k))
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
dictValue[k] = v.ToObjectValue();
value = dictValue;
}
else if(property.PropertyType == typeof(Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression))
{
value = mp.CreateModelExpression<dynamic>(vd,v.ToStringValue() );
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
value = v.ToObjectValue();
Expand Down Expand Up @@ -123,18 +152,26 @@ public LiquidTagHelperActivator(Type type)
{
tagHelper = _activatorByFactory(factory, context);
}

var dictKeySeperator =new char[] {'-','_'};

var expresionProvider = context.HttpContext.RequestServices.GetService(typeof(Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpressionProvider)) as
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpressionProvider;

var viewData = new ViewDataDictionary<dynamic>(context.ViewData);

foreach (var name in arguments.Names)
{
var propertyName = name.ToPascalCaseUnderscore();

var dictPropertyName = propertyName.LastIndexOfAny(dictKeySeperator) > -1 ? propertyName.Substring(0,propertyName.LastIndexOfAny(dictKeySeperator)+1) : String.Empty;
var dictPropertyKey = propertyName.LastIndexOfAny(dictKeySeperator) > -1 ? propertyName.Substring(propertyName.LastIndexOfAny(dictKeySeperator)+1) : String.Empty;
var found = false;

if (_setters.TryGetValue(propertyName, out var setter))
if (_setters.TryGetValue(propertyName, out var setter) || ( !string.IsNullOrWhiteSpace(dictPropertyName) && _setters.TryGetValue(dictPropertyName, out setter) ) )
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
{
try
{
setter(tagHelper, arguments[name]);
setter(tagHelper, expresionProvider, viewData, dictPropertyKey, arguments[name] );
found = true;
}
catch (ArgumentException e)
Expand Down Expand Up @@ -172,12 +209,28 @@ public static ITagHelper CreateTagHelper(ITagHelperFactory tagHelperFactory, Vie
var setterDelegate = setterClosedGenericMethod.CreateDelegate(typeof(Action<object, object>), setterAsAction);

return (Action<object, object>)setterDelegate;
}
}
ns8482e marked this conversation as resolved.
Show resolved Hide resolved

private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
typeof(LiquidTagHelperActivator).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter));

private static void CallPropertySetter<TDeclaringType, TValue>(Action<TDeclaringType, TValue> setter, object target, object value)
=> setter((TDeclaringType)target, (TValue)value);

private static Func<object, object> MakeFastPropertyGetter(Type type, PropertyInfo prop)
{
// Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; }
var getterAsFunc = prop.GetMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(type, prop.PropertyType));
var getterClosedGenericMethod = CallPropertyGetterOpenGenericMethod.MakeGenericMethod(type, prop.PropertyType);
var getterDelegate = getterClosedGenericMethod.CreateDelegate(typeof(Func<object, object>), getterAsFunc);

return (Func<object, object>)getterDelegate;
}

private static readonly MethodInfo CallPropertyGetterOpenGenericMethod =
typeof(LiquidTagHelperActivator).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter));

private static object CallPropertyGetter<TDeclaringType, TValue>(Func<TDeclaringType, TValue> getter, object target)
=> getter((TDeclaringType)target);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ public static string ToPascalCase(this string attribute, char upperAfterDelimite
var nextIsUpper = true;
attribute = attribute.Trim();
var result = new StringBuilder(attribute.Length);
var endsWithDelimiter = attribute.EndsWith(upperAfterDelimiter);
foreach (var c in attribute)
{
if (c == upperAfterDelimiter)
Expand All @@ -465,6 +466,8 @@ public static string ToPascalCase(this string attribute, char upperAfterDelimite
nextIsUpper = false;
}

if(endsWithDelimiter)
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
result.Append(upperAfterDelimiter);
return result.ToString();
ns8482e marked this conversation as resolved.
Show resolved Hide resolved
}
}
Expand Down