Skip to content

Commit 4a865d0

Browse files
committed
Replace HtmlTags with our HtmlTagBuilder
1 parent 945da80 commit 4a865d0

File tree

108 files changed

+1032
-980
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1032
-980
lines changed
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using Microsoft.AspNetCore.Html;
23

34
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
45

@@ -8,14 +9,14 @@ public class BreadcrumbsOptions
89
{
910
public bool? CollapseOnMobile { get; set; }
1011
public string? Classes { get; set; }
11-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
12+
public EncodedAttributesDictionary? Attributes { get; set; }
1213
public IReadOnlyCollection<BreadcrumbsOptionsItem>? Items { get; set; }
1314
}
1415

1516
public class BreadcrumbsOptionsItem
1617
{
17-
public string? Html { get; set; }
18+
public IHtmlContent? Html { get; set; }
1819
public string? Text { get; set; }
19-
public string? Href { get; set; }
20-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
20+
public IHtmlContent? Href { get; set; }
21+
public EncodedAttributesDictionary? Attributes { get; set; }
2122
}
Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
1-
using System.Collections.Generic;
1+
using Microsoft.AspNetCore.Html;
22

33
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
44

55
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
66

77
public class ButtonOptions
88
{
9-
public string? Element { get; set; }
10-
public string? Html { get; set; }
9+
public IHtmlContent? Element { get; set; }
10+
public IHtmlContent? Html { get; set; }
1111
public string? Text { get; set; }
12-
public string? Name { get; set; }
13-
public string? Type { get; set; }
14-
public string? Value { get; set; }
12+
public IHtmlContent? Name { get; set; }
13+
public IHtmlContent? Type { get; set; }
14+
public IHtmlContent? Value { get; set; }
1515
public bool? Disabled { get; set; }
16-
public string? Href { get; set; }
17-
public string? Classes { get; set; }
18-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
16+
public IHtmlContent? Href { get; set; }
17+
public IHtmlContent? Classes { get; set; }
18+
public EncodedAttributesDictionary? Attributes { get; set; }
1919
public bool? PreventDoubleClick { get; set; }
2020
public bool? IsStartButton { get; set; }
21-
public string? Id { get; set; }
21+
public IHtmlContent? Id { get; set; }
2222

2323
internal void Validate()
2424
{
25-
if (Element is not null && Element != "a" && Element != "button" && Element != "input")
25+
var elementStr = Element?.ToHtmlString();
26+
27+
if (elementStr is not null && elementStr != "a" && elementStr != "button" && elementStr != "input")
2628
{
2729
throw new InvalidOptionsException(GetType(), $"{nameof(Element)} must be 'a', 'button', or 'input'.");
2830
}
2931

30-
if (Element == "input" && IsStartButton == true)
32+
if (elementStr == "input" && IsStartButton == true)
3133
{
3234
throw new InvalidOptionsException(GetType(), $"{nameof(IsStartButton)} cannot be specified for 'input' elements.");
3335
}
@@ -37,12 +39,12 @@ internal void Validate()
3739
throw new InvalidOptionsException(GetType(), $"{nameof(PreventDoubleClick)} can only be specified for 'button' or 'input' elements.");
3840
}
3941

40-
if (Element == "a" && Disabled is not null)
42+
if (elementStr == "a" && Disabled is not null)
4143
{
4244
throw new InvalidOptionsException(GetType(), $"{nameof(Disabled)} cannot be specified for 'a' elements.");
4345
}
4446

45-
if (Html.NormalizeEmptyString() is not null && Element == "input")
47+
if (Html.NormalizeEmptyString() is not null && elementStr == "input")
4648
{
4749
throw new InvalidOptionsException(GetType(), $"{nameof(Html)} cannot be specified for 'input' elements.");
4850
}
@@ -54,5 +56,5 @@ internal void Validate()
5456
}
5557

5658
internal string GetElement() =>
57-
Element.NormalizeEmptyString() ?? (Href.NormalizeEmptyString() is not null ? "a" : "button");
59+
Element?.ToHtmlString().NormalizeEmptyString() ?? (Href.NormalizeEmptyString() is not null ? "a" : "button");
5860
}
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,42 @@
1-
using System.Collections.Generic;
1+
using Microsoft.AspNetCore.Html;
22

33
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
44

55
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
66

