From e15b764bf9466af2ce55edb8b0b626ecd6c9af0f Mon Sep 17 00:00:00 2001 From: Zachary Pudil Date: Sat, 11 May 2013 16:00:33 -0700 Subject: [PATCH 1/2] Added logic to the LabelFor<> Helper Logic now includes a "*" in the label if the field has a required attribute or is not able to be assigned null. --- .../Builders/Builder.cs | 9 ++++--- .../Utility/ExpressionParser.cs | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/FluentKnockoutHelpers.Core/Builders/Builder.cs b/src/FluentKnockoutHelpers.Core/Builders/Builder.cs index 530c1e9..e32fc22 100644 --- a/src/FluentKnockoutHelpers.Core/Builders/Builder.cs +++ b/src/FluentKnockoutHelpers.Core/Builders/Builder.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq.Expressions; using System.Web; using System.Web.Mvc; @@ -167,12 +168,12 @@ public virtual IHtmlString GetExpressionTextFor(Expression /// /// - public virtual StringReturningBuilder LabelFor(Expression> propExpr) + public virtual StringReturningBuilder LabelFor(Expression> propExpr, bool displayStarIfRequired = true) { - return ElementSelfClosing("label", DisplayNameFor(propExpr).ToString()).Attr("for", ExpressionParser.GetExpressionText(propExpr)); - } - + var required = displayStarIfRequired && (!ExpressionParser.ExpressionCanBeAssignedNull(propExpr) || ExpressionParser.ExpressionHasAttribute(propExpr, typeof(RequiredAttribute))); + return ElementSelfClosing("label", (required ? "*" : "") + DisplayNameFor(propExpr).ToString()).Attr("for", ExpressionParser.GetExpressionText(propExpr)); + } #region Bound ___ For diff --git a/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs b/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs index 8a4a023..bdaeeb9 100644 --- a/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs +++ b/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs @@ -55,6 +55,32 @@ public static string DisplayNameFor(Expression + /// Determine if the property in the Lambda Expression can be assigned a null + /// + /// Expression containing property to check + /// + public static bool ExpressionCanBeAssignedNull(LambdaExpression expr) + { + var type = ToMemberExpression(expr).Type; + return !type.IsValueType || (Nullable.GetUnderlyingType(type) != null); + } + + /// + /// Determine if the property in the Lambda Expression has a paramater attribute type on it. + /// + /// Expression containing the property + /// The type of attribute to check for + /// + public static bool ExpressionHasAttribute(LambdaExpression expr, Type type) + { + /*TODO: + * I'm assuming that the first paramater of the expression is the Class that contains the property to check. + * May not be the best way of doing business, ifyaknowwhatimsaying. + */ + return expr.Parameters[0].Type.GetProperty(GetExpressionText(expr)).GetCustomAttributes(type, false).Length != 0; + } + //FirstName => First Name private static string CamelCaseSpacer(string propName) { From 75614b041092465386594d7f93da91a405e4d31d Mon Sep 17 00:00:00 2001 From: Zachary Pudil Date: Sun, 12 May 2013 13:39:42 -0700 Subject: [PATCH 2/2] Refactoring required token logic Move display logic into ExpressionParser.DisplayFor to reduce hits on expression parsing. Added a Global Setting for the token and whether or not to use it. --- .../Builders/Builder.cs | 6 ++-- .../GlobalSettings.cs | 20 +++++++++++++ .../Utility/ExpressionParser.cs | 30 ++----------------- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/FluentKnockoutHelpers.Core/Builders/Builder.cs b/src/FluentKnockoutHelpers.Core/Builders/Builder.cs index e32fc22..b40db19 100644 --- a/src/FluentKnockoutHelpers.Core/Builders/Builder.cs +++ b/src/FluentKnockoutHelpers.Core/Builders/Builder.cs @@ -168,11 +168,9 @@ public virtual IHtmlString GetExpressionTextFor(Expression /// /// - public virtual StringReturningBuilder LabelFor(Expression> propExpr, bool displayStarIfRequired = true) + public virtual StringReturningBuilder LabelFor(Expression> propExpr) { - var required = displayStarIfRequired && (!ExpressionParser.ExpressionCanBeAssignedNull(propExpr) || ExpressionParser.ExpressionHasAttribute(propExpr, typeof(RequiredAttribute))); - - return ElementSelfClosing("label", (required ? "*" : "") + DisplayNameFor(propExpr).ToString()).Attr("for", ExpressionParser.GetExpressionText(propExpr)); + return ElementSelfClosing("label", DisplayNameFor(propExpr).ToString()).Attr("for", ExpressionParser.GetExpressionText(propExpr)); } #region Bound ___ For diff --git a/src/FluentKnockoutHelpers.Core/GlobalSettings.cs b/src/FluentKnockoutHelpers.Core/GlobalSettings.cs index 585106b..aa30308 100644 --- a/src/FluentKnockoutHelpers.Core/GlobalSettings.cs +++ b/src/FluentKnockoutHelpers.Core/GlobalSettings.cs @@ -8,6 +8,8 @@ namespace FluentKnockoutHelpers.Core public static class GlobalSettings { private static IJsonSerializer _jsonSerializer = new DefaultJsonSerializer(); + private static string _requiredToken = "*"; + private static bool _useRequiredToken = true; /// /// Supply a custom IJsonSerializer to use something other than the default JSON.NET. Ex: ServiceStack @@ -17,5 +19,23 @@ public static IJsonSerializer JsonSerializer get { return _jsonSerializer; } set { _jsonSerializer = value; } } + + /// + /// Supply a custom required token to use something other than the default "*" + /// + public static string RequiredToken + { + get { return _requiredToken; } + set { _requiredToken = value; } + } + + /// + /// Set whether or not to use a required token on the display name for non-nullable/required properties + /// + public static bool UseRequiredToken + { + get { return _useRequiredToken; } + set { _useRequiredToken = value; } + } } } \ No newline at end of file diff --git a/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs b/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs index bdaeeb9..a94a954 100644 --- a/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs +++ b/src/FluentKnockoutHelpers.Core/Utility/ExpressionParser.cs @@ -49,36 +49,12 @@ public static string DisplayNameFor(Expression p.PropertyName == propertyName); + var requiredToken = (GlobalSettings.UseRequiredToken && propMetadata.IsRequired ? GlobalSettings.RequiredToken : String.Empty); + if (propMetadata == null) return CamelCaseSpacer(propertyName); - return propMetadata.DisplayName ?? CamelCaseSpacer(propMetadata.PropertyName); - } - - /// - /// Determine if the property in the Lambda Expression can be assigned a null - /// - /// Expression containing property to check - /// - public static bool ExpressionCanBeAssignedNull(LambdaExpression expr) - { - var type = ToMemberExpression(expr).Type; - return !type.IsValueType || (Nullable.GetUnderlyingType(type) != null); - } - - /// - /// Determine if the property in the Lambda Expression has a paramater attribute type on it. - /// - /// Expression containing the property - /// The type of attribute to check for - /// - public static bool ExpressionHasAttribute(LambdaExpression expr, Type type) - { - /*TODO: - * I'm assuming that the first paramater of the expression is the Class that contains the property to check. - * May not be the best way of doing business, ifyaknowwhatimsaying. - */ - return expr.Parameters[0].Type.GetProperty(GetExpressionText(expr)).GetCustomAttributes(type, false).Length != 0; + return requiredToken + (propMetadata.DisplayName ?? CamelCaseSpacer(propMetadata.PropertyName)); } //FirstName => First Name