Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
artiomchi committed Jan 31, 2016
2 parents dd935e1 + 8c6ecc4 commit fc1251a
Show file tree
Hide file tree
Showing 26 changed files with 507 additions and 540 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,5 @@ FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
ModelManifest.xml
project.lock.json
12 changes: 11 additions & 1 deletion FlexLabs.Web.TablePager.sln → FlexLabs.Util.Web.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A2875F06-7319-47E7-910E-02AFDB0926A8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A1A76EFD-F496-4950-9519-3121D04D6938}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E685C7B6-1D8A-4969-8C53-AF238F7300F8}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
README.md = README.md
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FlexLabs.Web.TablePager", "src\FlexLabs.Web.TablePager\FlexLabs.Web.TablePager.xproj", "{819C9A3B-C8FA-42D2-9E4E-209355ED8443}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FlexLabs.Util.Web", "src\FlexLabs.Util.Web\FlexLabs.Util.Web.xproj", "{819C9A3B-C8FA-42D2-9E4E-209355ED8443}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FlexLabs.Util.Web.Tests", "test\FlexLabs.Util.Web.Tests\FlexLabs.Util.Web.Tests.xproj", "{7EA2A423-79BD-4F18-8E5C-F3681A682EF0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -22,11 +27,16 @@ Global
{819C9A3B-C8FA-42D2-9E4E-209355ED8443}.Debug|Any CPU.Build.0 = Debug|Any CPU
{819C9A3B-C8FA-42D2-9E4E-209355ED8443}.Release|Any CPU.ActiveCfg = Release|Any CPU
{819C9A3B-C8FA-42D2-9E4E-209355ED8443}.Release|Any CPU.Build.0 = Release|Any CPU
{7EA2A423-79BD-4F18-8E5C-F3681A682EF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7EA2A423-79BD-4F18-8E5C-F3681A682EF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EA2A423-79BD-4F18-8E5C-F3681A682EF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EA2A423-79BD-4F18-8E5C-F3681A682EF0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{819C9A3B-C8FA-42D2-9E4E-209355ED8443} = {A2875F06-7319-47E7-910E-02AFDB0926A8}
{7EA2A423-79BD-4F18-8E5C-F3681A682EF0} = {A1A76EFD-F496-4950-9519-3121D04D6938}
EndGlobalSection
EndGlobal
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
TablePager
FlexLabs.Util.Web
==========

A NuGet extension that helps automate and simplify paging for MVC sites
A NuGet extension that helps automate and simplify some common tasks in MVC projects.

Contains the TablePager and some new html editor extensions

---

Expand Down
19 changes: 19 additions & 0 deletions src/FlexLabs.Util.Web/AutoDropDownListAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace FlexLabs.Web
{
public sealed class AutoDropDownListAttribute : Attribute
{
/// <summary>
/// Defines the settings to initialise the DropDownList with
/// </summary>
/// <param name="optionsFieldName">The field in the model class that contains the IEnumerable&lt;SelectListItem&gt;</param>
public AutoDropDownListAttribute(String optionsFieldName)
{
OptionsFieldName = optionsFieldName;
}

public String OptionsFieldName { get; private set; }
public String OptionsLabel { get; set; }
}
}
13 changes: 13 additions & 0 deletions src/FlexLabs.Util.Web/AutoTextBoxAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace FlexLabs.Web
{
public sealed class AutoTextBoxAttribute : Attribute
{
/// <summary>
/// A string that is used to format the input
/// </summary>
public String Format { get; set; }
public String Type { get; set; }
}
}
42 changes: 42 additions & 0 deletions src/FlexLabs.Util.Web/ExpressionHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Linq.Expressions;
using System.Reflection;

namespace FlexLabs.Web.Html
{
internal static class ExpressionHelper
{
public static MemberInfo GetMemberInfo(Expression expression)
{
if (expression == null)
return null;

if (expression is LambdaExpression)
return GetMemberInfo((expression as LambdaExpression).Body);

switch (expression.NodeType)
{
case ExpressionType.ArrayIndex:
var binaryExpression = expression as BinaryExpression;
return GetMemberInfo(binaryExpression.Left);

case ExpressionType.MemberAccess:
var memberExpression = expression as MemberExpression;
return memberExpression.Member;

default:
return null;
}
}

public static TAttribute GetAttribute<TAttribute>(MemberInfo memberInfo)
where TAttribute: Attribute
{
var attributes = memberInfo.GetCustomAttributes(typeof(TAttribute), false);
if (attributes.Length > 0)
return attributes[0] as TAttribute;

return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>819c9a3b-c8fa-42d2-9e4e-209355ed8443</ProjectGuid>
<RootNamespace>FlexLabs.TablePager</RootNamespace>
<RootNamespace>FlexLabs.Web</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
64 changes: 64 additions & 0 deletions src/FlexLabs.Util.Web/Html/EditorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace FlexLabs.Web.Html
{
public static class EditorHelpers
{
public static MvcHtmlString AutoEditorFieldFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, String templateName = null, Object additionalViewData = null)
{
var label = html.LabelFor(expression);
var validation = html.ValidationMessageFor(expression);

MvcHtmlString editor = null;
var member = ExpressionHelper.GetMemberInfo(expression);

if (editor == null && ExpressionHelper.GetAttribute<AutoDropDownListAttribute>(member) != null)
editor = html.AutoDropDownListFor(expression);
if (editor == null && ExpressionHelper.GetAttribute<AutoTextBoxAttribute>(member) != null)
editor = html.AutoTextBoxFor(expression);
if (editor == null)
editor = html.EditorFor(expression, templateName, additionalViewData);

return MvcHtmlString.Create(label.ToString() + editor.ToString() + validation.ToString());
}

public static MvcHtmlString AutoDropDownListFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Object htmlAttributes = null)
{
var member = ExpressionHelper.GetMemberInfo(expression);
var attr = ExpressionHelper.GetAttribute<AutoDropDownListAttribute>(member);
if (attr == null)
throw new InvalidOperationException("Missing AutoDropDownListAttribute on property");

var field = member.DeclaringType.GetField(attr.OptionsFieldName);
if (field == null)
throw new MissingFieldException($"Could not find field {attr.OptionsFieldName} on type {member.DeclaringType}");
if (!typeof(IEnumerable<SelectListItem>).IsAssignableFrom(field.FieldType))
throw new Exception($"Field {attr.OptionsFieldName} is not of type IEnumerable<SelectListItem>");

var model = html.ViewData.Model;
var options = field.GetValue(model) as IEnumerable<SelectListItem>;
return html.DropDownListFor(expression, options, attr.OptionsLabel, htmlAttributes);
}

public static MvcHtmlString AutoTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Object htmlAttributes = null)
{
var member = ExpressionHelper.GetMemberInfo(expression);
var attr = ExpressionHelper.GetAttribute<AutoTextBoxAttribute>(member);
if (attr == null)
throw new InvalidOperationException("Missing AutoTextBoxAttribute on property");

var attributes = htmlAttributes != null
? (IDictionary<String, Object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)
: new Dictionary<String, Object>(StringComparer.OrdinalIgnoreCase);

if (attr.Type != null && !attributes.ContainsKey("type"))
attributes["type"] = attr.Type;

return html.TextBoxFor(expression, attr.Format, attributes);
}
}
}
101 changes: 101 additions & 0 deletions src/FlexLabs.Util.Web/Html/PagingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using FlexLabs.Web.TablePager;
using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace FlexLabs.Web.Html
{
public static class PagingExtensions
{
public static MvcHtmlString EnableFormSorting<TModel>(this HtmlHelper<TModel> html)
where TModel : ITableModel
{
var model = html.ViewData.Model;
String result = String.Empty;

if (model.SortBy != null)
{
var sortBy = new TagBuilder("input");
sortBy.MergeAttribute("type", "hidden");
sortBy.MergeAttribute("name", "SortBy");
sortBy.MergeAttribute("value", model.SortBy.ToString());
result += sortBy.ToString(TagRenderMode.SelfClosing);
}

if (model.SortAsc != null)
{
var sortAsc = new TagBuilder("input");
sortAsc.MergeAttribute("type", "hidden");
sortAsc.MergeAttribute("name", "SortAsc");
sortAsc.MergeAttribute("value", model.SortAsc.ToString());
result += sortAsc.ToString(TagRenderMode.SelfClosing);
}

if (model.FirstItemID != null)
{
var firstItemID = new TagBuilder("input");
firstItemID.MergeAttribute("type", "hidden");
firstItemID.MergeAttribute("name", "FirstItemID");
firstItemID.MergeAttribute("value", model.FirstItemID.ToString());
result += firstItemID.ToString(TagRenderMode.SelfClosing);
}

return MvcHtmlString.Create(result);
}

public static MvcHtmlString PageSizer<TModel>(this HtmlHelper<TModel> html, String lavel = "Page Size: ", Int32[] pageSizes = null, Int32? currentSize = null)
where TModel : ITableModel
{
var label = html.LabelFor(m => m.PageSize);
var editor = html.DropDownListFor(m => m.PageSize, TableModel.GetPageSizes(pageSizes, currentSize), new { onchange = "$(this).closest('form').submit();" });
var validation = html.ValidationMessageFor(m => m.PageSize);

return MvcHtmlString.Create(label.ToString() + editor.ToString() + validation.ToString());
}

public static MvcHtmlString Pager<TModel>(this HtmlHelper<TModel> html, PagedListData pageData, String label = "Page: ")
where TModel : ITableModel
{
var labelTag = new TagBuilder("label");
labelTag.SetInnerText(label);

var ulTag = new TagBuilder("ul");

if (!pageData.CanSeeFirstPage())
ulTag.InnerHtml += PagerLink(1);

foreach (var page in pageData.PageRange)
{
if (page == pageData.PageNumber)
ulTag.InnerHtml += $"<li class=\"page-current\">{page}</li>";
else
ulTag.InnerHtml += PagerLink(page);
}

if (!pageData.CanSeeLastPage())
ulTag.InnerHtml += PagerLink(pageData.PageCount);

var divTag = new TagBuilder("div");
divTag.AddCssClass("table-pager");
divTag.InnerHtml += labelTag.ToString();
divTag.InnerHtml += ulTag;
return MvcHtmlString.Create(divTag.ToString());
}

private static String PagerLink(Int32 pageNumber)
{
return $"<li><button type=\"submit\" name=\"page\" value=\"{pageNumber}\">{pageNumber}</button></li>";
}

public static MvcHtmlString Pager<TModel>(this HtmlHelper<TModel> html, String label = "Page: ")
where TModel : ITableModel
{
if (html.ViewData.Model?.PageItems?.PageCount == 0)
return null;

var pageItems = html.ViewData.Model.PageItems;
var pageData = new PagedListData(pageItems.PageNumber, pageItems.PageSize, pageItems.PageCount, pageItems.TotalItemCount);
return Pager(html, pageData, label);
}
}
}
70 changes: 70 additions & 0 deletions src/FlexLabs.Util.Web/Html/TableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using FlexLabs.Web.TablePager;
using System.Collections.Generic;
using System.Web.Mvc;

namespace FlexLabs.Web.Html
{
public static class TableExtensions
{
public static MvcHtmlString TableHeader(this HtmlHelper html, IEnumerable<ITableHeader> headers)
{
return TableHeader(html, new[] { headers });
}

public static MvcHtmlString TableHeader(this HtmlHelper html, IEnumerable<IEnumerable<ITableHeader>> headersSet)
{
var theadTag = new TagBuilder("thead");

foreach (var headers in headersSet)
{
var rowTag = new TagBuilder("tr");
foreach (var iheader in headers)
{
var thTag = new TagBuilder("th");
if (iheader.CssClass != null)
thTag.AddCssClass(iheader.CssClass);
if (iheader.ColSpan.HasValue)
thTag.MergeAttribute("colspan", iheader.ColSpan.ToString());
if (iheader.RowSpan.HasValue)
thTag.MergeAttribute("rowspan", iheader.RowSpan.ToString());

if (iheader is CustomTableHeader)
{
thTag.InnerHtml = (iheader as CustomTableHeader).Content(html.ViewData.Model).ToString();
}
else
{
var header = iheader as TableHeader;
if (header.Value != null)
{
var buttonTag = new TagBuilder("button");
buttonTag.MergeAttribute("type", "submit");
buttonTag.MergeAttribute("name", "changeSort");
buttonTag.MergeAttribute("value", header.Value.ToString());
if (header.ToolTip != null)
buttonTag.MergeAttribute("title", header.ToolTip);
buttonTag.SetInnerText(header.Title);
thTag.InnerHtml = buttonTag.ToString();
}
else if (header.ToolTip != null)
{
var span = new TagBuilder("span");
span.MergeAttribute("title", header.ToolTip);
span.SetInnerText(header.Title);
thTag.InnerHtml = span.ToString();
}
else
{
thTag.SetInnerText(header.Title);
}
}

rowTag.InnerHtml += thTag.ToString();
}
theadTag.InnerHtml += rowTag.ToString();
}

return MvcHtmlString.Create(theadTag.ToString());
}
}
}
File renamed without changes.
Loading

0 comments on commit fc1251a

Please sign in to comment.