Skip to content

Commit

Permalink
Merge pull request #21 from IowaComputerGurus/feature/card-header-but…
Browse files Browse the repository at this point in the history
…tons

Fixes #20 by adding back the helper
  • Loading branch information
mitchelsellers committed Aug 3, 2023
2 parents 9e770d2 + 82cc2bb commit ad5a0af
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@
<card>
<card-header title="Testing All Options">
<card-header-actions>
<a href="https://www.google.com" class="btn btn-primary">Google</a>
<a href="https://www.microsoft.com" class="btn btn-secondary">Microsoft</a>
<a href="https://www.google.com" class="btn btn-sm btn-primary me-1">Google</a>
<a href="https://www.microsoft.com" class="btn btn-sm btn-secondary">Microsoft</a>
</card-header-actions>
</card-header>
<card-body>
Expand All @@ -306,8 +306,8 @@
&lt;card&gt;
&lt;card-header title=&quot;Testing All Options&quot;&gt;
&lt;card-header-actions&gt;
&lt;a href=&quot;https://www.google.com&quot; class=&quot;btn btn-primary&quot;&gt;Google&lt;/a&gt;
&lt;a href=&quot;https://www.microsoft.com&quot; class=&quot;btn btn-secondary&quot;&gt;Microsoft&lt;/a&gt;
&lt;a href=&quot;https://www.google.com&quot; class=&quot;btn btn-sm btn-primary me-1&quot;&gt;Google&lt;/a&gt;
&lt;a href=&quot;https://www.microsoft.com&quot; class=&quot;btn btn-sm btn-secondary&quot;&gt;Microsoft&lt;/a&gt;
&lt;/card-header-actions&gt;
&lt;/card-header&gt;
&lt;card-body&gt;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Card;
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Contexts;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Tests.Card;
public class CardHeaderActionsTagHelperTests : AbstractTagHelperTest
{
[Fact]
public async Task Should_ThrowException_WhenMissingContext()
{
//Arrange
var context = MakeTagHelperContext();
var output = MakeTagHelperOutput(" ");

//Act
var helper = new CardHeaderActionsTagHelper();
var exceptionResult = await Record.ExceptionAsync(() => helper.ProcessAsync(context, output));

Assert.NotNull(exceptionResult);
Assert.IsType<KeyNotFoundException>(exceptionResult);
}

[Fact]
public async Task Should_ThrowException_WhenContextIsNull()
{
//Arrange
var context = MakeTagHelperContext();
context.Items.Add(typeof(CardContext), null);
var output = MakeTagHelperOutput(" ");

//Act
var helper = new CardHeaderActionsTagHelper();
var exceptionResult = await Record.ExceptionAsync(() => helper.ProcessAsync(context, output));

Assert.NotNull(exceptionResult);
Assert.IsType<ArgumentException>(exceptionResult);
}

[Theory]
[InlineData("d-flex")]
[InlineData("flex-nowrap")]
[InlineData("mt-2")]
[InlineData("mt-sm-0")]
public async Task Should_Render_With_ClassAdded(string expectedClass)
{
//Arrange
var context = MakeTagHelperContext();
context.Items.Add(typeof(CardContext), new CardContext());
var output = MakeTagHelperOutput(" ");

//Act
var helper = new CardHeaderActionsTagHelper();
await helper.ProcessAsync(context, output);

//Assert
var classValue = output.Attributes["class"].Value;
Assert.NotNull(classValue);
var classString = classValue.ToString();
Assert.True(classString?.Contains(expectedClass));
}

[Fact]
public async Task Should_Render_With_ClassAdded_PreservingCustomClasses()
{
//Arrange
var customClass = "testing-out";
var expectedClass = $"{customClass} d-flex flex-nowrap mt-2 mt-sm-0";
var existingAttributes = new TagHelperAttributeList(new List<TagHelperAttribute>
{new("class", customClass)});
var context = MakeTagHelperContext();
context.Items.Add(typeof(CardContext), new CardContext());
var output = MakeTagHelperOutput(" ", existingAttributes);

//Act
var helper = new CardHeaderActionsTagHelper();
await helper.ProcessAsync(context, output);

//Assert
Assert.Equal(expectedClass, output.Attributes["class"].Value.ToString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Contexts;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using System;

namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Card;

/// <summary>
/// Helper for rendering actions within the header of a card
/// </summary>
[RestrictChildren("button", "a")]
public class CardHeaderActionsTagHelper : TagHelper
{
/// <summary>
/// Renders the control
/// </summary>
/// <param name="context"></param>
/// <param name="output"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
//Get the context information
var cardContext = context.Items[typeof(CardContext)] as CardContext;
if (cardContext == null)
throw new ArgumentException("CardContext is not specified in context parameter");

return ProcessAsyncInternal(output);
}

/// <summary>
/// Internal implementation
/// </summary>
/// <param name="output"></param>
/// <returns></returns>
private static async Task ProcessAsyncInternal(TagHelperOutput output)
{
output.TagName = "div";
output.AddClass("d-flex", HtmlEncoder.Default);
output.AddClass("flex-nowrap", HtmlEncoder.Default);
output.AddClass("mt-2", HtmlEncoder.Default);
output.AddClass("mt-sm-0", HtmlEncoder.Default);

var content = (await output.GetChildContentAsync()).GetContent();

output.Content.AppendHtml(content);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Contexts;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Card
{
Expand All @@ -18,23 +20,42 @@ public class CardHeaderTagHelper : TagHelper
/// </summary>
public string Title { get; set; }


/// <summary>
/// Renders the header for a bootstrap card
/// </summary>
/// <param name="context"></param>
/// <param name="output"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public override void Process(TagHelperContext context, TagHelperOutput output)
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
//Get the context information
if (context.Items[typeof(CardContext)] is not CardContext cardContext)
throw new ArgumentException("CardContext is not specified in context parameter");

return ProcessAsyncInternal(output, cardContext);
}

private async Task ProcessAsyncInternal(TagHelperOutput output, CardContext cardContext)
{
//Setup basic tag information
output.TagName = "div";
output.AddClass("card-header", HtmlEncoder.Default);

//Get sub controls if we need them
var body = (await output.GetChildContentAsync()).GetContent();
body = body.Trim();

if (!string.IsNullOrWhiteSpace(body))
{
output.AddClass("d-flex", HtmlEncoder.Default);
output.AddClass("flex-column", HtmlEncoder.Default);
output.AddClass("flex-sm-row", HtmlEncoder.Default);
output.AddClass("align-items-sm-center", HtmlEncoder.Default);
output.AddClass("justify-content-between", HtmlEncoder.Default);
}

//If we have an id make a custom span
if (!string.IsNullOrEmpty(cardContext.Id))
{
Expand All @@ -47,6 +68,12 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Content.AppendHtml(Title);
}


//Add sub-content after our title
if (!string.IsNullOrEmpty(body))
output.Content.AppendHtml(body);

}
}
}

0 comments on commit ad5a0af

Please sign in to comment.