77
public class CharacterCountOptions
88
{
9-
public string? Id { get; set; }
10-
public string? Name { get; set; }
9+
public IHtmlContent? Id { get; set; }
10+
public IHtmlContent? Name { get; set; }
1111
public int? Rows { get; set; }
12-
public string? Value { get; set; }
12+
public IHtmlContent? Value { get; set; }
1313
public int? MaxLength { get; set; }
1414
public int? MaxWords { get; set; }
1515
public int? Threshold { get; set; }
1616
public LabelOptions? Label { get; set; }
1717
public HintOptions? Hint { get; set; }
1818
public ErrorMessageOptions? ErrorMessage { get; set; }
1919
public FormGroupOptions? FormGroup { get; set; }
20-
public string? Classes { get; set; }
20+
public IHtmlContent? Classes { get; set; }
2121
public bool? Spellcheck { get; set; }
22-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
22+
public EncodedAttributesDictionary? Attributes { get; set; }
2323
public CharacterCountCountOptionsMessage? CountMessage { get; set; }
24-
public string? TextareaDescriptionText { get; set; }
24+
public IHtmlContent? TextareaDescriptionText { get; set; }
2525
public CharacterCountOptionsLocalizedText? CharactersUnderLimitText { get; set; }
26-
public string? CharactersAtLimitText { get; set; }
26+
public IHtmlContent? CharactersAtLimitText { get; set; }
2727
public CharacterCountOptionsLocalizedText? CharactersOverLimitText { get; set; }
2828
public CharacterCountOptionsLocalizedText? WordsUnderLimitText { get; set; }
29-
public string? WordsAtLimitText { get; set; }
29+
public IHtmlContent? WordsAtLimitText { get; set; }
3030
public CharacterCountOptionsLocalizedText? WordsOverLimitText { get; set; }
3131
}
3232

3333
public class CharacterCountCountOptionsMessage
3434
{
35-
public string? Classes { get; set; }
35+
public IHtmlContent? Classes { get; set; }
3636
}
3737

3838
public class CharacterCountOptionsLocalizedText
3939
{
40-
public string? One { get; set; }
41-
public string? Other { get; set; }
40+
public IHtmlContent? One { get; set; }
41+
public IHtmlContent? Other { get; set; }
4242
}
Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
11
using System.Collections.Generic;
2+
using Microsoft.AspNetCore.Html;
23

34
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
45

56
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
67

78
public record CookieBannerOptions
89
{
9-
public string? AriaLabel { get; set; }
10+
public IHtmlContent? AriaLabel { get; set; }
1011
public bool? Hidden { get; set; }
11-
public string? Classes { get; set; }
12-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
12+
public IHtmlContent? Classes { get; set; }
13+
public EncodedAttributesDictionary? Attributes { get; set; }
1314
public IReadOnlyCollection<CookieBannerOptionsMessage>? Messages { get; set; }
1415

1516
internal void Validate()
1617
{
18+
// TODO Each action should have non-null Text
1719
}
1820
}
1921

2022
public record CookieBannerOptionsMessage
2123
{
2224
public string? HeadingText { get; set; }
23-
public string? HeadingHtml { get; set; }
25+
public IHtmlContent? HeadingHtml { get; set; }
2426
public string? Text { get; set; }
25-
public string? Html { get; set; }
27+
public IHtmlContent? Html { get; set; }
2628
public IReadOnlyCollection<CookieBannerOptionsMessageAction>? Actions { get; set; }
2729
public bool? Hidden { get; set; }
28-
public string? Role { get; set; }
29-
public string? Classes { get; set; }
30-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
30+
public IHtmlContent? Role { get; set; }
31+
public IHtmlContent? Classes { get; set; }
32+
public EncodedAttributesDictionary? Attributes { get; set; }
3133
}
3234

3335
public record CookieBannerOptionsMessageAction
3436
{
3537
public string? Text { get; set; }
36-
public string? Type { get; set; }
37-
public string? Href { get; set; }
38-
public string? Name { get; set; }
39-
public string? Value { get; set; }
40-
public string? Classes { get; set; }
41-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
38+
public IHtmlContent? Type { get; set; }
39+
public IHtmlContent? Href { get; set; }
40+
public IHtmlContent? Name { get; set; }
41+
public IHtmlContent? Value { get; set; }
42+
public IHtmlContent? Classes { get; set; }
43+
public EncodedAttributesDictionary? Attributes { get; set; }
4244
}
Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
using System.Collections.Generic;
2+
using Microsoft.AspNetCore.Html;
23

34
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
45

56
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
67

