diff --git a/Engine/Directory.Build.props b/Engine/Directory.Build.props
index 5df47ec..b0e18f5 100644
--- a/Engine/Directory.Build.props
+++ b/Engine/Directory.Build.props
@@ -16,6 +16,6 @@
- 8.2.0
+ 8.3.0
diff --git a/Engine/Mindbox.Quokka.Abstractions/Html/Reference.cs b/Engine/Mindbox.Quokka.Abstractions/Html/Reference.cs
index 004d09b..1030c7b 100644
--- a/Engine/Mindbox.Quokka.Abstractions/Html/Reference.cs
+++ b/Engine/Mindbox.Quokka.Abstractions/Html/Reference.cs
@@ -13,6 +13,7 @@
// // limitations under the License.
using System;
+using System.Collections.Generic;
namespace Mindbox.Quokka.Html
{
@@ -22,13 +23,20 @@ public class Reference
public string RedirectUrl { get; }
public string Name { get; }
public bool IsConstant { get; }
+ public IReadOnlyDictionary Attributes { get; }
- public Reference(string redirectUrl, string name, Guid uniqueKey, bool isConstant)
+ public Reference(
+ string redirectUrl,
+ string name,
+ Guid uniqueKey,
+ bool isConstant,
+ IReadOnlyDictionary attributes = null)
{
RedirectUrl = redirectUrl;
Name = name;
UniqueKey = uniqueKey;
IsConstant = isConstant;
+ Attributes = attributes ?? new Dictionary(StringComparer.InvariantCultureIgnoreCase);
}
}
}
diff --git a/Engine/Quokka.Core/Html/Nodes/LinkBlock.cs b/Engine/Quokka.Core/Html/Nodes/LinkBlock.cs
index 49db010..427dd33 100644
--- a/Engine/Quokka.Core/Html/Nodes/LinkBlock.cs
+++ b/Engine/Quokka.Core/Html/Nodes/LinkBlock.cs
@@ -27,13 +27,15 @@ internal class LinkBlock : TemplateNodeBase, IStaticBlockPart
private readonly AttributeValue hrefValue;
private readonly AttributeValue nameValue;
+ private readonly IReadOnlyDictionary attributes;
private readonly Guid uniqueKey;
- public LinkBlock(AttributeValue hrefValue, AttributeValue nameValue)
+ public LinkBlock(AttributeValue hrefValue, AttributeValue nameValue, IReadOnlyDictionary attributes)
{
this.hrefValue = hrefValue;
this.nameValue = nameValue;
+ this.attributes = attributes;
uniqueKey = Guid.NewGuid();
}
@@ -85,7 +87,8 @@ public override void CompileGrammarSpecificData(GrammarSpecificDataAnalysisConte
hrefValue.Text,
nameValue?.Text,
uniqueKey,
- isConstant: !hrefValue.TextComponents.OfType().Any()));
+ isConstant: !hrefValue.TextComponents.OfType().Any(),
+ attributes: attributes));
}
public override void Accept(ITemplateVisitor treeVisitor)
diff --git a/Engine/Quokka.Core/Html/Visitors/Html/HtmlBlockVisitor.cs b/Engine/Quokka.Core/Html/Visitors/Html/HtmlBlockVisitor.cs
index d195b3f..c67625b 100644
--- a/Engine/Quokka.Core/Html/Visitors/Html/HtmlBlockVisitor.cs
+++ b/Engine/Quokka.Core/Html/Visitors/Html/HtmlBlockVisitor.cs
@@ -66,22 +66,27 @@ public override IStaticBlockPart VisitClosingTag(QuokkaHtml.ClosingTagContext co
private IStaticBlockPart TryGetLinkNodeFromTagAttributes(IEnumerable attributes)
{
- var hrefAttributeValueVisitor = new AttributeValueVisitor(ParsingContext);
+ var attributeValueVisitor = new AttributeValueVisitor(ParsingContext);
AttributeValue hrefValue = null;
AttributeValue nameValue = null;
+ var allAttributes = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
foreach (var attribute in attributes)
{
var attributeName = attribute.TAG_NAME().GetText();
+ var attributeValue = attribute.attributeValue()?.Accept(attributeValueVisitor);
+
if (attributeName.Equals("href", StringComparison.InvariantCultureIgnoreCase))
- hrefValue = attribute.attributeValue()?.Accept(hrefAttributeValueVisitor);
+ hrefValue = attributeValue;
if (attributeName.Equals("data-name", StringComparison.InvariantCultureIgnoreCase))
- nameValue = attribute.attributeValue()?.Accept(hrefAttributeValueVisitor);
+ nameValue = attributeValue;
+
+ allAttributes[attributeName] = attributeValue?.Text ?? string.Empty;
}
return hrefValue != null
- ? new LinkBlock(hrefValue, nameValue)
+ ? new LinkBlock(hrefValue, nameValue, allAttributes)
: null;
}
}
diff --git a/Engine/Quokka.Tests/Helpers/ReferencesAssert.cs b/Engine/Quokka.Tests/Helpers/ReferencesAssert.cs
index 7c3ef44..42ec3f5 100644
--- a/Engine/Quokka.Tests/Helpers/ReferencesAssert.cs
+++ b/Engine/Quokka.Tests/Helpers/ReferencesAssert.cs
@@ -40,5 +40,23 @@ public static void AreCollectionsEquivalent(IEnumerable expected, IRe
Assert.AreEqual(expectedElement.IsConstant, actualElement.IsConstant);
}
}
+
+ public static void ContainsAttribute(Reference reference, string attributeName, string expectedValue)
+ {
+ Assert.IsTrue(
+ reference.Attributes.ContainsKey(attributeName),
+ $"Reference does not contain attribute '{attributeName}'");
+ Assert.AreEqual(
+ expectedValue,
+ reference.Attributes[attributeName],
+ $"Attribute '{attributeName}' has unexpected value");
+ }
+
+ public static void DoesNotContainAttribute(Reference reference, string attributeName)
+ {
+ Assert.IsFalse(
+ reference.Attributes.ContainsKey(attributeName),
+ $"Reference unexpectedly contains attribute '{attributeName}'");
+ }
}
}
diff --git a/Engine/Quokka.Tests/Html/HtmlReferenceDiscoveryTests.cs b/Engine/Quokka.Tests/Html/HtmlReferenceDiscoveryTests.cs
index 02678d2..fcf492d 100644
--- a/Engine/Quokka.Tests/Html/HtmlReferenceDiscoveryTests.cs
+++ b/Engine/Quokka.Tests/Html/HtmlReferenceDiscoveryTests.cs
@@ -383,5 +383,59 @@ public void Html_ReferenceDiscovery_AHref_HtmlEncoded()
},
references);
}
+
+ [TestMethod]
+ public void Html_ReferenceDiscovery_AHref_SingleDataAttribute_PopulatesAttributes()
+ {
+ var template = new HtmlTemplate(
+ "Test");
+ var references = template.GetReferences();
+
+ Assert.AreEqual(1, references.Count);
+ ReferencesAssert.ContainsAttribute(references[0], "data-custom", "value-42");
+ }
+
+ [TestMethod]
+ public void Html_ReferenceDiscovery_AHref_MultipleDataAttributes_AllPopulated()
+ {
+ var template = new HtmlTemplate(
+ "Test");
+ var references = template.GetReferences();
+
+ Assert.AreEqual(1, references.Count);
+ ReferencesAssert.ContainsAttribute(references[0], "data-foo", "bar");
+ ReferencesAssert.ContainsAttribute(references[0], "data-name", "Link name");
+ }
+
+ [TestMethod]
+ public void Html_ReferenceDiscovery_AHref_AttributeWithoutValue_EmptyString()
+ {
+ var template = new HtmlTemplate(
+ "Test");
+ var references = template.GetReferences();
+
+ Assert.AreEqual(1, references.Count);
+ ReferencesAssert.ContainsAttribute(references[0], "data-custom", string.Empty);
+ }
+
+ [TestMethod]
+ public void Html_ReferenceDiscovery_AHref_NoExtraAttributes_AttributesEmpty()
+ {
+ var template = new HtmlTemplate("Test");
+ var references = template.GetReferences();
+
+ Assert.AreEqual(1, references.Count);
+ ReferencesAssert.DoesNotContainAttribute(references[0], "data-custom");
+ }
+
+ [TestMethod]
+ public void Html_ReferenceDiscovery_AHref_HrefIsIncludedInAttributes()
+ {
+ var template = new HtmlTemplate("Test");
+ var references = template.GetReferences();
+
+ Assert.AreEqual(1, references.Count);
+ ReferencesAssert.ContainsAttribute(references[0], "href", "http://example.com");
+ }
}
}