Skip to content

Commit 9d1d292

Browse files
Added support for OffCanvas #10
1 parent a87ee09 commit 9d1d292

18 files changed

+677
-0
lines changed

src/AspNetCore.Utilities.Bootstrap5TagHelpers.Sample/Views/Home/Index.cshtml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,85 @@
441441
</tbody>
442442
</table>
443443

444+
<h2>OffCanvas</h2>
445+
<table class="table table-striped table-hover">
446+
<thead>
447+
<tr>
448+
<th>Description</th>
449+
<th>Display</th>
450+
</tr>
451+
</thead>
452+
<tbody>
453+
<tr>
454+
<td>Simple Setup</td>
455+
<td>
456+
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample" aria-controls="offcanvasExample">
457+
Show Demo
458+
</button>
459+
<offcanvas id="offcanvasExample">
460+
<offcanvas-header title="Example 1">
461+
<offcanvas-dismiss></offcanvas-dismiss>
462+
</offcanvas-header>
463+
<offcanvas-body>
464+
<h3>Magic Content</h3>
465+
<p>Goes here!</p>
466+
</offcanvas-body>
467+
</offcanvas>
468+
</td>
469+
</tr>
470+
<tr>
471+
<td>Static Backdrop</td>
472+
<td>
473+
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample2" aria-controls="offcanvasExample2">
474+
Show Example
475+
</button>
476+
<offcanvas id="offcanvasExample2" static-backdrop="true">
477+
<offcanvas-header title="Example 2">
478+
<offcanvas-dismiss></offcanvas-dismiss>
479+
</offcanvas-header>
480+
<offcanvas-body>
481+
<h3>Magic Content</h3>
482+
<p>Goes here!</p>
483+
</offcanvas-body>
484+
</offcanvas>
485+
</td>
486+
</tr>
487+
<tr>
488+
<td>Body Scroll Backdrop</td>
489+
<td>
490+
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample3" aria-controls="offcanvasExample3">
491+
Show Example
492+
</button>
493+
<offcanvas id="offcanvasExample3" enable-body-scrolling="true">
494+
<offcanvas-header title="Example 3">
495+
<offcanvas-dismiss></offcanvas-dismiss>
496+
</offcanvas-header>
497+
<offcanvas-body>
498+
<h3>Magic Content</h3>
499+
<p>Goes here!</p>
500+
</offcanvas-body>
501+
</offcanvas>
502+
</td>
503+
</tr>
504+
<tr>
505+
<td>Placement</td>
506+
<td>
507+
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample4" aria-controls="offcanvasExample4">
508+
Show Example
509+
</button>
510+
<offcanvas id="offcanvasExample4" placement="End">
511+
<offcanvas-header title="Example 4">
512+
<offcanvas-dismiss></offcanvas-dismiss>
513+
</offcanvas-header>
514+
<offcanvas-body>
515+
<h3>Magic Content</h3>
516+
<p>Goes here!</p>
517+
</offcanvas-body>
518+
</offcanvas>
519+
</td>
520+
</tr>
521+
</tbody>
522+
</table>
444523
<style>
445524
code {
446525
white-space: pre;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.OffCanvas;
2+
using Microsoft.AspNetCore.Razor.TagHelpers;
3+
4+
namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Tests.OffCanvas;
5+
6+
public class OffCanvasBodyTagHelperTests : AbstractTagHelperTest
7+
{
8+
[Fact]
9+
public async Task Should_Render_As_Div()
10+
{
11+
//Arrange
12+
TagHelperContext context = MakeTagHelperContext();
13+
TagHelperOutput output = MakeTagHelperOutput(" ");
14+
15+
//Act
16+
var helper = new OffCanvasBodyTagHelper();
17+
await helper.ProcessAsync(context, output);
18+
19+
//Assert
20+
Assert.Equal("div", output.TagName);
21+
}
22+
23+
[Fact]
24+
public async Task Should_Render_With_ClassAdded()
25+
{
26+
//Arrange
27+
TagHelperContext context = MakeTagHelperContext();
28+
TagHelperOutput output = MakeTagHelperOutput(" ");
29+
30+
//Act
31+
var helper = new OffCanvasBodyTagHelper();
32+
await helper.ProcessAsync(context, output);
33+
34+
//Assert
35+
Assert.Equal("offcanvas-body", output.Attributes["class"].Value);
36+
}
37+
38+
[Fact]
39+
public async Task Should_Render_With_ClassAdded_PreservingCustomClasses()
40+
{
41+
//Arrange
42+
var customClass = "testing-out";
43+
var expectedClass = $"{customClass} offcanvas-body";
44+
var existingAttributes = new TagHelperAttributeList(new List<TagHelperAttribute> { new("class", customClass) });
45+
TagHelperContext context = MakeTagHelperContext();
46+
TagHelperOutput output = MakeTagHelperOutput(" ", existingAttributes);
47+
48+
//Act
49+
var helper = new OffCanvasBodyTagHelper();
50+
await helper.ProcessAsync(context, output);
51+
52+
//Assert
53+
Assert.Equal(expectedClass, output.Attributes["class"].Value.ToString());
54+
}
55+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.OffCanvas;
2+
using Microsoft.AspNetCore.Razor.TagHelpers;
3+
4+
namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Tests.OffCanvas;
5+
6+
public class OffCanvasDismissTagHelperTests : AbstractTagHelperTest
7+
{
8+
[Fact]
9+
public void Should_Render_As_Button()
10+
{
11+
//Arrange
12+
TagHelperContext context = MakeTagHelperContext();
13+
TagHelperOutput output = MakeTagHelperOutput(" ");
14+
15+
//Act
16+
var helper = new OffCanvasDismissTagHelper();
17+
helper.Process(context, output);
18+
19+
//Assert
20+
Assert.Equal("button", output.TagName);
21+
}
22+
23+
[Theory]
24+
[InlineData("aria-label", "Close")]
25+
[InlineData("data-bs-dismiss", "offcanvas")]
26+
[InlineData("class", "btn-close")]
27+
[InlineData("type", "button")]
28+
public void Should_Set_Needed_Attributes(string expectedAttribute, string expectedValue)
29+
{
30+
//Arrange
31+
TagHelperContext context = MakeTagHelperContext();
32+
TagHelperOutput output = MakeTagHelperOutput(" ");
33+
34+
//Act
35+
var helper = new OffCanvasDismissTagHelper();
36+
helper.Process(context, output);
37+
38+
//Assert
39+
Assert.Equal(expectedValue, output.Attributes[expectedAttribute].Value);
40+
}
41+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Contexts;
2+
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Modal;
3+
using ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.OffCanvas;
4+
using Microsoft.AspNetCore.Razor.TagHelpers;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Tests.OffCanvas;
12+
public class OffCanvasHeaderTagHelperTests : AbstractTagHelperTest
13+
{
14+
[Fact]
15+
public async Task Should_ThrowException_WhenMissingContext()
16+
{
17+
//Arrange
18+
TagHelperContext context = MakeTagHelperContext();
19+
TagHelperOutput output = MakeTagHelperOutput(" ");
20+
21+
//Act
22+
var helper = new OffCanvasHeaderTagHelper();
23+
Exception exceptionResult = await Record.ExceptionAsync(() => helper.ProcessAsync(context, output));
24+
25+
Assert.NotNull(exceptionResult);
26+
Assert.IsType<KeyNotFoundException>(exceptionResult);
27+
}
28+
29+
[Fact]
30+
public async Task Should_ThrowException_WhenContextIsNull()
31+
{
32+
//Arrange
33+
TagHelperContext context = MakeTagHelperContext();
34+
context.Items.Add(typeof(OffCanvasContext), null);
35+
TagHelperOutput output = MakeTagHelperOutput(" ");
36+
37+
//Act
38+
var helper = new OffCanvasHeaderTagHelper();
39+
Exception exceptionResult = await Record.ExceptionAsync(() => helper.ProcessAsync(context, output));
40+
41+
Assert.NotNull(exceptionResult);
42+
Assert.IsType<ArgumentException>(exceptionResult);
43+
}
44+
45+
[Fact]
46+
public async Task Should_Render_As_Div()
47+
{
48+
//Arrange
49+
TagHelperContext context = MakeTagHelperContext();
50+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext());
51+
TagHelperOutput output = MakeTagHelperOutput(" ");
52+
53+
//Act
54+
var helper = new OffCanvasHeaderTagHelper();
55+
await helper.ProcessAsync(context, output);
56+
57+
//Assert
58+
Assert.Equal("div", output.TagName);
59+
}
60+
61+
[Fact]
62+
public async Task Should_Render_With_ClassAdded()
63+
{
64+
//Arrange
65+
TagHelperContext context = MakeTagHelperContext();
66+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext());
67+
TagHelperOutput output = MakeTagHelperOutput(" ");
68+
69+
//Act
70+
var helper = new OffCanvasHeaderTagHelper();
71+
await helper.ProcessAsync(context, output);
72+
73+
//Assert
74+
Assert.Equal("offcanvas-header", output.Attributes["class"].Value);
75+
}
76+
77+
[Fact]
78+
public async Task Should_Render_With_ClassAdded_PreservingCustomClasses()
79+
{
80+
//Arrange
81+
var customClass = "testing-out";
82+
var expectedClass = $"{customClass} offcanvas-header";
83+
var existingAttributes = new TagHelperAttributeList(new List<TagHelperAttribute> { new("class", customClass) });
84+
TagHelperContext context = MakeTagHelperContext();
85+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext());
86+
TagHelperOutput output = MakeTagHelperOutput(" ", existingAttributes);
87+
88+
//Act
89+
var helper = new OffCanvasHeaderTagHelper();
90+
await helper.ProcessAsync(context, output);
91+
92+
//Assert
93+
Assert.Equal(expectedClass, output.Attributes["class"].Value.ToString());
94+
}
95+
96+
[Fact]
97+
public async Task Should_NotRender_InnerContent_When_Title_Missing()
98+
{
99+
//Arrange
100+
TagHelperContext context = MakeTagHelperContext();
101+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext());
102+
TagHelperOutput output = MakeTagHelperOutput(" ");
103+
104+
//Act
105+
var helper = new OffCanvasHeaderTagHelper();
106+
await helper.ProcessAsync(context, output);
107+
108+
//Assert
109+
Assert.Equal("", output.Content.GetContent());
110+
}
111+
112+
[Theory]
113+
[InlineData("My Title", "", "<h5 class=\"offcanvas-title\">My Title</h5>")]
114+
[InlineData("My Title", "myOffcanvas", "<h5 class=\"offcanvas-title\" id=\"myOffcanvasLabel\">My Title</h5>")]
115+
public async Task Should_Render_InnerContent_Title_When_Title_Provided(string title, string id, string expectedHtml)
116+
{
117+
//Arrange
118+
TagHelperContext context = MakeTagHelperContext();
119+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext { Id = id });
120+
TagHelperOutput output = MakeTagHelperOutput(" ");
121+
122+
//Act
123+
var helper = new OffCanvasHeaderTagHelper { Title = title };
124+
await helper.ProcessAsync(context, output);
125+
126+
//Assert
127+
Assert.Equal(expectedHtml, output.Content.GetContent());
128+
}
129+
130+
[Theory]
131+
[InlineData("My Title", "", "", "<h5 class=\"offcanvas-title\">My Title</h5>")]
132+
[InlineData("My Title", "myOffcanvas", "h4", "<h4 class=\"offcanvas-title\" id=\"myOffcanvasLabel\">My Title</h4>")]
133+
public async Task Should_Render_InnerContent_Title_WithCustomTag_When_Title_Provided(string title, string id, string tag, string expectedHtml)
134+
{
135+
//Arrange
136+
TagHelperContext context = MakeTagHelperContext();
137+
context.Items.Add(typeof(OffCanvasContext), new OffCanvasContext { Id = id });
138+
TagHelperOutput output = MakeTagHelperOutput(" ");
139+
140+
//Act
141+
var helper = new OffCanvasHeaderTagHelper { Title = title };
142+
if (!string.IsNullOrEmpty(tag))
143+
helper.TitleTag = tag;
144+
await helper.ProcessAsync(context, output);
145+
146+
//Assert
147+
Assert.Equal(expectedHtml, output.Content.GetContent());
148+
}
149+
}

0 commit comments

Comments
 (0)