78
public class DateInputOptions
89
{
9-
public string? Id { get; set; }
10-
public string? NamePrefix { get; set; }
10+
public IHtmlContent? Id { get; set; }
11+
public IHtmlContent? NamePrefix { get; set; }
1112
public IReadOnlyCollection<DateInputOptionsItem>? Items { get; set; }
1213
public HintOptions? Hint { get; set; }
1314
public ErrorMessageOptions? ErrorMessage { get; set; }
1415
public FormGroupOptions? FormGroup { get; set; }
1516
public FieldsetOptions? Fieldset { get; set; }
16-
public string? Classes { get; set; }
17-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
17+
public IHtmlContent? Classes { get; set; }
18+
public EncodedAttributesDictionary? Attributes { get; set; }
1819
}
1920

2021
public class DateInputOptionsItem
2122
{
22-
public string? Id { get; set; }
23-
public string? Name { get; set; }
24-
public string? Label { get; set; }
25-
public string? Value { get; set; }
26-
public string? Autocomplete { get; set; }
27-
public string? InputMode { get; set; }
28-
public string? Pattern { get; set; }
29-
public string? Classes { get; set; }
30-
public IReadOnlyDictionary<string, string?>? Attributes { get; set; }
23+
public IHtmlContent? Id { get; set; }
24+
public IHtmlContent? Name { get; set; }
25+
public IHtmlContent? Label { get; set; }
26+
public IHtmlContent? Value { get; set; }
27+
public IHtmlContent? Autocomplete { get; set; }
28+
public IHtmlContent? InputMode { get; set; }
29+
public IHtmlContent? Pattern { get; set; }
30+
public IHtmlContent? Classes { get; set; }
31+
public EncodedAttributesDictionary? Attributes { get; set; }
3132
}
Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,80 @@
11
using System;
2-
using System.Collections.Immutable;
32
using System.Diagnostics;
4-
using HtmlTags;
3+
using Microsoft.AspNetCore.Html;
54

65
namespace GovUk.Frontend.AspNetCore.ComponentGeneration;
76

