Intial
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Web.Mvc;
|
||||
using HtmlTags;
|
||||
using Microsoft.Web.Mvc;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public static class AngularHelperExtension
|
||||
{
|
||||
public static AngularHelper<TModel> Angular<TModel>(this HtmlHelper<TModel> helper)
|
||||
{
|
||||
return new AngularHelper<TModel>(helper);
|
||||
}
|
||||
}
|
||||
|
||||
public class AngularHelper<TModel>
|
||||
{
|
||||
private readonly HtmlHelper<TModel> _htmlHelper;
|
||||
|
||||
public AngularHelper(HtmlHelper<TModel> helper)
|
||||
{
|
||||
_htmlHelper = helper;
|
||||
}
|
||||
|
||||
public AngularModelHelper<TModel> ModelFor(string expressionPrefix)
|
||||
{
|
||||
return new AngularModelHelper<TModel>(_htmlHelper, expressionPrefix);
|
||||
}
|
||||
|
||||
public HtmlTag FormForModel(string expressionPrefix)
|
||||
{
|
||||
var modelHelper = ModelFor(expressionPrefix);
|
||||
|
||||
var formGroupForMethodGeneric = typeof(AngularModelHelper<TModel>)
|
||||
.GetMethod("FormGroupFor");
|
||||
|
||||
var wrapperTag = new HtmlTag("div").NoTag();
|
||||
|
||||
foreach (var prop in typeof(TModel)
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (prop.GetCustomAttributes().OfType<HiddenInputAttribute>().Any()) continue;
|
||||
|
||||
var formGroupForProp = formGroupForMethodGeneric
|
||||
.MakeGenericMethod(prop.PropertyType);
|
||||
|
||||
var propertyLambda = MakeLambda(prop);
|
||||
|
||||
var formGroupTag = (HtmlTag)formGroupForProp.Invoke(modelHelper,
|
||||
new[] { propertyLambda });
|
||||
|
||||
wrapperTag.Append(formGroupTag);
|
||||
}
|
||||
|
||||
return wrapperTag;
|
||||
}
|
||||
|
||||
//Constructs a lambda of the form x => x.PropName
|
||||
private object MakeLambda(PropertyInfo prop)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(TModel), "x");
|
||||
var property = Expression.Property(parameter, prop);
|
||||
var funcType = typeof(Func<,>).MakeGenericType(typeof(TModel), prop.PropertyType);
|
||||
|
||||
//x => x.PropName
|
||||
return Expression.Lambda(funcType, property, parameter);
|
||||
}
|
||||
|
||||
public UIRatingTag UIRating(string model)
|
||||
{
|
||||
return new UIRatingTag(model);
|
||||
}
|
||||
|
||||
public GridTag GridFor<TController>(Expression<Action<TController>> targetAction)
|
||||
where TController : Controller
|
||||
{
|
||||
var dataUrl = _htmlHelper.BuildUrlFromExpression(targetAction);
|
||||
|
||||
return new GridTag(dataUrl);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using HtmlTags;
|
||||
using Humanizer;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public class AngularModelHelper<TModel>
|
||||
{
|
||||
protected readonly HtmlHelper Helper;
|
||||
private readonly string _expressionPrefix;
|
||||
|
||||
public AngularModelHelper(HtmlHelper helper, string expressionPrefix)
|
||||
{
|
||||
Helper = helper;
|
||||
_expressionPrefix = expressionPrefix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an lambda expression into a camel-cased string, prefixed
|
||||
/// with the helper's configured prefix expression, ie:
|
||||
/// vm.model.parentProperty.childProperty
|
||||
/// </summary>
|
||||
public IHtmlString ExpressionFor<TProp>(Expression<Func<TModel, TProp>> property)
|
||||
{
|
||||
var expressionText = ExpressionForInternal(property);
|
||||
return new MvcHtmlString(expressionText);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a lambda expression into a camel-cased AngularJS binding expression, ie:
|
||||
/// {{vm.model.parentProperty.childProperty}}
|
||||
/// </summary>
|
||||
public IHtmlString BindingFor<TProp>(Expression<Func<TModel, TProp>> property)
|
||||
{
|
||||
return MvcHtmlString.Create("{{" + ExpressionForInternal(property) + "}}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a div with an ng-repeat directive to enumerate the specified property,
|
||||
/// and returns a new helper you can use for strongly-typed bindings on the items
|
||||
/// in the enumerable property.
|
||||
/// </summary>
|
||||
public AngularNgRepeatHelper<TSubModel> Repeat<TSubModel>(
|
||||
Expression<Func<TModel, IEnumerable<TSubModel>>> property, string variableName)
|
||||
{
|
||||
var propertyExpression = ExpressionForInternal(property);
|
||||
return new AngularNgRepeatHelper<TSubModel>(
|
||||
Helper, variableName, propertyExpression);
|
||||
}
|
||||
|
||||
private string ExpressionForInternal<TProp>(Expression<Func<TModel, TProp>> property)
|
||||
{
|
||||
var camelCaseName = property.ToCamelCaseName();
|
||||
|
||||
var expression = !string.IsNullOrEmpty(_expressionPrefix)
|
||||
? _expressionPrefix + "." + camelCaseName
|
||||
: camelCaseName;
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
public HtmlTag FormGroupFor<TProp>(Expression<Func<TModel, TProp>> property)
|
||||
{
|
||||
var metadata = ModelMetadata.FromLambdaExpression(property, new ViewDataDictionary<TModel>());
|
||||
|
||||
var name = ExpressionHelper.GetExpressionText(property);
|
||||
|
||||
var expression = ExpressionForInternal(property);
|
||||
|
||||
//Creates <div class="form-group has-feedback"
|
||||
// form-group-validation="Name">
|
||||
var formGroup = new HtmlTag("div")
|
||||
.AddClasses("form-group", "has-feedback")
|
||||
.Attr("form-group-validation", name);
|
||||
|
||||
var labelText = metadata.DisplayName ?? name.Humanize(LetterCasing.Title);
|
||||
|
||||
//Creates <label class="control-label" for="Name">Name</label>
|
||||
var label = new HtmlTag("label")
|
||||
.AddClass("control-label")
|
||||
.Attr("for", name)
|
||||
.Text(labelText);
|
||||
|
||||
var tagName = metadata.DataTypeName == "MultilineText"
|
||||
? "textarea"
|
||||
: "input";
|
||||
|
||||
var placeholder = metadata.Watermark ??
|
||||
(labelText + "...");
|
||||
//Creates <input ng-model="expression"
|
||||
// class="form-control" name="Name" type="text" >
|
||||
var input = new HtmlTag(tagName)
|
||||
.AddClass("form-control")
|
||||
.Attr("ng-model", expression)
|
||||
.Attr("name", name)
|
||||
.Attr("type", "text")
|
||||
.Attr("placeholder", placeholder);
|
||||
|
||||
ApplyValidationToInput(input, metadata);
|
||||
|
||||
return formGroup
|
||||
.Append(label)
|
||||
.Append(input);
|
||||
}
|
||||
|
||||
private void ApplyValidationToInput(HtmlTag input, ModelMetadata metadata)
|
||||
{
|
||||
if (metadata.IsRequired)
|
||||
input.Attr("required", "");
|
||||
|
||||
if (metadata.DataTypeName == "EmailAddress")
|
||||
input.Attr("type", "email");
|
||||
|
||||
if (metadata.ModelType == typeof(DateTime))
|
||||
input.Attr("type", "date");
|
||||
|
||||
if (metadata.DataTypeName == "PhoneNumber")
|
||||
input.Attr("pattern", @"[\ 0-9()-]+");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Web.Mvc;
|
||||
using HtmlTags;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public class AngularNgRepeatHelper<TModel> : AngularModelHelper<TModel>, IDisposable
|
||||
{
|
||||
public AngularNgRepeatHelper(HtmlHelper helper,
|
||||
string variableName, string propertyExpression)
|
||||
: base(helper, variableName)
|
||||
{
|
||||
var div = new HtmlTag("div");
|
||||
div.Attr("ng-repeat",
|
||||
string.Format("{0} in {1}", variableName, propertyExpression));
|
||||
div.NoClosingTag();
|
||||
|
||||
Helper.ViewContext.Writer.Write(div.ToString());
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Helper.ViewContext.Writer.Write("</div>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Web.UI;
|
||||
using HtmlTags;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public class GridTag : HtmlTag
|
||||
{
|
||||
public class ColumnBuilder<T>
|
||||
{
|
||||
private readonly GridTag _tag;
|
||||
|
||||
public ColumnBuilder(GridTag tag)
|
||||
{
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
public void Add<TProp>(Expression<Func<T, TProp>> property,
|
||||
string columnHeader = null,
|
||||
string cellFilter = null)
|
||||
{
|
||||
_tag._columns.Add(new ColumnDefinition
|
||||
{
|
||||
Field = property.ToCamelCaseName(),
|
||||
Name = columnHeader,
|
||||
CellFilter = cellFilter
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ColumnDefinition
|
||||
{
|
||||
public string Field { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string CellFilter { get; set; }
|
||||
}
|
||||
|
||||
private readonly List<ColumnDefinition> _columns = new List<ColumnDefinition>();
|
||||
|
||||
public GridTag(string dataUrl)
|
||||
: base("mvc-grid")
|
||||
{
|
||||
Attr("grid-data-url", dataUrl);
|
||||
}
|
||||
|
||||
public new GridTag Title(string title)
|
||||
{
|
||||
Attr("title", title);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GridTag Columns<T>(Action<ColumnBuilder<T>> configAction)
|
||||
{
|
||||
var builder = new ColumnBuilder<T>(this);
|
||||
configAction(builder);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override void writeHtml(HtmlTextWriter html)
|
||||
{
|
||||
if (_columns.Any())
|
||||
this.Attr("columns", _columns.ToArray().ToJson(includeNull: false));
|
||||
|
||||
base.writeHtml(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using InventoryTraker.Web.Utilities;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public static class JsonHtmlHelpers
|
||||
{
|
||||
public static IHtmlString JsonFor<T>(this HtmlHelper helper, T obj)
|
||||
{
|
||||
return helper.Raw(obj.ToJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using HtmlTags;
|
||||
|
||||
namespace InventoryTraker.Web.Helpers
|
||||
{
|
||||
public class UIRatingTag : HtmlTag
|
||||
{
|
||||
public UIRatingTag(string model) : base("rating")
|
||||
{
|
||||
Attr("ng-model", model);
|
||||
}
|
||||
|
||||
public UIRatingTag Max(int max)
|
||||
{
|
||||
Attr("max", max);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public UIRatingTag NgClick(string action)
|
||||
{
|
||||
Attr("ng-click", action);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user