87
public partial class DefaultComponentGenerator
98
{
109
/// <inheritdoc/>
11-
public virtual HtmlTag GenerateButton(ButtonOptions options)
10+
public virtual HtmlTagBuilder GenerateButton(ButtonOptions options)
1211
{
1312
ArgumentNullException.ThrowIfNull(options);
1413
options.Validate();
1514

1615
var classes = ($"govuk-button " + options.Classes).TrimEnd();
1716
var element = options.GetElement();
1817

19-
HtmlTag? iconHtml = null;
18+
HtmlTagBuilder? iconHtml = null;
2019
if (options.IsStartButton == true)
2120
{
22-
iconHtml = new HtmlTag("svg")
23-
.AddClass("govuk-button__start-icon")
24-
.UnencodedAttr("xmlns", "http://www.w3.org/2000/svg")
25-
.UnencodedAttr("width", "17.5")
26-
.UnencodedAttr("height", "19")
27-
.UnencodedAttr("viewbox", "0 0 33 40")
28-
.UnencodedAttr("aria-hidden", "true")
29-
.UnencodedAttr("focusable", "false")
30-
.Append(new HtmlTag("path")
31-
.NoClosingTag()
32-
.UnencodedAttr("fill", "currentColor")
33-
.UnencodedAttr("d", "M0 0h13l20 20-20 20H0l20-20z"));
21+
iconHtml = new HtmlTagBuilder("svg")
22+
.WithCssClass("govuk-button__start-icon")
23+
.WithAttribute("xmlns", "http://www.w3.org/2000/svg", encodeValue: false)
24+
.WithAttribute("width", "17.5", encodeValue: false)
25+
.WithAttribute("height", "19", encodeValue: false)
26+
.WithAttribute("viewbox", "0 0 33 40", encodeValue: false)
27+
.WithAttribute("aria-hidden", "true", encodeValue: false)
28+
.WithAttribute("focusable", "false", encodeValue: false)
29+
.WithAppendedHtml(new HtmlTagBuilder("path")
30+
.WithAttribute("fill", "currentColor", encodeValue: false)
31+
.WithAttribute("d", "M0 0h13l20 20-20 20H0l20-20z", encodeValue: false));
3432

3533
classes += " govuk-button--start";
3634
}
3735

38-
var commonAttributes = options.Attributes
39-
.ToImmutableDictionary()
40-
.Add("class", classes)
41-
.Add("data-module", "govuk-button")
42-
.AddIfNotNull("id", options.Id.NormalizeEmptyString());
36+
var commonAttributes = new EncodedAttributesDictionaryBuilder(options.Attributes)
37+
.WithCssClass(classes)
38+
.With("data-module", "govuk-button", encodeValue: false)
39+
.WithWhenNotNull(options.Id.NormalizeEmptyString(), "id");
4340

44-
var buttonAttributes = ImmutableDictionary<string, string?>.Empty
45-
.AddIfNotNull("name", options.Name.NormalizeEmptyString())
46-
.AddIf(options.Disabled == true, "disabled", null)
47-
.AddIf(options.Disabled == true, "aria-disabled", "true")
48-
.AddIfNotNull("data-prevent-double-click", options.PreventDoubleClick?.ToString().ToLower());
41+
var buttonAttributes = new EncodedAttributesDictionaryBuilder()
42+
.WithWhenNotNull(options.Name.NormalizeEmptyString(), "name")
43+
.When(options.Disabled == true, b => b.WithBoolean("disabled").With("aria-disabled", "true", encodeValue: false))
44+
.WhenNotNull(options.PreventDoubleClick, (pdc, b) => b.With("data-prevent-double-click", pdc.ToString()!.ToLower(), encodeValue: false));
4945

5046
if (element == "a")
5147
{
52-
var button = new HtmlTag("a")
53-
.UnencodedAttr("href", options.Href.NormalizeEmptyString() ?? "#")
54-
.UnencodedAttr("role", "button")
55-
.UnencodedAttr("draggable", "false")
56-
.MergeEncodedAttributes(commonAttributes)
57-
.AppendHtml(GetEncodedTextOrHtml(options.Text, options.Html));
48+
var button = new HtmlTagBuilder("a")
49+
.WithAttribute("href", options.Href.NormalizeEmptyString() ?? new HtmlString("#"))
50+
.WithAttribute("role", "button", encodeValue: false)
51+
.WithAttribute("draggable", "false", encodeValue: false)
52+
.WithAttributes(commonAttributes)
53+
.WithAppendedHtml(GetEncodedTextOrHtml(options.Text, options.Html)!);
5854

5955
if (iconHtml is not null)
6056
{
61-
button.Append(iconHtml);
57+
button.WithAppendedHtml(iconHtml);
6258
}
6359

6460
return button;
6561
}
6662
else if (element == "button")
6763
{
68-
var button = new HtmlTag("button")
69-
.UnencodedAttr("type", options.Type.NormalizeEmptyString() ?? "submit")
70-
.MergeEncodedAttributes(buttonAttributes)
71-
.MergeEncodedAttributes(commonAttributes)
72-
.AppendHtml(GetEncodedTextOrHtml(options.Text, options.Html));
64+
var button = new HtmlTagBuilder("button")
65+
.WithAttribute("type", options.Type.NormalizeEmptyString() ?? new HtmlString("submit"))
66+
.WithAttributes(buttonAttributes)
67+
.WithAttributes(commonAttributes)
68+
.WithAppendedHtml(GetEncodedTextOrHtml(options.Text, options.Html)!);
7369

74-
if (options.Value.NormalizeEmptyString() is string value)
70+
if (options.Value.NormalizeEmptyString() is IHtmlContent value)
7571
{
76-
button.UnencodedAttr("value", value);
72+
button.WithAttribute("value", value);
7773
}
7874

7975
if (iconHtml is not null)
8076
{
81-
button.Append(iconHtml);
77+
button.WithAppendedHtml(iconHtml);
8278
}
8379

8480
return button;
@@ -88,11 +84,11 @@ public virtual HtmlTag GenerateButton(ButtonOptions options)
8884
Debug.Assert(element == "input");
8985
Debug.Assert(options.Text.NormalizeEmptyString() is not null);
9086

91-
return new HtmlTag("input")
92-
.UnencodedAttr("value", options.Text)
93-
.UnencodedAttr("type", options.Type.NormalizeEmptyString() ?? "submit")
94-
.MergeEncodedAttributes(buttonAttributes)
95-
.MergeEncodedAttributes(commonAttributes);
87+
return new HtmlTagBuilder("input")
88+
.WhenNotNull(options.Text, (value, b) => b.WithAttribute("value", value, encodeValue: true))
89+
.WithAttribute("type", options.Type.NormalizeEmptyString() ?? new HtmlString("submit"))
90+
.WithAttributes(buttonAttributes)
91+
.WithAttributes(commonAttributes);
9692
}
9793
}
9894
}

0 commit comments

Comments
 (0)